Many changes. Not quite there yet.
This commit is contained in:
@@ -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
470
libffi/mips/ffi.c
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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,10 +23,12 @@
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#ifndef FFI_MIPS_H
|
||||
|
||||
#include <ffi.h>
|
||||
#ifndef MIPS_H
|
||||
|
||||
#if defined(__mips_eabi)
|
||||
# define FFI_MIPS_EABI
|
||||
# define FFI_MIPS_O32
|
||||
#else
|
||||
# if !defined(_MIPS_SIM)
|
||||
-- something is very wrong --
|
||||
# else
|
||||
@@ -44,6 +46,7 @@
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define v0 $2
|
||||
#define v1 $3
|
||||
319
libffi/mips/n32.S
Normal file
319
libffi/mips/n32.S
Normal 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
172
libffi/mips/o32.S
Normal 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
589
libffi/s390/ffi.c
Normal 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
161
libffi/s390/sysv.S
Normal 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
422
libffi/sparc/ffi.c
Normal 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
93
libffi/sparc/v8.S
Normal 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
125
libffi/sparc/v9.S
Normal 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
|
||||
15
libffi/testsuite/Makefile.am
Normal file
15
libffi/testsuite/Makefile.am
Normal 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@
|
||||
|
||||
228
libffi/testsuite/Makefile.in
Normal file
228
libffi/testsuite/Makefile.in
Normal 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:
|
||||
1
libffi/testsuite/config/default.exp
Normal file
1
libffi/testsuite/config/default.exp
Normal file
@@ -0,0 +1 @@
|
||||
load_lib "standard.exp"
|
||||
44
libffi/testsuite/lib/libffi.exp
Normal file
44
libffi/testsuite/lib/libffi.exp
Normal 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:
|
||||
13
libffi/testsuite/libffi.call/call.exp
Normal file
13
libffi/testsuite/libffi.call/call.exp
Normal 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:
|
||||
4
libffi/testsuite/libffi.call/ffitest.h
Normal file
4
libffi/testsuite/libffi.call/ffitest.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#include <ffi.h>
|
||||
|
||||
#define CHECK(x) !(x) ? abort() : 0
|
||||
|
||||
55
libffi/testsuite/libffi.call/float.c
Normal file
55
libffi/testsuite/libffi.call/float.c
Normal 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);
|
||||
}
|
||||
|
||||
63
libffi/testsuite/libffi.call/many.c
Normal file
63
libffi/testsuite/libffi.call/many.c
Normal 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();
|
||||
}
|
||||
38
libffi/testsuite/libffi.call/strlen.c
Normal file
38
libffi/testsuite/libffi.call/strlen.c
Normal 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
509
libffi/x86/ffi.c
Normal 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
167
libffi/x86/sysv.S
Normal 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
125
libffi/x86/win32.S
Normal 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:
|
||||
Reference in New Issue
Block a user