Trace: A Function Call in C++
The Call Stack
High Address
┌─────────────────┐
│ bar() frame │ ← SP (top of stack)
│ y = ? │
├─────────────────┤
│ foo() frame │
│ y = 10 │
│ return addr │
├─────────────────┤
│ main() frame │
│ x = 42 │
│ return addr │
└─────────────────┘ Low AddressWhat Happens at Each Step
-
main()starts — the runtime creates the initial stack frame formain(). The stack pointer (RSP) points to the top of this frame. -
Local variable
x = 42—xis allocated inmain()'s stack frame. The compiler knows the offset from the stack pointer (e.g.,xis atRSP + 4). -
foo()is called — before transferring control, the CPU pushes the return address (the instruction after thecallinstruction) onto the stack. Thecallinstruction also jumps tofoo()'s code. -
foo()'s prologue —foo()'s first instructions (the prologue) set up a new stack frame: it moves the old base pointer (RBP) and sets a new one. -
Local variable
y = 10—yis allocated infoo()'s stack frame at a known offset. -
bar(5)is called — the argument5is pushed, then the return address, thenbar()'s frame is set up. This is stack growth — more frames are added on top. -
bar()executes —bar()computesresult = 5 * 2 = 10and stores it. -
bar()returns — theretinstruction pops the return address from the stack, jumps back tofoo(), andbar()'s frame is effectively discarded (the stack pointer moves back). -
foo()returns — same process. The stack pointer moves back, freeingfoo()'s frame. -
main()finishes — the runtime cleans upmain()'s frame and the process exits.
Key Takeaways
- Each function call pushes a stack frame (also called an activation record).
- The stack grows downward in memory (from high addresses to low).
- Function arguments and return addresses are stored on the stack.
- When a function returns, its stack frame is popped — all its local variables become invalid.
- A stack overflow occurs when the stack grows too large (e.g., infinite recursion).