Search code examples
cffilibffi

Call name of function, rather than pointer of function


The manpage for libffi features an example that, essentially, requires a pointer to the function (in the examples case, puts).

However, what do I do if I only know the name of the function, but don't actually have a pointer (which would usually happen if ffi is used in, say, dynamic programming languages)?

Say, I want to do something like this (pseudocode):

cif = null
s = "Hello World"
args = []
values = []
args[0] = ffi.type_pointer
values[0] = address_of(s)
if(ffi.prepare(cif, ffi.DEFAULT_ABI, ffi.type_uint, args)):
     ffi.call(cif, "puts", values)

In short, i want to have libffi dynamically look up the function (if that's supported by ffi in the first place) similar to dlfcn/LoadLibrary, and then call it with the supplied FFI CIF types.

Is such a thing possible with libffi? What would a simple example look like?


Solution

  • There are two possibilities - one requiring premeditation on the part of the programmer.

    Depending on the o/s, there are facilities associated with shared libraries for finding symbols from the program or its shared libraries.

    On many Unix systems and Linux specifically, the facilities are declared in <dlfcn.h> and are dlopen() and dlsym() (and dlclose(), etc). Given an appropriate handle for the shared library, then you can use:

    int (*ffi_ptr)(const char *) = dlsym(ffi_handle, "ffi_function_name");
    

    You have to consider the casting - usually brutal - to avoid compilation warnings.

    The alternative, premeditated technique is to build a table of function names and function pointers, in which you can search for the name and use the corresponding pointer:

    struct ptr_function
    {
        void (*func_ptr)(void);
        const char *func_name;
    };
    
    static const struct ptr_function[] =
    {
        { func_1, "func_1"       },
        { func_2, "func_2"       },
        { func_2, "func_synonym" },
    };
    
    enum { NUM_PTR_FUNCTION = sizeof(ptr_function) / sizeof(*ptr_function) } ;
    

    Note that this technique allows for synonyms in a way that the dlsym() mechanism does not. However, the premeditation is often a major stumbling block. It is a technique that harks back to the 80s and early 90s when shared libraries were not universally available. Once again, the need for casts can make the code somewhat more complex.