开发OS的第二天

&学习Makefile

编写NAS汇编文件

这里附件给的源文件已经是纯粹的汇编代码+数据组成了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
; hello-os
; TAB=4

ORG 0x7c00 ; 指明程序装载地址

; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code

JMP entry
DB 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扇区1440*1024/512)
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字节

; 程序主体

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

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 "hello, xia0ji233"
DB 0x0a ; 换行
DB 0

TIMES 0x1fe-($-$$) DB 0x00 ; 填写0x00直到0x001fe

DB 0x55, 0xaa

这里有些知识点需要注意一下

ORG 汇编指令指明程序装载的地址,整个地址是有讲究的,因为我们现在是 OS 开发者,我们必须规划整个内存,不能跟 BIOS 抢了内存。0x7c00 这个地址是我们最低可用的内存,因此我们的操作系统加载在这里。我们把地址 0x00007c00~0x00007dff 作为我们启动区的地址。

在屏幕上打印文字需要使用中断去调用显卡的函数,这里我们把寄存器设为这些状态即可:

  • AH:0x0e
  • AL:ch
  • BH:0
  • BL:color

然后进入中断的方法为 int 0x10

Makefile编写

先从网上的资料上拷贝一些 Makefile 的基本信息下来。

什么是 Makefile ?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员, Makefile 还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写 Makefile 了,会不会写 Makefile ,从一个侧面说明了一个人是否具备完成大型工程的能力。

因为, Makefile 关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中, Makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 Makefile 就像一个Shell脚本一样,其中也可以执行操作系统的命令。

Makefile 带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释 Makefile 中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见, Makefile 都成为了一种在工程方面的编译方法。

然后来说说我对于 Makefile 的直观理解吧。首先它的基本格式是这样的:

1
2
3
4
label: prerequisites...
command1
command2
...

这里的 label 就是你 Makefile 的标签,后面所跟着的是检查所需的文件,如果文件存在则会直接执行下面的命令,如果文件不存在则需要在 Makefile 中寻找生成这些文件的方式之后,执行完对应的选项,再看看有没有这个文件,有的话就可以执行下面的命令了,如果执行完了生成那个文件的选项依然没有该文件,那么就会报错退出。

使用 make 命令编译的时候,会先找到当前目录下的 Makefile 文件,并根据你命令行的第二个参数决定要执行哪个标签下的命令。

并且它很聪明,它会根据已有文件的修改日期判断当前是否需要编译,若所需文件的最后修改日期 早于 目标文件的最后修改日期,那么它不会进行编译这个文件的操作。

这里我们这样编写 Makefile 文件

1
2
3
4
ipl.img:ipl.nas
nasm ipl.nas -o ipl.img
run:
qemu-system-x86_64 -drive file=ipl.img,if=floppy

所以我们编译就只需要 make,运行就只需要 make run 了。

运行结果


这一章只是把昨天的字节码变成了汇编码让 nasm 去汇编成机器码,这样让我们编程更加方便了,不过今天还额外学了一下 Makefile 的用法,挺开心的。