Rog*_*mbe 5 c linux shared-libraries
从共享库中的函数,在运行进程(用 C 编写)中,我如何发现该共享库是从哪里加载的?
我找到的所有答案都涉及使用诸如ldd在命令行中或通过查看/proc/self/maps.
在 Win32 上,我只会使用GetModuleFileName(GetModuleHandle("foo.dll"), szPath, COUNTOF(szPath)). Linux 等价物是什么?
额外问题:我需要在 OS X 中使用相同的信息。
实现此目的的一种方法是使用 dladdr:
共享对象的代码:
$ cat so.c
#include <stdio.h>
#include <dlfcn.h>
void test_so_func()
{
Dl_info info;
if (dladdr(test_so_func, &info))
{
printf("Loaded from path = %s\n", info.dli_fname);
}
printf("hello\n");
}
Run Code Online (Sandbox Code Playgroud)
主执行代码:
$ cat test.c
void test_so_func();
int main() {
test_so_func();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
生成文件:
$ cat Makefile
test: test.o libso.so
gcc test.o -o $@ -Wl,-L.,-lso,-rpath,'$$ORIGIN'
clean:
-rm -f libso.so test.o test
libso.so: so.c
gcc -D_GNU_SOURCE=1 -fPIC -shared $< -o $@ -lc -ldl
test.o: test.c
gcc -fPIC -c $< -o $@
Run Code Online (Sandbox Code Playgroud)
我们来编译一下吧!
$ make
gcc -fPIC -c test.c -o test.o
gcc -D_GNU_SOURCE=1 -fPIC -shared so.c -o libso.so -lc -ldl
gcc test.o -o test -Wl,-L.,-lso,-rpath,'$ORIGIN'
Run Code Online (Sandbox Code Playgroud)
测试这个二进制文件。
$ ./test
Loaded from path = /spare/scratch/1564054710/libso.so
hello
Run Code Online (Sandbox Code Playgroud)
验证 libso.so 确实说的是实话。
$ ldd ./test
linux-vdso.so.1 => (0x00007ffdf55d5000)
libso.so => /spare/scratch/1564054710/./libso.so (0x00007fbcc4602000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbcc4238000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fbcc4034000)
/lib64/ld-linux-x86-64.so.2 (0x00007fbcc4804000)
Run Code Online (Sandbox Code Playgroud)
这个答案的功劳归于https://github.com/mingwandroid
您可以使用dl_iterate_phdr来迭代所有加载的库及其段(类似的功能可用于 OSX,请参阅此问题)。但大多数项目只是解析/proc/self/maps。
作为旁注,请记住映射可能会动态更改(如果通过加载库dlopen),因此在启动时读取它们可能还不够。