#include <stdio.h>
#include <dlfcn.h>
extern int f1_g();
extern int f2_g();
extern int f3_g();
int (*f1_f)();
int (*f2_f)();
int (*f3_f)();
int main() {
puts("Loading f1");
f1_f = dlsym(dlopen("libf1.so", RTLD_NOW), "f");
puts("Loading f2");
f2_f = dlsym(dlopen("libf2.so", RTLD_NOW), "f");
puts("Loading f3");
f3_f = dlsym(dlopen("libf3.so", RTLD_NOW), "f");
f1_f();
f1_g();
f2_f();
f2_g();
f3_f();
// f3_g(); /* We don't explicitly use f3_g, so f3.so is not linked */
return 0;
}
现在,我们编译并运行它:
$ # Need to specify -L in the build and LD_LIBRARY_PATH when running
$ # because . is not in the default library search path.
$ gcc -o main -Wall main.c -L. -lf1 -lf2 -lf3 -ldl
$ LD_LIBRARY_PATH=. ./main
Initializing f2
Initializing f1
Loading f1
Loading f2
Loading f3
Initializing f3
I'm f1::f
I'm f1_g
I'm f2::f
I'm f2_g
I'm f3::f
1条答案
按热度按时间dm7nw8vv1#
只要稍加小心,就可以将
dlopen
与链接到应用程序的共享库一起使用。dlopen
试图返回一个已经加载的共享对象的句柄。只要共享对象的名称正确,如果它是因为链接符号而被加载的,使用dlopen
将不会导致它被第二次加载。一个例子可以使这一点更加清楚。
下面是三个几乎相同的库,每个库都定义了一个名为
f
的函数和另一个具有唯一名称的函数(它们也有非导出的初始化器,我添加了这些初始化器,以便加载可见):文件f1.c
文件f2.c
文件f3.c
它们被编译成共享对象,并指定每个共享对象的soname:
下面是一个main函数,它显式引用了两个唯一的函数名,但是依赖于dlopen/dlsym来使用具有公共名称的函数。(它引用了两个唯一的名称而不是三个名称,以显示加载行为的差异,尽管如此,这是透明的)。注意,使用dlopen加载的库名称不包含斜杠,因此它们将与具有相同soname的已加载库匹配。
文件main.c
现在,我们编译并运行它:
因此,加载了
f1
和f2
在main
启动之前,因为显式使用的函数f1_g
和f2_g
需要这些共享对象(并对其进行初始化)。(使用dlopen
),则不会再次加载库。但是,对libf3.so
的dlopen
调用不会在可执行文件中找到共享对象,因此它由对dlopen
的调用加载(并初始化)。随后,调用所有函数,并获得各种
f
函数的预期版本。