org指令詳解

《自己動手寫操作系統》書中第二頁的代碼1-1中對於 org07c00h是這樣註釋的:“告訴編譯器程序加載到7c00h處”
org 07c00h

mov ax,cs
mov ds,ax
mov es,ax

call screen
jmp $

screen:mov ax,bootmsg
mov bp,ax
mov cx,16
mov ax,01301h
mov bx,000ch
mov dl,0
int 10h
ret

bootmsg:db'Hello OS world!' 
times 510-($-$$) db 0 
dw 0xaa55


但是我看到一些資料說,bios會自動將引導程序加載到07c00h處,也就是說無論代碼是什麼都會被bios加載到07c00h處,那麼爲什麼還要寫呢?後來我去掉org 7c00h試了一下,仍可以啓動。只是顯示亂碼。 

org 會在編譯期影響到內存尋址指令的編譯(編譯器會把所有程序用到的段內偏移地址自動加上org 後跟的數值),而其自身並不會被編譯成機器碼。就是爲程序中所有的引用地址(需要計算的相對地址)增加一個段內偏移值。org 指令本身並不能決定程序將要加載到內存的什麼位置,它只是告訴編譯器,我的程序在編譯好後需要加載到xxx 地址,所以請你在編譯時幫我調整好數據訪問時的地址。

如果沒有org指令,那麼編譯器計算偏移量(雖然nasm中沒有offset但編譯器仍會進行這個運算)是從0000開始的,如果有了org,就會在最後加上org後面跟的數字。

在這個引導程序中:mov ax,bootmsg 在編譯的時候實際上是將 mov ax,bootmsg所在的地址與bootmsg同當前語句(mov ax,bootmsg)地址的偏移量相加所計算出來的。沒有org則偏移量從0000h開始,於是雖然整個代碼被加載到0x7c00處,但當執行到mov ax,bootmsg一句的時候,由於沒有算入偏移量7c00從而沒有將bootmsg字符串的首地址放入ax,以至發生錯誤。


Ndisasm -o 0x0000 boot.bin >> disboot1.asm 所得到的彙編文件:

Ndisasm –o 0x7c00 boot.bin >> disboot2.asm所得到的彙編文件:


通過反彙編,模擬了引導程序被加載到0000:0000處和0000:7c00處時的不同情形。第一次爲0000:0000第二次爲 0000:7C00。而對於mov ax,bootmsg一句的翻譯卻是一樣的,都是 mov ax,0x7c1e 。顯然第一次發生了錯誤(因爲在整個程序中就沒有出現0x7c1e這個地址,也就是說這是個無效地址)。錯誤產生的原因就是由於當代碼被編譯器編譯的時候編譯器是按照從7c00處開始計算地址的。也證明了bootmsg的地址是由編譯器計算出來的。

最後我們來分析一下爲什麼有時候去掉org 指令程序也能正常執行?
如:
ORG   7C00H   
msg: db 'HELLO   WORLD',0
MOV   DX, OFFSET   msg  

在有ORG   7C00H的情況下,MOV   DX,   OFFSET   msg對應的指令爲MOV   DX,7C4B(這裏4B爲msg在當前數據段中的偏移位置)如果沒有ORG   7C00H,那麼真正被執行的指令將爲MOV   SI,004B,試想,BIOS已經將該代碼裝載到0000:7C00處,0000:0000–0000:7C00之間的數據可能爲其他更重要的數據,如果使用004B就得不到我們所要訪問字符串msg,因爲我們的字符串被BIOS放在7C4B這裏了,所以我們的程序(最終由編譯器來完成)就必須迎合 BIOS的這種規定了。

因此,如果在程序中沒有牽扯到地址的計算,那麼完全可以不寫org(沒有做實驗驗證)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章