Why does global symbol in the same file needed to be relocated?

324 views Asked by At

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

2

There are 2 answers

3
chqrlie On

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.

2
Bo Persson On

Right here the function is in the same file, but being non-static it can also be called from other files compiled later.

The compiler cannot know if that will happen, so it has to "prepare for the worst."