30天自制操作系统——第二天汇编语言学习和Makefile入门
今天的任务是汇编语言和寄存器学习、制作启动区、Makefile入门
里面用到的文件,都在文末的链接里。
下面是采用汇编语言编写的helloos.nas文件,是不是比前一版好读多了:
; hello-os
; TAB=4
ORG 0x7c00 ; 指明程序的装载地址
; 以下这段是标准FAT12格式软盘专用的代码
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扇区)
DB 0xf0 ; 磁盘的种类(必须是0xf0)
DW 9 ; FAT的长度(必须是9扇区)
DW 18 ; 1个磁道(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 ; 换行2次
DB "hello, world"
DB 0x0a ; 换行
DB 0
RESB 0x7dfe-$ ; 填写0x00,直到0x7dfe
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
汇编语言
学习一下上面新出现的汇编指令——
ORG指令:该指令会告诉编译器,在开始执行时机器语言指令装载到内存中的指定地址。
JMP指令:类似于C语言的goto语句。
MOV指令:赋值的意思,例如 “MOV AX,0” 相当于"AX = 0",“MOV SS,AX”相当于 SS=AX。
ADD指令:加法指令,“ADD SI,1”,就是SI=SI+1。
CMP指令:比较指令,“CMP AL,0”,就是将AL中的值与0比较。
JE指令:条件跳转指令,就是根据比较结果决定跳转或者不跳转。若比较结果相等,则跳转到指定地址;若比较结果不相等,则不跳转,继续执行下一条指令。
INT指令:软件中断指令,类似于函数调用。
HLT指令:CPU停止动作的指令,并不是彻底地停止,而是让CPU进入待机状态。
寄存器
寄存器是CPU中的一种存储电路,在机器语言中,相当于变量。下面列举了8个具有代表性的16位寄存器,可以存储16位的二进制数。
AX(accumulator)—— 累加寄存器
CX(counter)—— 计数寄存器
DX(data)—— 数据寄存器
BX(base)—— 基址寄存器
SP(stack pointer)—— 栈指针寄存器
BP(base pointer)—— 基址指针寄存器
SI(source index)—— 源变址寄存器
DI(destination index)—— 目的变址寄存器
另外CPU还有8个8位寄存器,这8个寄存器并非扩展了存储能力,而是分别表示了AX、CX、DX、BX四个寄存器的低位和高位。比如AX寄存器有16位,其中0到7的低8位称为AL,8到15位高8位称为AH。
AL(accumulator low)—— 累加寄存器低位
CL(counter low)—— 计数寄存器低位
DL(data low)—— 数据寄存器低位
BL(base low)—— 基址寄存器低位
AH(accumulator high)—— 累加寄存器高位
CH(counter high)—— 计数寄存器高位
DH(data high)—— 数据寄存器高位
BH(base high)—— 基址寄存器高位
还有一类寄存器叫段寄存器,这些段寄存器都是16位的。
ES(extra segment)—— 附加段寄存器
CS(code segment)—— 代码段寄存器
SS(stack segment)—— 栈段寄存器
DS(data segment)—— 数据段寄存器
FS(segment part2)—— 没有名称
GS(segment part3)—— 没有名称
制作启动区
将hellooos.nas的后半部分截掉,生成启动区,启动区的大小只有512字节。使用命令nask.exe ipl.nas ipl.bin ipl.lst,生成ipl.bin、ipl.1st两个文件。

其中ipl.1st是一个文本文件,可以用来确认每个指令是怎样翻译成机器语言的。
我们再次制作一遍helloos.img,不同的是这次以ipl.bin文件为基础。准备好edimg.exe、fdimg0at.tek、ipl.bin文件(文件网盘里都会提供),在命令行输入命令:edimg.exe imgin:fdimg0at.tek wbinimg src:ipl.bin len:512 from:0 to:0 imgout:helloos.img。

发现helloos.img成功生成,启动区就制作好啦。
Makefile入门
Makefile就像是一个比较聪明的批处理文件,怎么个聪明法呢?
先生成一个不带扩展名的Makefile文件,写入如下内容:
# 文件生成规则
ipl.bin : ipl.nas Makefile
nask.exe ipl.nas ipl.bin ipl.lst
helloos.img : ipl.bin Makefile
edimg.exe imgin:fdimg0at.tek \
wbinimg src:ipl.bin len:512 from:0 to:0 imgout:helloos.img
分析一下上的代码——
#表示注释
ipl.bin : ipl.nas Makefile,意思是如果想要制作文件ipl.bin,需要先检查ipl.nas和Makefile两个文件是否都准备好了,如果都准备好了,Make工具会自动执行Makefile的下一行。
我们把helloos.img和ipl.bin都删除,再输入“make -r helloos.img”命令,make首先尝试生成helloos.img,但发现需要的ipl.bin不存在,就会自动寻找ipl.bin的生成方法。找到后,先生成ipl.bin文件,确认ipl.bin生成成功后,继续生成helloos.img。

若不删除helloos.img和ipl.bin,会输出一行helloos.img’ is up to date,helloos.img已经是最新版本了,不用再重新生成一次。若将ipl.nas中的输出信息更改,再执行一遍“make -r helloos.img,会发现make.exe又会从ipl.bin开始重新生成输出文件。make.exe不仅会判断输入文件是否存在,还会判断文件的更新日期,Makefile确实比批处理文件灵活很多。

百度网盘
链接:https://pan.baidu.com/s/1tjys6-wC_hRDqOPv0BXDvg
提取码:spxk
更多推荐


所有评论(0)