aboutsummaryrefslogtreecommitdiff
path: root/libffi/src
diff options
context:
space:
mode:
authorDavid Daney <ddaney@avtrex.com>2007-08-10 15:35:55 +0000
committerDavid Daney <daney@gcc.gnu.org>2007-08-10 15:35:55 +0000
commit89d9d98ae5337a4c32ffe3c3b4be59b2ce3f2ddb (patch)
tree7f34b10176eedc697f1ada58dd6a727f07371578 /libffi/src
parent2fbe0e5aec26f9a07df2146aeb427b94fdabe27e (diff)
downloadgcc-89d9d98ae5337a4c32ffe3c3b4be59b2ce3f2ddb.zip
gcc-89d9d98ae5337a4c32ffe3c3b4be59b2ce3f2ddb.tar.gz
gcc-89d9d98ae5337a4c32ffe3c3b4be59b2ce3f2ddb.tar.bz2
re PR libffi/28313 (libffi has not been ported to mips64-linux-gnu)
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. From-SVN: r127336
Diffstat (limited to 'libffi/src')
-rw-r--r--libffi/src/mips/ffi.c369
-rw-r--r--libffi/src/mips/ffitarget.h46
-rw-r--r--libffi/src/mips/n32.S226
-rw-r--r--libffi/src/mips/o32.S39
4 files changed, 591 insertions, 89 deletions
diff --git a/libffi/src/mips/ffi.c b/libffi/src/mips/ffi.c
index 12b8b62..cc2a42e 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 e610745..08f03c3 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 358cfd7..ff268c6 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 63f3d14..f6363cb 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