HomeARM CourseDay 14
DAY 14 · THE INSTRUCTION SET

The Stack — PUSH, POP & How It Grows

By EcrioniX · Updated Jun 6, 2026

You have only 16 registers, but programs nest calls and juggle far more data. The answer is the stack — a last-in-first-out scratchpad in memory, pointed to by SP. Today: how it works, which way it grows, and the PUSH/POP idioms behind every function.

1. What the stack is for

The stack is a region of RAM used as a LIFO (last-in, first-out) scratchpad, addressed by the Stack Pointer, SP (R13) from Day 3. Programs use it to:

💡 Analogy

A stack of plates. You push a new plate on top and pop the top one off. The last plate on is the first off. SP always marks the top plate.

2. ARM's convention: full-descending

Two questions define a stack: which way does it grow, and does SP point at the last full slot or the next empty one? ARM's standard is full-descending:

So PUSH = decrement SP, then store. POP = load, then increment SP.

higher addr ┌──────────────┐ │ (older) │ │ saved r5 │ │ saved r4 │ SP ─────▶ │ saved lr │ ← top of stack (last pushed) lower addr └──────────────┘ grows DOWN ↓ as you push

3. PUSH and POP

PUSH and POP take a register list and do the SP bookkeeping for you:

PUSH {r4, r5, lr} ; save r4, r5 and the return address ; ... use r4, r5 freely ... POP {r4, r5, pc} ; restore r4, r5 — and return! (lr → pc)

Notice the elegant trick on the way out: pushing lr and popping it directly into pc restores the registers and performs the function return in one instruction. Registers are always stored in a fixed order regardless of how you list them, so a matching POP unwinds correctly.

4. The LDM/STM truth underneath

From Day 10, PUSH/POP are just friendly names for load/store multiple with the full-descending stack mode and writeback:

You writeReally is
PUSH {regs}STMFD sp!, {regs}
POP {regs}LDMFD sp!, {regs}

FD = Full Descending. The sp! means "update SP afterwards" (writeback). Other modes exist (EA/ED/FA) but full-descending is the ARM standard you'll almost always use.

5. The stack frame

Each function call typically carves out a stack frame: a slice of stack holding its saved registers, return address and locals. As calls nest, frames stack up; as functions return, frames are popped off. This is exactly what a debugger walks to show you a call stack / backtrace.

; typical function shape myfunc: PUSH {r4-r6, lr} ; prologue: save callee regs + return addr ; ... body uses r4-r6, may call others ... POP {r4-r6, pc} ; epilogue: restore + return

6. Stack overflow

The stack has a finite size. If it grows too far — deep/infinite recursion, or huge local arrays — it runs past its reserved memory and corrupts whatever is next. That's a stack overflow: a classic, serious bug (and the namesake of a certain website). Keep recursion bounded, locals modest, and size the stack for the worst-case call depth.

✅ The mental model

The stack is a LIFO scratchpad in RAM at SP, growing down (full-descending). PUSH saves registers, POP restores them — and PUSH {…, lr} / POP {…, pc} brackets a function and returns in one move. It's how a chip with 16 registers runs arbitrarily deep call chains.

🎯 Day 14 takeaways

Quick check

  1. Which direction does an ARM full-descending stack grow?
  2. Why is POP {r4-r6, pc} a return as well as a restore?
  3. Name one cause of a stack overflow.

FAQ

What is the stack?

A LIFO region of RAM at SP (R13) used to save registers, return addresses and locals across function calls.

What is a full-descending stack?

ARM's convention: it grows downward and SP points at the last pushed item. PUSH decrements then stores; POP loads then increments.

PUSH/POP vs STM/LDM?

PUSH/POP are aliases for STMFD sp! / LDMFD sp! — store/load multiple in full-descending mode with writeback.

Previous
← Day 13: Multiply & divide

← Back to the full course roadmap