mirror of
https://github.com/partic2/libffi
synced 2026-11-09 17:47:19 +00:00
* fix mingw build and crashing bugs for Python Windows ARM64 * Fix issues found in PR review
506 lines
12 KiB
ArmAsm
506 lines
12 KiB
ArmAsm
/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
a copy of this software and associated documentation files (the
|
|
``Software''), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
the following conditions:
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
|
|
#define LIBFFI_ASM
|
|
#include <fficonfig.h>
|
|
#include <ffi.h>
|
|
#include <ffi_cfi.h>
|
|
#include "internal.h"
|
|
|
|
OPT 2 /*disable listing */
|
|
/* For some macros to add unwind information */
|
|
#include "ksarm64.h"
|
|
OPT 1 /*re-enable listing */
|
|
|
|
#define BE(X) 0
|
|
#define PTR_REG(n) x##n
|
|
#define PTR_SIZE 8
|
|
|
|
IMPORT ffi_closure_SYSV_inner
|
|
EXPORT ffi_call_SYSV
|
|
EXPORT ffi_closure_SYSV_V
|
|
EXPORT ffi_closure_SYSV
|
|
EXPORT extend_hfa_type
|
|
EXPORT compress_hfa_type
|
|
#ifdef FFI_GO_CLOSURES
|
|
EXPORT ffi_go_closure_SYSV_V
|
|
EXPORT ffi_go_closure_SYSV
|
|
#endif
|
|
|
|
TEXTAREA, ALLIGN=8
|
|
|
|
/* ffi_call_SYSV
|
|
extern void ffi_call_SYSV (void *stack, void *frame,
|
|
void (*fn)(void), void *rvalue,
|
|
int flags, void *closure);
|
|
Therefore on entry we have:
|
|
x0 stack
|
|
x1 frame
|
|
x2 fn
|
|
x3 rvalue
|
|
x4 flags
|
|
x5 closure
|
|
*/
|
|
|
|
NESTED_ENTRY ffi_call_SYSV_fake
|
|
|
|
/* For unwind information, Windows has to store fp and lr */
|
|
PROLOG_SAVE_REG_PAIR x29, x30, #-32!
|
|
|
|
ALTERNATE_ENTRY ffi_call_SYSV
|
|
/* Use a stack frame allocated by our caller. */
|
|
stp x29, x30, [x1]
|
|
mov x29, x1
|
|
mov sp, x0
|
|
|
|
mov x9, x2 /* save fn */
|
|
mov x8, x3 /* install structure return */
|
|
#ifdef FFI_GO_CLOSURES
|
|
/*mov x18, x5 install static chain */
|
|
#endif
|
|
stp x3, x4, [x29, #16] /* save rvalue and flags */
|
|
|
|
/* Load the vector argument passing registers, if necessary. */
|
|
tbz x4, #AARCH64_FLAG_ARG_V_BIT, ffi_call_SYSV_L1
|
|
ldp q0, q1, [sp, #0]
|
|
ldp q2, q3, [sp, #32]
|
|
ldp q4, q5, [sp, #64]
|
|
ldp q6, q7, [sp, #96]
|
|
|
|
ffi_call_SYSV_L1
|
|
/* Load the core argument passing registers, including
|
|
the structure return pointer. */
|
|
ldp x0, x1, [sp, #16*N_V_ARG_REG + 0]
|
|
ldp x2, x3, [sp, #16*N_V_ARG_REG + 16]
|
|
ldp x4, x5, [sp, #16*N_V_ARG_REG + 32]
|
|
ldp x6, x7, [sp, #16*N_V_ARG_REG + 48]
|
|
|
|
/* Deallocate the context, leaving the stacked arguments. */
|
|
add sp, sp, #CALL_CONTEXT_SIZE
|
|
|
|
blr x9 /* call fn */
|
|
|
|
ldp x3, x4, [x29, #16] /* reload rvalue and flags */
|
|
|
|
/* Partially deconstruct the stack frame. */
|
|
mov sp, x29
|
|
ldp x29, x30, [x29]
|
|
|
|
/* Save the return value as directed. */
|
|
adr x5, ffi_call_SYSV_return
|
|
and w4, w4, #AARCH64_RET_MASK
|
|
add x5, x5, x4, lsl #3
|
|
br x5
|
|
|
|
/* Note that each table entry is 2 insns, and thus 8 bytes.
|
|
For integer data, note that we're storing into ffi_arg
|
|
and therefore we want to extend to 64 bits; these types
|
|
have two consecutive entries allocated for them. */
|
|
ALIGN 4
|
|
ffi_call_SYSV_return
|
|
ret /* VOID */
|
|
nop
|
|
str x0, [x3] /* INT64 */
|
|
ret
|
|
stp x0, x1, [x3] /* INT128 */
|
|
ret
|
|
brk #1000 /* UNUSED */
|
|
ret
|
|
brk #1000 /* UNUSED */
|
|
ret
|
|
brk #1000 /* UNUSED */
|
|
ret
|
|
brk #1000 /* UNUSED */
|
|
ret
|
|
brk #1000 /* UNUSED */
|
|
ret
|
|
st4 { v0.s, v1.s, v2.s, v3.s }[0], [x3] /* S4 */
|
|
ret
|
|
st3 { v0.s, v1.s, v2.s }[0], [x3] /* S3 */
|
|
ret
|
|
stp s0, s1, [x3] /* S2 */
|
|
ret
|
|
str s0, [x3] /* S1 */
|
|
ret
|
|
st4 { v0.d, v1.d, v2.d, v3.d }[0], [x3] /* D4 */
|
|
ret
|
|
st3 { v0.d, v1.d, v2.d }[0], [x3] /* D3 */
|
|
ret
|
|
stp d0, d1, [x3] /* D2 */
|
|
ret
|
|
str d0, [x3] /* D1 */
|
|
ret
|
|
str q3, [x3, #48] /* Q4 */
|
|
nop
|
|
str q2, [x3, #32] /* Q3 */
|
|
nop
|
|
stp q0, q1, [x3] /* Q2 */
|
|
ret
|
|
str q0, [x3] /* Q1 */
|
|
ret
|
|
uxtb w0, w0 /* UINT8 */
|
|
str x0, [x3]
|
|
ret /* reserved */
|
|
nop
|
|
uxth w0, w0 /* UINT16 */
|
|
str x0, [x3]
|
|
ret /* reserved */
|
|
nop
|
|
mov w0, w0 /* UINT32 */
|
|
str x0, [x3]
|
|
ret /* reserved */
|
|
nop
|
|
sxtb x0, w0 /* SINT8 */
|
|
str x0, [x3]
|
|
ret /* reserved */
|
|
nop
|
|
sxth x0, w0 /* SINT16 */
|
|
str x0, [x3]
|
|
ret /* reserved */
|
|
nop
|
|
sxtw x0, w0 /* SINT32 */
|
|
str x0, [x3]
|
|
ret /* reserved */
|
|
nop
|
|
|
|
|
|
NESTED_END ffi_call_SYSV_fake
|
|
|
|
|
|
/* ffi_closure_SYSV
|
|
Closure invocation glue. This is the low level code invoked directly by
|
|
the closure trampoline to setup and call a closure.
|
|
On entry x17 points to a struct ffi_closure, x16 has been clobbered
|
|
all other registers are preserved.
|
|
We allocate a call context and save the argument passing registers,
|
|
then invoked the generic C ffi_closure_SYSV_inner() function to do all
|
|
the real work, on return we load the result passing registers back from
|
|
the call context.
|
|
*/
|
|
|
|
#define ffi_closure_SYSV_FS (8*2 + CALL_CONTEXT_SIZE + 64)
|
|
|
|
NESTED_ENTRY ffi_closure_SYSV_V
|
|
PROLOG_SAVE_REG_PAIR x29, x30, #-ffi_closure_SYSV_FS!
|
|
|
|
/* Save the argument passing vector registers. */
|
|
stp q0, q1, [sp, #16 + 0]
|
|
stp q2, q3, [sp, #16 + 32]
|
|
stp q4, q5, [sp, #16 + 64]
|
|
stp q6, q7, [sp, #16 + 96]
|
|
|
|
b ffi_closure_SYSV_save_argument
|
|
NESTED_END ffi_closure_SYSV_V
|
|
|
|
NESTED_ENTRY ffi_closure_SYSV
|
|
PROLOG_SAVE_REG_PAIR x29, x30, #-ffi_closure_SYSV_FS!
|
|
|
|
ffi_closure_SYSV_save_argument
|
|
/* Save the argument passing core registers. */
|
|
stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
|
|
stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
|
|
stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
|
|
stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
|
|
|
|
/* Load ffi_closure_inner arguments. */
|
|
ldp PTR_REG(0), PTR_REG(1), [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET] /* load cif, fn */
|
|
ldr PTR_REG(2), [x17, #FFI_TRAMPOLINE_CLOSURE_OFFSET+PTR_SIZE*2] /* load user_data */
|
|
|
|
do_closure
|
|
add x3, sp, #16 /* load context */
|
|
add x4, sp, #ffi_closure_SYSV_FS /* load stack */
|
|
add x5, sp, #16+CALL_CONTEXT_SIZE /* load rvalue */
|
|
mov x6, x8 /* load struct_rval */
|
|
|
|
bl ffi_closure_SYSV_inner
|
|
|
|
/* Load the return value as directed. */
|
|
adr x1, ffi_closure_SYSV_return_base
|
|
and w0, w0, #AARCH64_RET_MASK
|
|
add x1, x1, x0, lsl #3
|
|
add x3, sp, #16+CALL_CONTEXT_SIZE
|
|
br x1
|
|
|
|
/* Note that each table entry is 2 insns, and thus 8 bytes. */
|
|
ALIGN 8
|
|
ffi_closure_SYSV_return_base
|
|
b ffi_closure_SYSV_epilog /* VOID */
|
|
nop
|
|
ldr x0, [x3] /* INT64 */
|
|
b ffi_closure_SYSV_epilog
|
|
ldp x0, x1, [x3] /* INT128 */
|
|
b ffi_closure_SYSV_epilog
|
|
brk #1000 /* UNUSED */
|
|
nop
|
|
brk #1000 /* UNUSED */
|
|
nop
|
|
brk #1000 /* UNUSED */
|
|
nop
|
|
brk #1000 /* UNUSED */
|
|
nop
|
|
brk #1000 /* UNUSED */
|
|
nop
|
|
ldr s3, [x3, #12] /* S4 */
|
|
nop
|
|
ldr s2, [x3, #8] /* S3 */
|
|
nop
|
|
ldp s0, s1, [x3] /* S2 */
|
|
b ffi_closure_SYSV_epilog
|
|
ldr s0, [x3] /* S1 */
|
|
b ffi_closure_SYSV_epilog
|
|
ldr d3, [x3, #24] /* D4 */
|
|
nop
|
|
ldr d2, [x3, #16] /* D3 */
|
|
nop
|
|
ldp d0, d1, [x3] /* D2 */
|
|
b ffi_closure_SYSV_epilog
|
|
ldr d0, [x3] /* D1 */
|
|
b ffi_closure_SYSV_epilog
|
|
ldr q3, [x3, #48] /* Q4 */
|
|
nop
|
|
ldr q2, [x3, #32] /* Q3 */
|
|
nop
|
|
ldp q0, q1, [x3] /* Q2 */
|
|
b ffi_closure_SYSV_epilog
|
|
ldr q0, [x3] /* Q1 */
|
|
b ffi_closure_SYSV_epilog
|
|
ldrb w0, [x3, #BE(7)] /* UINT8 */
|
|
b ffi_closure_SYSV_epilog
|
|
brk #1000 /* reserved */
|
|
nop
|
|
ldrh w0, [x3, #BE(6)] /* UINT16 */
|
|
b ffi_closure_SYSV_epilog
|
|
brk #1000 /* reserved */
|
|
nop
|
|
ldr w0, [x3, #BE(4)] /* UINT32 */
|
|
b ffi_closure_SYSV_epilog
|
|
brk #1000 /* reserved */
|
|
nop
|
|
ldrsb x0, [x3, #BE(7)] /* SINT8 */
|
|
b ffi_closure_SYSV_epilog
|
|
brk #1000 /* reserved */
|
|
nop
|
|
ldrsh x0, [x3, #BE(6)] /* SINT16 */
|
|
b ffi_closure_SYSV_epilog
|
|
brk #1000 /* reserved */
|
|
nop
|
|
ldrsw x0, [x3, #BE(4)] /* SINT32 */
|
|
nop
|
|
/* reserved */
|
|
|
|
ffi_closure_SYSV_epilog
|
|
EPILOG_RESTORE_REG_PAIR x29, x30, #ffi_closure_SYSV_FS!
|
|
EPILOG_RETURN
|
|
NESTED_END ffi_closure_SYSV
|
|
|
|
|
|
#ifdef FFI_GO_CLOSURES
|
|
NESTED_ENTRY ffi_go_closure_SYSV_V
|
|
PROLOG_SAVE_REG_PAIR x29, x30, #-ffi_closure_SYSV_FS!
|
|
|
|
/* Save the argument passing vector registers. */
|
|
stp q0, q1, [sp, #16 + 0]
|
|
stp q2, q3, [sp, #16 + 32]
|
|
stp q4, q5, [sp, #16 + 64]
|
|
stp q6, q7, [sp, #16 + 96]
|
|
b ffi_go_closure_SYSV_save_argument
|
|
NESTED_END ffi_go_closure_SYSV_V
|
|
|
|
NESTED_ENTRY ffi_go_closure_SYSV
|
|
PROLOG_SAVE_REG_PAIR x29, x30, #-ffi_closure_SYSV_FS!
|
|
|
|
ffi_go_closure_SYSV_save_argument
|
|
/* Save the argument passing core registers. */
|
|
stp x0, x1, [sp, #16 + 16*N_V_ARG_REG + 0]
|
|
stp x2, x3, [sp, #16 + 16*N_V_ARG_REG + 16]
|
|
stp x4, x5, [sp, #16 + 16*N_V_ARG_REG + 32]
|
|
stp x6, x7, [sp, #16 + 16*N_V_ARG_REG + 48]
|
|
|
|
/* Load ffi_closure_inner arguments. */
|
|
ldp PTR_REG(0), PTR_REG(1), [x18, #PTR_SIZE]/* load cif, fn */
|
|
mov x2, x18 /* load user_data */
|
|
b do_closure
|
|
NESTED_END ffi_go_closure_SYSV
|
|
|
|
#endif /* FFI_GO_CLOSURES */
|
|
|
|
|
|
/* void extend_hfa_type (void *dest, void *src, int h) */
|
|
|
|
LEAF_ENTRY extend_hfa_type
|
|
|
|
adr x3, extend_hfa_type_jump_base
|
|
and w2, w2, #AARCH64_RET_MASK
|
|
sub x2, x2, #AARCH64_RET_S4
|
|
add x3, x3, x2, lsl #4
|
|
br x3
|
|
|
|
ALIGN 4
|
|
extend_hfa_type_jump_base
|
|
ldp s16, s17, [x1] /* S4 */
|
|
ldp s18, s19, [x1, #8]
|
|
b extend_hfa_type_store_4
|
|
nop
|
|
|
|
ldp s16, s17, [x1] /* S3 */
|
|
ldr s18, [x1, #8]
|
|
b extend_hfa_type_store_3
|
|
nop
|
|
|
|
ldp s16, s17, [x1] /* S2 */
|
|
b extend_hfa_type_store_2
|
|
nop
|
|
nop
|
|
|
|
ldr s16, [x1] /* S1 */
|
|
b extend_hfa_type_store_1
|
|
nop
|
|
nop
|
|
|
|
ldp d16, d17, [x1] /* D4 */
|
|
ldp d18, d19, [x1, #16]
|
|
b extend_hfa_type_store_4
|
|
nop
|
|
|
|
ldp d16, d17, [x1] /* D3 */
|
|
ldr d18, [x1, #16]
|
|
b extend_hfa_type_store_3
|
|
nop
|
|
|
|
ldp d16, d17, [x1] /* D2 */
|
|
b extend_hfa_type_store_2
|
|
nop
|
|
nop
|
|
|
|
ldr d16, [x1] /* D1 */
|
|
b extend_hfa_type_store_1
|
|
nop
|
|
nop
|
|
|
|
ldp q16, q17, [x1] /* Q4 */
|
|
ldp q18, q19, [x1, #16]
|
|
b extend_hfa_type_store_4
|
|
nop
|
|
|
|
ldp q16, q17, [x1] /* Q3 */
|
|
ldr q18, [x1, #16]
|
|
b extend_hfa_type_store_3
|
|
nop
|
|
|
|
ldp q16, q17, [x1] /* Q2 */
|
|
b extend_hfa_type_store_2
|
|
nop
|
|
nop
|
|
|
|
ldr q16, [x1] /* Q1 */
|
|
b extend_hfa_type_store_1
|
|
|
|
extend_hfa_type_store_4
|
|
str q19, [x0, #48]
|
|
extend_hfa_type_store_3
|
|
str q18, [x0, #32]
|
|
extend_hfa_type_store_2
|
|
str q17, [x0, #16]
|
|
extend_hfa_type_store_1
|
|
str q16, [x0]
|
|
ret
|
|
|
|
LEAF_END extend_hfa_type
|
|
|
|
|
|
/* void compress_hfa_type (void *dest, void *reg, int h) */
|
|
|
|
LEAF_ENTRY compress_hfa_type
|
|
|
|
adr x3, compress_hfa_type_jump_base
|
|
and w2, w2, #AARCH64_RET_MASK
|
|
sub x2, x2, #AARCH64_RET_S4
|
|
add x3, x3, x2, lsl #4
|
|
br x3
|
|
|
|
ALIGN 4
|
|
compress_hfa_type_jump_base
|
|
ldp q16, q17, [x1] /* S4 */
|
|
ldp q18, q19, [x1, #32]
|
|
st4 { v16.s, v17.s, v18.s, v19.s }[0], [x0]
|
|
ret
|
|
|
|
ldp q16, q17, [x1] /* S3 */
|
|
ldr q18, [x1, #32]
|
|
st3 { v16.s, v17.s, v18.s }[0], [x0]
|
|
ret
|
|
|
|
ldp q16, q17, [x1] /* S2 */
|
|
st2 { v16.s, v17.s }[0], [x0]
|
|
ret
|
|
nop
|
|
|
|
ldr q16, [x1] /* S1 */
|
|
st1 { v16.s }[0], [x0]
|
|
ret
|
|
nop
|
|
|
|
ldp q16, q17, [x1] /* D4 */
|
|
ldp q18, q19, [x1, #32]
|
|
st4 { v16.d, v17.d, v18.d, v19.d }[0], [x0]
|
|
ret
|
|
|
|
ldp q16, q17, [x1] /* D3 */
|
|
ldr q18, [x1, #32]
|
|
st3 { v16.d, v17.d, v18.d }[0], [x0]
|
|
ret
|
|
|
|
ldp q16, q17, [x1] /* D2 */
|
|
st2 { v16.d, v17.d }[0], [x0]
|
|
ret
|
|
nop
|
|
|
|
ldr q16, [x1] /* D1 */
|
|
st1 { v16.d }[0], [x0]
|
|
ret
|
|
nop
|
|
|
|
ldp q16, q17, [x1] /* Q4 */
|
|
ldp q18, q19, [x1, #32]
|
|
b compress_hfa_type_store_q4
|
|
nop
|
|
|
|
ldp q16, q17, [x1] /* Q3 */
|
|
ldr q18, [x1, #32]
|
|
b compress_hfa_type_store_q3
|
|
nop
|
|
|
|
ldp q16, q17, [x1] /* Q2 */
|
|
stp q16, q17, [x0]
|
|
ret
|
|
nop
|
|
|
|
ldr q16, [x1] /* Q1 */
|
|
str q16, [x0]
|
|
ret
|
|
|
|
compress_hfa_type_store_q4
|
|
str q19, [x0, #48]
|
|
compress_hfa_type_store_q3
|
|
str q18, [x0, #32]
|
|
stp q16, q17, [x0]
|
|
ret
|
|
|
|
LEAF_END compress_hfa_type
|
|
|
|
END |