【发布时间】:2017-03-21 22:02:47
【问题描述】:
我有一些具有循环依赖关系的共享库,我想用dlopen 加载它们。为此,我使用 RTLD_LAZY | RTLD_GLOBAL 标志调用 dlopen。
这很好用。
现在,我想检查所有共享库中的所有符号是否都已完全解析,因此我再次使用RTLD_NOW 调用dlopen,如果无法解析所有符号,这将失败。
至少,我是这样理解手册页的:
但是,随后的 dlopen() 调用会加载相同的共享对象 RTLD_NOW 可能会强制对早先加载的共享对象进行符号解析 RTLD_LAZY。
这是一个简单的例子来说明我的问题:
main.h
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include "h.h"
#define CNT 3
static const char *libs[CNT] = {"./liba.so", "./libb.so", "./libc.so"};
typedef int (*f_ptr)();
int main() {
void *h[CNT];
f_ptr f[CNT];
for (int i = 0; i < CNT; i++) {
printf("dlopen: %s\n", libs[i]);
h[i] = dlopen(libs[i], RTLD_LAZY | RTLD_GLOBAL);
if (!h[i]) {
fprintf(stderr, "%d %s: %s\n", __LINE__, libs[i], dlerror());
exit(EXIT_FAILURE);
}
}
for (int i = 0; i < CNT; i++) {
printf("dlopen again: %s\n", libs[i]);
void *xx = dlopen(libs[i], RTLD_NOW | RTLD_GLOBAL);
if (!xx) {
fprintf(stderr, "%d %s: %s\n", __LINE__, libs[i], dlerror());
dlclose(h[i]);
h[i] = 0;
} else {
dlclose(xx);
}
}
for (int i = 0; i < CNT; i++) {
if (h[i]) {
f[i] = (int (*)())dlsym(h[i], "init");
if (!f[i]) {
fprintf(stderr, "%d %s: %s\n", __LINE__, libs[i], dlerror());
exit(EXIT_FAILURE);
}
}
}
for (int i = 0; i < CNT; i++) {
if (f[i]) {
printf("%s %08d\n", libs[i], f[i]());
}
}
return 0;
}
交流
#include "h.h"
int init() { return 1 + b_(); }
int a_() { return 10; }
b.c
#include "h.h"
int init() { return 100 + a_(); }
int b_() { return 1000; }
c.c
#include "h.h"
int init() { return 10000 + x_(); }
int c_() { return 100000; }
h.h
int init();
int a_();
int b_();
int x_();
CMakeLists.txt
project(xx)
add_library(a SHARED a.c)
add_library(b SHARED b.c)
add_library(c SHARED c.c)
add_executable(main main.c)
target_link_libraries(main dl)
编译运行:
$ mkdir b && cd b && cmake .. && make && ./main
...
[100%] Built target b
dlopen: ./liba.so
dlopen: ./libb.so
dlopen: ./libc.so
dlopen again: ./liba.so
dlopen again: ./libb.so
dlopen again: ./libc.so
./liba.so 00001001
./libb.so 00000110
./main: symbol lookup error: ./libc.so: undefined symbol: x_
如何检测到 libc.so 无法完全加载 - 在调用之前 导致它崩溃的符号?
【问题讨论】:
-
在我工作的地方,如果有未定义的符号,我们总是将链接器标志设置为错误来构建共享库。所以这不是问题。不确定 cmake 的魔法符文是什么,但你想要的链接器标志是 --no-allow-shlib-undefined
-
按照我的理解,那么这个选项会不会允许共享库之间循环依赖?还是我错过了什么?
-
是的,不会。但你真的想要吗?
标签: c shared-libraries dlopen