Add David Gilbert's variadic function call support

This commit is contained in:
Anthony Green
2011-11-12 17:18:51 -05:00
parent ea14ae85e8
commit ff9454da44
34 changed files with 8317 additions and 21 deletions

View File

@@ -35,3 +35,4 @@ minix
interix-patch
remove-debug-code
powerpc-ffi-softfloat
variadic

0
.pc/variadic/.timestamp Normal file
View File

4667
.pc/variadic/ChangeLog Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,600 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename libffi.info
@settitle libffi
@setchapternewpage off
@c %**end of header
@c Merge the standard indexes into a single one.
@syncodeindex fn cp
@syncodeindex vr cp
@syncodeindex ky cp
@syncodeindex pg cp
@syncodeindex tp cp
@include version.texi
@copying
This manual is for Libffi, a portable foreign-function interface
library.
Copyright @copyright{} 2008, 2010 Red Hat, Inc.
@quotation
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version. A copy of the license is included in the
section entitled ``GNU General Public License''.
@end quotation
@end copying
@dircategory Development
@direntry
* libffi: (libffi). Portable foreign-function interface library.
@end direntry
@titlepage
@title Libffi
@page
@vskip 0pt plus 1filll
@insertcopying
@end titlepage
@ifnottex
@node Top
@top libffi
@insertcopying
@menu
* Introduction:: What is libffi?
* Using libffi:: How to use libffi.
* Missing Features:: Things libffi can't do.
* Index:: Index.
@end menu
@end ifnottex
@node Introduction
@chapter What is libffi?
Compilers for high level languages generate code that follow certain
conventions. These conventions are necessary, in part, for separate
compilation to work. One such convention is the @dfn{calling
convention}. The calling convention is a set of assumptions made by
the compiler about where function arguments will be found on entry to
a function. A calling convention also specifies where the return
value for a function is found. The calling convention is also
sometimes called the @dfn{ABI} or @dfn{Application Binary Interface}.
@cindex calling convention
@cindex ABI
@cindex Application Binary Interface
Some programs may not know at the time of compilation what arguments
are to be passed to a function. For instance, an interpreter may be
told at run-time about the number and types of arguments used to call
a given function. @samp{Libffi} can be used in such programs to
provide a bridge from the interpreter program to compiled code.
The @samp{libffi} library provides a portable, high level programming
interface to various calling conventions. This allows a programmer to
call any function specified by a call interface description at run
time.
@acronym{FFI} stands for Foreign Function Interface. A foreign
function interface is the popular name for the interface that allows
code written in one language to call code written in another language.
The @samp{libffi} library really only provides the lowest, machine
dependent layer of a fully featured foreign function interface. A
layer must exist above @samp{libffi} that handles type conversions for
values passed between the two languages.
@cindex FFI
@cindex Foreign Function Interface
@node Using libffi
@chapter Using libffi
@menu
* The Basics:: The basic libffi API.
* Simple Example:: A simple example.
* Types:: libffi type descriptions.
* Multiple ABIs:: Different passing styles on one platform.
* The Closure API:: Writing a generic function.
* Closure Example:: A closure example.
@end menu
@node The Basics
@section The Basics
@samp{Libffi} assumes that you have a pointer to the function you wish
to call and that you know the number and types of arguments to pass
it, as well as the return type of the function.
The first thing you must do is create an @code{ffi_cif} object that
matches the signature of the function you wish to call. This is a
separate step because it is common to make multiple calls using a
single @code{ffi_cif}. The @dfn{cif} in @code{ffi_cif} stands for
Call InterFace. To prepare a call interface object, use the function
@code{ffi_prep_cif}.
@cindex cif
@findex ffi_prep_cif
@defun ffi_status ffi_prep_cif (ffi_cif *@var{cif}, ffi_abi @var{abi}, unsigned int @var{nargs}, ffi_type *@var{rtype}, ffi_type **@var{argtypes})
This initializes @var{cif} according to the given parameters.
@var{abi} is the ABI to use; normally @code{FFI_DEFAULT_ABI} is what
you want. @ref{Multiple ABIs} for more information.
@var{nargs} is the number of arguments that this function accepts.
@samp{libffi} does not yet handle varargs functions; see @ref{Missing
Features} for more information.
@var{rtype} is a pointer to an @code{ffi_type} structure that
describes the return type of the function. @xref{Types}.
@var{argtypes} is a vector of @code{ffi_type} pointers.
@var{argtypes} must have @var{nargs} elements. If @var{nargs} is 0,
this argument is ignored.
@code{ffi_prep_cif} returns a @code{libffi} status code, of type
@code{ffi_status}. This will be either @code{FFI_OK} if everything
worked properly; @code{FFI_BAD_TYPEDEF} if one of the @code{ffi_type}
objects is incorrect; or @code{FFI_BAD_ABI} if the @var{abi} parameter
is invalid.
@end defun
To call a function using an initialized @code{ffi_cif}, use the
@code{ffi_call} function:
@findex ffi_call
@defun void ffi_call (ffi_cif *@var{cif}, void *@var{fn}, void *@var{rvalue}, void **@var{avalues})
This calls the function @var{fn} according to the description given in
@var{cif}. @var{cif} must have already been prepared using
@code{ffi_prep_cif}.
@var{rvalue} is a pointer to a chunk of memory that will hold the
result of the function call. This must be large enough to hold the
result and must be suitably aligned; it is the caller's responsibility
to ensure this. If @var{cif} declares that the function returns
@code{void} (using @code{ffi_type_void}), then @var{rvalue} is
ignored. If @var{rvalue} is @samp{NULL}, then the return value is
discarded.
@var{avalues} is a vector of @code{void *} pointers that point to the
memory locations holding the argument values for a call. If @var{cif}
declares that the function has no arguments (i.e., @var{nargs} was 0),
then @var{avalues} is ignored. Note that argument values may be
modified by the callee (for instance, structs passed by value); the
burden of copying pass-by-value arguments is placed on the caller.
@end defun
@node Simple Example
@section Simple Example
Here is a trivial example that calls @code{puts} a few times.
@example
#include <stdio.h>
#include <ffi.h>
int main()
@{
ffi_cif cif;
ffi_type *args[1];
void *values[1];
char *s;
int rc;
/* Initialize the argument info vectors */
args[0] = &ffi_type_pointer;
values[0] = &s;
/* Initialize the cif */
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
&ffi_type_uint, args) == FFI_OK)
@{
s = "Hello World!";
ffi_call(&cif, puts, &rc, values);
/* rc now holds the result of the call to puts */
/* values holds a pointer to the function's arg, so to
call puts() again all we need to do is change the
value of s */
s = "This is cool!";
ffi_call(&cif, puts, &rc, values);
@}
return 0;
@}
@end example
@node Types
@section Types
@menu
* Primitive Types:: Built-in types.
* Structures:: Structure types.
* Type Example:: Structure type example.
@end menu
@node Primitive Types
@subsection Primitive Types
@code{Libffi} provides a number of built-in type descriptors that can
be used to describe argument and return types:
@table @code
@item ffi_type_void
@tindex ffi_type_void
The type @code{void}. This cannot be used for argument types, only
for return values.
@item ffi_type_uint8
@tindex ffi_type_uint8
An unsigned, 8-bit integer type.
@item ffi_type_sint8
@tindex ffi_type_sint8
A signed, 8-bit integer type.
@item ffi_type_uint16
@tindex ffi_type_uint16
An unsigned, 16-bit integer type.
@item ffi_type_sint16
@tindex ffi_type_sint16
A signed, 16-bit integer type.
@item ffi_type_uint32
@tindex ffi_type_uint32
An unsigned, 32-bit integer type.
@item ffi_type_sint32
@tindex ffi_type_sint32
A signed, 32-bit integer type.
@item ffi_type_uint64
@tindex ffi_type_uint64
An unsigned, 64-bit integer type.
@item ffi_type_sint64
@tindex ffi_type_sint64
A signed, 64-bit integer type.
@item ffi_type_float
@tindex ffi_type_float
The C @code{float} type.
@item ffi_type_double
@tindex ffi_type_double
The C @code{double} type.
@item ffi_type_uchar
@tindex ffi_type_uchar
The C @code{unsigned char} type.
@item ffi_type_schar
@tindex ffi_type_schar
The C @code{signed char} type. (Note that there is not an exact
equivalent to the C @code{char} type in @code{libffi}; ordinarily you
should either use @code{ffi_type_schar} or @code{ffi_type_uchar}
depending on whether @code{char} is signed.)
@item ffi_type_ushort
@tindex ffi_type_ushort
The C @code{unsigned short} type.
@item ffi_type_sshort
@tindex ffi_type_sshort
The C @code{short} type.
@item ffi_type_uint
@tindex ffi_type_uint
The C @code{unsigned int} type.
@item ffi_type_sint
@tindex ffi_type_sint
The C @code{int} type.
@item ffi_type_ulong
@tindex ffi_type_ulong
The C @code{unsigned long} type.
@item ffi_type_slong
@tindex ffi_type_slong
The C @code{long} type.
@item ffi_type_longdouble
@tindex ffi_type_longdouble
On platforms that have a C @code{long double} type, this is defined.
On other platforms, it is not.
@item ffi_type_pointer
@tindex ffi_type_pointer
A generic @code{void *} pointer. You should use this for all
pointers, regardless of their real type.
@end table
Each of these is of type @code{ffi_type}, so you must take the address
when passing to @code{ffi_prep_cif}.
@node Structures
@subsection Structures
Although @samp{libffi} has no special support for unions or
bit-fields, it is perfectly happy passing structures back and forth.
You must first describe the structure to @samp{libffi} by creating a
new @code{ffi_type} object for it.
@tindex ffi_type
@deftp ffi_type
The @code{ffi_type} has the following members:
@table @code
@item size_t size
This is set by @code{libffi}; you should initialize it to zero.
@item unsigned short alignment
This is set by @code{libffi}; you should initialize it to zero.
@item unsigned short type
For a structure, this should be set to @code{FFI_TYPE_STRUCT}.
@item ffi_type **elements
This is a @samp{NULL}-terminated array of pointers to @code{ffi_type}
objects. There is one element per field of the struct.
@end table
@end deftp
@node Type Example
@subsection Type Example
The following example initializes a @code{ffi_type} object
representing the @code{tm} struct from Linux's @file{time.h}.
Here is how the struct is defined:
@example
struct tm @{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
/* Those are for future use. */
long int __tm_gmtoff__;
__const char *__tm_zone__;
@};
@end example
Here is the corresponding code to describe this struct to
@code{libffi}:
@example
@{
ffi_type tm_type;
ffi_type *tm_type_elements[12];
int i;
tm_type.size = tm_type.alignment = 0;
tm_type.elements = &tm_type_elements;
for (i = 0; i < 9; i++)
tm_type_elements[i] = &ffi_type_sint;
tm_type_elements[9] = &ffi_type_slong;
tm_type_elements[10] = &ffi_type_pointer;
tm_type_elements[11] = NULL;
/* tm_type can now be used to represent tm argument types and
return types for ffi_prep_cif() */
@}
@end example
@node Multiple ABIs
@section Multiple ABIs
A given platform may provide multiple different ABIs at once. For
instance, the x86 platform has both @samp{stdcall} and @samp{fastcall}
functions.
@code{libffi} provides some support for this. However, this is
necessarily platform-specific.
@c FIXME: document the platforms
@node The Closure API
@section The Closure API
@code{libffi} also provides a way to write a generic function -- a
function that can accept and decode any combination of arguments.
This can be useful when writing an interpreter, or to provide wrappers
for arbitrary functions.
This facility is called the @dfn{closure API}. Closures are not
supported on all platforms; you can check the @code{FFI_CLOSURES}
define to determine whether they are supported on the current
platform.
@cindex closures
@cindex closure API
@findex FFI_CLOSURES
Because closures work by assembling a tiny function at runtime, they
require special allocation on platforms that have a non-executable
heap. Memory management for closures is handled by a pair of
functions:
@findex ffi_closure_alloc
@defun void *ffi_closure_alloc (size_t @var{size}, void **@var{code})
Allocate a chunk of memory holding @var{size} bytes. This returns a
pointer to the writable address, and sets *@var{code} to the
corresponding executable address.
@var{size} should be sufficient to hold a @code{ffi_closure} object.
@end defun
@findex ffi_closure_free
@defun void ffi_closure_free (void *@var{writable})
Free memory allocated using @code{ffi_closure_alloc}. The argument is
the writable address that was returned.
@end defun
Once you have allocated the memory for a closure, you must construct a
@code{ffi_cif} describing the function call. Finally you can prepare
the closure function:
@findex ffi_prep_closure_loc
@defun ffi_status ffi_prep_closure_loc (ffi_closure *@var{closure}, ffi_cif *@var{cif}, void (*@var{fun}) (ffi_cif *@var{cif}, void *@var{ret}, void **@var{args}, void *@var{user_data}), void *@var{user_data}, void *@var{codeloc})
Prepare a closure function.
@var{closure} is the address of a @code{ffi_closure} object; this is
the writable address returned by @code{ffi_closure_alloc}.
@var{cif} is the @code{ffi_cif} describing the function parameters.
@var{user_data} is an arbitrary datum that is passed, uninterpreted,
to your closure function.
@var{codeloc} is the executable address returned by
@code{ffi_closure_alloc}.
@var{fun} is the function which will be called when the closure is
invoked. It is called with the arguments:
@table @var
@item cif
The @code{ffi_cif} passed to @code{ffi_prep_closure_loc}.
@item ret
A pointer to the memory used for the function's return value.
@var{fun} must fill this, unless the function is declared as returning
@code{void}.
@c FIXME: is this NULL for void-returning functions?
@item args
A vector of pointers to memory holding the arguments to the function.
@item user_data
The same @var{user_data} that was passed to
@code{ffi_prep_closure_loc}.
@end table
@code{ffi_prep_closure_loc} will return @code{FFI_OK} if everything
went ok, and something else on error.
@c FIXME: what?
After calling @code{ffi_prep_closure_loc}, you can cast @var{codeloc}
to the appropriate pointer-to-function type.
@end defun
You may see old code referring to @code{ffi_prep_closure}. This
function is deprecated, as it cannot handle the need for separate
writable and executable addresses.
@node Closure Example
@section Closure Example
A trivial example that creates a new @code{puts} by binding
@code{fputs} with @code{stdin}.
@example
#include <stdio.h>
#include <ffi.h>
/* Acts like puts with the file given at time of enclosure. */
void puts_binding(ffi_cif *cif, unsigned int *ret, void* args[],
FILE *stream)
@{
*ret = fputs(*(char **)args[0], stream);
@}
int main()
@{
ffi_cif cif;
ffi_type *args[1];
ffi_closure *closure;
int (*bound_puts)(char *);
int rc;
/* Allocate closure and bound_puts */
closure = ffi_closure_alloc(sizeof(ffi_closure), &bound_puts);
if (closure)
@{
/* Initialize the argument info vectors */
args[0] = &ffi_type_pointer;
/* Initialize the cif */
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
&ffi_type_uint, args) == FFI_OK)
@{
/* Initialize the closure, setting stream to stdout */
if (ffi_prep_closure_loc(closure, &cif, puts_binding,
stdout, bound_puts) == FFI_OK)
@{
rc = bound_puts("Hello World!");
/* rc now holds the result of the call to fputs */
@}
@}
@}
/* Deallocate both closure, and bound_puts */
ffi_closure_free(closure);
return 0;
@}
@end example
@node Missing Features
@chapter Missing Features
@code{libffi} is missing a few features. We welcome patches to add
support for these.
@itemize @bullet
@item
There is no support for calling varargs functions. This may work on
some platforms, depending on how the ABI is defined, but it is not
reliable.
@item
There is no support for bit fields in structures.
@item
The closure API is
@c FIXME: ...
@item
The ``raw'' API is undocumented.
@c argument promotion?
@c unions?
@c anything else?
@end itemize
@node Index
@unnumbered Index
@printindex cp
@bye

