gpt4 book ai didi

linux - @plt在这里是什么意思?

转载 作者:行者123 更新时间:2023-12-02 15:10:50 27 4
gpt4 key购买 nike

0x00000000004004b6 <main+30>:   callq  0x400398 <printf@plt>

有人知道吗?

更新

为什么两个 disas printf 给出不同的结果?

(gdb) disas printf
Dump of assembler code for function printf@plt:
0x0000000000400398 <printf@plt+0>: jmpq *0x2004c2(%rip) # 0x600860 <_GLOBAL_OFFSET_TABLE_+24>
0x000000000040039e <printf@plt+6>: pushq $0x0
0x00000000004003a3 <printf@plt+11>: jmpq 0x400388

(gdb) disas printf
Dump of assembler code for function printf:
0x00000037aa44d360 <printf+0>: sub $0xd8,%rsp
0x00000037aa44d367 <printf+7>: mov %rdx,0x30(%rsp)
0x00000037aa44d36c <printf+12>: movzbl %al,%edx
0x00000037aa44d36f <printf+15>: mov %rsi,0x28(%rsp)
0x00000037aa44d374 <printf+20>: lea 0x0(,%rdx,4),%rax
0x00000037aa44d37c <printf+28>: lea 0x3f(%rip),%rdx # 0x37aa44d3c2 <printf+98>

最佳答案

这是一种获得代码修复的方法(根据代码在虚拟内存中的位置调整地址,不同进程的地址可能不同),而无需为每个进程维护单独的代码副本。 PLT,或过程链接表,是使动态加载和链接更容易使用的结构之一(另一个是GOT,或全局偏移量表)。

请参阅下图,其中显示了映射到两个不同进程中不同虚拟地址的调用代码和(您调用的)库代码,AB 。每段代码在实内存中只有一个副本,每个进程中的不同虚拟地址映射到该真实地址):

Process A
Addresses (virtual):
0x1234 0x8888
+-------------+ +---------+ +---------+
| | | Private | | |
| | | PLT/GOT | | |
| Shared | +---------+ | Shared |
===== application =============== library =====
| code | +---------+ | code |
| | | Private | | |
| | | PLT/GOT | | |
+-------------+ +---------+ +---------+
0x2020 0x6666
Process B
<小时/>

当共享库被引入地址空间时,条目会在特定于进程的(私有(private))PLT 和/或 GOT 中构建,在第一次使用时,它们会执行一些修复以使事情变得更快。后续使用将绕过修复,因为不再需要它。

这个过程是这样的。

printf@plt实际上是一个小 stub ,(最终)调用真实的 printf函数,在途中修改一些东西以使后续调用更快。

真实 printf函数被映射到给定进程(虚拟地址空间)中的任意位置,尝试调用它的代码也是如此。

因此,为了允许调用代码(上面左侧)和被调用代码(右侧)正确共享代码,您不能直接对调用代码应用任何修复,因为这会“损害”它的工作方式其他进程(如果它映射到每个进程中的相同位置,那并不重要,但这有点限制,特别是如果其他东西已经映射到那里)。

所以PLT是一个较小的特定于进程的区域,位于运行时可靠计算的地址,在进程之间共享,因此任何给定的进程都可以自由地更改它,但是它想要,而不会对其他进程产生不利影响。

<小时/>

让我们更详细地了解该过程。上图没有显示 PLT/GOT 的地址,因为可以使用相对于当前程序计数器的位置找到它。这可以通过与 PC 相关的查找来证明:

<printf@plt+0>: jmpq  *0x2004c2(%rip)  ; 0x600860 <_GOT_+24>

通过在被调用库中使用与位置无关的代码以及 PLT/GOT,第一次 调用函数 printf@plt (因此 PLT 中)是一个多阶段操作,其中发生以下操作:

  • 它调用 GOT 版本(通过指针),该版本最初指向 PLT 中的某些设置代码。
  • 该设置代码加载相关共享库(如果尚未完成),然后修改 GOT 指针,以便后续调用直接转到真实的 printf (在特定于进程的虚拟地址处)而不是 PLT 设置代码。
  • 然后调用加载的 printf该地址的代码。

后续调用中,由于 GOT 指针已被修改,因此多阶段方法得到了简化:

  • 它调用 GOT 版本(通过指针),该版本现在指向真实 printf .

可以找到好文章here ,详细说明如何glibc在运行时加载。

关于linux - @plt在这里是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5469274/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com