@plt 在这里是什么意思? [英] What does @plt mean here?

查看:28
本文介绍了@plt 在这里是什么意思?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

有人知道吗?

更新

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

Why two disas printf give me different result?

(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 是过程链接表,是使动态加载和链接更易于使用的结构之一.

It's a way to get code fixups (adjusting addresses based on where code sits in virtual memory, which may be different across different processes) without having to maintain a separate copy of the code for each process. The PLT is the procedure linkage table, one of the structures which makes dynamic loading and linking easier to use.

printf@plt 实际上是一个小存根,它(最终)调用真正的 printf 函数,在途中进行修改以使后续调用更快.

printf@plt is actually a small stub which (eventually) calls the real printf function, modifying things on the way to make subsequent calls faster.

real printf 函数可以映射到给定进程(虚拟地址空间)中的任何位置,就像正在尝试的代码一样调用它.

The real printf function may be mapped into any location in a given process (virtual address space) as may the code that is trying to call it.

因此,为了允许调用代码(下方左侧)和被调用代码(下方右侧)的正确代码共享,您不想直接对调用代码应用任何修正,因为这将限制它可以在哪里位于其他进程中.

So, in order to allow proper code sharing of calling code (left side below) and called code (right side below), you don't want to apply any fixups to the calling code directly since that will restrict where it can be located in other processes.

所以 PLT 是一个较小的进程特定区域,位于一个可靠计算的运行时地址,不在之间共享流程,因此任何给定的流程都可以随意更改,而不会产生不利影响.

So the PLT is a smaller process-specific area at a reliably-calculated-at-runtime address that isn't shared between processes, so any given process is free to change it however it wants to, without adverse effects.

检查下图,该图显示了您的代码和库代码映射到两个不同进程中不同的虚拟地址,ProcAProcB:

Examine the following diagram which shows both your code and the library code mapped to different virtual addresses in two different processes, ProcA and ProcB:

Address: 0x1234          0x9000      0x8888
        +-------------+ +---------+ +---------+
        |             | | Private | |         |
ProcA   |             | | PLT/GOT | |         |
        | Shared      | +---------+ | Shared  |
========| application |=============| library |==
        | code        | +---------+ | code    |
        |             | | Private | |         |
ProcB   |             | | PLT/GOT | |         |
        +-------------+ +---------+ +---------+
Address: 0x2020          0x9000      0x6666

这个特殊的例子展示了一个简单的例子,其中 PLT 映射到一个固定位置.在您的场景中,它相对于当前程序计数器定位,正如您的程序计数器相关查找所证明的那样:

This particular example shows a simple case where the PLT maps to a fixed location. In your scenario, it's located relative to the current program counter as evidenced by your program-counter-relative lookup:

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

为了使示例更简单,我刚刚使用了固定寻址.

I've just used fixed addressing to keep the example simpler.

共享代码的原始方式意味着它们必须加载到使用它的每个进程的每个虚拟地址空间中的相同内存位置.要么不能共享,要么不能共享,因为为一个进程修复单个共享副本的行为会完全填满映射到不同位置的其他进程.

The original way in which code was shared meant it they had to be loaded at the same memory location in each virtual address space of every process that used it. Either that or it couldn't be shared, since the act of fixing up the single shared copy for one process would totally stuff up other processes where it was mapped to a different location.

通过使用位置无关代码,连同 PLT 和全局偏移表 (GOT),第一次调用函数 printf@plt(在 PLT 中)是一个多阶段操作,其中发生以下动作:

By using position independent code, along with the PLT and a global offset table (GOT), the first call to a function printf@plt (in the PLT) is a multi-stage operation, in which the following actions take place:

  • 您在 PLT 中调用 printf@plt.
  • 它调用 GOT 版本(通过指针),最初指向 PLT 中的某些设置代码.
  • 这个设置代码如果还没有加载相关的共享库,然后修改GOT指针,以便后续调用直接到真正的printf而不是PLT设置代码.
  • 然后它会在此进程的正确地址调用加载的 printf 代码.
  • You call printf@plt in the PLT.
  • It calls the GOT version (via a pointer) which initially points back to some set-up code in the PLT.
  • This set-up code loads the relevant shared library if not yet done, then modifies the GOT pointer so that subsequent calls directly to the real printf rather than the PLT set-up code.
  • It then calls the loaded printf code at the correct address for this process.

在后续调用中,因为修改了GOT指针,简化了多阶段的方式:

On subsequent calls, because the GOT pointer has been modified, the multi-stage approach is simplified:

  • 您在 PLT 中调用 printf@plt.
  • 它调用 GOT 版本(通过指针),它现在指向 real printf.

可以找到一篇好文章here,详细说明 glibc 在运行时是如何加载的.

A good article can be found here, detailing how glibc is loaded at run time.

这篇关于@plt 在这里是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