View File

@@ -0,0 +1,427 @@
/* -----------------------------------------------------------------*-C-*-
libffi @VERSION@ - Copyright (c) 2011 Anthony Green
- Copyright (c) 1996-2003, 2007, 2008 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 THE AUTHORS OR COPYRIGHT
HOLDERS 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. */
#ifndef @TARGET@
#define @TARGET@
#endif
/* ---- System configuration information --------------------------------- */
#include <ffitarget.h>
#ifndef LIBFFI_ASM
#ifdef _MSC_VER
#define __attribute__(X)
#endif
#include <stddef.h>
#include <limits.h>
/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example).
But we can find it either under the correct ANSI name, or under GNU
C's internal name. */
#define FFI_64_BIT_MAX 9223372036854775807
#ifdef LONG_LONG_MAX
# define FFI_LONG_LONG_MAX LONG_LONG_MAX
#else
# ifdef LLONG_MAX
# define FFI_LONG_LONG_MAX LLONG_MAX
# ifdef _AIX52 /* or newer has C99 LLONG_MAX */
# undef FFI_64_BIT_MAX
# define FFI_64_BIT_MAX 9223372036854775807LL
# endif /* _AIX52 or newer */
# else
# ifdef __GNUC__
# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__
# endif
# ifdef _AIX /* AIX 5.1 and earlier have LONGLONG_MAX */
# ifndef __PPC64__
# if defined (__IBMC__) || defined (__IBMCPP__)
# define FFI_LONG_LONG_MAX LONGLONG_MAX
# endif
# endif /* __PPC64__ */
# undef FFI_64_BIT_MAX
# define FFI_64_BIT_MAX 9223372036854775807LL
# endif
# endif
#endif
/* The closure code assumes that this works on pointers, i.e. a size_t */
/* can hold a pointer. */
typedef struct _ffi_type
{
size_t size;
unsigned short alignment;
unsigned short type;
struct _ffi_type **elements;
} ffi_type;
#ifndef LIBFFI_HIDE_BASIC_TYPES
#if SCHAR_MAX == 127
# define ffi_type_uchar ffi_type_uint8
# define ffi_type_schar ffi_type_sint8
#else
#error "char size not supported"
#endif
#if SHRT_MAX == 32767
# define ffi_type_ushort ffi_type_uint16
# define ffi_type_sshort ffi_type_sint16
#elif SHRT_MAX == 2147483647
# define ffi_type_ushort ffi_type_uint32
# define ffi_type_sshort ffi_type_sint32
#else
#error "short size not supported"
#endif
#if INT_MAX == 32767
# define ffi_type_uint ffi_type_uint16
# define ffi_type_sint ffi_type_sint16
#elif INT_MAX == 2147483647
# define ffi_type_uint ffi_type_uint32
# define ffi_type_sint ffi_type_sint32
#elif INT_MAX == 9223372036854775807
# define ffi_type_uint ffi_type_uint64
# define ffi_type_sint ffi_type_sint64
#else
#error "int size not supported"
#endif
#if LONG_MAX == 2147483647
# if FFI_LONG_LONG_MAX != FFI_64_BIT_MAX
#error "no 64-bit data type supported"
# endif
#elif LONG_MAX != FFI_64_BIT_MAX
#error "long size not supported"
#endif
#if LONG_MAX == 2147483647
# define ffi_type_ulong ffi_type_uint32
# define ffi_type_slong ffi_type_sint32
#elif LONG_MAX == FFI_64_BIT_MAX
# define ffi_type_ulong ffi_type_uint64
# define ffi_type_slong ffi_type_sint64
#else
#error "long size not supported"
#endif
/* These are defined in types.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_pointer;
#if @HAVE_LONG_DOUBLE@
extern ffi_type ffi_type_longdouble;
#else
#define ffi_type_longdouble ffi_type_double
#endif
#endif /* LIBFFI_HIDE_BASIC_TYPES */
typedef enum {
FFI_OK = 0,
FFI_BAD_TYPEDEF,
FFI_BAD_ABI
} ffi_status;
typedef unsigned FFI_TYPE;
typedef struct {
ffi_abi abi;
unsigned nargs;
ffi_type **arg_types;
ffi_type *rtype;
unsigned bytes;
unsigned flags;
#ifdef FFI_EXTRA_CIF_FIELDS
FFI_EXTRA_CIF_FIELDS;
#endif
} ffi_cif;
/* ---- Definitions for the raw API -------------------------------------- */
#ifndef FFI_SIZEOF_ARG
# if LONG_MAX == 2147483647
# define FFI_SIZEOF_ARG 4
# elif LONG_MAX == FFI_64_BIT_MAX
# define FFI_SIZEOF_ARG 8
# endif
#endif
#ifndef FFI_SIZEOF_JAVA_RAW
# define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG
#endif
typedef union {
ffi_sarg sint;
ffi_arg uint;
float flt;
char data[FFI_SIZEOF_ARG];
void* ptr;
} ffi_raw;
#if FFI_SIZEOF_JAVA_RAW == 4 && FFI_SIZEOF_ARG == 8
/* This is a special case for mips64/n32 ABI (and perhaps others) where
sizeof(void *) is 4 and FFI_SIZEOF_ARG is 8. */
typedef union {
signed int sint;
unsigned int uint;
float flt;
char data[FFI_SIZEOF_JAVA_RAW];
void* ptr;
} ffi_java_raw;
#else
typedef ffi_raw ffi_java_raw;
#endif
void ffi_raw_call (ffi_cif *cif,
void (*fn)(void),
void *rvalue,
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);
/* 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 (ffi_cif *cif,
void (*fn)(void),
void *rvalue,
ffi_java_raw *avalue);
void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw);
void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args);
size_t ffi_java_raw_size (ffi_cif *cif);
/* ---- Definitions for closures ----------------------------------------- */
#if FFI_CLOSURES
#ifdef _MSC_VER
__declspec(align(8))
#endif
typedef struct {
char tramp[FFI_TRAMPOLINE_SIZE];
ffi_cif *cif;
void (*fun)(ffi_cif*,void*,void**,void*);
void *user_data;
#ifdef __GNUC__
} ffi_closure __attribute__((aligned (8)));
#else
} ffi_closure;
# ifdef __sgi
# pragma pack 0
# endif
#endif
void *ffi_closure_alloc (size_t size, void **code);
void ffi_closure_free (void *);
ffi_status
ffi_prep_closure (ffi_closure*,
ffi_cif *,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data);
ffi_status
ffi_prep_closure_loc (ffi_closure*,
ffi_cif *,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data,
void*codeloc);
#ifdef __sgi
# pragma pack 8
#endif
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;
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_java_raw*,void*);
void *user_data;
} ffi_java_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);
ffi_status
ffi_prep_raw_closure_loc (ffi_raw_closure*,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data,
void *codeloc);
ffi_status
ffi_prep_java_raw_closure (ffi_java_raw_closure*,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
void *user_data);
ffi_status
ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
void *user_data,
void *codeloc);
#endif /* FFI_CLOSURES */
/* ---- Public interface definition -------------------------------------- */
ffi_status ffi_prep_cif(ffi_cif *cif,
ffi_abi abi,
unsigned int nargs,
ffi_type *rtype,
ffi_type **atypes);
void ffi_call(ffi_cif *cif,
void (*fn)(void),
void *rvalue,
void **avalue);
/* Useful for eliminating compiler warnings */
#define FFI_FN(f) ((void (*)(void))f)
/* ---- Definitions shared with assembly code ---------------------------- */
#endif
/* If these change, update src/mips/ffitarget.h. */
#define FFI_TYPE_VOID 0
#define FFI_TYPE_INT 1
#define FFI_TYPE_FLOAT 2
#define FFI_TYPE_DOUBLE 3
#if @HAVE_LONG_DOUBLE@
#define FFI_TYPE_LONGDOUBLE 4
#else
#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE
#endif
#define FFI_TYPE_UINT8 5
#define FFI_TYPE_SINT8 6
#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
#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

View File

