gdb*_*gdb 71 assembly disassembly
0x00000000004004b6 <main+30>:   callq  0x400398 <printf@plt>
有谁知道?
UPDATE
为什么两个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>
pax*_*blo 112
这是一种获取代码修正的方法(根据代码在虚拟内存中的位置调整地址),而无需为每个进程维护代码的单独副本.PLT是过程链接表,其中一种结构使动态加载和链接更容易使用.
printf@plt实际上是一个小的存根(最终)调用真正的printf函数.
这个真实函数可以映射到给定进程(虚拟地址空间)中的任何位置,调用它的代码也可以映射到该位置.
因此,为了允许正确的代码共享调用代码(左下方),您不希望直接对其应用任何修正,因为这将限制它在其他进程中的位置.
的printf是一个较小的特定过程在一个可靠地计算-在运行时的地址区域没有进程之间共享,所以任何给定的过程,但是可以更改它就是了.
换句话说,请检查下图,该图显示了在两个进程中映射到不同虚拟地址的代码和库代码:
Address: 0x1234          0x9000      0x8888
        +-------------+ +---------+ +---------+
        |             | | Private | |         |
ProcA   |             | | PLT/GOT | |         |
        | Shared      | +---------+ | Shared  |
========| application |=============| library |==
        | code        | +---------+ | code    |
        |             | | Private | |         |
ProcB   |             | | PLT/GOT | |         |
        +-------------+ +---------+ +---------+
Address: 0x2020          0x9000      0x6666
该特定示例示出了PLT映射到固定位置的简单情况.在您的方案中,它位于相对于当前程序计数器的位置,如程序计数器相对查找所示:
<printf@plt+0>: jmpq  *0x2004c2(%rip)  ; 0x600860 <_GOT_+24>
可以在这里找到一篇好文章,详细说明如何PLT在运行时加载.
基本上,共享代码的原始方式意味着必须将它们加载到使用它的每个进程的虚拟地址空间中的相同内存位置.无论是那个还是无法共享,因为为一个进程修复单个共享副本的行为将完全填满另一个映射到不同位置的进程.
通过使用与位置无关的代码,以及PLT和全局偏移表(GOT),对函数的第一次调用ProcA(在PLT中)是一个多阶段操作,其中:
ProcB给PLT.printf@plt而不是设置代码.在后续调用中,由于GOT已被修改,因此简化了多阶段方法:
printf@plt给PLT.printf.不确定,但是您所看到的可能有意义。首次运行disas命令时,尚未调用printf,因此无法解决。一旦您的程序首次调用了printf方法,就更新了GOT,现在解析了printf,并且GOT指向了实函数。因此,对disas命令的下一次调用显示了实际的printf程序集。