--- libffi/src/aarch64/ffi.c | 42 ++++++++++++++++++++++++++--- libffi/src/aarch64/ffitarget.h | 3 ++- libffi/src/aarch64/sysv.S | 60 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 99 insertions(+), 6 deletions(-)
diff --git a/libffi/src/aarch64/ffi.c b/libffi/src/aarch64/ffi.c index c409c0c..1fe5a60 100644 --- a/libffi/src/aarch64/ffi.c +++ b/libffi/src/aarch64/ffi.c @@ -72,10 +72,13 @@ get_d_addr (struct call_context *context, unsigned n) extern void ffi_call_SYSV (void *frame, void *rvalue, struct call_context *context, - unsigned flags, void (*fn)(void)) FFI_HIDDEN; + unsigned flags, void (*fn)(void), + void *static_chain) FFI_HIDDEN; extern void ffi_closure_SYSV (void) FFI_HIDDEN; extern void ffi_closure_SYSV_V (void) FFI_HIDDEN; +extern void ffi_go_closure_SYSV (void) FFI_HIDDEN; +extern void ffi_go_closure_SYSV_V (void) FFI_HIDDEN; /* A subroutine of is_hfa. Given a structure type, return the type code of the first non-structure element. Recurse for structure elements. @@ -336,8 +339,9 @@ ffi_prep_cif_machdep (ffi_cif *cif) /* Call a function with the provided arguments and capture the return value. */ -void -ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +static void +ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) { struct call_context *context; UINT64 *stack, *slot; @@ -533,11 +537,24 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) } size = cif->rtype->size; - ffi_call_SYSV (frame, local_rvalue, context, cif->flags, fn); + ffi_call_SYSV (frame, local_rvalue, context, cif->flags, fn, closure); if (local_rvalue != rvalue && rvalue != NULL) memcpy (rvalue, local_rvalue, size); } +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + ffi_call_int (cif, fn, rvalue, avalue, NULL); +} + +void +ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, + void **avalue, void *closure) +{ + ffi_call_int (cif, fn, rvalue, avalue, closure); +} + /* Build a trampoline. */ ffi_status @@ -574,6 +591,23 @@ ffi_prep_closure_loc (ffi_closure* closure, return FFI_OK; } +/* Build a Go language closure. */ + +ffi_status +ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*)) +{ + if (cif->abi != FFI_SYSV) + return FFI_BAD_ABI; + + closure->tramp = (cif->flags & AARCH64_FLAG_ARG_V + ? ffi_go_closure_SYSV_V : ffi_go_closure_SYSV); + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; +} + /* Primary handler to setup and invoke a function within a closure. A closure when invoked enters via the assembler wrapper diff --git a/libffi/src/aarch64/ffitarget.h b/libffi/src/aarch64/ffitarget.h index ecfa159..bb7340b 100644 --- a/libffi/src/aarch64/ffitarget.h +++ b/libffi/src/aarch64/ffitarget.h @@ -42,7 +42,8 @@ typedef enum ffi_abi /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 -#define FFI_TRAMPOLINE_SIZE 24 +#define FFI_GO_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 24 #define FFI_NATIVE_RAW_API 0 #endif diff --git a/libffi/src/aarch64/sysv.S b/libffi/src/aarch64/sysv.S index 126c527..0544176 100644 --- a/libffi/src/aarch64/sysv.S +++ b/libffi/src/aarch64/sysv.S @@ -35,7 +35,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ extern void ffi_call_SYSV (void *frame, void *rvalue, struct call_context *context, - unsigned flags, void (*fn)(void)) + unsigned flags, void (*fn)(void), void *static_chain) This function uses an unusual stack layout. Our local frame has been allocated by the caller in FRAME with the outgoing arguments @@ -60,6 +60,7 @@ ffi_call_SYSV: mov x8, x1 /* rvalue into place */ mov x10, x2 /* context */ mov x11, x4 /* fn */ + mov x18, x5 /* static chain into place */ /* Load the vector argument passing registers, if needed. */ tbz w3, #AARCH64_FLAG_ARG_V_BIT, 1f @@ -304,3 +305,60 @@ ffi_closure_SYSV: ret .cfi_endproc .size ffi_closure_SYSV, .-ffi_closure_SYSV + +/* ffi_go_closure_SYSV + + Similarly for a Go closure. The difference here is that the + calling convention loads x18 with the ffi_go_closure structure + automatically. Further, the ffi_go_closure is also the user_data + that want passed to the inner function. +*/ + + .globl ffi_go_closure_SYSV_V + .hidden ffi_go_closure_SYSV_V + .type ffi_go_closure_SYSV_V, %function + .balign 32 + +ffi_go_closure_SYSV_V: + .cfi_startproc + stp x29, x30, [sp, #-ffi_closure_FS]! + .cfi_adjust_cfa_offset ffi_closure_FS + .cfi_rel_offset x29, 0 + .cfi_rel_offset x30, 8 + mov x29, sp + + /* Save the argument passing vector registers. */ + stp q0, q1, [sp, #16 + 8*AARCH64_N_XREG + 0] + stp q2, q3, [sp, #16 + 8*AARCH64_N_XREG + 32] + stp q4, q5, [sp, #16 + 8*AARCH64_N_XREG + 64] + stp q6, q7, [sp, #16 + 8*AARCH64_N_XREG + 96] + b 0f + + .cfi_endproc + .size ffi_go_closure_SYSV_V, . - ffi_go_closure_SYSV_V + + .globl ffi_go_closure_SYSV + .hidden ffi_go_closure_SYSV + .type ffi_go_closure_SYSV, %function + .balign 32 + +ffi_go_closure_SYSV: + .cfi_startproc + stp x29, x30, [sp, #-ffi_closure_FS]! + .cfi_adjust_cfa_offset ffi_closure_FS + .cfi_rel_offset x29, 0 + .cfi_rel_offset x30, 8 + mov x29, sp + + /* Save the argument passing core registers. */ +0: stp x0, x1, [sp, #16 + 0] + stp x2, x3, [sp, #16 + 16] + stp x4, x5, [sp, #16 + 32] + stp x6, x7, [sp, #16 + 48] + + ldp x0, x1, [x18, #8] /* cif and fun */ + mov x2, x18 /* user_data */ + b .Ldo_closure + + .cfi_endproc + .size ffi_go_closure_SYSV, . - ffi_go_closure_SYSV -- 1.9.3