Next: , Up: Using libffi   [Index]


2.1 The Basics

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.

abi is the ABI to use; normally FFI_DEFAULT_ABI is what you want. Multiple ABIs for more information.

nargs is the number of arguments that this function accepts.

rtype is a pointer to an ffi_type structure that describes the return type of the function. See Types.

argtypes is a vector of ffi_type pointers. argtypes must have nargs elements. If nargs is 0, this argument is ignored.

ffi_prep_cif returns a libffi status code, of type ffi_status. This will be either FFI_OK if everything worked properly; FFI_BAD_TYPEDEF if one of the ffi_type objects is incorrect; or 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.

Function: ffi_status ffi_prep_cif_var (ffi_cif *cif, ffi_abi abi, unsigned int nfixedargs, unsigned int ntotalargs, ffi_type *rtype, ffi_type **argtypes)

This initializes cif according to the given parameters for a call to a variadic function. In general its operation is the same as for ffi_prep_cif except that:

nfixedargs is the number of fixed arguments, prior to any variadic arguments. It must be greater than zero.

ntotalargs the total number of arguments, including variadic and fixed arguments. argtypes must have this many elements.

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 ffi_prep_cif_var with nfixedargs=nototalargs is NOT equivalent to a call to ffi_prep_cif.

Note that the resulting ffi_cif holds pointers to all the ffi_type objects that were 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:

Function: void ffi_call (ffi_cif *cif, void *fn, void *rvalue, void **avalues)

This calls the function fn according to the description given in cif. cif must have already been prepared using ffi_prep_cif.

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, no smaller than the system register size (generally 32 or 64 bits), and must be suitably aligned; it is the caller’s responsibility to ensure this. If cif declares that the function returns void (using ffi_type_void), then rvalue is ignored.

In most situations, ‘libffi’ will handle promotion according to the ABI. However, for historical reasons, there is a special case with return values that must be handled by your code. In particular, for integral (not struct) types that are narrower than the system register size, the return value will be widened by ‘libffi’. ‘libffi’ provides a type, ffi_arg, that can be used as the return type. For example, if the CIF was defined with a return type of char, ‘libffi’ will try to store a full ffi_arg into the return value.

avalues is a vector of void * pointers that point to the memory locations holding the argument values for a call. If cif declares that the function has no arguments (i.e., nargs was 0), then 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.

Note that while the return value must be register-sized, arguments should exactly match their declared type. For example, if an argument is a short, then the entry in avalues should point to an object declared as short; but if the return type is short, then rvalue should point to an object declared as a larger type – usually ffi_arg.


Next: , Up: Using libffi   [Index]