通过运行应用程序以编程方式确定正在使用的共享库
是否有可能(以及如果是这样,如何)确定应用程序在运行时使用的应用程序的共享库? 基本上,我可以通过编程方式获得ldd
的输出吗? 首选的C / C ++解决方案不仅仅是跳转到命令行执行ldd。
请考虑以下内容:我有一个驱动程序应用程序从共享库libfoo
调用doAction()
。 我编译应用程序一次,然后将LD_LIBRARY_PATH
设置为包含定义了doAction()
符号的libfoo
的相应目录。 这样,我可以在不同的libfoo
有多个doAction()
实现,但只能编译一次应用程序。
一个现实世界的例子是教授有一类学生实现doAction()
。 学生不是为每个学生的doAction()
实现编译测试工具,而是提交一个共享库,教授可以简单地改变LD_LIBRARY_PATH
来评估每个学生。
我获取当前正在使用的库的目标是在运行时对库执行md5sum
以确保我调用正确的库。 在人为设计的例子中,所有学生都会提交他们图书馆的md5sum
,教授可以将正在运行的可执行文件+共享库(数据库查找,登录文件,…)与学生相匹配,以防止设置LD_LIBRARY_PATH
影响另一个人时发生意外学生的成绩(忘记将LD_LIBRARY_PATH
更改为David的目录并使用Bill的libfoo
再次libfoo
)。
由于看起来你正在使用UNIX-y,只需使用dlopen
而不是动态链接你的驱动程序应用程序与丢失的符号。
完整序列是:
- 以某种方式迭代所有提交的.so库文件名(也许你有一个带有studentname.so的目录)
- 加载每个库
- 获得入口点function
- 叫它
- 卸载库(可选,我猜)
像这样:
void *lib = dlopen(filename, RTLD_LOCAL); void *libfun = dlsym(lib, "doAction"); if (libfun == NULL) cout << "student failed by not providing doAction() in " << filename << endl; else { void (*doAction)(void) = (void (*)(void)) libfun; // no, I can't remember the correct syntax for casting to function pointer cout << "calling " << filename << ":doAction()" << endl; doAction(); // is there some way to tell if it succeeded? cout << "unloading " << filename << endl; dlclose(lib); }
笔记:
- 如果在每种情况下接口都相同(即,
void (*)()
),您可以通过目录名称和符号名称对其进行配置,并且它可以用于多个测试 - 事实上,如果界面不是你所期望的,那么函数指针转换会做出可怕的事情,所以要小心
- 最后,如果学生使用C ++,他们的函数名称符号将被破坏。 告诉他们将入口点声明为
extern "C" void doAction()
以避免这种情况。 -
RTLD_LOCAL
标志应该阻止一个学生的库中的任何内容干扰另一个(如果你没有卸载),但是有其他标志可能是明智的添加- 具体来说,如果学生lib有一个无法解决的未解析的外部引用,
RTLD_NOW
将导致dlopen
失败(所以你可以通过失败来优雅地处理它):否则你的程序可能会在你调用doAction
时崩溃。
- 具体来说,如果学生lib有一个无法解决的未解析的外部引用,
虽然我认为上述内容比您直接寻求帮助的解决方案更好 ,但我还在重复检查文档时找到了对dl_iterate_phdr
的引用。 如果您专门使用Linux,并且dl_phdr_info.dlpi_name
实际上是文件名...您可能能够以这种方式获得它。
不过,我仍然认为这更加丑陋。
如果您使用的是Linux,则可以使用dl_iterate_phdr
函数:
dl_iterate_phdr()函数允许应用程序在运行时查询以找出它已加载的共享对象。
在运行时,它不是一个应用程序,它是一个过程。
如果进程有pid 1234,你可以通过读取/proc/1234/maps
(或/proc/1234/smaps
更详细)来获取其内存映射。 该映射特别列出了mmap -ed文件(特别是共享库)。 从应用程序内部,读取/proc/self/maps
尝试
grep so /proc/self/maps
了解我的意思。
顺便说一下,如果你有一个地址, dladdr函数会提供有关最近的符号和共享对象的信息……
附加物
正如Rob Mayoff 回答的那样 , dl_iterate_phdr可能是Linux上最好的解决方案
如果这是Linux(我怀疑有一种通用的POSIX方法可以做到这一点,但我可能错了),你可能会对/ proc /(pid)/ maps的内容感兴趣。 这为您的进程提供了映射的内存范围,您可以搜索md5sum()函数的地址属于哪个范围。
如果你在linux / unix中,你可以像strace -o strace.log -f students_binary
一样使用strace 。 Strace跟踪所有系统调用,包括打开库的调用。 然后你可以解析任何文件的所有开口的strace.log
并在所有打开的文件上执行md5sum
。