本文讨論的是AT&T彙編語言。
1.工具準備
Linux發行版
QEMU虛拟機
2.使用AT&T彙編語言編寫BootSector
.code16 #十六位彙編
.global _start #程式開始
.text
.equ BOOTSEG, 0x07c0 #equ定義常量;被BIOS識别為啟動扇區,裝載到記憶體0x07co處
#此時處于實彙編,記憶體尋址為 (段位址 << 4 +量) 可尋址的線性空間為 20位
ljmp $BOOTSEG,$_start #修改cs寄存器為BOOTSEG,并跳轉到_start處執行代碼
_start:
mov $BOOTSEG,%ax #ax = BOOTSEG
mov %ax,%es #設定ES寄存器,為輸出字元串作準備
mov $0x03,%ah #在輸出資訊前讀取光标位置儲存在DX裡,DH為行,DL為列
xor %bh,%bh
int $0x10
mov $20,%cx #設定輸出長度 cx = 20
mov $0x0007,%bx #page 0, attribute 7 (normal) 設定必要的屬性
#lea msg1,%bp
mov $msg1,%bp
mov $0x1301,%ax #寫字元,移動光标 ax = 0x1301
int $0x10 #使用這個中斷0x10時,輸出所得的,因而要設定好 ES 和 BP
loop_forever: #一直循環
jmp loop_forever
sectors:
.word 0
msg1:
.byte 13,10
.ascii "Hello world!"
.byte 13,10,13,10
.=0x1fe #對齊文法,等價于.org,表示在該處補0,即第一扇區的最後兩位元組
#在此填充魔術值,BIOS會識别硬碟中第一扇區,以0xaa55結尾的為啟動扇區,于是BIOS會裝載
boot_flag:
.word 0xAA55
3.在QEMU中啟動這個引導
假設這個BootSector彙編代碼的檔案名是Lesson1.s。
彙編
as -32 -o Lesson1.o Lesson1.s
這是關于as指令比較詳細的文檔:
https://www.ibm.com/support/knowledgecenter/zh/ssw_aix_71/com.ibm.aix.cmds1/as.htm
as支援-32和-64,參數中寫-32。
彙編出的目标檔案Lesson1.o符合要求的标志是,執行這段語句
file Lesson1.o
得到的是
Lesson1.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
連結
ld -m elf_i386 -Ttext 0 -o Lesson1.bin Lesson1.o
elf-i386 和-Ttext 0兩個參數是必須的。-T設定輸出檔案的文本部分的開始位址到T後緊跟的數字,_text用于指定程式的第一個位置。
ld預設會給代碼内所有的偏移加上0x08048000,使用-Ttext 0會讓ld給代碼内所有的偏移加上0,這樣相當于保留了符号引用的原值。
這是關于ld指令比較詳細的文檔:
https://www.ibm.com/support/knowledgecenter/zh/ssw_aix_71/com.ibm.aix.cmds3/ld.htm
連結得到Lesson1.bin。
修改目标檔案
這段是本文最重要的地方。修改目标檔案是十分必要的。我們需要了解ELF格式和BIN格式的差別:
BIN格式即 raw binary,這種檔案隻包含機器碼;
ELF格式除了機器碼外,還包含其他資訊,諸如段的加載位址,運作位址,重定位表,符号表等。
ELF格式的體積比對應的BIN格式要大。
前述的彙編出的.o檔案是ELF格式的檔案,而此處我們需要讓QEMU使用BIN格式的鏡像。
關于QEMU和鏡像格式:http://www.10tiao.com/html/625/201410/201566704/1.html
objcopy -O binary Lesson1.bin
這句話可将ELF 32-bit的Lesson1.bin轉化為BIN格式。
Lesson1.bin符合要求的标志是,執行這段語句
file Lesson1.bin
得到的是:
Lesson1.bin: DOS/MBR boot sector
在QEMU中啟動
然後,恭喜你打開了OS世界的大門,Hello world!qemu-system-i386 Lesson1.bin