Search code examples
cpointerssegmentation-faultdynamic-linkingdlopen

dlsym returns an invalid pointer


I have a dynamically linked module like so:

int func() {
    return 5;
}

extern int(*func_p)() = func;

And a main function that loads the function pointer:

#include <stdio.h>
#include <dlfcn.h>

int main() {
    void *module = dlopen("/tmp/mod/mod.so", RTLD_NOW);
    if (!module)
  {
     printf("Cannot load module: %s\n", dlerror());
     return 1;
  }

    typedef int(*func_f)();
    func_f func;

    func = dlsym(module, "func_p");
    char *error = dlerror();
    if (error)
{
   printf("Cannot find init in module: %s\n", error);
   return 1;
}

    printf("Func returns: %i\n", func());
}

Is there any way I can make this work or is this completely out of bounds?

Could I manually "resolve" the function pointer?


Solution

  • In C, func is a function, and func_p is a pointer to a function. When a name is given as an argument to dlsym, dlsym returns the address of the named thing. So, for "func", it returns the address of the function named func. For "func_p", it returns the address of the pointer named func_p.

    Of course, the address of the pointer func_p cannot be used to call the function. For that, you need the value of the pointer.

    Either of these should work:

    // Get address of function.
    int (*func)() = (int (*)()) dlsym(module, "func");
    
    // Call function.
    func();
    
    // Get address of pointer to function.
    int (**p)() = dlsym(module, "func_p");
    
    // Deference to get pointer to function, then call function.
    (*p)();
    

    The latter is unnecessary unless the function is not externally visible. As long as func can be looked up by dlsym, the former should suffice.

    Also note that documentation about linkers and related things, possibly dlsym, refers to the values of symbols, but, for these kinds of symbols, those values are the addresses where the things the symbols refer to are. That is, for C, func is a function and func_p is a pointer, but, for the linker, func is some name it found in an object module, and its “value” is the address where it will be in memory, and similarly the value of func_p is the address where it will be. When reading such documentation, you have to be mindful the linkers and symbol resolvers are performing different tasks and treating names differently than C compilers do.