1#define LIBFFI_ASM
2#include <fficonfig.h>
3#include <ffi.h>
4
5/* Constants for ffi_call_win64 */
6#define STACK 0
7#define PREP_ARGS_FN 32
8#define ECIF 40
9#define CIF_BYTES 48
10#define CIF_FLAGS 56
11#define RVALUE 64
12#define FN 72
13
14/* ffi_call_win64 (void (*prep_args_fn)(char *, extended_cif *),
15                   extended_cif *ecif, unsigned bytes, unsigned flags,
16                   unsigned *rvalue, void (*fn)());
17 */
18
19#ifdef _MSC_VER
20PUBLIC	ffi_call_win64
21
22EXTRN	__chkstk:NEAR
23EXTRN	ffi_closure_win64_inner:NEAR
24
25_TEXT	SEGMENT
26
27;;; ffi_closure_win64 will be called with these registers set:
28;;;    rax points to 'closure'
29;;;    r11 contains a bit mask that specifies which of the
30;;;    first four parameters are float or double
31;;;
32;;; It must move the parameters passed in registers to their stack location,
33;;; call ffi_closure_win64_inner for the actual work, then return the result.
34;;;
35ffi_closure_win64 PROC FRAME
36	;; copy register arguments onto stack
37	test	r11, 1
38	jne	first_is_float
39	mov	QWORD PTR [rsp+8], rcx
40	jmp	second
41first_is_float:
42	movlpd	QWORD PTR [rsp+8], xmm0
43
44second:
45	test	r11, 2
46	jne	second_is_float
47	mov	QWORD PTR [rsp+16], rdx
48	jmp	third
49second_is_float:
50	movlpd	QWORD PTR [rsp+16], xmm1
51
52third:
53	test	r11, 4
54	jne	third_is_float
55	mov	QWORD PTR [rsp+24], r8
56	jmp	fourth
57third_is_float:
58	movlpd	QWORD PTR [rsp+24], xmm2
59
60fourth:
61	test	r11, 8
62	jne	fourth_is_float
63	mov	QWORD PTR [rsp+32], r9
64	jmp	done
65fourth_is_float:
66	movlpd	QWORD PTR [rsp+32], xmm3
67
68done:
69        .ALLOCSTACK 40
70	sub	rsp, 40
71        .ENDPROLOG
72	mov	rcx, rax	; context is first parameter
73	mov	rdx, rsp	; stack is second parameter
74	add	rdx, 48		; point to start of arguments
75	mov	rax, ffi_closure_win64_inner
76	call	rax		; call the real closure function
77	add	rsp, 40
78	movd	xmm0, rax	; If the closure returned a float,
79                                ; ffi_closure_win64_inner wrote it to rax
80	ret	0
81ffi_closure_win64 ENDP
82
83ffi_call_win64 PROC FRAME
84        ;; copy registers onto stack
85	mov	QWORD PTR [rsp+32], r9
86	mov	QWORD PTR [rsp+24], r8
87	mov	QWORD PTR [rsp+16], rdx
88	mov	QWORD PTR [rsp+8], rcx
89        .PUSHREG rbp
90	push	rbp
91        .ALLOCSTACK 48
92	sub	rsp, 48					; 00000030H
93        .SETFRAME rbp, 32
94	lea	rbp, QWORD PTR [rsp+32]
95        .ENDPROLOG
96
97	mov	eax, DWORD PTR CIF_BYTES[rbp]
98	add	rax, 15
99	and	rax, -16
100	call	__chkstk
101	sub	rsp, rax
102	lea	rax, QWORD PTR [rsp+32]
103	mov	QWORD PTR STACK[rbp], rax
104
105	mov	rdx, QWORD PTR ECIF[rbp]
106	mov	rcx, QWORD PTR STACK[rbp]
107	call	QWORD PTR PREP_ARGS_FN[rbp]
108
109	mov	rsp, QWORD PTR STACK[rbp]
110
111	movlpd	xmm3, QWORD PTR [rsp+24]
112	movd	r9, xmm3
113
114	movlpd	xmm2, QWORD PTR [rsp+16]
115	movd	r8, xmm2
116
117	movlpd	xmm1, QWORD PTR [rsp+8]
118	movd	rdx, xmm1
119
120	movlpd	xmm0, QWORD PTR [rsp]
121	movd	rcx, xmm0
122
123	call	QWORD PTR FN[rbp]
124ret_struct4b$:
125 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_4B
126 	jne	ret_struct2b$
127
128	mov	rcx, QWORD PTR RVALUE[rbp]
129	mov	DWORD PTR [rcx], eax
130	jmp	ret_void$
131
132ret_struct2b$:
133 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_2B
134 	jne	ret_struct1b$
135
136	mov	rcx, QWORD PTR RVALUE[rbp]
137	mov	WORD PTR [rcx], ax
138	jmp	ret_void$
139
140ret_struct1b$:
141 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_1B
142 	jne	ret_uint8$
143
144	mov	rcx, QWORD PTR RVALUE[rbp]
145	mov	BYTE PTR [rcx], al
146	jmp	ret_void$
147
148ret_uint8$:
149 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT8
150 	jne	ret_sint8$
151
152	mov	rcx, QWORD PTR RVALUE[rbp]
153	movzx   rax, al
154	mov	QWORD PTR [rcx], rax
155	jmp	ret_void$
156
157ret_sint8$:
158 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT8
159 	jne	ret_uint16$
160
161	mov	rcx, QWORD PTR RVALUE[rbp]
162	movsx   rax, al
163	mov	QWORD PTR [rcx], rax
164	jmp	ret_void$
165
166ret_uint16$:
167 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT16
168 	jne	ret_sint16$
169
170	mov	rcx, QWORD PTR RVALUE[rbp]
171	movzx   rax, ax
172	mov	QWORD PTR [rcx], rax
173	jmp	SHORT ret_void$
174
175ret_sint16$:
176 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT16
177 	jne	ret_uint32$
178
179	mov	rcx, QWORD PTR RVALUE[rbp]
180	movsx   rax, ax
181	mov	QWORD PTR [rcx], rax
182	jmp	SHORT ret_void$
183
184ret_uint32$:
185 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT32
186 	jne	ret_sint32$
187
188	mov	rcx, QWORD PTR RVALUE[rbp]
189	mov     eax, eax
190	mov	QWORD PTR [rcx], rax
191	jmp	SHORT ret_void$
192
193ret_sint32$:
194 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT32
195 	jne	ret_float$
196
197	mov	rcx, QWORD PTR RVALUE[rbp]
198	cdqe
199	mov	QWORD PTR [rcx], rax
200	jmp	SHORT ret_void$
201
202ret_float$:
203 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_FLOAT
204 	jne	SHORT ret_double$
205
206 	mov	rax, QWORD PTR RVALUE[rbp]
207 	movss	DWORD PTR [rax], xmm0
208 	jmp	SHORT ret_void$
209
210ret_double$:
211 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_DOUBLE
212 	jne	SHORT ret_sint64$
213
214 	mov	rax, QWORD PTR RVALUE[rbp]
215 	movlpd	QWORD PTR [rax], xmm0
216 	jmp	SHORT ret_void$
217
218ret_sint64$:
219  	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT64
220  	jne	ret_void$
221
222 	mov	rcx, QWORD PTR RVALUE[rbp]
223 	mov	QWORD PTR [rcx], rax
224 	jmp	SHORT ret_void$
225
226ret_void$:
227	xor	rax, rax
228
229	lea	rsp, QWORD PTR [rbp+16]
230	pop	rbp
231	ret	0
232ffi_call_win64 ENDP
233_TEXT	ENDS
234END
235
236#else
237
238#ifdef SYMBOL_UNDERSCORE
239#define SYMBOL_NAME(name) _##name
240#else
241#define SYMBOL_NAME(name) name
242#endif
243
244.text
245
246.extern SYMBOL_NAME(ffi_closure_win64_inner)
247
248# ffi_closure_win64 will be called with these registers set:
249#    rax points to 'closure'
250#    r11 contains a bit mask that specifies which of the
251#    first four parameters are float or double
252#
253# It must move the parameters passed in registers to their stack location,
254# call ffi_closure_win64_inner for the actual work, then return the result.
255#
256	.balign 16
257        .globl SYMBOL_NAME(ffi_closure_win64)
258SYMBOL_NAME(ffi_closure_win64):
259	# copy register arguments onto stack
260	test	$1,%r11
261	jne	.Lfirst_is_float
262	mov	%rcx, 8(%rsp)
263	jmp	.Lsecond
264.Lfirst_is_float:
265	movlpd	%xmm0, 8(%rsp)
266
267.Lsecond:
268	test	$2, %r11
269	jne	.Lsecond_is_float
270	mov	%rdx, 16(%rsp)
271	jmp	.Lthird
272.Lsecond_is_float:
273	movlpd	%xmm1, 16(%rsp)
274
275.Lthird:
276	test	$4, %r11
277	jne	.Lthird_is_float
278	mov	%r8,24(%rsp)
279	jmp	.Lfourth
280.Lthird_is_float:
281	movlpd	%xmm2, 24(%rsp)
282
283.Lfourth:
284	test	$8, %r11
285	jne	.Lfourth_is_float
286	mov	%r9, 32(%rsp)
287	jmp	.Ldone
288.Lfourth_is_float:
289	movlpd	%xmm3, 32(%rsp)
290
291.Ldone:
292#.ALLOCSTACK 40
293	sub	$40, %rsp
294#.ENDPROLOG
295	mov	%rax, %rcx	# context is first parameter
296	mov	%rsp, %rdx	# stack is second parameter
297	add	$48, %rdx	# point to start of arguments
298	leaq	SYMBOL_NAME(ffi_closure_win64_inner)(%rip), %rax
299	callq	*%rax		# call the real closure function
300	add	$40, %rsp
301	movq	%rax, %xmm0	# If the closure returned a float,
302                                # ffi_closure_win64_inner wrote it to rax
303	retq
304.ffi_closure_win64_end:
305
306	.balign 16
307        .globl	SYMBOL_NAME(ffi_call_win64)
308SYMBOL_NAME(ffi_call_win64):
309        # copy registers onto stack
310	mov	%r9,32(%rsp)
311	mov	%r8,24(%rsp)
312	mov	%rdx,16(%rsp)
313	mov	%rcx,8(%rsp)
314        #.PUSHREG rbp
315	push	%rbp
316        #.ALLOCSTACK 48
317	sub	$48,%rsp
318        #.SETFRAME rbp, 32
319	lea	32(%rsp),%rbp
320        #.ENDPROLOG
321
322	mov	CIF_BYTES(%rbp),%eax
323	add	$15, %rax
324	and	$-16, %rax
325	cmpq	$0x1000, %rax
326	jb	Lch_done
327Lch_probe:
328	subq	$0x1000,%rsp
329	orl	$0x0, (%rsp)
330	subq	$0x1000,%rax
331	cmpq	$0x1000,%rax
332	ja	Lch_probe
333Lch_done:
334	subq	%rax, %rsp
335	orl	$0x0, (%rsp)
336	lea	32(%rsp), %rax
337	mov	%rax, STACK(%rbp)
338
339	mov	ECIF(%rbp), %rdx
340	mov	STACK(%rbp), %rcx
341	callq	*PREP_ARGS_FN(%rbp)
342
343	mov	STACK(%rbp), %rsp
344
345	movlpd	24(%rsp), %xmm3
346	movd	%xmm3, %r9
347
348	movlpd	16(%rsp), %xmm2
349	movd	%xmm2, %r8
350
351	movlpd	8(%rsp), %xmm1
352	movd	%xmm1, %rdx
353
354	movlpd	(%rsp), %xmm0
355	movd	%xmm0, %rcx
356
357	callq	*FN(%rbp)
358.Lret_struct4b:
359 	cmpl	$FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp)
360 	jne .Lret_struct2b
361
362	mov	RVALUE(%rbp), %rcx
363	mov	%eax, (%rcx)
364	jmp	.Lret_void
365
366.Lret_struct2b:
367	cmpl	$FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp)
368	jne .Lret_struct1b
369
370	mov	RVALUE(%rbp), %rcx
371	mov	%ax, (%rcx)
372	jmp .Lret_void
373
374.Lret_struct1b:
375	cmpl	$FFI_TYPE_SMALL_STRUCT_1B, CIF_FLAGS(%rbp)
376	jne .Lret_uint8
377
378	mov	RVALUE(%rbp), %rcx
379	mov	%al, (%rcx)
380	jmp .Lret_void
381
382.Lret_uint8:
383	cmpl	$FFI_TYPE_UINT8, CIF_FLAGS(%rbp)
384	jne .Lret_sint8
385
386        mov     RVALUE(%rbp), %rcx
387        movzbq  %al, %rax
388	movq    %rax, (%rcx)
389	jmp .Lret_void
390
391.Lret_sint8:
392	cmpl	$FFI_TYPE_SINT8, CIF_FLAGS(%rbp)
393	jne .Lret_uint16
394
395        mov     RVALUE(%rbp), %rcx
396        movsbq  %al, %rax
397	movq    %rax, (%rcx)
398	jmp .Lret_void
399
400.Lret_uint16:
401	cmpl	$FFI_TYPE_UINT16, CIF_FLAGS(%rbp)
402	jne .Lret_sint16
403
404        mov     RVALUE(%rbp), %rcx
405        movzwq  %ax, %rax
406	movq    %rax, (%rcx)
407	jmp .Lret_void
408
409.Lret_sint16:
410	cmpl	$FFI_TYPE_SINT16, CIF_FLAGS(%rbp)
411	jne .Lret_uint32
412
413        mov     RVALUE(%rbp), %rcx
414        movswq  %ax, %rax
415	movq    %rax, (%rcx)
416	jmp .Lret_void
417
418.Lret_uint32:
419	cmpl	$FFI_TYPE_UINT32, CIF_FLAGS(%rbp)
420	jne .Lret_sint32
421
422        mov     RVALUE(%rbp), %rcx
423        movl    %eax, %eax
424	movq    %rax, (%rcx)
425	jmp .Lret_void
426
427.Lret_sint32:
428 	cmpl	$FFI_TYPE_SINT32, CIF_FLAGS(%rbp)
429 	jne	.Lret_float
430
431	mov	RVALUE(%rbp), %rcx
432	cltq
433	movq	%rax, (%rcx)
434	jmp	.Lret_void
435
436.Lret_float:
437 	cmpl	$FFI_TYPE_FLOAT, CIF_FLAGS(%rbp)
438 	jne	.Lret_double
439
440 	mov	RVALUE(%rbp), %rax
441 	movss	%xmm0, (%rax)
442 	jmp	.Lret_void
443
444.Lret_double:
445 	cmpl	$FFI_TYPE_DOUBLE, CIF_FLAGS(%rbp)
446 	jne	.Lret_sint64
447
448 	mov	RVALUE(%rbp), %rax
449 	movlpd	%xmm0, (%rax)
450 	jmp	.Lret_void
451
452.Lret_sint64:
453  	cmpl	$FFI_TYPE_SINT64, CIF_FLAGS(%rbp)
454  	jne	.Lret_void
455
456 	mov	RVALUE(%rbp), %rcx
457 	mov	%rax, (%rcx)
458 	jmp	.Lret_void
459
460.Lret_void:
461	xor	%rax, %rax
462
463	lea	16(%rbp), %rsp
464	pop	%rbp
465	retq
466.ffi_call_win64_end:
467#endif /* !_MSC_VER */
468
469