Skip to content

Concepts

general

PIE & ASLR (position-independent code)

Why modern binaries load at a random base address every run, how position-independent code uses RIP-relative addressing to cope, and what that means for reversing and exploitation.

ASLR (Address Space Layout Randomization) is an OS mitigation that loads the stack, heap, shared libraries — and, with PIE, the executable itself — at a randomised base address on every run. PIE (Position-Independent Executable) is the compiler/linker mode that makes the main program able to run at any base, which is what lets ASLR randomise it too.

Why code has to be position-independent

If the load address isn't known until runtime, code can't hard-code absolute addresses for its own functions and globals. PIE solves this on x86-64 with RIP-relative addressing: operands are encoded as a signed offset from the current instruction pointer, so the same machine code works at any base.

asm
; non-PIE: absolute address baked into the instruction
mov eax, DWORD PTR [0x404060]      ; global at a fixed VA

; PIE: address computed relative to RIP
mov eax, DWORD PTR [rip + 0x2f1a]  ; global = (next insn) + 0x2f1a
lea rdi, [rip + 0x1c0]             ; &string, position-independent

On AArch64 the same job is done by the adrp + add/ldr pair, which forms an address relative to the program counter.

Static vs runtime addresses

This is the practical headache for reverse engineers:

  • The addresses you see in a disassembler are static (file/preferred VAs).
  • At runtime everything is shifted by a random load base (the "slide").
  • Runtime address = static address + base. To correlate a debugger's live addresses with your static analysis, find the base (e.g. from /proc/<pid>/maps, the debugger's module list, or vmmap) and subtract it.

Reverse-engineering & exploitation notes

  • A binary full of [rip + …] / lea …, [rip + …] is PIE; one with bare absolute addresses ([0x4xxxxx]) is a classic non-PIE executable, which always loads at the same base — much easier to script against.
  • ASLR is the reason an information leak is the first step of most modern exploits: you must leak one runtime address to defeat the randomisation before a hard-coded 0x4011... payload would work again.
  • PIE is required for the main executable to be randomised; shared libraries (.so/PIC) have always been position-independent. Check with file (pie executable vs executable) or readelf -h (Type: DYN = PIE, EXEC = non-PIE).
  • The randomised global/function references in PIE go through the GOT/PLT for external symbols; understanding both together explains how a PIE binary resolves anything outside itself.

See also: GOT & PLT · Addressing modes · Memory protection (NX / W^X).