Add David Gilbert's variadic function call support
This commit is contained in:
@@ -35,3 +35,4 @@ minix
|
|||||||
interix-patch
|
interix-patch
|
||||||
remove-debug-code
|
remove-debug-code
|
||||||
powerpc-ffi-softfloat
|
powerpc-ffi-softfloat
|
||||||
|
variadic
|
||||||
|
|||||||
0
.pc/variadic/.timestamp
Normal file
0
.pc/variadic/.timestamp
Normal file
4667
.pc/variadic/ChangeLog
Normal file
4667
.pc/variadic/ChangeLog
Normal file
File diff suppressed because it is too large
Load Diff
600
.pc/variadic/doc/libffi.texi
Normal file
600
.pc/variadic/doc/libffi.texi
Normal 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
|
||||||
427
.pc/variadic/include/ffi.h.in
Normal file
427
.pc/variadic/include/ffi.h.in
Normal 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
|
||||||
126
.pc/variadic/include/ffi_common.h
Normal file
126
.pc/variadic/include/ffi_common.h
Normal 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
|
||||||
8
.pc/variadic/man/Makefile.am
Normal file
8
.pc/variadic/man/Makefile.am
Normal 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
31
.pc/variadic/man/ffi.3
Normal 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
|
||||||
66
.pc/variadic/man/ffi_prep_cif.3
Normal file
66
.pc/variadic/man/ffi_prep_cif.3
Normal 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
|
||||||
0
.pc/variadic/man/ffi_prep_cif_var.3
Normal file
0
.pc/variadic/man/ffi_prep_cif_var.3
Normal file
740
.pc/variadic/src/arm/ffi.c
Normal file
740
.pc/variadic/src/arm/ffi.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
65
.pc/variadic/src/arm/ffitarget.h
Normal file
65
.pc/variadic/src/arm/ffitarget.h
Normal 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
383
.pc/variadic/src/cris/ffi.c
Normal 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
177
.pc/variadic/src/prep_cif.c
Normal 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
|
||||||
60
.pc/variadic/testsuite/libffi.call/cls_double_va.c
Normal file
60
.pc/variadic/testsuite/libffi.call/cls_double_va.c
Normal 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);
|
||||||
|
}
|
||||||
60
.pc/variadic/testsuite/libffi.call/cls_longdouble_va.c
Normal file
60
.pc/variadic/testsuite/libffi.call/cls_longdouble_va.c
Normal 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);
|
||||||
|
}
|
||||||
0
.pc/variadic/testsuite/libffi.call/float_va.c
Normal file
0
.pc/variadic/testsuite/libffi.call/float_va.c
Normal file
11
ChangeLog
11
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>
|
2011-11-12 Kyle Moffett <Kyle.D.Moffett@boeing.com>
|
||||||
|
|
||||||
* src/powerpc/ffi.c, src/powerpc/ffitarget.h,
|
* src/powerpc/ffi.c, src/powerpc/ffitarget.h,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
This manual is for Libffi, a portable foreign-function interface
|
This manual is for Libffi, a portable foreign-function interface
|
||||||
library.
|
library.
|
||||||
|
|
||||||
Copyright @copyright{} 2008, 2010 Red Hat, Inc.
|
Copyright @copyright{} 2008, 2010, 2011 Red Hat, Inc.
|
||||||
|
|
||||||
@quotation
|
@quotation
|
||||||
Permission is granted to copy, distribute and/or modify this document
|
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.
|
you want. @ref{Multiple ABIs} for more information.
|
||||||
|
|
||||||
@var{nargs} is the number of arguments that this function accepts.
|
@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
|
@var{rtype} is a pointer to an @code{ffi_type} structure that
|
||||||
describes the return type of the function. @xref{Types}.
|
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.
|
is invalid.
|
||||||
@end defun
|
@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
|
To call a function using an initialized @code{ffi_cif}, use the
|
||||||
@code{ffi_call} function:
|
@code{ffi_call} function:
|
||||||
@@ -572,9 +596,7 @@ support for these.
|
|||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@item
|
||||||
There is no support for calling varargs functions. This may work on
|
Variadic closures.
|
||||||
some platforms, depending on how the ABI is defined, but it is not
|
|
||||||
reliable.
|
|
||||||
|
|
||||||
@item
|
@item
|
||||||
There is no support for bit fields in structures.
|
There is no support for bit fields in structures.
|
||||||
@@ -591,6 +613,8 @@ The ``raw'' API is undocumented.
|
|||||||
@c anything else?
|
@c anything else?
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
|
Note that variadic support is very new and tested on a relatively
|
||||||
|
small number of platforms.
|
||||||
|
|
||||||
@node Index
|
@node Index
|
||||||
@unnumbered Index
|
@unnumbered Index
|
||||||
|
|||||||
@@ -207,6 +207,15 @@ typedef struct {
|
|||||||
#endif
|
#endif
|
||||||
} ffi_cif;
|
} 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 -------------------------------------- */
|
/* ---- Definitions for the raw API -------------------------------------- */
|
||||||
|
|
||||||
#ifndef FFI_SIZEOF_ARG
|
#ifndef FFI_SIZEOF_ARG
|
||||||
@@ -384,6 +393,13 @@ ffi_status ffi_prep_cif(ffi_cif *cif,
|
|||||||
ffi_type *rtype,
|
ffi_type *rtype,
|
||||||
ffi_type **atypes);
|
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 ffi_call(ffi_cif *cif,
|
||||||
void (*fn)(void),
|
void (*fn)(void),
|
||||||
void *rvalue,
|
void *rvalue,
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ void ffi_type_test(ffi_type *a, char *file, int line);
|
|||||||
|
|
||||||
/* Perform machine dependent cif processing */
|
/* Perform machine dependent cif processing */
|
||||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif);
|
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 */
|
/* Extended cif, used in callback from assembly routine */
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
AUTOMAKE_OPTIONS=foreign
|
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
|
||||||
|
|
||||||
|
|||||||
10
man/ffi.3
10
man/ffi.3
@@ -16,6 +16,15 @@ libffi, -lffi
|
|||||||
.Fa "ffi_type **atypes"
|
.Fa "ffi_type **atypes"
|
||||||
.Fc
|
.Fc
|
||||||
.Ft void
|
.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
|
.Fo ffi_call
|
||||||
.Fa "ffi_cif *cif"
|
.Fa "ffi_cif *cif"
|
||||||
.Fa "void (*fn)(void)"
|
.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.
|
the called function's interface at compile time.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr ffi_prep_cif 3 ,
|
.Xr ffi_prep_cif 3 ,
|
||||||
|
.Xr ffi_prep_cif_var 3 ,
|
||||||
.Xr ffi_call 3
|
.Xr ffi_call 3
|
||||||
|
|||||||
@@ -37,7 +37,9 @@ structs that describe the data type, size and alignment of each argument.
|
|||||||
points to an
|
points to an
|
||||||
.Nm ffi_type
|
.Nm ffi_type
|
||||||
that describes the data type, size and alignment of the
|
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
|
.Sh RETURN VALUES
|
||||||
Upon successful completion,
|
Upon successful completion,
|
||||||
.Nm ffi_prep_cif
|
.Nm ffi_prep_cif
|
||||||
@@ -63,4 +65,6 @@ defined in
|
|||||||
.
|
.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr ffi 3 ,
|
.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
73
man/ffi_prep_cif_var.3
Normal 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
|
||||||
@@ -36,3 +36,4 @@ minix
|
|||||||
interix-patch
|
interix-patch
|
||||||
remove-debug-code
|
remove-debug-code
|
||||||
powerpc-ffi-softfloat
|
powerpc-ffi-softfloat
|
||||||
|
variadic
|
||||||
|
|||||||
581
patches/variadic
Normal file
581
patches/variadic
Normal 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,
|
||||||
@@ -196,6 +196,18 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
|||||||
return FFI_OK;
|
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 */
|
/* Prototypes for assembly functions, in sysv.S */
|
||||||
extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
|
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 *);
|
extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ typedef enum ffi_abi {
|
|||||||
#define FFI_TYPE_STRUCT_VFP_FLOAT (FFI_TYPE_LAST + 1)
|
#define FFI_TYPE_STRUCT_VFP_FLOAT (FFI_TYPE_LAST + 1)
|
||||||
#define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2)
|
#define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2)
|
||||||
|
|
||||||
|
#define FFI_TARGET_SPECIFIC_VARIADIC
|
||||||
|
|
||||||
/* ---- Definitions for closures ----------------------------------------- */
|
/* ---- Definitions for closures ----------------------------------------- */
|
||||||
|
|
||||||
#define FFI_CLOSURES 1
|
#define FFI_CLOSURES 1
|
||||||
@@ -62,4 +64,3 @@ typedef enum ffi_abi {
|
|||||||
#define FFI_NATIVE_RAW_API 0
|
#define FFI_NATIVE_RAW_API 0
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -153,9 +153,10 @@ ffi_prep_args (char *stack, extended_cif * ecif)
|
|||||||
return (struct_count);
|
return (struct_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
ffi_status
|
ffi_status FFI_HIDDEN
|
||||||
ffi_prep_cif (ffi_cif * cif,
|
ffi_prep_cif_core (ffi_cif * cif,
|
||||||
ffi_abi abi, unsigned int nargs,
|
ffi_abi abi, unsigned int isvariadic,
|
||||||
|
unsigned int nfixedargs, unsigned int ntotalargs,
|
||||||
ffi_type * rtype, ffi_type ** atypes)
|
ffi_type * rtype, ffi_type ** atypes)
|
||||||
{
|
{
|
||||||
unsigned bytes = 0;
|
unsigned bytes = 0;
|
||||||
@@ -163,11 +164,13 @@ ffi_prep_cif (ffi_cif * cif,
|
|||||||
ffi_type **ptr;
|
ffi_type **ptr;
|
||||||
|
|
||||||
FFI_ASSERT (cif != NULL);
|
FFI_ASSERT (cif != NULL);
|
||||||
|
FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
|
||||||
|
FFI_ASSERT(nfixedargs <= ntotalargs);
|
||||||
FFI_ASSERT (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI);
|
FFI_ASSERT (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI);
|
||||||
|
|
||||||
cif->abi = abi;
|
cif->abi = abi;
|
||||||
cif->arg_types = atypes;
|
cif->arg_types = atypes;
|
||||||
cif->nargs = nargs;
|
cif->nargs = ntotalargs;
|
||||||
cif->rtype = rtype;
|
cif->rtype = rtype;
|
||||||
|
|
||||||
cif->flags = 0;
|
cif->flags = 0;
|
||||||
|
|||||||
@@ -90,7 +90,17 @@ static ffi_status initialize_aggregate(ffi_type *arg)
|
|||||||
/* Perform machine independent ffi_cif preparation, then call
|
/* Perform machine independent ffi_cif preparation, then call
|
||||||
machine dependent routine. */
|
machine dependent routine. */
|
||||||
|
|
||||||
ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
|
/* 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)
|
ffi_type *rtype, ffi_type **atypes)
|
||||||
{
|
{
|
||||||
unsigned bytes = 0;
|
unsigned bytes = 0;
|
||||||
@@ -98,12 +108,15 @@ ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
|
|||||||
ffi_type **ptr;
|
ffi_type **ptr;
|
||||||
|
|
||||||
FFI_ASSERT(cif != NULL);
|
FFI_ASSERT(cif != NULL);
|
||||||
|
FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
|
||||||
|
FFI_ASSERT(nfixedargs <= ntotalargs);
|
||||||
|
|
||||||
if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
|
if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
|
||||||
return FFI_BAD_ABI;
|
return FFI_BAD_ABI;
|
||||||
|
|
||||||
cif->abi = abi;
|
cif->abi = abi;
|
||||||
cif->arg_types = atypes;
|
cif->arg_types = atypes;
|
||||||
cif->nargs = nargs;
|
cif->nargs = ntotalargs;
|
||||||
cif->rtype = rtype;
|
cif->rtype = rtype;
|
||||||
|
|
||||||
cif->flags = 0;
|
cif->flags = 0;
|
||||||
@@ -159,10 +172,31 @@ ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
|
|||||||
cif->bytes = bytes;
|
cif->bytes = bytes;
|
||||||
|
|
||||||
/* Perform machine dependent cif processing */
|
/* 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);
|
return ffi_prep_cif_machdep(cif);
|
||||||
}
|
}
|
||||||
#endif /* not __CRIS__ */
|
#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
|
#if FFI_CLOSURES
|
||||||
|
|
||||||
ffi_status
|
ffi_status
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ int main (void)
|
|||||||
arg_types[1] = &ffi_type_double;
|
arg_types[1] = &ffi_type_double;
|
||||||
arg_types[2] = NULL;
|
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);
|
arg_types) == FFI_OK);
|
||||||
|
|
||||||
args[0] = &format;
|
args[0] = &format;
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ int main (void)
|
|||||||
arg_types[1] = &ffi_type_longdouble;
|
arg_types[1] = &ffi_type_longdouble;
|
||||||
arg_types[2] = NULL;
|
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);
|
arg_types) == FFI_OK);
|
||||||
|
|
||||||
args[0] = &format;
|
args[0] = &format;
|
||||||
@@ -49,6 +50,10 @@ int main (void)
|
|||||||
printf("res: %d\n", (int) res);
|
printf("res: %d\n", (int) res);
|
||||||
// { dg-output "\nres: 4" }
|
// { 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);
|
CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL, code) == FFI_OK);
|
||||||
|
|
||||||
res = ((int(*)(char*, long double))(code))(format, ldArg);
|
res = ((int(*)(char*, long double))(code))(format, ldArg);
|
||||||
|
|||||||
107
testsuite/libffi.call/float_va.c
Normal file
107
testsuite/libffi.call/float_va.c
Normal 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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user