| #define LIBFFI_ASM |
| #include <fficonfig.h> |
| #include <ffi.h> |
| |
| /* Constants for ffi_call_win64 */ |
| #define STACK 0 |
| #define PREP_ARGS_FN 32 |
| #define ECIF 40 |
| #define CIF_BYTES 48 |
| #define CIF_FLAGS 56 |
| #define RVALUE 64 |
| #define FN 72 |
| |
| /* ffi_call_win64 (void (*prep_args_fn)(char *, extended_cif *), |
| extended_cif *ecif, unsigned bytes, unsigned flags, |
| unsigned *rvalue, void (*fn)()); |
| */ |
| |
| #ifdef _MSC_VER |
| PUBLIC ffi_call_win64 |
| |
| EXTRN __chkstk:NEAR |
| EXTRN ffi_closure_win64_inner:NEAR |
| |
| _TEXT SEGMENT |
| |
| ;;; ffi_closure_win64 will be called with these registers set: |
| ;;; rax points to 'closure' |
| ;;; r11 contains a bit mask that specifies which of the |
| ;;; first four parameters are float or double |
| ;;; |
| ;;; It must move the parameters passed in registers to their stack location, |
| ;;; call ffi_closure_win64_inner for the actual work, then return the result. |
| ;;; |
| ffi_closure_win64 PROC FRAME |
| ;; copy register arguments onto stack |
| test r11, 1 |
| jne first_is_float |
| mov QWORD PTR [rsp+8], rcx |
| jmp second |
| first_is_float: |
| movlpd QWORD PTR [rsp+8], xmm0 |
| |
| second: |
| test r11, 2 |
| jne second_is_float |
| mov QWORD PTR [rsp+16], rdx |
| jmp third |
| second_is_float: |
| movlpd QWORD PTR [rsp+16], xmm1 |
| |
| third: |
| test r11, 4 |
| jne third_is_float |
| mov QWORD PTR [rsp+24], r8 |
| jmp fourth |
| third_is_float: |
| movlpd QWORD PTR [rsp+24], xmm2 |
| |
| fourth: |
| test r11, 8 |
| jne fourth_is_float |
| mov QWORD PTR [rsp+32], r9 |
| jmp done |
| fourth_is_float: |
| movlpd QWORD PTR [rsp+32], xmm3 |
| |
| done: |
| .ALLOCSTACK 40 |
| sub rsp, 40 |
| .ENDPROLOG |
| mov rcx, rax ; context is first parameter |
| mov rdx, rsp ; stack is second parameter |
| add rdx, 48 ; point to start of arguments |
| mov rax, ffi_closure_win64_inner |
| call rax ; call the real closure function |
| add rsp, 40 |
| movd xmm0, rax ; If the closure returned a float, |
| ; ffi_closure_win64_inner wrote it to rax |
| ret 0 |
| ffi_closure_win64 ENDP |
| |
| ffi_call_win64 PROC FRAME |
| ;; copy registers onto stack |
| mov QWORD PTR [rsp+32], r9 |
| mov QWORD PTR [rsp+24], r8 |
| mov QWORD PTR [rsp+16], rdx |
| mov QWORD PTR [rsp+8], rcx |
| .PUSHREG rbp |
| push rbp |
| .ALLOCSTACK 48 |
| sub rsp, 48 ; 00000030H |
| .SETFRAME rbp, 32 |
| lea rbp, QWORD PTR [rsp+32] |
| .ENDPROLOG |
| |
| mov eax, DWORD PTR CIF_BYTES[rbp] |
| add rax, 15 |
| and rax, -16 |
| call __chkstk |
| sub rsp, rax |
| lea rax, QWORD PTR [rsp+32] |
| mov QWORD PTR STACK[rbp], rax |
| |
| mov rdx, QWORD PTR ECIF[rbp] |
| mov rcx, QWORD PTR STACK[rbp] |
| call QWORD PTR PREP_ARGS_FN[rbp] |
| |
| mov rsp, QWORD PTR STACK[rbp] |
| |
| movlpd xmm3, QWORD PTR [rsp+24] |
| movd r9, xmm3 |
| |
| movlpd xmm2, QWORD PTR [rsp+16] |
| movd r8, xmm2 |
| |
| movlpd xmm1, QWORD PTR [rsp+8] |
| movd rdx, xmm1 |
| |
| movlpd xmm0, QWORD PTR [rsp] |
| movd rcx, xmm0 |
| |
| call QWORD PTR FN[rbp] |
| ret_struct4b$: |
| cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_4B |
| jne ret_struct2b$ |
| |
| mov rcx, QWORD PTR RVALUE[rbp] |
| mov DWORD PTR [rcx], eax |
| jmp ret_void$ |
| |
| ret_struct2b$: |
| cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_2B |
| jne ret_struct1b$ |
| |
| mov rcx, QWORD PTR RVALUE[rbp] |
| mov WORD PTR [rcx], ax |
| jmp ret_void$ |
| |
| ret_struct1b$: |
| cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_1B |
| jne ret_uint8$ |
| |
| mov rcx, QWORD PTR RVALUE[rbp] |
| mov BYTE PTR [rcx], al |
| jmp ret_void$ |
| |
| ret_uint8$: |
| cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT8 |
| jne ret_sint8$ |
| |
| mov rcx, QWORD PTR RVALUE[rbp] |
| movzx rax, al |
| mov QWORD PTR [rcx], rax |
| jmp ret_void$ |
| |
| ret_sint8$: |
| cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT8 |
| jne ret_uint16$ |
| |
| mov rcx, QWORD PTR RVALUE[rbp] |
| movsx rax, al |
| mov QWORD PTR [rcx], rax |
| jmp ret_void$ |
| |
| ret_uint16$: |
| cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT16 |
| jne ret_sint16$ |
| |
| mov rcx, QWORD PTR RVALUE[rbp] |
| movzx rax, ax |
| mov QWORD PTR [rcx], rax |
| jmp SHORT ret_void$ |
| |
| ret_sint16$: |
| cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT16 |
| jne ret_uint32$ |
| |
| mov rcx, QWORD PTR RVALUE[rbp] |
| movsx rax, ax |
| mov QWORD PTR [rcx], rax |
| jmp SHORT ret_void$ |
| |
| ret_uint32$: |
| cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT32 |
| jne ret_sint32$ |
| |
| mov rcx, QWORD PTR RVALUE[rbp] |
| mov eax, eax |
| mov QWORD PTR [rcx], rax |
| jmp SHORT ret_void$ |
| |
| ret_sint32$: |
| cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT32 |
| jne ret_float$ |
| |
| mov rcx, QWORD PTR RVALUE[rbp] |
| cdqe |
| mov QWORD PTR [rcx], rax |
| jmp SHORT ret_void$ |
| |
| ret_float$: |
| cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_FLOAT |
| jne SHORT ret_double$ |
| |
| mov rax, QWORD PTR RVALUE[rbp] |
| movss DWORD PTR [rax], xmm0 |
| jmp SHORT ret_void$ |
| |
| ret_double$: |
| cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_DOUBLE |
| jne SHORT ret_sint64$ |
| |
| mov rax, QWORD PTR RVALUE[rbp] |
| movlpd QWORD PTR [rax], xmm0 |
| jmp SHORT ret_void$ |
| |
| ret_sint64$: |
| cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT64 |
| jne ret_void$ |
| |
| mov rcx, QWORD PTR RVALUE[rbp] |
| mov QWORD PTR [rcx], rax |
| jmp SHORT ret_void$ |
| |
| ret_void$: |
| xor rax, rax |
| |
| lea rsp, QWORD PTR [rbp+16] |
| pop rbp |
| ret 0 |
| ffi_call_win64 ENDP |
| _TEXT ENDS |
| END |
| #else |
| .text |
| |
| .extern _ffi_closure_win64_inner |
| |
| # ffi_closure_win64 will be called with these registers set: |
| # rax points to 'closure' |
| # r11 contains a bit mask that specifies which of the |
| # first four parameters are float or double |
| # |
| # It must move the parameters passed in registers to their stack location, |
| # call ffi_closure_win64_inner for the actual work, then return the result. |
| # |
| .balign 16 |
| .globl _ffi_closure_win64 |
| _ffi_closure_win64: |
| # copy register arguments onto stack |
| test $1,%r11 |
| jne .Lfirst_is_float |
| mov %rcx, 8(%rsp) |
| jmp .Lsecond |
| .Lfirst_is_float: |
| movlpd %xmm0, 8(%rsp) |
| |
| .Lsecond: |
| test $2, %r11 |
| jne .Lsecond_is_float |
| mov %rdx, 16(%rsp) |
| jmp .Lthird |
| .Lsecond_is_float: |
| movlpd %xmm1, 16(%rsp) |
| |
| .Lthird: |
| test $4, %r11 |
| jne .Lthird_is_float |
| mov %r8,24(%rsp) |
| jmp .Lfourth |
| .Lthird_is_float: |
| movlpd %xmm2, 24(%rsp) |
| |
| .Lfourth: |
| test $8, %r11 |
| jne .Lfourth_is_float |
| mov %r9, 32(%rsp) |
| jmp .Ldone |
| .Lfourth_is_float: |
| movlpd %xmm3, 32(%rsp) |
| |
| .Ldone: |
| #.ALLOCSTACK 40 |
| sub $40, %rsp |
| #.ENDPROLOG |
| mov %rax, %rcx # context is first parameter |
| mov %rsp, %rdx # stack is second parameter |
| add $48, %rdx # point to start of arguments |
| mov $_ffi_closure_win64_inner, %rax |
| callq *%rax # call the real closure function |
| add $40, %rsp |
| movq %rax, %xmm0 # If the closure returned a float, |
| # ffi_closure_win64_inner wrote it to rax |
| retq |
| .ffi_closure_win64_end: |
| |
| .balign 16 |
| .globl _ffi_call_win64 |
| _ffi_call_win64: |
| # copy registers onto stack |
| mov %r9,32(%rsp) |
| mov %r8,24(%rsp) |
| mov %rdx,16(%rsp) |
| mov %rcx,8(%rsp) |
| #.PUSHREG rbp |
| push %rbp |
| #.ALLOCSTACK 48 |
| sub $48,%rsp |
| #.SETFRAME rbp, 32 |
| lea 32(%rsp),%rbp |
| #.ENDPROLOG |
| |
| mov CIF_BYTES(%rbp),%eax |
| add $15, %rax |
| and $-16, %rax |
| cmpq $0x1000, %rax |
| jb Lch_done |
| Lch_probe: |
| subq $0x1000,%rsp |
| orl $0x0, (%rsp) |
| subq $0x1000,%rax |
| cmpq $0x1000,%rax |
| ja Lch_probe |
| Lch_done: |
| subq %rax, %rsp |
| orl $0x0, (%rsp) |
| lea 32(%rsp), %rax |
| mov %rax, STACK(%rbp) |
| |
| mov ECIF(%rbp), %rdx |
| mov STACK(%rbp), %rcx |
| callq *PREP_ARGS_FN(%rbp) |
| |
| mov STACK(%rbp), %rsp |
| |
| movlpd 24(%rsp), %xmm3 |
| movd %xmm3, %r9 |
| |
| movlpd 16(%rsp), %xmm2 |
| movd %xmm2, %r8 |
| |
| movlpd 8(%rsp), %xmm1 |
| movd %xmm1, %rdx |
| |
| movlpd (%rsp), %xmm0 |
| movd %xmm0, %rcx |
| |
| callq *FN(%rbp) |
| .Lret_struct4b: |
| cmpl $FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp) |
| jne .Lret_struct2b |
| |
| mov RVALUE(%rbp), %rcx |
| mov %eax, (%rcx) |
| jmp .Lret_void |
| |
| .Lret_struct2b: |
| cmpl $FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp) |
| jne .Lret_struct1b |
| |
| mov RVALUE(%rbp), %rcx |
| mov %ax, (%rcx) |
| jmp .Lret_void |
| |
| .Lret_struct1b: |
| cmpl $FFI_TYPE_SMALL_STRUCT_1B, CIF_FLAGS(%rbp) |
| jne .Lret_uint8 |
| |
| mov RVALUE(%rbp), %rcx |
| mov %al, (%rcx) |
| jmp .Lret_void |
| |
| .Lret_uint8: |
| cmpl $FFI_TYPE_UINT8, CIF_FLAGS(%rbp) |
| jne .Lret_sint8 |
| |
| mov RVALUE(%rbp), %rcx |
| movzbq %al, %rax |
| movq %rax, (%rcx) |
| jmp .Lret_void |
| |
| .Lret_sint8: |
| cmpl $FFI_TYPE_SINT8, CIF_FLAGS(%rbp) |
| jne .Lret_uint16 |
| |
| mov RVALUE(%rbp), %rcx |
| movsbq %al, %rax |
| movq %rax, (%rcx) |
| jmp .Lret_void |
| |
| .Lret_uint16: |
| cmpl $FFI_TYPE_UINT16, CIF_FLAGS(%rbp) |
| jne .Lret_sint16 |
| |
| mov RVALUE(%rbp), %rcx |
| movzwq %ax, %rax |
| movq %rax, (%rcx) |
| jmp .Lret_void |
| |
| .Lret_sint16: |
| cmpl $FFI_TYPE_SINT16, CIF_FLAGS(%rbp) |
| jne .Lret_uint32 |
| |
| mov RVALUE(%rbp), %rcx |
| movswq %ax, %rax |
| movq %rax, (%rcx) |
| jmp .Lret_void |
| |
| .Lret_uint32: |
| cmpl $FFI_TYPE_UINT32, CIF_FLAGS(%rbp) |
| jne .Lret_sint32 |
| |
| mov RVALUE(%rbp), %rcx |
| movl %eax, %eax |
| movq %rax, (%rcx) |
| jmp .Lret_void |
| |
| .Lret_sint32: |
| cmpl $FFI_TYPE_SINT32, CIF_FLAGS(%rbp) |
| jne .Lret_float |
| |
| mov RVALUE(%rbp), %rcx |
| cltq |
| movq %rax, (%rcx) |
| jmp .Lret_void |
| |
| .Lret_float: |
| cmpl $FFI_TYPE_FLOAT, CIF_FLAGS(%rbp) |
| jne .Lret_double |
| |
| mov RVALUE(%rbp), %rax |
| movss %xmm0, (%rax) |
| jmp .Lret_void |
| |
| .Lret_double: |
| cmpl $FFI_TYPE_DOUBLE, CIF_FLAGS(%rbp) |
| jne .Lret_sint64 |
| |
| mov RVALUE(%rbp), %rax |
| movlpd %xmm0, (%rax) |
| jmp .Lret_void |
| |
| .Lret_sint64: |
| cmpl $FFI_TYPE_SINT64, CIF_FLAGS(%rbp) |
| jne .Lret_void |
| |
| mov RVALUE(%rbp), %rcx |
| mov %rax, (%rcx) |
| jmp .Lret_void |
| |
| .Lret_void: |
| xor %rax, %rax |
| |
| lea 16(%rbp), %rsp |
| pop %rbp |
| retq |
| .ffi_call_win64_end: |
| #endif /* !_MSC_VER */ |
| |