diff options
-rw-r--r-- | libffi/ChangeLog | 33 | ||||
-rw-r--r-- | libffi/Makefile.am | 2 | ||||
-rw-r--r-- | libffi/Makefile.in | 5 | ||||
-rwxr-xr-x | libffi/configure | 2 | ||||
-rw-r--r-- | libffi/configure.ac | 2 | ||||
-rw-r--r-- | libffi/fficonfig.h.in | 7 | ||||
-rw-r--r-- | libffi/src/mips/ffi.c | 369 | ||||
-rw-r--r-- | libffi/src/mips/ffitarget.h | 46 | ||||
-rw-r--r-- | libffi/src/mips/n32.S | 226 | ||||
-rw-r--r-- | libffi/src/mips/o32.S | 39 |
10 files changed, 635 insertions, 96 deletions
diff --git a/libffi/ChangeLog b/libffi/ChangeLog index 947621fc249..8a3ddc98f6d 100644 --- a/libffi/ChangeLog +++ b/libffi/ChangeLog @@ -1,3 +1,36 @@ +2007-08-10 David Daney <ddaney@avtrex.com> + + PR libffi/28313 + * configure.ac: Don't treat mips64 as a special case. + * Makefile.am (nodist_libffi_la_SOURCES): Add n32.S. + * configure: Regenerate + * Makefile.in: Ditto. + * fficonfig.h.in: Ditto. + * src/mips/ffitarget.h (REG_L, REG_S, SUBU, ADDU, SRL, LI): Indent. + (LA, EH_FRAME_ALIGN, FDE_ADDR_BYTES): New preprocessor macros. + (FFI_DEFAULT_ABI): Set for n64 case. + (FFI_CLOSURES, FFI_TRAMPOLINE_SIZE): Define for n32 and n64 cases. + * src/mips/n32.S (ffi_call_N32): Add debug macros and labels for FDE. + (ffi_closure_N32): New function. + (.eh_frame): New section + * src/mips/o32.S: Clean up comments. + (ffi_closure_O32): Pass ffi_closure parameter in $12. + * src/mips/ffi.c: Use FFI_MIPS_N32 instead of + _MIPS_SIM == _ABIN32 throughout. + (FFI_MIPS_STOP_HERE): New, use in place of + ffi_stop_here. + (ffi_prep_args): Use unsigned long to hold pointer values. Rewrite + to support n32/n64 ABIs. + (calc_n32_struct_flags): Rewrite. + (calc_n32_return_struct_flags): Remove unused variable. Reverse + position of flag bits. + (ffi_prep_cif_machdep): Rewrite n32 portion. + (ffi_call): Enable for n64. Add special handling for small structure + return values. + (ffi_prep_closure_loc): Add n32 and n64 support. + (ffi_closure_mips_inner_O32): Add cast to silence warning. + (copy_struct_N32, ffi_closure_mips_inner_N32): New functions. + 2007-08-08 David Daney <ddaney@avtrex.com> * testsuite/libffi.call/ffitest.h (ffi_type_mylong): Remove definition. diff --git a/libffi/Makefile.am b/libffi/Makefile.am index 3000c9c2df7..2a2d174c492 100644 --- a/libffi/Makefile.am +++ b/libffi/Makefile.am @@ -88,7 +88,7 @@ if MIPS_IRIX nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S endif if MIPS_LINUX -nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S +nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S endif if X86 nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S diff --git a/libffi/Makefile.in b/libffi/Makefile.in index fc5539e992b..42a444d395f 100644 --- a/libffi/Makefile.in +++ b/libffi/Makefile.in @@ -38,7 +38,7 @@ build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @MIPS_IRIX_TRUE@am__append_1 = src/mips/ffi.c src/mips/o32.S src/mips/n32.S -@MIPS_LINUX_TRUE@am__append_2 = src/mips/ffi.c src/mips/o32.S +@MIPS_LINUX_TRUE@am__append_2 = src/mips/ffi.c src/mips/o32.S src/mips/n32.S @X86_TRUE@am__append_3 = src/x86/ffi.c src/x86/sysv.S @X86_WIN32_TRUE@am__append_4 = src/x86/ffi.c src/x86/win32.S @X86_DARWIN_TRUE@am__append_5 = src/x86/ffi.c src/x86/darwin.S src/x86/ffi64.c src/x86/darwin64.S @@ -97,7 +97,8 @@ am_libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo src/types.lo \ src/raw_api.lo src/java_raw_api.lo src/closures.lo @MIPS_IRIX_TRUE@am__objects_1 = src/mips/ffi.lo src/mips/o32.lo \ @MIPS_IRIX_TRUE@ src/mips/n32.lo -@MIPS_LINUX_TRUE@am__objects_2 = src/mips/ffi.lo src/mips/o32.lo +@MIPS_LINUX_TRUE@am__objects_2 = src/mips/ffi.lo src/mips/o32.lo \ +@MIPS_LINUX_TRUE@ src/mips/n32.lo @X86_TRUE@am__objects_3 = src/x86/ffi.lo src/x86/sysv.lo @X86_WIN32_TRUE@am__objects_4 = src/x86/ffi.lo src/x86/win32.lo @X86_DARWIN_TRUE@am__objects_5 = src/x86/ffi.lo src/x86/darwin.lo \ diff --git a/libffi/configure b/libffi/configure index 404475f353c..68165201f1e 100755 --- a/libffi/configure +++ b/libffi/configure @@ -10324,8 +10324,6 @@ case "$host" in TARGET=M68K; TARGETDIR=m68k ;; - mips64*-*) - ;; mips-sgi-irix5.* | mips-sgi-irix6.*) TARGET=MIPS_IRIX; TARGETDIR=mips ;; diff --git a/libffi/configure.ac b/libffi/configure.ac index 6c7a9d26969..e47013f39ab 100644 --- a/libffi/configure.ac +++ b/libffi/configure.ac @@ -94,8 +94,6 @@ case "$host" in TARGET=M68K; TARGETDIR=m68k ;; - mips64*-*) - ;; mips-sgi-irix5.* | mips-sgi-irix6.*) TARGET=MIPS_IRIX; TARGETDIR=mips ;; diff --git a/libffi/fficonfig.h.in b/libffi/fficonfig.h.in index d32d488ed12..e93cf8ae77b 100644 --- a/libffi/fficonfig.h.in +++ b/libffi/fficonfig.h.in @@ -37,6 +37,9 @@ */ #undef HAVE_AS_SPARC_UA_PCREL +/* Define to 1 if you have the <dlfcn.h> header file. */ +#undef HAVE_DLFCN_H + /* Define if __attribute__((visibility("hidden"))) is supported. */ #undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE @@ -91,6 +94,10 @@ /* Define to 1 if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + /* Define to 1 if your C compiler doesn't accept -c and -o together. */ #undef NO_MINUS_C_MINUS_O diff --git a/libffi/src/mips/ffi.c b/libffi/src/mips/ffi.c index 12b8b62bab9..cc2a42e7a9f 100644 --- a/libffi/src/mips/ffi.c +++ b/libffi/src/mips/ffi.c @@ -28,13 +28,19 @@ #include <stdlib.h> -#if _MIPS_SIM == _ABIN32 +#ifdef FFI_DEBUG +# define FFI_MIPS_STOP_HERE() ffi_stop_here() +#else +# define FFI_MIPS_STOP_HERE() do {} while(0) +#endif + +#ifdef FFI_MIPS_N32 #define FIX_ARGP \ FFI_ASSERT(argp <= &stack[bytes]); \ if (argp == &stack[bytes]) \ { \ argp = stack; \ - ffi_stop_here(); \ + FFI_MIPS_STOP_HERE(); \ } #else #define FIX_ARGP @@ -54,7 +60,7 @@ static void ffi_prep_args(char *stack, char *argp; ffi_type **p_arg; -#if _MIPS_SIM == _ABIN32 +#ifdef FFI_MIPS_N32 /* 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. */ @@ -68,7 +74,7 @@ static void ffi_prep_args(char *stack, memset(stack, 0, bytes); -#if _MIPS_SIM == _ABIN32 +#ifdef FFI_MIPS_N32 if ( ecif->cif->rstruct_flag != 0 ) #else if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) @@ -91,7 +97,7 @@ static void ffi_prep_args(char *stack, if (a < sizeof(ffi_arg)) a = sizeof(ffi_arg); - if ((a - 1) & (unsigned int) argp) + if ((a - 1) & (unsigned long) argp) { argp = (char *) ALIGN(argp, a); FIX_ARGP; @@ -100,9 +106,15 @@ static void ffi_prep_args(char *stack, z = (*p_arg)->size; if (z <= sizeof(ffi_arg)) { + int type = (*p_arg)->type; z = sizeof(ffi_arg); - switch ((*p_arg)->type) + /* The size of a pointer depends on the ABI */ + if (type == FFI_TYPE_POINTER) + type = + (ecif->cif->abi == FFI_N64) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32; + + switch (type) { case FFI_TYPE_SINT8: *(ffi_arg *)argp = *(SINT8 *)(* p_argv); @@ -125,7 +137,6 @@ static void ffi_prep_args(char *stack, break; case FFI_TYPE_UINT32: - case FFI_TYPE_POINTER: *(ffi_arg *)argp = *(UINT32 *)(* p_argv); break; @@ -134,8 +145,7 @@ static void ffi_prep_args(char *stack, *(float *) argp = *(float *)(* p_argv); break; - /* Handle small structures. */ - case FFI_TYPE_STRUCT: + /* Handle structures. */ default: memcpy(argp, *p_argv, (*p_arg)->size); break; @@ -143,12 +153,12 @@ static void ffi_prep_args(char *stack, } else { -#if _MIPS_SIM == _ABIO32 +#ifdef FFI_MIPS_O32 memcpy(argp, *p_argv, z); #else { - unsigned end = (unsigned) argp+z; - unsigned cap = (unsigned) stack+bytes; + unsigned long end = (unsigned long) argp + z; + unsigned long cap = (unsigned long) stack + bytes; /* Check if the data will fit within the register space. Handle it if it doesn't. */ @@ -157,12 +167,13 @@ static void ffi_prep_args(char *stack, memcpy(argp, *p_argv, z); else { - unsigned portion = end - cap; + unsigned long portion = cap - (unsigned long)argp; memcpy(argp, *p_argv, portion); argp = stack; - memcpy(argp, - (void*)((unsigned)(*p_argv)+portion), z - portion); + z -= portion; + memcpy(argp, (void*)((unsigned long)(*p_argv) + portion), + z); } } #endif @@ -173,7 +184,7 @@ static void ffi_prep_args(char *stack, } } -#if _MIPS_SIM == _ABIN32 +#ifdef FFI_MIPS_N32 /* 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 @@ -181,35 +192,41 @@ static void ffi_prep_args(char *stack, 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) +static unsigned +calc_n32_struct_flags(ffi_type *arg, unsigned *loc, unsigned *arg_reg) { unsigned flags = 0; unsigned index = 0; ffi_type *e; - while (e = arg->elements[index]) + while ((e = arg->elements[index])) { + /* Align this object. */ + *loc = ALIGN(*loc, e->alignment); if (e->type == FFI_TYPE_DOUBLE) { - flags += (FFI_TYPE_DOUBLE << *shift); - *shift += FFI_FLAG_BITS; + /* Already aligned to FFI_SIZEOF_ARG. */ + *arg_reg = *loc / FFI_SIZEOF_ARG; + if (*arg_reg > 7) + break; + flags += (FFI_TYPE_DOUBLE << (*arg_reg * FFI_FLAG_BITS)); + *loc += e->size; } - else if (e->type == FFI_TYPE_STRUCT) - flags += calc_n32_struct_flags(e, shift); else - *shift += FFI_FLAG_BITS; - + *loc += e->size; index++; } + /* Next Argument register at alignment of FFI_SIZEOF_ARG. */ + *arg_reg = ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; return flags; } -unsigned calc_n32_return_struct_flags(ffi_type *arg) +static unsigned +calc_n32_return_struct_flags(ffi_type *arg) { unsigned flags = 0; - unsigned index = 0; unsigned small = FFI_TYPE_SMALLSTRUCT; ffi_type *e; @@ -228,16 +245,16 @@ unsigned calc_n32_return_struct_flags(ffi_type *arg) e = arg->elements[0]; if (e->type == FFI_TYPE_DOUBLE) - flags = FFI_TYPE_DOUBLE << FFI_FLAG_BITS; + flags = FFI_TYPE_DOUBLE; else if (e->type == FFI_TYPE_FLOAT) - flags = FFI_TYPE_FLOAT << FFI_FLAG_BITS; + flags = FFI_TYPE_FLOAT; if (flags && (e = arg->elements[1])) { if (e->type == FFI_TYPE_DOUBLE) - flags += FFI_TYPE_DOUBLE; + flags += FFI_TYPE_DOUBLE << FFI_FLAG_BITS; else if (e->type == FFI_TYPE_FLOAT) - flags += FFI_TYPE_FLOAT; + flags += FFI_TYPE_FLOAT << FFI_FLAG_BITS; else return small; @@ -262,7 +279,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) { cif->flags = 0; -#if _MIPS_SIM == _ABIO32 +#ifdef FFI_MIPS_O32 /* Set the flags necessary for O32 processing. FFI_O32_SOFT_FLOAT * does not have special handling for floating point args. */ @@ -350,10 +367,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) } #endif -#if _MIPS_SIM == _ABIN32 +#ifdef FFI_MIPS_N32 /* Set the flags necessary for N32 processing */ { - unsigned shift = 0; + unsigned arg_reg = 0; + unsigned loc = 0; unsigned count = (cif->nargs < 8) ? cif->nargs : 8; unsigned index = 0; @@ -368,7 +386,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) /* This means that the structure is being passed as a hidden argument */ - shift = FFI_FLAG_BITS; + arg_reg = 1; count = (cif->nargs < 7) ? cif->nargs : 7; cif->rstruct_flag = !0; @@ -379,23 +397,37 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) else cif->rstruct_flag = 0; - while (count-- > 0) + while (count-- > 0 && arg_reg < 8) { 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; + cif->flags += + ((cif->arg_types)[index]->type << (arg_reg * FFI_FLAG_BITS)); + arg_reg++; break; + case FFI_TYPE_LONGDOUBLE: + /* Align it. */ + arg_reg = ALIGN(arg_reg, 2); + /* Treat it as two adjacent doubles. */ + cif->flags += + (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS)); + arg_reg++; + cif->flags += + (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS)); + arg_reg++; + break; case FFI_TYPE_STRUCT: + loc = arg_reg * FFI_SIZEOF_ARG; cif->flags += calc_n32_struct_flags((cif->arg_types)[index], - &shift); + &loc, &arg_reg); break; default: - shift += FFI_FLAG_BITS; + arg_reg++; + break; } index++; @@ -430,7 +462,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) 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; @@ -469,7 +501,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) switch (cif->abi) { -#if _MIPS_SIM == _ABIO32 +#ifdef FFI_MIPS_O32 case FFI_O32: case FFI_O32_SOFT_FLOAT: ffi_call_O32(ffi_prep_args, &ecif, cif->bytes, @@ -477,10 +509,25 @@ void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) break; #endif -#if _MIPS_SIM == _ABIN32 +#ifdef FFI_MIPS_N32 case FFI_N32: - ffi_call_N32(ffi_prep_args, &ecif, cif->bytes, - cif->flags, ecif.rvalue, fn); + case FFI_N64: + { + int copy_rvalue = 0; + void *rvalue_copy = ecif.rvalue; + if (cif->rtype->type == FFI_TYPE_STRUCT && cif->rtype->size < 16) + { + /* For structures smaller than 16 bytes we clobber memory + in 8 byte increments. Make a copy so we don't clobber + the callers memory outside of the struct bounds. */ + rvalue_copy = alloca(16); + copy_rvalue = 1; + } + ffi_call_N32(ffi_prep_args, &ecif, cif->bytes, + cif->flags, rvalue_copy, fn); + if (copy_rvalue) + memcpy(ecif.rvalue, rvalue_copy, cif->rtype->size); + } break; #endif @@ -490,9 +537,11 @@ void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) } } -#if FFI_CLOSURES /* N32 not implemented yet, FFI_CLOSURES not defined */ +#if FFI_CLOSURES #if defined(FFI_MIPS_O32) extern void ffi_closure_O32(void); +#else +extern void ffi_closure_N32(void); #endif /* FFI_MIPS_O32 */ ffi_status @@ -503,23 +552,58 @@ ffi_prep_closure_loc (ffi_closure *closure, void *codeloc) { unsigned int *tramp = (unsigned int *) &closure->tramp[0]; - unsigned int fn; - unsigned int ctx = (unsigned int) codeloc; + void * fn; char *clear_location = (char *) codeloc; #if defined(FFI_MIPS_O32) FFI_ASSERT(cif->abi == FFI_O32 || cif->abi == FFI_O32_SOFT_FLOAT); - fn = (unsigned int) ffi_closure_O32; + fn = ffi_closure_O32; #else /* FFI_MIPS_N32 */ - FFI_ASSERT(cif->abi == FFI_N32); - FFI_ASSERT(!"not implemented"); + FFI_ASSERT(cif->abi == FFI_N32 || cif->abi == FFI_N64); + fn = ffi_closure_N32; #endif /* FFI_MIPS_O32 */ - tramp[0] = 0x3c190000 | (fn >> 16); /* lui $25,high(fn) */ - tramp[1] = 0x37390000 | (fn & 0xffff); /* ori $25,low(fn) */ - tramp[2] = 0x3c080000 | (ctx >> 16); /* lui $8,high(ctx) */ - tramp[3] = 0x03200008; /* jr $25 */ - tramp[4] = 0x35080000 | (ctx & 0xffff); /* ori $8,low(ctx) */ +#if defined(FFI_MIPS_O32) || (_MIPS_SIM ==_ABIN32) + /* lui $25,high(fn) */ + tramp[0] = 0x3c190000 | ((unsigned)fn >> 16); + /* ori $25,low(fn) */ + tramp[1] = 0x37390000 | ((unsigned)fn & 0xffff); + /* lui $12,high(codeloc) */ + tramp[2] = 0x3c0c0000 | ((unsigned)codeloc >> 16); + /* jr $25 */ + tramp[3] = 0x03200008; + /* ori $12,low(codeloc) */ + tramp[4] = 0x358c0000 | ((unsigned)codeloc & 0xffff); +#else + /* N64 has a somewhat larger trampoline. */ + /* lui $25,high(fn) */ + tramp[0] = 0x3c190000 | ((unsigned long)fn >> 48); + /* lui $12,high(codeloc) */ + tramp[1] = 0x3c0c0000 | ((unsigned long)codeloc >> 48); + /* ori $25,mid-high(fn) */ + tramp[2] = 0x37390000 | (((unsigned long)fn >> 32 ) & 0xffff); + /* ori $12,mid-high(codeloc) */ + tramp[3] = 0x358c0000 | (((unsigned long)codeloc >> 32) & 0xffff); + /* dsll $25,$25,16 */ + tramp[4] = 0x0019cc38; + /* dsll $12,$12,16 */ + tramp[5] = 0x000c6438; + /* ori $25,mid-low(fn) */ + tramp[6] = 0x37390000 | (((unsigned long)fn >> 16 ) & 0xffff); + /* ori $12,mid-low(codeloc) */ + tramp[7] = 0x358c0000 | (((unsigned long)codeloc >> 16) & 0xffff); + /* dsll $25,$25,16 */ + tramp[8] = 0x0019cc38; + /* dsll $12,$12,16 */ + tramp[9] = 0x000c6438; + /* ori $25,low(fn) */ + tramp[10] = 0x37390000 | ((unsigned long)fn & 0xffff); + /* jr $25 */ + tramp[11] = 0x03200008; + /* ori $12,low(codeloc) */ + tramp[12] = 0x358c0000 | ((unsigned long)codeloc & 0xffff); + +#endif closure->cif = cif; closure->fun = fun; @@ -567,7 +651,7 @@ ffi_closure_mips_inner_O32 (ffi_closure *closure, if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT) { - rvalue = (void *) ar[0]; + rvalue = (void *)(UINT32)ar[0]; argn = 1; } @@ -645,4 +729,177 @@ ffi_closure_mips_inner_O32 (ffi_closure *closure, } } +#if defined(FFI_MIPS_N32) + +static void +copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type, + int argn, unsigned arg_offset, ffi_arg *ar, + ffi_arg *fpr) +{ + ffi_type **elt_typep = type->elements; + while(*elt_typep) + { + ffi_type *elt_type = *elt_typep; + unsigned o; + char *tp; + char *argp; + char *fpp; + + o = ALIGN(offset, elt_type->alignment); + arg_offset += o - offset; + offset = o; + argn += arg_offset / sizeof(ffi_arg); + arg_offset = arg_offset % sizeof(ffi_arg); + + argp = (char *)(ar + argn); + fpp = (char *)(argn >= 8 ? ar + argn : fpr + argn); + + tp = target + offset; + + if (elt_type->type == FFI_TYPE_DOUBLE) + *(double *)tp = *(double *)fpp; + else + memcpy(tp, argp + arg_offset, elt_type->size); + + offset += elt_type->size; + arg_offset += elt_type->size; + elt_typep++; + argn += arg_offset / sizeof(ffi_arg); + arg_offset = arg_offset % sizeof(ffi_arg); + } +} + +/* + * Decodes the arguments to a function, which will be stored on the + * stack. AR is the pointer to the beginning of the integer + * arguments. FPR is a pointer to the area where floating point + * registers have been saved. + * + * RVALUE is the location where the function return value will be + * stored. CLOSURE is the prepared closure to invoke. + * + * This function should only be called from assembly, which is in + * turn called from a trampoline. + * + * Returns the function return flags. + * + */ +int +ffi_closure_mips_inner_N32 (ffi_closure *closure, + void *rvalue, ffi_arg *ar, + ffi_arg *fpr) +{ + ffi_cif *cif; + void **avaluep; + ffi_arg *avalue; + ffi_type **arg_types; + int i, avn, argn; + + cif = closure->cif; + avalue = alloca (cif->nargs * sizeof (ffi_arg)); + avaluep = alloca (cif->nargs * sizeof (ffi_arg)); + + argn = 0; + + if (cif->rstruct_flag) + { +#if _MIPS_SIM==_ABIN32 + rvalue = (void *)(UINT32)ar[0]; +#else /* N64 */ + rvalue = (void *)ar[0]; +#endif + argn = 1; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + while (i < avn) + { + if (arg_types[i]->type == FFI_TYPE_FLOAT + || arg_types[i]->type == FFI_TYPE_DOUBLE) + { + ffi_arg *argp = argn >= 8 ? ar + argn : fpr + argn; +#ifdef __MIPSEB__ + if (arg_types[i]->type == FFI_TYPE_FLOAT && argn < 8) + avaluep[i] = ((char *) argp) + sizeof (float); + else +#endif + avaluep[i] = (char *) argp; + } + else + { + unsigned type = arg_types[i]->type; + + if (arg_types[i]->alignment > sizeof(ffi_arg)) + argn = ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg)); + + ffi_arg *argp = ar + argn; + + /* The size of a pointer depends on the ABI */ + if (type == FFI_TYPE_POINTER) + type = (cif->abi == FFI_N64) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32; + + switch (type) + { + case FFI_TYPE_SINT8: + avaluep[i] = &avalue[i]; + *(SINT8 *) &avalue[i] = (SINT8) *argp; + break; + + case FFI_TYPE_UINT8: + avaluep[i] = &avalue[i]; + *(UINT8 *) &avalue[i] = (UINT8) *argp; + break; + + case FFI_TYPE_SINT16: + avaluep[i] = &avalue[i]; + *(SINT16 *) &avalue[i] = (SINT16) *argp; + break; + + case FFI_TYPE_UINT16: + avaluep[i] = &avalue[i]; + *(UINT16 *) &avalue[i] = (UINT16) *argp; + break; + + case FFI_TYPE_SINT32: + avaluep[i] = &avalue[i]; + *(SINT32 *) &avalue[i] = (SINT32) *argp; + break; + + case FFI_TYPE_UINT32: + avaluep[i] = &avalue[i]; + *(UINT32 *) &avalue[i] = (UINT32) *argp; + break; + + case FFI_TYPE_STRUCT: + if (argn < 8) + { + /* Allocate space for the struct as at least part of + it was passed in registers. */ + avaluep[i] = alloca(arg_types[i]->size); + copy_struct_N32(avaluep[i], 0, cif->abi, arg_types[i], + argn, 0, ar, fpr); + + break; + } + /* Else fall through. */ + default: + avaluep[i] = (char *) argp; + break; + } + } + argn += ALIGN(arg_types[i]->size, sizeof(ffi_arg)) / sizeof(ffi_arg); + i++; + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avaluep, closure->user_data); + + return cif->flags >> (FFI_FLAG_BITS * 8); +} + +#endif /* FFI_MIPS_N32 */ + #endif /* FFI_CLOSURES */ diff --git a/libffi/src/mips/ffitarget.h b/libffi/src/mips/ffitarget.h index e610745698f..08f03c3e42a 100644 --- a/libffi/src/mips/ffitarget.h +++ b/libffi/src/mips/ffitarget.h @@ -104,19 +104,28 @@ #define ra $31 #ifdef FFI_MIPS_O32 -#define REG_L lw -#define REG_S sw -#define SUBU subu -#define ADDU addu -#define SRL srl -#define LI li +# define REG_L lw +# define REG_S sw +# define SUBU subu +# define ADDU addu +# define SRL srl +# define LI li #else /* !FFI_MIPS_O32 */ -#define REG_L ld -#define REG_S sd -#define SUBU dsubu -#define ADDU daddu -#define SRL dsrl -#define LI dli +# define REG_L ld +# define REG_S sd +# define SUBU dsubu +# define ADDU daddu +# define SRL dsrl +# define LI dli +# if (_MIPS_SIM==_ABI64) +# define LA dla +# define EH_FRAME_ALIGN 3 +# define FDE_ADDR_BYTES .8byte +# else +# define LA la +# define EH_FRAME_ALIGN 2 +# define FDE_ADDR_BYTES .4byte +# endif /* _MIPS_SIM==_ABI64 */ #endif /* !FFI_MIPS_O32 */ #else /* !LIBFFI_ASM */ #ifdef FFI_MIPS_O32 @@ -143,7 +152,11 @@ typedef enum ffi_abi { FFI_DEFAULT_ABI = FFI_O32, #endif #else +# if _MIPS_SIM==_ABI64 + FFI_DEFAULT_ABI = FFI_N64, +# else FFI_DEFAULT_ABI = FFI_N32, +# endif #endif FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 @@ -158,8 +171,13 @@ typedef enum ffi_abi { #define FFI_CLOSURES 1 #define FFI_TRAMPOLINE_SIZE 20 #else -/* N32/N64 not implemented yet. */ -#define FFI_CLOSURES 0 +/* N32/N64. */ +# define FFI_CLOSURES 1 +#if _MIPS_SIM==_ABI64 +#define FFI_TRAMPOLINE_SIZE 52 +#else +#define FFI_TRAMPOLINE_SIZE 20 +#endif #endif /* FFI_MIPS_O32 */ #define FFI_NATIVE_RAW_API 0 diff --git a/libffi/src/mips/n32.S b/libffi/src/mips/n32.S index 358cfd7e409..ff268c6a173 100644 --- a/libffi/src/mips/n32.S +++ b/libffi/src/mips/n32.S @@ -45,13 +45,19 @@ .globl ffi_call_N32 .ent ffi_call_N32 ffi_call_N32: +.LFB3: + .frame $fp, SIZEOF_FRAME, ra + .mask 0xc0000000,-FFI_SIZEOF_ARG + .fmask 0x00000000,0 # Prologue SUBU $sp, SIZEOF_FRAME # Frame size +.LCFI0: REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address +.LCFI1: move $fp, $sp - +.LCFI3: move t9, callback # callback function pointer REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags @@ -315,6 +321,224 @@ epilogue: ADDU $sp, SIZEOF_FRAME # Fix stack pointer j ra +.LFE3: .end ffi_call_N32 + +/* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0 + ($12). Stores any arguments passed in registers onto the stack, + then calls ffi_closure_mips_inner_N32, which then decodes + them. + + Stack layout: + + 20 - Start of parameters, original sp + 19 - Called function a7 save + 18 - Called function a6 save + 17 - Called function a5 save + 16 - Called function a4 save + 15 - Called function a3 save + 14 - Called function a2 save + 13 - Called function a1 save + 12 - Called function a0 save + 11 - Called function f19 + 10 - Called function f18 + 9 - Called function f17 + 8 - Called function f16 + 7 - Called function f15 + 6 - Called function f14 + 5 - Called function f13 + 4 - Called function f12 + 3 - return value high (v1 or $f2) + 2 - return value low (v0 or $f0) + 1 - ra save + 0 - gp save our sp points here + */ + +#define SIZEOF_FRAME2 (20 * FFI_SIZEOF_ARG) + +#define A7_OFF2 (19 * FFI_SIZEOF_ARG) +#define A6_OFF2 (18 * FFI_SIZEOF_ARG) +#define A5_OFF2 (17 * FFI_SIZEOF_ARG) +#define A4_OFF2 (16 * FFI_SIZEOF_ARG) +#define A3_OFF2 (15 * FFI_SIZEOF_ARG) +#define A2_OFF2 (14 * FFI_SIZEOF_ARG) +#define A1_OFF2 (13 * FFI_SIZEOF_ARG) +#define A0_OFF2 (12 * FFI_SIZEOF_ARG) + +#define F19_OFF2 (11 * FFI_SIZEOF_ARG) +#define F18_OFF2 (10 * FFI_SIZEOF_ARG) +#define F17_OFF2 (9 * FFI_SIZEOF_ARG) +#define F16_OFF2 (8 * FFI_SIZEOF_ARG) +#define F15_OFF2 (7 * FFI_SIZEOF_ARG) +#define F14_OFF2 (6 * FFI_SIZEOF_ARG) +#define F13_OFF2 (5 * FFI_SIZEOF_ARG) +#define F12_OFF2 (4 * FFI_SIZEOF_ARG) + +#define V1_OFF2 (3 * FFI_SIZEOF_ARG) +#define V0_OFF2 (2 * FFI_SIZEOF_ARG) + +#define RA_OFF2 (1 * FFI_SIZEOF_ARG) +#define GP_OFF2 (0 * FFI_SIZEOF_ARG) + + .align 2 + .globl ffi_closure_N32 + .ent ffi_closure_N32 +ffi_closure_N32: +.LFB2: + .frame $sp, SIZEOF_FRAME2, ra + .mask 0x90000000,-(SIZEOF_FRAME2 - RA_OFF2) + .fmask 0x00000000,0 + SUBU $sp, SIZEOF_FRAME2 +.LCFI5: + .cpsetup t9, GP_OFF2, ffi_closure_N32 + REG_S ra, RA_OFF2($sp) # Save return address +.LCFI6: + # Store all possible argument registers. If there are more than + # fit in registers, then they were stored on the stack. + REG_S a0, A0_OFF2($sp) + REG_S a1, A1_OFF2($sp) + REG_S a2, A2_OFF2($sp) + REG_S a3, A3_OFF2($sp) + REG_S a4, A4_OFF2($sp) + REG_S a5, A5_OFF2($sp) + REG_S a6, A6_OFF2($sp) + REG_S a7, A7_OFF2($sp) + + # Store all possible float/double registers. + s.d $f12, F12_OFF2($sp) + s.d $f13, F13_OFF2($sp) + s.d $f14, F14_OFF2($sp) + s.d $f15, F15_OFF2($sp) + s.d $f16, F16_OFF2($sp) + s.d $f17, F17_OFF2($sp) + s.d $f18, F18_OFF2($sp) + s.d $f19, F19_OFF2($sp) + + # Call ffi_closure_mips_inner_N32 to do the real work. + LA t9, ffi_closure_mips_inner_N32 + move a0, $12 # Pointer to the ffi_closure + addu a1, $sp, V0_OFF2 + addu a2, $sp, A0_OFF2 + addu a3, $sp, F12_OFF2 + jalr t9 + + # Return flags are in v0 + bne v0, FFI_TYPE_INT, cls_retfloat + REG_L v0, V0_OFF2($sp) + b cls_epilogue + +cls_retfloat: + bne v0, FFI_TYPE_FLOAT, cls_retdouble + l.s $f0, V0_OFF2($sp) + b cls_epilogue + +cls_retdouble: + bne v0, FFI_TYPE_DOUBLE, cls_retstruct_d + l.d $f0, V0_OFF2($sp) + b cls_epilogue + +cls_retstruct_d: + bne v0, FFI_TYPE_STRUCT_D, cls_retstruct_f + l.d $f0, V0_OFF2($sp) + b cls_epilogue + +cls_retstruct_f: + bne v0, FFI_TYPE_STRUCT_F, cls_retstruct_d_d + l.s $f0, V0_OFF2($sp) + b cls_epilogue + +cls_retstruct_d_d: + bne v0, FFI_TYPE_STRUCT_DD, cls_retstruct_f_f + l.d $f0, V0_OFF2($sp) + l.d $f2, V1_OFF2($sp) + b cls_epilogue + +cls_retstruct_f_f: + bne v0, FFI_TYPE_STRUCT_FF, cls_retstruct_d_f + l.s $f0, V0_OFF2($sp) + l.s $f2, V1_OFF2($sp) + b cls_epilogue + +cls_retstruct_d_f: + bne v0, FFI_TYPE_STRUCT_DF, cls_retstruct_f_d + l.d $f0, V0_OFF2($sp) + l.s $f2, V1_OFF2($sp) + b cls_epilogue + +cls_retstruct_f_d: + bne v0, FFI_TYPE_STRUCT_FD, cls_retstruct_small2 + l.s $f0, V0_OFF2($sp) + l.d $f2, V1_OFF2($sp) + b cls_epilogue + +cls_retstruct_small2: + REG_L v0, V0_OFF2($sp) + REG_L v1, V1_OFF2($sp) + + # Epilogue +cls_epilogue: + REG_L ra, RA_OFF2($sp) # Restore return address + .cpreturn + ADDU $sp, SIZEOF_FRAME2 + j ra +.LFE2: + .end ffi_closure_N32 + + .section .eh_frame,"aw",@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 # length +.LSCIE1: + .4byte 0x0 # CIE + .byte 0x1 # Version 1 + .ascii "\000" # Augmentation + .uleb128 0x1 # Code alignment 1 + .sleb128 -4 # Data alignment -4 + .byte 0x1f # Return Address $31 + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1d # in $sp + .uleb128 0x0 # offset 0 + .align EH_FRAME_ALIGN +.LECIE1: + +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 # length. +.LASFDE1: + .4byte .LASFDE1-.Lframe1 # CIE_pointer. + FDE_ADDR_BYTES .LFB3 # initial_location. + FDE_ADDR_BYTES .LFE3-.LFB3 # address_range. + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI0-.LFB3 # to .LCFI0 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 SIZEOF_FRAME # adjust stack.by SIZEOF_FRAME + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI1-.LCFI0 # to .LCFI1 + .byte 0x9e # DW_CFA_offset of $fp + .uleb128 2*FFI_SIZEOF_ARG/4 # + .byte 0x9f # DW_CFA_offset of ra + .uleb128 1*FFI_SIZEOF_ARG/4 # + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI3-.LCFI1 # to .LCFI3 + .byte 0xd # DW_CFA_def_cfa_register + .uleb128 0x1e # in $fp + .align EH_FRAME_ALIGN +.LEFDE1: +.LSFDE3: + .4byte .LEFDE3-.LASFDE3 # length +.LASFDE3: + .4byte .LASFDE3-.Lframe1 # CIE_pointer. + FDE_ADDR_BYTES .LFB2 # initial_location. + FDE_ADDR_BYTES .LFE2-.LFB2 # address_range. + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI5-.LFB2 # to .LCFI5 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 SIZEOF_FRAME2 # adjust stack.by SIZEOF_FRAME + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI6-.LCFI5 # to .LCFI6 + .byte 0x9c # DW_CFA_offset of $gp ($28) + .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4 + .byte 0x9f # DW_CFA_offset of ra ($31) + .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4 + .align EH_FRAME_ALIGN +.LEFDE3: #endif diff --git a/libffi/src/mips/o32.S b/libffi/src/mips/o32.S index 63f3d146357..f6363cb6c54 100644 --- a/libffi/src/mips/o32.S +++ b/libffi/src/mips/o32.S @@ -183,27 +183,30 @@ $LFE0: /* ffi_closure_O32. Expects address of the passed-in ffi_closure - in t0. Stores any arguments passed in registers onto the + in t4 ($12). Stores any arguments passed in registers onto the stack, then calls ffi_closure_mips_inner_O32, which then decodes them. Stack layout: - 14 - Start of parameters, original sp - 13 - ra save - 12 - fp save - 11 - $16 (s0) save - 10 - cprestore - 9 - return value high (v1) - 8 - return value low (v0) - 7 - f14 (le high, be low) - 6 - f14 (le low, be high) - 5 - f12 (le high, be low) - 4 - f12 (le low, be high) - 3 - Called function a3 save - 2 - Called function a2 save - 1 - Called function a1 save - 0 - Called function a0 save our sp, fp point here + 3 - a3 save + 2 - a2 save + 1 - a1 save + 0 - a0 save, original sp + -1 - ra save + -2 - fp save + -3 - $16 (s0) save + -4 - cprestore + -5 - return value high (v1) + -6 - return value low (v0) + -7 - f14 (le high, be low) + -8 - f14 (le low, be high) + -9 - f12 (le high, be low) + -10 - f12 (le low, be high) + -11 - Called function a3 save + -12 - Called function a2 save + -13 - Called function a1 save + -14 - Called function a0 save, our sp and fp point here */ #define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG) @@ -251,7 +254,7 @@ $LCFI7: REG_S a3, A3_OFF2($fp) # Load ABI enum to s0 - REG_L $16, 20($8) # cif pointer follows tramp. + REG_L $16, 20($12) # cif pointer follows tramp. REG_L $16, 0($16) # abi is first member. li $13, 1 # FFI_O32 @@ -263,7 +266,7 @@ $LCFI7: 1: # Call ffi_closure_mips_inner_O32 to do the work. la t9, ffi_closure_mips_inner_O32 - move a0, $8 # Pointer to the ffi_closure + move a0, $12 # Pointer to the ffi_closure addu a1, $fp, V0_OFF2 addu a2, $fp, A0_OFF2 addu a3, $fp, FA_0_0_OFF2 |