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
|
; 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.
; ==++==
;
;
; ==--==
include AsmMacros.inc
include AsmConstants.inc
extern GenericPInvokeCalliStubWorker:proc
extern VarargPInvokeStubWorker:proc
ifdef FEATURE_INCLUDE_ALL_INTERFACES
PInvokeStubForHostWorker equ ?PInvokeStubForHostWorker@@YAXKPEAX0@Z
extern PInvokeStubForHostWorker:proc
PInvokeStubForHost_CALLEE_SCRATCH_SIZE = 20h
PInvokeStubForHost_STACK_FRAME_SIZE = PInvokeStubForHost_CALLEE_SCRATCH_SIZE
; 4 FP parameter registers
PInvokeStubForHost_XMM_SAVE_OFFSET = PInvokeStubForHost_STACK_FRAME_SIZE
PInvokeStubForHost_STACK_FRAME_SIZE = PInvokeStubForHost_STACK_FRAME_SIZE + 40h
; Ensure that the new rsp will be 16-byte aligned.
if ((PInvokeStubForHost_STACK_FRAME_SIZE + 8) MOD 16) ne 0
PInvokeStubForHost_STACK_FRAME_SIZE = PInvokeStubForHost_STACK_FRAME_SIZE + 8
endif
; Return address is immediately above the local variables.
PInvokeStubForHost_RETURN_ADDRESS_OFFSET = PInvokeStubForHost_STACK_FRAME_SIZE
PInvokeStubForHost_PARAM_REGISTERS_OFFSET = PInvokeStubForHost_RETURN_ADDRESS_OFFSET + 8
NESTED_ENTRY PInvokeStubForHost, _TEXT
alloc_stack PInvokeStubForHost_STACK_FRAME_SIZE
END_PROLOGUE
; spill args
mov [rsp + PInvokeStubForHost_PARAM_REGISTERS_OFFSET + 0h], rcx
mov [rsp + PInvokeStubForHost_PARAM_REGISTERS_OFFSET + 8h], rdx
mov [rsp + PInvokeStubForHost_PARAM_REGISTERS_OFFSET + 10h], r8
mov [rsp + PInvokeStubForHost_PARAM_REGISTERS_OFFSET + 18h], r9
movdqa [rsp + PInvokeStubForHost_XMM_SAVE_OFFSET + 0h], xmm0
movdqa [rsp + PInvokeStubForHost_XMM_SAVE_OFFSET + 10h], xmm1
movdqa [rsp + PInvokeStubForHost_XMM_SAVE_OFFSET + 20h], xmm2
movdqa [rsp + PInvokeStubForHost_XMM_SAVE_OFFSET + 30h], xmm3
; PInvokeStubForHostWorker(#stack args, stack frame, this)
mov r8, rcx
mov rcx, r11
mov rdx, rsp
call PInvokeStubForHostWorker
; unspill return value
mov rax, [rsp + PInvokeStubForHost_XMM_SAVE_OFFSET + 0h]
movdqa xmm0, [rsp + PInvokeStubForHost_XMM_SAVE_OFFSET + 10h]
add rsp, PInvokeStubForHost_STACK_FRAME_SIZE
ret
NESTED_END PInvokeStubForHost, _TEXT
PInvokeStubForHostInner_STACK_FRAME_SIZE = 0
; integer registers saved in prologue
PInvokeStubForHostInner_NUM_REG_PUSHES = 2
PInvokeStubForHostInner_STACK_FRAME_SIZE = PInvokeStubForHostInner_STACK_FRAME_SIZE + PInvokeStubForHostInner_NUM_REG_PUSHES*8
; Ensure that the new rsp will be 16-byte aligned.
if ((PInvokeStubForHostInner_STACK_FRAME_SIZE + 8) MOD 16) ne 0
PInvokeStubForHostInner_STACK_FRAME_SIZE = PInvokeStubForHostInner_STACK_FRAME_SIZE + 8
endif
; Return address is immediately above the local variables.
PInvokeStubForHostInner_RETURN_ADDRESS_OFFSET = PInvokeStubForHostInner_STACK_FRAME_SIZE
PInvokeStubForHostInner_PARAM_REGISTERS_OFFSET = PInvokeStubForHostInner_RETURN_ADDRESS_OFFSET + 8
PInvokeStubForHostInner_FRAME_OFFSET = PInvokeStubForHost_CALLEE_SCRATCH_SIZE
; RCX - #stack args
; RDX - PInvokeStubForHost's stack frame
; R8 - target address
NESTED_ENTRY PInvokeStubForHostInner, _TEXT
push_nonvol_reg rbp
push_nonvol_reg r12
alloc_stack PInvokeStubForHostInner_FRAME_OFFSET + PInvokeStubForHostInner_STACK_FRAME_SIZE - PInvokeStubForHostInner_NUM_REG_PUSHES*8
set_frame rbp, PInvokeStubForHostInner_FRAME_OFFSET
END_PROLOGUE
mov r10, r8
mov r12, rdx
test rcx, rcx
jnz HandleStackArgs
;
; Allocate space for scratch area if there are no stack args.
;
sub rsp, PInvokeStubForHost_CALLEE_SCRATCH_SIZE
DoneStackArgs:
; unspill args
mov rcx, [r12 + PInvokeStubForHost_PARAM_REGISTERS_OFFSET + 0h]
mov rdx, [r12 + PInvokeStubForHost_PARAM_REGISTERS_OFFSET + 8h]
mov r8, [r12 + PInvokeStubForHost_PARAM_REGISTERS_OFFSET + 10h]
mov r9, [r12 + PInvokeStubForHost_PARAM_REGISTERS_OFFSET + 18h]
movdqa xmm0, [r12 + PInvokeStubForHost_XMM_SAVE_OFFSET + 0h]
movdqa xmm1, [r12 + PInvokeStubForHost_XMM_SAVE_OFFSET + 10h]
movdqa xmm2, [r12 + PInvokeStubForHost_XMM_SAVE_OFFSET + 20h]
movdqa xmm3, [r12 + PInvokeStubForHost_XMM_SAVE_OFFSET + 30h]
call r10
; spill return value
mov [r12 + PInvokeStubForHost_XMM_SAVE_OFFSET + 0h], rax
movdqa [r12 + PInvokeStubForHost_XMM_SAVE_OFFSET + 10h], xmm0
; epilogue
lea rsp, [rbp + PInvokeStubForHostInner_RETURN_ADDRESS_OFFSET - PInvokeStubForHostInner_NUM_REG_PUSHES*8]
pop r12
pop rbp
ret
; INPUTS:
; RDX - number of stack bytes
; R12 - the outer method's frame pointer
; RSP -
; RBP -
;
HandleStackArgs:
;
; Allocate space for stack parameters + scratch area.
;
sub rsp, rcx
and rsp, -16
sub rsp, PInvokeStubForHost_CALLEE_SCRATCH_SIZE
;
; Copy stack parameters
;
shr rcx, 3 ; setup count
mov r8, rdi
mov r9, rsi
lea rdi, [rsp + PInvokeStubForHost_CALLEE_SCRATCH_SIZE] ; rdi -> above callee scratch area
lea rsi, [r12 + PInvokeStubForHost_PARAM_REGISTERS_OFFSET + PInvokeStubForHost_CALLEE_SCRATCH_SIZE]
rep movsq
mov rsi, r9 ; restore rsi
mov rdi, r8 ; restore rdi
jmp DoneStackArgs
NESTED_END PInvokeStubForHostInner, _TEXT
endif ; FEATURE_INCLUDE_ALL_INTERFACES
;
; in:
; PINVOKE_CALLI_TARGET_REGISTER (r10) = unmanaged target
; PINVOKE_CALLI_SIGTOKEN_REGNUM (r11) = sig token
;
; out:
; METHODDESC_REGISTER (r10) = unmanaged target
;
LEAF_ENTRY GenericPInvokeCalliHelper, _TEXT
;
; check for existing IL stub
;
mov rax, [PINVOKE_CALLI_SIGTOKEN_REGISTER + OFFSETOF__VASigCookie__pNDirectILStub]
test rax, rax
jz GenericPInvokeCalliGenILStub
;
; We need to distinguish between a MethodDesc* and an unmanaged target in PInvokeStubForHost().
; The way we do this is to shift the managed target to the left by one bit and then set the
; least significant bit to 1. This works because MethodDesc* are always 8-byte aligned.
;
shl PINVOKE_CALLI_TARGET_REGISTER, 1
or PINVOKE_CALLI_TARGET_REGISTER, 1
;
; jump to existing IL stub
;
jmp rax
LEAF_END GenericPInvokeCalliHelper, _TEXT
NESTED_ENTRY GenericPInvokeCalliGenILStub, _TEXT
PROLOG_WITH_TRANSITION_BLOCK
;
; save target
;
mov r12, METHODDESC_REGISTER
mov r13, PINVOKE_CALLI_SIGTOKEN_REGISTER
;
; GenericPInvokeCalliStubWorker(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget)
;
lea rcx, [rsp + __PWTB_TransitionBlock] ; pTransitionBlock*
mov rdx, PINVOKE_CALLI_SIGTOKEN_REGISTER ; pVASigCookie
mov r8, METHODDESC_REGISTER ; pUnmanagedTarget
call GenericPInvokeCalliStubWorker
;
; restore target
;
mov METHODDESC_REGISTER, r12
mov PINVOKE_CALLI_SIGTOKEN_REGISTER, r13
EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
jmp GenericPInvokeCalliHelper
NESTED_END GenericPInvokeCalliGenILStub, _TEXT
LEAF_ENTRY VarargPInvokeStub, _TEXT
mov PINVOKE_CALLI_SIGTOKEN_REGISTER, rcx
jmp VarargPInvokeStubHelper
LEAF_END VarargPInvokeStub, _TEXT
LEAF_ENTRY VarargPInvokeStub_RetBuffArg, _TEXT
mov PINVOKE_CALLI_SIGTOKEN_REGISTER, rdx
jmp VarargPInvokeStubHelper
LEAF_END VarargPInvokeStub_RetBuffArg, _TEXT
LEAF_ENTRY VarargPInvokeStubHelper, _TEXT
;
; check for existing IL stub
;
mov rax, [PINVOKE_CALLI_SIGTOKEN_REGISTER + OFFSETOF__VASigCookie__pNDirectILStub]
test rax, rax
jz VarargPInvokeGenILStub
;
; jump to existing IL stub
;
jmp rax
LEAF_END VarargPInvokeStubHelper, _TEXT
;
; IN: METHODDESC_REGISTER (R10) stub secret param
; PINVOKE_CALLI_SIGTOKEN_REGISTER (R11) VASigCookie*
;
; ASSUMES: we already checked for an existing stub to use
;
NESTED_ENTRY VarargPInvokeGenILStub, _TEXT
PROLOG_WITH_TRANSITION_BLOCK
;
; save target
;
mov r12, METHODDESC_REGISTER
mov r13, PINVOKE_CALLI_SIGTOKEN_REGISTER
;
; VarargPInvokeStubWorker(TransitionBlock * pTransitionBlock, VASigCookie *pVASigCookie, MethodDesc *pMD)
;
lea rcx, [rsp + __PWTB_TransitionBlock] ; pTransitionBlock*
mov rdx, PINVOKE_CALLI_SIGTOKEN_REGISTER ; pVASigCookie
mov r8, METHODDESC_REGISTER ; pMD
call VarargPInvokeStubWorker
;
; restore target
;
mov METHODDESC_REGISTER, r12
mov PINVOKE_CALLI_SIGTOKEN_REGISTER, r13
EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
jmp VarargPInvokeStubHelper
NESTED_END VarargPInvokeGenILStub, _TEXT
end
|