這份文檔基於EXE的文件格式 https://www.cnblogs.com/zxyLeaf/articles/14132526.htmlhtml
前面在解釋文件頭的第[6-7] ,[18h-19h]字節含義時並無說明什麼是重定位表,什麼是重定位項。由於這涉及到一個重要的概念叫作重定位。 這一小節就來講明什麼是重定位。函數
一個.asm
彙編文件,通過編譯器編譯後生成.obj
文件,再由連接器(linker)連接生成.exe
文件,也就是可執行程序,這個可執行程序被保存在硬盤(disk)中。當咱們運行這個程序時,加載器(loader)會把在硬盤中的可執行文件加載到內存(memory)上的空餘位置,這時運行中的程序會就是進程。操作系統
當編譯器,連接器在生成可執行文件時,並不會知道程序在真正運行時加載到哪個物理地址上,因此編譯器對於段,變量,函數的編譯均採用相對地址的形式進行。可是程序真正在內存中運行時,CPU是須要知道段,變量等真正的物理地址的。3d
所以,在加載程序到內存時,誰來將編譯器產生的相對地址轉換成絕對物理地址呢?這個操做又是如何完成的呢?調試
上面的第一個問題就是重定位要解決的事情,這裏咱們給出重定位的定義:code
操做系統根據EXE文件頭中的重定位表將程序中引用的段地址進行修正的過程稱爲重定位htm
接下里的內容由兩大部分組成:第一部分在驗證在編譯完成後,EXE文件中的變量,段址記錄的都是相對值;第二部分用來講明重定位的具體過程。blog
hello2.asm
的具體代碼以下:進程
data segment; 1000:0000 abc db "Hello, abc!$"; 12字節=0Ch字節 db 10h dup(0); 16字節 data ends code segment; assume cs:code, ds:data, ss:stk begin: mov ax, data mov ds, ax mov ah, 9 mov dx, offset abc int 21h mov ax, code; 編譯時code被設成如下值 ; (code段-首個段的距離)/10h mov ds, ax mov ah, 9 mov dx, offset xyz int 21h mov ah, 4Ch int 21h xyz db "Hello, xyz!$" main: jmp begin code ends stk segment stack db 100h dup('$'); 爲了方便查看,將堆棧中的初始值改成'$' stk ends end main
經過Qview打開hello2.exe
文件,跳過200h字節的文件頭,來到程序開始的地方ip
能夠看到編譯後源文件中的段,變量被編譯成了相對地址
mov ax, data
--------------------mov ax, 0000
-----------------data與第一個段地址的差(data)=0mov dx, offset abc
---------mov dx, 0000
-----------------abc位置與該段段首的差=(0200Ch-0200h)=0hmov ax, code
-------------------mov ax, 0002
-----------------code與data段地址的差=(0220h-0200h)/10h=2hmov dx, offset xyz
---------mov dx, 001C
-----------------zxy位置與該段段首的差=(023Ch-0220h)=1Ch根據上述結果,咱們能夠知道,在程序加載到內存中開始運行時,咱們只要獲得每一個段的物理地址,咱們就能夠計算出每一個變量的物理地址。那麼要如何根據程序的代碼段來算出每一個段的物理地址呢?這裏涉及到兩個問題:
如何判斷編譯後的exe文件中指令中的當即數是一個地址?例如,mov ax,0000
這條指令中0000
是一個相對地址仍是一個當即數呢?
這就是文件頭中重定位表項的做用了。重定位項必定指向須要重定位的段地址所在的地方
根據重定位項查到一個相對地址後,重定位的具體過程是怎樣的?
操做系統把須要重定位的段地址取出來,和首段的段地址相加後再寫回去
等重定位完成後,設置ds=es=psp設置ss:sp,再jmp cs:ip
重定位表是由重定位項組成的,每個重定位項指向須要重定位的段地址所在的地方。爲了肯定重定位項指向的具體地址,EXE文件頭採用Δ段地址:偏移量
的方式。
因此,每個重定位項含有四個字節:其中前兩個字節是須要重定位的數據的偏移地址,後兩個字節是段地址的Δ值,即須要(重定位的段地址-首段段地)址。
如今,咱們經過具體的例子來講明重定位的過程。
重定位表項的個數*4
個字節繼續看hello2.exe的文件頭
00000000: 4d5a 5001 0200 0200 2000 0000 ffff 0500 MZP..... .......
00000010: 0001 e80e 2800 0200 1e00 0000 0100 0100 ....(...........
00000020: 0200 0d00 0200 0000 0000 0000 0000 0000 ................
加粗的部分均爲在文件頭中和重定位有關係的字節
得到程序首段地址:程序的首段地址=psp+10h
假設程序首段地址=1010h,第一項重定位項的重定位過程以下:
(1010+0002):0001=1012:0001
word ptr 1012:[0001] += 1010h
當前ds=es=psp的段地址,首段地址=psp+10h=5292h+10h=52A2h
根據重定位項的第一項:偏移量=0001h, Δ段地址=0002h,找到須要重定位的地方是在52A4:0001
處
而後進行重定位:word ptr 52A4:[0001]=0000h+首段地址=0000h+52A2h=52A2h
也就是mov ax,52A2
這條指令中的52A2