在同一对象模块中调用过程是否需要在链接阶段进行重定位

时间:2018-04-05 13:09:24

标签: c linux compilation linker gnu

我假设在同一个对象模块中的过程调用在链接阶段不需要重定位。例如以下代码

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;

1 个答案:

答案 0 :(得分:2)

重定位表必须存储在每个模块中,用于 实际模块,以允许共享库的加载时重定位。

由于(大多数)Unix发行版中的动态链接器可以覆盖共享库中的函数,这意味着即使调用发生在单个模块中,也可以重定位该函数。像Valgrind这样的工具可以从仪器和泄漏检测等功能中受益。

因此,如注释中所述,如果您标记函数static,则编译器可以完全跳过此部分并对跳转进行硬编码。