为什么需要重新定位同一文件中的全局符号?

时间:2017-09-08 09:11:31

标签: c gcc symbols object-files relocation

我有一个用于测试的C程序:a.c

int a = 0;

static int fa_local()
{
    a = 78; 
    int b;
    int c;
}

int fa_global()
{
    a = 7777;
    fa_local();
}

int test()
{
    a = 6666;
    fa_global();

}

这是构建后的重定位表:

[freeman@centos-7 link_symbol_test]$ gcc -c a.c
[freeman@centos-7 link_symbol_test]$ readelf -r a.o

Relocation section '.rela.text' at offset 0x5d0 contains 4 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000006  000900000002 R_X86_64_PC32     0000000000000000 a - 8
000000000016  000900000002 R_X86_64_PC32     0000000000000000 a - 8
000000000030  000900000002 R_X86_64_PC32     0000000000000000 a - 8
00000000003e  000a00000002 R_X86_64_PC32     0000000000000010 fa_global - 4

重定位条目是test()中的函数调用fa_global(),其偏移量为00000000003e。

[freeman@centos-7 link_symbol_test]$ objdump -dS a.o:

0000000000000010 <fa_global>:

int fa_global()
{
  10:   55                      push   %rbp
  11:   48 89 e5                mov    %rsp,%rbp
    a = 7777;
  14:   c7 05 00 00 00 00 61    movl   $0x1e61,0x0(%rip)        # 1e <fa_global+0xe>
  1b:   1e 00 00 
    fa_local();
  1e:   b8 00 00 00 00          mov    $0x0,%eax
  23:   e8 d8 ff ff ff          callq  0 <fa_local>
}
  28:   5d                      pop    %rbp
  29:   c3                      retq   

000000000000002a <test>:

int test()
{
  2a:   55                      push   %rbp
  2b:   48 89 e5                mov    %rsp,%rbp
    a = 6666;
  2e:   c7 05 00 00 00 00 0a    movl   $0x1a0a,0x0(%rip)        # 38 <test+0xe>
  35:   1a 00 00 
    fa_global();
  38:   b8 00 00 00 00          mov    $0x0,%eax
  3d:   e8 00 00 00 00          callq  42 <test+0x18>
}
  42:   5d                      pop    %rbp
  43:   c3                      retq

对于fa_global(),它位于同一个文件中。

为什么这个符号需要重新定位, 而静态符号fa_local()不是<?t?

2017.9.12更新:优化后的汇编代码

[freeman@centos-7 relocation_test]$ gcc -fno-inline -O2 -c a.c
[freeman@centos-7 relocation_test]$ objdump -dS a.o

a.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <fa_local>:
   0:   c7 05 00 00 00 00 4e    movl   $0x4e,0x0(%rip)        # a <fa_local+0xa>
   7:   00 00 00 
   a:   c3                      retq   
   b:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

0000000000000010 <fa_global>:
  10:   31 c0                   xor    %eax,%eax
  12:   c7 05 00 00 00 00 61    movl   $0x1e61,0x0(%rip)        # 1c <fa_global+0xc>
  19:   1e 00 00 
  1c:   eb e2                   jmp    0 <fa_local>
  1e:   66 90                   xchg   %ax,%ax

0000000000000020 <test>:
  20:   31 c0                   xor    %eax,%eax
  22:   c7 05 00 00 00 00 0a    movl   $0x1a0a,0x0(%rip)        # 2c <test+0xc>
  29:   1a 00 00 
  2c:   e9 00 00 00 00          jmpq   31 <test+0x11>

但我仍然看到重定位条目:

000000000000002d R_X86_64_PC32 fa_global-0x0000000000000004

2 个答案:

答案 0 :(得分:1)

fa_local是一个功能。编译器可以确定其与调用点的偏移量。它使用PC相对寻址模式进行调用指令,因此它不需要绝对地址,可以直接发出代码。

相反,a符号位于内存的不同部分,是可写段,其编译时无法确定其偏移量。链接器在重定位阶段执行此操作。

答案 1 :(得分:0)

就在这里该函数在同一个文件中,但是非静态函数也可以从稍后编译的其他文件中调用。

编译器无法知道是否会发生这种情况,因此它必须“为最坏的情况做好准备。”