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.

RegisterABI nameDescriptionSaver
x0zeroHard-wired zero
x1raReturn addressCaller
x2spStack pointerCallee
x3gpGlobal pointer
x4tpThread pointer
x5–7t0–2TemporariesCaller
x8s0/fpSaved register/frame pointerCallee
x9s1Saved registerCallee
x10–11a0–1Function arguments/return valuesCaller
x12–17a2–7Function argumentsCaller
x18–27s2–11Saved registersCallee
x28–31t3–6TemporariesCaller
f0–7ft0–7FP temporariesCaller
f8–9fs0–1FP saved registersCallee
f10–11fa0–1FP arguments/return valuesCaller
f12–17fa2–7FP argumentsCaller
f18–27fs2–11FP saved registersCallee
f28–31ft8–11FP temporariesCaller

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.