Many changes. Not quite there yet.

This commit is contained in:
green
2001-04-22 18:17:14 +00:00
parent f893d22733
commit a8b0d40ff9
22 changed files with 3627 additions and 524 deletions

View File

@@ -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 <fficonfig.h>
#if !defined(LIBFFI_ASM)
#include <stddef.h>
#if defined(FFI_DEBUG)
#include <stdio.h>
#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 <ffi_mips.h>
#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

470
libffi/mips/ffi.c Normal file
View File

@@ -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 <ffi.h>
#include <ffi_common.h>
#include <mips/mips.h>
#include <stdlib.h>
#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;
}
}

View File

@@ -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,13 +23,15 @@
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#ifndef FFI_MIPS_H
#ifndef MIPS_H
#include <ffi.h>
#if !defined(_MIPS_SIM)
-- something is very wrong --
#if defined(__mips_eabi)
# define FFI_MIPS_EABI
# define FFI_MIPS_O32
#else
# if !defined(_MIPS_SIM)
-- something is very wrong --
# else
# if _MIPS_SIM==_ABIN32 && defined(_ABIN32)
# define FFI_MIPS_N32
# else
@@ -43,6 +45,7 @@
# endif
# endif
# endif
# endif
#endif
#define v0 $2

319
libffi/mips/n32.S Normal file
View File

