I had a C program for test: 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();
}
This is its relocation table after build:
[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
the relocation entry is the funcation call fa_global() in test(), which has offset 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
For fa_global(), it is in the same file.
why would this symbol need to be relocated, while static symbol fa_local() doesn't?
2017.9.12 update: assembly code after optimization
[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>
But I still see the relocation entry:
000000000000002d R_X86_64_PC32 fa_global-0x0000000000000004
fa_local
is a function. The compiler can determine its offset from the calling point. it uses a PC relative addressing mode for the call instruction so it does not need the absolute address and can emit the code directly.Conversely, the
a
symbol is in a different section of memory, a writable segment whose offset cannot be determined at compile time. The linker does this in the relocation phase.