I've been looking at some disassembly of some ELF binaries and I noticed this:
0000000000401020 <_start>:
401020: 31 ed xor ebp,ebp
401022: 49 89 d1 mov r9,rdx
401025: 5e pop rsi
401026: 48 89 e2 mov rdx,rsp
401029: 48 83 e4 f0 and rsp,0xfffffffffffffff0
40102d: 50 push rax
40102e: 54 push rsp
40102f: 49 c7 c0 30 13 40 00 mov r8,0x401330
401036: 48 c7 c1 d0 12 40 00 mov rcx,0x4012d0
40103d: 48 c7 c7 72 12 40 00 mov rdi,0x401272
401044: ff 15 a6 2f 00 00 call QWORD PTR [rip+0x2fa6] # 403ff0 <__libc_start_main@GLIBC_2.2.5>
40104a: f4 hlt
40104b: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0]
When __libc_start_main
gets called, we have those three immediate values passed via registers as parameters. Those are obviously function pointers that get called in __libc_start_main
(including main
). But these are virtual addresses, and my understanding is that the actual mapped address of the binary when it's loaded into memory and running will not necessarily be the same. So, these function pointers may not reflect their actual location in memory.
Being more acquainted with PE files, the IMAGE_DIRECTORY_BASERELOC
section provides us with IMAGE_BASE_RELOCATION
structures that help us adjust these constant values to reflect the new image base. But I don't see any equivalent of that for ELF files. Am I missing something here? How do these addresses get fixed when an ELF file is loaded?