@@ -0,0 +1,126 @@
/* -----------------------------------------------------------------------
ffi_common.h - Copyright (C) 2011 Anthony Green
Copyright (C) 2007 Free Software Foundation, Inc
Copyright (c) 1996 Red Hat, Inc.
Common internal definitions and macros. Only necessary for building
libffi.
----------------------------------------------------------------------- */
#ifndef FFI_COMMON_H
#define FFI_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
#include <fficonfig.h>
/* Do not move this. Some versions of AIX are very picky about where
this is positioned. */
#ifdef __GNUC__
/* mingw64 defines this already in malloc.h. */
#ifndef alloca
# define alloca __builtin_alloca
#endif
# define MAYBE_UNUSED __attribute__((__unused__))
#else
# define MAYBE_UNUSED
# if HAVE_ALLOCA_H
# include <alloca.h>
# else
# ifdef _AIX
#pragma alloca
# else
# ifndef alloca /* predefined by HP cc +Olibcalls */
# ifdef _MSC_VER
# define alloca _alloca
# else
char *alloca ();
# endif
# endif
# endif
# endif
#endif
/* Check for the existence of memcpy. */
#if STDC_HEADERS
# include <string.h>
#else
# ifndef HAVE_MEMCPY
# define memcpy(d, s, n) bcopy ((s), (d), (n))
# endif
#endif
#if defined(FFI_DEBUG)
#include <stdio.h>
#endif
#ifdef FFI_DEBUG
void ffi_assert(char *expr, char *file, int line);
void ffi_stop_here(void);
void ffi_type_test(ffi_type *a, char *file, int line);
#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__))
#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l)))
#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__)
#else
#define FFI_ASSERT(x)
#define FFI_ASSERT_AT(x, f, l)
#define FFI_ASSERT_VALID_TYPE(x)
#endif
#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1)
#define ALIGN_DOWN(v, a) (((size_t) (v)) & -a)
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif);
/* Extended cif, used in callback from assembly routine */
typedef struct
{
ffi_cif *cif;
void *rvalue;
void **avalue;
} extended_cif;
/* Terse sized type definitions. */
#if defined(_MSC_VER) || defined(__sgi)
typedef unsigned char UINT8;
typedef signed char SINT8;
typedef unsigned short UINT16;
typedef signed short SINT16;
typedef unsigned int UINT32;
typedef signed int SINT32;
# ifdef _MSC_VER
typedef unsigned __int64 UINT64;
typedef signed __int64 SINT64;
# else
# include <inttypes.h>
typedef uint64_t UINT64;
typedef int64_t SINT64;
# endif
#else
typedef unsigned int UINT8 __attribute__((__mode__(__QI__)));
typedef signed int SINT8 __attribute__((__mode__(__QI__)));
typedef unsigned int UINT16 __attribute__((__mode__(__HI__)));
typedef signed int SINT16 __attribute__((__mode__(__HI__)));
typedef unsigned int UINT32 __attribute__((__mode__(__SI__)));
typedef signed int SINT32 __attribute__((__mode__(__SI__)));
typedef unsigned int UINT64 __attribute__((__mode__(__DI__)));
typedef signed int SINT64 __attribute__((__mode__(__DI__)));
#endif
typedef float FLOAT32;
#ifndef __GNUC__
#define __builtin_expect(x, expected_value) (x)
#endif
#define LIKELY(x) __builtin_expect((x),1)
#define UNLIKELY(x) __builtin_expect((x),1)
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,8 @@
## Process this with automake to create Makefile.in
AUTOMAKE_OPTIONS=foreign
EXTRA_DIST = ffi.3 ffi_call.3 ffi_prep_cif.3
man_MANS = ffi.3 ffi_call.3 ffi_prep_cif.3

31
.pc/variadic/man/ffi.3 Normal file
View File

@@ -0,0 +1,31 @@
.Dd February 15, 2008
.Dt FFI 3
.Sh NAME
.Nm FFI
.Nd Foreign Function Interface
.Sh LIBRARY
libffi, -lffi
.Sh SYNOPSIS
.In ffi.h
.Ft ffi_status
.Fo ffi_prep_cif
.Fa "ffi_cif *cif"
.Fa "ffi_abi abi"
.Fa "unsigned int nargs"
.Fa "ffi_type *rtype"
.Fa "ffi_type **atypes"
.Fc
.Ft void
.Fo ffi_call
.Fa "ffi_cif *cif"
.Fa "void (*fn)(void)"
.Fa "void *rvalue"
.Fa "void **avalue"
.Fc
.Sh DESCRIPTION
The foreign function interface provides a mechanism by which a function can
generate a call to another function at runtime without requiring knowledge of
the called function's interface at compile time.
.Sh SEE ALSO
.Xr ffi_prep_cif 3 ,
.Xr ffi_call 3

View File

@@ -0,0 +1,66 @@
.Dd February 15, 2008
.Dt ffi_prep_cif 3
.Sh NAME
.Nm ffi_prep_cif
.Nd Prepare a
.Nm ffi_cif
structure for use with
.Nm ffi_call
.
.Sh SYNOPSIS
.In ffi.h
.Ft ffi_status
.Fo ffi_prep_cif
.Fa "ffi_cif *cif"
.Fa "ffi_abi abi"
.Fa "unsigned int nargs"
.Fa "ffi_type *rtype"
.Fa "ffi_type **atypes"
.Fc
.Sh DESCRIPTION
The
.Nm ffi_prep_cif
function prepares a
.Nm ffi_cif
structure for use with
.Nm ffi_call
.
.Fa abi
specifies a set of calling conventions to use.
.Fa atypes
is an array of
.Fa nargs
pointers to
.Nm ffi_type
structs that describe the data type, size and alignment of each argument.
.Fa rtype
points to an
.Nm ffi_type
that describes the data type, size and alignment of the
return value.
.Sh RETURN VALUES
Upon successful completion,
.Nm ffi_prep_cif
returns
.Nm FFI_OK .
It will return
.Nm FFI_BAD_TYPEDEF
if
.Fa cif
is
.Nm NULL
or
.Fa atypes
or
.Fa rtype
is malformed. If
.Fa abi
does not refer to a valid ABI,
.Nm FFI_BAD_ABI
will be returned. Available ABIs are
defined in
.Nm <ffitarget.h>
.
.Sh SEE ALSO
.Xr ffi 3 ,
.Xr ffi_call 3

View File

740
.pc/variadic/src/arm/ffi.c Normal file
View File

