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
|
// 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.
#define C_VAR(Name) rip + C_FUNC(Name)
.macro NESTED_ENTRY Name, Section, Handler
LEAF_ENTRY \Name, \Section
.ifnc \Handler, NoHandler
#if defined(__APPLE__)
.cfi_personality 0x9b, C_FUNC(\Handler) // 0x9b == DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4
#else
.cfi_personality 0, C_FUNC(\Handler) // 0 == DW_EH_PE_absptr
#endif
.endif
.endm
.macro NESTED_END Name, Section
LEAF_END \Name, \Section
#if defined(__APPLE__)
.set LOCAL_LABEL(\Name\()_Size), . - C_FUNC(\Name)
.section __LD,__compact_unwind,regular,debug
.quad C_FUNC(\Name)
.long LOCAL_LABEL(\Name\()_Size)
.long 0x04000000 # DWARF
.quad 0
.quad 0
#endif
.endm
.macro PATCH_LABEL Name
.global C_FUNC(\Name)
C_FUNC(\Name):
.endm
.macro ALTERNATE_ENTRY Name
.global C_FUNC(\Name)
C_FUNC(\Name):
.endm
.macro LEAF_ENTRY Name, Section
.global C_FUNC(\Name)
#if defined(__APPLE__)
.text
#else
.global C_FUNC(_\Name)
.type \Name, %function
#endif
C_FUNC(\Name):
.cfi_startproc
.endm
.macro LEAF_END Name, Section
#if !defined(__APPLE__)
.size \Name, .-\Name
#endif
.cfi_endproc
.endm
.macro push_nonvol_reg Register
push \Register
.cfi_adjust_cfa_offset 8
.cfi_rel_offset \Register, 0
.endm
.macro pop_nonvol_reg Register
pop \Register
.cfi_adjust_cfa_offset -8
.cfi_restore \Register
.endm
.macro alloc_stack Size
.att_syntax
lea -(\Size)(%rsp), %rsp
.intel_syntax noprefix
.cfi_adjust_cfa_offset (\Size)
.endm
.macro free_stack Size
.att_syntax
lea (\Size)(%rsp), %rsp
.intel_syntax noprefix
.cfi_adjust_cfa_offset -(\Size)
.endm
.macro set_cfa_register Reg, Offset
.cfi_def_cfa_register \Reg
.cfi_def_cfa_offset \Offset
.endm
.macro save_reg_postrsp Reg, Offset
__Offset = \Offset
mov qword ptr [rsp + __Offset], \Reg
.cfi_rel_offset \Reg, __Offset
.endm
.macro restore_reg Reg, Offset
__Offset = \Offset
mov \Reg, [rsp + __Offset]
.cfi_restore \Reg
.endm
.macro save_xmm128_postrsp Reg, Offset
__Offset = \Offset
movdqa xmmword ptr [rsp + __Offset], \Reg
// NOTE: We cannot use ".cfi_rel_offset \Reg, __Offset" here,
// the xmm registers are not supported by the libunwind
.endm
.macro restore_xmm128 Reg, ofs
__Offset = \ofs
movdqa \Reg, xmmword ptr [rsp + __Offset]
// NOTE: We cannot use ".cfi_restore \Reg" here,
// the xmm registers are not supported by the libunwind
.endm
.macro PUSH_CALLEE_SAVED_REGISTERS
push_register rbp
push_register rbx
push_register r15
push_register r14
push_register r13
push_register r12
.endm
.macro POP_CALLEE_SAVED_REGISTERS
pop_nonvol_reg r12
pop_nonvol_reg r13
pop_nonvol_reg r14
pop_nonvol_reg r15
pop_nonvol_reg rbx
pop_nonvol_reg rbp
.endm
.macro push_register Reg
push \Reg
.cfi_adjust_cfa_offset 8
.endm
.macro push_imm imm
.att_syntax
push $\imm
.intel_syntax noprefix
.cfi_adjust_cfa_offset 8
.endm
.macro push_eflags
pushfq
.cfi_adjust_cfa_offset 8
.endm
.macro push_argument_register Reg
push_register \Reg
.endm
.macro PUSH_ARGUMENT_REGISTERS
push_argument_register r9
push_argument_register r8
push_argument_register rcx
push_argument_register rdx
push_argument_register rsi
push_argument_register rdi
.endm
.macro pop_register Reg
pop \Reg
.cfi_adjust_cfa_offset -8
.endm
.macro pop_eflags
popfq
.cfi_adjust_cfa_offset -8
.endm
.macro pop_argument_register Reg
pop_register \Reg
.endm
.macro POP_ARGUMENT_REGISTERS
pop_argument_register rdi
pop_argument_register rsi
pop_argument_register rdx
pop_argument_register rcx
pop_argument_register r8
pop_argument_register r9
.endm
#define SIZEOF_FP_REGS 0x80
.macro SAVE_FLOAT_ARGUMENT_REGISTERS ofs
save_xmm128_postrsp xmm0, \ofs
save_xmm128_postrsp xmm1, \ofs + 0x10
save_xmm128_postrsp xmm2, \ofs + 0x20
save_xmm128_postrsp xmm3, \ofs + 0x30
save_xmm128_postrsp xmm4, \ofs + 0x40
save_xmm128_postrsp xmm5, \ofs + 0x50
save_xmm128_postrsp xmm6, \ofs + 0x60
save_xmm128_postrsp xmm7, \ofs + 0x70
.endm
.macro RESTORE_FLOAT_ARGUMENT_REGISTERS ofs
restore_xmm128 xmm0, \ofs
restore_xmm128 xmm1, \ofs + 0x10
restore_xmm128 xmm2, \ofs + 0x20
restore_xmm128 xmm3, \ofs + 0x30
restore_xmm128 xmm4, \ofs + 0x40
restore_xmm128 xmm5, \ofs + 0x50
restore_xmm128 xmm6, \ofs + 0x60
restore_xmm128 xmm7, \ofs + 0x70
.endm
.macro EXPORT_POINTER_TO_ADDRESS Name
// NOTE: The label is intentionally left as 2 - otherwise on OSX 0b or 1b will be incorrectly interpreted as binary integers
2:
.data
.align 8
C_FUNC(\Name):
.quad 2b
.global C_FUNC(\Name)
.text
.endm
//
// CONSTANTS -- INTEGER
//
#define TSF_Attached 0x01
#define TSF_SuppressGcStress 0x08
#define TSF_DoNotTriggerGc 0x10
//
// Rename fields of nested structs
//
#define OFFSETOF__Thread__m_alloc_context__alloc_ptr OFFSETOF__Thread__m_rgbAllocContextBuffer + OFFSETOF__gc_alloc_context__alloc_ptr
#define OFFSETOF__Thread__m_alloc_context__alloc_limit OFFSETOF__Thread__m_rgbAllocContextBuffer + OFFSETOF__gc_alloc_context__alloc_limit
// GC type flags
#define GC_ALLOC_FINALIZE 1
// Note: these must match the defs in PInvokeTransitionFrameFlags
#define PTFF_SAVE_RBX 00000001h
#define PTFF_SAVE_R12 00000010h
#define PTFF_SAVE_R13 00000020h
#define PTFF_SAVE_R14 00000040h
#define PTFF_SAVE_R15 00000080h
#define PTFF_SAVE_ALL_PRESERVED 000000F1h // NOTE: RBP is not included in this set!
#define PTFF_SAVE_RSP 00008000h
#define PTFF_SAVE_RAX 00000100h // RAX is saved if it contains a GC ref and we're in hijack handler
#define PTFF_SAVE_ALL_SCRATCH 00007F00h
#define PTFF_RAX_IS_GCREF 00010000h // iff PTFF_SAVE_RAX: set -> eax is Object, clear -> eax is scalar
#define PTFF_RAX_IS_BYREF 00020000h // iff PTFF_SAVE_RAX: set -> eax is ByRef, clear -> eax is Object or scalar
#define PTFF_THREAD_ABORT 00040000h // indicates that ThreadAbortException should be thrown when returning from the transition
// These must match the TrapThreadsFlags enum
#define TrapThreadsFlags_None 0
#define TrapThreadsFlags_AbortInProgress 1
#define TrapThreadsFlags_TrapThreads 2
.macro INLINE_GET_TLS_VAR Var
.att_syntax
#if defined(__APPLE__)
movq _\Var@TLVP(%rip), %rdi
callq *(%rdi)
#else
leaq \Var@TLSLD(%rip), %rdi
callq __tls_get_addr@PLT
addq $\Var@DTPOFF, %rax
#endif
.intel_syntax noprefix
.endm
.macro INLINE_GETTHREAD
// Inlined version of call C_FUNC(RhpGetThread)
INLINE_GET_TLS_VAR tls_CurrentThread
.endm
.macro INLINE_THREAD_UNHIJACK threadReg, trashReg1, trashReg2
//
// Thread::Unhijack()
//
mov \trashReg1, [\threadReg + OFFSETOF__Thread__m_pvHijackedReturnAddress]
cmp \trashReg1, 0
je 1f
mov \trashReg2, [\threadReg + OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation]
mov [\trashReg2], \trashReg1
mov qword ptr [\threadReg + OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation], 0
mov qword ptr [\threadReg + OFFSETOF__Thread__m_pvHijackedReturnAddress], 0
1:
.endm
DEFAULT_FRAME_SAVE_FLAGS = PTFF_SAVE_ALL_PRESERVED + PTFF_SAVE_RSP
.macro PUSH_COOP_PINVOKE_FRAME trashReg
push_nonvol_reg rbp // push RBP frame
mov rbp, rsp
lea \trashReg, [rsp + 10h]
push_register \trashReg // save caller's RSP
push_nonvol_reg r15 // save preserved registers
push_nonvol_reg r14 // ..
push_nonvol_reg r13 // ..
push_nonvol_reg r12 // ..
push_nonvol_reg rbx // ..
push_imm DEFAULT_FRAME_SAVE_FLAGS // save the register bitmask
push_register \trashReg // Thread * (unused by stackwalker)
mov \trashReg, [rsp + 8*8] // Find and save the callers RBP
push_register \trashReg
mov \trashReg, [rsp + 10*8] // Find and save the return address
push_register \trashReg
lea \trashReg, [rsp] // trashReg == address of frame
.endm
.macro POP_COOP_PINVOKE_FRAME
pop_register r10 // discard RIP
pop_nonvol_reg rbp // restore RBP
pop_register r10 // discard thread
pop_register r10 // discard bitmask
pop_nonvol_reg rbx
pop_nonvol_reg r12
pop_nonvol_reg r13
pop_nonvol_reg r14
pop_nonvol_reg r15
pop_register r10 // discard caller RSP
pop_register r10 // discard RBP frame
.endm
|