自制操作系统10-自已搭建制作工具

在第三篇文章我想用nasm与c来开发我们的操作系统,但当时最终还是用了作者现成的工具做的镜像文件。在学完汇编语言后,再来尝试。


1.汇编语言的引导程序。

第二天虽然已经实现了用汇编语言编写hello word,但这个显示只是引导区(0扇区),软盘启动都会读取。第三天我们把引导文件拆成了ipl10.nas与haribote.nas。同样今天我们今天还用这两个文件,不过我们编译工具换成nasm,生成映像文件工具改成我们自己用java写的工具。
ipl10.nas与第三天的一样:
; haribote-ipl
; TAB=4

CYLS    EQU        10                ; 读取到哪里?

        ORG        0x7c00            ; 这个程序要读取到哪里?

; 以下是标准FAT 12格式软盘的描述

        JMP        entry
        DB        0x90
        DB        "HARIBOTE"        ; 可以自由写启动扇区的名字(8字节)
        DW        512                ; 一个扇区的大小(必须是512)
        DB        1                ; 集群大小(必须是一个扇区)
        DW        1                ; FAT从哪里开始(一般从第一扇区开始)
        DB        2                ; FAT的个数(必须设为2)
        DW        224                ; 根目录区域的大小(通常为224个条目,FAT里的概念)
        DW        2880            ; 该驱动器的大小(必须是2880扇区)
        DB        0xf0            ; 媒体类型(必须为0xf0)
        DW        9                ; FAT区域的长度(必须是9个扇区)
        DW        18                ; 每个柱面上有几个扇区(必须要18个扇区)
        DW        2                ; 头的数量(必须是2)
        DD        0                ; 因为没有使用分区,所以这里必须是0
        DD        2880            ; 再写一次这个驱动器的大小
        DB        0,0,0x29        ; 不清楚,最好是这样
        DD        0xffffffff        ; 可能是卷序列号
        DB        "HARIBOTEOS "    ; 磁盘名称(11字节)
        DB        "FAT12   "        ; 格式名称(8字节)
        RESB    18                ; 总之先空出18个字节

; 程序主体

entry:
        MOV        AX,0            ; 寄存器初始化
        MOV        SS,AX
        MOV        SP,0x7c00
        MOV        DS,AX

; 读磁盘

        MOV        AX,0x0820
        MOV        ES,AX
        MOV        CH,0            ; 柱面0
        MOV        DH,0            ; 磁头0
        MOV        CL,2            ; 扇区2
readloop:
        MOV        SI,0            ; 计算失败次数的寄存器
retry:
        MOV        AH,0x02            ; AH=0x02 : 磁盘装入
        MOV        AL,1            ; 1扇区
        MOV        BX,0
        MOV        DL,0x00            ; A型驱动器
        INT        0x13            ; 磁盘BIOS调用
        JNC        next            ; 如果不发生错误,请向next发送
        ADD        SI,1            ; 在SI上加1
        CMP        SI,5            ; 比较SI和5
        JAE        error            ; SI >= 5 那就去error吧
        MOV        AH,0x00
        MOV        DL,0x00            ; A型驱动器
        INT        0x13            ; 驱动器复位
        JMP        retry
next:
        MOV        AX,ES            ; 使地址进0x200
        ADD        AX,0x0020
        MOV        ES,AX            ; ADD ES,0x020 没有这样的命令,所以这样做
        ADD        CL,1            ; 在CL上加1
        CMP        CL,18            ; 比较CL和18
        JBE        readloop        ; CL <= 18 那就去readloop吧
        MOV        CL,1
        ADD        DH,1
        CMP        DH,2
        JB        readloop        ; DH < 2 那就去readloop吧
        MOV        DH,0
        ADD        CH,1
        CMP        CH,CYLS
        JB        readloop        ; CH < CYLS 那就去readloop吧

; 读完了10柱面,开始读haribote.sys

        MOV        [0x0ff0],CH        ; 记下IPL读到哪里了
        JMP        0xc200

error:
        MOV        SI,msg
putloop:
        MOV        AL,[SI]
        ADD        SI,1            ; 在SI上加1
        CMP        AL,0
        JE        fin
        MOV        AH,0x0e            ; 单字显示功能
        MOV        BX,15            ; 彩色代码
        INT        0x10            ; 视频BIOS调用
        JMP        putloop