@@ -0,0 +1,740 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2011 Timothy Wall
Copyright (c) 2011 Plausible Labs Cooperative, Inc.
Copyright (c) 2011 Anthony Green
Copyright (c) 2011 Free Software Foundation
Copyright (c) 1998, 2008, 2011 Red Hat, Inc.
ARM 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 AUTHORS OR COPYRIGHT
HOLDERS 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>
/* Forward declares. */
static int vfp_type_p (ffi_type *);
static void layout_vfp_args (ffi_cif *);
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments
The vfp_space parameter is the load area for VFP regs, the return
value is cif->vfp_used (word bitset of VFP regs used for passing
arguments). These are only used for the VFP hard-float ABI.
*/
int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space)
{
register unsigned int i, vi = 0;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
*(void **) argp = ecif->rvalue;
argp += 4;
}
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
(i != 0);
i--, p_arg++)
{
size_t z;
size_t alignment;
/* Allocated in VFP registers. */
if (ecif->cif->abi == FFI_VFP
&& vi < ecif->cif->vfp_nargs && vfp_type_p (*p_arg))
{
float* vfp_slot = vfp_space + ecif->cif->vfp_args[vi++];
if ((*p_arg)->type == FFI_TYPE_FLOAT)
*((float*)vfp_slot) = *((float*)*p_argv);
else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
*((double*)vfp_slot) = *((double*)*p_argv);
else
memcpy(vfp_slot, *p_argv, (*p_arg)->size);
p_argv++;
continue;
}
/* Align if necessary */
alignment = (*p_arg)->alignment;
#ifdef _WIN32_WCE
if (alignment > 4)
alignment = 4;
#endif
if ((alignment - 1) & (unsigned) argp) {
argp = (char *) ALIGN(argp, alignment);
}
if ((*p_arg)->type == FFI_TYPE_STRUCT)
argp = (char *) ALIGN(argp, 4);
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_STRUCT:
memcpy(argp, *p_argv, (*p_arg)->size);
break;
default:
FFI_ASSERT(0);
}
}
else if (z == sizeof(int))
{
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
}
else
{
memcpy(argp, *p_argv, z);
}
p_argv++;
argp += z;
}
/* Indicate the VFP registers used. */
return ecif->cif->vfp_used;
}
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
int type_code;
/* Round the stack up to a multiple of 8 bytes. This isn't needed
everywhere, but it is on some platforms, and it doesn't harm anything
when it isn't needed. */
cif->bytes = (cif->bytes + 7) & ~7;
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
cif->flags = (unsigned) cif->rtype->type;
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
cif->flags = (unsigned) FFI_TYPE_SINT64;
break;
case FFI_TYPE_STRUCT:
if (cif->abi == FFI_VFP
&& (type_code = vfp_type_p (cif->rtype)) != 0)
{
/* A Composite Type passed in VFP registers, either
FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */
cif->flags = (unsigned) type_code;
}
else if (cif->rtype->size <= 4)
/* A Composite Type not larger than 4 bytes is returned in r0. */
cif->flags = (unsigned)FFI_TYPE_INT;
else
/* A Composite Type larger than 4 bytes, or whose size cannot
be determined statically ... is stored in memory at an
address passed [in r0]. */
cif->flags = (unsigned)FFI_TYPE_STRUCT;
break;
default:
cif->flags = FFI_TYPE_INT;
break;
}
/* Map out the register placements of VFP register args.
The VFP hard-float calling conventions are slightly more sophisticated than
the base calling conventions, so we do it here instead of in ffi_prep_args(). */
if (cif->abi == FFI_VFP)
layout_vfp_args (cif);
return FFI_OK;
}
/* Prototypes for assembly functions, in sysv.S */
extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
extended_cif ecif;
int small_struct = (cif->flags == FFI_TYPE_INT
&& cif->rtype->type == FFI_TYPE_STRUCT);
int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT
|| cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE);
ecif.cif = cif;
ecif.avalue = avalue;
unsigned int temp;
/* 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->flags == FFI_TYPE_STRUCT))
{
ecif.rvalue = alloca(cif->rtype->size);
}
else if (small_struct)
ecif.rvalue = &temp;
else if (vfp_struct)
{
/* Largest case is double x 4. */
ecif.rvalue = alloca(32);
}
else
ecif.rvalue = rvalue;
switch (cif->abi)
{
case FFI_SYSV:
ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
break;
case FFI_VFP:
ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
break;
default:
FFI_ASSERT(0);
break;
}
if (small_struct)
memcpy (rvalue, &temp, cif->rtype->size);
else if (vfp_struct)
memcpy (rvalue, ecif.rvalue, cif->rtype->size);
}
/** private members **/
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
void** args, ffi_cif* cif, float *vfp_stack);
void ffi_closure_SYSV (ffi_closure *);
void ffi_closure_VFP (ffi_closure *);
/* This function is jumped to by the trampoline */
unsigned int
ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
ffi_closure *closure;
void **respp;
void *args;
void *vfp_args;
{
// our various things...
ffi_cif *cif;
void **arg_area;
cif = closure->cif;
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
/* 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, respp, arg_area, cif, vfp_args);
(closure->fun) (cif, *respp, arg_area, closure->user_data);
return cif->flags;
}
/*@-exportheader@*/
static void
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
void **avalue, ffi_cif *cif,
/* Used only under VFP hard-float ABI. */
float *vfp_stack)
/*@=exportheader@*/
{
register unsigned int i, vi = 0;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
if ( cif->flags == FFI_TYPE_STRUCT ) {
*rvalue = *(void **) argp;
argp += 4;
}
p_argv = avalue;
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
{
size_t z;
size_t alignment;
if (cif->abi == FFI_VFP
&& vi < cif->vfp_nargs && vfp_type_p (*p_arg))
{
*p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]);
continue;
}
alignment = (*p_arg)->alignment;
if (alignment < 4)
alignment = 4;
#ifdef _WIN32_WCE
else
if (alignment > 4)
alignment = 4;
#endif
/* Align if necessary */
if ((alignment - 1) & (unsigned) argp) {
argp = (char *) ALIGN(argp, alignment);
}
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. */
extern unsigned int ffi_arm_trampoline[3];
#if FFI_EXEC_TRAMPOLINE_TABLE
#include <mach/mach.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
extern void *ffi_closure_trampoline_table_page;
typedef struct ffi_trampoline_table ffi_trampoline_table;
typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry;
struct ffi_trampoline_table {
/* contigious writable and executable pages */
vm_address_t config_page;
vm_address_t trampoline_page;
/* free list tracking */
uint16_t free_count;
ffi_trampoline_table_entry *free_list;
ffi_trampoline_table_entry *free_list_pool;
ffi_trampoline_table *prev;
ffi_trampoline_table *next;
};
struct ffi_trampoline_table_entry {
void *(*trampoline)();
ffi_trampoline_table_entry *next;
};
/* Override the standard architecture trampoline size */
// XXX TODO - Fix
#undef FFI_TRAMPOLINE_SIZE
#define FFI_TRAMPOLINE_SIZE 12
/* The trampoline configuration is placed at 4080 bytes prior to the trampoline's entry point */
#define FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc) ((void **) (((uint8_t *) codeloc) - 4080));
/* The first 16 bytes of the config page are unused, as they are unaddressable from the trampoline page. */
#define FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET 16
/* Total number of trampolines that fit in one trampoline table */
#define FFI_TRAMPOLINE_COUNT ((PAGE_SIZE - FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET) / FFI_TRAMPOLINE_SIZE)
static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER;
static ffi_trampoline_table *ffi_trampoline_tables = NULL;
static ffi_trampoline_table *
ffi_trampoline_table_alloc ()
{
ffi_trampoline_table *table = NULL;
/* Loop until we can allocate two contigious pages */
while (table == NULL) {
vm_address_t config_page = 0x0;
kern_return_t kt;
/* Try to allocate two pages */
kt = vm_allocate (mach_task_self (), &config_page, PAGE_SIZE*2, VM_FLAGS_ANYWHERE);
if (kt != KERN_SUCCESS) {
fprintf(stderr, "vm_allocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
break;
}
/* Now drop the second half of the allocation to make room for the trampoline table */
vm_address_t trampoline_page = config_page+PAGE_SIZE;
kt = vm_deallocate (mach_task_self (), trampoline_page, PAGE_SIZE);
if (kt != KERN_SUCCESS) {
fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
break;
}
/* Remap the trampoline table to directly follow the config page */
vm_prot_t cur_prot;
vm_prot_t max_prot;
kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_SIZE, 0x0, FALSE, mach_task_self (), (vm_address_t) &ffi_closure_trampoline_table_page, FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE);
/* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */
if (kt != KERN_SUCCESS) {
/* Log unexpected failures */
if (kt != KERN_NO_SPACE) {
fprintf(stderr, "vm_remap() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
}
vm_deallocate (mach_task_self (), config_page, PAGE_SIZE);
continue;
}
/* We have valid trampoline and config pages */
table = calloc (1, sizeof(ffi_trampoline_table));
table->free_count = FFI_TRAMPOLINE_COUNT;
table->config_page = config_page;
table->trampoline_page = trampoline_page;
/* Create and initialize the free list */
table->free_list_pool = calloc(FFI_TRAMPOLINE_COUNT, sizeof(ffi_trampoline_table_entry));
uint16_t i;
for (i = 0; i < table->free_count; i++) {
ffi_trampoline_table_entry *entry = &table->free_list_pool[i];
entry->trampoline = (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE));
if (i < table->free_count - 1)
entry->next = &table->free_list_pool[i+1];
}
table->free_list = table->free_list_pool;
}
return table;
}
void *
ffi_closure_alloc (size_t size, void **code)
{
/* Create the closure */
ffi_closure *closure = malloc(size);
if (closure == NULL)
return NULL;
pthread_mutex_lock(&ffi_trampoline_lock);
/* Check for an active trampoline table with available entries. */
ffi_trampoline_table *table = ffi_trampoline_tables;
if (table == NULL || table->free_list == NULL) {
table = ffi_trampoline_table_alloc ();
if (table == NULL) {
free(closure);
return NULL;
}
/* Insert the new table at the top of the list */
table->next = ffi_trampoline_tables;
if (table->next != NULL)
table->next->prev = table;
ffi_trampoline_tables = table;
}
/* Claim the free entry */
ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list;
ffi_trampoline_tables->free_list = entry->next;
ffi_trampoline_tables->free_count--;
entry->next = NULL;
pthread_mutex_unlock(&ffi_trampoline_lock);
/* Initialize the return values */
*code = entry->trampoline;
closure->trampoline_table = table;
closure->trampoline_table_entry = entry;
return closure;
}
void
ffi_closure_free (void *ptr)
{
ffi_closure *closure = ptr;
pthread_mutex_lock(&ffi_trampoline_lock);
/* Fetch the table and entry references */
ffi_trampoline_table *table = closure->trampoline_table;
ffi_trampoline_table_entry *entry = closure->trampoline_table_entry;
/* Return the entry to the free list */
entry->next = table->free_list;
table->free_list = entry;
table->free_count++;
/* If all trampolines within this table are free, and at least one other table exists, deallocate
* the table */
if (table->free_count == FFI_TRAMPOLINE_COUNT && ffi_trampoline_tables != table) {
/* Remove from the list */
if (table->prev != NULL)
table->prev->next = table->next;
if (table->next != NULL)
table->next->prev = table->prev;
/* Deallocate pages */
kern_return_t kt;
kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE);
if (kt != KERN_SUCCESS)
fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
kt = vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE);
if (kt != KERN_SUCCESS)
fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
/* Deallocate free list */
free (table->free_list_pool);
free (table);
} else if (ffi_trampoline_tables != table) {
/* Otherwise, bump this table to the top of the list */
table->prev = NULL;
table->next = ffi_trampoline_tables;
if (ffi_trampoline_tables != NULL)
ffi_trampoline_tables->prev = table;
ffi_trampoline_tables = table;
}
pthread_mutex_unlock (&ffi_trampoline_lock);
/* Free the closure */
free (closure);
}
#else
#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 char *insns = (unsigned char *)(CTX); \
memcpy (__tramp, ffi_arm_trampoline, sizeof ffi_arm_trampoline); \
*(unsigned int*) &__tramp[12] = __ctx; \
*(unsigned int*) &__tramp[16] = __fun; \
__clear_cache((&__tramp[0]), (&__tramp[19])); /* Clear data mapping. */ \
__clear_cache(insns, insns + 3 * sizeof (unsigned int)); \
/* Clear instruction \
mapping. */ \
})
#endif
/* the cif must already be prep'ed */
ffi_status
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data,
void *codeloc)
{
void (*closure_func)(ffi_closure*) = NULL;
if (cif->abi == FFI_SYSV)
closure_func = &ffi_closure_SYSV;
else if (cif->abi == FFI_VFP)
closure_func = &ffi_closure_VFP;
else
return FFI_BAD_ABI;
#if FFI_EXEC_TRAMPOLINE_TABLE
void **config = FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc);
config[0] = closure;
config[1] = closure_func;
#else
FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
closure_func, \
codeloc);
#endif
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
return FFI_OK;
}
/* Below are routines for VFP hard-float support. */
static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum)
{
switch (t->type)
{
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
*elt = (int) t->type;
*elnum = 1;
return 1;
case FFI_TYPE_STRUCT_VFP_FLOAT:
*elt = FFI_TYPE_FLOAT;
*elnum = t->size / sizeof (float);
return 1;
case FFI_TYPE_STRUCT_VFP_DOUBLE:
*elt = FFI_TYPE_DOUBLE;
*elnum = t->size / sizeof (double);
return 1;
case FFI_TYPE_STRUCT:;
{
int base_elt = 0, total_elnum = 0;
ffi_type **el = t->elements;
while (*el)
{
int el_elt = 0, el_elnum = 0;
if (! rec_vfp_type_p (*el, &el_elt, &el_elnum)
|| (base_elt && base_elt != el_elt)
|| total_elnum + el_elnum > 4)
return 0;
base_elt = el_elt;
total_elnum += el_elnum;
el++;
}
*elnum = total_elnum;
*elt = base_elt;
return 1;
}
default: ;
}
return 0;
}
static int vfp_type_p (ffi_type *t)
{
int elt, elnum;
if (rec_vfp_type_p (t, &elt, &elnum))
{
if (t->type == FFI_TYPE_STRUCT)
{
if (elnum == 1)
t->type = elt;
else
t->type = (elt == FFI_TYPE_FLOAT
? FFI_TYPE_STRUCT_VFP_FLOAT
: FFI_TYPE_STRUCT_VFP_DOUBLE);
}
return (int) t->type;
}
return 0;
}
static void place_vfp_arg (ffi_cif *cif, ffi_type *t)
{
int reg = cif->vfp_reg_free;
int nregs = t->size / sizeof (float);
int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT
|| t->type == FFI_TYPE_FLOAT) ? 1 : 2);
/* Align register number. */
if ((reg & 1) && align == 2)
reg++;
while (reg + nregs <= 16)
{
int s, new_used = 0;
for (s = reg; s < reg + nregs; s++)
{
new_used |= (1 << s);
if (cif->vfp_used & (1 << s))
{
reg += align;
goto next_reg;
}
}
/* Found regs to allocate. */
cif->vfp_used |= new_used;
cif->vfp_args[cif->vfp_nargs++] = reg;
/* Update vfp_reg_free. */
if (cif->vfp_used & (1 << cif->vfp_reg_free))
{
reg += nregs;
while (cif->vfp_used & (1 << reg))
reg += 1;
cif->vfp_reg_free = reg;
}
return;
next_reg: ;
}
}
static void layout_vfp_args (ffi_cif *cif)
{
int i;
/* Init VFP fields */
cif->vfp_used = 0;
cif->vfp_nargs = 0;
cif->vfp_reg_free = 0;
memset (cif->vfp_args, -1, 16); /* Init to -1. */
for (i = 0; i < cif->nargs; i++)
{
ffi_type *t = cif->arg_types[i];
if (vfp_type_p (t))
place_vfp_arg (cif, t);
}
}

View File

@@ -0,0 +1,65 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Copyright (c) 2010 CodeSourcery
Target configuration macros for ARM.
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 AUTHORS OR COPYRIGHT
HOLDERS 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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
#ifndef LIBFFI_ASM
typedef unsigned long ffi_arg;
typedef signed long ffi_sarg;
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
FFI_SYSV,
FFI_VFP,
FFI_LAST_ABI,
#ifdef __ARM_PCS_VFP
FFI_DEFAULT_ABI = FFI_VFP,
#else
FFI_DEFAULT_ABI = FFI_SYSV,
#endif
} ffi_abi;
#endif
#define FFI_EXTRA_CIF_FIELDS \
int vfp_used; \
short vfp_reg_free, vfp_nargs; \
signed char vfp_args[16] \
/* Internally used. */
#define FFI_TYPE_STRUCT_VFP_FLOAT (FFI_TYPE_LAST + 1)
#define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2)
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
#define FFI_TRAMPOLINE_SIZE 20
#define FFI_NATIVE_RAW_API 0
#endif

383
.pc/variadic/src/cris/ffi.c Normal file
View File

