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