2017-09-08 168 views
0

我有测试C程序:AC为什么需要重新定位同一文件中的全局符号?

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(); 

} 

这是它的重定位表生成后:

[[email protected] link_symbol_test]$ gcc -c a.c 
[[email protected] 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 

搬迁项是funcation调用fa_global()在试验(+),其中有偏移量00000000003e。

[[email protected] 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()没有?


2017年9月12日更新:优化后汇编代码

[[email protected] relocation_test]$ gcc -fno-inline -O2 -c a.c 
[[email protected] 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

+0

尝试使用优化进行编译。 – o11c

+0

@ o11c,似乎它的工作原因是fa_global有点像被内联到test(),这意味着test()实际上不会调用fa_global()。但当然,它仍然可以通过外部访问。 – Freeman

+0

我甚至用'__attribute __((noinline))'尝试过,优化仍然会消除重定位。 – o11c

回答

1

fa_local是一个函数。编译器可以确定它与调用点的偏移量。它为呼叫指令使用PC相对寻址模式,因此它不需要绝对地址并可以直接发送代码。

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

+0

嗨@chqrlie,其实我的问题是fa_global函数 – Freeman

+0

'fa_global'有外部链接,这可以解释为什么编译器会生成一个重定位条目。有可能对'fa_local'的调用内嵌扩展,所以没有重定位项,因为没有调用操作码。你能发布为'fa_global'生成的代码吗? – chqrlie

+0

当-Ox未设置时,它似乎不会默认内联。 man gcc,-fno-inline:“不要将任何内联函数扩展为标记为”always_inline“属性的内联函数,这是未优化时的默认值。” – Freeman

0

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

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

+0

为什么外部程序需要重定位表链接到fa_global?我认为他们可以通过符号表链接到fa_global? 我试过“objdump -dS”,找出重定位入口是程序​​集callq指令将跳转到的地址。 (我更新了这个帖子) – Freeman

相关问题