Assembly Language DISCUSSION

What do the stack pointer and base pointer actually point to in an x86-64 function?

Started by jim stack frameRBP and RSPfunction prologuereturn addresscalling convention
5 replies 248 views 6 participants
Latest activity · 30 Sep 2026

What do the stack pointer and base pointer actually point to in an x86-64 function?

jim Assembly Language Forum
#1

Every unoptimised function I disassemble starts with push rbp, mov rbp, rsp, sub rsp, 32 and ends with leave and ret. Locals are then addressed as [rbp-4], [rbp-8] and so on. With -O2 the first two instructions disappear and everything is addressed from rsp instead.

What exactly do RSP and RBP point to at each step, where is the return address, and why is the frame pointer optional? I would like to be able to draw the stack for a given function.

Community replies 5

Re: What do the stack pointer and base pointer actually point to in an x86-64 function?

#2

RSP always points at the most recently pushed item, and the stack grows towards lower addresses. push x subtracts 8 from RSP and stores x at the new [rsp]; pop reverses that. call f pushes the address of the instruction after the call and jumps; ret pops that address into RIP. So on entry to any function, [rsp] holds the return address.

After push rbp and mov rbp, rsp the layout is fixed: [rbp] is the caller's saved RBP, [rbp+8] is the return address, [rbp+16] and above are any arguments passed on the stack, and negative offsets are this function's locals, for which sub rsp, 32 reserves 32 bytes.

Re: What do the stack pointer and base pointer actually point to in an x86-64 function?

#3

RBP is a fixed reference point for the life of the function. RSP moves with every push and pop, so an RSP-relative offset for the same local would change through the body, whereas [rbp-4] names the same variable from prologue to epilogue. That is easier for people and for simple debuggers.

leave is equivalent to mov rsp, rbp followed by pop rbp: it discards the locals and restores the caller's RBP, leaving RSP pointing at the return address for ret. Because each frame's [rbp] holds the previous frame's RBP, the saved values form a linked list. A debugger or profiler walks that list, reading the return address at [rbp+8] in each frame, to produce a backtrace.

Re: What do the stack pointer and base pointer actually point to in an x86-64 function?

#4

The frame pointer is optional because the compiler knows, at every instruction, how far RSP is from the start of the frame. It can address everything as [rsp+N] and adjust N itself. Dropping the frame pointer frees RBP as a general-purpose register and removes the prologue and epilogue instructions; GCC's -fomit-frame-pointer does this and is normally on when optimising for x86-64.

Debuggers then unwind using the call-frame information the compiler writes to the .eh_frame section instead of following the RBP chain. Functions that use alloca or variable-length arrays still get a frame pointer, because the distance to RSP is no longer known at compile time. If a profiler relies on frame pointers, build with -fno-omit-frame-pointer.

Re: What do the stack pointer and base pointer actually point to in an x86-64 function?

#5

Two details of the System V AMD64 ABI used on Linux explain the rest of what you see. The first six integer or pointer arguments arrive in RDI, RSI, RDX, RCX, R8 and R9, so small functions have nothing at [rbp+16]. At -O0 the compiler copies those registers into local slots such as [rbp-20], which is why arguments look like locals.

Second, RSP must be a multiple of 16 at the moment of a call. The call pushes 8 bytes and push rbp another 8, so the local area is rounded up to a multiple of 16; that is why 20 bytes of locals become sub rsp, 32. Hand-written code that calls printf with a misaligned stack typically crashes inside the library on an aligned SSE instruction such as movaps. Windows x64 uses different registers and 32 bytes of shadow space, so check which ABI applies.

Re: What do the stack pointer and base pointer actually point to in an x86-64 function?

#6

One more thing you will run into is the red zone. Under the System V ABI a leaf function, one that calls nothing, may use the 128 bytes below RSP without moving RSP. An unoptimised leaf function therefore shows push rbp and mov rbp, rsp but no sub rsp, and still stores locals at [rbp-4]. Kernel code is built with -mno-red-zone because an interrupt would overwrite that area, and the Windows x64 ABI has no red zone.

To practise drawing frames, compile a two-function program with -O0 -g, break inside the callee in GDB and run info frame and x/8gx $rsp. You can pick out the locals, the saved RBP and the return address, which points just after the call in the caller.

TEP COMMUNITY