我需要动态打开一个共享库lib.so
如果在运行时满足特定条件。该库包含约 700 个函数,我需要加载它们的所有符号。
一个简单的解决方案是定义指向lib.so
中包含的所有符号的函数指针。 , 使用 dlopen
加载库最后使用 dlsym
获取所有符号的地址.然而,考虑到函数的数量,实现该解决方案的代码非常繁琐。
我想知道是否存在更优雅和简洁的解决方案,也许可以适当使用宏来定义函数指针。谢谢!
最佳答案
您可以为 dlopen
-ed 库中的所有符号自动生成蹦床函数。 Trampolines 将被视为应用程序中的正常功能,但会在内部重定向到库中的真实代码。这是一个简单的 5 分钟 PoC:
$ cat lib.h
// Dynamic library header
#ifndef LIB_H
#define LIB_H
extern void foo(int);
extern void bar(int);
extern void baz(int);
#endif
$ cat lib.c
// Dynamic library implementation
#include <stdio.h>
void foo(int x) {
printf("Called library foo: %d\n", x);
}
void bar(int x) {
printf("Called library baz: %d\n", x);
}
void baz(int x) {
printf("Called library baz: %d\n", x);
}
$ cat main.c
// Main application
#include <dlfcn.h>
#include <stdio.h>
#include <lib.h>
// Should be autogenerated
void *fptrs[100];
void init_trampoline_table() {
void *h = dlopen("./lib.so", RTLD_LAZY);
fptrs[0] = dlsym(h, "foo");
fptrs[1] = dlsym(h, "bar");
fptrs[2] = dlsym(h, "baz");
}
int main() {
init_trampoline_table();
printf("Calling wrappers\n");
foo(123);
bar(456);
baz(789);
printf("Returned from wrappers\n");
return 0;
}
$ cat trampolines.S
// Trampoline code.
// Should be autogenerated. Each wrapper gets its own index in table.
// TODO: abort if table wasn't initialized.
.text
.globl foo
foo:
jmp *fptrs(%rip)
.globl bar
bar:
jmp *fptrs+8(%rip)
.globl baz
baz:
jmp *fptrs+16(%rip)
$ gcc -fPIC -shared -O2 lib.c -o lib.so
$ gcc -I. -O2 main.c trampolines.S -ldl
$ ./a.out
Calling wrappers
Called library foo: 123
Called library baz: 456
Called library baz: 789
Returned from wrappers
请注意,main.c
中的应用程序代码仅使用本地函数(包装库函数)并且根本不需要弄乱函数指针(除了在启动时初始化重定向表之外,这应该无论如何都是自动生成的代码)。
编辑:我创建了一个独立的工具 Implib.so 来自动创建 stub 库,如上例所示。结果证明这或多或少等同于众所周知的 Windows DLL 导入库。
关于c - 在 C 中使用 dlopen 时,是否有避免 dlsym 的优雅方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45917816/