考虑以下程序 hello.c
:
#include <stdio.h>
int main(int argc, char** argv)
{
printf("hello");
return 0;
}
该文件是以下列方式汇编的 gcc -o hello -Og -g hello.c
然后装上 gdb hello
.
检查GOT,以便呼叫 printf
与 p '[email protected]'
给予
$1 = (<text from jump slot in .got.plt, no debug info>) 0x1036 <printf@plt+6>
即相应PLT条目中的第二条指令相对于本节开始的偏移量。
在启动程序并将其与 starti
, p '[email protected]'
现在给
$2 = (<text from jump slot in .got.plt, no debug info>) 0x555555555036 <printf@plt+6>
也就是对应PLT条目中第二条指令的绝对地址。
我明白是怎么回事,为什么。我的问题是 动态链接器加载器如何知道将部分偏移量(0x1036)更新为绝对地址(0x555555555036)?
A p &'[email protected]'
链接前给
$1 = (<text from jump slot in .got.plt, no debug info> *) 0x4018 <[email protected]>
和 readelf -r simple
显示该地址的搬迁条目
Relocation section '.rela.plt' at offset 0x550 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
000000004018 000200000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0
但我的解读是 系统五应用二进制接口AMD64架构处理器补充版第76页,这些搬迁条目只有在以下情况下才会使用 LD_BIND_NOW
是非空的。是否有其他我遗漏的重定位条目?相对于GOT的最终地址,重定偏移量的机制是什么?
根据Drepper的说法 如何编写共享库动态链接器重定位两种依赖关系。
对于PLT的GOT,Drepper指出(§1.5.5) 在启动时,动态链接器用指向相应PLT条目的第二条指令的地址填充GOT槽。 读取 glibc 源代码表明,链接器确实循环过了 R_X86_64_JUMP_SLOT
搬迁(elf/do-rel.h:elf_dynamic_do_Rel
),并递增它们所包含的偏移量(sysdeps/x86_64/dl-machine.h:elf_machine_lazy_rel
):
if (__glibc_likely (r_type == R_X86_64_JUMP_SLOT))
{
/* Prelink has been deprecated. */
if (__glibc_likely (map->l_mach.plt == 0))
*reloc_addr += l_addr;
else
...
当使用懒惰的PLT绑定时(默认情况)。