2

是否有可能(如果是的话,如何)确定应用程序在运行时使用的应用程序的共享库?基本上,我可以以编程方式获取输出ldd吗?首选的 C/C++ 解决方案不只是跳转到命令行上执行 ldd。

doAction()考虑以下几点:我有一个从共享库调用的驱动程序应用程序libfoo。我编译了一次应用程序,然后设置LD_LIBRARY_PATH到一个适当的目录,其中包含定义libfoodoAction()符号的 a 。这样,我可以doAction()在不同libfoo的 s 中有多个实现,但只能编译一次应用程序。

一个真实世界的例子是教授有一个学生的班级实施doAction()。学生无需针对每个学生的实现编译测试工具,而是doAction()提交一个共享库,教授可以简单地更改LD_LIBRARY_PATH以评估每个学生。

我获取当前正在使用的库的目标是md5sum在运行时对库执行 an 以确保调用正确的库。在人为设计的示例中,所有学生都将提交md5sum他们的库,教授可以将正在运行的可执行文件 + 共享库(数据库查找,日志到文件,...)匹配给学生,以防止设置意外LD_LIBRARY_PATH影响另一个学生的成绩(忘记切换LD_LIBRARY_PATH到 David 的目录并再次使用 Bill 的目录运行libfoo)。

4

5 回答 5

4

由于看起来您使用的是 UNIX-y,因此只需使用dlopen而不是动态链接您的驱动程序应用程序与缺少的符号。

完整的序列是:

  1. 以某种方式遍历所有提交的 .so 库文件名(也许您有一个目录,其中包含studentname.so或其他内容)
  2. 加载每个库
  3. 获取入口点函数
  4. 称它为
  5. 卸载库(我猜是可选的)

像这样:

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标志应该阻止一个学生图书馆中的任何东西干扰另一个学生(如果你不卸载),但还有其他标志可能是明智的添加
    • 具体来说,如果学生库有一个无法解决的未解析外部引用,RTLD_NOW将导致dlopen失败(因此您可以通过失败来优雅地处理它):否则您的程序可能会在您调用doAction.

尽管我认为上述解决方案比您直接寻求帮助的解决方案要好,但我在仔细检查文档时也确实找到了参考dl_iterate_phdr。如果您专门在 Linux 上,并且dl_phdr_info.dlpi_name实际上是文件名……您也许可以这样获得。

不过,我仍然认为它更丑陋。

于 2012-01-27T18:47:46.983 回答
3

如果您使用的是 Linux,则可以使用以下dl_iterate_phdr功能:

dl_iterate_phdr() 函数允许应用程序在运行时查询以找出它已加载的共享对象。

http://linux.die.net/man/3/dl_iterate_phdr

于 2012-01-27T18:57:52.847 回答
2

在运行时,它不是一个应用程序,它是一个进程。

如果进程有 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 上的最佳解决方案

于 2012-01-27T18:39:50.047 回答
1

如果这是 Linux(我怀疑是否有通用的 POSIX 方法可以做到这一点,但我可能是错的),您可能对 /proc/(pid)/maps 的内容感兴趣。这为您的进程提供了映射的内存范围,您可以搜索 md5sum() 函数的地址属于哪个范围。

于 2012-01-27T18:41:43.817 回答
0

如果您在 linux/unix 中,则可以使用strace 之类的strace -o strace.log -f students_binary. Strace 跟踪所有系统调用,包括打开库的调用。然后您可以解析strace.log任何文件的所有开口并md5sum在所有打开的文件上执行。

于 2012-01-27T18:43:31.417 回答