下面是一个最小的可重现示例,其目标是从
b_util()
调用 a()
。我的问题是是否可以在不显式地将 b_util()
函数指针传递给 a.c
的情况下执行此操作。我正在寻找像-rdynamic
这样的标志,如
this Stack Overflow post中所述,它允许共享库从主可执行文件调用函数。使用此标志编译
a.c
或 b.c
会打印相同的运行时错误,但也许有一种方法可以利用该标志?您可以使用 gcc c.c -o c.out && gcc b.c -o b.so -shared -fPIC && gcc a.c -o a.so -shared && ./c.out
编译并运行以下代码,但问题是它会打印
dlopen: ./a.so: undefined symbol: b_util
:// a.c
void b_util(void);
void a(void) {
b_util();
}
// b.c
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
void assert_dl(void *p, char *fn_name) {
if (!p) {
fprintf(stderr, "%s: %s\n", fn_name, dlerror());
exit(EXIT_FAILURE);
}
}
void b(void) {
void *dll = dlopen("./a.so", RTLD_NOW);
assert_dl(dll, "dlopen");
void (*a)(void) = dlsym(dll, "a");
assert_dl(a, "dlsym");
a();
}
void b_util(void) {
printf("b_util\n");
}
// c.c
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
void assert_dl(void *p, char *fn_name) {
if (!p) {
fprintf(stderr, "%s: %s\n", fn_name, dlerror());
exit(EXIT_FAILURE);
}
}
int main(void) {
void *dll = dlopen("./b.so", RTLD_NOW);
assert_dl(dll, "dlopen");
void (*b)(void) = dlsym(dll, "b");
assert_dl(b, "dlsym");
b();
}
让我意识到了RTLD_GLOBAL
标志,我确实只需要将
dlopen("./b.so", RTLD_NOW)
更改为dlopen("./b.so", RTLD_NOW | RTLD_GLOBAL)
。过了一会儿我发现不需要b.so
来打开
a.so
。 c.c
只需先用b.so
打开RTLD_GLOBAL
即可使b_util
可见,就好像它已直接链接到程序中一样。之后,dlopen("./a.so", RTLD_NOW)
成功了:// a.c
void b_util(void);
void a(void) {
b_util();
}
// b.c
#include <stdio.h>
void b_util(void) {
printf("b_util\n");
}
// c.c
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
void assert_dl(void *p, char *fn_name) {
if (!p) {
fprintf(stderr, "%s: %s\n", fn_name, dlerror());
exit(EXIT_FAILURE);
}
}
int main(void) {
// Comment dlopen("./b.so") out to cause `undefined symbol: b_util`
void *dll_b = dlopen("./b.so", RTLD_NOW | RTLD_GLOBAL);
assert_dl(dll_b, "dlopen");
void *dll_a = dlopen("./a.so", RTLD_NOW);
assert_dl(dll_a, "dlopen");
void (*a)(void) = dlsym(dll_a, "a");
assert_dl(a, "dlsym");
a();
}