ELF - 了解 R_386_PC32 重定位
ELF - Understanding R_386_PC32 relocations
我正在尝试了解 ELF 中的重定位,但我在阅读这方面的文档时遇到了一些问题,该文档相当神秘。例如,重定位方程描述了 3 个参数,S、A 和 P。现在我知道 A 只是加数,它是一些用于帮助重定位计算的数字,S 是 "Value of the symbol whose index resides in the relocation entry"(和函数名一样吧?)但是P呢?手册将其描述为 "the place of the storage unit being relocated" 但这到底是什么意思?
我刚找到一个例子来说明这一点:假设我们有 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 [=11=]x8,%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 [=12=]x8,%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的值从何而来?
- 加数有什么意义?
P是Program-Counter,所以这是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
或者对于 真实 示例,look at what gcc and clang do 对于 -m32 -PIE
加载全局。 (但是全局偏移 table 符号名称得到特殊处理,所以我不打算重现编译器 asm 输出。)
S = 0x80480e8为符号起始地址(foo()的入口地址)
P = 0x80480df 为需要修改(重定位)值的地址
所以S-P就是这两个地址之间的距离(以字节为单位)
然而,调用rel32指令计算从下一条指令开始的距离(rel32),并且与P有4个字节的偏移量,所以-4。
我正在尝试了解 ELF 中的重定位,但我在阅读这方面的文档时遇到了一些问题,该文档相当神秘。例如,重定位方程描述了 3 个参数,S、A 和 P。现在我知道 A 只是加数,它是一些用于帮助重定位计算的数字,S 是 "Value of the symbol whose index resides in the relocation entry"(和函数名一样吧?)但是P呢?手册将其描述为 "the place of the storage unit being relocated" 但这到底是什么意思?
我刚找到一个例子来说明这一点:假设我们有 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 [=11=]x8,%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 [=12=]x8,%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的值从何而来?
- 加数有什么意义?
P是Program-Counter,所以这是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
或者对于 真实 示例,look at what gcc and clang do 对于 -m32 -PIE
加载全局。 (但是全局偏移 table 符号名称得到特殊处理,所以我不打算重现编译器 asm 输出。)
S = 0x80480e8为符号起始地址(foo()的入口地址) P = 0x80480df 为需要修改(重定位)值的地址
所以S-P就是这两个地址之间的距离(以字节为单位)
然而,调用rel32指令计算从下一条指令开始的距离(rel32),并且与P有4个字节的偏移量,所以-4。