I have a shared library that I implemented and want the .so to call a function that's implemented in the main program which loads the library.
Let's say I have main.c (executable) which contains:
void inmain_function(void*); dlopen("libmy.so");
In the my.c (the code for the libmy.so) I want to call inmain_function
:
inmain_function(NULL);
How can the shared library call inmain_function
regardless the fact inmain_function
is defined in the main program.
Note: I want to call a symbol in main.c from my.c not vice versa which is the common usage.
Static Libraries are linked into a compiled executable (or another library). After the compilation, the new artifact contains the static library's content. Shared Libraries are loaded by the executable (or other shared library) at runtime.
Shared libraries are the most common way to manage dependencies on Linux systems. These shared resources are loaded into memory before the application starts, and when several processes require the same library, it will be loaded only once on the system. This feature saves on memory usage by the application.
A file with the . SO file extension is a Shared Library file. They contain information that can be used by one or more programs to offload resources so that the application(s) calling the SO file doesn't have to actually provide the file.
You have two options, from which you can choose:
Option 1: export all symbols from your executable. This is simple option, just when building executable, add a flag -Wl,--export-dynamic
. This would make all functions available to library calls.
Option 2: create an export symbol file with list of functions, and use -Wl,--dynamic-list=exported.txt
. This requires some maintenance, but more accurate.
To demonstrate: simple executable and dynamically loaded library.
#include <stdio.h> #include <dlfcn.h> void exported_callback() /*< Function we want to export */ { printf("Hello from callback!\n"); } void unexported_callback() /*< Function we don't want to export */ { printf("Hello from unexported callback!\n"); } typedef void (*lib_func)(); int call_library() { void *handle = NULL; lib_func func = NULL; handle = dlopen("./libprog.so", RTLD_NOW | RTLD_GLOBAL); if (handle == NULL) { fprintf(stderr, "Unable to open lib: %s\n", dlerror()); return -1; } func = dlsym(handle, "library_function"); if (func == NULL) { fprintf(stderr, "Unable to get symbol\n"); return -1; } func(); return 0; } int main(int argc, const char *argv[]) { printf("Hello from main!\n"); call_library(); return 0; }
Library code (lib.c):
#include <stdio.h> int exported_callback(); int library_function() { printf("Hello from library!\n"); exported_callback(); /* unexported_callback(); */ /*< This one will not be exported in the second case */ return 0; }
So, first build the library (this step doesn't differ):
gcc -shared -fPIC lib.c -o libprog.so
Now build executable with all symbols exported:
gcc -Wl,--export-dynamic main.c -o prog.exe -ldl
Run example:
$ ./prog.exe Hello from main! Hello from library! Hello from callback!
Symbols exported:
$ objdump -e prog.exe -T | grep callback 00000000004009f4 g DF .text 0000000000000015 Base exported_callback 0000000000400a09 g DF .text 0000000000000015 Base unexported_callback
Now with the exported list (exported.txt
):
{ extern "C" { exported_callback; }; };
Build & check visible symbols:
$ gcc -Wl,--dynamic-list=./exported.txt main.c -o prog.exe -ldl $ objdump -e prog.exe -T | grep callback 0000000000400774 g DF .text 0000000000000015 Base exported_callback
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