What does <some symbol>@GOTPCREL(%rip)
mean?
I've come across this line mov var@GOTPCREL(%rip), %rax
and was a bit puzzled about the weird syntax.
Can someone please recommend the relevant docs I should read to understand this? Thanks!
foo@GOTPCREL(%rip)
is the Global Offset Table (GOT) entry for the symbol foo
, accessed with a RIP-relative addressing mode.
The GOT entry is filled in by the dynamic linker (supporting symbol interposition), and holds the absolute address of the symbol foo
, so mov foo@GOTPCREL(%rip), %rax
loads &foo
into RAX. Often this is followed by mov (%rax), %eax
or similar to actually get the value of a global variable like int foo;
, in a shared library where our definition of the symbol may not be the one the main executable is using. (See Thiago Macieira's blog: Sorry state of dynamic libraries on Linux from 2012; it pre-dates gcc -fno-plt
, and also predates PIE executables, but the situations for shared libraries accessing global variables hasn't improved.)
Normally you'd only ever use foo@GOTPCREL(%rip)
for a global variable address in a shared library, not an executable (not even a PIE executable). Compilers assume that the main executable's global vars won't be "shadowed" by symbol interposition. (In a shared library, you can give symbols "hidden" ELF visibility so compilers will access them directly, knowing they won't participate in symbol interposition.)
For int foo
, just mov foo(%rip), %eax
to load it or lea foo(%rip), %rdi
to take its address without going through the GOT.
But for function calls, if you want a pointer to a library function like sin
, you can certainly get the final address in libm itself from loading a pointer from sin@GOTPCREL
, instead of just taking a pointer to its PLT stub with mov $sin, %edi
(and letting the linker rewrite sin to sin@plt when the symbol isn't found in anything you're statically linking, only a shared lib). GCC's choice of which do use depends on how you're compiling. (PIE vs. traditional position-dependent, and/or -fno-plt
or not.) Unexpected value of a function pointer local variable
Or like gcc -fno-plt
mode, call library functions with call *sin@gotpcrel(%rip)
to use an indirect call through its GOT entry, basically inlining almost the same thing the PLT stub would, and forcing early binding instead of lazy (resolve the GOT entries at startup, instead of on first call.)
The NASM equivalent is call [rel printf wrt ..got]
.
Note that foo(%rip)
uses the relative offset from here to the foo
label/symbol, not adding its absolute address to the end of this instruction like you might guess, or like 123(%rip)
does. But the
PCREL part of GOTPCREL is clearly referring to a PC-relative offset to the GOT entry from here.
Similar to @gotpcrel, you can do stuff like call printf@plt
to explicitly call a function through a PLT entry. I didn't find @gotpcrel documented in the GNU as
manual, unfortunately. https://sourceware.org/binutils/docs/as/.