Search code examples
cdlopen

Portability of dlfunc?


I'm reading through the manpage for dlopen and friends on FreeBSD. I'm working on a cross-platform application that is using shared libraries for loadable plugins. I've never done this before, but I think I have a decent grasp of how it works. The manpage mentions dlsym(), which appears to be the common means of getting a function pointer from a shared library, and dlfunc(), which supposedly avoids compiler complaints about casting a void* to a function pointer. Is there a reason dlsym() is more common (portability?) ? I'm wondering whether I should use dlfunc() to avoid compiler problems, or use dlsym(). Is dlfunc() portable?


Solution

  • You can't expect to have a dlfunc provided on other UNIXes, but it's implementation is straightforward and portable. You can do something like

    # configure.ac
    AC_SYSTEM_EXTENSIONS
    AC_CHECK_FUNCS([dlfunc])
    
    // some common header
    #include "config.h"
    #ifndef HAVE_DLFUNC
    /* copied from FreeBSD, source/include/dlfcn.h */
    struct __dlfunc_arg {
            int __dlfunc_dummy;
    };
    typedef void (*dlfunc_t)(struct __dlfunc_arg);
    dlfunc_t dlfunc(void *restrict handle, void *restrict symbol);
    #endif
    
    // some source file
    #include "config.h"
    #ifndef HAVE_DLFUNC
    /* copied from FreeBSD, lib/libc/gen/dlfunc.c */
    dlfunc_t dlfunc(void *restrict handle, void *restrict symbol) {
            union {
                    void *d;
                    dlfunc_t f;
            } rv;
            rv.d = dlsym(handle, symbol);
            return rv.f;
    }
    #endif
    

    if you are using Autoconf, and other build+configuration systems probably have similar abilities. (dlsym is much more widely available.)


    That being said, I think the compiler warning is silly – the C standard does not, but POSIX guarantees that void * pointers can safely represent all function pointers…