Assembly Language & Procedure Calls

the frame pointer

Inside a function, your local variables live at offsets from somewhere on the stack. The natural anchor is the stack pointer, but the stack pointer can move during the function (for example when you push arguments for a call), and then the same local would be at a different offset moment to moment. The frame pointer solves this by holding a fixed reference to the start of the current frame that does not move for the whole call. It is like nailing a tape measure to the doorway of a room so every measurement is from the same zero, even as you shuffle furniture inside.

On entry the prologue saves the old frame pointer and sets the frame pointer to mark this frame's base; from then on every local is at a constant offset from the frame pointer, no matter how the stack pointer wiggles. The saved frame pointers also chain together: each frame stores the previous frame pointer, forming a linked list of frames that a debugger can walk to produce a backtrace. On exit, the frame pointer is restored to the caller's value. On RISC-V the frame pointer, when used, is register s0 (also called fp), and because it is callee-saved it is preserved across calls automatically.

The frame pointer matters mostly for clarity and debuggability, but here is the honest part: it is optional. Modern compilers can compute every local's location relative to a stack pointer that they track precisely, freeing the frame-pointer register for general use (a small speed and register-pressure win); this is frame-pointer omission. The trade-off is that omitting it makes stack walking harder, which is why profilers and crash debuggers often ask you to keep frame pointers enabled. So it is a convenience and a debugging aid, not a hardware necessity.

Using s0/fp as a stable anchor: g: addi sp, sp, -16 sd ra, 8(sp) sd s0, 0(sp) # save caller's frame pointer addi s0, sp, 16 # s0 now marks the top of this frame, fixed for the call ... # locals addressed as -N(s0); sp may move, s0 won't ld s0, 0(sp) # restore caller's frame pointer ld ra, 8(sp) addi sp, sp, 16 ret

The frame pointer gives locals a fixed address even as the stack pointer moves during the call.

A frame pointer is a convenience, not a requirement: compilers often omit it to free a register, at the cost of harder stack unwinding for debuggers and profilers.

Also called
FPbase pointers0/fp基底指標