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!
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!
Copyright © 2021 Jogjafile Inc.
foo@GOTPCREL(%rip)
is the GOT entry for the symbolfoo
, 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
, somov foo@GOTPCREL(%rip), %rax
loads&foo
into RAX. https://en.wikipedia.org/wiki/Global_Offset_Table. Often this is followed bymov (%rax), %eax
or similar to actually get the value of a global variable likeint 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-datesgcc -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
, justmov foo(%rip), %eax
to load it orlea 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 fromsin@GOTPCREL
, instead of just taking a pointer to its PLT stub withmov $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 variableOr like
gcc -fno-plt
mode, call library functions withcall *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 thefoo
label/symbol, not adding its absolute address to the end of this instruction like you might guess, or like123(%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 GNUas
manual, unfortunately. https://sourceware.org/binutils/docs/as/.