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_uint64$
213
214 	mov	rax, QWORD PTR RVALUE[rbp]
215 	movlpd	QWORD PTR [rax], xmm0
216 	jmp	SHORT ret_void$
217
218ret_uint64$:
219  	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT64
220  	jne	SHORT ret_sint64$
221
222 	mov	rcx, QWORD PTR RVALUE[rbp]
223 	mov	QWORD PTR [rcx], rax
224 	jmp	SHORT ret_void$
225
226ret_sint64$:
227  	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT64
228  	jne	SHORT ret_pointer$
229
230 	mov	rcx, QWORD PTR RVALUE[rbp]
231 	mov	QWORD PTR [rcx], rax
232 	jmp	SHORT ret_void$
233
234ret_pointer$:
235  	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_POINTER
236  	jne	SHORT ret_int$
237
238 	mov	rcx, QWORD PTR RVALUE[rbp]
239 	mov	QWORD PTR [rcx], rax
240 	jmp	SHORT ret_void$
241
242ret_int$:
243  	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_INT
244  	jne	SHORT ret_void$
245
246	mov	rcx, QWORD PTR RVALUE[rbp]
247	cdqe
248	mov	QWORD PTR [rcx], rax
249 	jmp	SHORT ret_void$
250
251ret_void$:
252	xor	rax, rax
253
254	lea	rsp, QWORD PTR [rbp+16]
255	pop	rbp
256	ret	0
257ffi_call_win64 ENDP
258_TEXT	ENDS
259END
260
261#else
262
263#ifdef SYMBOL_UNDERSCORE
264#define SYMBOL_NAME(name) _##name
265#else
266#define SYMBOL_NAME(name) name
267#endif
268
269.text
270
271.extern SYMBOL_NAME(ffi_closure_win64_inner)
272
273# ffi_closure_win64 will be called with these registers set:
274#    rax points to 'closure'
275#    r11 contains a bit mask that specifies which of the
276#    first four parameters are float or double
277#
278# It must move the parameters passed in registers to their stack location,
279# call ffi_closure_win64_inner for the actual work, then return the result.
280#
281	.balign 16
282	.globl SYMBOL_NAME(ffi_closure_win64)
283	.seh_proc SYMBOL_NAME(ffi_closure_win64)
284SYMBOL_NAME(ffi_closure_win64):
285	# copy register arguments onto stack
286	test	$1,%r11
287	jne	.Lfirst_is_float
288	mov	%rcx, 8(%rsp)
289	jmp	.Lsecond
290.Lfirst_is_float:
291	movlpd	%xmm0, 8(%rsp)
292
293.Lsecond:
294	test	$2, %r11
295	jne	.Lsecond_is_float
296	mov	%rdx, 16(%rsp)
297	jmp	.Lthird
298.Lsecond_is_float:
299	movlpd	%xmm1, 16(%rsp)
300
301.Lthird:
302	test	$4, %r11
303	jne	.Lthird_is_float
304	mov	%r8,24(%rsp)
305	jmp	.Lfourth
306.Lthird_is_float:
307	movlpd	%xmm2, 24(%rsp)
308
309.Lfourth:
310	test	$8, %r11
311	jne	.Lfourth_is_float
312	mov	%r9, 32(%rsp)
313	jmp	.Ldone
314.Lfourth_is_float:
315	movlpd	%xmm3, 32(%rsp)
316
317.Ldone:
318	.seh_stackalloc 40
319	sub	$40, %rsp
320	.seh_endprologue
321	mov	%rax, %rcx	# context is first parameter
322	mov	%rsp, %rdx	# stack is second parameter
323	add	$48, %rdx	# point to start of arguments
324	leaq	SYMBOL_NAME(ffi_closure_win64_inner)(%rip), %rax
325	callq	*%rax		# call the real closure function
326	add	$40, %rsp
327	movq	%rax, %xmm0	# If the closure returned a float,
328				# ffi_closure_win64_inner wrote it to rax
329	retq
330	.seh_endproc
331
332	.balign 16
333	.globl	SYMBOL_NAME(ffi_call_win64)
334	.seh_proc SYMBOL_NAME(ffi_call_win64)
335SYMBOL_NAME(ffi_call_win64):
336	# copy registers onto stack
337	mov	%r9,32(%rsp)
338	mov	%r8,24(%rsp)
339	mov	%rdx,16(%rsp)
340	mov	%rcx,8(%rsp)
341	.seh_pushreg rbp
342	push	%rbp
343	.seh_stackalloc 48
344	sub	$48,%rsp
345	.seh_setframe rbp, 32
346	lea	32(%rsp),%rbp
347	.seh_endprologue
348
349	mov	CIF_BYTES(%rbp),%eax
350	add	$15, %rax
351	and	$-16, %rax
352	cmpq	$0x1000, %rax
353	jb	Lch_done
354Lch_probe:
355	subq	$0x1000,%rsp
356	orl	$0x0, (%rsp)
357	subq	$0x1000,%rax
358	cmpq	$0x1000,%rax
359	ja	Lch_probe
360Lch_done:
361	subq	%rax, %rsp
362	orl	$0x0, (%rsp)
363	lea	32(%rsp), %rax
364	mov	%rax, STACK(%rbp)
365
366	mov	ECIF(%rbp), %rdx
367	mov	STACK(%rbp), %rcx
368	callq	*PREP_ARGS_FN(%rbp)
369
370	mov	STACK(%rbp), %rsp
371
372	movlpd	24(%rsp), %xmm3
373	movd	%xmm3, %r9
374
375	movlpd	16(%rsp), %xmm2
376	movd	%xmm2, %r8
377
378	movlpd	8(%rsp), %xmm1
379	movd	%xmm1, %rdx
380
381	movlpd	(%rsp), %xmm0
382	movd	%xmm0, %rcx
383
384	callq	*FN(%rbp)
385.Lret_struct4b:
386 	cmpl	$FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp)
387 	jne .Lret_struct2b
388
389	mov	RVALUE(%rbp), %rcx
390	mov	%eax, (%rcx)
391	jmp	.Lret_void
392
393.Lret_struct2b:
394	cmpl	$FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp)
395	jne .Lret_struct1b
396
397	mov	RVALUE(%rbp), %rcx
398	mov	%ax, (%rcx)
399	jmp .Lret_void
400
401.Lret_struct1b:
402	cmpl	$FFI_TYPE_SMALL_STRUCT_1B, CIF_FLAGS(%rbp)
403	jne .Lret_uint8
404
405	mov	RVALUE(%rbp), %rcx
406	mov	%al, (%rcx)
407	jmp .Lret_void
408
409.Lret_uint8:
410	cmpl	$FFI_TYPE_UINT8, CIF_FLAGS(%rbp)
411	jne .Lret_sint8
412
413	mov     RVALUE(%rbp), %rcx
414	movzbq  %al, %rax
415	movq    %rax, (%rcx)
416	jmp .Lret_void
417
418.Lret_sint8:
419	cmpl	$FFI_TYPE_SINT8, CIF_FLAGS(%rbp)
420	jne .Lret_uint16
421
422	mov     RVALUE(%rbp), %rcx
423	movsbq  %al, %rax
424	movq    %rax, (%rcx)
425	jmp .Lret_void
426
427.Lret_uint16:
428	cmpl	$FFI_TYPE_UINT16, CIF_FLAGS(%rbp)
429	jne .Lret_sint16
430
431	mov     RVALUE(%rbp), %rcx
432	movzwq  %ax, %rax
433	movq    %rax, (%rcx)
434	jmp .Lret_void
435
436.Lret_sint16:
437	cmpl	$FFI_TYPE_SINT16, CIF_FLAGS(%rbp)
438	jne .Lret_uint32
439
440	mov     RVALUE(%rbp), %rcx
441	movswq  %ax, %rax
442	movq    %rax, (%rcx)
443	jmp .Lret_void
444
445.Lret_uint32:
446	cmpl	$FFI_TYPE_UINT32, CIF_FLAGS(%rbp)
447	jne .Lret_sint32
448
449	mov     RVALUE(%rbp), %rcx
450	movl    %eax, %eax
451	movq    %rax, (%rcx)
452	jmp .Lret_void
453
454.Lret_sint32:
455 	cmpl	$FFI_TYPE_SINT32, CIF_FLAGS(%rbp)
456 	jne	.Lret_float
457
458	mov	RVALUE(%rbp), %rcx
459	cltq
460	movq	%rax, (%rcx)
461	jmp	.Lret_void
462
463.Lret_float:
464 	cmpl	$FFI_TYPE_FLOAT, CIF_FLAGS(%rbp)
465 	jne	.Lret_double
466
467 	mov	RVALUE(%rbp), %rax
468 	movss	%xmm0, (%rax)
469 	jmp	.Lret_void
470
471.Lret_double:
472 	cmpl	$FFI_TYPE_DOUBLE, CIF_FLAGS(%rbp)
473 	jne	.Lret_uint64
474
475 	mov	RVALUE(%rbp), %rax
476 	movlpd	%xmm0, (%rax)
477 	jmp	.Lret_void
478
479.Lret_uint64:
480  	cmpl	$FFI_TYPE_UINT64, CIF_FLAGS(%rbp)
481 	jne	.Lret_sint64
482
483 	mov	RVALUE(%rbp), %rcx
484 	mov	%rax, (%rcx)
485 	jmp	.Lret_void
486
487.Lret_sint64:
488  	cmpl	$FFI_TYPE_SINT64, CIF_FLAGS(%rbp)
489  	jne	.Lret_pointer
490
491 	mov	RVALUE(%rbp), %rcx
492 	mov	%rax, (%rcx)
493 	jmp	.Lret_void
494
495.Lret_pointer:
496  	cmpl	$FFI_TYPE_POINTER, CIF_FLAGS(%rbp)
497  	jne	.Lret_int
498
499 	mov	RVALUE(%rbp), %rcx
500 	mov	%rax, (%rcx)
501 	jmp	.Lret_void
502
503.Lret_int:
504  	cmpl	$FFI_TYPE_INT, CIF_FLAGS(%rbp)
505  	jne	.Lret_void
506
507	mov	RVALUE(%rbp), %rcx
508	cltq
509	movq	%rax, (%rcx)
510	jmp	.Lret_void
511
512.Lret_void:
513	xor	%rax, %rax
514
515	lea	16(%rbp), %rsp
516	pop	%rbp
517	retq
518	.seh_endproc
519#endif /* !_MSC_VER */
520
521