@@ -0,0 +1,383 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1998 Cygnus Solutions
Copyright (c) 2004 Simon Posnjak
Copyright (c) 2005 Axis Communications AB
Copyright (C) 2007 Free Software Foundation, Inc.
CRIS 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 SIMON POSNJAK 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>
#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
static ffi_status
initialize_aggregate_packed_struct (ffi_type * arg)
{
ffi_type **ptr;
FFI_ASSERT (arg != NULL);
FFI_ASSERT (arg->elements != NULL);
FFI_ASSERT (arg->size == 0);
FFI_ASSERT (arg->alignment == 0);
ptr = &(arg->elements[0]);
while ((*ptr) != NULL)
{
if (((*ptr)->size == 0)
&& (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
FFI_ASSERT (ffi_type_test ((*ptr)));
arg->size += (*ptr)->size;
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
arg->alignment : (*ptr)->alignment;
ptr++;
}
if (arg->size == 0)
return FFI_BAD_TYPEDEF;
else
return FFI_OK;
}
int
ffi_prep_args (char *stack, extended_cif * ecif)
{
unsigned int i;
unsigned int struct_count = 0;
void **p_argv;
char *argp;
ffi_type **p_arg;
argp = stack;
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
(i != 0); i--, p_arg++)
{
size_t z;
switch ((*p_arg)->type)
{
case FFI_TYPE_STRUCT:
{
z = (*p_arg)->size;
if (z <= 4)
{
memcpy (argp, *p_argv, z);
z = 4;
}
else if (z <= 8)
{
memcpy (argp, *p_argv, z);
z = 8;
}
else
{
unsigned int uiLocOnStack;
z = sizeof (void *);
uiLocOnStack = 4 * ecif->cif->nargs + struct_count;
struct_count = struct_count + (*p_arg)->size;
*(unsigned int *) argp =
(unsigned int) (UINT32 *) (stack + uiLocOnStack);
memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size);
}
break;
}
default:
z = (*p_arg)->size;
if (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;
default:
FFI_ASSERT (0);
}
z = sizeof (int);
}
else if (z == sizeof (int))
*(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
else
memcpy (argp, *p_argv, z);
break;
}
p_argv++;
argp += z;
}
return (struct_count);
}
ffi_status
ffi_prep_cif (ffi_cif * cif,
ffi_abi abi, unsigned int nargs,
ffi_type * rtype, ffi_type ** atypes)
{
unsigned bytes = 0;
unsigned int i;
ffi_type **ptr;
FFI_ASSERT (cif != NULL);
FFI_ASSERT (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI);
cif->abi = abi;
cif->arg_types = atypes;
cif->nargs = nargs;
cif->rtype = rtype;
cif->flags = 0;
if ((cif->rtype->size == 0)
&& (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK))
return FFI_BAD_TYPEDEF;
FFI_ASSERT_VALID_TYPE (cif->rtype);
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
{
if (((*ptr)->size == 0)
&& (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
FFI_ASSERT_VALID_TYPE (*ptr);
if (((*ptr)->alignment - 1) & bytes)
bytes = ALIGN (bytes, (*ptr)->alignment);
if ((*ptr)->type == FFI_TYPE_STRUCT)
{
if ((*ptr)->size > 8)
{
bytes += (*ptr)->size;
bytes += sizeof (void *);
}
else
{
if ((*ptr)->size > 4)
bytes += 8;
else
bytes += 4;
}
}
else
bytes += STACK_ARG_SIZE ((*ptr)->size);
}
cif->bytes = bytes;
return ffi_prep_cif_machdep (cif);
}
ffi_status
ffi_prep_cif_machdep (ffi_cif * cif)
{
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
cif->flags = (unsigned) cif->rtype->type;
break;
default:
cif->flags = FFI_TYPE_INT;
break;
}
return FFI_OK;
}
extern void ffi_call_SYSV (int (*)(char *, extended_cif *),
extended_cif *,
unsigned, unsigned, unsigned *, void (*fn) ())
__attribute__ ((__visibility__ ("hidden")));
void
ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue)
{
extended_cif ecif;
ecif.cif = cif;
ecif.avalue = avalue;
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;
}
}
/* Because the following variables are not exported outside libffi, we
mark them hidden. */
/* Assembly code for the jump stub. */
extern const char ffi_cris_trampoline_template[]
__attribute__ ((__visibility__ ("hidden")));
/* Offset into ffi_cris_trampoline_template of where to put the
ffi_prep_closure_inner function. */
extern const int ffi_cris_trampoline_fn_offset
__attribute__ ((__visibility__ ("hidden")));
/* Offset into ffi_cris_trampoline_template of where to put the
closure data. */
extern const int ffi_cris_trampoline_closure_offset
__attribute__ ((__visibility__ ("hidden")));
/* This function is sibling-called (jumped to) by the closure
trampoline. We get R10..R13 at PARAMS[0..3] and a copy of [SP] at
PARAMS[4] to simplify handling of a straddling parameter. A copy
of R9 is at PARAMS[5] and SP at PARAMS[6]. These parameters are
put at the appropriate place in CLOSURE which is then executed and
the return value is passed back to the caller. */
static unsigned long long
ffi_prep_closure_inner (void **params, ffi_closure* closure)
{
char *register_args = (char *) params;
void *struct_ret = params[5];
char *stack_args = params[6];
char *ptr = register_args;
ffi_cif *cif = closure->cif;
ffi_type **arg_types = cif->arg_types;
/* Max room needed is number of arguments as 64-bit values. */
void **avalue = alloca (closure->cif->nargs * sizeof(void *));
int i;
int doing_regs;
long long llret = 0;
/* Find the address of each argument. */
for (i = 0, doing_regs = 1; i < cif->nargs; i++)
{
/* Types up to and including 8 bytes go by-value. */
if (arg_types[i]->size <= 4)
{
avalue[i] = ptr;
ptr += 4;
}
else if (arg_types[i]->size <= 8)
{
avalue[i] = ptr;
ptr += 8;
}
else
{
FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT);
/* Passed by-reference, so copy the pointer. */
avalue[i] = *(void **) ptr;
ptr += 4;
}
/* If we've handled more arguments than fit in registers, start
looking at the those passed on the stack. Step over the
first one if we had a straddling parameter. */
if (doing_regs && ptr >= register_args + 4*4)
{
ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0);
doing_regs = 0;
}
}
/* Invoke the closure. */
(closure->fun) (cif,
cif->rtype->type == FFI_TYPE_STRUCT
/* The caller allocated space for the return
structure, and passed a pointer to this space in
R9. */
? struct_ret
/* We take advantage of being able to ignore that
the high part isn't set if the return value is
not in R10:R11, but in R10 only. */
: (void *) &llret,
avalue, closure->user_data);
return llret;
}
/* API function: Prepare the trampoline. */
ffi_status
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif *, void *, void **, void*),
void *user_data,
void *codeloc)
{
void *innerfn = ffi_prep_closure_inner;
FFI_ASSERT (cif->abi == FFI_SYSV);
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
memcpy (closure->tramp, ffi_cris_trampoline_template,
FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE);
memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
&innerfn, sizeof (void *));
memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
&codeloc, sizeof (void *));
return FFI_OK;
}

177
.pc/variadic/src/prep_cif.c Normal file
View File

@@ -0,0 +1,177 @@
/* -----------------------------------------------------------------------
prep_cif.c - Copyright (c) 2011 Anthony Green
Copyright (c) 1996, 1998, 2007 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 THE AUTHORS OR COPYRIGHT
HOLDERS 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>
/* Round up to FFI_SIZEOF_ARG. */
#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
/* Perform machine independent initialization of aggregate type
specifications. */
static ffi_status initialize_aggregate(ffi_type *arg)
{
ffi_type **ptr;
if (UNLIKELY(arg == NULL || arg->elements == NULL))
return FFI_BAD_TYPEDEF;
arg->size = 0;
arg->alignment = 0;
ptr = &(arg->elements[0]);
if (UNLIKELY(ptr == 0))
return FFI_BAD_TYPEDEF;
while ((*ptr) != NULL)
{
if (UNLIKELY(((*ptr)->size == 0)
&& (initialize_aggregate((*ptr)) != FFI_OK)))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the argument type */
FFI_ASSERT_VALID_TYPE(*ptr);
arg->size = ALIGN(arg->size, (*ptr)->alignment);
arg->size += (*ptr)->size;
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
arg->alignment : (*ptr)->alignment;
ptr++;
}
/* Structure size includes tail padding. This is important for
structures that fit in one register on ABIs like the PowerPC64
Linux ABI that right justify small structs in a register.
It's also needed for nested structure layout, for example
struct A { long a; char b; }; struct B { struct A x; char y; };
should find y at an offset of 2*sizeof(long) and result in a
total size of 3*sizeof(long). */
arg->size = ALIGN (arg->size, arg->alignment);
if (arg->size == 0)
return FFI_BAD_TYPEDEF;
else
return FFI_OK;
}
#ifndef __CRIS__
/* The CRIS ABI specifies structure elements to have byte
alignment only, so it completely overrides this functions,
which assumes "natural" alignment and padding. */
/* Perform machine independent ffi_cif preparation, then call
machine dependent routine. */
ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
ffi_type *rtype, ffi_type **atypes)
{
unsigned bytes = 0;
unsigned int i;
ffi_type **ptr;
FFI_ASSERT(cif != NULL);
if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
return FFI_BAD_ABI;
cif->abi = abi;
cif->arg_types = atypes;
cif->nargs = nargs;
cif->rtype = rtype;
cif->flags = 0;
/* Initialize the return type if necessary */
if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the return type */
FFI_ASSERT_VALID_TYPE(cif->rtype);
/* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */
#if !defined M68K && !defined X86_ANY && !defined S390 && !defined PA
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT
#ifdef SPARC
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
#endif
)
bytes = STACK_ARG_SIZE(sizeof(void*));
#endif
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
{
/* Initialize any uninitialized aggregate type definitions */
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the argument type, do this
check after the initialization. */
FFI_ASSERT_VALID_TYPE(*ptr);
#if !defined X86_ANY && !defined S390 && !defined PA
#ifdef SPARC
if (((*ptr)->type == FFI_TYPE_STRUCT
&& ((*ptr)->size > 16 || cif->abi != FFI_V9))
|| ((*ptr)->type == FFI_TYPE_LONGDOUBLE
&& cif->abi != FFI_V9))
bytes += sizeof(void*);
else
#endif
{
/* Add any padding if necessary */
if (((*ptr)->alignment - 1) & bytes)
bytes = ALIGN(bytes, (*ptr)->alignment);
bytes += STACK_ARG_SIZE((*ptr)->size);
}
#endif
}
cif->bytes = bytes;
/* Perform machine dependent cif processing */
return ffi_prep_cif_machdep(cif);
}
#endif /* not __CRIS__ */
#if FFI_CLOSURES
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data)
{
return ffi_prep_closure_loc (closure, cif, fun, user_data, closure);
}
#endif

View File

@@ -0,0 +1,60 @@
/* Area: ffi_call, closure_call
Purpose: Test doubles passed in variable argument lists.
Limitations: none.
PR: none.
Originator: Blake Chaffin 6/6/2007 */
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
/* { dg-output "" { xfail avr32*-*-* } } */
/* { dg-output "" { xfail mips-sgi-irix6* } } PR libffi/46660 */
/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */
#include "ffitest.h"
static void
cls_double_va_fn(ffi_cif* cif __UNUSED__, void* resp,
void** args, void* userdata __UNUSED__)
{
char* format = *(char**)args[0];
double doubleValue = *(double*)args[1];
*(ffi_arg*)resp = printf(format, doubleValue);
}
int main (void)
{
ffi_cif cif;
void *code;
ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
void* args[3];
ffi_type* arg_types[3];
char* format = "%.1f\n";
double doubleArg = 7;
ffi_arg res = 0;
arg_types[0] = &ffi_type_pointer;
arg_types[1] = &ffi_type_double;
arg_types[2] = NULL;
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
arg_types) == FFI_OK);
args[0] = &format;
args[1] = &doubleArg;
args[2] = NULL;
ffi_call(&cif, FFI_FN(printf), &res, args);
// { dg-output "7.0" }
printf("res: %d\n", (int) res);
// { dg-output "\nres: 4" }
CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL, code) == FFI_OK);
res = ((int(*)(char*, double))(code))(format, doubleArg);
// { dg-output "\n7.0" }
printf("res: %d\n", (int) res);
// { dg-output "\nres: 4" }
exit(0);
}

View File

@@ -0,0 +1,60 @@
/* Area: ffi_call, closure_call
Purpose: Test long doubles passed in variable argument lists.
Limitations: none.
PR: none.
Originator: Blake Chaffin 6/6/2007 */
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
/* { dg-output "" { xfail avr32*-*-* x86_64-*-mingw* } } */
/* { dg-output "" { xfail mips-sgi-irix6* } } PR libffi/46660 */
/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */
#include "ffitest.h"
static void
cls_longdouble_va_fn(ffi_cif* cif __UNUSED__, void* resp,
void** args, void* userdata __UNUSED__)
{
char* format = *(char**)args[0];
long double ldValue = *(long double*)args[1];
*(ffi_arg*)resp = printf(format, ldValue);
}
int main (void)
{
ffi_cif cif;
void *code;
ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
void* args[3];
ffi_type* arg_types[3];
char* format = "%.1Lf\n";
long double ldArg = 7;
ffi_arg res = 0;
arg_types[0] = &ffi_type_pointer;
arg_types[1] = &ffi_type_longdouble;
arg_types[2] = NULL;
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
arg_types) == FFI_OK);
args[0] = &format;
args[1] = &ldArg;
args[2] = NULL;
ffi_call(&cif, FFI_FN(printf), &res, args);
// { dg-output "7.0" }
printf("res: %d\n", (int) res);
// { dg-output "\nres: 4" }
CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL, code) == FFI_OK);
res = ((int(*)(char*, long double))(code))(format, ldArg);
// { dg-output "\n7.0" }
printf("res: %d\n", (int) res);
// { dg-output "\nres: 4" }
exit(0);
}

