延迟加载程序

时间:2014-10-08 23:06:28

标签: linux assembly compilation linker decompiling

我想知道它是如何正常工作的。 假设我们有以下代码片段:

0000000000400400 <printf@plt-0x10>:
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 <printf@plt>:
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 <printf@plt>

首先调用printf stub(printf @ plt),然后获取位于0x601018(GOT内)的地址以跳转到它。

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

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

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

1 个答案:

答案 0 :(得分:0)

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