STACK
Understanding the call stack architecture including stack frames, registers (EBP, ESP, EIP), function prologues and epilogues, and stack-based memory layout.
Contents
What is the Stack?
The call stack (or just “stack”) is a special region of a program’s memory used for managing function calls and local (temporary) data. It’s like a stack of plates: you push new items on top when entering a function, and pop them off when exiting. This ensures everything happens in the correct order (last in, first out – LIFO).
The stack handles:
- Local variables (e.g., buffers, ints in a function)
- Function parameters (in older calling conventions)
- Saved registers
- Return address (where to go back after the function finishes)
It’s fast because it’s managed automatically by the CPU instructions (like push, pop, call, ret on x86).
Why the Stack Grows Downwards
In most architectures (including x86/x86_64 on Linux/Kali), the stack starts at high memory addresses and grows towards lower addresses (downwards).
Reason:
- The program’s code, data, and heap (dynamic memory from malloc) start at low addresses and grow upwards.
- This leaves a big empty space in the middle for both to expand freely without fixed limits.


Typical Linux process virtual memory layout: Code/data at bottom (growing ↑), stack at top (growing ↓), heap in between.
Key Registers Involved (x86 32-bit Example)
- EIP (Instruction Pointer): Points to the next instruction to execute.
- ESP (Stack Pointer): Points to the top of the stack (lowest address currently in use). Moves down on push/call.
- EBP (Base/Frame Pointer): Points to the base (higher address) of the current function’s frame. Used for easy access to locals.


Detailed Stack Frame Layout (One Function’s Space)
When a function is called (function prologue):
- call instruction pushes the return address and jumps.
- push ebp saves old EBP.
- mov ebp, esp sets new frame.
- sub esp, N allocates space for locals (moves ESP down).
Layout from high address to low address:






- Arguments (pushed by caller, higher than EBP)
- Saved EIP (return address – critical for control flow)
- Saved EBP (old frame pointer)
- Local variables/buffers (allocated by sub esp)
- ESP points here ↓ (grows down)
Why This Matters for Exploits: Buffer Overflow
Vulnerable code like strcpy(buffer, input) doesn’t check size. If you send too much input:
- It fills the buffer.
- Overflows into saved EBP.
- Then overwrites saved EIP (return address).
When function returns (ret): Pops EIP → program jumps to your controlled address → code execution!


Classic stack smashing: Overflow travels “up” the frame (towards higher addresses) to hit the return address.
This is the foundation of basic binary exploitation (what you’re learning now). Modern protections (ASLR, NX, Stack Canaries) make it harder, but understanding the raw stack is key to everything else (ROP, heap exploits, etc.).