int foo(int);We can write a program to invoke the function even when at the compiling time we have no idea which implemenation of the function will be used at run-time; That means the symbol resolution and code loading only happen at running-time. For example , the main.c program is shown below:
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char* argv[])
{
if (argc != 2) {
printf("Usage: <path of shared library>");
return 0;
}
void *handle = dlopen(argv[1],RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
return 0;
}
dlerror(); /* clear any existing error */
int (*foo)(int);
foo = (int (*)(int)) dlsym(handle,"foo");
char* error;
if ((error = dlerror()) != NULL){
fprintf(stderr, "%s\n",error);
return 1;
}
printf("%d\n",(*foo)(3));
dlclose(handle);
return 0;
}
To invoke dlsym
foo = (int (*)(int)) dlsym(handle,"foo");we should be careful about the name we are using to indicate the function. Here we assuming the C linkage is used so the name will be just ``foo''. But if the implemenation is using C++ linkage, the C++ name mangling will change the name to be some sort like "_Z3fooi", so the dlsym call will be changed to be
foo = (int (*)(int)) dlsym(handle,"_Z3fooi");More about C++ mangling can be found at
g++ -o main dyn_main.c -ldl
Now assuming we have an implemenation of the function foo in foo_a.c
int foo(int a)
{
return a + 1;
}
and we compile it to be a shared library by
g++ -o libfoo_a.so foo_a.o -shared -Wl,-soname="libfoo_a.so"Now we can run the main by specifying which library is supposed to used
./main ./libfoo_a.so
The -rdynamic option is used to force the linker the create the global symbol table and export all of its global variables into the global symbol table. This options is not for compilation, it is for linking. But unlike -Wl option, which passes the following options to the linker, -rdynamimc is a higher level option and differs according different platforms. In linux, it is just the -export-dynamic option for the linker. -export-dynamic
From the man page of ld