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