461 lines
9.0 KiB
ArmAsm
461 lines
9.0 KiB
ArmAsm
#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 */
|
|
|