EXE文件的重定位

EXE文件的重定位

這份文檔基於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

儲存在硬盤中的EXE文件

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)=0
  • mov dx, offset abc---------mov dx, 0000-----------------abc位置與該段段首的差=(0200Ch-0200h)=0h
  • mov ax, code-------------------mov ax, 0002-----------------code與data段地址的差=(0220h-0200h)/10h=2h
  • mov dx, offset xyz---------mov dx, 001C-----------------zxy位置與該段段首的差=(023Ch-0220h)=1Ch

根據上述結果,咱們能夠知道,在程序加載到內存中開始運行時,咱們只要獲得每一個段的物理地址,咱們就能夠計算出每一個變量的物理地址。那麼要如何根據程序的代碼段來算出每一個段的物理地址呢?這裏涉及到兩個問題:

  1. 如何判斷編譯後的exe文件中指令中的當即數是一個地址?例如,mov ax,0000這條指令中0000是一個相對地址仍是一個當即數呢?

    這就是文件頭中重定位表項的做用了。重定位項必定指向須要重定位的段地址所在的地方

  2. 根據重定位項查到一個相對地址後,重定位的具體過程是怎樣的?

    操做系統把須要重定位的段地址取出來,和首段的段地址相加後再寫回去

    等重定位完成後,設置ds=es=psp設置ss:sp,再jmp cs:ip

重定位表

重定位表是由重定位項組成的,每個重定位項指向須要重定位的段地址所在的地方。爲了肯定重定位項指向的具體地址,EXE文件頭採用Δ段地址:偏移量的方式。

因此,每個重定位項含有四個字節:其中前兩個字節是須要重定位的數據的偏移地址,後兩個字節是段地址的Δ值,即須要(重定位的段地址-首段段地)址。

讀懂文件頭中的重定位表

如今,咱們經過具體的例子來講明重定位的過程。

  • [6-7]字節:重定位表項的個數
  • [18h-19h]字節:重定位表的相對文件頭的偏移位置
  • 根據[18h-19h]字節找到重定位表,以及[6-7]字節肯定重定位表的長度= 重定位表項的個數*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 ................

加粗的部分均爲在文件頭中和重定位有關係的字節

  • [6-7]字節表示重定位表項的個數=0002h
  • [18h-19h]字節表示重定位表的相對文件頭的偏移位置位001eh
  • [1eh-25h]字節表示重定位表中的兩項
    • 第一項:偏移量=0001h, Δ段地址=0002h
    • 第二項:偏移量=000dh, Δ段地址=0002h

得到程序首段地址:程序的首段地址=psp+10h

假設程序首段地址=1010h,第一項重定位項的重定位過程以下:

  1. 肯定須要重定位的位置:(1010+0002):0001=1012:0001
  2. 更改該位置中的段地址值:word ptr 1012:[0001] += 1010h

具體例子

  1. 經過td調試hello2.exe文件

  1. 當前ds=es=psp的段地址,首段地址=psp+10h=5292h+10h=52A2h

  2. 根據重定位項的第一項:偏移量=0001h, Δ段地址=0002h,找到須要重定位的地方是在52A4:0001

  3. 而後進行重定位:word ptr 52A4:[0001]=0000h+首段地址=0000h+52A2h=52A2h

    也就是mov ax,52A2這條指令中的52A2

相關文章
相關標籤/搜索