View File

@@ -1,3 +1,14 @@
2011-11-12 David Gilbert <david.gilbert@linaro.org>
* doc/libffi.texi, include/ffi.h.in, include/ffi_common.h,
man/Makefile.am, man/ffi.3, man/ffi_prep_cif.3,
man/ffi_prep_cif_var.3, src/arm/ffi.c, src/arm/ffitarget.h,
src/cris/ffi.c, src/prep_cif.c,
testsuite/libffi.call/cls_double_va.c,
testsuite/libffi.call/cls_longdouble_va.c,
testsuite/libffi.call/float_va.c: Many changes to support variadic
function calls.
2011-11-12 Kyle Moffett <Kyle.D.Moffett@boeing.com>
* src/powerpc/ffi.c, src/powerpc/ffitarget.h,

View File

@@ -19,7 +19,7 @@
This manual is for Libffi, a portable foreign-function interface
library.
Copyright @copyright{} 2008, 2010 Red Hat, Inc.
Copyright @copyright{} 2008, 2010, 2011 Red Hat, Inc.
@quotation
Permission is granted to copy, distribute and/or modify this document
@@ -133,8 +133,6 @@ This initializes @var{cif} according to the given parameters.
you want. @ref{Multiple ABIs} for more information.
@var{nargs} is the number of arguments that this function accepts.
@samp{libffi} does not yet handle varargs functions; see @ref{Missing
Features} for more information.
@var{rtype} is a pointer to an @code{ffi_type} structure that
describes the return type of the function. @xref{Types}.
@@ -150,6 +148,32 @@ objects is incorrect; or @code{FFI_BAD_ABI} if the @var{abi} parameter
is invalid.
@end defun
If the function being called is variadic (varargs) then
@code{ffi_prep_cif_var} must be used instead of @code{ffi_prep_cif}.
@findex ffi_prep_cif_var
@defun ffi_status ffi_prep_cif_var (ffi_cif *@var{cif}, ffi_abi
var{abi}, unsigned int @var{nfixedargs}, unsigned int
var{ntotalargs}, ffi_type *@var{rtype}, ffi_type **@var{argtypes})
This initializes @var{cif} according to the given parameters for
a call to a variadic function. In general it's operation is the
same as for @code{ffi_prep_cif} except that:
@var{nfixedargs} is the number of fixed arguments, prior to any
variadic arguments. It must be greater than zero.
@var{ntotalargs} the total number of arguments, including variadic
and fixed arguments.
Note that, different cif's must be prepped for calls to the same
function when different numbers of arguments are passed.
Also note that a call to @code{ffi_prep_cif_var} with
@var{nfixedargs}=@var{nototalargs} is NOT equivalent to a call to
@code{ffi_prep_cif}.
@end defun
To call a function using an initialized @code{ffi_cif}, use the
@code{ffi_call} function:
@@ -572,9 +596,7 @@ support for these.
@itemize @bullet
@item
There is no support for calling varargs functions. This may work on
some platforms, depending on how the ABI is defined, but it is not
reliable.
Variadic closures.
@item
There is no support for bit fields in structures.
@@ -591,6 +613,8 @@ The ``raw'' API is undocumented.
@c anything else?
@end itemize
Note that variadic support is very new and tested on a relatively
small number of platforms.
@node Index
@unnumbered Index

View File

@@ -207,6 +207,15 @@ typedef struct {
#endif
} ffi_cif;
/* Used internally, but overridden by some architectures */
ffi_status ffi_prep_cif_core(ffi_cif *cif,
ffi_abi abi,
unsigned int isvariadic,
unsigned int nfixedargs,
unsigned int ntotalargs,
ffi_type *rtype,
ffi_type **atypes);
/* ---- Definitions for the raw API -------------------------------------- */
#ifndef FFI_SIZEOF_ARG
@@ -384,6 +393,13 @@ ffi_status ffi_prep_cif(ffi_cif *cif,
ffi_type *rtype,
ffi_type **atypes);
ffi_status ffi_prep_cif_var(ffi_cif *cif,
ffi_abi abi,
unsigned int nfixedargs,
unsigned int ntotalargs,
ffi_type *rtype,
ffi_type **atypes);
void ffi_call(ffi_cif *cif,
void (*fn)(void),
void *rvalue,

View File

@@ -75,6 +75,8 @@ void ffi_type_test(ffi_type *a, char *file, int line);
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif);
ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
unsigned int nfixedargs, unsigned int ntotalargs);
/* Extended cif, used in callback from assembly routine */
typedef struct

View File

@@ -2,7 +2,7 @@
AUTOMAKE_OPTIONS=foreign
EXTRA_DIST = ffi.3 ffi_call.3 ffi_prep_cif.3
EXTRA_DIST = ffi.3 ffi_call.3 ffi_prep_cif.3 ffi_prep_cif_var.3
man_MANS = ffi.3 ffi_call.3 ffi_prep_cif.3
man_MANS = ffi.3 ffi_call.3 ffi_prep_cif.3 ffi_prep_cif_var.3

View File

@@ -16,6 +16,15 @@ libffi, -lffi
.Fa "ffi_type **atypes"
.Fc
.Ft void
.Fo ffi_prep_cif_var
.Fa "ffi_cif *cif"
.Fa "ffi_abi abi"
.Fa "unsigned int nfixedargs"
.Fa "unsigned int ntotalargs"
.Fa "ffi_type *rtype"
.Fa "ffi_type **atypes"
.Fc
.Ft void
.Fo ffi_call
.Fa "ffi_cif *cif"
.Fa "void (*fn)(void)"
@@ -28,4 +37,5 @@ generate a call to another function at runtime without requiring knowledge of
the called function's interface at compile time.
.Sh SEE ALSO
.Xr ffi_prep_cif 3 ,
.Xr ffi_prep_cif_var 3 ,
.Xr ffi_call 3

View File

@@ -37,7 +37,9 @@ structs that describe the data type, size and alignment of each argument.
points to an
.Nm ffi_type
that describes the data type, size and alignment of the
return value.
return value. Note that to call a variadic function
.Nm ffi_prep_cif_var
must be used instead.
.Sh RETURN VALUES
Upon successful completion,
.Nm ffi_prep_cif
@@ -63,4 +65,6 @@ defined in
.
.Sh SEE ALSO
.Xr ffi 3 ,
.Xr ffi_call 3
.Xr ffi_call 3 ,
.Xr ffi_prep_cif_var 3

73
man/ffi_prep_cif_var.3 Normal file
View File

@@ -0,0 +1,73 @@
.Dd January 25, 2011
.Dt ffi_prep_cif_var 3
.Sh NAME
.Nm ffi_prep_cif_var
.Nd Prepare a
.Nm ffi_cif
structure for use with
.Nm ffi_call
for variadic functions.
.Sh SYNOPSIS
.In ffi.h
.Ft ffi_status
.Fo ffi_prep_cif_var
.Fa "ffi_cif *cif"
.Fa "ffi_abi abi"
.Fa "unsigned int nfixedargs"
.Fa "unsigned int ntotalargs"
.Fa "ffi_type *rtype"
.Fa "ffi_type **atypes"
.Fc
.Sh DESCRIPTION
The
.Nm ffi_prep_cif_var
function prepares a
.Nm ffi_cif
structure for use with
.Nm ffi_call
for variadic functions.
.Fa abi
specifies a set of calling conventions to use.
.Fa atypes
is an array of
.Fa ntotalargs
pointers to
.Nm ffi_type
structs that describe the data type, size and alignment of each argument.
.Fa rtype
points to an
.Nm ffi_type
that describes the data type, size and alignment of the
return value.
.Fa nfixedargs
must contain the number of fixed (non-variadic) arguments.
Note that to call a non-variadic function
.Nm ffi_prep_cif
must be used.
.Sh RETURN VALUES
Upon successful completion,
.Nm ffi_prep_cif_var
returns
.Nm FFI_OK .
It will return
.Nm FFI_BAD_TYPEDEF
if
.Fa cif
is
.Nm NULL
or
.Fa atypes
or
.Fa rtype
is malformed. If
.Fa abi
does not refer to a valid ABI,
.Nm FFI_BAD_ABI
will be returned. Available ABIs are
defined in
.Nm <ffitarget.h>
.
.Sh SEE ALSO
.Xr ffi 3 ,
.Xr ffi_call 3 ,
.Xr ffi_prep_cif 3

View File

@@ -36,3 +36,4 @@ minix
interix-patch
remove-debug-code
powerpc-ffi-softfloat
variadic

581
patches/variadic Normal file
View File

