| Use Case | Command | Description |
|---|---|---|
| ๐ฏ Prepare a call interface | ffi_prep_cif(cif, abi, nargs, rtype, argtypes) | Initializes a ffi_cif for calling a function with fixed args |
| ๐ฏ Prepare a variadic call interface | ffi_prep_cif_var(cif, abi, nfixed, ntotal, rtype, argtypes) | Initializes a ffi_cif for a variadic function call |
| ๐ Call a function | ffi_call(cif, fn, rvalue, avalues) | Invokes the function described by cif |
| ๐ Allocate closure memory | ffi_closure_alloc(size, &code) | Allocates writable+executable memory for a closure |
| ๐ Free closure memory | ffi_closure_free(writable) | Frees memory allocated by ffi_closure_alloc |
| ๐ Prepare a closure function | ffi_prep_closure_loc(closure, cif, fun, user_data, codeloc) | Prepares a closure that can be called as a function |
| ๐ Get struct member offsets | ffi_get_struct_offsets(abi, struct_type, offsets) | Computes offsets of each element in a structure type |
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 "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 "ABI" or "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. 'Libffi' can be used in such programs to provide a bridge from the interpreter program to compiled code.
The '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.
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 'libffi' library really only provides the lowest, machine dependent layer of a fully featured foreign function interface. A layer must exist above 'libffi' that handles type conversions for values passed between the two languages.
'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 '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 'ffi_cif'. The "cif" in 'ffi_cif' stands for Call InterFace. To prepare a call interface object, use the function 'ffi_prep_cif'.
๐ง Function: ffi_status ffi_prep_cif (ffi_cif *CIF, ffi_abi ABI, unsigned int NARGS, ffi_type *RTYPE, ffi_type **ARGTYPES) This initializes CIF according to the given parameters.ffi_type structure that describes the return type of the function. See Types.ffi_type pointers. ARGTYPES must have NARGS elements. If NARGS is 0, this argument is ignored.libffi status code: FFI_OK if everything worked; FFI_BAD_TYPEDEF if an ffi_type object is incorrect; FFI_BAD_ABI if the ABI parameter is invalid.If the function being called is variadic (varargs) then ffi_prep_cif_var must be used instead of ffi_prep_cif.
ffi_prep_cif except that:
FFI_BAD_ARGTYPE if any variable argument types are ffi_type_float (promote to ffi_type_double first), or any integer type smaller than an int (promote to int-sized type first).Note that different cif's must be prepped for calls to the same function when different numbers of arguments are passed. Also a call to ffi_prep_cif_var with NFIXEDARGS=NTOTALARGS is NOT equivalent to a call to ffi_prep_cif.
โ๏ธ Note that the resulting ffi_cif holds pointers to all the ffi_type objects used during initialization. You must ensure that these type objects have a lifetime at least as long as that of the ffi_cif.
To call a function using an initialized ffi_cif, use the ffi_call function:
ffi_prep_cif.
void, ignored.ffi_arg as return type in such cases.void * pointers to argument values. If no arguments, ignored. Argument values may be modified by the callee.short, RVALUE should point to ffi_arg).Here is a trivial example that calls 'puts' a few times.
#include <stdio.h>
#include <ffi.h>
int main()
{
ffi_cif cif;
ffi_type *args[1];
void *values[1];
char *s;
ffi_arg 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_sint, 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;
}
'Libffi' provides built-in type descriptors:
ffi_type_void โ The type 'void'. Cannot be used for argument types, only for return values.ffi_type_uint8 โ Unsigned, 8-bit integer.ffi_type_sint8 โ Signed, 8-bit integer.ffi_type_uint16 โ Unsigned, 16-bit integer.ffi_type_sint16 โ Signed, 16-bit integer.ffi_type_uint32 โ Unsigned, 32-bit integer.ffi_type_sint32 โ Signed, 32-bit integer.ffi_type_uint64 โ Unsigned, 64-bit integer.ffi_type_sint64 โ Signed, 64-bit integer.ffi_type_float โ C 'float' type.ffi_type_double โ C 'double' type.ffi_type_uchar โ C 'unsigned char' type.ffi_type_schar โ C 'signed char' type. (Use depending on whether 'char' is signed.)ffi_type_ushort โ C 'unsigned short' type.ffi_type_sshort โ C 'short' type.ffi_type_uint โ C 'unsigned int' type.ffi_type_sint โ C 'int' type.ffi_type_ulong โ C 'unsigned long' type.ffi_type_slong โ C 'long' type.ffi_type_longdouble โ C 'long double' type (if supported on platform).ffi_type_pointer โ Generic void * pointer. Use for all pointers.ffi_type_complex_float โ C '_Complex float' type.ffi_type_complex_double โ C '_Complex double' type.ffi_type_complex_longdouble โ C '_Complex long double' type (if supported).Each is of type ffi_type, take the address when passing to ffi_prep_cif.
Create a new ffi_type object for a structure:
size_t size โ Set by libffi; initialize to zero.unsigned short alignment โ Set by libffi; initialize to zero.unsigned short type โ For a structure, set to FFI_TYPE_STRUCT.ffi_type **elements โ NULL-terminated array of pointers to ffi_type objects, one per field.No special support for bit-fields; manage manually.
The size and alignment fields filled in by ffi_prep_cif or ffi_prep_cif_var.
libffi sets size and alignment for you, but there are caveats:
ffi_prep_cif or ffi_get_struct_offsets.Example usage:
ffi_type *desired_type;
ffi_abi desired_abi;
...
ffi_cif cif;
if (ffi_prep_cif (&cif, desired_abi, 0, desired_type, NULL) == FFI_OK)
{
size_t size = desired_type->size;
unsigned short alignment = desired_type->alignment;
}
Also provides ffi_get_struct_offsets:
FFI_OK on success, FFI_BAD_ABI if ABI invalid, FFI_BAD_TYPEDEF if struct_type invalid.
Emulate arrays using FFI_TYPE_STRUCT with as many members as elements.
ffi_type array_type;
ffi_type **elements
int i;
elements = malloc ((n + 1) * sizeof (ffi_type *));
for (i = 0; i < n; ++i)
elements[i] = array_element_type;
elements[n] = NULL;
array_type.size = array_type.alignment = 0;
array_type.type = FFI_TYPE_STRUCT;
array_type.elements = elements;
Arrays cannot be passed/returned by value in C; this is for referencing members of real structs. Using as argument/return type may not cause errors but may be confusing.
Emulate unions using FFI_TYPE_STRUCT. Ensure size and alignment match real union requirements. Example uses ffi_prep_cif to lay out each element type:
ffi_abi desired_abi;
ffi_type union_type;
ffi_type **union_elements;
int i;
ffi_type element_types[2];
element_types[1] = NULL;
union_type.size = union_type.alignment = 0;
union_type.type = FFI_TYPE_STRUCT;
union_type.elements = element_types;
for (i = 0; union_elements[i]; ++i)
{
ffi_cif cif;
if (ffi_prep_cif (&cif, desired_abi, 0, union_elements[i], NULL) == FFI_OK)
{
if (union_elements[i]->size > union_type.size)
{
union_type.size = union_elements[i];
size = union_elements[i]->size;
}
if (union_elements[i]->alignment > union_type.alignment)
union_type.alignment = union_elements[i]->alignment;
}
}
No special support. The underlying integral type cannot be determined by libffi; depends on values or compiler flags like -fshort-enums. See GCC documentation for details.
Describing the tm struct from time.h:
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__;
};
{
ffi_type tm_type;
ffi_type *tm_type_elements[12];
int i;
tm_type.size = tm_type.alignment = 0;
tm_type.type = FFI_TYPE_STRUCT;
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() */
}
libffi supports C99 complex types (_Complex float, _Complex double, _Complex long double) via built-in descriptors ffi_type_complex_float, ffi_type_complex_double, ffi_type_complex_longdouble.
Custom complex types like _Complex int can be defined using ffi_type:
size โ manually set to size of complex type.alignment โ manually set to alignment.type โ set to FFI_TYPE_COMPLEX.elements โ NULL-terminated array; first element is base type ffi_type, second is NULL.See Complex Type Example for platform-independent size/alignment determination. On platforms without complex support, ffi_prep_cif and ffi_prep_args abort on encountering a complex type.
#include <stdio.h>
#include <ffi.h>
#include <complex.h>
void complex_fn(_Complex float cf,
_Complex double cd,
_Complex long double cld)
{
printf("cf=%f+%fi\ncd=%f+%fi\ncld=%f+%fi\n",
(float)creal (cf), (float)cimag (cf),
(float)creal (cd), (float)cimag (cd),
(float)creal (cld), (float)cimag (cld));
}
int main()
{
ffi_cif cif;
ffi_type *args[3];
void *values[3];
_Complex float cf;
_Complex double cd;
_Complex long double cld;
/* Initialize the argument info vectors */
args[0] = &ffi_type_complex_float;
args[1] = &ffi_type_complex_double;
args[2] = &ffi_type_complex_longdouble;
values[0] = &cf;
values[1] = &cd;
values[2] = &cld;
/* Initialize the cif */
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3,
&ffi_type_void, args) == FFI_OK)
{
cf = 1.0 + 20.0 * I;
cd = 300.0 + 4000.0 * I;
cld = 50000.0 + 600000.0 * I;
/* Call the function */
ffi_call(&cif, (void (*)(void))complex_fn, 0, values);
}
return 0;
}
Example for defining custom complex type descriptor:
/*
* This macro can be used to define new complex type descriptors
* in a platform independent way.
*
* name: Name of the new descriptor is ffi_type_complex_<name>.
* type: The C base type of the complex type.
*/
#define FFI_COMPLEX_TYPEDEF(name, type, ffitype) \
static ffi_type *ffi_elements_complex_##name [2] = { \
(ffi_type *)(&ffitype), NULL \
}; \
struct struct_align_complex_##name { \
char c; \
_Complex type x; \
}; \
ffi_type ffi_type_complex_##name = { \
sizeof(_Complex type), \
offsetof(struct struct_align_complex_##name, x), \
FFI_TYPE_COMPLEX, \
(ffi_type **)ffi_elements_complex_##name \
}
/* Define new complex type descriptors using the macro: */
/* ffi_type_complex_sint */
FFI_COMPLEX_TYPEDEF(sint, int, ffi_type_sint);
/* ffi_type_complex_uchar */
FFI_COMPLEX_TYPEDEF(uchar, unsigned char, ffi_type_uint8);
New type descriptors can be used like built-in ones.
A given platform may provide multiple ABIs (e.g., x86 has stdcall and fastcall). libffi provides some support, necessarily platform-specific.
Write a generic function (function that can accept any combination of arguments). Useful for interpreters or wrappers. Check FFI_CLOSURES define for platform support.
ffi_closure object.
๐ง Function: void ffi_closure_free (void *WRITABLE)
Free memory allocated by ffi_closure_alloc.
After allocating memory, construct a ffi_cif describing the function call, then prepare the closure:
ffi_closure_alloc.ffi_cif describing function parameters. Must outlive the closure.ffi_closure_alloc.ffi_arg), ARGS (vector of pointers to arguments), USER_DATA.Returns FFI_OK on success. After call, cast CODELOC to appropriate function pointer type.
๐ The older ffi_prep_closure is deprecated (cannot separate writable and executable addresses).
#include <stdio.h>
#include <ffi.h>
/* Acts like puts with the file given at time of enclosure. */
void puts_binding(ffi_cif *cif, void *ret, void* args[],
void *stream)
{
*(ffi_arg *)ret = fputs(*(char **)args[0], (FILE *)stream);
}
typedef int (*puts_t)(char *);
int main()
{
ffi_cif cif;
ffi_type *args[1];
ffi_closure *closure;
void *bound_puts;
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_sint, 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 = ((puts_t)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;
}
libffi is not completely thread-safe. Follow these rules:
ffi_cif at a time.ffi_prep_cif may modify size/alignment of types based on ABI (currently PowerPC only, type long double), ensure only one call to ffi_prep_cif at a time when switching ABIs.Memory allocated by ffi_closure_alloc and freed by ffi_closure_free comes from a different pool than malloc/free. libffi may map temporary files into multiple address-space locations for security. Search order for memory:
memfd_create() (if kernel supports)LIBFFI_TMPDIR env varTMPDIR env var/tmp/var/tmp/dev/shm$HOME)/etc/mtab/proc/mountsIf security settings prohibit all, ffi_closure_alloc fails.
Known missing features (patches welcome):
Generated by phpman v4.9.22-1-g1b0fcb4 · Markdown · JSON · MCP Author: Che Dong Under GNU General Public License
2026-07-05 16:43 @216.73.216.52
CrawledBy Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)
Enhanced by LLM: deepseek-v4-pro / taotoken.net / www.chedong.com - original format