第一天,算是正式开始了,这一天我们在前面部分会做出一个在完全没有任何操作系统的基础上打印一句话。但是我们不会写任何一句代码。而是利用一个工具,一个二进制的工具。在这里讲一个故事, 不过是个假的故事,但理论上却又可行。据说啊,某天深夜,女神电脑坏了,找到了旁边的程序员小哥哥,需要重装,不过恰巧这时候没有下载操作系统,那咋办呢,于是那个程序员说没事我来想办法,然后一个通宵过后,电脑好了,原来是这个程序员拿了一个二进制编辑器,手按了一个操作系统出来,原文大家可以在网上找找,后来被人证实这件事是在一晚上不可能完成的,而且这也需要高超的记忆力。
本章作者用的是c.mos公司的一款二进制编辑器,然后就按着作者说的开启了漫长的按键,当然我没有去做这件事,我是直接用的作者光盘里生成好的img文件。按着作者的方式下来后,这就是一个操作系统了,不过他的功能非常非常简单,直是在屏幕上输出了hello,world。执行这个img也非常简单,按照笔者说的,就行,注意把路径改成你真是的路径,否则run的时候会报错。
好了,来理解下刚才按了那么久的键盘做了些啥(虽然我没有做)计算机只认识0和1这是一个计算机系人的常识了,犹如图中,计算机要显示出一个笑脸娃娃,就是由0和1来拼凑的。有了0和1那么我们就可以把他变成0-9,甚至其他任何进制。有了这个玩意儿,我们给每一个数字对应一个编号,然后他就可以完全模拟26个英文字母了(最初估计那波人压根儿没考虑要支持其他语言)哪怕是一段音乐,文字,图像,程序,等等的东西都是由二进制组成。那么这时也不难理解为啥刚才敲了一堆二进制能做出一个操作系统来,当然你敲一段二进制然后说这个二进制就是一张图片,那也可以。。 所以二进制编辑器这玩意儿太强大了,不过就是不方便(手动滑稽)。什么photoshop要钱买?我可以手动用二进制写一个啊。在输入二进制的时候,在右边会对应十六进制,至于进制这些转换就不细说了,网上也是相当多的资料片。
接下来就弄点搞得懂的,或者说来点实际的。笔者给了一个超长源代码。。。我也没有再工程里找到。按照笔者说的方式应该也能做出一个img文件。不过找到了后来精简的helloos.nas,首先这里面有几个新指令是汇编的,DB是往文件里写入一个字节的指令(我觉得至于何是字节等问题大家请自行学习)然后就是RESB指令,看作者的意思是预定十个字节并填充为0,这确实是帮了大忙呀。
虽然程序已经相比之前比较短了,关键是我们就是难以看懂,难以维护。所以呢,下面让我们来看看我们读得懂的东西吧。。。。
; hello-os
; TAB=4
; 以下这段是标准FAT12格式软盘专用的代码
DB 0xeb, 0x4e, 0x90
DB "HELLOIPL" ; 启动区的名称可以实任意的字符串(8字节)
DW 512 ; 每个扇区(sector)的大小(必须为512字节)
DB 1 ; 族(cluster)的大小(必须为1个扇区)
DW 1 ; FAT的起始位置(一般从第一个扇区开始)
DB 2 ; FAT的个数(必须为2)
DW 224 ; 根目录的大小(一般设成224项)
DW 2880 ; 该磁盘的大小(必须是2880扇区)
DB 0xf0 ; 磁盘的种类(必须是0xf0)
DW 9 ; FAT的长度(必须是9扇区)
DW 18 ; 一个磁道(track)有几个扇区(必须是18)
DW 2 ; 磁头数(必须是2)
DD 0 ; 不适用分区,必须是0
DD 2880 ; 重写一次磁盘大小
DB 0,0,0x29 ; 意义不明,固定
DD 0xffffffff ; (可能是)卷标号码
DB "HELLO-OS " ; 磁盘的名称(11字节)
DB "FAT12 " ; 磁盘格式名称(8字节)
RESB 18 ; 空出18字节
; 程序主体
DB 0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
DB 0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
DB 0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
DB 0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
DB 0xee, 0xf4, 0xeb, 0xfd
; 信息显示部分
DB 0x0a, 0x0a ; 2个换行
DB "Hello, world"
DB 0x0a ; 换行
DB 0
RESB 0x1fe-$ ; 填写0x00直到0x001fe
DB 0x55, 0xaa
; 以下是启动区以外部分的输出
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
RESB 4600
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
RESB 1469432
来进行解释一下,DB,当我们要写一个字符串的时候,如果在纯二进制下,我们需要知道他的编码,但是有了这个指令,他会自动去帮我们算出所需对应编码
DW是写一个word其含义就是16字节,DD就是写一个32字节,当然要写8位的话可以把16位拆成高8位和低8位。
RESB是预留多少字节,但是这里有两个疑问点一个是为什么是0x1fe和$是什么,首先来看看第一个疑问点,一开始我也没往后看的时候也有点疑问,但是把0x1fe一换算成十进制就明了了510 ,再结合很早以前就知道计算机读取磁盘会读取第一个扇区,就是512个字节,然后这512个字节里面最后两个必须是0x55,0xaa,减去后正好510字节,个所以恍然大悟。然后再来看看第二个疑问,这是nask编译器的功能算出当前已经用了多少字节,当然这里笔者的作用就是为了凑够512个字节。当然有可能前面就超过了510字节,当然,真正的操作系统不会这样的,因为这个算是引导扇区,只会写引导逻辑所以不用担心这个问题。
关于作者后面给了一些术语相关的解释,大部分都比较简单。
我说一下几个比较重要的,第一个是启动区,正如我前面所说,计算机启动的时候会去读取磁盘的第一个扇区。至于何为扇区,请自行恶补。然后回去看这个扇区的后两个字节是否是0x55,0xaa。
第二个IPL启动程序加载器,也正如上面所说512个字节不能做不了太多的逻辑,但是,它可以作为一个起点。举个例子,有点像main函数,一般大型点儿的项目main函数里只会做一些框架的启动,而不会在这个main函数里做太多的逻辑。
今天就这样,从二进制到我们能看得懂的过程,仔细品味很有意思,不过还有太多的问什么等着我们的,例如那个程序中每一行代码什么意思。。
我曾读到过一句话,对知识的深究一定要有个限度。不然你是永远学不完的。