通过运行应用程序以编程方式确定正在使用的共享库

发布于 2024-12-29 12:41:40 字数 727 浏览 0 评论 0原文

是否可以(如果可以,如何)确定应用程序在运行时使用的共享库?基本上,我可以通过编程方式获取 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)。

Is it possible to (and, if so, how does one) determine the shared libraries of an application that are used by an application at runtime? Basically, can I programmatically obtain the the output of ldd? Preferred C/C++ solution does not just jump to execute ldd on the command-line.

Consider the following:
I have a driver application that calls doAction() from a shared library libfoo. I compile the application once and then set LD_LIBRARY_PATH to an appropriate directory containing a libfoo with the doAction() symbol defined. This way, I can have multiple implementations of doAction() in different libfoos but only ever compile an application once.

A real world example would be a professor having a class of students implement doAction(). Instead of compiling a test harness against each student's implementation of doAction(), the students submit a shared library and the professor can simply change LD_LIBRARY_PATH to evaluate each student.

My goal in obtaining the library currently being used is to perform an md5sum on the library at runtime to ensure I'm calling the correct library. In the contrived example, all students would submit the md5sum of their library and the professor could match the running executable + shared library (database lookup, log to file, ...) to the student, to prevent an accident in setting LD_LIBRARY_PATH effecting another student's grade (forgot to change LD_LIBRARY_PATH to David's directory and ran again with Bill's libfoo).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

岁月打碎记忆 2025-01-05 12:41:41

如果您使用的是 Linux,则可以使用 dl_iterate_phdr 函数:

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

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

If you're using Linux, you can use the dl_iterate_phdr function:

The dl_iterate_phdr() function allows an application to inquire at run time to find out which shared objects it has loaded.

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

源来凯始玺欢你 2025-01-05 12:41:41

由于看起来您正在使用 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 实际上是文件名……您也许可以通过这种方式获取它。

但我仍然认为它丑陋得多。

Since it looks like you're using something UNIX-y, just use dlopen instead of dynamically linking your driver app against the missing symbol.

Full sequence is:

  1. iterate over all submitted .so library filenames somehow (maybe you have one directory with studentname.so or something)
  2. load each library
  3. get the entry point function
  4. call it
  5. unload library (optional, I guess)

like so:

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);
}

Notes:

  • if the interface is the same in each case (ie, void (*)()), you could make this configurable by directory name and symbol name, and it'd work for more than one test
  • in fact, if the interface is NOT what you expect, the function pointer cast will do horrible things, so careful with this
  • finally, if the student used C++, their function name symbol will be mangled. Tell them to declare the entry-point as extern "C" void doAction() to avoid that.
  • the RTLD_LOCAL flag should stop anything in one student's library interfering with another (if you don't unload), but there are other flags it may be sensible to add
    • specifically, RTLD_NOW will cause dlopen to fail if the student lib has an unresolved external reference it can't figure out (so you can handle it gracefully, by failing them): otherwise your program may just crash when you call doAction.

Although I think the above is better than the solution you're directly asking for help with, I did also find a reference to dl_iterate_phdr while double-checking the docs. If you're on Linux specifically, and if the dl_phdr_info.dlpi_name is actually the filename ... you might be able to get it that way.

I still think it's much uglier, though.

近箐 2025-01-05 12:41:41

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

如果进程的pid为1234,则可以通过读取/proc/1234/maps(或更详细的/proc/1234/smaps)来获取其内存映射。该映射特别列出了 mmap 编辑的文件(尤其是共享库)。从应用程序内部,阅读 /proc/self/maps

尝试

   grep so /proc/self/maps

理解我的意思。

顺便说一句,如果您有地址,dladdr 函数会提供有关最近的地址的信息符号和共享对象...

附录

正如 Rob Mayoff 回答dl_iterate_phdr 可能是 Linux 上最好的解决方案

At runtime, it is not an application, it is a process.

If the process has pid 1234, you can get its memory map by reading /proc/1234/maps (or /proc/1234/smaps which is more detailed). That map lists in particular mmap-ed files (notably shared libraries). From inside the application, read /proc/self/maps

Try

   grep so /proc/self/maps

to have an idea of what I mean.

By the way, if you have an address, the dladdr function gives information about the nearest symbol and shared object...

addenda

And as Rob Mayoff answered, dl_iterate_phdr is probably the best solution on Linux

征棹 2025-01-05 12:41:41

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

If this is Linux (I doubt there's a generic POSIX way to do this but I could be wrong), you may be interested in the contents of /proc/(pid)/maps. This gives the mapped memory ranges for your process and you could search for which of the ranges your md5sum() function's address falls in.

萌梦深 2025-01-05 12:41:41

如果您使用的是 linux/unix,则可以使用 strace ,例如 strace -o strace .log -f Students_binary 。 Strace 跟踪所有系统调用,包括打开库的调用。然后,您可以解析 strace.log 来查找任何文件的所有打开情况,并对所有打开的文件执行 md5sum 。

If you're in linux/unix, you could use strace like strace -o strace.log -f students_binary . Strace traces all system calls, including the calls to open a library. Then you could parse strace.log for all openings of any file and perform the md5sum on all open files.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文