-
Notifications
You must be signed in to change notification settings - Fork 4.8k
/
unixasmmacrosarm64.inc
359 lines (279 loc) · 9.87 KB
/
unixasmmacrosarm64.inc
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#include "AsmOffsets.inc"
.macro NESTED_ENTRY Name, Section, Handler
LEAF_ENTRY \Name, \Section
.ifnc \Handler, NoHandler
.cfi_personality 0x1b, C_FUNC(\Handler) // 0x1b == DW_EH_PE_pcrel | DW_EH_PE_sdata4
// @TODO: Check if we have systems that use indirect personality 0x9b == DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4
.endif
.endm
.macro NESTED_END Name, Section
LEAF_END \Name, \Section
.endm
.macro PATCH_LABEL Name
.global C_FUNC(\Name)
C_FUNC(\Name):
.endm
.macro ALTERNATE_ENTRY Name
.global C_FUNC(\Name)
.hidden C_FUNC(\Name)
C_FUNC(\Name):
.endm
.macro LABELED_RETURN_ADDRESS Name
.global C_FUNC(\Name)
.hidden C_FUNC(\Name)
C_FUNC(\Name):
.endm
.macro LEAF_ENTRY Name, Section
.global C_FUNC(\Name)
.hidden C_FUNC(\Name)
.type \Name, %function
C_FUNC(\Name):
.cfi_startproc
.endm
.macro LEAF_END Name, Section
.size \Name, .-\Name
.cfi_endproc
.endm
.macro PREPARE_EXTERNAL_VAR Name, HelperReg
adrp \HelperReg, C_FUNC(\Name)
add \HelperReg, \HelperReg, :lo12:C_FUNC(\Name)
.endm
.macro PREPARE_EXTERNAL_VAR_INDIRECT Name, HelperReg
adrp \HelperReg, C_FUNC(\Name)
ldr \HelperReg, [\HelperReg, :lo12:C_FUNC(\Name)]
.endm
.macro PREPARE_EXTERNAL_VAR_INDIRECT_W Name, HelperReg
adrp x\HelperReg, C_FUNC(\Name)
ldr w\HelperReg, [x\HelperReg, :lo12:C_FUNC(\Name)]
.endm
.macro PROLOG_STACK_ALLOC Size
sub sp, sp, \Size
.endm
.macro EPILOG_STACK_FREE Size
add sp, sp, \Size
.cfi_adjust_cfa_offset -\Size
.endm
.macro EPILOG_STACK_RESTORE
mov sp, fp
.cfi_restore sp
.endm
.macro PROLOG_SAVE_REG reg, ofs
str \reg, [sp, \ofs]
.cfi_rel_offset \reg, \ofs
.endm
.macro PROLOG_SAVE_REG_PAIR reg1, reg2, ofs
stp \reg1, \reg2, [sp, \ofs]
.cfi_rel_offset \reg1, \ofs
.cfi_rel_offset \reg2, \ofs + 8
.ifc \reg1, fp
mov fp, sp
.cfi_def_cfa_register fp
.endif
.endm
.macro PROLOG_SAVE_REG_PAIR_INDEXED reg1, reg2, ofs
stp \reg1, \reg2, [sp, \ofs]!
.cfi_adjust_cfa_offset -\ofs
.cfi_rel_offset \reg1, 0
.cfi_rel_offset \reg2, 8
.ifc \reg1, fp
mov fp, sp
.cfi_def_cfa_register fp
.endif
.endm
.macro PROLOG_SAVE_REG_PAIR_NO_FP_INDEXED reg1, reg2, ofs
stp \reg1, \reg2, [sp, \ofs]!
.cfi_adjust_cfa_offset -\ofs
.cfi_rel_offset \reg1, 0
.cfi_rel_offset \reg2, 8
.endm
.macro EPILOG_RESTORE_REG reg, ofs
ldr \reg, [sp, \ofs]
.cfi_restore \reg
.endm
.macro EPILOG_RESTORE_REG_PAIR reg1, reg2, ofs
ldp \reg1, \reg2, [sp, \ofs]
.cfi_restore \reg1
.cfi_restore \reg2
.endm
.macro EPILOG_RESTORE_REG_PAIR_INDEXED reg1, reg2, ofs
ldp \reg1, \reg2, [sp], \ofs
.cfi_restore \reg1
.cfi_restore \reg2
.cfi_adjust_cfa_offset -\ofs
.endm
.macro EPILOG_RETURN
ret
.endm
.macro EMIT_BREAKPOINT
brk #0
.endm
//-----------------------------------------------------------------------------
// The Following sets of SAVE_*_REGISTERS expect the memory to be reserved and
// base address to be passed in $reg
//
// Reserve 64 bytes of memory before calling SAVE_ARGUMENT_REGISTERS
.macro SAVE_ARGUMENT_REGISTERS reg, ofs
stp x0, x1, [\reg, #(\ofs)]
stp x2, x3, [\reg, #(\ofs + 16)]
stp x4, x5, [\reg, #(\ofs + 32)]
stp x6, x7, [\reg, #(\ofs + 48)]
.endm
// Reserve 64 bytes of memory before calling SAVE_FLOAT_ARGUMENT_REGISTERS
.macro SAVE_FLOAT_ARGUMENT_REGISTERS reg, ofs
stp d0, d1, [\reg, #(\ofs)]
stp d2, d3, [\reg, #(\ofs + 16)]
stp d4, d5, [\reg, #(\ofs + 32)]
stp d6, d7, [\reg, #(\ofs + 48)]
.endm
.macro RESTORE_ARGUMENT_REGISTERS reg, ofs
ldp x0, x1, [\reg, #(\ofs)]
ldp x2, x3, [\reg, #(\ofs + 16)]
ldp x4, x5, [\reg, #(\ofs + 32)]
ldp x6, x7, [\reg, #(\ofs + 48)]
.endm
.macro RESTORE_FLOAT_ARGUMENT_REGISTERS reg, ofs
ldp d0, d1, [\reg, #(\ofs)]
ldp d2, d3, [\reg, #(\ofs + 16)]
ldp d4, d5, [\reg, #(\ofs + 32)]
ldp d6, d7, [\reg, #(\ofs + 48)]
.endm
.macro EPILOG_BRANCH_REG reg
br \reg
.endm
#define xip0 x16
#define xip1 x17
#define xpr x18
// Loads the address of a thread-local variable into the target register,
// which cannot be x0. Preserves all other registers.
.macro INLINE_GET_TLS_VAR target, var
.ifc \target, x0
.error "target cannot be x0"
.endif
stp x0, lr, [sp,#-0x10]!
// This sequence of instructions is recognized and potentially patched
// by the linker (GD->IE/LE relaxation).
adrp x0, :tlsdesc:\var
ldr \target, [x0, #:tlsdesc_lo12:\var]
add x0, x0, :tlsdesc_lo12:\var
.tlsdesccall \var
blr \target
// End of the sequence
mrs \target, tpidr_el0
add \target, \target, x0
ldp x0, lr, [sp],#0x10
.endm
// Inlined version of RhpGetThread. Target cannot be x0.
.macro INLINE_GETTHREAD target
INLINE_GET_TLS_VAR \target, tls_CurrentThread
.endm
// Do not use these ETLS macros in functions that already create a stack frame.
// Creating two stack frames in one function can confuse the unwinder/debugger
.macro GETTHREAD_ETLS_1
PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32 // ;; Push down stack pointer and store FP and LR
str x0, [sp, #0x10]
bl RhpGetThread
mov x1, x0
ldr x0, [sp, #0x10]
EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32
.endm
.macro GETTHREAD_ETLS_3
PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -48 // ;; Push down stack pointer and store FP and LR
stp x0, x1, [sp, #0x10]
str x2, [sp, #0x20]
bl RhpGetThread
mov x3, x0
ldp x0, x1, [sp, #0x10]
ldr x2, [sp, #0x20]
EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 48
.endm
.macro GETTHUNKDATA_ETLS_9
PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -96 // ;; Push down stack pointer and store FP and LR
stp x0, x1, [sp, #0x10]
stp x2, x3, [sp, #0x20]
stp x4, x5, [sp, #0x30]
stp x6, x7, [sp, #0x40]
stp x8, xip0, [sp, #0x50]
bl RhpGetThunkData
mov x9, x0
ldp x0, x1, [sp, #0x10]
ldp x2, x3, [sp, #0x20]
ldp x4, x5, [sp, #0x30]
ldp x6, x7, [sp, #0x40]
ldp x8, xip0, [sp, #0x50]
EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 96
.endm
.macro ArmInterlockedOperationBarrier
dmb ish
.endm
.macro INLINE_THREAD_UNHIJACK threadReg, trashReg1, trashReg2
//
// Thread::Unhijack()
//
ldr \trashReg1, [\threadReg, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
cbz \trashReg1, 0f
ldr \trashReg2, [\threadReg, #OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation]
str \trashReg1, [\trashReg2]
str xzr, [\threadReg, #OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation]
str xzr, [\threadReg, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
0:
.endm
.macro EXPORT_POINTER_TO_ADDRESS Name
1:
.data
.align 8
C_FUNC(\Name):
.quad 1b
.global C_FUNC(\Name)
.hidden C_FUNC(\Name)
.text
.endm
// Note: these must match the defs in PInvokeTransitionFrameFlags
PTFF_SAVE_SP = 0x00000400
PTFF_SAVE_ALL_PRESERVED = 0x000003FF // NOTE: x19-x28
DEFAULT_FRAME_SAVE_FLAGS = PTFF_SAVE_ALL_PRESERVED + PTFF_SAVE_SP
.macro PUSH_COOP_PINVOKE_FRAME trashReg
PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -0x80 // Push down stack pointer and store FP and LR
// 0x10 bytes reserved for Thread* and flags
// Save callee saved registers
PROLOG_SAVE_REG_PAIR x19, x20, 0x20
PROLOG_SAVE_REG_PAIR x21, x22, 0x30
PROLOG_SAVE_REG_PAIR x23, x24, 0x40
PROLOG_SAVE_REG_PAIR x25, x26, 0x50
PROLOG_SAVE_REG_PAIR x27, x28, 0x60
// Save the value of SP before stack allocation to the last slot in the frame (slot #15)
add \trashReg, sp, #0x80
str \trashReg, [sp, #0x70]
// Record the bitmask of saved registers in the frame (slot #3)
mov \trashReg, #DEFAULT_FRAME_SAVE_FLAGS
str \trashReg, [sp, #0x18]
mov \trashReg, sp
.endm
// Pop the frame and restore register state preserved by PUSH_COOP_PINVOKE_FRAME
.macro POP_COOP_PINVOKE_FRAME
EPILOG_RESTORE_REG_PAIR x19, x20, 0x20
EPILOG_RESTORE_REG_PAIR x21, x22, 0x30
EPILOG_RESTORE_REG_PAIR x23, x24, 0x40
EPILOG_RESTORE_REG_PAIR x25, x26, 0x50
EPILOG_RESTORE_REG_PAIR x27, x28, 0x60
EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 0x80
.endm
// Bit position for the flags above, to be used with tbz / tbnz instructions
PTFF_THREAD_ABORT_BIT = 36
//
// CONSTANTS -- INTEGER
//
#define TSF_Attached 0x01
#define TSF_SuppressGcStress 0x08
#define TSF_DoNotTriggerGc 0x10
#define TSF_SuppressGcStress__OR__TSF_DoNotTriggerGC 0x18
// Bit position for the flags above, to be used with tbz / tbnz instructions
TrapThreadsFlags_AbortInProgress_Bit = 0
TrapThreadsFlags_TrapThreads_Bit = 1
// This must match HwExceptionCode.STATUS_REDHAWK_THREAD_ABORT
#define STATUS_REDHAWK_THREAD_ABORT 0x43
// These must match the TrapThreadsFlags enum
#define TrapThreadsFlags_None 0
#define TrapThreadsFlags_AbortInProgress 1
#define TrapThreadsFlags_TrapThreads 2