4

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

Freeman
  • 61
  • 6
  • Try compiling with optimization. – o11c Sep 11 '17 at 03:55
  • @o11c, seems it works due to fa_global is somehow like being inlined to test(), which means test() does not actually calls fa_global(). But of course, it still can be accessed by external. – Freeman Sep 11 '17 at 06:35
  • I tried even with `__attribute__((noinline))` and optimization still removes the relocation. – o11c Sep 12 '17 at 06:08
  • @o11c, please see my update at the last part. Are you checking the object file after compiled but before linking? – Freeman Sep 12 '17 at 08:13
  • Use `objdump -drwC` to include relocation annotations on the disassembly. (The `-r` option). I also like `-Mintel`. This got re-asked as [Why function that refers to a global function in the same section can only be solved at link time while local functions will be solve at compile time?](https://stackoverflow.com/q/70323125) - still no answer why GAS or LLVM don't fully resolve `call fa_global` or `jmp fa_global` at assemble time. (GAS does for `jmp fa_global`, using a 2-byte `jmp rel8`, but clang doesn't) – Peter Cordes Dec 12 '21 at 22:18

2 Answers2

3

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.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Hi @chqrlie, actually what I had question is for fa_global function – Freeman Sep 08 '17 at 09:37
  • `fa_global` has external linkage, which may explain why the compiler generates a relocation entry. There is a possibility that the call to `fa_local` be expanded inline, so there is no relocation entry because there is no call opcode. Can you post the code generated for `fa_global`? – chqrlie Sep 12 '17 at 05:26
  • seems it will not inline by default when -Ox is not set. man gcc, -fno-inline: "Do not expand any functions inline apart from those marked with the "always_inline" attribute. This is the default when not optimizing." – Freeman Sep 12 '17 at 08:15
1

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."

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • Why does external program need relocation table to link to fa_global? I thought they can link to fa_global by the symbol table? I tried "objdump -dS" and find out the relocation entry is the address which the assembly callq instruction will jump to. (I've updated this to the post) – Freeman Sep 11 '17 at 03:41
  • If you tried to link another `.o` that also defined `fa_global`, you'd get an error: `multiple definitions of 'fa_global'`. So that doesn't really explain this. Probably functions *can* be marked as ignoring multiple identical definitions (to support C and/o C++ `inline` keyword linkage semantics), and maybe GAS is missing the possible optimization even when the visible definition *doesn't* use that. – Peter Cordes Dec 12 '21 at 22:21