RISC-V Assembly Language - Frame Pointer

Be sure to distinguish between 32bit and 64bit assembly code.

Introduction

A RISC-V function prologue sets up the stack frame and saves registers, while the epilogue restores them, either using only the stack pointer (sp) or adding a frame pointer (s0) for variable or large stack frames.

The frame pointer (fp or s0, register x8) is used in RISC-V assembly, but compilers often omit it by default to save a register and optimize code size.

How and When the fp Register Is Used

Do People Actually Use It?

Example Without the Frame Pointer

Functions without a frame pointer rely solely on the stack pointer (sp) to track local storage and return addresses. This saves a register (s0) for general use, but requires fixed offsets from sp.

# Without FP Example (32-bit architecture) my_func: # Prologue addi sp, sp, -4 sw ra, 0(sp) # Function Body # ... do work ... # Epilogue lw ra, 0(sp) addi sp, sp, 4 ret

Example With the Frame Pointer (32-bit architecture)

Functions with a frame pointer (s0) copy the stack pointer into s0/fp after saving the old frame pointer and return address. This is helpful for debugging or when stack sizes change dynamically.

# With FP Example (32-bit architecture) my_func_fp: # Prologue addi sp, sp, -8 # allocate stack frame space sw ra, 4(sp) # save of return address sw fp, 0(sp) # save of current s0/fp mv fp, sp # set new frame pointer # Function Body # ... do work using s0/fp as base ... # Epilogue lw ra, 4(sp) # restore of return address lw fp, 0(sp) # restore of current s0/fp addi sp, sp, 8 # restore caller's stack pointer ret

Links

RISC-V from scratch 4: Creating a function prologue for our UART driver (2 / 3)