Overview Why you should care about the ISA Instruction sets in the Arm architecture Instruction set resources Simple sequential execution Registers in AArch64 - general-purpose registers Registers in AArch64 - other registers Registers in AArch64 - system registers Data processing - arithmetic and logic operations Data processing - floating point Data processing - bit manipulation Data processing - extension and saturation Data processing - format conversion Data processing - vector data Loads and stores Loads and stores - size Loads and stores - zero and sign extension Loads and stores - addressing Loads and stores - load pair and store pair Loads and stores - using floating point registers Program flow Program flow - loops and decisions Program flow - generating condition code Program flow - conditional select instructions Function calls Procedure Call Standard System calls Check your knowledge Related information Next steps
Procedure Call Standard
The Arm architecture places few restrictions on how general purpose registers are used. To recap, integer registers and floating-point registers are general purpose registers.However, if you want your code to interact with code that is written by someone else, or with code that is produced by a compiler, then you need to agree rules for register usage. For the Arm architecture, these rules are called the Procedure Call Standard, or PCS.
The PCS specifies:
- Which registers are used to pass arguments into the function.
- Which registers are used to return a value to the function doing the calling, known as the caller.
- Which registers the function being called, which is known as the callee, can corrupt.
- Which registers the callee cannot corrupt.
Consider a function foo()
, being called from main()
:
The PCS says that the first argument is passed in X0
, the second argument in X1,
and so on up to X7
. Any further arguments are passed on the stack. Our function, foo()
, takes two arguments: b
and c
. Therefore, b
will be in W0
and c
will be in W1
.
Why W
and not X
? Because the arguments are a 32-bit type, and therefore we only need a W
register.
Note: In C++, X0
is used to pass the implicit this
pointer that points to the called function.
Next, the PCS defines which registers can be corrupted, and which registers cannot be corrupted. If a register can be corrupted, then the called function can overwrite without needing to restore, as this table of PCS register rules shows:
X0-X7
|
X8-X15
|
X16-X23
|
X24-X30
|
Parameter and Result Registers ( X0-X7 )
|
XR (X8 )
|
IP0 (X16 )
|
Callee-saved Registers ( X24-X28 )
|
Corruptible Registers ( X9-X15 )
|
IP1 (
|
||
PR (X18 )
|
|||
Callee-saved Registers ( X19-X23 )
|
|||
FP (X29 )
|
|||
LR (X30 )
|
For example, the function foo()
can use registers X0
to X15
without needing to preserve their values. However, if foo()
wants to use X19
to X28
it must save them to stack first, and then restore from the stack before returning.
Some registers have special significance in the PCS:
XR
- This is an indirect result register. If foo() returned a struct, then the memory for struct would be allocated by the caller, main() in the earlier example.XR
is a pointer to the memory allocated by the caller for returning the struct.IP0 and IP1
- These registers are intra-procedure-call corruptible registers. These registers can be corrupted between the time that the function is called and the time that it arrives at the first instruction in the function. These registers are used by linkers to insert veneers between the caller and callee. Veneers are small pieces of code. The most common example is for branch range extension. The branch instruction in A64 has a limited range. If the target is beyond that range, then the linker needs to generate a veneer to extend the range of the branch.FP
- Frame pointer.LR -
X30
is the link register (LR
) for function calls.
Note: We previously introduced the ALU flags, which are used for conditional branches and conditional selects. The PCS says that the ALU flags do not need to be preserved across a function call.
There is a similar set of rules for the floating-point registers:
D0-D7
|
D8-D15
|
D16-D23
|
D24-D31
|
Parameter and Result Registers ( D0-D7 )
|
Callee-saved Registers ( D8-D15 )
|
Callee-saved Registers ( D16-D31 )
|