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
|
;; Licensed to the.NET Foundation under one or more agreements.
;; The.NET Foundation licenses this file to you under the MIT license.
;; See the LICENSE file in the project root for more information.
;; OS provided macros
#include <ksarm.h>
;; generated by the build from AsmOffsets.cpp
#include "AsmOffsets.inc"
;;
;; CONSTANTS -- INTEGER
;;
TSF_Attached equ 0x01
TSF_SuppressGcStress equ 0x08
TSF_DoNotTriggerGc equ 0x10
TSF_SuppressGcStress__OR__TSF_DoNotTriggerGC equ 0x18
;; GC type flags
GC_ALLOC_FINALIZE equ 1
GC_ALLOC_ALIGN8_BIAS equ 4
GC_ALLOC_ALIGN8 equ 8
;; GC minimal sized object. We use this to switch between 4 and 8 byte alignment in the GC heap (see AllocFast.asm).
SIZEOF__MinObject equ 12
ASSERT (SIZEOF__MinObject :MOD: 8) == 4
;; Note: these must match the defs in PInvokeTransitionFrameFlags
PTFF_SAVE_R4 equ 0x00000001
PTFF_SAVE_R5 equ 0x00000002
PTFF_SAVE_R6 equ 0x00000004
PTFF_SAVE_R7 equ 0x00000008
PTFF_SAVE_R8 equ 0x00000010
PTFF_SAVE_R9 equ 0x00000020
PTFF_SAVE_R10 equ 0x00000040
PTFF_SAVE_ALL_PRESERVED equ 0x00000077 ;; NOTE: FP is not included in this set!
PTFF_SAVE_SP equ 0x00000100
PTFF_SAVE_R0 equ 0x00000200 ;; R0 is saved if it contains a GC ref and we're in hijack handler
PTFF_SAVE_ALL_SCRATCH equ 0x00003e00 ;; R0-R3,LR (R12 is trashed by the helpers anyway, but LR is relevant for loop hijacking
PTFF_R0_IS_GCREF equ 0x00004000 ;; iff PTFF_SAVE_R0: set -> r0 is Object, clear -> r0 is scalar
PTFF_R0_IS_BYREF equ 0x00008000 ;; iff PTFF_SAVE_R0: set -> r0 is ByRef, clear -> r0 is Object or scalar
PTFF_THREAD_ABORT equ 0x00010000 ;; indicates that ThreadAbortException should be thrown when returning from the transition
;; These must match the TrapThreadsFlags enum
TrapThreadsFlags_None equ 0
TrapThreadsFlags_AbortInProgress equ 1
TrapThreadsFlags_TrapThreads equ 2
;; This must match HwExceptionCode.STATUS_REDHAWK_THREAD_ABORT
STATUS_REDHAWK_THREAD_ABORT equ 0x43
;;
;; Rename fields of nested structs
;;
OFFSETOF__Thread__m_alloc_context__alloc_ptr equ OFFSETOF__Thread__m_rgbAllocContextBuffer + OFFSETOF__gc_alloc_context__alloc_ptr
OFFSETOF__Thread__m_alloc_context__alloc_limit equ OFFSETOF__Thread__m_rgbAllocContextBuffer + OFFSETOF__gc_alloc_context__alloc_limit
__tls_array equ 0x2C ;; offsetof(TEB, ThreadLocalStoragePointer)
;;
;; MACROS
;;
GBLS __SECTIONREL_tls_CurrentThread
__SECTIONREL_tls_CurrentThread SETS "SECTIONREL_tls_CurrentThread"
MACRO
INLINE_GETTHREAD $destReg, $trashReg
EXTERN _tls_index
ldr $destReg, =_tls_index
ldr $destReg, [$destReg]
mrc p15, 0, $trashReg, c13, c0, 2
ldr $trashReg, [$trashReg, #__tls_array]
ldr $destReg, [$trashReg, $destReg, lsl #2]
ldr $trashReg, $__SECTIONREL_tls_CurrentThread
add $destReg, $trashReg
MEND
;; INLINE_GETTHREAD_CONSTANT_POOL macro has to be used after the last function in the .asm file that used
;; INLINE_GETTHREAD. Optionally, it can be also used after any function that used INLINE_GETTHREAD
;; to improve density, or to reduce distance betweeen the constant pool and its use.
MACRO
INLINE_GETTHREAD_CONSTANT_POOL
EXTERN tls_CurrentThread
$__SECTIONREL_tls_CurrentThread
DCD tls_CurrentThread
RELOC 15 ;; SECREL
__SECTIONREL_tls_CurrentThread SETS "$__SECTIONREL_tls_CurrentThread":CC:"_"
MEND
MACRO
INLINE_THREAD_UNHIJACK $threadReg, $trashReg1, $trashReg2
;;
;; Thread::Unhijack()
;;
ldr $trashReg1, [$threadReg, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
cbz $trashReg1, %ft0
ldr $trashReg2, [$threadReg, #OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation]
str $trashReg1, [$trashReg2]
mov $trashReg1, #0
str $trashReg1, [$threadReg, #OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation]
str $trashReg1, [$threadReg, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
0
MEND
DEFAULT_FRAME_SAVE_FLAGS equ PTFF_SAVE_ALL_PRESERVED + PTFF_SAVE_SP
;;
;; Macro used from unmanaged helpers called from managed code where the helper does not transition immediately
;; into pre-emptive mode but may cause a GC and thus requires the stack is crawlable. This is typically the
;; case for helpers that meddle in GC state (e.g. allocation helpers) where the code must remain in
;; cooperative mode since it handles object references and internal GC state directly but a garbage collection
;; may be inevitable. In these cases we need to be able to transition to pre-meptive mode deep within the
;; unmanaged code but still be able to initialize the stack iterator at the first stack frame which may hold
;; interesting GC references. In all our helper cases this corresponds to the most recent managed frame (e.g.
;; the helper's caller).
;;
;; This macro builds a frame describing the current state of managed code.
;;
;; INVARIANTS
;; - The macro assumes it defines the method prolog, it should typically be the first code in a method and
;; certainly appear before any attempt to alter the stack pointer.
;; - This macro uses trashReg (after its initial value has been saved in the frame) and upon exit trashReg
;; will contain the address of transition frame.
;;
MACRO
PUSH_COOP_PINVOKE_FRAME $trashReg
PROLOG_STACK_ALLOC 4 ; Save space for caller's SP
PROLOG_PUSH {r4-r6,r8-r10} ; Save preserved registers
PROLOG_STACK_ALLOC 8 ; Save space for flags and Thread*
PROLOG_PUSH {r7} ; Save caller's FP
PROLOG_PUSH {r11,lr} ; Save caller's frame-chain pointer and PC
; Compute SP value at entry to this method and save it in the last slot of the frame (slot #11).
add $trashReg, sp, #(12 * 4)
str $trashReg, [sp, #(11 * 4)]
; Record the bitmask of saved registers in the frame (slot #4).
mov $trashReg, #DEFAULT_FRAME_SAVE_FLAGS
str $trashReg, [sp, #(4 * 4)]
mov $trashReg, sp
MEND
;; Pop the frame and restore register state preserved by PUSH_COOP_PINVOKE_FRAME
MACRO
POP_COOP_PINVOKE_FRAME
EPILOG_POP {r11,lr} ; Restore caller's frame-chain pointer and PC (return address)
EPILOG_POP {r7} ; Restore caller's FP
EPILOG_STACK_FREE 8 ; Discard flags and Thread*
EPILOG_POP {r4-r6,r8-r10} ; Restore preserved registers
EPILOG_STACK_FREE 4 ; Discard caller's SP
MEND
; Macro used to assign an alternate name to a symbol containing characters normally disallowed in a symbol
; name (e.g. C++ decorated names).
MACRO
SETALIAS $name, $symbol
GBLS $name
$name SETS "|$symbol|"
MEND
;
; Helper macro: create a global label for the given name,
; decorate it, and export it for external consumption.
;
MACRO
__ExportLabelName $FuncName
LCLS Name
Name SETS "|$FuncName|"
EXPORT $Name
$Name
MEND
;
; Macro for indicating an alternate entry point into a function.
;
MACRO
LABELED_RETURN_ADDRESS $ReturnAddressName
; export the return address name, but do not perturb the code by forcing alignment
__ExportLabelName $ReturnAddressName
; flush any pending literal pool stuff
ROUT
MEND
MACRO
EXPORT_POINTER_TO_ADDRESS $Name
1
AREA |.rdata|, ALIGN=4, DATA, READONLY
$Name
DCD %BT1
EXPORT $Name
TEXTAREA
ROUT
MEND
;-----------------------------------------------------------------------------
; Macro used to check (in debug builds only) whether the stack is 64-bit aligned (a requirement before calling
; out into C++/OS code). Invoke this directly after your prolog (if the stack frame size is fixed) or directly
; before a call (if you have a frame pointer and a dynamic stack). A breakpoint will be invoked if the stack
; is misaligned.
;
MACRO
CHECK_STACK_ALIGNMENT
#ifdef _DEBUG
push {r0}
add r0, sp, #4
tst r0, #7
pop {r0}
beq %F0
EMIT_BREAKPOINT
0
#endif
MEND
;; Loads a 32bit constant into destination register
MACRO
MOV32 $destReg, $constant
movw $destReg, #(($constant) & 0xFFFF)
movt $destReg, #(($constant) >> 16)
MEND
;;
;; CONSTANTS -- SYMBOLS
;;
SETALIAS G_LOWEST_ADDRESS, g_lowest_address
SETALIAS G_HIGHEST_ADDRESS, g_highest_address
SETALIAS G_EPHEMERAL_LOW, g_ephemeral_low
SETALIAS G_EPHEMERAL_HIGH, g_ephemeral_high
SETALIAS G_CARD_TABLE, g_card_table
SETALIAS G_FREE_OBJECT_EETYPE, ?g_pFreeObjectMethodTable@@3PAVMethodTable@@A
#ifdef FEATURE_GC_STRESS
SETALIAS THREAD__HIJACKFORGCSTRESS, ?HijackForGcStress@Thread@@SAXPAUPAL_LIMITED_CONTEXT@@@Z
SETALIAS REDHAWKGCINTERFACE__STRESSGC, ?StressGc@RedhawkGCInterface@@SAXXZ
#endif ;; FEATURE_GC_STRESS
;;
;; IMPORTS
;;
EXTERN RhpGcAlloc
EXTERN RhDebugBreak
EXTERN RhpWaitForSuspend2
EXTERN RhpWaitForGC2
EXTERN RhpReversePInvokeAttachOrTrapThread2
EXTERN RhExceptionHandling_FailedAllocation
EXTERN RhpPublishObject
EXTERN RhpCalculateStackTraceWorker
EXTERN $G_LOWEST_ADDRESS
EXTERN $G_HIGHEST_ADDRESS
EXTERN $G_EPHEMERAL_LOW
EXTERN $G_EPHEMERAL_HIGH
EXTERN $G_CARD_TABLE
EXTERN RhpTrapThreads
EXTERN $G_FREE_OBJECT_EETYPE
EXTERN RhThrowHwEx
EXTERN RhThrowEx
EXTERN RhRethrow
#ifdef FEATURE_GC_STRESS
EXTERN $REDHAWKGCINTERFACE__STRESSGC
EXTERN $THREAD__HIJACKFORGCSTRESS
#endif ;; FEATURE_GC_STRESS
|