简而言之:这取决于dlopen 选项。默认情况下,如果请求的库需要的符号已经存在于全局范围内,它将被重用(这就是你想要的)。但是您可以使用RTLD_DEEPBIND 绕过此行为,使用此标志,将不会从全局范围重用依赖项,而是会再次加载。
这里有一些代码可以重现您的情况并演示此标志的效果。
让我们创建一个库 A 和程序 B 都将使用的公共库。这个库将存在两个版本。
$ cat libcommon_v1.c
int common_func(int a)
{
return a+1;
}
$ cat libcommon_v2.c
int common_func(int a)
{
return a+2;
}
现在让我们编写使用 libcommon_v2 的库 A:
$ cat liba.c
int common_func(int a);
int a_func(int a)
{
return common_func(a)+1;
}
最后是动态链接到 libcommon_v1 和 dlopens lib A 的程序 B:
$ cat progb.c
#include <stdio.h>
#include <dlfcn.h>
int common_func(int a);
int a_func(int a);
int main(int argc, char *argv[])
{
void *dl_handle;
int (*a_ptr)(int);
char c;
/* just make sure common_func is registered in our global scope */
common_func(42);
printf("press 1 for global scope lookup, 2 for deep bind\n");
c = getchar();
if(c == '1')
{
dl_handle = dlopen("./liba.so", RTLD_NOW);
}
else if(c == '2')
{
dl_handle = dlopen("./liba.so", RTLD_NOW | RTLD_DEEPBIND);
}
else
{
printf("wrong choice\n");
return 1;
}
if( ! dl_handle)
{
printf("dlopen failed: %s\n", dlerror());
return 2;
}
a_ptr = dlsym(dl_handle, "a_func");
if( ! a_ptr)
{
printf("dlsym failed: %s\n", dlerror());
return 3;
}
printf("calling a_func(42): %d\n", (*a_ptr)(42));
return 0;
}
让我们构建并运行所有的东西:
$ export LD_LIBRARY_PATH=.
$ gcc -o libcommon_v1.so -fPIC -shared libcommon_v1.c
$ gcc -o libcommon_v2.so -fPIC -shared libcommon_v2.c
$ gcc -Wall -g -o progb progb.c -L. -lcommon_v1 -ldl
$ gcc -o liba.so -fPIC -shared liba.c -L. -lcommon_v2
$ ./progb
press 1 for global scope lookup, 2 for deep bind
1
calling a_func(42): 44
$ ./progb
press 1 for global scope lookup, 2 for deep bind
2
calling a_func(42): 45
我们可以清楚地看到,使用默认选项时,dlopen 重用了程序 B 中存在的符号 common_func,而使用 RTLD_DEEPBIND,libcommon 被再次加载,库 A 获得了自己的 common_func 版本。