1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//! AArch64 register definition.
use crateReg;
use ;
/// FPR index bound.
pub const MAX_FPR: u32 = 32;
/// FPR index bound.
pub const MAX_GPR: u32 = 32;
/// Construct a X-register from an index.
pub const
/// Construct a V-register from an index.
pub const
/// Scratch register.
/// Intra-procedure-call corruptible register.
pub const
/// Alias to the IP0 register.
pub const
// Alias to register v31.
pub const
/// Scratch register.
/// Intra-procedure-call corruptible register.
pub const
/// Register used to carry platform state.
const
/// Frame pointer register.
pub const
/// Link register for function calls.
pub const
/// Zero register.
pub const
/// The VM context register.
pub const
/// Stack pointer register.
///
/// In aarch64 the zero and stack pointer registers are contextually
/// different but have the same hardware encoding; to differentiate
/// them, we are following Cranelift's encoding and representing it as
/// 31 + 32. Ref:
/// https://github.com/bytecodealliance/wasmtime/blob/main/cranelift/codegen/src/isa/aarch64/inst/regs.rs#L70
pub const
/// Shadow stack pointer register.
///
/// The shadow stack pointer (SSP) is used as the base for memory addressing
/// to workaround Aarch64's constraint on the stack pointer 16-byte
/// alignment for memory addressing. This allows word-size loads and
/// stores. It's always assumed that the real stack pointer (SP) is
/// 16-byte unaligned; the only exceptions to this assumption are:
///
/// * The function prologue and epilogue in which we use SP
/// for addressing, assuming that the 16-byte alignment is respected.
/// * Call sites, in which the code generation process explicitly ensures that
/// the stack pointer is 16-byte aligned.
/// * Code that could result in signal handling, like loads/stores.
///
/// SSP is utilized for space allocation. After each allocation, its value is
/// copied to SP, ensuring that SP accurately reflects the allocated space.
/// Accessing memory below SP may lead to undefined behavior, as this memory can
/// be overwritten by interrupts and signal handlers.
///
/// This approach requires copying the value of SSP into SP every time SSP
/// changes, more explicitly, this happens at three main locations:
///
/// 1. After space is allocated, to respect the requirement of avoiding
/// addressing space below SP.
/// 2. At function epilogue.
/// 3. After explicit SP is emitted (code that could result in signal handling).
///
/// +-----------+ Prologue:
/// | | * Save SSP (callee-saved)
/// +-----------+----- * SP at function entry (after prologue, slots for FP and LR)
/// | | * Copy the value of SP to SSP
/// | |
/// +-----------+----- SSP after reserving stack space for locals and arguments
/// | | Copy the value of SSP to SP
/// | |
/// +-----------+----- SSP after a push
/// | | Copy the value of SSP to SP
/// | |
/// | |
/// | |
/// | | Epilogue:
/// | | * Copy SSP to SP
/// +-----------+----- * Restore SSP (callee-saved)
/// +-----------+
///
/// In summary, the following invariants must be respected:
///
/// * SSP is considered primary, and must be used to allocate and deallocate
/// stack space(e.g. push, pop). This operation must always be followed by
/// a copy of SSP to SP.
/// * SP must never be used to address memory except when we are certain that
/// the required alignment is respected (e.g. during the prologue and epilogue)
/// * SP must be explicitly aligned when code could result in signal handling.
/// * The value of SP is copied to SSP when entering a function.
/// * The value of SSP doesn't change between
/// function calls (as it's callee saved), compliant with
/// Aarch64's ABI.
/// * SSP is not available during register allocation.
pub const
/// Bitmask for non-allocatable GPR.
pub const NON_ALLOCATABLE_GPR: u32 =
|
|
|
|
|
|
| ;
/// Bitmask to represent the available general purpose registers.
pub const ALL_GPR: u32 = u32MAX & !NON_ALLOCATABLE_GPR;
/// Bitmask for non-allocatable FPR.
/// All FPRs are allocatable, v0..=v7 are generally used for params and results.
pub const NON_ALLOCATABLE_FPR: u32 = 1 << float_scratch.hw_enc;
/// Bitmask to represent the available floating point registers.
pub const ALL_FPR: u32 = u32MAX & !NON_ALLOCATABLE_FPR;