我假设在同一个对象模块中的过程调用在链接阶段不需要重定位。例如以下代码
void callee()
{
printf("Should I be relocated\n");
}
void caller()
{
callee();
}
编译/汇编后,我得到了以下
Relocation section '.rel.text' at offset 0x438 contains 3 entries:
Offset Info Type Sym.Value Sym. Name
00000009 00000501 R_386_32 00000000 .rodata
0000000e 00000a02 R_386_PC32 00000000 puts
0000001b 00000902 R_386_PC32 00000000 callee
反汇编的结果:
Disassembly of section .text:
00000000 <callee>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 18 sub $0x18,%esp
6: c7 04 24 00 00 00 00 movl $0x0,(%esp)
d: e8 fc ff ff ff call e <callee+0xe>
12: c9 leave
13: c3 ret
00000014 <caller>:
14: 55 push %ebp
15: 89 e5 mov %esp,%ebp
17: 83 ec 08 sub $0x8,%esp
1a: e8 fc ff ff ff call 1b <caller+0x7>
1f: c9 leave
20: c3 ret
为什么程序调用同一个对象模块(1a:e8 ff ff ff ff ff ff ff call 1b)需要重定位?它取决于我的工具链吗?在相同的对象模块中调用过程时,PC相对地址(调用者和被调用者之间的地址偏移)是否有机会更改?如果没有,为什么不把代码修改为0x1a到&#34; e8 e1 ff ff ff&#34;
答案 0 :(得分:2)
重定位表必须存储在每个模块中,用于 实际模块,以允许共享库的加载时重定位。
由于(大多数)Unix发行版中的动态链接器可以覆盖共享库中的函数,这意味着即使调用发生在单个模块中,也可以重定位该函数。像Valgrind这样的工具可以从仪器和泄漏检测等功能中受益。
因此,如注释中所述,如果您标记函数static
,则编译器可以完全跳过此部分并对跳转进行硬编码。