@@ -0,0 +1,581 @@
Index: libffi/include/ffi.h.in
===================================================================
--- libffi.orig/include/ffi.h.in
+++ libffi/include/ffi.h.in
@@ -207,6 +207,15 @@ typedef struct {
#endif
} ffi_cif;
+/* Used internally, but overridden by some architectures */
+ffi_status ffi_prep_cif_core(ffi_cif *cif,
+ ffi_abi abi,
+ unsigned int isvariadic,
+ unsigned int nfixedargs,
+ unsigned int ntotalargs,
+ ffi_type *rtype,
+ ffi_type **atypes);
+
/* ---- Definitions for the raw API -------------------------------------- */
#ifndef FFI_SIZEOF_ARG
@@ -384,6 +393,13 @@ ffi_status ffi_prep_cif(ffi_cif *cif,
ffi_type *rtype,
ffi_type **atypes);
+ffi_status ffi_prep_cif_var(ffi_cif *cif,
+ ffi_abi abi,
+ unsigned int nfixedargs,
+ unsigned int ntotalargs,
+ ffi_type *rtype,
+ ffi_type **atypes);
+
void ffi_call(ffi_cif *cif,
void (*fn)(void),
void *rvalue,
Index: libffi/include/ffi_common.h
===================================================================
--- libffi.orig/include/ffi_common.h
+++ libffi/include/ffi_common.h
@@ -75,6 +75,8 @@ void ffi_type_test(ffi_type *a, char *fi
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif);
+ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
+ unsigned int nfixedargs, unsigned int ntotalargs);
/* Extended cif, used in callback from assembly routine */
typedef struct
Index: libffi/man/Makefile.am
===================================================================
--- libffi.orig/man/Makefile.am
+++ libffi/man/Makefile.am
@@ -2,7 +2,7 @@
AUTOMAKE_OPTIONS=foreign
-EXTRA_DIST = ffi.3 ffi_call.3 ffi_prep_cif.3
+EXTRA_DIST = ffi.3 ffi_call.3 ffi_prep_cif.3 ffi_prep_cif_var.3
-man_MANS = ffi.3 ffi_call.3 ffi_prep_cif.3
+man_MANS = ffi.3 ffi_call.3 ffi_prep_cif.3 ffi_prep_cif_var.3
Index: libffi/man/ffi.3
===================================================================
--- libffi.orig/man/ffi.3
+++ libffi/man/ffi.3
@@ -16,6 +16,15 @@ libffi, -lffi
.Fa "ffi_type **atypes"
.Fc
.Ft void
+.Fo ffi_prep_cif_var
+.Fa "ffi_cif *cif"
+.Fa "ffi_abi abi"
+.Fa "unsigned int nfixedargs"
+.Fa "unsigned int ntotalargs"
+.Fa "ffi_type *rtype"
+.Fa "ffi_type **atypes"
+.Fc
+.Ft void
.Fo ffi_call
.Fa "ffi_cif *cif"
.Fa "void (*fn)(void)"
@@ -28,4 +37,5 @@ generate a call to another function at r
the called function's interface at compile time.
.Sh SEE ALSO
.Xr ffi_prep_cif 3 ,
+.Xr ffi_prep_cif_var 3 ,
.Xr ffi_call 3
Index: libffi/man/ffi_prep_cif.3
===================================================================
--- libffi.orig/man/ffi_prep_cif.3
+++ libffi/man/ffi_prep_cif.3
@@ -37,7 +37,9 @@ structs that describe the data type, siz
points to an
.Nm ffi_type
that describes the data type, size and alignment of the
-return value.
+return value. Note that to call a variadic function
+.Nm ffi_prep_cif_var
+must be used instead.
.Sh RETURN VALUES
Upon successful completion,
.Nm ffi_prep_cif
@@ -63,4 +65,6 @@ defined in
.
.Sh SEE ALSO
.Xr ffi 3 ,
-.Xr ffi_call 3
+.Xr ffi_call 3 ,
+.Xr ffi_prep_cif_var 3
+
Index: libffi/man/ffi_prep_cif_var.3
===================================================================
--- /dev/null
+++ libffi/man/ffi_prep_cif_var.3
@@ -0,0 +1,73 @@
+.Dd January 25, 2011
+.Dt ffi_prep_cif_var 3
+.Sh NAME
+.Nm ffi_prep_cif_var
+.Nd Prepare a
+.Nm ffi_cif
+structure for use with
+.Nm ffi_call
+for variadic functions.
+.Sh SYNOPSIS
+.In ffi.h
+.Ft ffi_status
+.Fo ffi_prep_cif_var
+.Fa "ffi_cif *cif"
+.Fa "ffi_abi abi"
+.Fa "unsigned int nfixedargs"
+.Fa "unsigned int ntotalargs"
+.Fa "ffi_type *rtype"
+.Fa "ffi_type **atypes"
+.Fc
+.Sh DESCRIPTION
+The
+.Nm ffi_prep_cif_var
+function prepares a
+.Nm ffi_cif
+structure for use with
+.Nm ffi_call
+for variadic functions.
+.Fa abi
+specifies a set of calling conventions to use.
+.Fa atypes
+is an array of
+.Fa ntotalargs
+pointers to
+.Nm ffi_type
+structs that describe the data type, size and alignment of each argument.
+.Fa rtype
+points to an
+.Nm ffi_type
+that describes the data type, size and alignment of the
+return value.
+.Fa nfixedargs
+must contain the number of fixed (non-variadic) arguments.
+Note that to call a non-variadic function
+.Nm ffi_prep_cif
+must be used.
+.Sh RETURN VALUES
+Upon successful completion,
+.Nm ffi_prep_cif_var
+returns
+.Nm FFI_OK .
+It will return
+.Nm FFI_BAD_TYPEDEF
+if
+.Fa cif
+is
+.Nm NULL
+or
+.Fa atypes
+or
+.Fa rtype
+is malformed. If
+.Fa abi
+does not refer to a valid ABI,
+.Nm FFI_BAD_ABI
+will be returned. Available ABIs are
+defined in
+.Nm <ffitarget.h>
+.
+.Sh SEE ALSO
+.Xr ffi 3 ,
+.Xr ffi_call 3 ,
+.Xr ffi_prep_cif 3
Index: libffi/src/arm/ffi.c
===================================================================
--- libffi.orig/src/arm/ffi.c
+++ libffi/src/arm/ffi.c
@@ -196,6 +196,18 @@ ffi_status ffi_prep_cif_machdep(ffi_cif
return FFI_OK;
}
+/* Perform machine dependent cif processing for variadic calls */
+ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
+ unsigned int nfixedargs,
+ unsigned int ntotalargs)
+{
+ /* VFP variadic calls actually use the SYSV ABI */
+ if (cif->abi == FFI_VFP)
+ cif->abi = FFI_SYSV;
+
+ return ffi_prep_cif_machdep(cif);
+}
+
/* Prototypes for assembly functions, in sysv.S */
extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
Index: libffi/src/arm/ffitarget.h
===================================================================
--- libffi.orig/src/arm/ffitarget.h
+++ libffi/src/arm/ffitarget.h
@@ -55,6 +55,8 @@ typedef enum ffi_abi {
#define FFI_TYPE_STRUCT_VFP_FLOAT (FFI_TYPE_LAST + 1)
#define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2)
+#define FFI_TARGET_SPECIFIC_VARIADIC
+
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
@@ -62,4 +64,3 @@ typedef enum ffi_abi {
#define FFI_NATIVE_RAW_API 0
#endif
-
Index: libffi/src/cris/ffi.c
===================================================================
--- libffi.orig/src/cris/ffi.c
+++ libffi/src/cris/ffi.c
@@ -153,21 +153,24 @@ ffi_prep_args (char *stack, extended_cif
return (struct_count);
}
-ffi_status
-ffi_prep_cif (ffi_cif * cif,
- ffi_abi abi, unsigned int nargs,
- ffi_type * rtype, ffi_type ** atypes)
+ffi_status FFI_HIDDEN
+ffi_prep_cif_core (ffi_cif * cif,
+ ffi_abi abi, unsigned int isvariadic,
+ unsigned int nfixedargs, unsigned int ntotalargs,
+ ffi_type * rtype, ffi_type ** atypes)
{
unsigned bytes = 0;
unsigned int i;
ffi_type **ptr;
FFI_ASSERT (cif != NULL);
+ FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
+ FFI_ASSERT(nfixedargs <= ntotalargs);
FFI_ASSERT (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI);
cif->abi = abi;
cif->arg_types = atypes;
- cif->nargs = nargs;
+ cif->nargs = ntotalargs;
cif->rtype = rtype;
cif->flags = 0;
Index: libffi/src/prep_cif.c
===================================================================
--- libffi.orig/src/prep_cif.c
+++ libffi/src/prep_cif.c
@@ -90,20 +90,33 @@ static ffi_status initialize_aggregate(f
/* Perform machine independent ffi_cif preparation, then call
machine dependent routine. */
-ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
- ffi_type *rtype, ffi_type **atypes)
+/* For non variadic functions isvariadic should be 0 and
+ nfixedargs==ntotalargs.
+
+ For variadic calls, isvariadic should be 1 and nfixedargs
+ and ntotalargs set as appropriate. nfixedargs must always be >=1 */
+
+
+ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
+ unsigned int isvariadic,
+ unsigned int nfixedargs,
+ unsigned int ntotalargs,
+ ffi_type *rtype, ffi_type **atypes)
{
unsigned bytes = 0;
unsigned int i;
ffi_type **ptr;
FFI_ASSERT(cif != NULL);
+ FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
+ FFI_ASSERT(nfixedargs <= ntotalargs);
+
if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
return FFI_BAD_ABI;
cif->abi = abi;
cif->arg_types = atypes;
- cif->nargs = nargs;
+ cif->nargs = ntotalargs;
cif->rtype = rtype;
cif->flags = 0;
@@ -159,10 +172,31 @@ ffi_status ffi_prep_cif(ffi_cif *cif, ff
cif->bytes = bytes;
/* Perform machine dependent cif processing */
+#ifdef FFI_TARGET_SPECIFIC_VARIADIC
+ if (isvariadic)
+ return ffi_prep_cif_machdep_var(cif, nfixedargs, ntotalargs);
+#endif
+
return ffi_prep_cif_machdep(cif);
}
#endif /* not __CRIS__ */
+ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
+ ffi_type *rtype, ffi_type **atypes)
+{
+ return ffi_prep_cif_core(cif, abi, 0, nargs, nargs, rtype, atypes);
+}
+
+ffi_status ffi_prep_cif_var(ffi_cif *cif,
+ ffi_abi abi,
+ unsigned int nfixedargs,
+ unsigned int ntotalargs,
+ ffi_type *rtype,
+ ffi_type **atypes)
+{
+ return ffi_prep_cif_core(cif, abi, 1, nfixedargs, ntotalargs, rtype, atypes);
+}
+
#if FFI_CLOSURES
ffi_status
Index: libffi/testsuite/libffi.call/cls_double_va.c
===================================================================
--- libffi.orig/testsuite/libffi.call/cls_double_va.c
+++ libffi/testsuite/libffi.call/cls_double_va.c
@@ -37,7 +37,8 @@ int main (void)
arg_types[1] = &ffi_type_double;
arg_types[2] = NULL;
- CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
+ /* This printf call is variadic */
+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
arg_types) == FFI_OK);
args[0] = &format;
Index: libffi/testsuite/libffi.call/cls_longdouble_va.c
===================================================================
--- libffi.orig/testsuite/libffi.call/cls_longdouble_va.c
+++ libffi/testsuite/libffi.call/cls_longdouble_va.c
@@ -37,7 +37,8 @@ int main (void)
arg_types[1] = &ffi_type_longdouble;
arg_types[2] = NULL;
- CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
+ /* This printf call is variadic */
+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
arg_types) == FFI_OK);
args[0] = &format;
@@ -49,6 +50,10 @@ int main (void)
printf("res: %d\n", (int) res);
// { dg-output "\nres: 4" }
+ /* The call to cls_longdouble_va_fn is static, so have to use a normal prep_cif */
+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
+ arg_types) == FFI_OK);
+
CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL, code) == FFI_OK);
res = ((int(*)(char*, long double))(code))(format, ldArg);
Index: libffi/testsuite/libffi.call/float_va.c
===================================================================
--- /dev/null
+++ libffi/testsuite/libffi.call/float_va.c
@@ -0,0 +1,107 @@
+/* Area: fp and variadics
+ Purpose: check fp inputs and returns work on variadics, even the fixed params
+ Limitations: None
+ PR: none
+ Originator: <david.gilbert@linaro.org> 2011-01-25
+
+ Intended to stress the difference in ABI on ARM vfp
+*/
+
+/* { dg-do run } */
+
+#include <stdarg.h>
+
+#include "ffitest.h"
+
+/* prints out all the parameters, and returns the sum of them all.
+ * 'x' is the number of variadic parameters all of which are double in this test
+ */
+double float_va_fn(unsigned int x, double y,...)
+{
+ double total=0.0;
+ va_list ap;
+ unsigned int i;
+
+ total+=(double)x;
+ total+=y;
+
+ printf("%u: %.1lf :", x, y);
+
+ va_start(ap, y);
+ for(i=0;i<x;i++)
+ {
+ double arg=va_arg(ap, double);
+ total+=arg;
+ printf(" %d:%.1lf ", i, arg);
+ }
+ va_end(ap);
+
+ printf(" total: %.1lf\n", total);
+
+ return total;
+}
+
+int main (void)
+{
+ ffi_cif cif;
+
+ ffi_type *arg_types[5];
+ void *values[5];
+ double doubles[5];
+ unsigned int firstarg;
+ double resfp;
+
+ /* First test, pass float_va_fn(0,2.0) - note there are no actual
+ * variadic parameters, but it's declared variadic so the ABI may be
+ * different. */
+ /* Call it statically and then via ffi */
+ resfp=float_va_fn(0,2.0);
+ // { dg-output "0: 2.0 : total: 2.0" }
+ printf("compiled: %.1lf\n", resfp);
+ // { dg-output "\ncompiled: 2.0" }
+
+ arg_types[0] = &ffi_type_uint;
+ arg_types[1] = &ffi_type_double;
+ arg_types[2] = NULL;
+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 2, 2,
+ &ffi_type_double, arg_types) == FFI_OK);
+
+ firstarg = 0;
+ doubles[0] = 2.0;
+ values[0] = &firstarg;
+ values[1] = &doubles[0];
+ ffi_call(&cif, FFI_FN(float_va_fn), &resfp, values);
+ // { dg-output "\n0: 2.0 : total: 2.0" }
+ printf("ffi: %.1lf\n", resfp);
+ // { dg-output "\nffi: 2.0" }
+
+ /* Second test, float_va_fn(2,2.0,3.0,4.0), now with variadic params */
+ /* Call it statically and then via ffi */
+ resfp=float_va_fn(2,2.0,3.0,4.0);
+ // { dg-output "\n2: 2.0 : 0:3.0 1:4.0 total: 11.0" }
+ printf("compiled: %.1lf\n", resfp);
+ // { dg-output "\ncompiled: 11.0" }
+
+ arg_types[0] = &ffi_type_uint;
+ arg_types[1] = &ffi_type_double;
+ arg_types[2] = &ffi_type_double;
+ arg_types[3] = &ffi_type_double;
+ arg_types[4] = NULL;
+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 2, 4,
+ &ffi_type_double, arg_types) == FFI_OK);
+
+ firstarg = 2;
+ doubles[0] = 2.0;
+ doubles[1] = 3.0;
+ doubles[2] = 4.0;
+ values[0] = &firstarg;
+ values[1] = &doubles[0];
+ values[2] = &doubles[1];
+ values[3] = &doubles[2];
+ ffi_call(&cif, FFI_FN(float_va_fn), &resfp, values);
+ // { dg-output "\n2: 2.0 : 0:3.0 1:4.0 total: 11.0" }
+ printf("ffi: %.1lf\n", resfp);
+ // { dg-output "\nffi: 11.0" }
+
+ exit(0);
+}
Index: libffi/doc/libffi.texi
===================================================================
--- libffi.orig/doc/libffi.texi
+++ libffi/doc/libffi.texi
@@ -19,7 +19,7 @@
This manual is for Libffi, a portable foreign-function interface
library.
-Copyright @copyright{} 2008, 2010 Red Hat, Inc.
+Copyright @copyright{} 2008, 2010, 2011 Red Hat, Inc.
@quotation
Permission is granted to copy, distribute and/or modify this document
@@ -133,8 +133,6 @@ This initializes @var{cif} according to
you want. @ref{Multiple ABIs} for more information.
@var{nargs} is the number of arguments that this function accepts.
-@samp{libffi} does not yet handle varargs functions; see @ref{Missing
-Features} for more information.
@var{rtype} is a pointer to an @code{ffi_type} structure that
describes the return type of the function. @xref{Types}.
@@ -150,6 +148,32 @@ objects is incorrect; or @code{FFI_BAD_A
is invalid.
@end defun
+If the function being called is variadic (varargs) then
+@code{ffi_prep_cif_var} must be used instead of @code{ffi_prep_cif}.
+
+@findex ffi_prep_cif_var
+@defun ffi_status ffi_prep_cif_var (ffi_cif *@var{cif}, ffi_abi
+var{abi}, unsigned int @var{nfixedargs}, unsigned int
+var{ntotalargs}, ffi_type *@var{rtype}, ffi_type **@var{argtypes})
+This initializes @var{cif} according to the given parameters for
+a call to a variadic function. In general it's operation is the
+same as for @code{ffi_prep_cif} except that:
+
+@var{nfixedargs} is the number of fixed arguments, prior to any
+variadic arguments. It must be greater than zero.
+
+@var{ntotalargs} the total number of arguments, including variadic
+and fixed arguments.
+
+Note that, different cif's must be prepped for calls to the same
+function when different numbers of arguments are passed.
+
+Also note that a call to @code{ffi_prep_cif_var} with
+@var{nfixedargs}=@var{nototalargs} is NOT equivalent to a call to
+@code{ffi_prep_cif}.
+
+@end defun
+
To call a function using an initialized @code{ffi_cif}, use the
@code{ffi_call} function:
@@ -572,9 +596,7 @@ support for these.
@itemize @bullet
@item
-There is no support for calling varargs functions. This may work on
-some platforms, depending on how the ABI is defined, but it is not
-reliable.
+Variadic closures.
@item
There is no support for bit fields in structures.
@@ -591,6 +613,8 @@ The ``raw'' API is undocumented.
@c anything else?
@end itemize
+Note that variadic support is very new and tested on a relatively
+small number of platforms.
@node Index
@unnumbered Index
Index: libffi/ChangeLog
===================================================================
--- libffi.orig/ChangeLog
+++ libffi/ChangeLog
@@ -1,3 +1,14 @@
+2011-11-12 David Gilbert <david.gilbert@linaro.org>
+
+ * doc/libffi.texi, include/ffi.h.in, include/ffi_common.h,
+ man/Makefile.am, man/ffi.3, man/ffi_prep_cif.3,
+ man/ffi_prep_cif_var.3, src/arm/ffi.c, src/arm/ffitarget.h,
+ src/cris/ffi.c, src/prep_cif.c,
+ testsuite/libffi.call/cls_double_va.c,
+ testsuite/libffi.call/cls_longdouble_va.c,
+ testsuite/libffi.call/float_va.c: Many changes to support variadic
+ function calls.
+
2011-11-12 Kyle Moffett <Kyle.D.Moffett@boeing.com>
* src/powerpc/ffi.c, src/powerpc/ffitarget.h,

View File

@@ -196,6 +196,18 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
return FFI_OK;
}
/* Perform machine dependent cif processing for variadic calls */
ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
unsigned int nfixedargs,
unsigned int ntotalargs)
{
/* VFP variadic calls actually use the SYSV ABI */
if (cif->abi == FFI_VFP)
cif->abi = FFI_SYSV;
return ffi_prep_cif_machdep(cif);
}
/* Prototypes for assembly functions, in sysv.S */
extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);

