Post

RISC-V Calling Conventions and Stack Frames

RISC-V Calling Conventions and Stack Frames

C -> Asm / processors

  • Every processor has an associated instruction set architecture (ISA)
  • C -> Asm (.S) -> .o files -> executables

RISC-V & x86-64

x86-64

  • 3 full books
  • 3 instr/month (15k instr)

RISC-V

  • Fewer instructions
  • Simple instructions
  • Open source
  • Integrated devices

ARM (RISC)

  • Qualcomm snapdragon (Android)
  • iOS

Registers

There are basically two types of registers: integer registers and floating-point registers. Listed below.

Register ABI name Description Saver
x0 zero Hard-wired zero
x1 ra Return address Caller
x2 sp Stack pointer Callee
x3 gp Global pointer
x4 tp Thread pointer
x5–7 t0–2 Temporaries Caller
x8 s0/fp Saved register/frame pointer Callee
x9 s1 Saved register Callee
x10–11 a0–1 Function arguments/return values Caller
x12–17 a2–7 Function arguments Caller
x18–27 s2–11 Saved registers Callee
x28–31 t3–6 Temporaries Caller
f0–7 ft0–7 FP temporaries Caller
f8–9 fs0–1 FP saved registers Callee
f10–11 fa0–1 FP arguments/return values Caller
f12–17 fa2–7 FP arguments Caller
f18–27 fs2–11 FP saved registers Callee
f28–31 ft8–11 FP temporaries Caller

ABI name is much important than those noted by number, except when compressed version of RISC-V code.

Saver

When calling a function, registers may be overwritten by the callee. So RISC-V gives a calling convention to decide who saves what, so that register values are preserved correctly across function calls.

Caller saved registers

  • Also called volatile or scratch registers.
  • The caller (the function making the call) must save them before calling another function if it wants to keep their values.

Callee-saved registers

  • Also called non-volatile or preserved registers.
  • The callee (the function being called) must save their contents before using them and restore them before returning.
  • That way, the caller can safely assume their values stay the same across function calls.

When using compressed version of RISC-V, you can only use register 8 to 15. So ax registers are inserted into sx registers.

Stack & calling conventions

Stack

Stack keeps functions organized and sane. It’s what makes functions work, it’s what makes return work, and it’s also where often we will find ourselves saving our registers and things likes that.

Here is what a stack looks like.

stack

Each of these boxes is what we refer to as a stack frame, from current return address to return address of deeper function (the latter not inclueded). And stack frames are generated by function calls. It’s done by moving around the stack pointer (sp register). And stack frames for functions contain registers, local variables; if you run out of argument registers, additional arguments will show up on the stack.

In each stack frame, the first thing is always return address and the second thing is previous frame pointer.

sp points to the bottom of stack, and fp points to the top of current frame.

It’s worth noting that stack always grows downwards.

Struct layout in memory

This post is licensed under CC BY 4.0 by the author.