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 ;pop IP BootMessage: db "Hello, OS world!" times 510-($-$$)db 0 ;填充剩下的空間,使生成的二進制代碼恰好為512字節 dw 0xaa55 ;結束標志
以上是個非常簡單的操作系統helloworld源碼,用bochs加載後如下圖(bochs是個虛擬機,模擬操作系統加載),顯示了紅色的Hello,OS world,實際上是系統加載起來的樣子:
源碼解析:
1.org 07c00h和dw 0xaa55和times 510-($-$$) db 0
當計算機電源打開,會先進行加電自檢(POST),然後尋找啟動盤,如果是選擇從軟盤啟動,計算機會檢查軟盤的0面0磁道1扇區,如果發現它以0xaa55結束,則BIOS認為它是一個引導扇區。一個正確的引導扇區除了以0xaa55結束之外,還應該包含一段512字節的執行碼。一旦BIOS發現了引導扇區,就會將這512字節的內容裝載到內存地址0000:7c00處,然後跳轉到0000:7c00處將控制權徹底交給這段引導代碼。
org 07c00h就是告訴編譯器,這段代碼是要被加載到這個地址的。所以BootMessage的偏移地址是相對於07c00h處開始的。BootMessage實際上也是一個地址,不是相對量
2.mov ax, cs、mov ds, ax、mov es, ax
讓ds和es指向當前代碼段。以便在以後進行數據操作的時候能定位到正確的位置。
3.call DispStr
調用顯示字符串的函數,在NASM中,任何不被[]括起來的標簽或變量名都被認為是地址,如果是訪問標簽中的內容則必須使用[]。所以mov ax, BootMessage會把"Hello,OS world!"這個字符串的首地址傳給寄存器ax。然後mov bp, ax賦給bp,如果沒寫org指令,則BootMessage編譯的時候就是相對於本程序加載到地址0的偏移地址,但是這裡是相對於07c00h為基址的偏移地址,所以這裡顯示了org的作用。
4.int 10h
10H中斷是由BIOS對顯示器和屏幕所提供的服務程序。使用int 10h服務程序時,必須先指定ah寄存器。
功能13h:
功能描述:在Teletype模式下顯示字符串
入口參數:AH=13H
BH=頁碼
BL=屬性(若AL=00H或 01H)
CX=顯示字符串長度
(DH、DL)=坐標(行、列)
ES:BP=顯示字符串的地址
AL=顯示輸出方式
0—— 字符串中只含顯示字符,其顯示屬性在BL中。顯示後,光標位置不變
1——字符串中只含顯示字符,其顯示屬性在BL中。顯示後,光標位置改變
2 ——字符串中含顯示字符和顯示屬性。顯示後,光標位置不變
3——字符串中含顯示字符和顯示屬性。顯示後,光標位置改變
出口參數:無
5.$和$$
$-$$表示本行距離程序開始處的相對距離。times 510-($-$$) db 0表示將0這個字節重復510-($-$$)遍,也就是在剩下的空間中不停地填充0,直到程序有510字節為止。這樣,加上結束標志0xaa55占用的2字節,恰好是512字節。