View File

@@ -55,6 +55,8 @@ typedef enum ffi_abi {
#define FFI_TYPE_STRUCT_VFP_FLOAT (FFI_TYPE_LAST + 1)
#define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2)
#define FFI_TARGET_SPECIFIC_VARIADIC
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
@@ -62,4 +64,3 @@ typedef enum ffi_abi {
#define FFI_NATIVE_RAW_API 0
#endif

View File

@@ -153,21 +153,24 @@ ffi_prep_args (char *stack, extended_cif * ecif)
return (struct_count);
}
ffi_status
ffi_prep_cif (ffi_cif * cif,
ffi_abi abi, unsigned int nargs,
ffi_type * rtype, ffi_type ** atypes)
ffi_status FFI_HIDDEN
ffi_prep_cif_core (ffi_cif * cif,
ffi_abi abi, unsigned int isvariadic,
unsigned int nfixedargs, unsigned int ntotalargs,
ffi_type * rtype, ffi_type ** atypes)
{
unsigned bytes = 0;
unsigned int i;
ffi_type **ptr;
FFI_ASSERT (cif != NULL);
FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
FFI_ASSERT(nfixedargs <= ntotalargs);
FFI_ASSERT (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI);
cif->abi = abi;
cif->arg_types = atypes;
cif->nargs = nargs;
cif->nargs = ntotalargs;
cif->rtype = rtype;
cif->flags = 0;

View File

@@ -90,20 +90,33 @@ static ffi_status initialize_aggregate(ffi_type *arg)
/* Perform machine independent ffi_cif preparation, then call
machine dependent routine. */
ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
ffi_type *rtype, ffi_type **atypes)
/* For non variadic functions isvariadic should be 0 and
nfixedargs==ntotalargs.
For variadic calls, isvariadic should be 1 and nfixedargs
and ntotalargs set as appropriate. nfixedargs must always be >=1 */
ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
unsigned int isvariadic,
unsigned int nfixedargs,
unsigned int ntotalargs,
ffi_type *rtype, ffi_type **atypes)
{
unsigned bytes = 0;
unsigned int i;
ffi_type **ptr;
FFI_ASSERT(cif != NULL);
FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
FFI_ASSERT(nfixedargs <= ntotalargs);
if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
return FFI_BAD_ABI;
cif->abi = abi;
cif->arg_types = atypes;
cif->nargs = nargs;
cif->nargs = ntotalargs;
cif->rtype = rtype;
cif->flags = 0;
@@ -159,10 +172,31 @@ ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
cif->bytes = bytes;
/* Perform machine dependent cif processing */
#ifdef FFI_TARGET_SPECIFIC_VARIADIC
if (isvariadic)
return ffi_prep_cif_machdep_var(cif, nfixedargs, ntotalargs);
#endif
return ffi_prep_cif_machdep(cif);
}
#endif /* not __CRIS__ */
ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
ffi_type *rtype, ffi_type **atypes)
{
return ffi_prep_cif_core(cif, abi, 0, nargs, nargs, rtype, atypes);
}
ffi_status ffi_prep_cif_var(ffi_cif *cif,
ffi_abi abi,
unsigned int nfixedargs,
unsigned int ntotalargs,
ffi_type *rtype,
ffi_type **atypes)
{
return ffi_prep_cif_core(cif, abi, 1, nfixedargs, ntotalargs, rtype, atypes);
}
#if FFI_CLOSURES
ffi_status

View File

@@ -37,7 +37,8 @@ int main (void)
arg_types[1] = &ffi_type_double;
arg_types[2] = NULL;
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
/* This printf call is variadic */
CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
arg_types) == FFI_OK);
args[0] = &format;

View File

@@ -37,7 +37,8 @@ int main (void)
arg_types[1] = &ffi_type_longdouble;
arg_types[2] = NULL;
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
/* This printf call is variadic */
CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2, &ffi_type_sint,
arg_types) == FFI_OK);
args[0] = &format;
@@ -49,6 +50,10 @@ int main (void)
printf("res: %d\n", (int) res);
// { dg-output "\nres: 4" }
/* The call to cls_longdouble_va_fn is static, so have to use a normal prep_cif */
CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint,
arg_types) == FFI_OK);
CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL, code) == FFI_OK);
res = ((int(*)(char*, long double))(code))(format, ldArg);

View File

@@ -0,0 +1,107 @@
/* Area: fp and variadics
Purpose: check fp inputs and returns work on variadics, even the fixed params
Limitations: None
PR: none
Originator: <david.gilbert@linaro.org> 2011-01-25
Intended to stress the difference in ABI on ARM vfp
*/
/* { dg-do run } */
#include <stdarg.h>
#include "ffitest.h"
/* prints out all the parameters, and returns the sum of them all.
* 'x' is the number of variadic parameters all of which are double in this test
*/
double float_va_fn(unsigned int x, double y,...)
{
double total=0.0;
va_list ap;
unsigned int i;
total+=(double)x;
total+=y;
printf("%u: %.1lf :", x, y);
va_start(ap, y);
for(i=0;i<x;i++)
{
double arg=va_arg(ap, double);
total+=arg;
printf(" %d:%.1lf ", i, arg);
}
va_end(ap);
printf(" total: %.1lf\n", total);
return total;
}
int main (void)
{
ffi_cif cif;
ffi_type *arg_types[5];
void *values[5];
double doubles[5];
unsigned int firstarg;
double resfp;
/* First test, pass float_va_fn(0,2.0) - note there are no actual
* variadic parameters, but it's declared variadic so the ABI may be
* different. */
/* Call it statically and then via ffi */
resfp=float_va_fn(0,2.0);
// { dg-output "0: 2.0 : total: 2.0" }
printf("compiled: %.1lf\n", resfp);
// { dg-output "\ncompiled: 2.0" }
arg_types[0] = &ffi_type_uint;
arg_types[1] = &ffi_type_double;
arg_types[2] = NULL;
CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 2, 2,
&ffi_type_double, arg_types) == FFI_OK);
firstarg = 0;
doubles[0] = 2.0;
values[0] = &firstarg;
values[1] = &doubles[0];
ffi_call(&cif, FFI_FN(float_va_fn), &resfp, values);
// { dg-output "\n0: 2.0 : total: 2.0" }
printf("ffi: %.1lf\n", resfp);
// { dg-output "\nffi: 2.0" }
/* Second test, float_va_fn(2,2.0,3.0,4.0), now with variadic params */
/* Call it statically and then via ffi */
resfp=float_va_fn(2,2.0,3.0,4.0);
// { dg-output "\n2: 2.0 : 0:3.0 1:4.0 total: 11.0" }
printf("compiled: %.1lf\n", resfp);
// { dg-output "\ncompiled: 11.0" }
arg_types[0] = &ffi_type_uint;
arg_types[1] = &ffi_type_double;
arg_types[2] = &ffi_type_double;
arg_types[3] = &ffi_type_double;
arg_types[4] = NULL;
CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 2, 4,
&ffi_type_double, arg_types) == FFI_OK);
firstarg = 2;
doubles[0] = 2.0;
doubles[1] = 3.0;
doubles[2] = 4.0;
values[0] = &firstarg;
values[1] = &doubles[0];
values[2] = &doubles[1];
values[3] = &doubles[2];
ffi_call(&cif, FFI_FN(float_va_fn), &resfp, values);
// { dg-output "\n2: 2.0 : 0:3.0 1:4.0 total: 11.0" }
printf("ffi: %.1lf\n", resfp);
// { dg-output "\nffi: 11.0" }
exit(0);
}