Class LibFFI

java.lang.Object
org.lwjgl.system.libffi.LibFFI

public class LibFFI extends Object
Native bindings to the libffi library.

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. This enables use of native libraries that LWJGL does not provide bindings for.

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 FFICIF 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 FFICIF. The cif in ffi_cif stands for Call InterFace. To prepare a call interface object, use the function prep_cif. To call a function using an initialized ffi_cif, use the call function.

  • Field Details

  • Method Details

    • nffi_prep_cif

      public static int nffi_prep_cif(long cif, int abi, int nargs, long rtype, long atypes)
      Unsafe version of: prep_cif
      Parameters:
      nargs - the number of arguments that this function accepts
    • ffi_prep_cif

      public static int ffi_prep_cif(FFICIF cif, int abi, FFIType rtype, @Nullable PointerBuffer atypes)
      Initializes the specified Call Interface (CIF) according to the given parameters.

      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.

      Parameters:
      cif - the ffi_cif structure to prepare
      abi - the ABI to use; normally DEFAULT_ABI is what you want. One of:
      FIRST_ABIWIN64GNUW64UNIX64EFI64SYSVSTDCALLTHISCALLFASTCALLMS_CDECLPASCAL
      REGISTERVFPLAST_ABIDEFAULT_ABI
      rtype - a pointer to an ffi_type structure that describes the return type of the function
      atypes - a vector of ffi_type pointers. atypes must have nargs elements. If nargs is 0, this argument is ignored.
      Returns:
      a status code, of type ffi_status.

      This will be either OK if everything worked properly; BAD_TYPEDEF if one of the ffi_type objects is incorrect; or BAD_ABI if the ABI parameter is invalid.

    • nffi_prep_cif_var

      public static int nffi_prep_cif_var(long cif, int abi, int nfixedargs, int ntotalargs, long rtype, long atypes)
      Unsafe version of: prep_cif_var
      Parameters:
      ntotalargs - the total number of arguments, including variadic and fixed arguments
    • ffi_prep_cif_var

      public static int ffi_prep_cif_var(FFICIF cif, int abi, int nfixedargs, FFIType rtype, PointerBuffer atypes)
      Initializes the specified Call Interface (CIF) according to the given parameters for a call to a variadic function.

      Different CIF's must be prepped for calls to the same function when different numbers of arguments are passed. A call to ffi_prep_cif_var with nfixedargs == ntotalargs is NOT equivalent to a call to prep_cif.

      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.

      Parameters:
      cif - the ffi_cif structure to prepare
      abi - the ABI to use; normally DEFAULT_ABI is what you want. One of:
      FIRST_ABIWIN64GNUW64UNIX64EFI64SYSVSTDCALLTHISCALLFASTCALLMS_CDECLPASCAL
      REGISTERVFPLAST_ABIDEFAULT_ABI
      nfixedargs - the number of fixed arguments, prior to any variadic arguments. It must be greater than zero.
      rtype - a pointer to an ffi_type structure that describes the return type of the function
      atypes - a vector of ffi_type pointers. atypes must have ntotalargs elements.
      Returns:
      a status code, of type ffi_status.

      This will be either OK if everything worked properly; BAD_TYPEDEF if one of the ffi_type objects is incorrect; or BAD_ABI if the ABI parameter is invalid.

    • nffi_call

      public static void nffi_call(long cif, long fn, long rvalue, long avalues)
      Unsafe version of: call
    • ffi_call

      public static void ffi_call(FFICIF cif, long fn, @Nullable ByteBuffer rvalue, @Nullable PointerBuffer avalues)
      Calls the function fn according to the description given in cif.

      cif must have already been prepared using prep_cif.

      Parameters:
      cif - a FFICIF structure. It must be initialized with prep_cif or prep_cif_var before it is used with ffi_call.
      fn - the function to call
      rvalue - 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 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 - 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.

    • nffi_get_struct_offsets

      public static int nffi_get_struct_offsets(int abi, long struct_type, long offsets)
      Unsafe version of: get_struct_offsets
    • ffi_get_struct_offsets

      public static int ffi_get_struct_offsets(int abi, FFIType struct_type, @Nullable PointerBuffer offsets)
      Computes the offset of each element of the given structure type.
      Parameters:
      abi - the ABI to use; this is needed because in some cases the layout depends on the ABI
      offsets - an out parameter. The caller is responsible for providing enough space for all the results to be written - one element per element type in struct_type. If offsets is NULL, then the type will be laid out but not otherwise modified. This can be useful for accessing the type's size or layout.
      Returns:
      returns OK on success; BAD_ABI if abi is invalid; or BAD_TYPEDEF if struct_type is invalid in some way. Note that only FFI_STRUCT types are valid here.
    • nffi_closure_alloc

      public static long nffi_closure_alloc(long size, long code)
      Unsafe version of: closure_alloc
    • ffi_closure_alloc

      @Nullable public static FFIClosure ffi_closure_alloc(long size, PointerBuffer code)
      Allocates a chunk of memory holding size bytes.

      Returns a pointer to the writable address, and sets *code to the corresponding executable address.

      Parameters:
      size - the number of bytes to allocate. Should be sufficient to hold an ffi_closure object (FFIClosure.SIZEOF).
      code - a buffer in which to place the returned executable address
      Returns:
      a pointer to the writable address
    • nffi_closure_free

      public static void nffi_closure_free(long writable)
      Unsafe version of: closure_free
    • ffi_closure_free

      public static void ffi_closure_free(FFIClosure writable)
      Frees memory allocated using closure_alloc.
      Parameters:
      writable - the address of an FFIClosure structure
    • nffi_prep_closure_loc

      public static int nffi_prep_closure_loc(long closure, long cif, long fun, long user_data, long codeloc)
      Unsafe version of: prep_closure_loc
    • ffi_prep_closure_loc

      public static int ffi_prep_closure_loc(FFIClosure closure, FFICIF cif, long fun, long user_data, long codeloc)
      Prepares a closure function.

      After calling ffi_prep_closure_loc, you can cast codeloc to the appropriate pointer-to-function type.

      Parameters:
      closure - the address of an ffi_closure object; this is the writable address returned by closure_alloc.
      cif - the ffi_cif describing the function parameters
      fun - the function which will be called when the closure is invoked. It is called with the arguments:
      • cif - The ffi_cif passed to ffi_prep_closure_loc.
      • ret - a pointer to the memory used for the function's return value.

        If the function is declared as returning void, then this value is garbage and should not be used.

        Otherwise, fun must fill the object to which this points, following the same special promotion behavior as ffi_call. That is, in most cases, ret points to an object of exactly the size of the type specified when cif was constructed. However, integral types narrower than the system register size are widened. In these cases your program may assume that ret points to an ffi_arg object.

      • args - a vector of pointers to memory holding the arguments to the function.
      • user_data - the same USER_DATA that was passed to ffi_prep_closure_loc.
      user_data - an arbitrary datum that is passed, uninterpreted, to your closure function
      codeloc - the executable address returned by closure_alloc.
      Returns:
      OK if everything went ok, and one of the other ffi_status values on error