
以write函數(shù)為例說(shuō)明延遲綁定,如上圖所示,當(dāng)?shù)谝淮握{(diào)用write函數(shù)時(shí)候,程序會(huì)跳轉(zhuǎn)到.plt表處

程序首先會(huì)跳轉(zhuǎn)到0x601018處,我們看一下0x601018是什么

0x601018是一個(gè)地址,這個(gè)地址就是jmp命令的下一條指令的地址。因?yàn)槭堑谝淮蔚谝淮握{(diào)用,此時(shí)got還沒有添加write函數(shù)的實(shí)際地址。當(dāng)重定位完成之后就不會(huì)執(zhí)行0x400586處的指令了。

我們繼續(xù)調(diào)試,程序會(huì)跳轉(zhuǎn)到0x400570處,這里首先會(huì)將0x601008(*(GOT+8)指向struct link_map的指針)地址的值壓入堆棧,之前的0已經(jīng)在堆棧中了。隨后程序跳轉(zhuǎn)到0x601010處。

0x601010處存放的是一個(gè)地址即7ffff7dee6a0,這個(gè)地址是dl_runtime_reslove函數(shù)的地址。

所以重定位最終是調(diào)用dl_runtime_reslove函數(shù)去解析write函數(shù)的實(shí)際地址,解析成功將地址保存到.got.plt表中。以后在調(diào)用write函數(shù)流程就變?yōu)閜lt->got。
dl_runtime_reslove函數(shù)確定符號(hào)的過程如下:

_dl_runtime_resolve(link_map, rel_offset);
根據(jù)rel_offset,找到重定位條目:
Elf32_Rel * rel_entry = JMPREL + rel_offset;
根據(jù)rel_entry中的符號(hào)表?xiàng)l目編號(hào),得到對(duì)應(yīng)的符號(hào)信息:
Elf32_Sym *sym_entry = SYMTAB[ELF32_R_SYM(rel_entry->r_info)];
再找到符號(hào)信息中的符號(hào)名稱:
char *sym_name = STRTAB + sym_entry->st_name;
獲取符號(hào)對(duì)應(yīng)的字符串僅僅是一小部分,具體的地址獲取與link_map的實(shí)現(xiàn)息息相關(guān),即壓入堆棧的另一個(gè)參數(shù),這一部分的原理與實(shí)現(xiàn)參考此文