diff --git a/libffi/include/ffi.h.in b/libffi/include/ffi.h.in deleted file mode 100644 index c6c85fd9..00000000 --- a/libffi/include/ffi.h.in +++ /dev/null @@ -1,513 +0,0 @@ -/* -----------------------------------------------------------------*-C-*- - libffi @VERSION@ - Copyright (C) 1996, 1997, 1998, 1999, 2000, - 2001 Red Hat, Inc. - - 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 RED HAT 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. - - ----------------------------------------------------------------------- */ - -/* ------------------------------------------------------------------- - The basic API is described in the README file. - - The raw API is designed to bypass some of the argument packing - and unpacking on architectures for which it can be avoided. - - The closure API allows interpreted functions to be packaged up - inside a C function pointer, so that they can be called as C functions, - with no understanding on the client side that they are interpreted. - It can also be used in other cases in which it is necessary to package - up a user specified parameter and a function pointer as a single - function pointer. - - The closure API must be implemented in order to get its functionality, - e.g. for use by gij. Routines are provided to emulate the raw API - if the underlying platform doesn't allow faster implementation. - - More details on the raw and cloure API can be found in: - - http://gcc.gnu.org/ml/java/1999-q3/msg00138.html - - and - - http://gcc.gnu.org/ml/java/1999-q3/msg00174.html - -------------------------------------------------------------------- */ - -#ifndef LIBFFI_H -#define LIBFFI_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Specify which architecture libffi is configured for. */ -#define @TARGET@ - -/* ---- System configuration information --------------------------------- */ - -#include - -#if !defined(LIBFFI_ASM) -#include -#if defined(FFI_DEBUG) -#include -#endif -#endif - -/* ---- Generic type definitions ----------------------------------------- */ - -#define FLOAT32 float -#define FLOAT64 double -#define FLOAT80 long double - -#define UINT8 unsigned char -#define SINT8 signed char - -#if SIZEOF_INT == 2 - -#define UINT16 unsigned int -#define SINT16 int -#define ffi_type_uint ffi_type_uint16 -#define ffi_type_sint ffi_type_sint16 - -#else -#if SIZEOF_SHORT == 2 - -#define UINT16 unsigned short -#define SINT16 short -#define ffi_type_ushort ffi_type_uint16 -#define ffi_type_sshort ffi_type_sint16 - -#endif -#endif - -#if SIZEOF_INT == 4 - -#define UINT32 unsigned int -#define SINT32 int -#define ffi_type_uint ffi_type_uint32 -#define ffi_type_sint ffi_type_sint32 - -#else -#if SIZEOF_SHORT == 4 - -#define UINT32 unsigned short -#define SINT32 short -#define ffi_type_ushort ffi_type_uint32 -#define ffi_type_sshort ffi_type_sint32 - -#else -#if SIZEOF_LONG == 4 - -#define UINT32 unsigned long -#define SINT32 long -#define ffi_type_ulong ffi_type_uint32 -#define ffi_type_slong ffi_type_sint32 - -#endif -#endif -#endif - -#if SIZEOF_INT == 8 - -#define UINT64 unsigned int -#define SINT64 int -#define ffi_type_uint ffi_type_uint64 -#define ffi_type_sint ffi_type_sint64 - -#else -#if SIZEOF_LONG == 8 - -#define UINT64 unsigned long -#define SINT64 long -#define ffi_type_ulong ffi_type_uint64 -#define ffi_type_slong ffi_type_sint64 - -#else -#if SIZEOF_LONG_LONG == 8 - -#define UINT64 unsigned long long -#define SINT64 long long -#define ffi_type_ulong ffi_type_uint64 -#define ffi_type_slong ffi_type_sint64 - -#endif -#endif -#endif - -/* ---- System specific configurations ----------------------------------- */ - -#ifdef MIPS -#include -#else -#define SIZEOF_ARG SIZEOF_VOID_P -#endif - -#ifdef SPARC -#if defined(__arch64__) || defined(__sparcv9) -#define SPARC64 -#endif -#endif - -#ifndef LIBFFI_ASM - -/* ---- Generic type definitions ----------------------------------------- */ - -#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) -/* The closure code assumes that this works on pointers, i.e. a size_t */ -/* can hold a pointer. */ - -typedef enum ffi_abi { - - /* Leave this for debugging purposes */ - FFI_FIRST_ABI = 0, - - /* ---- Sparc -------------------- */ -#ifdef SPARC - FFI_V8, - FFI_V8PLUS, - FFI_V9, -#ifdef SPARC64 - FFI_DEFAULT_ABI = FFI_V9, -#else - FFI_DEFAULT_ABI = FFI_V8, -#endif -#endif - - /* ---- Intel x86 ---------------- */ -#ifdef X86 - FFI_SYSV, - FFI_DEFAULT_ABI = FFI_SYSV, -#endif - - /* ---- Intel x86 Win32 ---------- */ -#ifdef X86_WIN32 - FFI_SYSV, - FFI_DEFAULT_ABI = FFI_SYSV, -#endif - - /* ---- Intel ia64 ---------------- */ -#ifdef IA64 - FFI_UNIX, /* Linux and all Unix variants use the same conventions */ - FFI_DEFAULT_ABI = FFI_UNIX, -#endif - - /* ---- Mips --------------------- */ -#ifdef MIPS - FFI_O32, - FFI_N32, - FFI_N64, -#endif - - /* ---- Alpha -------------------- */ -#ifdef ALPHA - FFI_OSF, - FFI_DEFAULT_ABI = FFI_OSF, -#endif - - /* ---- Motorola m68k ------------ */ -#ifdef M68K - FFI_SYSV, - FFI_DEFAULT_ABI = FFI_SYSV, -#endif - - /* ---- PowerPC ------------------ */ -#ifdef POWERPC - FFI_SYSV, - FFI_GCC_SYSV, - FFI_DEFAULT_ABI = FFI_GCC_SYSV, -#endif - - /* ---- ARM --------------------- */ -#ifdef ARM - FFI_SYSV, - FFI_DEFAULT_ABI = FFI_SYSV, -#endif - - /* ---- S390 --------------------- */ -#ifdef S390 - FFI_SYSV, - FFI_DEFAULT_ABI = FFI_SYSV, -#endif - - /* Leave this for debugging purposes */ - FFI_LAST_ABI - -} ffi_abi; - -typedef struct _ffi_type -{ - size_t size; - unsigned short alignment; - unsigned short type; - /*@null@*/ struct _ffi_type **elements; -} ffi_type; - -/* These are defined in ffi.c */ -extern ffi_type ffi_type_void; -extern ffi_type ffi_type_uint8; -extern ffi_type ffi_type_sint8; -extern ffi_type ffi_type_uint16; -extern ffi_type ffi_type_sint16; -extern ffi_type ffi_type_uint32; -extern ffi_type ffi_type_sint32; -extern ffi_type ffi_type_uint64; -extern ffi_type ffi_type_sint64; -extern ffi_type ffi_type_float; -extern ffi_type ffi_type_double; -extern ffi_type ffi_type_longdouble; -extern ffi_type ffi_type_pointer; - -/* Characters are 8 bit integral types */ -#define ffi_type_schar ffi_type_sint8 -#define ffi_type_uchar ffi_type_uint8 - -typedef enum { - FFI_OK = 0, - FFI_BAD_TYPEDEF, - FFI_BAD_ABI -} ffi_status; - -typedef unsigned FFI_TYPE; - -typedef struct { - ffi_abi abi; - unsigned nargs; - /*@dependent@*/ ffi_type **arg_types; - /*@dependent@*/ ffi_type *rtype; - unsigned bytes; - unsigned flags; - -#ifdef MIPS -#if _MIPS_SIM == _ABIN32 - unsigned rstruct_flag; -#endif -#endif - -} ffi_cif; - -/* ---- Definitions for the raw API -------------------------------------- */ - -#if !FFI_NO_RAW_API - -#if SIZEOF_ARG == 4 - -#define UINT_ARG UINT32 -#define SINT_ARG SINT32 - -#endif - -#if SIZEOF_ARG == 8 - -#define UINT_ARG UINT64 -#define SINT_ARG SINT64 - -#endif - -typedef union { - SINT_ARG sint; - UINT_ARG uint; - float flt; - char data[SIZEOF_ARG]; - void* ptr; -} ffi_raw; - -void ffi_raw_call (/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ ffi_raw *avalue); - -void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); -void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); -size_t ffi_raw_size (ffi_cif *cif); - -#if !NO_JAVA_RAW_API - -/* This is analogous to the raw API, except it uses Java parameter */ -/* packing, even on 64-bit machines. I.e. on 64-bit machines */ -/* longs and doubles are followed by an empty 64-bit word. */ - -void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ ffi_raw *avalue); - -void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); -void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); -size_t ffi_java_raw_size (ffi_cif *cif); - -#endif /* !NO_JAVA_RAW_API */ - -#endif /* !FFI_NO_RAW_API */ - -/* ---- Definitions for closures ----------------------------------------- */ - -#ifdef X86 - -#define FFI_CLOSURES 1 /* x86 supports closures */ -#define FFI_TRAMPOLINE_SIZE 10 -#define FFI_NATIVE_RAW_API 1 /* and has native raw api support */ - -#elif defined(X86_WIN32) - -#define FFI_CLOSURES 1 /* x86 supports closures */ -#define FFI_TRAMPOLINE_SIZE 10 -#define FFI_NATIVE_RAW_API 1 /* and has native raw api support */ - -#elif defined(IA64) - -#define FFI_CLOSURES 1 -#define FFI_TRAMPOLINE_SIZE 24 /* Really the following struct, which */ - /* can be interpreted as a C function */ - /* decriptor: */ - -struct ffi_ia64_trampoline_struct { - void * code_pointer; /* Pointer to ffi_closure_UNIX */ - void * fake_gp; /* Pointer to closure, installed as gp */ - void * real_gp; /* Real gp value, reinstalled by */ - /* ffi_closure_UNIX. */ -}; -#define FFI_NATIVE_RAW_API 0 - -#elif defined(ALPHA) - -#define FFI_CLOSURES 1 -#define FFI_TRAMPOLINE_SIZE 24 -#define FFI_NATIVE_RAW_API 0 - -#elif defined(POWERPC) - -#define FFI_CLOSURES 1 -#define FFI_TRAMPOLINE_SIZE 40 -#define FFI_NATIVE_RAW_API 0 - -#else - -#define FFI_CLOSURES 0 -#define FFI_NATIVE_RAW_API 0 - -#endif - - - -#if FFI_CLOSURES - -typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - ffi_cif *cif; - void (*fun)(ffi_cif*,void*,void**,void*); - void *user_data; -} ffi_closure; - -ffi_status -ffi_prep_closure (ffi_closure*, - ffi_cif *, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data); - -#if !FFI_NO_RAW_API - -typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - - ffi_cif *cif; - -#if !FFI_NATIVE_RAW_API - - /* if this is enabled, then a raw closure has the same layout - as a regular closure. We use this to install an intermediate - handler to do the transaltion, void** -> ffi_raw*. */ - - void (*translate_args)(ffi_cif*,void*,void**,void*); - void *this_closure; - -#endif - - void (*fun)(ffi_cif*,void*,ffi_raw*,void*); - void *user_data; - -} ffi_raw_closure; - -ffi_status -ffi_prep_raw_closure (ffi_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data); - -#ifndef NO_JAVA_RAW_API -ffi_status -ffi_prep_java_raw_closure (ffi_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data); -#endif - -#endif /* !FFI_NO_RAW_API */ -#endif /* FFI_CLOSURES */ - -/* ---- Public interface definition -------------------------------------- */ - -ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, - ffi_abi abi, - unsigned int nargs, - /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, - /*@dependent@*/ ffi_type **atypes); - -void ffi_call(/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ void **avalue); - -/* Useful for eliminating compiler warnings */ -#define FFI_FN(f) ((void (*)())f) - -/* ---- Definitions shared with assembly code ---------------------------- */ - -#endif - -#define FFI_TYPE_VOID 0 -#define FFI_TYPE_INT 1 -#define FFI_TYPE_FLOAT 2 -#define FFI_TYPE_DOUBLE 3 -#if SIZEOF_LONG_DOUBLE == SIZEOF_DOUBLE -#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE -#else -#define FFI_TYPE_LONGDOUBLE 4 -#endif - -#define FFI_TYPE_UINT8 5 /* If this changes, update ffi_mips.h. */ -#define FFI_TYPE_SINT8 6 /* If this changes, update ffi_mips.h. */ -#define FFI_TYPE_UINT16 7 -#define FFI_TYPE_SINT16 8 -#define FFI_TYPE_UINT32 9 -#define FFI_TYPE_SINT32 10 -#define FFI_TYPE_UINT64 11 -#define FFI_TYPE_SINT64 12 -#define FFI_TYPE_STRUCT 13 /* If this changes, update ffi_mips.h. */ -#define FFI_TYPE_POINTER 14 - -/* This should always refer to the last type code (for sanity checks) */ -#define FFI_TYPE_LAST FFI_TYPE_POINTER - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/libffi/mips/ffi.c b/libffi/mips/ffi.c new file mode 100644 index 00000000..fb733b2b --- /dev/null +++ b/libffi/mips/ffi.c @@ -0,0 +1,470 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996, 2001 Red Hat, Inc. + + MIPS 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 CYGNUS SOLUTIONS 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 +#include +#include + +#include + +#if _MIPS_SIM == _MIPS_SIM_NABI32 +#define FIX_ARGP \ +FFI_ASSERT(argp <= &stack[bytes]); \ +if (argp == &stack[bytes]) \ +{ \ + argp = stack; \ + ffi_stop_here(); \ +} +#else +#define FIX_ARGP +#endif + + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +static void ffi_prep_args(char *stack, + extended_cif *ecif, + int bytes, + int flags) +{ + register int i; + register int avn; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + +#if _MIPS_SIM == _MIPS_SIM_NABI32 + /* If more than 8 double words are used, the remainder go + on the stack. We reorder stuff on the stack here to + support this easily. */ + if (bytes > 8 * SIZEOF_ARG) + argp = &stack[bytes - (8 * SIZEOF_ARG)]; + else + argp = stack; +#else + argp = stack; +#endif + + memset(stack, 0, bytes); + +#if _MIPS_SIM == _MIPS_SIM_NABI32 + if ( ecif->cif->rstruct_flag != 0 ) +#else + if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) +#endif + { + *(SLOT_TYPE_UNSIGNED *) argp = (SLOT_TYPE_UNSIGNED) ecif->rvalue; + argp += sizeof(SLOT_TYPE_UNSIGNED); + FIX_ARGP; + } + + avn = ecif->cif->nargs; + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + i && avn; + i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if (((*p_arg)->alignment - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, (*p_arg)->alignment); + FIX_ARGP; + } + +#if _MIPS_SIM == _MIPS_SIM_ABI32 +#define OFFSET 0 +#else +#define OFFSET sizeof(int) +#endif + + if (avn) + { + avn--; + z = (*p_arg)->size; + if (z < sizeof(SLOT_TYPE_UNSIGNED)) + { + z = sizeof(SLOT_TYPE_UNSIGNED); + + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_SINT32: + *(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + *(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT32 *)(* p_argv); + break; + + /* This can only happen with 64bit slots */ + case FFI_TYPE_FLOAT: + *(float *) argp = *(float *)(* p_argv); + break; + + /* Handle small structures */ + case FFI_TYPE_STRUCT: + memcpy(argp, *p_argv, (*p_arg)->size); + break; + + default: + FFI_ASSERT(0); + } + } + else + { +#if _MIPS_SIM == _MIPS_SIM_ABI32 + memcpy(argp, *p_argv, z); +#else + { + unsigned end = (unsigned) argp+z; + unsigned cap = (unsigned) stack+bytes; + + /* Check if the data will fit within the register + space. Handle it if it doesn't. */ + + if (end <= cap) + memcpy(argp, *p_argv, z); + else + { + unsigned portion = end - cap; + + memcpy(argp, *p_argv, portion); + argp = stack; + memcpy(argp, + (void*)((unsigned)(*p_argv)+portion), z - portion); + } + } +#endif + } + p_argv++; + argp += z; + FIX_ARGP; + } + } + + return; +} + +#if _MIPS_SIM == _MIPS_SIM_NABI32 + +/* The n32 spec says that if "a chunk consists solely of a double + float field (but not a double, which is part of a union), it + is passed in a floating point register. Any other chunk is + passed in an integer register". This code traverses structure + definitions and generates the appropriate flags. */ + +unsigned calc_n32_struct_flags(ffi_type *arg, unsigned *shift) +{ + unsigned flags = 0; + unsigned index = 0; + + ffi_type *e; + + while (e = arg->elements[index]) + { + if (e->type == FFI_TYPE_DOUBLE) + { + flags += (FFI_TYPE_DOUBLE << *shift); + *shift += FFI_FLAG_BITS; + } + else if (e->type == FFI_TYPE_STRUCT) + flags += calc_n32_struct_flags(e, shift); + else + *shift += FFI_FLAG_BITS; + + index++; + } + + return flags; +} + +unsigned calc_n32_return_struct_flags(ffi_type *arg) +{ + unsigned flags = 0; + unsigned index = 0; + unsigned small = FFI_TYPE_SMALLSTRUCT; + ffi_type *e; + + /* Returning structures under n32 is a tricky thing. + A struct with only one or two floating point fields + is returned in $f0 (and $f2 if necessary). Any other + struct results at most 128 bits are returned in $2 + (the first 64 bits) and $3 (remainder, if necessary). + Larger structs are handled normally. */ + + if (arg->size > 16) + return 0; + + if (arg->size > 8) + small = FFI_TYPE_SMALLSTRUCT2; + + e = arg->elements[0]; + if (e->type == FFI_TYPE_DOUBLE) + flags = FFI_TYPE_DOUBLE << FFI_FLAG_BITS; + else if (e->type == FFI_TYPE_FLOAT) + flags = FFI_TYPE_FLOAT << FFI_FLAG_BITS; + + if (flags && (e = arg->elements[1])) + { + if (e->type == FFI_TYPE_DOUBLE) + flags += FFI_TYPE_DOUBLE; + else if (e->type == FFI_TYPE_FLOAT) + flags += FFI_TYPE_FLOAT; + else + return small; + + if (flags && (arg->elements[2])) + { + /* There are three arguments and the first two are + floats! This must be passed the old way. */ + return small; + } + } + else + if (!flags) + return small; + + return flags; +} + +#endif + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + cif->flags = 0; + +#if _MIPS_SIM == _MIPS_SIM_ABI32 + /* Set the flags necessary for O32 processing */ + + if (cif->rtype->type != FFI_TYPE_STRUCT) + { + if (cif->nargs > 0) + { + switch ((cif->arg_types)[0]->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += (cif->arg_types)[0]->type; + break; + + default: + break; + } + + if (cif->nargs > 1) + { + /* Only handle the second argument if the first + is a float or double. */ + if (cif->flags) + { + switch ((cif->arg_types)[1]->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += (cif->arg_types)[1]->type << FFI_FLAG_BITS; + break; + + default: + break; + } + } + } + } + } + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2); + break; + + default: + cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2); + break; + } +#endif + +#if _MIPS_SIM == _MIPS_SIM_NABI32 + /* Set the flags necessary for N32 processing */ + { + unsigned shift = 0; + unsigned count = (cif->nargs < 8) ? cif->nargs : 8; + unsigned index = 0; + + unsigned struct_flags = 0; + + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + struct_flags = calc_n32_return_struct_flags(cif->rtype); + + if (struct_flags == 0) + { + /* This means that the structure is being passed as + a hidden argument */ + + shift = FFI_FLAG_BITS; + count = (cif->nargs < 7) ? cif->nargs : 7; + + cif->rstruct_flag = !0; + } + else + cif->rstruct_flag = 0; + } + else + cif->rstruct_flag = 0; + + while (count-- > 0) + { + switch ((cif->arg_types)[index]->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += ((cif->arg_types)[index]->type << shift); + shift += FFI_FLAG_BITS; + break; + + case FFI_TYPE_STRUCT: + cif->flags += calc_n32_struct_flags((cif->arg_types)[index], + &shift); + break; + + default: + shift += FFI_FLAG_BITS; + } + + index++; + } + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_STRUCT: + { + if (struct_flags == 0) + { + /* The structure is returned through a hidden + first argument. Do nothing, 'cause FFI_TYPE_VOID + is 0 */ + } + else + { + /* The structure is returned via some tricky + mechanism */ + cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8); + cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8)); + } + break; + } + + case FFI_TYPE_VOID: + /* Do nothing, 'cause FFI_TYPE_VOID is 0 */ + break; + + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8); + break; + + default: + cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8); + break; + } + } +#endif + + return FFI_OK; +} + +/* Low level routine for calling O32 functions */ +extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int), + extended_cif *, unsigned, + unsigned, unsigned *, void (*)()); + +/* Low level routine for calling N32 functions */ +extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int), + extended_cif *, unsigned, + unsigned, unsigned *, void (*)()); + +void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* 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->rtype->type == FFI_TYPE_STRUCT)) + ecif.rvalue = alloca(cif->rtype->size); + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { +#if _MIPS_SIM == _MIPS_SIM_ABI32 + case FFI_O32: + ffi_call_O32(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; +#endif + +#if _MIPS_SIM == _MIPS_SIM_NABI32 + case FFI_N32: + ffi_call_N32(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; +#endif + + default: + FFI_ASSERT(0); + break; + } +} diff --git a/libffi/include/ffi_mips.h b/libffi/mips/mips.h similarity index 90% rename from libffi/include/ffi_mips.h rename to libffi/mips/mips.h index 6fd56474..8ca9e849 100644 --- a/libffi/include/ffi_mips.h +++ b/libffi/mips/mips.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- - ffi-mips.h - Copyright (c) 1996 Cygnus Support + ffi-mips.h - Copyright (c) 1996, 2001 Red Hat, Inc. MIPS FFI Definitions @@ -23,23 +23,26 @@ OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ -#ifndef FFI_MIPS_H +#ifndef MIPS_H -#include - -#if !defined(_MIPS_SIM) --- something is very wrong -- +#if defined(__mips_eabi) +# define FFI_MIPS_EABI +# define FFI_MIPS_O32 #else -# if _MIPS_SIM==_ABIN32 && defined(_ABIN32) -# define FFI_MIPS_N32 +# if !defined(_MIPS_SIM) +-- something is very wrong -- # else -# if defined(__GNUC__) -# define FFI_MIPS_O32 +# if _MIPS_SIM==_ABIN32 && defined(_ABIN32) +# define FFI_MIPS_N32 # else -# if _MIPS_SIM==_ABIO32 +# if defined(__GNUC__) # define FFI_MIPS_O32 # else +# if _MIPS_SIM==_ABIO32 +# define FFI_MIPS_O32 +# else -- this is an unsupported platform -- +# endif # endif # endif # endif diff --git a/libffi/mips/n32.S b/libffi/mips/n32.S new file mode 100644 index 00000000..ee137b73 --- /dev/null +++ b/libffi/mips/n32.S @@ -0,0 +1,319 @@ +/* ----------------------------------------------------------------------- + n32.S - Copyright (c) 1996, 1998 Cygnus Solutions + + MIPS 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 CYGNUS SOLUTIONS 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 +#include + +/* Only build this code if we are compiling for n32 */ + +#if defined(FFI_MIPS_N32) + +#define callback a0 +#define bytes a2 +#define flags a3 +#define raddr a4 +#define fn a5 + +#define SIZEOF_FRAME ( 8 * SIZEOF_ARG ) + + .text + .align 2 + .globl ffi_call_N32 + .ent ffi_call_N32 +ffi_call_N32: + + # Prologue + SUBU $sp, SIZEOF_FRAME # Frame size + REG_S $fp, SIZEOF_FRAME - 2*SIZEOF_ARG($sp) # Save frame pointer + REG_S ra, SIZEOF_FRAME - 1*SIZEOF_ARG($sp) # Save return address + move $fp, $sp + + move t9, callback # callback function pointer + REG_S bytes, 2*SIZEOF_ARG($fp) # bytes + REG_S flags, 3*SIZEOF_ARG($fp) # flags + REG_S raddr, 4*SIZEOF_ARG($fp) # raddr + REG_S fn, 5*SIZEOF_ARG($fp) # fn + + # Allocate at least 4 words in the argstack + move v0, bytes + bge bytes, 4 * SIZEOF_ARG, bigger + LI v0, 4 * SIZEOF_ARG + b sixteen + + bigger: + ADDU t4, v0, 2 * SIZEOF_ARG -1 # make sure it is aligned + and v0, t4, -2 * SIZEOF_ARG # to a proper boundry. + +sixteen: + SUBU $sp, $sp, v0 # move the stack pointer to reflect the + # arg space + + ADDU a0, $sp, 0 # 4 * SIZEOF_ARG + ADDU a3, $fp, 3 * SIZEOF_ARG + + # Call ffi_prep_args + jal t9 + + # ADDU $sp, $sp, 4 * SIZEOF_ARG # adjust $sp to new args + + # Copy the stack pointer to t9 + move t9, $sp + + # Fix the stack if there are more than 8 64bit slots worth + # of arguments. + + # Load the number of bytes + REG_L t6, 2*SIZEOF_ARG($fp) + + # Is it bigger than 8 * SIZEOF_ARG? + dadd t7, $0, 8 * SIZEOF_ARG + dsub t8, t6, t7 + bltz t8, loadregs + + add t9, t9, t8 + +loadregs: + + REG_L t4, 3*SIZEOF_ARG($fp) # load the flags word + add t6, t4, 0 # and copy it into t6 + + and t4, ((1< +#include + +/* Only build this code if we are compiling for o32 */ + +#if defined(FFI_MIPS_O32) + +#define callback a0 +#define bytes a2 +#define flags a3 + +#define SIZEOF_FRAME ( 4 * SIZEOF_ARG + 2 * SIZEOF_ARG ) + + .text + .align 2 + .globl ffi_call_O32 + .ent ffi_call_O32 +ffi_call_O32: + + # Prologue + SUBU $sp, SIZEOF_FRAME # Frame size + REG_S $fp, SIZEOF_FRAME - 2*SIZEOF_ARG($sp) # Save frame pointer + REG_S ra, SIZEOF_FRAME - 1*SIZEOF_ARG($sp) # Save return address + move $fp, $sp + + move t9, callback # callback function pointer + REG_S flags, SIZEOF_FRAME + 3*SIZEOF_ARG($fp) # flags + + # Allocate at least 4 words in the argstack + move v0, bytes + bge bytes, 4 * SIZEOF_ARG, bigger + LI v0, 4 * SIZEOF_ARG + b sixteen + +bigger: + ADDU t0, v0, 2 * SIZEOF_ARG -1 # make sure it is aligned + and v0, t0, -2 * SIZEOF_ARG # to an 8 byte boundry + +sixteen: + SUBU $sp, $sp, v0 # move the stack pointer to reflect the + # arg space + + ADDU a0, $sp, 4 * SIZEOF_ARG + ADDU a3, $fp, SIZEOF_FRAME + 3*SIZEOF_ARG + + jal t9 + + REG_L t0, SIZEOF_FRAME + 3*SIZEOF_ARG($fp) # load the flags word + add t2, t0, 0 # and copy it into t2 + + and t0, ((1<<4)-1) # mask out the return type + SRL t2, 4 # shift our arg info + + ADDU $sp, $sp, 4 * SIZEOF_ARG # adjust $sp to new args + + bnez t0, pass_d # make it quick for int + REG_L a0, 0*SIZEOF_ARG($sp) # just go ahead and load the + REG_L a1, 1*SIZEOF_ARG($sp) # four regs. + REG_L a2, 2*SIZEOF_ARG($sp) + REG_L a3, 3*SIZEOF_ARG($sp) + b call_it + +pass_d: + bne t0, FFI_ARGS_D, pass_f + l.d $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args + REG_L a2, 2*SIZEOF_ARG($sp) # passing a double + REG_L a3, 3*SIZEOF_ARG($sp) + b call_it + +pass_f: + bne t0, FFI_ARGS_F, pass_d_d + l.s $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args + REG_L a1, 1*SIZEOF_ARG($sp) # passing a float + REG_L a2, 2*SIZEOF_ARG($sp) + REG_L a3, 3*SIZEOF_ARG($sp) + b call_it + +pass_d_d: + bne t0, FFI_ARGS_DD, pass_f_f + l.d $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args + l.d $f14, 2*SIZEOF_ARG($sp) # passing two doubles + b call_it + +pass_f_f: + bne t0, FFI_ARGS_FF, pass_d_f + l.s $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args + l.s $f14, 1*SIZEOF_ARG($sp) # passing two floats + REG_L a2, 2*SIZEOF_ARG($sp) + REG_L a3, 3*SIZEOF_ARG($sp) + b call_it + +pass_d_f: + bne t0, FFI_ARGS_DF, pass_f_d + l.d $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args + l.s $f14, 2*SIZEOF_ARG($sp) # passing double and float + REG_L a3, 3*SIZEOF_ARG($sp) + b call_it + +pass_f_d: + # assume that the only other combination must be float then double + # bne t0, FFI_ARGS_F_D, call_it + l.s $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args + l.d $f14, 2*SIZEOF_ARG($sp) # passing double and float + +call_it: + # Load the function pointer + REG_L t9, SIZEOF_FRAME + 5*SIZEOF_ARG($fp) + + # If the return value pointer is NULL, assume no return value. + REG_L t1, SIZEOF_FRAME + 4*SIZEOF_ARG($fp) + beqz t1, noretval + + bne t2, FFI_TYPE_INT, retfloat + jal t9 + REG_L t0, SIZEOF_FRAME + 4*SIZEOF_ARG($fp) + REG_S v0, 0(t0) + b epilogue + +retfloat: + bne t2, FFI_TYPE_FLOAT, retdouble + jal t9 + REG_L t0, SIZEOF_FRAME + 4*SIZEOF_ARG($fp) + s.s $f0, 0(t0) + b epilogue + +retdouble: + bne t2, FFI_TYPE_DOUBLE, noretval + jal t9 + REG_L t0, SIZEOF_FRAME + 4*SIZEOF_ARG($fp) + s.d $f0, 0(t0) + b epilogue + +noretval: + jal t9 + + # Epilogue +epilogue: + move $sp, $fp + REG_L $fp, SIZEOF_FRAME - 2*SIZEOF_ARG($sp) # Restore frame pointer + REG_L ra, SIZEOF_FRAME - 1*SIZEOF_ARG($sp) # Restore return address + ADDU $sp, SIZEOF_FRAME # Fix stack pointer + j ra + + .end ffi_call_O32 + +#endif diff --git a/libffi/s390/ffi.c b/libffi/s390/ffi.c new file mode 100644 index 00000000..54988839 --- /dev/null +++ b/libffi/s390/ffi.c @@ -0,0 +1,589 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2000 Software AG + + S390 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 AUTHOR 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. + ----------------------------------------------------------------------- */ +/*====================================================================*/ +/* Includes */ +/* -------- */ +/*====================================================================*/ + +#include +#include + +#include +#include + +/*====================== End of Includes =============================*/ + +/*====================================================================*/ +/* Defines */ +/* ------- */ +/*====================================================================*/ + +#define MAX_GPRARGS 5 /* Max. no. of GPR available */ +#define MAX_FPRARGS 2 /* Max. no. of FPR available */ + +#define STR_GPR 1 /* Structure will fit in 1 or 2 GPR */ +#define STR_FPR 2 /* Structure will fit in a FPR */ +#define STR_STACK 3 /* Structure needs to go on stack */ + +/*===================== End of Defines ===============================*/ + +/*====================================================================*/ +/* Types */ +/* ----- */ +/*====================================================================*/ + +typedef struct stackLayout +{ + int *backChain; + int *endOfStack; + int glue[2]; + int scratch[2]; + int gprArgs[MAX_GPRARGS]; + int notUsed; + union + { + float f; + double d; + } fprArgs[MAX_FPRARGS]; + int unUsed[8]; + int outArgs[100]; +} stackLayout; + +/*======================== End of Types ==============================*/ + +/*====================================================================*/ +/* Prototypes */ +/* ---------- */ +/*====================================================================*/ + +void ffi_prep_args(stackLayout *, extended_cif *); +static int ffi_check_struct(ffi_type *, unsigned int *); +static void ffi_insert_int(int, stackLayout *, int *, int *); +static void ffi_insert_int64(long long, stackLayout *, int *, int *); +static void ffi_insert_double(double, stackLayout *, int *, int *); + +/*====================== End of Prototypes ===========================*/ + +/*====================================================================*/ +/* Externals */ +/* --------- */ +/*====================================================================*/ + +extern void ffi_call_SYSV(void (*)(stackLayout *, extended_cif *), + extended_cif *, + unsigned, unsigned, + unsigned *, + void (*fn)()); + +/*====================== End of Externals ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_check_struct. */ +/* */ +/* Function - Determine if a structure can be passed within a */ +/* general or floating point register. */ +/* */ +/*====================================================================*/ + +int +ffi_check_struct(ffi_type *arg, unsigned int *strFlags) +{ + ffi_type *element; + int i_Element; + + for (i_Element = 0; arg->elements[i_Element]; i_Element++) { + element = arg->elements[i_Element]; + switch (element->type) { + case FFI_TYPE_DOUBLE : + *strFlags |= STR_FPR; + break; + + case FFI_TYPE_STRUCT : + *strFlags |= ffi_check_struct(element, strFlags); + break; + + default : + *strFlags |= STR_GPR; + } + } + return (*strFlags); +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_insert_int. */ +/* */ +/* Function - Insert an integer parameter in a register if there are */ +/* spares else on the stack. */ +/* */ +/*====================================================================*/ + +void +ffi_insert_int(int gprValue, stackLayout *stack, + int *intArgC, int *outArgC) +{ + if (*intArgC < MAX_GPRARGS) { + stack->gprArgs[*intArgC] = gprValue; + *intArgC += 1; + } + else { + stack->outArgs[*outArgC++] = gprValue; + *outArgC += 1; + } +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_insert_int64. */ +/* */ +/* Function - Insert a long long parameter in registers if there are */ +/* spares else on the stack. */ +/* */ +/*====================================================================*/ + +void +ffi_insert_int64(long long llngValue, stackLayout *stack, + int *intArgC, int *outArgC) +{ + + if (*intArgC < (MAX_GPRARGS-1)) { + memcpy(&stack->gprArgs[*intArgC], + &llngValue, sizeof(long long)); + *intArgC += 2; + } + else { + memcpy(&stack->outArgs[*outArgC], + &llngValue, sizeof(long long)); + *outArgC += 2; + } + +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_insert_double. */ +/* */ +/* Function - Insert a double parameter in a FP register if there is */ +/* a spare else on the stack. */ +/* */ +/*====================================================================*/ + +void +ffi_insert_double(double dblValue, stackLayout *stack, + int *fprArgC, int *outArgC) +{ + + if (*fprArgC < MAX_FPRARGS) { + stack->fprArgs[*fprArgC].d = dblValue; + *fprArgC += 1; + } + else { + memcpy(&stack->outArgs[*outArgC], + &dblValue,sizeof(double)); + *outArgC += 2; + } + +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_prep_args. */ +/* */ +/* Function - Prepare parameters for call to function. */ +/* */ +/* ffi_prep_args is called by the assembly routine once stack space */ +/* has been allocated for the function's arguments. */ +/* */ +/* The stack layout we want looks like this: */ +/* *------------------------------------------------------------* */ +/* | 0 | Back chain (a 0 here signifies end of back chain) | */ +/* +--------+---------------------------------------------------+ */ +/* | 4 | EOS (end of stack, not used on Linux for S390) | */ +/* +--------+---------------------------------------------------+ */ +/* | 8 | Glue used in other linkage formats | */ +/* +--------+---------------------------------------------------+ */ +/* | 12 | Glue used in other linkage formats | */ +/* +--------+---------------------------------------------------+ */ +/* | 16 | Scratch area | */ +/* +--------+---------------------------------------------------+ */ +/* | 20 | Scratch area | */ +/* +--------+---------------------------------------------------+ */ +/* | 24 | GPR parameter register 1 | */ +/* +--------+---------------------------------------------------+ */ +/* | 28 | GPR parameter register 2 | */ +/* +--------+---------------------------------------------------+ */ +/* | 32 | GPR parameter register 3 | */ +/* +--------+---------------------------------------------------+ */ +/* | 36 | GPR parameter register 4 | */ +/* +--------+---------------------------------------------------+ */ +/* | 40 | GPR parameter register 5 | */ +/* +--------+---------------------------------------------------+ */ +/* | 44 | Unused | */ +/* +--------+---------------------------------------------------+ */ +/* | 48 | FPR parameter register 1 | */ +/* +--------+---------------------------------------------------+ */ +/* | 56 | FPR parameter register 2 | */ +/* +--------+---------------------------------------------------+ */ +/* | 64 | Unused | */ +/* +--------+---------------------------------------------------+ */ +/* | 96 | Outgoing args (length x) | */ +/* +--------+---------------------------------------------------+ */ +/* | 96+x | Copy area for structures (length y) | */ +/* +--------+---------------------------------------------------+ */ +/* | 96+x+y | Possible stack alignment | */ +/* *------------------------------------------------------------* */ +/* */ +/*====================================================================*/ + +void +ffi_prep_args(stackLayout *stack, extended_cif *ecif) +{ + const unsigned bytes = ecif->cif->bytes; + const unsigned flags = ecif->cif->flags; + + /*----------------------------------------------------------*/ + /* Pointer to the copy area on stack for structures */ + /*----------------------------------------------------------*/ + char *copySpace = (char *) stack + bytes + sizeof(stackLayout); + + /*----------------------------------------------------------*/ + /* Count of general and floating point register usage */ + /*----------------------------------------------------------*/ + int intArgC = 0, + fprArgC = 0, + outArgC = 0; + + int i; + ffi_type **ptr; + void **p_argv; + size_t structCopySize; + unsigned gprValue, strFlags = 0; + unsigned long long llngValue; + double dblValue; + + /* Now for the arguments. */ + p_argv = ecif->avalue; + + /*----------------------------------------------------------------------*/ + /* If we returning a structure then we set the first parameter register */ + /* to the address of where we are returning this structure */ + /*----------------------------------------------------------------------*/ + if (flags == FFI_TYPE_STRUCT) + stack->gprArgs[intArgC++] = (int) ecif->rvalue; + + for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; + i > 0; + i--, ptr++, p_argv++) + { + switch ((*ptr)->type) { + + case FFI_TYPE_FLOAT: + if (fprArgC < MAX_FPRARGS) + stack->fprArgs[fprArgC++].f = *(float *) *p_argv; + else + stack->outArgs[outArgC++] = *(int *) *p_argv; + break; + + case FFI_TYPE_DOUBLE: + dblValue = *(double *) *p_argv; + ffi_insert_double(dblValue, stack, &fprArgC, &outArgC); + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + llngValue = *(unsigned long long *) *p_argv; + ffi_insert_int64(llngValue, stack, &intArgC, &outArgC); + break; + + case FFI_TYPE_UINT8: + gprValue = *(unsigned char *)*p_argv; + ffi_insert_int(gprValue, stack, &intArgC, &outArgC); + break; + + case FFI_TYPE_SINT8: + gprValue = *(signed char *)*p_argv; + ffi_insert_int(gprValue, stack, &intArgC, &outArgC); + break; + + case FFI_TYPE_UINT16: + gprValue = *(unsigned short *)*p_argv; + ffi_insert_int(gprValue, stack, &intArgC, &outArgC); + break; + + case FFI_TYPE_SINT16: + gprValue = *(signed short *)*p_argv; + ffi_insert_int(gprValue, stack, &intArgC, &outArgC); + break; + + case FFI_TYPE_STRUCT: + /*--------------------------------------------------*/ + /* If structure > 8 bytes then it goes on the stack */ + /*--------------------------------------------------*/ + if (((*ptr)->size > 8) || + ((*ptr)->size > 4 && + (*ptr)->size < 8)) + strFlags = STR_STACK; + else + strFlags = ffi_check_struct((ffi_type *) *ptr, &strFlags); + + switch (strFlags) { + /*-------------------------------------------*/ + /* Structure that will fit in one or two GPR */ + /*-------------------------------------------*/ + case STR_GPR : + if ((*ptr)->size <= 4) { + gprValue = *(unsigned int *) *p_argv; + gprValue = gprValue >> ((4 - (*ptr)->size) * 8); + ffi_insert_int(gprValue, stack, &intArgC, &outArgC); + } + else { + llngValue = *(unsigned long long *) *p_argv; + ffi_insert_int64(llngValue, stack, &intArgC, &outArgC); + } + break; + + /*-------------------------------------------*/ + /* Structure that will fit in one FPR */ + /*-------------------------------------------*/ + case STR_FPR : + dblValue = *(double *) *p_argv; + ffi_insert_double(dblValue, stack, &fprArgC, &outArgC); + break; + + /*-------------------------------------------*/ + /* Structure that must be copied to stack */ + /*-------------------------------------------*/ + default : + structCopySize = (((*ptr)->size + 15) & ~0xF); + copySpace -= structCopySize; + memcpy(copySpace, (char *)*p_argv, (*ptr)->size); + gprValue = (unsigned) copySpace; + if (intArgC < MAX_GPRARGS) + stack->gprArgs[intArgC++] = gprValue; + else + stack->outArgs[outArgC++] = gprValue; + } + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + structCopySize = (((*ptr)->size + 15) & ~0xF); + copySpace -= structCopySize; + memcpy(copySpace, (char *)*p_argv, (*ptr)->size); + gprValue = (unsigned) copySpace; + if (intArgC < MAX_GPRARGS) + stack->gprArgs[intArgC++] = gprValue; + else + stack->outArgs[outArgC++] = gprValue; + break; +#endif + + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + gprValue = *(unsigned *)*p_argv; + if (intArgC < MAX_GPRARGS) + stack->gprArgs[intArgC++] = gprValue; + else + stack->outArgs[outArgC++] = gprValue; + break; + + } + } +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_prep_cif_machdep. */ +/* */ +/* Function - Perform machine dependent CIF processing. */ +/* */ +/*====================================================================*/ + +ffi_status +ffi_prep_cif_machdep(ffi_cif *cif) +{ + int i; + ffi_type **ptr; + unsigned bytes; + int fpArgC = 0, + intArgC = 0; + unsigned flags = 0; + unsigned structCopySize = 0; + + /*-----------------------------------------------------------------*/ + /* Extra space required in stack for overflow parameters. */ + /*-----------------------------------------------------------------*/ + bytes = 0; + + /*--------------------------------------------------------*/ + /* Return value handling. The rules are as follows: */ + /* - 32-bit (or less) integer values are returned in gpr2 */ + /* - Structures are returned as pointers in gpr2 */ + /* - 64-bit integer values are returned in gpr2 and 3 */ + /* - Single/double FP values are returned in fpr0 */ + /*--------------------------------------------------------*/ + flags = cif->rtype->type; + + /*------------------------------------------------------------------------*/ + /* The first MAX_GPRARGS words of integer arguments, and the */ + /* first MAX_FPRARGS floating point arguments, go in registers; the rest */ + /* goes on the stack. Structures and long doubles (if not equivalent */ + /* to double) are passed as a pointer to a copy of the structure. */ + /* Stuff on the stack needs to keep proper alignment. */ + /*------------------------------------------------------------------------*/ + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + switch ((*ptr)->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + fpArgC++; + if (fpArgC > MAX_FPRARGS && intArgC%2 != 0) + intArgC++; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + /*----------------------------------------------------*/ + /* 'long long' arguments are passed as two words, but */ + /* either both words must fit in registers or both go */ + /* on the stack. If they go on the stack, they must */ + /* be 8-byte-aligned. */ + /*----------------------------------------------------*/ + if ((intArgC == MAX_GPRARGS-1) || + (intArgC >= MAX_GPRARGS) && + (intArgC%2 != 0)) + intArgC++; + intArgC += 2; + break; + + case FFI_TYPE_STRUCT: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + /*----------------------------------------------------*/ + /* We must allocate space for a copy of these to */ + /* enforce pass-by-value. Pad the space up to a */ + /* multiple of 16 bytes (the maximum alignment */ + /* required for anything under the SYSV ABI). */ + /*----------------------------------------------------*/ + structCopySize += ((*ptr)->size + 15) & ~0xF; + /*----------------------------------------------------*/ + /* Fall through (allocate space for the pointer). */ + /*----------------------------------------------------*/ + + default: + /*----------------------------------------------------*/ + /* Everything else is passed as a 4-byte word in a */ + /* GPR either the object itself or a pointer to it. */ + /*----------------------------------------------------*/ + intArgC++; + break; + } + } + + /*-----------------------------------------------------------------*/ + /* Stack space. */ + /*-----------------------------------------------------------------*/ + if (intArgC > MAX_GPRARGS) + bytes += (intArgC - MAX_GPRARGS) * sizeof(int); + if (fpArgC > MAX_FPRARGS) + bytes += (fpArgC - MAX_FPRARGS) * sizeof(double); + + /*-----------------------------------------------------------------*/ + /* The stack space allocated needs to be a multiple of 16 bytes. */ + /*-----------------------------------------------------------------*/ + bytes = (bytes + 15) & ~0xF; + + /*-----------------------------------------------------------------*/ + /* Add in the space for the copied structures. */ + /*-----------------------------------------------------------------*/ + bytes += structCopySize; + + cif->flags = flags; + cif->bytes = bytes; + + return FFI_OK; +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_call. */ +/* */ +/* Function - Call the FFI routine. */ +/* */ +/*====================================================================*/ + +void +ffi_call(ffi_cif *cif, + void (*fn)(), + void *rvalue, + void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /*-----------------------------------------------------------------*/ + /* 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->rtype->type == FFI_TYPE_STRUCT)) + ecif.rvalue = alloca(cif->rtype->size); + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV(ffi_prep_args, + &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; + + default: + FFI_ASSERT(0); + break; + } +} + +/*======================== End of Routine ============================*/ diff --git a/libffi/s390/sysv.S b/libffi/s390/sysv.S new file mode 100644 index 00000000..afaf1ea1 --- /dev/null +++ b/libffi/s390/sysv.S @@ -0,0 +1,161 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2000 Software AG + + S390 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 CYGNUS SOLUTIONS 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 +#ifdef HAVE_MACHINE_ASM_H +#include +#endif + +.text + + # r2: ffi_prep_args + # r3: &ecif + # r4: cif->bytes + # r5: fig->flags + # r6: ecif.rvalue + # sp+0: fn + + # This assumes we are using gas. + .globl ffi_call_SYSV + .type ffi_call_SYSV,%function +ffi_call_SYSV: + # Save registers + stm %r7,%r15,28(%r15) + l %r7,96(%r15) # Get A(fn) + lr %r0,%r15 + ahi %r15,-128 # Make room for my args + st %r0,0(%r15) # Set backchain + lr %r11,%r15 # Establish my stack register + sr %r15,%r4 # Make room for fn args + ahi %r15,-96 # Make room for new frame + lr %r10,%r15 # Establish stack build area + ahi %r15,-96 # Stack for next call + lr %r1,%r7 + stm %r2,%r7,96(%r11) # Save args on my stack + +#------------------------------------------------------------------ +# move first 3 parameters in registers +#------------------------------------------------------------------ + lr %r9,%r2 # r9: &ffi_prep_args + lr %r2,%r10 # Parm 1: &stack Parm 2: &ecif + basr %r14,%r9 # call ffi_prep_args + +#------------------------------------------------------------------ +# load first 5 parameter registers +#------------------------------------------------------------------ + lm %r2,%r6,24(%r10) + +#------------------------------------------------------------------ +# load fp parameter registers +#------------------------------------------------------------------ + ld %f0,48(%r10) + ld %f2,56(%r10) + +#------------------------------------------------------------------ +# call function +#------------------------------------------------------------------ + lr %r15,%r10 # Set new stack + l %r9,116(%r11) # Get &fn + basr %r14,%r9 # Call function + +#------------------------------------------------------------------ +# On return: +# r2: Return value (r3: Return value + 4 for long long) +#------------------------------------------------------------------ + +#------------------------------------------------------------------ +# If the return value pointer is NULL, assume no return value. +#------------------------------------------------------------------ + icm %r6,15,112(%r11) + jz .Lepilogue + + l %r5,108(%r11) # Get return type +#------------------------------------------------------------------ +# return INT +#------------------------------------------------------------------ + chi %r5,FFI_TYPE_INT + jne .Lchk64 + + st %r2,0(%r6) + j .Lepilogue + +.Lchk64: +#------------------------------------------------------------------ +# return LONG LONG (signed/unsigned) +#------------------------------------------------------------------ + chi %r5,FFI_TYPE_UINT64 + je .LdoLongLong + + chi %r5,FFI_TYPE_SINT64 + jne .LchkFloat + +.LdoLongLong: + stm %r2,%r3,0(%r6) + j .Lepilogue + +.LchkFloat: +#------------------------------------------------------------------ +# return FLOAT +#------------------------------------------------------------------ + chi %r5,FFI_TYPE_FLOAT + jne .LchkDouble + + std %f0,0(%r6) + j .Lepilogue + +.LchkDouble: +#------------------------------------------------------------------ +# return DOUBLE or LONGDOUBLE +#------------------------------------------------------------------ + chi %r5,FFI_TYPE_DOUBLE + jne .LchkStruct + + std %f0,0(%r6) + std %f2,8(%r6) + j .Lepilogue + +.LchkStruct: +#------------------------------------------------------------------ +# Structure - rvalue already set as sent as 1st parm to routine +#------------------------------------------------------------------ + chi %r5,FFI_TYPE_STRUCT + je .Lepilogue + +.Ldefault: +#------------------------------------------------------------------ +# return a pointer +#------------------------------------------------------------------ + st %r2,0(%r6) + j .Lepilogue + +.Lepilogue: + l %r15,0(%r11) + l %r4,56(%r15) + lm %r7,%r15,28(%r15) + br %r4 + +.ffi_call_SYSV_end: + .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV diff --git a/libffi/sparc/ffi.c b/libffi/sparc/ffi.c new file mode 100644 index 00000000..f557013a --- /dev/null +++ b/libffi/sparc/ffi.c @@ -0,0 +1,422 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996 Cygnus Solutions + + Sparc 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 CYGNUS SOLUTIONS 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 +#include + +#include + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +void ffi_prep_args_v8(char *stack, extended_cif *ecif) +{ + int i; + int tmp; + int avn; + void **p_argv; + char *argp; + ffi_type **p_arg; + + tmp = 0; + + /* Skip 16 words for the window save area */ + argp = stack + 16*sizeof(int); + + /* This should only really be done when we are returning a structure, + however, it's faster just to do it all the time... + + if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */ + *(int *) argp = (long)ecif->rvalue; + + /* And 1 word for the structure return value. */ + argp += sizeof(int); + +#ifdef USING_PURIFY + /* Purify will probably complain in our assembly routine, unless we + zero out this memory. */ + + ((int*)argp)[0] = 0; + ((int*)argp)[1] = 0; + ((int*)argp)[2] = 0; + ((int*)argp)[3] = 0; + ((int*)argp)[4] = 0; + ((int*)argp)[5] = 0; +#endif + + avn = ecif->cif->nargs; + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + i && avn; + i--, p_arg++) + { + size_t z; + + if (avn) + { + avn--; + if ((*p_arg)->type == FFI_TYPE_STRUCT +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || (*p_arg)->type == FFI_TYPE_LONGDOUBLE +#endif + ) + { + *(unsigned int *) argp = (unsigned long)(* p_argv); + z = sizeof(int); + } + else + { + z = (*p_arg)->size; + if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = *(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = *(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = *(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = *(UINT16 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else + { + memcpy(argp, *p_argv, z); + } + } + p_argv++; + argp += z; + } + } + + return; +} + +int ffi_prep_args_v9(char *stack, extended_cif *ecif) +{ + int i, ret = 0; + int tmp; + void **p_argv; + char *argp; + ffi_type **p_arg; + + tmp = 0; + + /* Skip 16 words for the window save area */ + argp = stack + 16*sizeof(long long); + +#ifdef USING_PURIFY + /* Purify will probably complain in our assembly routine, unless we + zero out this memory. */ + + ((long long*)argp)[0] = 0; + ((long long*)argp)[1] = 0; + ((long long*)argp)[2] = 0; + ((long long*)argp)[3] = 0; + ((long long*)argp)[4] = 0; + ((long long*)argp)[5] = 0; +#endif + + p_argv = ecif->avalue; + + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && + ecif->cif->rtype->size > 32) + { + *(unsigned long long *) argp = (unsigned long)ecif->rvalue; + tmp = 1; + } + + for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; + i++, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + switch ((*p_arg)->type) + { + case FFI_TYPE_STRUCT: + if (z > 16) + { + /* For structures larger than 16 bytes we pass reference. */ + *(unsigned long long *) argp = (unsigned long)* p_argv; + argp += sizeof(long long); + tmp++; + p_argv++; + continue; + } + /* FALLTHROUGH */ + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + ret = 1; /* We should promote into FP regs as well as integer. */ + break; + } + if (z < sizeof(long long)) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed long long *) argp = *(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned long long *) argp = *(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed long long *) argp = *(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned long long *) argp = *(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_SINT32: + *(signed long long *) argp = *(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + *(unsigned long long *) argp = *(UINT32 *)(* p_argv); + break; + + case FFI_TYPE_FLOAT: + *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */ + break; + + case FFI_TYPE_STRUCT: + memcpy(argp, *p_argv, z); + break; + + default: + FFI_ASSERT(0); + } + z = sizeof(long long); + tmp++; + } + else if (z == sizeof(long long)) + { + memcpy(argp, *p_argv, z); + z = sizeof(long long); + tmp++; + } + else + { + if ((tmp & 1) && (*p_arg)->alignment > 8) + { + tmp++; + argp += sizeof(long long); + } + memcpy(argp, *p_argv, z); + z = 2 * sizeof(long long); + tmp += 2; + } + p_argv++; + argp += z; + } + + return ret; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + int wordsize; + + if (cif->abi != FFI_V9) + { + wordsize = 4; + + /* If we are returning a struct, this will already have been added. + Otherwise we need to add it because it's always got to be there! */ + + if (cif->rtype->type != FFI_TYPE_STRUCT) + cif->bytes += wordsize; + + /* sparc call frames require that space is allocated for 6 args, + even if they aren't used. Make that space if necessary. */ + + if (cif->bytes < 4*6+4) + cif->bytes = 4*6+4; + } + else + { + wordsize = 8; + + /* sparc call frames require that space is allocated for 6 args, + even if they aren't used. Make that space if necessary. */ + + if (cif->bytes < 8*6) + cif->bytes = 8*6; + } + + /* Adjust cif->bytes. to include 16 words for the window save area, + and maybe the struct/union return pointer area, */ + + cif->bytes += 16 * wordsize; + + /* The stack must be 2 word aligned, so round bytes up + appropriately. */ + + cif->bytes = ALIGN(cif->bytes, 2 * wordsize); + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + cif->flags = cif->rtype->type; + break; + + case FFI_TYPE_STRUCT: + if (cif->abi == FFI_V9 && cif->rtype->size > 32) + cif->flags = FFI_TYPE_VOID; + else + cif->flags = FFI_TYPE_STRUCT; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + if (cif->abi != FFI_V9) + { + cif->flags = FFI_TYPE_SINT64; + break; + } + /* FALLTHROUGH */ + default: + cif->flags = FFI_TYPE_INT; + break; + } + return FFI_OK; +} + +int ffi_V9_return_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt) +{ + ffi_type **ptr = &arg->elements[0]; + + while (*ptr != NULL) + { + if (off & ((*ptr)->alignment - 1)) + off = ALIGN(off, (*ptr)->alignment); + + switch ((*ptr)->type) + { + case FFI_TYPE_STRUCT: + off = ffi_V9_return_struct(*ptr, off, ret, intg, flt); + break; + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + memcpy(ret + off, flt + off, (*ptr)->size); + off += (*ptr)->size; + break; + default: + memcpy(ret + off, intg + off, (*ptr)->size); + off += (*ptr)->size; + break; + } + ptr++; + } + return off; +} + +extern int ffi_call_V8(void *, extended_cif *, unsigned, + unsigned, unsigned *, void (*fn)()); +extern int ffi_call_V9(void *, extended_cif *, unsigned, + unsigned, unsigned *, void (*fn)()); + +void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) +{ + extended_cif ecif; + void *rval = rvalue; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + ecif.rvalue = rvalue; + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + if (cif->rtype->size <= 32) + rval = alloca(64); + else + { + rval = NULL; + if (rvalue == NULL) + ecif.rvalue = alloca(cif->rtype->size); + } + } + + switch (cif->abi) + { + case FFI_V8: +#ifdef SPARC64 + /* We don't yet support calling 32bit code from 64bit */ + FFI_ASSERT(0); +#else + ffi_call_V8(ffi_prep_args_v8, &ecif, cif->bytes, + cif->flags, rvalue, fn); +#endif + break; + case FFI_V9: +#ifdef SPARC64 + ffi_call_V9(ffi_prep_args_v9, &ecif, cif->bytes, + cif->flags, rval, fn); + if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT) + ffi_V9_return_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32); +#else + /* And vice versa */ + FFI_ASSERT(0); +#endif + break; + default: + FFI_ASSERT(0); + break; + } + +} diff --git a/libffi/sparc/v8.S b/libffi/sparc/v8.S new file mode 100644 index 00000000..0357f4de --- /dev/null +++ b/libffi/sparc/v8.S @@ -0,0 +1,93 @@ +/* ----------------------------------------------------------------------- + v8.S - Copyright (c) 1996, 1997 Cygnus Solutions + + Sparc 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 CYGNUS SOLUTIONS 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 + +#define STACKFRAME 96 /* Minimum stack framesize for SPARC */ +#define ARGS (64+4) /* Offset of register area in frame */ + +.text + .align 8 +.globl ffi_call_V8 +.globl _ffi_call_V8 + +ffi_call_V8: +_ffi_call_V8: + save %sp, -STACKFRAME, %sp + + sub %sp, %i2, %sp ! alloca() space in stack for frame to set up + add %sp, STACKFRAME, %l0 ! %l0 has start of + ! frame to set up + + mov %l0, %o0 ! call routine to set up frame + call %i0 + mov %i1, %o1 ! (delay) + + ld [%l0+ARGS], %o0 ! call foreign function + ld [%l0+ARGS+4], %o1 + ld [%l0+ARGS+8], %o2 + ld [%l0+ARGS+12], %o3 + ld [%l0+ARGS+16], %o4 + ld [%l0+ARGS+20], %o5 + call %i5 + mov %l0, %sp ! (delay) switch to frame + nop ! STRUCT returning functions skip 12 instead of 8 bytes + + ! If the return value pointer is NULL, assume no return value. + tst %i4 + bz done + nop + + cmp %i3, FFI_TYPE_INT + be,a done + st %o0, [%i4] ! (delay) + + cmp %i3, FFI_TYPE_FLOAT + be,a done + st %f0, [%i4+0] ! (delay) + + cmp %i3, FFI_TYPE_SINT64 + be longlong + + cmp %i3, FFI_TYPE_DOUBLE + bne done + nop + st %f0, [%i4+0] + st %f1, [%i4+4] + +done: + ret + restore + +longlong: + st %o0, [%i4+0] + st %o1, [%i4+4] + ret + restore + +.ffi_call_V8_end: + .size ffi_call_V8,.ffi_call_V8_end-ffi_call_V8 + diff --git a/libffi/sparc/v9.S b/libffi/sparc/v9.S new file mode 100644 index 00000000..c937f439 --- /dev/null +++ b/libffi/sparc/v9.S @@ -0,0 +1,125 @@ +/* ----------------------------------------------------------------------- + v9.S - Copyright (c) 2000 Cygnus Solutions + + Sparc 64bit 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 CYGNUS SOLUTIONS 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 + +#ifdef SPARC64 +/* Only compile this in for 64bit builds, because otherwise the object file + will have inproper architecture due to used instructions. */ + +#define STACKFRAME 128 /* Minimum stack framesize for SPARC */ +#define STACK_BIAS 2047 +#define ARGS (128) /* Offset of register area in frame */ + +.text + .align 8 +.globl ffi_call_V9 +.globl _ffi_call_V9 + +ffi_call_V9: +_ffi_call_V9: + save %sp, -STACKFRAME, %sp + + sub %sp, %i2, %sp ! alloca() space in stack for frame to set up + add %sp, STACKFRAME+STACK_BIAS, %l0 ! %l0 has start of + ! frame to set up + + mov %l0, %o0 ! call routine to set up frame + call %i0 + mov %i1, %o1 ! (delay) + brz,pt %o0, 1f + ldx [%l0+ARGS], %o0 ! call foreign function + + ldd [%l0+ARGS], %f0 + ldd [%l0+ARGS+8], %f2 + ldd [%l0+ARGS+16], %f4 + ldd [%l0+ARGS+24], %f6 + ldd [%l0+ARGS+32], %f8 + ldd [%l0+ARGS+40], %f10 + ldd [%l0+ARGS+48], %f12 + ldd [%l0+ARGS+56], %f14 + ldd [%l0+ARGS+64], %f16 + ldd [%l0+ARGS+72], %f18 + ldd [%l0+ARGS+80], %f20 + ldd [%l0+ARGS+88], %f22 + ldd [%l0+ARGS+96], %f24 + ldd [%l0+ARGS+104], %f26 + ldd [%l0+ARGS+112], %f28 + ldd [%l0+ARGS+120], %f30 + +1: ldx [%l0+ARGS+8], %o1 + ldx [%l0+ARGS+16], %o2 + ldx [%l0+ARGS+24], %o3 + ldx [%l0+ARGS+32], %o4 + ldx [%l0+ARGS+40], %o5 + call %i5 + sub %l0, STACK_BIAS, %sp ! (delay) switch to frame + + ! If the return value pointer is NULL, assume no return value. + brz,pn %i4, done + nop + + cmp %i3, FFI_TYPE_INT + be,a,pt %icc, done + stx %o0, [%i4] ! (delay) + + cmp %i3, FFI_TYPE_FLOAT + be,a,pn %icc, done + st %f0, [%i4+0] ! (delay) + + cmp %i3, FFI_TYPE_DOUBLE + be,a,pn %icc, done + std %f0, [%i4+0] ! (delay) + + cmp %i3, FFI_TYPE_STRUCT + be,pn %icc, dostruct + + cmp %i3, FFI_TYPE_LONGDOUBLE + bne,pt %icc, done + nop + std %f0, [%i4+0] + std %f2, [%i4+8] + +done: ret + restore + +dostruct: + /* This will not work correctly for unions. */ + stx %o0, [%i4+0] + stx %o1, [%i4+8] + stx %o2, [%i4+16] + stx %o3, [%i4+24] + std %f0, [%i4+32] + std %f2, [%i4+40] + std %f4, [%i4+48] + std %f6, [%i4+56] + ret + restore + +.ffi_call_V9_end: + .size ffi_call_V9,.ffi_call_V9_end-ffi_call_V9 + +#endif diff --git a/libffi/testsuite/Makefile.am b/libffi/testsuite/Makefile.am new file mode 100644 index 00000000..67bce5c3 --- /dev/null +++ b/libffi/testsuite/Makefile.am @@ -0,0 +1,15 @@ +## Process this file with automake to produce Makefile.in. + +AUTOMAKE_OPTIONS = foreign dejagnu + +# Setup the testing framework, if you have one +EXPECT = `if [ -f $(top_builddir)/../expect/expect ] ; then \ + echo $(top_builddir)/../expect/expect ; \ + else echo expect ; fi` + +RUNTEST = `if [ -f $(top_srcdir)/../dejagnu/runtest ] ; then \ + echo $(top_srcdir)/../dejagnu/runtest ; \ + else echo runtest; fi` + +RUNTESTFLAGS = @AM_RUNTESTFLAGS@ + diff --git a/libffi/testsuite/Makefile.in b/libffi/testsuite/Makefile.in new file mode 100644 index 00000000..4d3bdbc0 --- /dev/null +++ b/libffi/testsuite/Makefile.in @@ -0,0 +1,228 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +AM_RUNTESTFLAGS = @AM_RUNTESTFLAGS@ +AS = @AS@ +CC = @CC@ +DLLTOOL = @DLLTOOL@ +EXEEXT = @EXEEXT@ +LD = @LD@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +NM = @NM@ +OBJDUMP = @OBJDUMP@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +SHELL = @SHELL@ +TARGET = @TARGET@ +TARGETDIR = @TARGETDIR@ +VERSION = @VERSION@ +libffi_basedir = @libffi_basedir@ + +AUTOMAKE_OPTIONS = foreign dejagnu + +# Setup the testing framework, if you have one +EXPECT = `if [ -f $(top_builddir)/../expect/expect ] ; then echo $(top_builddir)/../expect/expect ; else echo expect ; fi` + + +RUNTEST = `if [ -f $(top_srcdir)/../dejagnu/runtest ] ; then echo $(top_srcdir)/../dejagnu/runtest ; else echo runtest; fi` + + +RUNTESTFLAGS = @AM_RUNTESTFLAGS@ +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../fficonfig.h +CONFIG_CLEAN_FILES = +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = testsuite + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign testsuite/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +DEJATOOL = $(PACKAGE) + +RUNTESTDEFAULTFLAGS = --tool $(DEJATOOL) --srcdir $$srcdir + +check-DEJAGNU: site.exp + srcdir=`cd $(srcdir) && pwd`; export srcdir; \ + EXPECT=$(EXPECT); export EXPECT; \ + runtest=$(RUNTEST); \ + if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \ + $$runtest $(RUNTESTDEFAULTFLAGS) $(RUNTESTFLAGS); \ + else echo "WARNING: could not find \`runtest'" 1>&2; :;\ + fi +site.exp: Makefile + @echo 'Making a new site.exp file...' + @test ! -f site.bak || rm -f site.bak + @echo '## these variables are automatically generated by make ##' > $@-t + @echo '# Do not edit here. If you wish to override these values' >> $@-t + @echo '# edit the last section' >> $@-t + @echo 'set tool $(DEJATOOL)' >> $@-t + @echo 'set srcdir $(srcdir)' >> $@-t + @echo 'set objdir' `pwd` >> $@-t + @echo 'set host_alias $(host_alias)' >> $@-t + @echo 'set host_triplet $(host_triplet)' >> $@-t + @echo '## All variables above are generated by configure. Do Not Edit ##' >> $@-t + @test ! -f site.exp || sed '1,/^## All variables above are.*##/ d' site.exp >> $@-t + @test ! -f site.exp || mv site.exp site.bak + @mv $@-t site.exp +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-generic clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: tags distdir check-DEJAGNU info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libffi/testsuite/config/default.exp b/libffi/testsuite/config/default.exp new file mode 100644 index 00000000..90967ccc --- /dev/null +++ b/libffi/testsuite/config/default.exp @@ -0,0 +1 @@ +load_lib "standard.exp" diff --git a/libffi/testsuite/lib/libffi.exp b/libffi/testsuite/lib/libffi.exp new file mode 100644 index 00000000..58c5408a --- /dev/null +++ b/libffi/testsuite/lib/libffi.exp @@ -0,0 +1,44 @@ +# Copyright (C) 2001 Red Hat, Inc. + +load_lib "libgloss.exp" + +global tmpdir + +if ![info exists tmpdir] { + set tmpdir "/tmp" +} + +proc test_libffi {src} { + + global tmpdir srcdir + + set executable $tmpdir/[file tail [file rootname $src].x] + + regsub "^$srcdir/?" $src "" testcase + # If we couldn't rip $srcdir out of `src' then just do the best we can. + # The point is to reduce the unnecessary noise in the logs. Don't strip + # out too much because different testcases with the same name can confuse + # `test-tool'. + if [string match "/*" $testcase] { + set testcase "[file tail [file dirname $src]]/[file tail $src]" + } + + remote_file build delete $executable; + verbose "Testing $testcase" 1 + + set comp_output [target_compile $src $executable executable "additional_flags=-g additional_flags=-I$srcdir/../include libs=../.libs/libffi.a"] + + set result [libffi_load "$executable" "" ""] + set status [lindex $result 0]; + set output [lindex $result 1]; + + $status "$testcase" + + if { $status == "pass" } { + remote_file build delete $executable; + } +} + +# Local Variables: +# tcl-indent-level:4 +# End: diff --git a/libffi/testsuite/libffi.call/call.exp b/libffi/testsuite/libffi.call/call.exp new file mode 100644 index 00000000..58be0ade --- /dev/null +++ b/libffi/testsuite/libffi.call/call.exp @@ -0,0 +1,13 @@ +global srcdir subdir + +catch "glob -nocomplain ${srcdir}/${subdir}/*.c" srcfiles +verbose "srcfiles are $srcfiles" + +set prefix "" +foreach x $srcfiles { + test_libffi $x +} + +# Local Variables: +# tcl-indent-level:4 +# End: diff --git a/libffi/testsuite/libffi.call/ffitest.h b/libffi/testsuite/libffi.call/ffitest.h new file mode 100644 index 00000000..42cb46f2 --- /dev/null +++ b/libffi/testsuite/libffi.call/ffitest.h @@ -0,0 +1,4 @@ +#include + +#define CHECK(x) !(x) ? abort() : 0 + diff --git a/libffi/testsuite/libffi.call/float.c b/libffi/testsuite/libffi.call/float.c new file mode 100644 index 00000000..95e7a31e --- /dev/null +++ b/libffi/testsuite/libffi.call/float.c @@ -0,0 +1,55 @@ +#include "ffitest.h" + +static int floating(int a, float b, double c, long double d, int e) +{ + int i; + + i = (int) ((float)a/b + ((float)c/(float)d)); + + return i; +} + +int +main () +{ + ffi_cif cif; + ffi_type *args[5]; + void *values[5]; + int si1, si2; + float f; + double d; + long double ld; + int rint __attribute__((aligned(8))); + + args[0] = &ffi_type_sint; + values[0] = &si1; + args[1] = &ffi_type_float; + values[1] = &f; + args[2] = &ffi_type_double; + values[2] = &d; + args[3] = &ffi_type_longdouble; + values[3] = &ld; + args[4] = &ffi_type_sint; + values[4] = &si2; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 5, + &ffi_type_sint, args) == FFI_OK); + + si1 = 6; + f = 3.14159; + d = (double)1.0/(double)3.0; + ld = 2.71828182846L; + si2 = 10; + + floating (si1, f, d, ld, si2); + + ffi_call(&cif, FFI_FN(floating), &rint, values); + + printf ("%d vs %d\n", rint, floating (si1, f, d, ld, si2)); + + CHECK(rint == floating(si1, f, d, ld, si2)); + + exit (0); +} + diff --git a/libffi/testsuite/libffi.call/many.c b/libffi/testsuite/libffi.call/many.c new file mode 100644 index 00000000..01a21381 --- /dev/null +++ b/libffi/testsuite/libffi.call/many.c @@ -0,0 +1,63 @@ +#include "ffitest.h" + +#include + +static float many(float f1, + float f2, + float f3, + float f4, + float f5, + float f6, + float f7, + float f8, + float f9, + float f10, + float f11, + float f12, + float f13) +{ +#if 0 + printf("%f %f %f %f %f %f %f %f %f %f %f %f %f\n", + (double) f1, (double) f2, (double) f3, (double) f4, (double) f5, + (double) f6, (double) f7, (double) f8, (double) f9, (double) f10, + (double) f11, (double) f12, (double) f13); +#endif + + return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13); +} + +int +main () +{ + ffi_cif cif; + ffi_type *args[13]; + void *values[13]; + float fa[13]; + float f, ff; + int i; + + for (i = 0; i < 13; i++) + { + args[i] = &ffi_type_float; + values[i] = &fa[i]; + fa[i] = (float) i; + } + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13, + &ffi_type_float, args) == FFI_OK); + + ffi_call(&cif, FFI_FN(many), &f, values); + + ff = many(fa[0], fa[1], + fa[2], fa[3], + fa[4], fa[5], + fa[6], fa[7], + fa[8], fa[9], + fa[10],fa[11],fa[12]); + + if (f - ff < FLT_EPSILON) + exit(0); + else + abort(); + } diff --git a/libffi/testsuite/libffi.call/strlen.c b/libffi/testsuite/libffi.call/strlen.c new file mode 100644 index 00000000..35172784 --- /dev/null +++ b/libffi/testsuite/libffi.call/strlen.c @@ -0,0 +1,38 @@ +#include "ffitest.h" + +static size_t my_strlen(char *s) +{ + return (strlen(s)); +} + +int +main () +{ + ffi_cif cif; + ffi_type *args[1]; + void *values[1]; + int rint __attribute__((aligned(8))); + char *s; + + args[0] = &ffi_type_pointer; + values[0] = (void*) &s; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_sint, args) == FFI_OK); + + s = "a"; + ffi_call(&cif, FFI_FN(my_strlen), &rint, values); + CHECK(rint == 1); + + s = "1234567"; + ffi_call(&cif, FFI_FN(my_strlen), &rint, values); + CHECK(rint == 7); + + s = "1234567890123456789012345"; + ffi_call(&cif, FFI_FN(my_strlen), &rint, values); + CHECK(rint == 25); + + exit (0); +} + diff --git a/libffi/x86/ffi.c b/libffi/x86/ffi.c new file mode 100644 index 00000000..830d6a12 --- /dev/null +++ b/libffi/x86/ffi.c @@ -0,0 +1,509 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996, 1998, 1999 Cygnus Solutions + + x86 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 CYGNUS SOLUTIONS 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 +#include +#include + +#include + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +/*@-exportheader@*/ +void ffi_prep_args(char *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ + register unsigned int i; + register int tmp; + register unsigned int avn; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + tmp = 0; + argp = stack; + + if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) { + *(void **) argp = ecif->rvalue; + argp += 4; + } + + avn = ecif->cif->nargs; + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0) && (avn != 0); + i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if (((*p_arg)->alignment - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, (*p_arg)->alignment); + } + + if (avn != 0) + { + avn--; + z = (*p_arg)->size; + 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); + break; + + case FFI_TYPE_SINT32: + *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + } + } + + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + case FFI_TYPE_SINT64: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_UINT64: + cif->flags = FFI_TYPE_SINT64; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* 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->rtype->type == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; + default: + FFI_ASSERT(0); + break; + } +} + + +/** private members **/ + +static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, + void** args, ffi_cif* cif); +static void ffi_closure_SYSV (); +static void ffi_closure_raw_SYSV (); + +/* This function is jumped to by the trampoline, on entry, %ecx (a + * caller-save register) holds the address of the closure. + * Clearly, this requires __GNUC__, so perhaps we should translate this + * into an assembly file if this is to be distributed with ffi. + */ + +static void +ffi_closure_SYSV () +{ + // this is our return value storage + long double res; + + // our various things... + void *args; + ffi_cif *cif; + void **arg_area; + ffi_closure *closure; + unsigned short rtype; + void *resp = (void*)&res; + + /* grab the trampoline context pointer */ + asm ("movl %%ecx,%0" : "=r" (closure)); + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + asm ("leal 8(%%ebp),%0" : "=q" (args)); + + /* 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, (void**)&resp, arg_area, cif); + + (closure->fun) (cif, resp, arg_area, closure->user_data); + + rtype = cif->flags; + + /* now, do a generic return based on the value of rtype */ + if (rtype == FFI_TYPE_INT) + { + asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); + } + else if (rtype == FFI_TYPE_FLOAT) + { + asm ("flds (%0)" : : "r" (resp) : "st" ); + } + else if (rtype == FFI_TYPE_DOUBLE) + { + asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (rtype == FFI_TYPE_LONGDOUBLE) + { + asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (rtype == FFI_TYPE_SINT64) + { + asm ("movl 0(%0),%%eax;" + "movl 4(%0),%%edx" + : : "r"(resp) + : "eax", "edx"); + } +} + +/*@-exportheader@*/ +static void +ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, + void **avalue, ffi_cif *cif) +/*@=exportheader@*/ +{ + register unsigned int i; + register int tmp; + register unsigned int avn; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + tmp = 0; + argp = stack; + + if ( cif->rtype->type == FFI_TYPE_STRUCT ) { + *rvalue = *(void **) argp; + argp += 4; + } + + avn = cif->nargs; + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; + (i != 0) && (avn != 0); + i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if (((*p_arg)->alignment - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, (*p_arg)->alignment); + } + + if (avn != 0) + { + avn--; + z = (*p_arg)->size; + + /* because we're little endian, this is + what it turns into. */ + + *p_argv = (void*) argp; + + p_argv++; + argp += z; + } + } + + return; +} + +/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ + +#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ +({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + unsigned int __fun = (unsigned int)(FUN); \ + unsigned int __ctx = (unsigned int)(CTX); \ + unsigned int __dis = __fun - ((unsigned int) __tramp + 10); \ + *(unsigned char*) &__tramp[0] = 0xb9; \ + *(unsigned int*) &__tramp[1] = __ctx; \ + *(unsigned char*) &__tramp[5] = 0xe9; \ + *(unsigned int*) &__tramp[6] = __dis; \ + }) + + +/* the cif must already be prep'ed */ + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data) +{ + FFI_ASSERT (cif->abi == FFI_SYSV); + + FFI_INIT_TRAMPOLINE (&closure->tramp[0], \ + &ffi_closure_SYSV, \ + (void*)closure); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +/* ------- Native raw API support -------------------------------- */ + +#if !FFI_NO_RAW_API + +static void +ffi_closure_raw_SYSV () +{ + // this is our return value storage + long double res; + + // our various things... + void *args; + ffi_raw *raw_args; + ffi_cif *cif; + ffi_raw_closure *closure; + unsigned short rtype; + void *resp = (void*)&res; + + /* grab the trampoline context pointer */ + asm ("movl %%ecx,%0" : "=r" (closure)); + + /* take the argument pointer */ + asm ("leal 8(%%ebp),%0" : "=q" (args)); + + /* get the cif */ + cif = closure->cif; + + /* the SYSV/X86 abi matches the RAW API exactly, well.. almost */ + raw_args = (ffi_raw*) args; + + (closure->fun) (cif, resp, raw_args, closure->user_data); + + rtype = cif->flags; + + /* now, do a generic return based on the value of rtype */ + if (rtype == FFI_TYPE_INT) + { + asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); + } + else if (rtype == FFI_TYPE_FLOAT) + { + asm ("flds (%0)" : : "r" (resp) : "st" ); + } + else if (rtype == FFI_TYPE_DOUBLE) + { + asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (rtype == FFI_TYPE_LONGDOUBLE) + { + asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (rtype == FFI_TYPE_SINT64) + { + asm ("movl 0(%0),%%eax; movl 4(%0),%%edx" + : : "r"(resp) + : "eax", "edx"); + } +} + + + + +ffi_status +ffi_prep_raw_closure (ffi_raw_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data) +{ + int i; + + FFI_ASSERT (cif->abi == FFI_SYSV); + + // we currently don't support certain kinds of arguments for raw + // closures. This should be implemented by a seperate assembly language + // routine, since it would require argument processing, something we + // don't do now for performance. + + for (i = cif->nargs-1; i >= 0; i--) + { + FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT); + FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE); + } + + + FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV, + (void*)closure); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +static void +ffi_prep_args_raw(char *stack, extended_cif *ecif) +{ + memcpy (stack, ecif->avalue, ecif->cif->bytes); +} + +/* we borrow this routine from libffi (it must be changed, though, to + * actually call the function passed in the first argument. as of + * libffi-1.20, this is not the case.) + */ + +extern void +ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); + +void +ffi_raw_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ ffi_raw *fake_avalue) +{ + extended_cif ecif; + void **avalue = (void **)fake_avalue; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* 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->rtype->type == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; + default: + FFI_ASSERT(0); + break; + } +} + +#endif diff --git a/libffi/x86/sysv.S b/libffi/x86/sysv.S new file mode 100644 index 00000000..c7a78127 --- /dev/null +++ b/libffi/x86/sysv.S @@ -0,0 +1,167 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 1996, 1998 Cygnus Solutions + + X86 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 CYGNUS SOLUTIONS 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 +#include + +.text + +.globl ffi_prep_args + + # This assumes we are using gas. + .balign 16 +.globl ffi_call_SYSV + .type ffi_call_SYSV,@function + +ffi_call_SYSV: +.LFB1: + pushl %ebp +.LCFI0: + movl %esp,%ebp +.LCFI1: + # Make room for all of the new args. + movl 16(%ebp),%ecx + subl %ecx,%esp + + movl %esp,%eax + + # Place all of the ffi_prep_args in position + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + # Return stack to previous state and call the function + addl $8,%esp + + call *28(%ebp) + + # Remove the space we pushed for the args + movl 16(%ebp),%ecx + addl %ecx,%esp + + # Load %ecx with the return type code + movl 20(%ebp),%ecx + + # If the return value pointer is NULL, assume no return value. + cmpl $0,24(%ebp) + jne retint + + # Even if there is no space for the return value, we are + # obliged to handle floating-point values. + cmpl $FFI_TYPE_FLOAT,%ecx + jne noretval + fstp %st(0) + + jmp epilogue + +retint: + cmpl $FFI_TYPE_INT,%ecx + jne retfloat + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + jmp epilogue + +retfloat: + cmpl $FFI_TYPE_FLOAT,%ecx + jne retdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstps (%ecx) + jmp epilogue + +retdouble: + cmpl $FFI_TYPE_DOUBLE,%ecx + jne retlongdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp epilogue + +retlongdouble: + cmpl $FFI_TYPE_LONGDOUBLE,%ecx + jne retint64 + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp epilogue + +retint64: + cmpl $FFI_TYPE_SINT64,%ecx + jne retstruct + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + +retstruct: + # Nothing to do! + +noretval: +epilogue: + movl %ebp,%esp + popl %ebp + ret +.LFE1: +.ffi_call_SYSV_end: + .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV + +.section .eh_frame,"aw",@progbits +__FRAME_BEGIN__: + .4byte .LLCIE1 +.LSCIE1: + .4byte 0x0 + .byte 0x1 + .byte 0x0 + .byte 0x1 + .byte 0x7c + .byte 0x8 + .byte 0xc + .byte 0x4 + .byte 0x4 + .byte 0x88 + .byte 0x1 + .align 4 +.LECIE1: + .set .LLCIE1,.LECIE1-.LSCIE1 + .4byte .LLFDE1 +.LSFDE1: + .4byte .LSFDE1-__FRAME_BEGIN__ + .4byte .LFB1 + .4byte .LFE1-.LFB1 + .byte 0x4 + .4byte .LCFI0-.LFB1 + .byte 0xe + .byte 0x8 + .byte 0x85 + .byte 0x2 + .byte 0x4 + .4byte .LCFI1-.LCFI0 + .byte 0xd + .byte 0x5 + .align 4 +.LEFDE1: + .set .LLFDE1,.LEFDE1-.LSFDE1 diff --git a/libffi/x86/win32.S b/libffi/x86/win32.S new file mode 100644 index 00000000..520d1fc0 --- /dev/null +++ b/libffi/x86/win32.S @@ -0,0 +1,125 @@ +/* ----------------------------------------------------------------------- + win32.S - Copyright (c) 1996, 1998, 2001 Cygnus Solutions + + X86 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 CYGNUS SOLUTIONS 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 + +.text + +.globl ffi_prep_args + + # This assumes we are using gas. + .balign 16 +.globl _ffi_call_SYSV + +_ffi_call_SYSV: + pushl %ebp + movl %esp,%ebp + + # Make room for all of the new args. + movl 16(%ebp),%ecx + subl %ecx,%esp + + movl %esp,%eax + + # Place all of the ffi_prep_args in position + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + # Return stack to previous state and call the function + addl $8,%esp + + call *28(%ebp) + + # Remove the space we pushed for the args + movl 16(%ebp),%ecx + addl %ecx,%esp + + # Load %ecx with the return type code + movl 20(%ebp),%ecx + + # If the return value pointer is NULL, assume no return value. + cmpl $0,24(%ebp) + jne retint + + # Even if there is no space for the return value, we are + # obliged to handle floating-point values. + cmpl $FFI_TYPE_FLOAT,%ecx + jne noretval + fstp %st(0) + + jmp epilogue + +retint: + cmpl $FFI_TYPE_INT,%ecx + jne retfloat + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + jmp epilogue + +retfloat: + cmpl $FFI_TYPE_FLOAT,%ecx + jne retdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstps (%ecx) + jmp epilogue + +retdouble: + cmpl $FFI_TYPE_DOUBLE,%ecx + jne retlongdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp epilogue + +retlongdouble: + cmpl $FFI_TYPE_LONGDOUBLE,%ecx + jne retint64 + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp epilogue + +retint64: + cmpl $FFI_TYPE_SINT64,%ecx + jne retstruct + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + +retstruct: + # Nothing to do! + +noretval: +epilogue: + movl %ebp,%esp + popl %ebp + ret + +.ffi_call_SYSV_end: