The same program, the same regions, the same order — but with ASLR every base address is re-rolled at every exec(). High-level user-space view of a 64-bit Linux process.
LINUX · x86-64 · USER-SPACE VIEW
1 The two pictures high addresses on top
Left: classic non-PIE binary with randomize_va_space=0 — you can hardcode any of these addresses in an exploit and they work every time. Right: PIE + full ASLR — white/pink address pairs show the same region on two different runs.
The relative layout inside a module never changes — .text, .data, and every function keep their offsets from the module base. Leak one pointer and you know where the whole module is. That is why info leaks defeat ASLR.
2 What actually moves and by how much
Region
ASLR off
ASLR on · typical x86-64 entropy
ELF image (non-PIE)
0x400000, fixed
still 0x400000 — image only moves if it is PIE
ELF image (PIE)
0x555555554000 (the famous gdb address)
0x55…/0x56…, ~28 bits
Heap (brk)
starts right after .bss, no gap
image end + random gap, ~13 bits
Shared libs / mmap
fixed 0x7ffff7…
0x7f…, ~28 bits (/proc/sys/vm/mmap_rnd_bits)
Stack
top at 0x7ffffffff000
0x7ffc…–0x7fff…, ~22 bits
vdso
fixed
randomized along with the mmap region
Kernel
separate mechanism (KASLR), decided once at boot, not per-process
The switch: /proc/sys/kernel/randomize_va_space
Value
Meaning
0
ASLR off — the left picture
1
stack, mmap/libs, vdso, PIE base randomized — but heap (brk) is not
2
everything in 1 plus the heap — the right picture (default)
ASLR ≠ PIE. ASLR is the kernel rolling dice; PIE is the binary being built relocatable so its image can join the game. Full ASLR + non-PIE binary = stack/heap/libs move but .text/.data sit at 0x400000 forever (this is what checksec’s PIE column is about).
3 See it on your machine two minutes
$ cat /proc/sys/kernel/randomize_va_space # 2 = full ASLR (default)
$ for i in 1 2; do grep -E 'heap|stack|libc' /proc/self/maps; echo; done
# every address differs between the two runs
$ setarch $(uname -m) -R grep -E 'heap|stack|libc' /proc/self/maps
$ setarch $(uname -m) -R grep -E 'heap|stack|libc' /proc/self/maps
# -R = ADDR_NO_RANDOMIZE for this one process: now identical runs
gdb disables ASLR by default — that’s why you always see 0x555555554000 for the image and 0x7ffff7… for libc while debugging. Turn it back on with set disable-randomization off.