在CSAPP鏈接相關(guān)章節(jié)中中狂,書中描述了鏈接大概分為兩步,第一步為符號解析唤蔗,第二步便是重定位。其中書中描述 (P478) 重定位時會合并各個重定位目標文件中相同類型的節(jié),然后鏈接器會將運行時內(nèi)存地址賦給各個節(jié)妓柜。
書中提到了段要加載到內(nèi)存時箱季,應(yīng)該放在的地址保存在程序頭部表中(Program header table),它描述了將文件各段映射到運行時內(nèi)存的一些參數(shù),但并未對運行時地址展開描述领虹。
- 該表記錄了數(shù)據(jù)段规哪,代碼段等在文件中的偏移,以及長度塌衰,該段要被加載至內(nèi)存哪個地址诉稍,以及對其要求。
猜測:
- 數(shù)據(jù)段代碼段總是被加載至內(nèi)存固定的位置最疆,即表中記錄的地址杯巨。
- 被定義的全局符號總是有固定的虛擬內(nèi)存地址。
- 在重定位的過程中努酸,是計算符號定義的運行時地址(符號定義在內(nèi)存中的地址)服爷,然后通過計算文件內(nèi)部的這個引用的偏移,將其裝填到這里获诈。
=================下面不作數(shù)=====================
我們可以進行一個簡單的測試:
- 查看這個可執(zhí)行目標文件的程序頭部表仍源,記錄下代碼段和數(shù)據(jù)段的 vaddr、paddr舔涎,然后執(zhí)行該文件笼踩,查看內(nèi)存代碼段和數(shù)據(jù)段的地址,是否就是該表所記錄的亡嫌。
- 找一個使用相對地址重定位的引用嚎于,取這個引用上的地址,然后將vaddr所記錄運行地址代入計算挟冠,查看結(jié)果是否一致于购。
對于一個極其簡單的C - testA.c 程序:
int test_var = 1;
int main(){
test_var = 10;;
}
將其編譯為可重定位目標文件,并查看這個文件的反匯編代碼:
>>> gcc -c -o testA.o testA.c
>>> objdump -d -F testA.o
0000000000000000 <main> (File Offset: 0x40):
0: c7 05 00 00 00 00 0a movl $0xa,0x0(%rip) # a <main+0xa> (File Offset: 0x4a)
....
我們可以看到重定位條目知染,在.text節(jié)內(nèi)偏移 0xa 處需要進行一個重定位肋僧,這正是對全局變量 test_var 的引用,而rip存放PC值控淡,這條指令的意思就是把常數(shù) 0xa 存放至 PC + addr 這個地址上色瘩,而此處的 addr 還未被重定位,就是一串 0逸寓。
然后我們將這個可重定位目標文件鏈個可執(zhí)行目標文件,然后查看反匯編數(shù)據(jù):
>>> gcc -c -o testA.out testA.o
對這個可執(zhí)行目標文件進行反匯編:
>>> objdump -d -F testA.out
00000000004004d6 <main> (File Offset: 0x4d6):
4004d6: c7 05 50 0b 20 00 0a movl $0xa,0x200b50(%rip) # 601030 <test_var> (File Offset: 0x201030)
...
Disassembly of section .data:
0000000000601030 <test_var> (File Offset: 0x1030):
601030: 01 00 add %eax,(%rax)
...
由于 objdump 反匯編時顯示的地址是 complete address (man objdump中所述)居兆,不是文件內(nèi)偏移,可以通過 -F 命令顯示出具體指令在文件內(nèi)部的偏移竹伸。
我們查看其程序頭部表泥栖,挑出數(shù)據(jù)段與代碼段相關(guān)信息:
>>> objdump -d -F testA.out
INTERP off 0x0000000000000238 vaddr 0x0000000000400238 paddr 0x0000000000400238 align 2**0
filesz 0x000000000000001c memsz 0x000000000000001c flags r--
LOAD off 0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**21
filesz 0x0000000000000694 memsz 0x0000000000000694 flags r-x // 代碼段
LOAD off 0x0000000000000e10 vaddr 0x0000000000600e10 paddr 0x0000000000600e10 align 2**21
filesz 0x0000000000000224 memsz 0x0000000000000228 flags rw- //數(shù)據(jù)段