diff options
Diffstat (limited to 'libffi/src/x86/ffi64.c')
-rw-r--r-- | libffi/src/x86/ffi64.c | 139 |
1 files changed, 136 insertions, 3 deletions
diff --git a/libffi/src/x86/ffi64.c b/libffi/src/x86/ffi64.c index f278a924eda..9427a37c8b5 100644 --- a/libffi/src/x86/ffi64.c +++ b/libffi/src/x86/ffi64.c @@ -27,6 +27,7 @@ #include <ffi_common.h> #include <stdlib.h> +#include <stdarg.h> /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments */ @@ -285,7 +286,8 @@ ffi_prep_args (stackLayout *stack, extended_cif *ecif) /* First check if the return value should be passed in memory. If so, pass the pointer as the first argument. */ gprcount = ssecount = 0; - if (examine_argument (ecif->cif->rtype, 1, &g, &s) == 0) + if (ecif->cif->rtype->type != FFI_TYPE_VOID + && examine_argument (ecif->cif->rtype, 1, &g, &s) == 0) (void *)stack->gpr[gprcount++] = ecif->rvalue; for (i=ecif->cif->nargs, p_arg=ecif->cif->arg_types, p_argv = ecif->avalue; @@ -389,8 +391,8 @@ ffi_prep_cif_machdep (ffi_cif *cif) /* If the return value should be passed in memory, pass the pointer as the first argument. The actual memory isn't allocated here. */ - - if (examine_argument (cif->rtype, 1, &g, &s) == 0) + if (cif->rtype->type != FFI_TYPE_VOID + && examine_argument (cif->rtype, 1, &g, &s) == 0) gprcount = 1; /* Go over all arguments and determine the way they should be passed. @@ -570,4 +572,135 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif, } } +extern void ffi_closure_UNIX64(void); + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data) +{ + volatile unsigned short *tramp; + + /* FFI_ASSERT (cif->abi == FFI_OSF); */ + + tramp = (volatile unsigned short *) &closure->tramp[0]; + tramp[0] = 0xbb49; /* mov <code>, %r11 */ + tramp[5] = 0xba49; /* mov <data>, %r10 */ + tramp[10] = 0xff49; /* jmp *%r11 */ + tramp[11] = 0x00e3; + *(void * volatile *) &tramp[1] = ffi_closure_UNIX64; + *(void * volatile *) &tramp[6] = closure; + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + +int +ffi_closure_UNIX64_inner(ffi_closure *closure, va_list l, void *rp) +{ + ffi_cif *cif; + void **avalue; + ffi_type **arg_types; + long i, avn, argn; + + cif = closure->cif; + avalue = alloca(cif->nargs * sizeof(void *)); + + argn = 0; + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + { + if (l->gp_offset > 48-8) + { + avalue[i] = l->overflow_arg_area; + l->overflow_arg_area = (char *)l->overflow_arg_area + 8; + } + else + { + avalue[i] = (char *)l->reg_save_area + l->gp_offset; + l->gp_offset += 8; + } + } + break; + + case FFI_TYPE_STRUCT: + /* FIXME */ + FFI_ASSERT(0); + break; + + case FFI_TYPE_DOUBLE: + { + if (l->fp_offset > 176-16) + { + avalue[i] = l->overflow_arg_area; + l->overflow_arg_area = (char *)l->overflow_arg_area + 8; + } + else + { + avalue[i] = (char *)l->reg_save_area + l->fp_offset; + l->fp_offset += 16; + } + } +#if DEBUG_FFI + fprintf (stderr, "double arg %d = %g\n", i, *(double *)avalue[i]); +#endif + break; + + case FFI_TYPE_FLOAT: + { + if (l->fp_offset > 176-16) + { + avalue[i] = l->overflow_arg_area; + l->overflow_arg_area = (char *)l->overflow_arg_area + 8; + } + else + { + avalue[i] = (char *)l->reg_save_area + l->fp_offset; + l->fp_offset += 16; + } + } +#if DEBUG_FFI + fprintf (stderr, "float arg %d = %g\n", i, *(float *)avalue[i]); +#endif + break; + + default: + FFI_ASSERT(0); + } + + argn += ALIGN(arg_types[i]->size, SIZEOF_ARG) / SIZEOF_ARG; + i++; + } + + /* Invoke the closure. */ + (closure->fun) (cif, rp, avalue, closure->user_data); + + /* FIXME: Structs not supported. */ + FFI_ASSERT(cif->rtype->type != FFI_TYPE_STRUCT); + + /* Tell ffi_closure_UNIX64 how to perform return type promotions. */ + + return cif->rtype->type; +} #endif /* ifndef __x86_64__ */ |