Chinaunix首页 | 论坛 | 博客
  • 博客访问: 188923
  • 博文数量: 56
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 625
  • 用 户 组: 普通用户
  • 注册时间: 2006-12-22 08:58
文章分类

全部博文(56)

文章存档

2011年(1)

2007年(46)

2006年(9)

我的朋友

分类: LINUX

2006-12-24 01:13:41

勿以善小而不为。
——刘备
虽说万事开头难,但有时也未必。比如说,写一个有实用价值的操作系统是一项艰巨的工作,但一个最小的操作系统或许很容易就实现了。现在我们就来实现一个小得无法再小的“操作系统”,建议你跟随书中的介绍一起动手来做,你会发现不但很容易,而且很有趣。
1.1 准备工作
对于写程序,准备工作无非就是硬件和软件两方面,我们来看一下:
1.硬件
— 一台计算机(Windows操作系统)
— 一张空白软盘
2.软件
— 汇编编译器NASM。最新版本可以在此链接处获得:
projects/nasm。(此刻你可能会有疑问:为什么是NASM,而不是MASM或者TASM?对于这一点本书后面会有解释。)
— 软盘绝对扇区读写工具。比如本书附赠光盘中的FloppyWriter.exe。
 

你相不相信,一个“操作系统”可以只有20行代码?请看:

代码1-1  \chapter1\a\boot.asm
 org 07c00h ; 告诉编译器程序加载到7c00处
 mov ax, cs
 mov ds, ax
 mov es, ax
 call DispStr ; 调用显示字符串例程
 jmp $ ; 无限循环
DispStr:
 mov ax, BootMessage
 mov bp, ax ; es:bp = 串地址
 mov cx, 16 ; cx = 串长度
 mov ax, 01301h ; ah = 13, al = 01h
 mov bx, 000ch ; 页号为0(bh = 0) 黑底红字(bl = 0Ch,高亮)
 mov dl, 0
 int 10h ; 10h 号中断
 ret
BootMessage: db "Hello, OS world!"
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为
; 512字节
dw 0xaa55 ; 结束标志
把这段代码用NASM编译一下:
nasm boot.asm –o boot.bin
我们就得到了一个512B的boot.bin,使用软盘绝对扇区读写工具将这个文件写到一张空白软盘的第一个扇区。好了,你的第一个“操作系统”就已经完成了。这张软盘已经是一张引导盘了。
把它放到你的软驱中重新启动计算机,从软盘引导,你看到了什么?
计算机显示出你的字符串了!红色的“Hello, OS world!”,多么奇妙啊,你的“操作系统”在运行了!
如果使用Virtual PC的话(下文中将会有关于Virtual PC的详细介绍),你应该能看到图1-1所示的画面。
这真的是太棒了,虽然你知道它有多么简陋,但是,毕竟你已经制作了一个可以引导的软盘了,而且所有工作都是你亲手独立完成的!
 
你可能还没有从刚刚的兴奋中走出来,可是我不得不告诉你,实际上,你刚刚所完成的并不是一个完整的OS,而仅仅是一个最最简单的引导扇区(Boot Sector)。然而不管我们完成的是什么,至少,它是直接在裸机上运行的,不依赖于任何其他软件,所以,这和我们平时所编写的应用软件有本质的区别。它不是操作系统,但已经具备了操作系统的一个特性。
我们知道,当计算机电源被打开时,它会先进行加电自检(POST),然后寻找启动盘,如果是选择从软盘启动,计算机就会检查软盘的0面0磁道1扇区,如果发现它以0xAA55(假如我们把此扇区看做一个字符数组sector[]的话,那么此结束标志相当于sector[510]=0x55,且sector[511]=0xAA)结束,则BIOS认为它是一个引导扇区,也就是我们说的Boot Sector。当然,一个正确的Boot Sector除了以0xAA55结束之外,还应该包含一段少于512B的执行码。
好了,一旦BIOS发现了Boot Sector,就会将这512B的内容装载到内存的0000:7c00处,然后跳转到0000:7c00处将控制权彻底交给这段引导代码。到此为止,计算机不再由BIOS中固有的程序来控制,而变成由操作系统的一部分来控制。
现在,你可能明白了为什么在那段代码的第一行会出现org 07c00这样的代码。没错,这行代码就是告诉编译器,将来我们的这段程序要被加载到内存偏移地址7c00处。好了,下面将对代码的其他部分进行详细解释。
 
