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
|
// 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.
;; ==++==
;;
;;
;; ==--==
;-----------------------------------------------------------------------------
; 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
;-----------------------------------------------------------------------------
; Macro used to end a function with explicit _End label
MACRO
LEAF_END_MARKED $FuncName
LCLS __EndLabelName
__EndLabelName SETS "$FuncName":CC:"_End"
EXPORT $__EndLabelName
$__EndLabelName
LEAF_END $FuncName
MEND
;-----------------------------------------------------------------------------
; Macro use for enabling C++ to know where to patch code at runtime.
MACRO
PATCH_LABEL $FuncName
$FuncName
EXPORT $FuncName
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
;-----------------------------------------------------------------------------
; The following group of macros assist in implementing prologs and epilogs for methods that set up some
; subclass of TransitionFrame. They ensure that the SP is 64-bit aligned at the conclusion of the prolog and
; provide a helper macro to locate the start of the NegInfo (if there is one) for the frame.
;-----------------------------------------------------------------------------
; Define the prolog for a TransitionFrame-based method. This macro should be called first in the method and
; comprises the entire prolog (i.e. don't modify SP after calling this). Takes the size of the frame's NegInfo
; (which may be zero) and the frame itself. No initialization of the frame is done beyond callee saved
; registers and (non-floating point) argument registers.
;
MACRO
PROLOG_WITH_TRANSITION_BLOCK $extraLocals, $SaveFPArgs, $PushArgRegs
GBLA __PWTB_FloatArgumentRegisters
GBLA __PWTB_StackAlloc
GBLA __PWTB_TransitionBlock
GBLL __PWTB_SaveFPArgs
IF "$SaveFPArgs" != ""
__PWTB_SaveFPArgs SETL $SaveFPArgs
ELSE
__PWTB_SaveFPArgs SETL {true}
ENDIF
IF "$extraLocals" != ""
__PWTB_FloatArgumentRegisters SETA $extraLocals
ELSE
__PWTB_FloatArgumentRegisters SETA 0
ENDIF
IF __PWTB_SaveFPArgs
IF __PWTB_FloatArgumentRegisters:MOD:8 != 0
__PWTB_FloatArgumentRegisters SETA __PWTB_FloatArgumentRegisters + 4
ENDIF
__PWTB_TransitionBlock SETA __PWTB_FloatArgumentRegisters + (SIZEOF__FloatArgumentRegisters + 4) ; padding
ELSE
IF __PWTB_FloatArgumentRegisters:MOD:8 == 0
__PWTB_FloatArgumentRegisters SETA __PWTB_FloatArgumentRegisters + 4; padding
ENDIF
__PWTB_TransitionBlock SETA __PWTB_FloatArgumentRegisters
ENDIF
__PWTB_StackAlloc SETA __PWTB_TransitionBlock
IF "$PushArgRegs" != "DoNotPushArgRegs"
; Spill argument registers.
PROLOG_PUSH {r0-r3}
ENDIF
; Spill callee saved registers and return address.
PROLOG_PUSH {r4-r11,lr}
; Allocate space for the rest of the frame
PROLOG_STACK_ALLOC __PWTB_StackAlloc
IF __PWTB_SaveFPArgs
add r6, sp, #(__PWTB_FloatArgumentRegisters)
vstm r6, {s0-s15}
ENDIF
CHECK_STACK_ALIGNMENT
MEND
;-----------------------------------------------------------------------------
; Provides a matching epilog to PROLOG_WITH_TRANSITION_BLOCK and ends by preparing for tail-calling.
; Since this is a tail call argument registers are restored.
;
MACRO
EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
IF __PWTB_SaveFPArgs
add r6, sp, #(__PWTB_FloatArgumentRegisters)
vldm r6, {s0-s15}
ENDIF
EPILOG_STACK_FREE __PWTB_StackAlloc
EPILOG_POP {r4-r11,lr}
EPILOG_POP {r0-r3}
MEND
;-----------------------------------------------------------------------------
; Provides a matching epilog to PROLOG_WITH_TRANSITION_FRAME and ends by returning to the original caller.
; Since this is not a tail call argument registers are not restored.
;
MACRO
EPILOG_WITH_TRANSITION_BLOCK_RETURN
EPILOG_STACK_FREE __PWTB_StackAlloc
EPILOG_POP {r4-r11,lr}
EPILOG_STACK_FREE 16
EPILOG_RETURN
MEND
;-----------------------------------------------------------------------------
; Macro to get a pointer to the Thread* object for the currently executing thread
;
__tls_array equ 0x2C ;; offsetof(TEB, ThreadLocalStoragePointer)
GBLS __SECTIONREL_gCurrentThreadInfo
__SECTIONREL_gCurrentThreadInfo SETS "SECTIONREL_gCurrentThreadInfo"
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_gCurrentThreadInfo
ldr $destReg,[$destReg, $trashReg] ; return gCurrentThreadInfo.m_pThread
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 gCurrentThreadInfo
$__SECTIONREL_gCurrentThreadInfo
DCDU gCurrentThreadInfo
RELOC 15 ;; SECREL
__SECTIONREL_gCurrentThreadInfo SETS "$__SECTIONREL_gCurrentThreadInfo":CC:"_"
MEND
|