diff options
author | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-16 18:49:26 +0900 |
---|---|---|
committer | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-30 00:39:06 +0900 |
commit | fcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch) | |
tree | 64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/ext/fiddle/libffi-3.2.1/src/metag |
Fresh start
Diffstat (limited to 'jni/ruby/ext/fiddle/libffi-3.2.1/src/metag')
-rw-r--r-- | jni/ruby/ext/fiddle/libffi-3.2.1/src/metag/ffi.c | 330 | ||||
-rw-r--r-- | jni/ruby/ext/fiddle/libffi-3.2.1/src/metag/ffitarget.h | 53 | ||||
-rw-r--r-- | jni/ruby/ext/fiddle/libffi-3.2.1/src/metag/sysv.S | 311 |
3 files changed, 694 insertions, 0 deletions
diff --git a/jni/ruby/ext/fiddle/libffi-3.2.1/src/metag/ffi.c b/jni/ruby/ext/fiddle/libffi-3.2.1/src/metag/ffi.c new file mode 100644 index 0000000..46b383e --- /dev/null +++ b/jni/ruby/ext/fiddle/libffi-3.2.1/src/metag/ffi.c @@ -0,0 +1,330 @@ +/* ---------------------------------------------------------------------- + ffi.c - Copyright (c) 2013 Imagination Technologies + + Meta Foreign Function Interface + 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 SIMON POSNJAK 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. +----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +/* + * ffi_prep_args is called by the assembly routine once stack space has been + * allocated for the function's arguments + */ + +unsigned int ffi_prep_args(char *stack, extended_cif *ecif) +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + /* Store return value */ + if ( ecif->cif->flags == FFI_TYPE_STRUCT ) { + argp -= 4; + *(void **) argp = ecif->rvalue; + } + + p_argv = ecif->avalue; + + /* point to next location */ + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++, p_argv++) + { + size_t z; + + /* Move argp to address of argument */ + z = (*p_arg)->size; + argp -= z; + + /* Align if necessary */ + argp = (char *) ALIGN_DOWN(ALIGN_DOWN(argp, (*p_arg)->alignment), 4); + + if (z < sizeof(int)) { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + case FFI_TYPE_STRUCT: + memcpy(argp, *p_argv, (*p_arg)->size); + break; + default: + FFI_ASSERT(0); + } + } else if ( z == sizeof(int)) { + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + } else { + memcpy(argp, *p_argv, z); + } + } + + /* return the size of the arguments to be passed in registers, + padded to an 8 byte boundary to preserve stack alignment */ + return ALIGN(MIN(stack - argp, 6*4), 8); +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + ffi_type **ptr; + unsigned i, bytes = 0; + + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) { + if ((*ptr)->size == 0) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the argument type, do this + check after the initialization. */ + FFI_ASSERT_VALID_TYPE(*ptr); + + /* Add any padding if necessary */ + if (((*ptr)->alignment - 1) & bytes) + bytes = ALIGN(bytes, (*ptr)->alignment); + + bytes += ALIGN((*ptr)->size, 4); + } + + /* Ensure arg space is aligned to an 8-byte boundary */ + bytes = ALIGN(bytes, 8); + + /* Make space for the return structure pointer */ + if (cif->rtype->type == FFI_TYPE_STRUCT) { + bytes += sizeof(void*); + + /* Ensure stack is aligned to an 8-byte boundary */ + bytes = ALIGN(bytes, 8); + } + + cif->bytes = bytes; + + /* Set the return type flag */ + switch (cif->rtype->type) { + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = (unsigned) FFI_TYPE_SINT64; + break; + case FFI_TYPE_STRUCT: + /* Meta can store return values which are <= 64 bits */ + if (cif->rtype->size <= 4) + /* Returned to D0Re0 as 32-bit value */ + cif->flags = (unsigned)FFI_TYPE_INT; + else if ((cif->rtype->size > 4) && (cif->rtype->size <= 8)) + /* Returned valued is stored to D1Re0|R0Re0 */ + cif->flags = (unsigned)FFI_TYPE_DOUBLE; + else + /* value stored in memory */ + cif->flags = (unsigned)FFI_TYPE_STRUCT; + break; + default: + cif->flags = (unsigned)FFI_TYPE_INT; + break; + } + return FFI_OK; +} + +extern void ffi_call_SYSV(void (*fn)(void), extended_cif *, unsigned, unsigned, double *); + +/* + * Exported in API. Entry point + * cif -> ffi_cif object + * fn -> function pointer + * rvalue -> pointer to return value + * avalue -> vector of void * pointers pointing to memory locations holding the + * arguments + */ +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + + int small_struct = (((cif->flags == FFI_TYPE_INT) || (cif->flags == FFI_TYPE_DOUBLE)) && (cif->rtype->type == FFI_TYPE_STRUCT)); + ecif.cif = cif; + ecif.avalue = avalue; + + double temp; + + /* + * If the return value is a struct and we don't have a return value address + * then we need to make one + */ + + if ((rvalue == NULL ) && (cif->flags == FFI_TYPE_STRUCT)) + ecif.rvalue = alloca(cif->rtype->size); + else if (small_struct) + ecif.rvalue = &temp; + else + ecif.rvalue = rvalue; + + switch (cif->abi) { + case FFI_SYSV: + ffi_call_SYSV(fn, &ecif, cif->bytes, cif->flags, ecif.rvalue); + break; + default: + FFI_ASSERT(0); + break; + } + + if (small_struct) + memcpy (rvalue, &temp, cif->rtype->size); +} + +/* private members */ + +static void ffi_prep_incoming_args_SYSV (char *, void **, void **, + ffi_cif*, float *); + +void ffi_closure_SYSV (ffi_closure *); + +/* Do NOT change that without changing the FFI_TRAMPOLINE_SIZE */ +extern unsigned int ffi_metag_trampoline[10]; /* 10 instructions */ + +/* end of private members */ + +/* + * __tramp: trampoline memory location + * __fun: assembly routine + * __ctx: memory location for wrapper + * + * At this point, tramp[0] == __ctx ! + */ +void ffi_init_trampoline(unsigned char *__tramp, unsigned int __fun, unsigned int __ctx) { + memcpy (__tramp, ffi_metag_trampoline, sizeof(ffi_metag_trampoline)); + *(unsigned int*) &__tramp[40] = __ctx; + *(unsigned int*) &__tramp[44] = __fun; + /* This will flush the instruction cache */ + __builtin_meta2_cachewd(&__tramp[0], 1); + __builtin_meta2_cachewd(&__tramp[47], 1); +} + + + +/* the cif must already be prepared */ + +ffi_status +ffi_prep_closure_loc (ffi_closure *closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ + void (*closure_func)(ffi_closure*) = NULL; + + if (cif->abi == FFI_SYSV) + closure_func = &ffi_closure_SYSV; + else + return FFI_BAD_ABI; + + ffi_init_trampoline( + (unsigned char*)&closure->tramp[0], + (unsigned int)closure_func, + (unsigned int)codeloc); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + + +/* This function is jumped to by the trampoline */ +unsigned int ffi_closure_SYSV_inner (closure, respp, args, vfp_args) + ffi_closure *closure; + void **respp; + void *args; + void *vfp_args; +{ + ffi_cif *cif; + void **arg_area; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + + /* + * This call will initialize ARG_AREA, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will re-set RESP to point to the + * structure return address. + */ + ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args); + + (closure->fun) ( cif, *respp, arg_area, closure->user_data); + + return cif->flags; +} + +static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, + void **avalue, ffi_cif *cif, + float *vfp_stack) +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + /* stack points to original arguments */ + argp = stack; + + /* Store return value */ + if ( cif->flags == FFI_TYPE_STRUCT ) { + argp -= 4; + *rvalue = *(void **) argp; + } + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) { + size_t z; + size_t alignment; + + alignment = (*p_arg)->alignment; + if (alignment < 4) + alignment = 4; + if ((alignment - 1) & (unsigned)argp) + argp = (char *) ALIGN(argp, alignment); + + z = (*p_arg)->size; + *p_argv = (void*) argp; + p_argv++; + argp -= z; + } + return; +} diff --git a/jni/ruby/ext/fiddle/libffi-3.2.1/src/metag/ffitarget.h b/jni/ruby/ext/fiddle/libffi-3.2.1/src/metag/ffitarget.h new file mode 100644 index 0000000..7b9dbeb --- /dev/null +++ b/jni/ruby/ext/fiddle/libffi-3.2.1/src/metag/ffitarget.h @@ -0,0 +1,53 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 2013 Imagination Technologies Ltd. + Target configuration macros for Meta + + 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. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_H +#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." +#endif + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_DEFAULT_ABI = FFI_SYSV, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1, +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 48 +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/jni/ruby/ext/fiddle/libffi-3.2.1/src/metag/sysv.S b/jni/ruby/ext/fiddle/libffi-3.2.1/src/metag/sysv.S new file mode 100644 index 0000000..b4b2a3b --- /dev/null +++ b/jni/ruby/ext/fiddle/libffi-3.2.1/src/metag/sysv.S @@ -0,0 +1,311 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2013 Imagination Technologies Ltd. + + Meta Foreign Function Interface + + 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> +#ifdef HAVE_MACHINE_ASM_H +#include <machine/asm.h> +#else +#ifdef __USER_LABEL_PREFIX__ +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ +#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) +#else +#define CNAME(x) x +#endif +#define ENTRY(x) .globl CNAME(x); .type CNAME(x), %function; CNAME(x): +#endif + +#ifdef __ELF__ +#define LSYM(x) .x +#else +#define LSYM(x) x +#endif + +.macro call_reg x= + .text + .balign 4 + mov D1RtP, \x + swap D1RtP, PC +.endm + +! Save register arguments +.macro SAVE_ARGS + .text + .balign 4 + setl [A0StP++], D0Ar6, D1Ar5 + setl [A0StP++], D0Ar4, D1Ar3 + setl [A0StP++], D0Ar2, D1Ar1 +.endm + +! Save retrun, frame pointer and other regs +.macro SAVE_REGS regs= + .text + .balign 4 + setl [A0StP++], D0FrT, D1RtP + ! Needs to be a pair of regs + .ifnc "\regs","" + setl [A0StP++], \regs + .endif +.endm + +! Declare a global function +.macro METAG_FUNC_START name + .text + .balign 4 + ENTRY(\name) +.endm + +! Return registers from the stack. Reverse SAVE_REGS operation +.macro RET_REGS regs=, cond= + .ifnc "\regs", "" + getl \regs, [--A0StP] + .endif + getl D0FrT, D1RtP, [--A0StP] +.endm + +! Return arguments +.macro RET_ARGS + getl D0Ar2, D1Ar1, [--A0StP] + getl D0Ar4, D1Ar3, [--A0StP] + getl D0Ar6, D1Ar5, [--A0StP] +.endm + + + ! D1Ar1: fn + ! D0Ar2: &ecif + ! D1Ar3: cif->bytes + ! D0Ar4: fig->flags + ! D1Ar5: ecif.rvalue + + ! This assumes we are using GNU as +METAG_FUNC_START ffi_call_SYSV + ! Save argument registers + + SAVE_ARGS + + ! new frame + mov D0FrT, A0FrP + add A0FrP, A0StP, #0 + + ! Preserve the old frame pointer + SAVE_REGS "D1.5, D0.5" + + ! Make room for new args. cifs->bytes is the total space for input + ! and return arguments + + add A0StP, A0StP, D1Ar3 + + ! Preserve cifs->bytes & fn + mov D0.5, D1Ar3 + mov D1.5, D1Ar1 + + ! Place all of the ffi_prep_args in position + mov D1Ar1, A0StP + + ! Call ffi_prep_args(stack, &ecif) +#ifdef __PIC__ + callr D1RtP, CNAME(ffi_prep_args@PLT) +#else + callr D1RtP, CNAME(ffi_prep_args) +#endif + + ! Restore fn pointer + + ! The foreign stack should look like this + ! XXXXX XXXXXX <--- stack pointer + ! FnArgN rvalue + ! FnArgN+2 FnArgN+1 + ! FnArgN+4 FnArgN+3 + ! .... + ! + + ! A0StP now points to the first (or return) argument + 4 + + ! Preserve cif->bytes + getl D0Ar2, D1Ar1, [--A0StP] + getl D0Ar4, D1Ar3, [--A0StP] + getl D0Ar6, D1Ar5, [--A0StP] + + ! Place A0StP to the first argument again + add A0StP, A0StP, #24 ! That's because we loaded 6 regs x 4 byte each + + ! A0FrP points to the initial stack without the reserved space for the + ! cifs->bytes, whilst A0StP points to the stack after the space allocation + + ! fn was the first argument of ffi_call_SYSV. + ! The stack at this point looks like this: + ! + ! A0StP(on entry to _SYSV) -> Arg6 Arg5 | low + ! Arg4 Arg3 | + ! Arg2 Arg1 | + ! A0FrP ----> D0FrtP D1RtP | + ! D1.5 D0.5 | + ! A0StP(bf prep_args) -> FnArgn FnArgn-1 | + ! FnArgn-2FnArgn-3 | + ! ................ | <= cifs->bytes + ! FnArg4 FnArg3 | + ! A0StP (prv_A0StP+cifs->bytes) FnArg2 FnArg1 | high + ! + ! fn was in Arg1 so it's located in in A0FrP+#-0xC + ! + + ! D0Re0 contains the size of arguments stored in registers + sub A0StP, A0StP, D0Re0 + + ! Arg1 is the function pointer for the foreign call. This has been + ! preserved in D1.5 + + ! Time to call (fn). Arguments should be like this: + ! Arg1-Arg6 are loaded to regs + ! The rest of the arguments are stored in stack pointed by A0StP + + call_reg D1.5 + + ! Reset stack. + + mov A0StP, A0FrP + + ! Load Arg1 with the pointer to storage for the return type + ! This was stored in Arg5 + + getd D1Ar1, [A0FrP+#-20] + + ! Load D0Ar2 with the return type code. This was stored in Arg4 (flags) + + getd D0Ar2, [A0FrP+#-16] + + ! We are ready to start processing the return value + ! D0Re0 (and D1Re0) hold the return value + + ! If the return value is NULL, assume no return value + cmp D1Ar1, #0 + beq LSYM(Lepilogue) + + ! return INT + cmp D0Ar2, #FFI_TYPE_INT + ! Sadly, there is no setd{cc} instruction so we need to workaround that + bne .INT64 + setd [D1Ar1], D0Re0 + b LSYM(Lepilogue) + + ! return INT64 +.INT64: + cmp D0Ar2, #FFI_TYPE_SINT64 + setleq [D1Ar1], D0Re0, D1Re0 + + ! return DOUBLE + cmp D0Ar2, #FFI_TYPE_DOUBLE + setl [D1AR1++], D0Re0, D1Re0 + +LSYM(Lepilogue): + ! At this point, the stack pointer points right after the argument + ! saved area. We need to restore 4 regs, therefore we need to move + ! 16 bytes ahead. + add A0StP, A0StP, #16 + RET_REGS "D1.5, D0.5" + RET_ARGS + getd D0Re0, [A0StP] + mov A0FrP, D0FrT + swap D1RtP, PC + +.ffi_call_SYSV_end: + .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) + + +/* + (called by ffi_metag_trampoline) + void ffi_closure_SYSV (ffi_closure*) + + (called by ffi_closure_SYSV) + unsigned int FFI_HIDDEN + ffi_closure_SYSV_inner (closure,respp, args) + ffi_closure *closure; + void **respp; + void *args; +*/ + +METAG_FUNC_START ffi_closure_SYSV + ! We assume that D1Ar1 holds the address of the + ! ffi_closure struct. We will use that to fetch the + ! arguments. The stack pointer points to an empty space + ! and it is ready to store more data. + + ! D1Ar1 is ready + ! Allocate stack space for return value + add A0StP, A0StP, #8 + ! Store it to D0Ar2 + sub D0Ar2, A0StP, #8 + + sub D1Ar3, A0FrP, #4 + + ! D1Ar3 contains the address of the original D1Ar1 argument + ! We need to subtract #4 later on + + ! Preverve D0Ar2 + mov D0.5, D0Ar2 + +#ifdef __PIC__ + callr D1RtP, CNAME(ffi_closure_SYSV_inner@PLT) +#else + callr D1RtP, CNAME(ffi_closure_SYSV_inner) +#endif + + ! Check the return value and store it to D0.5 + cmp D0Re0, #FFI_TYPE_INT + beq .Lretint + cmp D0Re0, #FFI_TYPE_DOUBLE + beq .Lretdouble +.Lclosure_epilogue: + sub A0StP, A0StP, #8 + RET_REGS "D1.5, D0.5" + RET_ARGS + swap D1RtP, PC + +.Lretint: + setd [D0.5], D0Re0 + b .Lclosure_epilogue +.Lretdouble: + setl [D0.5++], D0Re0, D1Re0 + b .Lclosure_epilogue +.ffi_closure_SYSV_end: +.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) + + +ENTRY(ffi_metag_trampoline) + SAVE_ARGS + ! New frame + mov A0FrP, A0StP + SAVE_REGS "D1.5, D0.5" + mov D0.5, PC + ! Load D1Ar1 the value of ffi_metag_trampoline + getd D1Ar1, [D0.5 + #8] + ! Jump to ffi_closure_SYSV + getd PC, [D0.5 + #12] |