ELF64加载程序如何知道如何更新.got.plt中的初始地址? [英] How does the ELF64 loader know to update the initial addresses in .got.plt?

查看:87
本文介绍了ELF64加载程序如何知道如何更新.got.plt中的初始地址?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下程序 hello.c :

#include <stdio.h>

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

使用 gcc -o hello -Og -g hello.c 编译文件,然后使用 gdb hello 加载文件.

The file is compiled with gcc -o hello -Og -g hello.c and then loaded with gdb hello.

使用 p'printf@got.plt'检查对调用 printf 的GOT可以

Inspecting the GOT for the call to printf with p 'printf@got.plt' gives

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

这是相应PLT条目中第二条指令相对于节开头的偏移量.

which is the offset of the second instruction in the corresponding PLT entry relative to the start of the section.

启动并使用 starti 链接程序后, p'printf@got.plt'现在给出

After starting and linking the program with starti, p 'printf@got.plt' now gives

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

是相应PLT条目中第二条指令的绝对地址.

which is the absolute address of the second instruction in the corresponding PLT entry.

我了解发生了什么以及为什么.我的问题是动态链接程序/加载器如何知道将节​​偏移量(0x1036)更新为绝对地址(0x555555555036)?

I understand what is going on and why. My question is how does the dynamic linker/loader know to update the section offset (0x1036) to the absolute address (0x555555555036)?

链接前的 p&'printf@got.plt'

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

readelf -r simple 显示此地址的重定位条目

and readelf -r simple shows a relocation entry for this address

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

但是,我阅读的系统V应用程序二进制接口AMD64体系结构处理器补充内容,第76页,仅当 LD_BIND_NOW 不为空时,才使用这些重定位条目.还有其他我想念的搬迁条目吗?相对于GOT最终地址重新设置偏移量的机制是什么?

But my reading of the System V Application Binary Interface AMD64 Architecture Processor Supplement, p.76, is that these relocation entries are only used when LD_BIND_NOW is non-null. Are there other relocation entries that I missed? What is the mechanism for rebasing offsets relative to the GOT's ultimate address?

推荐答案

根据Drepper的操作方法写共享库,动态链接器将重新定位两种依赖项:

According to Drepper's How To Write Shared Libraries, the dynamic linker relocates two kinds of dependencies:

  1. 相对重定位:对同一对象内位置的依赖性.链接器只是将对象的加载地址添加到目标目的地的偏移量中.
  2. 符号重定位:基于复杂的符号解析算法的过程更加复杂且昂贵.
  1. Relative relocations: dependencies to locations within the same object. The linker simply adds the load address of the object to the offset to the target destination.
  2. Symbol relocations: more complicated and expensive process based on a sophisticated symbol resolution algorithm.

对于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 ):

For the PLT's GOT, Drepper states (§1.5.5) At startup time the dynamic linker fills the GOT slot with the address pointing to the second instruction of the appropriate PLT entry. A reading of the glibc source code suggests that the linker indeed loops through the R_X86_64_JUMP_SLOT relocations (elf/do-rel.h:elf_dynamic_do_Rel) and increments the offsets they contain (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绑定时(默认情况).

when lazy PLT binding is used (the default case).

这篇关于ELF64加载程序如何知道如何更新.got.plt中的初始地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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