【问题标题】:How to use dlopen() to get the executables path如何使用 dlopen() 获取可执行文件路径
【发布时间】:2021-08-24 16:04:03
【问题描述】:

我正在尝试使用 dlopen() 和 dlinfo() 来获取我的可执行文件的路径。我可以通过使用 dlopen() 返回的句柄来获取 .so 的路径,但是当我使用 dlopen(NULL,RTLD_LAZY); 返回的句柄时那么我回来的路是空的。

void* executable_handle = dlopen(0, RTLD_LAZY);
if (nullptr != executable_handle) 
{
    char pp_linkmap[sizeof(link_map)];
    int r = dlinfo(executable_handle, RTLD_DI_LINKMAP, pp_linkmap);
    if (0 == r)
    {
        link_map* plink = *(link_map**)pp_linkmap;
        printf("path: %s\n", plink->l_name);
    }
}

我认为可执行文件的句柄可以像使用 .so 句柄一样在 dlinfo 函数中使用是错误的吗?

【问题讨论】:

  • 我不知道如何获取实际可执行文件的路径,但我认为您使用char[] 作为dlinfo 的参数会使它复杂化一点。 suggested fix
  • 为什么不使用argv[0]
  • 这将在库中调用,而不是从可执行文件本身调用。我无权访问 argv[0]。您可能会争辩说,如果可执行文件希望使用该路径,则应该使用 argv[0] ,但我无法控制。我正在尝试在 linux 上复制 GetModuleFileName() 的一些功能。

标签: c++ c filepath dlopen


【解决方案1】:

我认为可执行文件的句柄可以像使用 .so 句柄一样在 dlinfo 函数中使用是错误的吗?

是的,你是。

动态链接器不知道主可执行文件是从哪个文件加载的。这是因为内核为主要的可执行文件执行所有mmaps,并且只将一个文件描述符传递给动态加载程序(它的工作是加载其他所需的库并启动可执行文件运行)。

我正在尝试在 linux 上复制 GetModuleFileName() 的一些功能

没有可靠的方法来做到这一点。事实上,可执行文件可能不再存在在磁盘上的任何地方——运行可执行文件并在程序仍在运行时删除可执行文件是完全可以的。

另外,硬链接意味着可能有多个正确答案——如果a.outb.out 是硬链接的,则没有简单的方法来判断是使用a.out 还是b.out 来启动程序正在运行。

您最好的选择可能是阅读/proc/self/exe,或解析/proc/self/cmdline 和/或/proc/self/maps

【讨论】:

  • 我的代码目前使用 /proc/self/exe 但我看到很多地方说它不可靠。我想我现在会坚持下去,看看是否有任何问题。谢谢。
  • /proc/self/exe 确实是最好的选择,但请注意这是 Linux 特有的——它不适用于 macOS,也不适用于(我相信)Mingw。它肯定使代码不可移植。
  • 我只需要它在 Linux 上工作,所以这对我来说不是问题。谢谢。
  • 一点点:取消链接与删除不同。您当然可以在运行时取消链接可执行文件,并且 mmap 的页面将保留在磁盘上,直到它们被取消映射。但是,除非您将可执行文件加载到主内存中(通过交换或简单地流式传输到内存中)而不会导致问题(Linux AFAIK 无论如何都不允许您这样做),否则您无法从磁盘中删除这些页面。您是对的,如果您不习惯文件系统的工作方式,您可能会感到困惑。
【解决方案2】:

BSD 实用程序库有一个函数getprogname(3) 可以完全满足您的需求。在这种情况下,我建议它比 procfs 更便携且更易于使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    • 2014-09-21
    • 1970-01-01
    • 2019-09-22
    • 1970-01-01
    相关资源
    最近更新 更多