ELF64加载器如何知道更新.got.plt中的初始地址?

问题描述 投票:1回答:1

考虑以下程序 hello.c:

#include <stdio.h>

int main(int argc, char** argv)
{
    printf("hello");
    return 0;
}

该文件是以下列方式汇编的 gcc -o hello -Og -g hello.c 然后装上 gdb hello.

检查GOT,以便呼叫 printfp '[email protected]' 给予

$1 = (<text from jump slot in .got.plt, no debug info>) 0x1036 <printf@plt+6>

即相应PLT条目中的第二条指令相对于本节开始的偏移量。

在启动程序并将其与 starti, p '[email protected]' 现在给

$2 = (<text from jump slot in .got.plt, no debug info>) 0x555555555036 <printf@plt+6>

也就是对应PLT条目中第二条指令的绝对地址。

我明白是怎么回事,为什么。我的问题是 动态链接器加载器如何知道将部分偏移量(0x1036)更新为绝对地址(0x555555555036)?

A p &'[email protected]' 链接前给

$1 = (<text from jump slot in .got.plt, no debug info> *) 0x4018 <[email protected]>

readelf -r simple 显示该地址的搬迁条目

Relocation section '.rela.plt' at offset 0x550 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000004018  000200000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0

但我的解读是 系统五应用二进制接口AMD64架构处理器补充版第76页,这些搬迁条目只有在以下情况下才会使用 LD_BIND_NOW 是非空的。是否有其他我遗漏的重定位条目?相对于GOT的最终地址,重定偏移量的机制是什么?

linux elf glibc
1个回答
0
投票

根据Drepper的说法 如何编写共享库动态链接器重定位两种依赖关系。

  1. 相对重定位:同一对象内各位置的依赖关系。链接器只需将对象的加载地址添加到目标目的地的偏移量中即可。
  2. 符号重新定位符号解析算法:基于复杂符号解析算法的更复杂、更昂贵的过程。

对于PLT的GOT,Drepper指出(§1.5.5) 在启动时,动态链接器用指向相应PLT条目的第二条指令的地址填充GOT槽。 读取 glibc 源代码表明,链接器确实循环过了 R_X86_64_JUMP_SLOT 搬迁(elf/do-rel.h:elf_dynamic_do_Rel),并递增它们所包含的偏移量(sysdeps/x86_64/dl-machine.h:elf_machine_lazy_rel):

if (__glibc_likely (r_type == R_X86_64_JUMP_SLOT))
  {
    /* Prelink has been deprecated.  */
    if (__glibc_likely (map->l_mach.plt == 0))
      *reloc_addr += l_addr;
    else
      ...

当使用懒惰的PLT绑定时(默认情况)。

© www.soinside.com 2019 - 2024. All rights reserved.