計算機系統篇之鏈接(5):重定位
Author:stormQ
Wednesday, 15. April 2020 04:35PM
重定位的整體過程
重定位的目的是確定每個符號定義的運行時內存地址,並修改對這些符號的引用,使之指向符號定義的運行時內存地址。
重定位的整體過程可以分爲兩個步驟:
-
重定位節和符號定義。鏈接器將輸入目標文件的相同節合併成一個節,合併的節將作爲可執行目標文件中此類型的節。隨後,鏈接器確定每個合併節的運行時內存地址,並確定合併節中符號定義的運行時內存地址。這一步驟完成後,可執行目標文件中的所有指令和符號定義的運行時內存地址就唯一確定了。
-
重定位節中的符號引用。鏈接器修改所有的符號引用,使之指向符號定義的運行時內存地址。鏈接器要執行此步驟依賴於目標文件中的重定位信息。
重定位條目
ELF 中的重定位條目分爲兩種格式:Rel
和Rela
。每個重定位條目表示一個必須被重定位的符號引用,並指明如何計算被修改的符號引用。
查看可重定位目標文件中的重定位信息:
$ readelf -r main.o
Relocation section '.rela.text' at offset 0x208 contains 1 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000000005 000b00000002 R_X86_64_PC32 0000000000000000 _Z4funcv - 4
Relocation section '.rela.eh_frame' at offset 0x220 contains 1 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000000020 000200000002 R_X86_64_PC32 0000000000000000 .text + 0
-
注:
-
Offset
是 Relocation Entry 結構體中的第 1 個字段,佔用 8 字節,表示需要修改的符號引用的位置。對於可重定位目標文件,該字段表示需要修改的符號引用的起始位置在目標 section (.rela.text
中的重定位條目對應的目標 section 爲.text
,.rela.data
中的重定位條目對應的目標 section 爲.data
,以此類推)中的偏移量(字節)。對於可執行目標文件和可共享目標文件,該字段表示需要修改的符號引用的起始位置所對應的虛擬內存地址。 -
Info
是 Relocation Entry 結構體中的第 2 個字段,佔用 8 字節,表示符號表索引和重定位類型(符號表索引佔用高 32 位,重定位類型佔用低 32 位)。符號表索引表示需要修改的符號引用在
.symtab
section中的索引。這裏的Sym. Value
和Sym. Name
列只是打印了所對應符號表條目中Value
和Name
列的值。重定位類型指示鏈接器如何修改該符號引用的值。重定位類型因不同的處理器而異。
-
Addend
是 Relocation Entry 結構體中的第 3 個字段,佔用 8 字節,表示一個有符號常數,一些重定位類型要使用它對被修改符號引用的值做偏移調整。 -
重定位條目
Rel
和Rela
之間的唯一區別:Rel
中沒有Addend
字段。
-
源碼:
$ cat test.cpp
extern int g_val_1;
extern int g_val_2;
void func()
{
g_val_1 *= 2;
g_val_2 *= 2;
}
$ cat main.cpp
int g_val_1;
int g_val_2 = 3;
void func();
int main()
{
func();
return 0;
}
1)驗證對於可重定位目標文件,Offset 字段表示需要修改的符號引用的起始位置在目標 section 中的偏移量(字節)
可重定位目標文件main.o
中代碼的重定位條目放在.rela.text
section 中。該 section 只包含一個重定位條目,其中Offset
字段的值爲 0x5,表示在目標 section (即.text
)中起始位置爲 0x5 的內容需要被修改。如果該內容的值在可執行目標文件main
中被修改了,即可驗證此結論。
查看可重定位目標文件main.o
的.text
section:
$ objdump -d main.o
main.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: e8 00 00 00 00 callq 9 <main+0x9>
9: b8 00 00 00 00 mov $0x0,%eax
e: 5d pop %rbp
f: c3 retq
可以看出,main.o
的.text
section 中偏移量(相對於.text
的起始位置,即相對於main
函數的起始位置)爲 0x5 的內容的當前值爲 0x0。這裏有兩點需要注意:1)由於偏移量爲 0x5 的位置與下一條指令的開始位置之間有 4 個字節,所以該內容佔用 4 字節;2)由於main.o
的字節序是小端,所以,00 00 00 00
中最右邊的00
對應的地址爲偏移量 0x5。
關注公衆號,即可查看完整內容。