【问题标题】:Lazy loading procedure延迟加载过程
【发布时间】:2014-10-08 23:06:28
【问题描述】:

我想知道它是如何精确工作的。 假设我们有以下代码 sn-ps:

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 存根 (printf@plt),然后获取位于 0x601018(在 GOT 内)的地址以便跳转到其中。

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

按照代码,值 0 被压入堆栈,然后我们跳转到 0x400400。这里推送了一个 GOT 地址(0x601008),然后跳转到下一个地址(0x601010):为什么?里面到底有什么?

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

【问题讨论】:

    标签: linux assembly compilation linker decompiling


    【解决方案1】:

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

    【讨论】:

    • 您的回答缺少一些细节。特别是,如何 _dl_runtime_resolve 到达最终指针?更全过程的描述:eli.thegreenplace.net/2011/11/03/…
    • @EmployedRussian 当然,这不是一个完整的描述,但它回答了 OP 提出的具体问题。有趣的是,即使您的链接仅显示“第一个 PLT 条目是对位于动态加载器本身中的解析器例程的调用”,至少我找不到它提供更多详细信息的位置关于那个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-03
    • 2017-12-11
    • 1970-01-01
    • 2014-03-06
    相关资源
    最近更新 更多