从 dlopen 加载的函数可以调用加载它的可执行文件中的函数吗?
Can function loaded from dlopen call a function from the executable that loaded it?
设置
假设我在 C/C++ 中编写了一个程序并希望允许插件加载。典型的解决方案是将插件编写为:
plugin.c
int my_plugin_fn() {
return 7;
}
并使用gcc -fpic -shared -o plugin.so plugin.c
之类的东西编译它
然后,在加载这个插件的主程序中,我们可能有:
loader.c
#include <stdio.h>
#include <dlfcn.h>
int main() {
void *plugin_handle = dlopen("./plugin.so", RTLD_LAZY);
if (!plugin_handle) {
printf("Could not open shared object: %s\n", dlerror());
return -1;
}
int (*fn)() = dlsym(plugin_handle, "my_plugin_fn");
char *err = dlerror();
if (err) {
printf("Could not resolve symbol: %s\n", err);
return -1;
}
printf("Plugin object returned: %d\n", fn());
return 0;
}
我用 gcc -o loader loader.c -ldl
编译了 loader.c,在 运行 之后,正如预期的那样,输出是 Plugin object returned: 7
。
问题
假设我们想在我们的主程序(loader.c)中添加插件可以使用的功能。例如,
loader_v2.c
#include <stdio.h>
#include <dlfcn.h>
int times_2(int x) {
return 2*x;
}
int main() {
void *plugin_handle = dlopen("./plugin_v2.so", RTLD_LAZY);
if (!plugin_handle) {
printf("Could not open shared object: %s\n", dlerror());
return -1;
}
int (*fn)() = dlsym(plugin_handle, "my_plugin_fn");
char *err = dlerror();
if (err) {
printf("Could not resolve symbol: %s\n", err);
return -1;
}
printf("Plugin object returned: %d\n", fn());
return 0;
}
plugin_v2.c
extern int times_2(int);
int my_plugin_fn() {
return times_2(7);
}
以与以前相同的方式编译和 运行 这些文件会生成 Could not open shared object: ./loader_v2: symbol lookup error: ./plugin_v2.so: undefined symbol: times_2
。
有没有办法使用 dlopen()
从加载它们的程序中调用函数来加载插件?
执行此类操作的最佳方法是使用函数指针。您可以将函数指针传递给库函数,库函数随后会调用它。
所以库函数看起来像这样:
int my_plugin_fn(int (*cb)(int)) {
return cb(7);
}
对 dlsym
的调用将如下所示:
int (*fn)(int (*)(int)) = dlsym(plugin_handle, "my_plugin_fn");
你会像这样调用库函数:
printf("Plugin object returned: %d\n", fn(times_2));
Is there a way to have plugins loaded using dlopen() call functions from the program that loaded them?
是的,但是您要从主可执行文件调用的函数必须从中 exported,not默认。您可以使用 nm -D loader
.
查看从主二进制文件导出的符号
您可以通过 link 使用 -rdynamic
标志导出主可执行文件中定义的 所有 函数。
一些 link 用户,最著名的是 GNU-ld 的较新版本,GOLD 和 LLD,支持 --export-dynamic-symbol
标志,它允许 有选择地 仅导出您需要的符号。
在您的情况下,您将 link 您的 loader
可执行文件 -Wl,--export-dynamic-symbol=times_2
。
设置
假设我在 C/C++ 中编写了一个程序并希望允许插件加载。典型的解决方案是将插件编写为:
plugin.c
int my_plugin_fn() {
return 7;
}
并使用gcc -fpic -shared -o plugin.so plugin.c
然后,在加载这个插件的主程序中,我们可能有:
loader.c
#include <stdio.h>
#include <dlfcn.h>
int main() {
void *plugin_handle = dlopen("./plugin.so", RTLD_LAZY);
if (!plugin_handle) {
printf("Could not open shared object: %s\n", dlerror());
return -1;
}
int (*fn)() = dlsym(plugin_handle, "my_plugin_fn");
char *err = dlerror();
if (err) {
printf("Could not resolve symbol: %s\n", err);
return -1;
}
printf("Plugin object returned: %d\n", fn());
return 0;
}
我用 gcc -o loader loader.c -ldl
编译了 loader.c,在 运行 之后,正如预期的那样,输出是 Plugin object returned: 7
。
问题
假设我们想在我们的主程序(loader.c)中添加插件可以使用的功能。例如,
loader_v2.c
#include <stdio.h>
#include <dlfcn.h>
int times_2(int x) {
return 2*x;
}
int main() {
void *plugin_handle = dlopen("./plugin_v2.so", RTLD_LAZY);
if (!plugin_handle) {
printf("Could not open shared object: %s\n", dlerror());
return -1;
}
int (*fn)() = dlsym(plugin_handle, "my_plugin_fn");
char *err = dlerror();
if (err) {
printf("Could not resolve symbol: %s\n", err);
return -1;
}
printf("Plugin object returned: %d\n", fn());
return 0;
}
plugin_v2.c
extern int times_2(int);
int my_plugin_fn() {
return times_2(7);
}
以与以前相同的方式编译和 运行 这些文件会生成 Could not open shared object: ./loader_v2: symbol lookup error: ./plugin_v2.so: undefined symbol: times_2
。
有没有办法使用 dlopen()
从加载它们的程序中调用函数来加载插件?
执行此类操作的最佳方法是使用函数指针。您可以将函数指针传递给库函数,库函数随后会调用它。
所以库函数看起来像这样:
int my_plugin_fn(int (*cb)(int)) {
return cb(7);
}
对 dlsym
的调用将如下所示:
int (*fn)(int (*)(int)) = dlsym(plugin_handle, "my_plugin_fn");
你会像这样调用库函数:
printf("Plugin object returned: %d\n", fn(times_2));
Is there a way to have plugins loaded using dlopen() call functions from the program that loaded them?
是的,但是您要从主可执行文件调用的函数必须从中 exported,not默认。您可以使用 nm -D loader
.
您可以通过 link 使用 -rdynamic
标志导出主可执行文件中定义的 所有 函数。
一些 link 用户,最著名的是 GNU-ld 的较新版本,GOLD 和 LLD,支持 --export-dynamic-symbol
标志,它允许 有选择地 仅导出您需要的符号。
在您的情况下,您将 link 您的 loader
可执行文件 -Wl,--export-dynamic-symbol=times_2
。