2014-10-08 148 views
0

我想知道它是如何精确地工作的。 比方说,我们有下面的代码片段:延迟加载程序

0000000000400400 <[email protected]>: 
400400:  ff 35 02 0c 20 00  pushq 0x200c02(%rip)  # 601008 <_GLOBAL_OFFSET_TABLE_+0x8> 
400406:  ff 25 04 0c 20 00  jmpq *0x200c04(%rip)  # 601010 <_GLOBAL_OFFSET_TABLE_+0x10> 
40040c:  0f 1f 40 00    nopl 0x0(%rax) 

0000000000400410 <[email protected]>: 
400410:  ff 25 02 0c 20 00  jmpq *0x200c02(%rip)  # 601018 <_GLOBAL_OFFSET_TABLE_+0x18> 
400416:  68 00 00 00 00   pushq $0x0 
40041b:  e9 e0 ff ff ff   jmpq 400400 <_init+0x20> 

.... 

40053b:  e8 d0 fe ff ff   callq 400410 <[email protected]> 

所有的printf存根(printf的@ PLT)首先被调用,那么位于0x601018(GOT的范围内)的地址是为了跳进去。

假设这是第一次调用printf:我们找到的值将是0x400416,也就是说下一条指令,对吗?

在代码之后,值0被压入堆栈,然后跳转到0x400400。这里推送一个GOT地址(0x601008),然后跳转到下一个(0x601010):为什么?那里究竟有什么?

此外:何时调用动态链接器以及如何?

回答

0

你已经停止在答案上追踪;) 如果你看最后的指针(0x601010),你应该看到它去到_dl_runtime_resolveplt条目中的第一次推送将重定位索引存储在堆栈上(这标识要操作的条目),第二次从获得的推送是模块的链接映射。 _dl_runtime_resolve通常是链接器中的汇编函数(对于x86-64,它位于glibc/sysdeps/x86_64/dl-trampoline.S中),它在保留一些寄存器后调用_dl_fixup并执行所有解析工作(包括更新GOT中的指针,以便后续调用直接进入到解决的功能)。最后_dl_runtime_resolve跳转到现在解决的功能,所以它实际上也得到执行:)

+0

您的回答缺少一些细节。特别是,* _dl_runtime_resolve是怎样得到最终指针的?整个过程的更全面的描述:http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/ – 2014-10-12 00:26:35

+0

@EmployedRussian肯定,它不是一个完整的描述,但它回答了OP提出的具体问题。有趣的是,即使你的链接只说“_第一个PLT条目是一个调用程序例程,它位于动态加载程序本身_”,至少我找不到它提供更多细节的地方。 – Jester 2014-10-12 00:40:34