In shared objects, why does gcc relocate through the GOT for global variables which are defined in the same shared object?

315 views Asked by At

While answering another question on Stack, I came upon a question myself. With the following code in shared.c:

#include "stdio.h"

int glob_var = 0;

void shared_func(){
    printf("Hello World!");
    glob_var = 3;
}

Compiled with:

gcc -shared -fPIC shared.c -oshared.so

If I disassemble the code with objdump -D shared.so, I get the following for shared_func:

0000000000001119 <shared_func>:
    1119:   f3 0f 1e fa             endbr64 
    111d:   55                      push   %rbp
    111e:   48 89 e5                mov    %rsp,%rbp
    1121:   48 8d 3d d8 0e 00 00    lea    0xed8(%rip),%rdi        # 2000 <_fini+0xebc>
    1128:   b8 00 00 00 00          mov    $0x0,%eax
    112d:   e8 1e ff ff ff          callq  1050 <printf@plt>
    1132:   48 8b 05 9f 2e 00 00    mov    0x2e9f(%rip),%rax        # 3fd8 <glob_var@@Base-0x54>
    1139:   c7 00 03 00 00 00       movl   $0x3,(%rax)
    113f:   90                      nop
    1140:   5d                      pop    %rbp
    1141:   c3                      retq

Using readelf -S shared.so, I get (for the GOT):

[22] .got              PROGBITS         0000000000003fd8  00002fd8
     0000000000000028  0000000000000008  WA       0     0     8

Correct me if I'm wrong but, looking at this, the relocation for accessing glob_var seems to be through the GOT. As I read on some websites, this is due to limitations in x86-64 machine code where RIP-relative addressing is limited to a 32 bits offset. This explanation is not satisfactory to me because, since the global variable is in the same shared object, then it is guaranteed to be found in its own data segment. The global variable could thus be accessed using RIP-relative addressing without an issue.

I would understand the GOT relocation if glob_var had been declared extern but, in this case, it is defined in the same shared object. Why does gcc require a relocation through the GOT? Is it because it is not able to detect that the global variable is defined within the same shared object?

Related: Why are nonstatic global variables defined in shared objects referenced using GOT?

The above is 11 years old and doesn't answer my question because there doesn't seem to be an appropriate answer there.

Bonus: what does <glob_var@@Base-0x54> mean in the disassembly of shared_func? Why it isn't <glob_var@GOT>?

Thanks for any help!

0

There are 0 answers