fin:
        HLT                        ; 让CPU停止,直到发生什么。
        JMP        fin                ; 无限循环
msg:
        DB        0x0a, 0x0a        ; 两个换行符
        DB        "load error"
        DB        0x0a            ; 改行
        DB        0

        ;RESB    0x7dfe-$        ;
        times    510-($-$$) db 0 ; 以0x00填充到0x7dfe为止的命令

        DB        0x55, 0xaa


haribote.nas源码如下:
; haribote-os
; TAB=4

        ORG        0xc200            ; このプログラムがどこに読み込まれるのか

        MOV        AL,0x13            ; VGA图形,320x200x8 bit颜色
        MOV        AH,0x00
        INT        0x10
fin:
        HLT
        JMP        fin

这个程序就是定位到内存的0xc200,然后显示个黑屏。int 0x10是显示器中断,关于BIOS基本的中断编号与功能,可参考《汇编语言程序设计-从DOS到Windows》下图:

这三行调用,就是让显示器清屏幕,13是模式号。生成目标文件用以下两句命令:
nasm ipl10.asm -o ipl10.bin
nasm haribote.asm -o haribote.bin
然后我们写一个生成镜像文件的java程序,这两个目标文件作为输入:

package day3;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class CreateOSImg3 {

    
    public static void main(String[] args) throws Exception {
        //写入0磁道,从这里加载
        FileInputStream fis=new FileInputStream(new File("/Users/chengzhong/work/30_workspace/03_day/cz_work/ipl10.bin"));
        //写入0x4200,启动区,系统入口
        FileInputStream fis2=new FileInputStream(new File("/Users/chengzhong/work/30_workspace/03_day/cz_work/haribote2.bin"));
        FileOutputStream fos=new FileOutputStream(new File("/Users/chengzhong/work/30_workspace/03_day/cz_work/javaos3.img"));
        int totalLen=1474560;
        byte src[]=new byte[fis.available()];
        fis.read(src);
        
        
        //总共有1474560个字节,
        for(int i=0;i<totalLen;i++){
            if(i<src.length) {
                fos.write(src[i]);
            }else if(i>=0x4200&&i<(0x4200+fis2.available())) {
                fos.write(fis2.read());
            }else {
                fos.write(0);
            }
        }
        fis.close();
        fis2.close();
        fos.close();

    }

}

运行映像文件,可以看到效果与作者的工具生成的文件效果一样。


2.把c语言的机器码放进软盘

c语言生成的文件放到映像文件的过程比较复杂,《30天自制操作系统》是这样做的:

我们现在要做的事,使用通用的开源软件来替换作者提供的cc1,nask等工具.因为这些工具屏蔽了一些操作,且没有文档,不利于我们后面自主开发。当然对于和我一样c语言与汇编开发经验不足的人来说是有些难度。但经过几天的研究,初步实现了这一目标。

首先,我们用gcc生成obj2bim.exe与bim2hrb.exe这两文件。这两个文件涉及链接过程,但我们目前不用了解编译原理及其内部细节也能干活。这两个文件用作者提供的源码和MinGW就可以正常的生成,真是太好了。

这里先说明下环境:

win7,64位,MinGW32位,nasm x86安装包。环境变量已配好,可使用gcc,nasm命令。

cd 光盘文件/omake/tolsrc/bim2hrb
gcc bim2hrb.c
这样就生成了bim2hrb.exe

cd 光盘文件/omake/tolsrc/obj2bi4d
gcc -c obj2bim.c
gcc -c autodec_.c
gcc obj2bim.o autodec_.o -o obj2bim.exe
这样就生成了obj2bim.exe

然后,我们处理c语言如何编译与链接的问题。作者的做法如上图,都转成了nas,再用他的nask那一套工具来生成。我尝试成功的方案是这样,先用gcc生成汇编文件,再用as工具(gcc带的)生成目标文件。

还有对汇编文件的编译,对于ipl10与asmhead,直接用以下命令生成最终机器语言文件即可:
nasm asmhead.asm -o asmhead.bin
nasm ipl10.asm -o ipl10.bin
但对于naskfunc(一个汇编程序文件),因为c语言要调用他的函数,所以不能直接生成机器语言文件。而要先生成目标文件,才能保留里面的函数名等信息。命令如下:
nasm -f coff naskfunc.asm -o naskfunc.obj

