Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to correctly assign a pointer returned by dlsym into a variable of function pointer type?

Tags:

I am trying to use dlopen() and dlsym() in my code and compile it with gcc.

Here is the first file.

/* main.c */  #include <dlfcn.h>  int main() {     void *handle = dlopen("./foo.so", RTLD_NOW);      if (handle) {         void (*func)() = dlsym(handle, "func");         func();     }      return 0; } 

Here is the second file.

/* foo.c */  #include <stdio.h>  void func() {     printf("hello, world\n"); } 

Here is how I compile and run the code.

$ gcc -std=c99 -pedantic -Wall -Wextra -shared -fPIC -o foo.so foo.c $ gcc -std=c99 -pedantic -Wall -Wextra -ldl -o main main.c main.c: In function ‘main’: main.c:10:26: warning: ISO C forbids initialization between function pointer and ‘void *’ [-Wpedantic]          void (*func)() = dlsym(handle, "func");                           ^ $ ./main hello, world 

How can I get rid of the warning?

Type casting doesn't help. If I try to type cast the return value of dlsym() into a function pointer, I get this warning instead.

main.c:10:26: warning: ISO C forbids conversion of object pointer to function pointer type [-Wpedantic]          void (*func)() = (void (*)()) dlsym(handle, "func");                           ^ 

What would convince the compiler that this code is fine?

like image 784
Lone Learner Avatar asked Apr 03 '16 10:04

Lone Learner


People also ask

What does Dlsym return?

dlsym() returns the address binding of the symbol as it occurs in the shared object identified by handle. It returns a NULL pointer if the symbol cannot be found. More detailed diagnostic information is available through dlerror().

What is Dlsym in C?

The dlsym() function shall obtain the address of a symbol defined within an object made accessible through a dlopen() call. The handle argument is the value returned from a call to dlopen() (and which has not since been released via a call to dlclose()), and name is the symbol's name as a character string.


2 Answers

If you want to be pedantically correct, don't try to resolve the address of a function. Instead, export some kind of structure from the dynamic library:

In the library

struct export_vtable {    void (*helloworld)(void); }; struct export_vtable exports = { func }; 

In the caller

struct export_vtable {    void (*helloworld)(void); };  int main() {    struct export_vtable* imports;    void *handle = dlopen("./foo.so", RTLD_NOW);     if (handle) {         imports = dlsym(handle, "exports");         if (imports) imports->helloworld();     }      return 0; } 

This technique is actually quite common, not for portability -- POSIX guarantees that function pointers can be converted to and from void* -- but because it allows more flexibility.

like image 71
rici Avatar answered Oct 16 '22 12:10

rici


This made my code sufficiently pedantic:

*(void**)(&func_ptr) = dlsym(handle, "function_name"); 

(I found it here http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html)

like image 44
Whome Avatar answered Oct 16 '22 11:10

Whome