Notes / Machine Code & Assembly
Registers and the calling convention
Arguments in r0 to r3, return value in r0, return address in lr, stack position in sp. The agreement on how registers are used at function boundaries.
Cortex-M registers
| Register | Role |
|---|---|
| r0 to r3 | Passing arguments, return value (r0), freely used inside a function |
| r4 to r11 | A function that uses them must save and restore them |
| r12 | Scratch |
| r13 (sp) | Stack pointer |
| r14 (lr) | Return address |
| r15 (pc) | Program counter |
| xPSR | Flags and exception number |
The AAPCS calling convention
- Up to four arguments go in r0 to r3; the fifth onwards go on the stack
- A 64-bit value uses two registers, such as r0:r1
- A called function that uses r4 to r11 pushes them at the start and pops them at the end
So keeping to four arguments or fewer reduces stack access and is faster. With many arguments it is better to pass a single pointer to a struct.
Relation to interrupts
On entering an exception, Cortex-M hardware automatically saves r0 to r3, r12, lr, pc and xPSR. Because the registers that "the callee does not have to preserve" under the calling convention are saved in advance, an interrupt handler can be written as an ordinary C function.