記錄下org指令是幹啥的 :D

org指令時NASM中的一個指令。在《NASM手冊》中“org指定程序被載入內存時,程序的起始地址”
如下圖:

--------------------導言---------------------------------
boot.asm中第一行這樣寫的:org 07c00h。也許就會聯想它的意思就是指定boot程序被加載到內存07c00的位置,產生這樣的聯想也很正常。但是BIOS本身就規定boot程序要被加載到內存位置07c00的,那 這個org不是多餘的嗎。也就是說,不要這個org照樣也行咯?那麼不用org指令程序是否能正常運行呢?能達到預期的效果嗎?
第一回
當把源代碼裏面的org指令註釋掉,重新編譯org.asm,寫入軟盤引導分區,啓動Bochs。看到程序在org被註釋的情況下的確運行了,但是並沒有達到預期的效果(預期的效果時打印hello world)。

這一階段的結論就是沒有org程序依然能夠運行,但是無法達到預期的效果。(出現了亂碼)
第二回
針對前面的情況,簡單分析下沒有加org指令編譯後的二進制文件org.bin
$ hd org.bin

(以下兩個圖都可以看到字符串在二進制文件中的編碼位置)
可以看到字符串在位於偏移bin文件的0x1e位置(相對於0x00而言)。在實模式下,注意:當這個boot由BIOS載入內存之後,他的起始地址就是0x7c00了(而不再是之前的0x00),那麼,字符串在內存中的地址就成了0x7c1e(即就是:0x7c00 + 0x1e)。clear?
(當然,如果起始地址是0x00的話,那麼字符串在內存中的地址當然還是0x1e,)
總之:當org.bin被加載到內存位置0x7c00時(此時程序在內存中的起始地址就是0x7c00,EIP=0x7c00),那麼字符串在內存中的位置就是0x7c1e。

或者這樣反編譯一下也可以(下圖所示的boot和org是同一個二進制文件,只是本文在編輯過程中時間相隔比較大,所以示例程序有點混亂造成的,僅僅名字不一樣而已)

(沒有加org 0x7c00的效果如上圖)

現在來將沒有加org指令的boot(org.bin)程序在Bochs裏面運行下。
1)在0x7c00處設置breakpoint。反彙編內存地址0x7c00~0x7c30這段代碼。
可以看到,高亮那部分代碼是在調用BIOS的int 10h中斷之前將字符串首地址裝入到bp寄存器中,


實模式下,圖中直接把地址0x1e裝到了ax寄存器中,而這個地址就是字符串在未載入內存之前的地址,現在已經加載到內存中了,顯然字符串的地址就不應該是0x1e了。
而機器是不管那麼多的,你是怎麼指定的,它就怎麼執行!所以它就會將內存地址0x1e加載到ax中,而這個地址處存的肯定不是想要的,於是就出現了亂碼。
那要想正確的加載字符串該怎麼辦?首先boot被載入到內存中,這個時候字符串在內存中的地址就是0x7c1e(爲什麼?第二回開頭就解釋了的哈)。所以我們只需要在二進制編碼中制定字符串的地址是0x7c1e,這樣在尋找字符串的時候就不會想之前那樣出現mov ax,0x001e而是mov ax, 0x7c1e,而0x7c1e剛好是字符串所在的實際內存地址。
於慣性思維,想當然的以爲程序被加載的時候,0x7c00被存放在段寄存器中,這樣一來就剛好能尋址到0x7c1e。也就能剛好找到字符串了。實際情況剛好相反,段寄存器在機器啓動時被初始化0x00,此時的偏移地址就是物理地址。
於是,要訪問0x7c01e就要將偏移地址設置爲0x7c1e。
第三回
現在將org指令加上,重新在Bochs啓動。
同樣設置斷點,反彙編內存地址0x7c00到0x7c30這段代碼。
可以看到已經有變化了 


添加了org之後,字符串的內存地址已經是正確的ox7c1e了,程序通過段基址(爲0)+偏移地址(ox7c1e)訪問到了字符串。
添加了org,在編譯的時候字符串的地址就已經被指定爲0x7c1e了,當程序運行時,直接將這個地址傳給ax,就肯定能找到了。
第四回 org的作用:
這樣看來NASM manual中關於org定義就有些“模糊”了,畢竟是中文翻譯了。首先org指令並不能指定(或者決定)程序被加載到哪個位置,
他只是告訴NASM,此程序將要被加載到xxx地方,那麼在編譯時請調整好數據訪問位置。比如,程序要被加載0x7c00,那麼在編譯時將要訪問的字符串的地址加上0x7c00。簡單說,org指令只會在編譯期影響到內存尋址指令的編譯(編譯器會 把所有程序用到的段內偏移地址自動加上org後跟的數值。引導程序可以看做是被加載到以0爲基址的段,偏移爲0x7c00的地方)。 

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