While it is true that there are 31 general purpose registers (the x
and coincident w
registers), they aren't all equally general purpose. First, let's call out the different categories of general purpose registers:
x30
is the Link Registerx0
throughx7
are truly scratch registers.x9
throughx15
are registers you can't count on being preserved by functions called by your function. If you need them to be preserved, you must preserve and restore them yourself.x19
throughx28
are registers you must back up and restore if you use them.x8
,x16
throughx18
andx29
are used by compilers in support of the magic they do.
The above image is due to ARM and is found here.
To backup (or "preserve") a register is copying the register onto the stack (i.e. storing a copy of the register in RAM). The str
and stp
instructions are used for this.
To restore a register means copying a previously stored copy of the contents of a register from the stack (RAM) back to the register. The ldr
and ldp
instructions are used for this.
Any change you make to sp
must be a multiple of 16.
Here is an example:
.global main // 1
.text // 2
.align 2 // 3
// 4
main: str x30, [sp, -8]! // 5
ldr x30, [sp], 8 // 6
ret // 7
which produces:
regs > ./a.out
Bus error (core dumped)
regs >
x30
is the Link Register, a register which is automatically used to store the return address when a function call is made (i.e. the bl
instruction). Indeed, the bl
instruction is called Branch with Link.
Nearly all functions have the implicit assumption that, at some point, they will return to whence they were called. Exceptions to this, of course, are functions like exit()
and exec()
family of functions.
Here's a fun program:
.global main // 1
.text // 2
.align 2 // 3
// 4
main: mov x30, xzr // 5
ret // 6
// 7
.end // 8
regs > ./a.out
Segmentation fault (core dumped)
regs >
So short. So sweet. So lethal.
Manipulating the x30
register is done automatically by the bl
and ret
instructions.
The bl
performs these steps:
- Compute the address of the instruction following the
bl
- Put that address into
x30
- Put the address of the function being called into the Program Counter
Note that the Program Counter always contains the address of the next instruction to be executed. Loading a new value into the Program Counter causes a branch to take place. The Program Counter is a register but it is not one of the general purpose registers. Its mnemonic is pc
.
The ret
instruction copies the contents of x30
into the pc
, causing a branch to that address (which ought to be where the function was called from).
The program above crashes because line 5
obliterates the address to which main()
was supposed to return.
If your function:
- does not itself modify
x30
and - does not itself call any other functions
then you do not need to backup and restore x30
.
These registers are truly scratch.
- You can modify them at any time
- You cannot count on their values surviving any function call you make
Note these registers are used to convey up to 8 parameters to functions.
These registers are free for you to use but if you call other functions, you cannot count on them being what they were when a function returns. If you need these values to be preserved across function calls, you have to preserve them.
These registers are free for you to use but if you modify them, you must preserve them.
While these registers are general purpose registers and you can use them, compilers use these to facilitate certain functions they do including easing the use of a debugger. If you're flitting back and forth from assembly language to higher level languages you might think about avoiding their use. x29
in particular is known as the frame pointer
and is used for debugging. It will be explained in more detail elsewhere.
Registers | Preserve? |
---|---|
x0 ...x7 |
All bets are off - no promised made |
x9 ...x15 |
If you are counting on their value across function calls, you must preserve them |
x19 ...x28 |
If you use them you must preserve them |