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?
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().
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.
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:
struct export_vtable { void (*helloworld)(void); }; struct export_vtable exports = { func };
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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With