@@ -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 <ffi.h>
#include <mips/mips.h>
/* 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<<FFI_FLAG_BITS)-1)
bnez t4, arg1_floatp
REG_L a0, 0*SIZEOF_ARG(t9)
b arg1_next
arg1_floatp:
bne t4, FFI_TYPE_FLOAT, arg1_doublep
l.s $f12, 0*SIZEOF_ARG(t9)
b arg1_next
arg1_doublep:
l.d $f12, 0*SIZEOF_ARG(t9)
arg1_next:
add t4, t6, 0
SRL t4, 1*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg2_floatp
REG_L a1, 1*SIZEOF_ARG(t9)
b arg2_next
arg2_floatp:
bne t4, FFI_TYPE_FLOAT, arg2_doublep
l.s $f13, 1*SIZEOF_ARG(t9)
b arg2_next
arg2_doublep:
l.d $f13, 1*SIZEOF_ARG(t9)
arg2_next:
add t4, t6, 0
SRL t4, 2*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg3_floatp
REG_L a2, 2*SIZEOF_ARG(t9)
b arg3_next
arg3_floatp:
bne t4, FFI_TYPE_FLOAT, arg3_doublep
l.s $f14, 2*SIZEOF_ARG(t9)
b arg3_next
arg3_doublep:
l.d $f14, 2*SIZEOF_ARG(t9)
arg3_next:
add t4, t6, 0
SRL t4, 3*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg4_floatp
REG_L a3, 3*SIZEOF_ARG(t9)
b arg4_next
arg4_floatp:
bne t4, FFI_TYPE_FLOAT, arg4_doublep
l.s $f15, 3*SIZEOF_ARG(t9)
b arg4_next
arg4_doublep:
l.d $f15, 3*SIZEOF_ARG(t9)
arg4_next:
add t4, t6, 0
SRL t4, 4*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg5_floatp
REG_L a4, 4*SIZEOF_ARG(t9)
b arg5_next
arg5_floatp:
bne t4, FFI_TYPE_FLOAT, arg5_doublep
l.s $f16, 4*SIZEOF_ARG(t9)
b arg5_next
arg5_doublep:
l.d $f16, 4*SIZEOF_ARG(t9)
arg5_next:
add t4, t6, 0
SRL t4, 5*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg6_floatp
REG_L a5, 5*SIZEOF_ARG(t9)
b arg6_next
arg6_floatp:
bne t4, FFI_TYPE_FLOAT, arg6_doublep
l.s $f17, 5*SIZEOF_ARG(t9)
b arg6_next
arg6_doublep:
l.d $f17, 5*SIZEOF_ARG(t9)
arg6_next:
add t4, t6, 0
SRL t4, 6*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg7_floatp
REG_L a6, 6*SIZEOF_ARG(t9)
b arg7_next
arg7_floatp:
bne t4, FFI_TYPE_FLOAT, arg7_doublep
l.s $f18, 6*SIZEOF_ARG(t9)
b arg7_next
arg7_doublep:
l.d $f18, 6*SIZEOF_ARG(t9)
arg7_next:
add t4, t6, 0
SRL t4, 7*FFI_FLAG_BITS
and t4, ((1<<FFI_FLAG_BITS)-1)
bnez t4, arg8_floatp
REG_L a7, 7*SIZEOF_ARG(t9)
b arg8_next
arg8_floatp:
bne t4, FFI_TYPE_FLOAT, arg8_doublep
l.s $f19, 7*SIZEOF_ARG(t9)
b arg8_next
arg8_doublep:
l.d $f19, 7*SIZEOF_ARG(t9)
arg8_next:
callit:
# Load the function pointer
REG_L t9, 5*SIZEOF_ARG($fp)
# If the return value pointer is NULL, assume no return value.
REG_L t5, 4*SIZEOF_ARG($fp)
beqz t5, noretval
# Shift the return type flag over
SRL t6, 8*FFI_FLAG_BITS
bne t6, FFI_TYPE_INT, retfloat
jal t9
REG_L t4, 4*SIZEOF_ARG($fp)
REG_S v0, 0(t4)
b epilogue
retfloat:
bne t6, FFI_TYPE_FLOAT, retdouble
jal t9
REG_L t4, 4*SIZEOF_ARG($fp)
s.s $f0, 0(t4)
b epilogue
retdouble:
bne t6, FFI_TYPE_DOUBLE, retstruct_d
jal t9
REG_L t4, 4*SIZEOF_ARG($fp)
s.d $f0, 0(t4)
b epilogue
retstruct_d:
bne t6, FFI_TYPE_STRUCT_D, retstruct_f
jal t9
REG_L t4, 4*SIZEOF_ARG($fp)
s.d $f0, 0(t4)
b epilogue
retstruct_f:
bne t6, FFI_TYPE_STRUCT_F, retstruct_d_d
jal t9
REG_L t4, 4*SIZEOF_ARG($fp)
s.s $f0, 0(t4)
b epilogue
retstruct_d_d:
bne t6, FFI_TYPE_STRUCT_DD, retstruct_f_f
jal t9
REG_L t4, 4*SIZEOF_ARG($fp)
s.d $f0, 0(t4)
s.d $f2, 8(t4)
b epilogue
retstruct_f_f:
bne t6, FFI_TYPE_STRUCT_FF, retstruct_d_f
jal t9
REG_L t4, 4*SIZEOF_ARG($fp)
s.s $f0, 0(t4)
s.s $f2, 4(t4)
b epilogue
retstruct_d_f:
bne t6, FFI_TYPE_STRUCT_DF, retstruct_f_d
jal t9
REG_L t4, 4*SIZEOF_ARG($fp)
s.d $f0, 0(t4)
s.s $f2, 8(t4)
b epilogue
retstruct_f_d:
bne t6, FFI_TYPE_STRUCT_FD, retstruct_small
jal t9
REG_L t4, 4*SIZEOF_ARG($fp)
s.s $f0, 0(t4)
s.d $f2, 8(t4)
b epilogue
retstruct_small:
bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2
jal t9
REG_L t4, 4*SIZEOF_ARG($fp)
REG_S v0, 0(t4)
b epilogue
retstruct_small2:
bne t6, FFI_TYPE_STRUCT_SMALL2, retstruct
jal t9
REG_L t4, 4*SIZEOF_ARG($fp)
REG_S v0, 0(t4)
REG_S v1, 8(t4)
b epilogue
retstruct:
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_N32
#endif

172
libffi/mips/o32.S Normal file
View File

@@ -0,0 +1,172 @@
/* -----------------------------------------------------------------------
o32.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 <ffi.h>
#include <mips/mips.h>
/* 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

589
libffi/s390/ffi.c Normal file
View File

@@ -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 <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
#include <stdio.h>
/*====================== 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 ============================*/

161
libffi/s390/sysv.S Normal file
View File

@@ -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 <ffi.h>
#ifdef HAVE_MACHINE_ASM_H
#include <machine/asm.h>
#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

422
libffi/sparc/ffi.c Normal file
View File

@@ -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 <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* 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;
}
}

93
libffi/sparc/v8.S Normal file
View File

@@ -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 <ffi.h>
#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

125
libffi/sparc/v9.S Normal file
View File

@@ -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 <ffi.h>
#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

View File

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

View File

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

View File

@@ -0,0 +1 @@
load_lib "standard.exp"

View File

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

View File

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

View File

@@ -0,0 +1,4 @@
#include <ffi.h>
#define CHECK(x) !(x) ? abort() : 0

View File

@@ -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);
}

View File

@@ -0,0 +1,63 @@
#include "ffitest.h"
#include <float.h>
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();
}

View File

@@ -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);
}

509
libffi/x86/ffi.c Normal file
View File

@@ -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 <ffi.h>
#include <ffi_private.h>
#include <ffi_common.h>
#include <stdlib.h>
/* 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

167
libffi/x86/sysv.S Normal file
View File

@@ -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 <ffi.h>
#include <ffi_private.h>
.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

125
libffi/x86/win32.S Normal file
View File

@@ -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 <ffi.h>
.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: