MIPS Registers
The MIPS architecture has 32 general-purpose registers, $HI and $LO registers for multiplication and division, and another 32 for floating point numbers.
$zero ($0)
Always contains the value 0. Any write attempt to this register is silently ignored.
$at ($1)
Assembly temporary, reserved for assembler internal use. It is used by macro instructions like li or la to break them into multiple real instructions. You can take control of it using the .set noat directive, but after that, macro instructions that rely on it will stop working.
$v0 - $v1 ($2 - $3)
Used to return non-floating point values from a subroutine. If the return value fits in 32 bits, only $v0 is used; for 64-bit values, the high word goes in $v1. $v0 also holds the system call number before a syscall instruction.
$a0 - $a3 ($4 - $7)
Arguments, used to pass the first four non-floating point arguments to a subroutine. Additional arguments are passed on the stack.
$t0 - $t7 ($8 - $15)
Temporary registers, their values are not preserved across subroutine calls. The caller is responsible for saving them if needed.
$s0 - $s7 ($16 - $23)
Saved registers, subroutines must preserve their values across calls, either by not using them or by saving and restoring them on the stack.
$t8 - $t9 ($24 - $25)
Additional temporary registers, same conventions as $t0-$t7. Note that $t9 has a special role in PIC code: by convention it holds the address of the called function, allowing the callee to compute $gp.
$k0 - $k1 ($26 - $27)
Reserved for OS/interrupt handler use. They can be overwritten at any time by an interrupt or trap handler, so user code should never rely on their values.
$gp ($28)
Global pointer, used for two distinct purposes. In PIC code (Linux shared libraries), it points to the GOT (Global Offset Table), a table of pointers that the dynamic loader fills at runtime with the real addresses of external symbols. In non-PIC code (embedded systems), it points to the center of a compact region of small global/static variables, allowing them to be accessed with a single instruction using a signed 16-bit offset (covering ±32KB, 64KB total).
$sp ($29)
Stack pointer, points to the top of the stack. It is explicitly adjusted by the callee on subroutine entry and exit.
$fp ($30)
Frame pointer, also known as $s8. Used by a subroutine to track the stack frame when the stack pointer cannot be used directly, for example when the stack size is not known at compile time (e.g. when using alloca()).
$ra ($31)
Return address, automatically written by jal with the address of the instruction following the call. The subroutine returns by executing jr $ra. Functions that themselves call other subroutines must save $ra on the stack first, since jal would otherwise overwrite it.