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
This commit is contained in:
David Daney 2007-08-10 15:35:55 +00:00 committed by David Daney
parent 2fbe0e5aec
commit 89d9d98ae5
10 changed files with 635 additions and 96 deletions

View file

@ -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.

View file

@ -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

View file

@ -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 \

2
libffi/configure vendored
View file

@ -10324,8 +10324,6 @@ case "$host" in
TARGET=M68K; TARGETDIR=m68k
;;
mips64*-*)
;;
mips-sgi-irix5.* | mips-sgi-irix6.*)
TARGET=MIPS_IRIX; TARGETDIR=mips
;;

View file

@ -94,8 +94,6 @@ case "$host" in
TARGET=M68K; TARGETDIR=m68k
;;
mips64*-*)
;;
mips-sgi-irix5.* | mips-sgi-irix6.*)
TARGET=MIPS_IRIX; TARGETDIR=mips
;;

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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

View file

@ -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