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
|
;; 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.
.586
.model flat
option casemap:none
.code
include AsmMacros.inc
extern RhpReversePInvokeBadTransition : proc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; RhpWaitForSuspend -- rare path for RhpPInvoke and RhpReversePInvokeReturn
;;
;;
;; INPUT: none
;;
;; TRASHES: none
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_RhpWaitForSuspend proc public
push ebp
mov ebp, esp
push eax
push ecx
push edx
call RhpWaitForSuspend2
pop edx
pop ecx
pop eax
pop ebp
ret
_RhpWaitForSuspend endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; RhpWaitForGCNoAbort
;;
;;
;; INPUT: ECX: transition frame
;;
;; OUTPUT:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_RhpWaitForGCNoAbort proc public
push ebp
mov ebp, esp
push eax
push edx
push ebx
push esi
mov esi, [ecx + OFFSETOF__PInvokeTransitionFrame__m_pThread]
test dword ptr [esi + OFFSETOF__Thread__m_ThreadStateFlags], TSF_DoNotTriggerGc
jnz Done
; passing transition frame pointer in ecx
call RhpWaitForGC2
Done:
pop esi
pop ebx
pop edx
pop eax
pop ebp
ret
_RhpWaitForGCNoAbort endp
RhpThrowHwEx equ @RhpThrowHwEx@0
EXTERN RhpThrowHwEx : PROC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; RhpWaitForGC
;;
;;
;; INPUT: ECX: transition frame
;;
;; OUTPUT:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_RhpWaitForGC proc public
push ebp
mov ebp, esp
push ebx
mov ebx, ecx
test [RhpTrapThreads], TrapThreadsFlags_TrapThreads
jz NoWait
call _RhpWaitForGCNoAbort
NoWait:
test [RhpTrapThreads], TrapThreadsFlags_AbortInProgress
jz Done
test dword ptr [ebx + OFFSETOF__PInvokeTransitionFrame__m_Flags], PTFF_THREAD_ABORT
jz Done
mov ecx, STATUS_REDHAWK_THREAD_ABORT
pop ebx
pop ebp
pop edx ; return address as exception RIP
jmp RhpThrowHwEx ; Throw the ThreadAbortException as a special kind of hardware exception
Done:
pop ebx
pop ebp
ret
_RhpWaitForGC endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; RhpReversePInvoke
;;
;; IN: EAX: address of reverse pinvoke frame
;; 0: save slot for previous M->U transition frame
;; 4: save slot for thread pointer to avoid re-calc in epilog sequence
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FASTCALL_FUNC RhpReversePInvoke, 0
push ecx ; save arg regs -- we could omit this if we knew the calling convention wasn't fastcall.
push edx ; ...
;; edx = GetThread(), TRASHES ecx
INLINE_GETTHREAD edx, ecx
mov [eax + 4], edx ; save thread pointer for RhpReversePInvokeReturn
; edx = thread
; eax = prev save slot
; ecx = scratch
test dword ptr [edx + OFFSETOF__Thread__m_ThreadStateFlags], TSF_Attached
jz AttachThread
ThreadAttached:
;;
;; Check for the correct mode. This is accessible via various odd things that we cannot completely
;; prevent such as :
;; 1) Registering a reverse pinvoke entrypoint as a vectored exception handler
;; 2) Performing a managed delegate invoke on a reverse pinvoke delegate.
;;
cmp dword ptr [edx + OFFSETOF__Thread__m_pTransitionFrame], 0
je CheckBadTransition
; Save previous TransitionFrame prior to making the mode transition so that it is always valid
; whenever we might attempt to hijack this thread.
mov ecx, [edx + OFFSETOF__Thread__m_pTransitionFrame]
mov [eax], ecx
ReverseRetry:
mov dword ptr [edx + OFFSETOF__Thread__m_pTransitionFrame], 0
test [RhpTrapThreads], TrapThreadsFlags_TrapThreads
jnz ReverseTrapReturningThread
AllDone:
pop edx ; restore arg reg
pop ecx ; restore arg reg
ret
CheckBadTransition:
;; Allow 'bad transitions' in when the TSF_DoNotTriggerGc mode is set. This allows us to have
;; [NativeCallable] methods that are called via the "restricted GC callouts" as well as from native,
;; which is necessary because the methods are CCW vtable methods on interfaces passed to native.
test dword ptr [edx + OFFSETOF__Thread__m_ThreadStateFlags], TSF_DoNotTriggerGc
jz BadTransition
;; zero-out our 'previous transition frame' save slot
mov dword ptr [eax], 0
;; nothing more to do
jmp AllDone
ReverseTrapReturningThread:
;; put the previous frame back (sets us back to preemptive mode)
mov ecx, [eax]
mov [edx + OFFSETOF__Thread__m_pTransitionFrame], ecx
AttachThread:
mov ecx, eax ; arg <- address of reverse pinvoke frame
call RhpReversePInvokeAttachOrTrapThread2
jmp AllDone
BadTransition:
pop edx
pop ecx
mov ecx, dword ptr [esp] ; arg <- return address
jmp RhpReversePInvokeBadTransition
FASTCALL_ENDFUNC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; RhpReversePInvokeReturn
;;
;; IN: ECX: address of reverse pinvoke frame
;; 0: save slot for previous M->U transition frame
;; 4: save slot for thread pointer to avoid re-calc in epilog sequence
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FASTCALL_FUNC RhpReversePInvokeReturn, 0
push edx ; save return value
mov edx, [ecx + 4] ; get Thread pointer
mov ecx, [ecx + 0] ; get previous M->U transition frame
mov [edx + OFFSETOF__Thread__m_pTransitionFrame], ecx
test [RhpTrapThreads], TrapThreadsFlags_TrapThreads
pop edx ; restore return value
jnz _RhpWaitForSuspend
ret
FASTCALL_ENDFUNC
end
|