俺发现俺做操作系统的时候越来越迷糊,所以从来一遍吧🧐
这次参考的书籍是OrangeS一个操作系统的实现
nasm 的使用:
- NASM是一个80x86的汇编器
- 把汇编代码使用NASM编译
nasm boot.asm -o boot.bin
boot.asm文件
org 07c00h ; 告诉编译器程序加载到7c00处
mov ax, cs
mov ds, ax
mov es, ax
call DispStr ; 调用显示字符串例程
jmp $ ; 无限循环
DispStr:
mov ax, BootMessage
mov bp, ax ; ES:BP = 串地址
mov cx, 16 ; CX = 串长度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 000ch ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)
mov dl, 0
int 10h ; 10h 号中断
ret
BootMessage: db "Hello, OS world!"
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节
dw 0xaa55 ; 结束标志
- 把上面这段代码使用NASM编译
nasm boot.asm -o boot.bin
- 直接将.bin的后缀名改成.img就可以在虚拟机里运行了
- 使用软盘绝对扇区读写工具将这个文件写到一张空白软盘的第一个扇区
引导扇区
- 当计算机被打开时,它会进行加电自检,然后寻找启动盘,如果是选择从软盘启动,计算机就会检查软盘的0面0磁道1扇区,如果发现它以0xAA55结束,则BIOS认为它是一个引导扇区。当然,一个正确的引导扇区除了以0xAA55结束之外,还应该包含一段少于512字节的执行码
- 旦BIOS发现了引导扇区,就会将这512字节的内容装载到内存地址0000:7c00处,然后跳转到0000:7c00处将控制权彻底交给这段引导代码。到此为止,计算机不再由BIOS中固有的程序
来控制,而变成由操作系统的一部分来控制。
代码解释
- 在NASM中,变量和标签是一样的
foo dw 1
等价于roo: dw 1
- offset这个关键字在NASM中是不需要的,不加方括号时表示的就是Offset
$
表示当前行被汇编后的地址$$
表示一个节的开始处被汇编后的地址(0x7c00
)$ - $$
表示本行距离程序开始处的相对距离times 510-($-$$) db 0
表示将0这个字节重复510-($-$$)
遍,也就是在剩下的空间中不停地填充0,直到程序有510字节为止
调试
- 把
org 07c00h
这一行改写成org 0100h
编译成一个.COM文件
nasm boot.asm -o boot.com
- 使用
Turbo Debugger
在windows环境下进行调试 - 调试完之后要放到软盘上进行试验,我们需要再把0100h改成07c00h。改来改去比较麻烦,NASM提供了预编译宏
预编译宏
- 如果想要调试,就让第一行有效,想要做引导扇区,就把他注释掉
- 代码:
;%define _BOOT_DEBUG_ ; 制作 Boot Sector 时一定将此行注释掉!
; 去掉此行注释后可做成.COM文件易于调试:
; nasm Boot.asm -o Boot.com
%ifdef _BOOT_DEBUG_
org 0100h ; 调试状态, 做成 .COM 文件, 可调试
%else
org 07c00h ; BIOS 将把 Boot Sector 加载到 0:7C00 处
%endif
mov ax, cs
mov ds, ax
mov es, ax
call DispStr ; 调用显示字符串例程
jmp $ ; 无限循环
DispStr:
mov ax, BootMessage
mov bp, ax ; ES:BP = 串地址
mov cx, 16 ; CX = 串长度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 000ch ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)
mov dl, 0
int 10h ; int 10h
ret
BootMessage: db "Hello, OS world!"
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节
dw 0xaa55 ; 结束标志