符號解析與重定位
重定位
編譯器並不知道引用符號的真正地址,暫時用臨時的假地址代替著,把真正的地址計算工作留給了鏈接器,鏈接器可以根據符號的地址對每個需要重定位的指令進行地位修正。
重定位表
在ELF文件中,有一個叫重定位表的結構專門用來保存這些魚重定位相關的信息。對於可重定位的ELF文件來說,它必須包含有重定位表,用來描述如何修改相應的段裏的內容。
每個要被重定位的地方叫一個重定位入口(Relocation Entry),重定位入口的偏移(Offset)表示該入口在要被重定位的段中的位置,“RELOCATION RECORDS FOR [.text]”表示這個重定位表是代碼段的重定位表。
重定位入口的定義如下:
typedef struct{
Elf32_Addr r_offset; // 重定位入口的偏移
Elf32_Word r_info; // 重定位入口的類型(低8位)和符號(高24位表示符號在符號表中的下標)
}Elf32_Rel;
符號解析
我們平時在編寫程序的時候最常碰到的問題之一,就是鏈接時符號未定義。導致這個問題的原因很多,最常見的一般都是鏈接時缺少了某個庫,或者輸入目標文件路徑不正確或符號的聲明與定義不一樣。所以從普通程序員的角度看,符號的解析占據了鏈接過程的主要內容。
其實重定位過程也伴隨著符號的解析過程,每個目標文件都可能定義一些符號,也可能引用到定義在其他目標文件的符號。重定位的過程中,每個重定位的入口都是對一個符號的引用,那麽當鏈接器需要對某個符號的引用進行重定位時,它就要確定這符號的目標地址。這時候鏈接器就會去查找由所有輸入目標文件的符號表組成的全局符號表,找到相應的符號後進行重定位。若找不到就報符號未定義錯誤。
指令修正方式
不同的處理器指令對於地址的格式和方式都不一樣。這些尋址方式有如下幾方面的區別:
近址尋址或遠址尋址
絕對尋址或相對尋址
尋址長度為8位、16位、32位或64位
但對於32位x86平臺下的ELF文件的重定位入口所修正的指令尋址方式只有兩種:
絕對近址32位尋址
相對近址32位尋址
每個被修正的位置的長度都為32位,即4個字節。
宏定義 | 值 | 重定位修正方法 |
---|---|---|
R_386_32 | 1 | 絕對尋址修正 S+A |
R_386_PC32 | 2 | 相對尋址修正 S+A-P |
A=保存在被修正位置的值
P=被修正的位置(相對於段開始的偏移量或虛擬地址),註意,該值可通過r_offset計算得到
符號解析與重定位