9 开始导入C语言
终于准备就绪,现在我们直接切换到32位模式,然后运行用C语言写的程序。这就是projects/03_day下的harib00i。
程序里添加和修改了很多内容。首先是haribote.sys,它的前半部分是用汇编语言编写的,而后半部分则是用C语言编写的。所以以前的文件名haribote.nas也随之改成了asmhead.nas。并且,为了调用C语言写的程序,添加了100行左右的汇编代码。
虽然笔者也很想现在就讲这100行新添的程序,但是很抱歉,还是先跳过这部分吧。等我们再往后多学一点,再回过头来仔细讲解这段程序。其实笔者曾多次对这一部分进行说明,但每次都写得很长很复杂,恐怕大家很难理解。等到后面,大家掌握的内容多了,这一部分再理解起来也就轻松了,所以暂时先不做说明了。
下面讲C语言部分。文件名是bootpack.c。为什么要起这样的名字呢?因为以后为了启动操作系统,还要写各种其他的处理,我们想要把这些处理打成一个包(pack),所以就起了这么一个名字。最重要的核心内容非常非常短,如下所示:
本次的bootpack.c
void HariMain(void) { fin: /*这里想写上HLT,但C语言中不能用HLT! */ goto fin; }
这个程序第一行的意思是:现在要写函数了,函数名字叫HariMain,而且不带参数(void),不返回任何值。“{}”括起来的部分就是函数的处理内容。
C语言中所说的函数是指一块程序,在某种程度上可以看作数学中的函数一般,即从变量x取得值,将处理结果送给y。而上面情况下,既不从变量取得值,也不返回任何值,不太像数学中的函数,但在C语言中这也是函数。
goto指令是新出现的,相当于汇编语言中的JMP,实际上也是被编译成JMP指令。
由“/*”和“*/”括起来的部分是注释,正如这里所写的那样,C语言中不能使用HLT,也没有相当于DB的命令,所以不能用DB来放一句HLT语句。这让喜欢HTL语句的笔者感觉很是可惜。
■■■■■
那么,这个bootpack.c是怎样变成机器语言的呢?如果不能变成机器语言,就是说得再多也没有意义。这个步骤很长,让我们看一看。
❏ 首先,使用cc1.exe从bootpack.c生成bootpack.gas。
❏ 第二步,使用gas2nask.exe从bootpack.gas生成bootpack.nas。
❏ 第三步,使用nask.exe从bootpack.nas生成bootpack.obj。
❏ 第四步,使用obi2bim.exe从bootpack.obj生成bootpack.bim。
❏ 最后,使用bim2hrb.exe从bootpack.bim生成bootpack.hrb。
❏ 这样就做成了机器语言,再使用copy指令将asmhead.bin与bootpack.hrb单纯结合到起来,就成了haribote.sys。
来来去去搞出了这么多种类的文件,那么下面就简单介绍一下吧。
cc1是C编译器,可以将C语言程序编译成汇编语言源程序。但这个C编译器是笔者从名为gcc的编译器改造而来,而gcc又是以gas汇编语言为基础,输出的是gas用的源程序。它不能翻译成nask。
所以我们需要把gas变换成nask能翻译的语法,这就是gas2nask。解释一下这个名字。英语中的“从A到B”说成 “from A to B”,省略一下,就是“A to B”。这里把“to”写成“2”,世界上开发工具的人有时会这么写(这是英语中的谐音,2与to同音)。所以,gas2nask的意思就是“把gas文件转换成nask文件的程序”。
一旦转换成nas文件,它可就是我们的掌中之物了,只要用nask翻译一下,就能变成机器语言了。实际上也正是那样,首先用nask制作obj文件。obj文件又称目标文件,源自英文的“object”,也就是目标的意思。程序是用C语言写的,而我们的目标是机器语言,所以这就是“目标文件”这一名称的由来。
可能会有人想,既然已经做成了机器语言,那只要把它写进映像文件里就万事大吉了。但很遗憾,这还不行,事实上这也正是使用C语言的不便之处。目标文件是一种特殊的机器语言文件,必须与其他文件链接(link)后才能变成真正可以执行的机器语言。链接是什么意思呢?实际上C语言的作者已经认识到,C语言有它的局限性,不可能只用C语言来编写所有的程序,所以其中有一部分必须用汇编来写,然后链接到C语言写的程序上。
现在为止,都只有一个源程序,由它来直接生成机器语言文件,这好像是理所当然的,完全不用考虑什么目标文件的链接。但是这个问题以后要考虑了。下面我们来讲一下用汇编语言做目标文件的方法。
所以,为了将目标文件与别的目标文件相链接,除了机器语言之外,其中还有一部分是用来交换信息的。单个的目标文件还不是独立的机器语言,其中还有一部分是没完成的。为了能做成完整的机器语言文件,必须将必要的目标文件全部链接上。完成这项工作的,就是obj2bim。bim是笔者设计的一种文件格式,意思是“binary image”,它是一个二进制映像文件。
映像文件到底是什么呢?这么说来,磁盘映像也是一种映像文件。按笔者的理解,所谓映像文件即不是文件本来的状态,而是一种代替形式。英文里面说到image file,一般是指图像文件,首先要有一个真实的东西,而它的图像则是临摹仿造出来的,虽然跟它很像,但毕竟不是真的,只是以不同的形式展示出原物的映像。不是常有人这么讲吗,“嗯,搞不懂你在说什么。能不能说得再形象一点儿?”,也就是说“如果直接说明起来太困难的话,可以找个相似的东西来类比一下。”所谓类比,“不是本来的状态,而是一种代替的形式”。……映像文件大致也就是这个意思。
所以,实际上bim文件也“不是本来的状态,而是一种代替的形式”,也还不是完成品。这只是将各个部分全部都链接在一起,做成了一个完整的机器语言文件,而为了能实际使用,我们还需要针对每一个不同操作系统的要求进行必要的加工,比如说加上识别用的文件头,或者压缩等。这次因为要做成适合“纸娃娃操作系统”要求的形式,所以笔者为此专门写了一个程序bim2hrb.exe,这个程序留到后面来介绍。
■■■■■
可能有人会想:“我在Windows和Linux上做了很多次C程序了,既没用过那么多工具,也没那么多的中间文件就搞定了,这次是怎么回事呢?”说到底,这是因为那些编译器已经很成熟了。
但是,如果我们的编译器能够直接生成可执行文件,那再想把它用于别的用途可就难了。其实在编译器内部也要做同样的事,只是在外面看不见这些过程而已。这次提供的编译器,是以能适应各种不同操作系统为前提而设计的,所以对内部没有任何隐藏,是特意像这样多生成一些中间文件的。
这样做的好处是仅靠这个编译器,就可以制作Windows、Linux以及OSASK用的可执行文件,当然,还有我们的“纸娃娃操作系统”的可执行文件。
根据以上内容,对Makefile也做了很大改动。如果大家想知道编译时指定了什么样的选项,可以看一看Makefile。
■■■■■
啊,忘了一件大事。函数名HariMain非常重要,程序就是从以HariMain命名的函数开始运行的,所以这个函数名不能更改。
执行这个函数,结果出现黑屏。这表示运行正常。