我正在尝试理解 ELF 中的重定位,但是我在处理这方面的文档时遇到了一些麻烦,因为它相当神秘。例如,重定位方程描述了 3 个参数:S、A 和 P。现在我知道 A 只是加数,它是用于帮助重定位计算的一些数字,而 S 是“索引位于的符号的值”搬迁条目”(与函数名称相同,对吧?)但是 P 呢?手册将其描述为“存储单元被重新安置的位置”,但这到底是什么意思呢?
\n\n我刚刚找到一个例子来说明这一点:假设我们有 2 个目标文件,obj1.o和obj2.o。第一个引用了一个名为 foo() 的函数,该函数位于obj2.o内部。
\n\nobjdump -d obj1.o产生:
\n\nDisassembly of section .text:\n00000000 <func>:\n0: 55 push %ebp\n1: 89 e5 mov %esp,%ebp\n3: 83 ec 08 sub $0x8,%esp\n6: e8 fc ff ff ff call 7 <func+0x7>\nb: c9 leave \nc: c3 ret \nRun Code Online (Sandbox Code Playgroud)\n\n现在,readelf表明这是一个R_386_PC32重定位,其方程为:S + A - P。
\n\n将这两个文件组合起来生成完整的可执行文件re located后,重定位条目显然已被修补:
\n\nobjdump -d relocated\ntest: file format elf32-i386\nDisassembly of section .text:\n080480d8 <func>:\n80480d8: 55 push %ebp\n80480d9: 89 e5 mov %esp,%ebp\n80480db: 83 ec 08 sub $0x8,%esp\n80480de: e8 05 00 00 00 call 80480e8 <foo>\n80480e3: c9 leave \n80480e4: c3 ret \n80480e5: 90 nop\n80480e6: 90 nop\n80480e7: 90 nop\n080480e8 <foo>:\n80480e8: 55 push %ebp\n80480e9: 89 e5 mov %esp,%ebp\n80480eb: 5d pop %ebp\n80480ec: c3 ret\nRun Code Online (Sandbox Code Playgroud)\n\n因此,链接器似乎执行了以下计算:S + A \xe2\x80\x93 P: 0x80480e8 + 0xfffffffc \xe2\x80\x93 0x80480df
\n\n我的问题是:
\n\nP 是程序计数器,因此这是与 PC 相关的重定位。我没有具体检查 ELF32 使用什么作为参考点。从fc ff ff ff = -4un-linked中的来看call rel32,很可能是4字节位移的开始。在机器代码中,相对跳转以指令的call rel32结尾(即下一条指令的开始)为基数,这样就可以解释4字节的偏移量。
这是加数的一个用例。
另一个是对静态数据的 PC 相对寻址,以生成与位置无关的代码。您的 PC 引用可能就在附近,但甚至不在您使用它的指令内,或者您想要索引全局数组。
所以你可能有类似的东西
call get_eip_into_ebx
mov $table - this_instruction + 40(%ebx), %ecx
Run Code Online (Sandbox Code Playgroud)
或者举一个真实的例子,看看 gcc 和 clang 是如何加载-m32 -PIE全局变量的。(但是全局偏移表符号名称会得到特殊处理,因此我不会重现编译器 asm 输出。)
| 归档时间: |
|
| 查看次数: |
1476 次 |
| 最近记录: |