Consider the following program hello.c
:
#include <stdio.h>
int main(int argc, char** argv)
{
printf("hello");
return 0;
}
The file is compiled with gcc -o hello -Og -g hello.c
and then loaded with gdb hello
.
Inspecting the GOT for the call to printf
with p 'printf@got.plt'
gives
$1 = (<text from jump slot in .got.plt, no debug info>) 0x1036 <printf@plt+6>
which is the offset of the second instruction in the corresponding PLT entry relative to the start of the section.
After starting and linking the program with starti
, p 'printf@got.plt'
now gives
$2 = (<text from jump slot in .got.plt, no debug info>) 0x555555555036 <printf@plt+6>
which is the absolute address of the second instruction in the corresponding PLT entry.
I understand what is going on and why. My question is how does the dynamic linker/loader know to update the section offset (0x1036) to the absolute address (0x555555555036)?
A p &'printf@got.plt'
before linking gives
$1 = (<text from jump slot in .got.plt, no debug info> *) 0x4018 <printf@got.plt>
and readelf -r simple
shows a relocation entry for this address
Relocation section '.rela.plt' at offset 0x550 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
000000004018 000200000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0
But my reading of the System V Application Binary Interface AMD64 Architecture Processor Supplement, p.76, is that these relocation entries are only used when LD_BIND_NOW
is non-null. Are there other relocation entries that I missed? What is the mechanism for rebasing offsets relative to the GOT's ultimate address?