I want to load a shared library with dlopen
and have the symbols in it available without having to individually grab function pointers to them with dlsym
. The man page says that the RTLD_DEEPBIND
flag will place lookup of symbols in the library ahead of global scope, but evidently this does not mean it overrides existing symbols because this does not work. Consider this example:
main.c:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
int is_loaded(){return 0;}
int main(){
void *h = dlopen("./libimplementation.so", RTLD_NOW | RTLD_DEEPBIND);
if(!h){
printf("Could not load implementation: %s\n", dlerror());
return 1;
}
puts(is_loaded() ? "Implementation loaded" : "Implementation not loaded");
dlclose(h);
}
implementation.c:
int is_loaded(){return 1;}
Makefile:
all: main libimplementation.so
main: main.c
gcc -Wall -std=c99 -o $@ $^ -ldl
lib%.so: %.c
gcc -Wall -std=c99 -o $@ $^ -shared
clean:
-rm main *.so
When I build and run with make
and ./main
, I expect the test()
function from libimplementation.so
to override the test()
function from main
but it doesn't. I know I could also move all of the code in main()
into another shared library run
and then have main()
dlopen
libimplementation.so
with RTLD_GLOBAL
and then have librun.so
refer to the symbols from libimplementation.so
without having them defined so it loads them:
modified main.c:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
int main(){
void *impl_h = dlopen("./libimplementation.so", RTLD_LAZY | RTLD_GLOBAL);
if(!impl_h){
printf("Could not load implementation: %s\n", dlerror());
return 1;
}
void *run_h = dlopen("./librun.so", RTLD_LAZY);
if(!run_h){
printf("Could not load run: %s\n", dlerror());
dlclose(impl_h);
return 1;
}
void (*run)(void);
*(void**)&run = dlsym(run_h, "run");
if(!*(void**)&run){
printf("Could not find entry point in run: %s\n", dlerror());
dlclose(impl_h);
dlclose(run_h);
return 1;
}
run();
dlclose(impl_h);
dlclose(run_h);
}
run.c:
#include <stdio.h>
int is_loaded(void);
void run(void){
puts(is_loaded() ? "Implementation loaded" : "Implementation not loaded");
}
and the Makefile
gets librun.so
added as a prerequisite for all
.
Is there a way to get the symbols from the shared library available all at once without dlsym
or putting the actual code in another shared library like with librun.so
?
There is fundamentally no way to do what you're asking for. Imagine the main program had something like:
static char *myptr = array_in_lib1;
Later, at the time you dlopen
, myptr
has some other value. Has the program just changed the variable to point to a different object? Or has it been incremented to point to some element later in the array - in which case, would you want it adjusted to account for the redefinition of array_in_lib1
with a new definition from the newly-opened library? Or is it just a random integer cast to char *
? Deciding how to treat it is impossible without understanding programmer intent and full process history of how it arrived in the current state.
The above is a particulrly egregious sort of example I've constructed, but the idea of symbols changing definition at runtime is fundamentally inconsistent in all sorts of ways. Even RTLD_DEEPBIND
, in what it already does, is arguably inconsitent and buggy. Whatever you're trying to do, you should find another way to do it.