Imagine that you have an application with a plugin based architecture, where each plugin is a *.so
file that is dynamically loaded with dlopen()
.
The main application can refer to symbols via dlsym()
, and so it may call functions of the plugin. How can the plugin call functions of the main application?
I know that the main application could provide a struct full of function pointers, which the plugin could use to call into the application. Is there any easier way than that?
Edit: here’s a minimal working example to show what I mean:
app.h
:
#ifndef APP_H #define APP_H void app_utility(void); #endif
app.c
:
#include <dlfcn.h> #include <stdio.h> #include <stdlib.h> #include "app.h" void app_utility(void) { printf("app_utility()n"); } int main(int argc, char **argv) { void *handle; void (*plugin_function)(void); if (argc < 2) { fprintf(stderr, "usage: ./app plugin.son"); exit(1); } handle = dlopen(argv[1], RTLD_NOW | RTLD_LOCAL); if (!handle) { fprintf(stderr, "error loading plugin: %sn", dlerror()); exit(1); } plugin_function = dlsym(handle, "doit"); if (!plugin_function) { fprintf(stderr, "error loading symbol: %sn", dlerror()); dlclose(handle); exit(1); } plugin_function(); dlclose(handle); return 0; }
plugin.c
:
#include <stdio.h> #include "app.h" void doit(void) { printf("doit()n"); app_utility(); printf("did it!n"); }
Example usage:
$ gcc -o app app.c -ldl $ gcc -shared -o plugin.so $ ./app ./plugin.so error loading plugin: ./plugin.so: undefined symbol: app_utility
Advertisement
Answer
There is a option you can pass to gcc when you invoke it to create the executable for the main application: -rdynamic
$ gcc -rdynamic -o app app.c -ldl
The GCC documentation for -rdynamic
:
Pass the flag
-export-dynamic
to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. This option is needed for some uses ofdlopen
or to allow obtaining backtraces from within a program.
The ld
manual page for --export-dynamic
includes this paragraph:
If you use “
dlopen
” to load a dynamic object which needs to refer back to the symbols defined by the program, rather than some other dynamic object, then you will probably need to use this option when linking the program itself.