X86 ELF-了解R_386_PC32迁移

X86 ELF-了解R_386_PC32迁移,x86,elf,X86,Elf,我试图理解ELF中的重新定位,但我在这方面的文档中遇到了一些问题,这是相当神秘的。例如,重定位方程描述了3个参数,S,A和P。现在我知道A只是一个加数,它是用来帮助重定位计算的数字,S是索引位于重定位项中的符号的“值”(与函数名相同,对吗?),但是P呢?手册将其描述为“重新安置存储单元的位置”,但这到底意味着什么 我刚刚找到了一个例子来说明这一点:假设我们有两个对象文件,obj1.o和obj2.o。第一个引用了一个名为foo()的函数,该函数位于obj2.o内部 objdump-d obj1.o

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

我刚刚找到了一个例子来说明这一点:假设我们有两个对象文件,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   
节的反汇编。文本:
00000000 :
0:55推力%ebp
1:89 e5 mov%esp,%ebp
3:83 ec 08子$0x8,%esp
6:e8 fc ff呼叫7
b:c9请假
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
objdump-d
测试:文件格式elf32-i386
第节的分解。正文:
080480d8:
80480d8:55推力%ebp
80480d9:89 e5 mov%esp,%ebp
80480db:83 ec 08子$0x8,%esp
80480de:e8 05 00 00呼叫80480e8
80480e3:c9离开
80480e4:c3 ret
80480e5:90无
80480e6:90无
80480e7:90无
080480e8:
80480e8:55推力%ebp
80480e9:89 e5 mov%esp,%ebp
80480eb:5d pop%ebp
80480ec:c3 ret
因此,链接器似乎执行了以下计算:S+A–p:0x80480e8+0xfffffc–0x80480df

我的问题是:

  • P的值从哪里来
  • 有加数有什么意义

p是程序计数器,因此这是一个与PC相对的重新定位。我没有准确检查ELF32用作参考点的内容。从未链接的
调用rel32
中的
fc ff=-4
判断,这可能是4字节移位的开始。在机器代码中,以指令结尾(即下一条指令的开始)为基础的相对跳跃,因此可以解释4字节的偏移量

这是加数的一个用例

另一种是PC机对静态数据进行相对寻址,以生成位置无关的代码。您的PC引用可能就在附近,但甚至不在使用它的指令内,或者您希望为全局数组编制索引

所以你可能会有

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

或者,对于一个真实的示例,为
-m32-PIE
加载一个全局文件。(但是全局偏移量表符号名称得到特殊处理,因此我不打算重现编译器asm输出。)

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

所以S-p是这两个地址之间的距离(字节)


然而,call rel32指令计算从下一条指令开始的距离(rel32),距离p有4个字节的偏移量,因此a-4。

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