其实程序的主体框架只有5行(从第2行到第6行),其中调用了一个显示字符串的子程序。程序的第2、3、4行是3个mov指令,使ds和es两个段寄存器指向与cs相同的段,以便在以后进行数据操作的时候能定位到正确的位置。第5行调用子程序显示字符串,然后jmp
$让程序无限循环下去。
可能大部分人开始学汇编时用的都是MASM,其实NASM的格式跟MASM总体上是差不多的,在这段程序中,值得说明的地方有以下几点:
(1)在NASM中,任何不被方括号[]括起来的标签或变量名都被认为是地址,访问标签中的内容必须使用[]。所以,
mov ax, BootMessage
将会把“Hello, OS world!”这个字符串的首地址传给寄存器ax。又比如,如果有:
foo dw 1
则mov ax, foo将把foo的地址传给ax,而mov bx, [foo]将把bx的值赋为1。
实际上,在NASM中,变量和标签是一样的,也就是说:
foo dw 1 ≡ foo: dw 1
而且你会发现,Offset这个关键字在NASM也是不需要的。因为不加方括号时表示的就是Offset。
笔者认为这是NASM的一大优点,要地址就不加方括号,也不必额外地用什么Offset,想要访问地址中的内容就必须加上方括号。代码规则非常鲜明,一目了然。
(2)关于$和$$。$表示当前行被汇编后的地址。这好像不太好理解,不要紧,我们把刚刚生成的二进制代码文件反汇编来看看:
ndisasmw -o 0x7c00 boot.bin >> disboot.asm
打开disboot.asm,你会发现这样一行:
00007C09  EBFE              jmp short 0x7c09
明白了吧,$在这里的意思原来就是0x7c09。
那么$$表示什么呢?它表示一个节(section)的开始处被汇编后的地址。在这里,我们的程序只有1个节,所以,$$实际上就表示程序被编译后的开始地址,也就是0x7c00。
注意:这里的section属于NASM规范的一部分,表示一段代码,关于它和$$更详细的注解请参考NASM联机技术文档。
 
在写程序的过程中,$-$$可能会被经常用到,它表示本行距离程序开始处的相对距离。现在,你应该明白510-($-$$)表示什么意思了吧?times
510-($-$$) db
0表示将0这个字节重复510-($-$$)遍,也就是在剩下的空间中不停地填充0,直到程序有510B为止。这样,加上结束标志0xAA55占用的2B,恰好是512B
 
即便是非常袖珍的程序,也有可能遇到不能正确运行的情况,对此你一定并不惊讶,谁都可能少写一个标点,或者在一个小小的逻辑问题上犯迷糊。好在我们可以调试,通过调试,可以发现错误,让程序日臻完美。但是对于操作系统这样的特殊程序,我们没有办法用普通的调试工具来调试。可是,哪怕一个小小的Boot
Sector,我们也没有十足的把握一次就写好,那么,遇到不能正确运行的时候该怎么办呢?在屏幕上没有看到我们所要的东西,甚至于机器一下子重启了,你该如何是好呢?
每一个问题都是一把锁,你要相信,世界上一定存在一把钥匙可以打开这把锁。你也一定能找到这把钥匙。
一个引导扇区代码可能只有20行,如果Copy&Paste的话,10秒钟就搞定了,即便自己敲键盘抄一遍下来,也用不了10分钟。可是,在遇到一个问题时,如果不小心犯了小错,自己到运行时才发现,你可能不得不花费10个10分钟甚至更长时间来解决它。笔者把这20行的程序称做水面以上的冰山,而把你花了数小时的时间做的工作称做水面下的冰山。
古人云:“授之以鱼,不如授之以渔。”本书将努力将冰山下的部分展示给读者。这些都是笔者经历了痛苦的摸索后的一些心得,这些方法可能不是最好的,但至少可以给你提供一个参考。
好了,以Boot Sector为例,你可以想像得到,将来我们一定会对这20行进行扩充,最后得到200行甚至更多的代码,我们总得想一个办法,让它调试起来容易一些。其实很容易,我们只要把“org 07c00h”这一行改成“org  0100h”就可以编译成一个.COM文件让它在DOS下运行了。我们来试一试,首先把07c00h改成0100h,编译:nasm boot.asm –o boot.com好了,一个易于执行和调试的Boot Sector就制作完毕了。调试.COM文件可能让你仿佛一下子回到了20世纪,没关系,怀旧一下感觉还是蛮不错的。
 
 
阅读(1222) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:ocsp证书状态查询

给主人留下些什么吧!~~