我使用以下测试代码减少了我的问题,
main.cc
#include <iostream>
int main(int argc, const char** argv) {
void init2();
init2();
return 0;
}
2.cc
#include <iostream>
int init2() {
void init1();
init1();
std::cout<<"init2 called\n";
return 0;
}
1.cc
#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include <iostream>
typedef FILE* (*FopenFunction)(const char* path, const char* mode);
static FopenFunction g_libc_fopen = NULL;
void init1() {
g_libc_fopen = reinterpret_cast<FopenFunction>(
dlsym(RTLD_NEXT, "fopen"));
std::cout<<"init1: fopen addr:"<<(void*)g_libc_fopen<<"\n";
}
__attribute__ ((__visibility__("default")))
FILE* fopen_override(const char* path, const char* mode) __asm__ ("fopen");
__attribute__ ((__visibility__("default")))
FILE* fopen_override(const char* path, const char* mode) {
return g_libc_fopen(path, mode);
}
将1.cc编译成lib1.so,将2.cc编译成lib2.so,如下所示,
g++ 1.cc -shared -ldl -fvisibility=default -fPIC -o lib1.so -L.
g++ 2.cc -shared -ldl -fvisibility=default -fPIC -o lib2.so -l1 -L.
g++ main.cc -l2 -l1 -L.
以上步骤将产生lib1.so,lib2.so和a.out。这里的问题是在运行可执行文件a.out时,在使用dlsym(RTLD_NEXT)时无法查找原始的“fread”符号。
输出是,
arunprasadr@demo:~/works/myex/c++/rtdl_next$ LD_LIBRARY_PATH=./ ./a.out
init1: fopen addr:0
init2 called
但是如果更改lib2.so的链接过程(如下所示),它似乎正在工作
g++ 2.cc -shared -ldl -fvisibility=default -fPIC -o lib2.so -L.
g++ main.cc -l2 -l1 -L.
LD_LIBRARY_PATH=./ ./a.out
输出:
arunprasadr@demo:~/works/myex/c++/rtdl_next$ LD_LIBRARY_PATH=./ ./a.out
init1: fopen addr:0x7f9e84a9e2c0
init2 called
有谁能请解释后台发生的事情?提前谢谢。
答案 0 :(得分:2)
这是一个有趣的(对我而言意外)结果。
首先,使用原始命令,我观察:
LD_DEBUG=symbols,bindings LD_LIBRARY_PATH=./ ./a.out |& grep fopen
10204: symbol=fopen; lookup in file=/lib/x86_64-linux-gnu/libm.so.6 [0]
10204: symbol=fopen; lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
10204: symbol=fopen; lookup in file=/lib/x86_64-linux-gnu/libgcc_s.so.1 [0]
10204: symbol=fopen; lookup in file=/lib/x86_64-linux-gnu/libdl.so.2 [0]
init1: fopen addr:0
将此与同一输出进行比较,但从-l1
的链接行中删除lib2.so
:
LD_DEBUG=symbols,bindings LD_LIBRARY_PATH=./ ./a.out |& grep fopen
10314: symbol=fopen; lookup in file=/usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]
10314: symbol=fopen; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
10314: binding file ./lib1.so [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `fopen'
init1: fopen addr:0x7f03692352c0
接下来的问题是:在第一种情况下,为什么加载器不在libc.so.6
搜索fopen
?
答案:加载器在_r_debug.r_map
链接链中有一个线性的库列表,RTLD_NEXT
将在调用{{1>}之后搜索库 }}
案例1和案例2的库顺序是否不同?你敢打赌:
案例1:
dlopen
案例2:
LD_LIBRARY_PATH=./ ldd ./a.out
linux-vdso.so.1 => (0x00007fff2f1ff000)
lib2.so => ./lib2.so (0x00007f54a2b12000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f54a27f1000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f54a2430000)
lib1.so => ./lib1.so (0x00007f54a222e000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f54a1f32000)
/lib64/ld-linux-x86-64.so.2 (0x00007f54a2d16000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f54a1d1b000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f54a1b17000)
现在应该清楚的是,案例2 LD_LIBRARY_PATH=./ ldd ./a.out
linux-vdso.so.1 => (0x00007fff39fff000)
lib2.so => ./lib2.so (0x00007f8502329000)
lib1.so => ./lib1.so (0x00007f8502127000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f8501e05000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8501a45000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f8501841000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8501544000)
/lib64/ld-linux-x86-64.so.2 (0x00007f850252d000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f850132e000)
跟libc.so.6
之后,但案例1则没有。{/ p>
我还不明白是什么导致了这种特殊的排序。我将不得不考虑更多。