文件都准备好了就可以用obj2bim把c语言与汇编文件链接到一起了,命令如下:
obj2bim.exe @光盘文件\tools\haribote\haribote.rul out:bootpack.bim stack:3136k map:bootpack.map bootpack.obj  naskfunc.obj
看到这儿有人可能会问haribote.rul是什么?我打开发现是个配置文件,他依赖了两个lib
harilibc.lib与golibc.lib 。这是两静态连接库文件。有人就要说了,你这搞得不彻底啊,怎么还有未知(无源码)文件?其实我是研究过这两文件的生成的,但c语言功底不行,没有搞定。他的生成依赖了cc1等,如果要彻底搞清楚,先得把cc1编译一下,这个c的编译器太麻烦了。对C语言熟悉的同学相信能搞定的。

之后,再用这两工具:
bim2hrb.exe bootpack.bim bootpack.hrb 0
copy /B asmhead.bin+bootpack.hrb haribote.sys
生成haribote.sys文件

最后是把这ipl10.bin与haribote.sys生成为一软盘映像文件,本来我以为可以用上面写的Java工具做这个事。但事与愿违,对比两个img文件,才想起来32位的寻址方式与16位不一样,还要考虑GDT等东西。edimg.exe这个工具生成:
cd 光盘文件/omake/tolsrc/edimg0j
gcc -c autodec_.c
gcc -c edimg.c
gcc edimg.o autodec_.o -o edimg.exe

edimg.exe的使用:
edimg.exe   imgin:光盘文件/z_tools/fdimg0at.tek wbinimg src:ipl10.bin len:512 from:0 to:0 copy from:haribote.sys to:@: imgout:haribote.img


效果与第三天的一样:

现在文件已经不少了,可以用make管理起来了,我们用之前介绍的gnumake来打包。
把文件整理一下,工具放进tools文件夹,生成的文件放到bin文件夹:

写如下Makefile文件:

default:
    gcc -S  bootpack.c -o bin/bootpack.s
    as -o bin/bootpack.obj  bin/bootpack.s
    nasm asmhead.asm -o bin/asmhead.bin
    nasm -f coff naskfunc.asm -o bin/naskfunc.obj
    nasm ipl10.asm -o bin/ipl10.bin
    tools/obj2bim.exe @tools\haribote\haribote.rul out:bin/bootpack.bim stack:3136k map:bin/bootpack.map bin/bootpack.obj  bin/naskfunc.obj
    tools/bim2hrb.exe bin/bootpack.bim bin/bootpack.hrb 0
    copy /B bin\asmhead.bin+bin\bootpack.hrb bin\haribote.sys
    tools/edimg.exe   imgin:tools/fdimg0at.tek wbinimg src:bin/ipl10.bin len:512 from:0 to:0 copy from:bin/haribote.sys to:@: imgout:bin/haribote.img
clean:
    -del bin\bootpack.s
    -del bin\bootpack.obj
    -del bin\asmhead.bin
    -del bin\naskfunc.obj
    -del bin\ipl10.bin
    -del bin\bootpack.bim
    -del bin\bootpack.map
    -del bin\bootpack.hrb
    -del bin\haribote.sys
    -del bin\haribote.img



下面用图总结一下,我们改造工具的方法,有颜色的代表对作者的工具还有依赖的步骤:


改造的这几天,都是摸着石头过河,说不定那一步就搞不定了。还好,其本都完成了。
这几天踩了一些坑在这记录下,不要在linux下或者windows的Cygwin使用gcc生成汇编文件,他们生成的都是linux风格的。后面再在window的nasm下生成obj文件,就不兼容了。
winxp已经安装不了MinGW了,不过可以用安装好的MinGW打个zip包放到xp里运行。可能win7 32位更适合本书相关代码的学习。


gas2nask工具的笔记,本文没用到,只为记录。
这步作者的工具是gas2nask.exe。这个工具比nask.exe的构建要简单些,于是我用作者提供的源码制作一个gas2nask.exe。
首先进入光盘文件\omake\tolsrc\go_0023s\toolstdc,键入命令:cl gas2nask.c就可以生成gas2nask.exe。这个比较简单,可以把gas2nask.c相关的源码文件转移一个新文件夹来生成。


文/中中 浏览次数:0次   2020-04-24 21:55:42

相关阅读


评论: