以write函數(shù)為例說明延遲綁定嗽冒,如上圖所示,當(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ù)確定符號的過程如下:
_dl_runtime_resolve(link_map, rel_offset);
根據(jù)rel_offset,找到重定位條目:
Elf32_Rel * rel_entry = JMPREL + rel_offset;
根據(jù)rel_entry中的符號表?xiàng)l目編號规婆,得到對應(yīng)的符號信息:
Elf32_Sym *sym_entry = SYMTAB[ELF32_R_SYM(rel_entry->r_info)];
再找到符號信息中的符號名稱:
char *sym_name = STRTAB + sym_entry->st_name;
獲取符號對應(yīng)的字符串僅僅是一小部分澜躺,具體的地址獲取與link_map的實(shí)現(xiàn)息息相關(guān)蝉稳,即壓入堆棧的另一個(gè)參數(shù),這一部分的原理與實(shí)現(xiàn)參考此文