? ? ? ? 在開始之前講個有意思的笑話。某日,一程序猿退休在家,閑來無事想學習書法。開始時候左思右想,不知如何下筆,突然靈光一閃提筆寫下了幾個大字,定睛一看“hello world”。
所以這里,國際慣例我這里也是按照hello world開始。OK。
? ? ? ? 編譯連接完成了以后,這個代碼必須是在MBR上大小為512個字節并且必須要以0xAA55結束,這里不要問我為啥子。我也不曉得,估計這個需要問IBM的PC開發的工程師為啥要這樣定。開機自檢完成以后PC會將MBR上的前512個字節的程序,讀取到內存0x0000:0x07c0處,然后跳轉到這個地址執行,這里執行的就是我們的程序。這個Hello world 程序相當簡單,調用0x10號中斷,完成清屏和顯示“terrycheng”。這個程序我是在ubuntu下面實際能夠編譯完成,在bochsrc能夠運行的。嘎嘎。
詳細代碼:boot.asm
.section .text
.global _start
.code16
#這個也很重要,因為這里實際PC還是在實模式下,也就說為16位的機器,所以這里的數據都是要16位的。
.extern main
_start:
movw %cx, %ax
movw %ax, %ds
movw %ax, %es
#上面3行的作用是設置數據段寄存器,這個時候PC跳轉到了0x0000:0x07c0處,所以CX寄存器地址為0x0000,然而其他的數據段確不是這個地址。
#所以需要設置和代碼段一樣否則后面的terrycheng這個數據,是找不到的。
call ClearScreen
#調用后面的ClearScreen函數,完成清屏。
movw $msgstr, %bp
movw $10,? ? %cx
call Display
#調用0x10號中斷,顯示terrycheng
1:
jmp 1b
#不解釋,死循環。
ClearScreen:
movw $0x0700,? %ax
movw $0x0000,? %cx
movw $0xFFFF,? %dx
int $0x10
ret
Display:
movw $0x1300, %ax
movw $0,? ? ? %dx
movw $0x000C, %bx
int $0x10
ret
msgstr:
.asciz? "terrycheng"
#terrycheng的數據位置。
len:
.int? ? . - msgstr
#計算terrycheng的長度
.org? ? 0x1fe,? 0x00
#進行填充,之前我說過的MBR大小必須為512個字節,所以這里就把后面的數據填充為0
.word? 0xaa55
#魔數 0xaa55。
下面是makefile:
TARGET=boot.img
OBJECTS=
CSRC=$(wildcard *.c)
COBJ=$(patsubst %.c,%.o,$(CSRC))
ASRC=$(wildcard *.asm)
AOBJ=$(patsubst %.asm,%.o,$(ASRC))
ALLSRC=$(ASRC) $(CSRC)
ALLOBJECTS=$(AOBJ) $(COBJ)
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
%.o : %.asm
$(AS) -o $@ $<
$(patsubst %.img,%.bin,$(TARGET)):$(ALLOBJECTS)
ld -Ttext 0x7c00 -e _start $(ALLOBJECTS)? -o $@
$(TARGET):$(patsubst %.img,%.bin,$(TARGET))
objcopy -R .note -R .comment -S -O binary $< $@
Debug:$(TARGET)
objdump -D -b binary -mi8086 $(TARGET)
cleanDebug:
rm -fr $(ALLOBJECTS) $(TARGET) $(patsubst %.img,%.bin,$(TARGET))
慣例,上圖上真相: