【问题标题】:ELF - Understanding R_386_PC32 relocationsELF - 了解 R_386_PC32 重定位
【发布时间】:2018-10-25 16:54:45
【问题描述】:

我正在尝试了解 ELF 中的重定位,但我在使用这方面的文档时遇到了一些问题,这相当神秘。例如,重定位方程描述了 3 个参数,S、A 和 P。现在我知道 A 只是加数,它是一些用于帮助重定位计算的数字,而 S 是 " 符号的值index 位于重定位条目中”(与函数名称相同,对吗?)但是 P 呢?手册将其描述为“被重新安置的存储单元的位置”,但这究竟意味着什么?

我刚刚找到一个例子来说明这一点:假设我们有 2 个目标文件,obj1.o 和 obj2.o。第一个引用了一个名为 foo() 的函数,该函数位于 obj2.o 中。

objdump -d obj1.o 产生:

Disassembly of section .text:
00000000 <func>:
0:   55                      push   %ebp
1:   89 e5                   mov    %esp,%ebp
3:   83 ec 08                sub    $0x8,%esp
6:   e8 fc ff ff ff          call 7 <func+0x7>
b:   c9                      leave  
c:   c3                      ret   

现在,readelf 表明这是一个 R_386_PC32 重定位,其方程为:S + A - P。

在组合这两个文件以生成完整的可执行文件重定位后,重定位条目显然已修补:

objdump -d relocated
test:     file format elf32-i386
Disassembly of section .text:
080480d8 <func>:
80480d8:   55                      push   %ebp
80480d9:   89 e5                   mov    %esp,%ebp
80480db:   83 ec 08                sub    $0x8,%esp
80480de:   e8 05 00 00 00          call   80480e8 <foo>
80480e3:   c9                      leave  
80480e4:   c3                      ret    
80480e5:   90                      nop
80480e6:   90                      nop
80480e7:   90                      nop
080480e8 <foo>:
80480e8:   55                      push   %ebp
80480e9:   89 e5                   mov    %esp,%ebp
80480eb:   5d                      pop    %ebp
80480ec:   c3                      ret

看来链接器执行了以下计算:S + A – P: 0x80480e8 + 0xfffffffc – 0x80480df

我的问题是:

  • P 的值从何而来?
  • 加数有什么意义?

【问题讨论】:

    标签: x86 elf


    【解决方案1】:

    P 是程序计数器,所以这是一个 PC 相关的重定位。我没有准确检查 ELF32 使用什么作为参考点。从未链接的call rel32中的fc ff ff ff = -4来看,大概是4字节位移的开始。在机器码中,像call rel32指令的end之类的相对跳转(即下一条指令的开始)作为基础,这样就可以解释4字节的偏移量了。

    这是加数的一个用例。

    另一种方法是对静态数据进行相对于 PC 的寻址,以生成与位置无关的代码。您的 PC 引用可能就在附近,但甚至不在您使用它的指令中,或者您想要索引全局数组。

    所以你可能有类似的东西

    call get_eip_into_ebx
    mov $table - this_instruction + 40(%ebx), %ecx
    

    或者对于 real 示例,look at what gcc and clang do 用于 -m32 -PIE 加载全局。 (但全局偏移表符号名称会得到特殊处理,因此我不会重现编译器 asm 输出。)

    【讨论】:

    • 这个答案是错误的,还是只是因为我没有尝试让它值得赏金而被否决?不值得一票否决的 IMO。
    • 不是我 Peter(您可以查看我上次登录的时间是昨天),但我真的一如既往地感谢您的回答
    • @Trey:别担心,我没有假设你是反对者。很有可能我从代码中推断出的一些东西不是 100% 正确的,所以我不得不问它是否真的是错误的:P。我认为这对于理解它的工作原理来说已经足够接近了,但是如果我实际上是在实现自己的链接器,我不会完全相信这个答案。我猜你对了解引擎盖下的内容更感兴趣,我很确定它是准确的。
    【解决方案2】:

    S = 0x80480e8 是符号起始地址(foo() 的入口地址) P = 0x80480df 是需要修改(被重定位)值的地址

    所以 S-P 是这两个地址之间的距离(以字节为单位)

    但是,调用 rel32 指令计算从下一条指令开始的距离(rel32),并且与 P 有 4 个字节的偏移量,因此为 -4。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-23
      • 2013-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-30
      • 2013-06-20
      • 2011-10-14
      相关资源
      最近更新 更多