0

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!

user123
  • 2,510
  • 2
  • 6
  • 20
  • 3
    The answer you linked is correct: this is due to the possibility of symbol interposition. – fuz Feb 28 '22 at 23:06
  • Thanks, but can you explain further in an answer with some example? I don't get what is symbol interposition. I disposed of the answer in the link because I thought it was either incomplete or false. – user123 Feb 28 '22 at 23:36
  • I may do some research when I'm home about that. – user123 Feb 28 '22 at 23:36
  • Symbol interposition means that any shared library symbol that is not hidden or otherwise made exempt can be overridden from another shared library or the main program. This means that `glob_var` may eventually reside in a different place than expected. With variables, this is regularly the case when the main program refers to them. – fuz Feb 28 '22 at 23:51
  • By overriden, you mean that another shared library or the main program may redefine the symbol? – user123 Feb 28 '22 at 23:55
  • You are correct. – fuz Feb 28 '22 at 23:56
  • In this case, how is it determined which definition is the one actually used by the program during execution? – user123 Mar 01 '22 at 00:24
  • This depends on the order in which shared libraries are linked in. IIRC the earliest definition of each symbol is used and definitions in the main program always beat shared library definitions. – fuz Mar 01 '22 at 00:43
  • If multiple shared objects all use `int global_var;`, dynamic linking has to make sure that's the *same* global var in all libraries and the main executable. Unless you give it ELF visibility = hidden, in which case it's global to this shared object but separate from any variables in other shared objects. It's usually a good idea to make "hidden" the default and only export the functions / globals you actually *want* outside code to be able to link against and access by name. – Peter Cordes Mar 01 '22 at 04:10
  • Thanks very much. You've been very helpful. If any of you want to post that as an answer. – user123 Mar 01 '22 at 05:16

0 Answers0