问题 如何获取与dlopen相对路径对应的绝对库文件名?


在我的程序中,我有如下代码

/* libname may be a relative path */
void loadLib(char const *libname) {
   void *handle = dlopen(libname);
   /* ... */
   dlclose(handle);
}

/* .. */,我需要读取内存映射文件 /proc/self/maps,找到哪个虚拟内存地址 libname 映射到,我还需要打开库以查找其中的某些部分。为此,我需要绝对的名字 dlopen 通过在各个地方搜索(例如,在 ldconfig 缓存文件)。我怎样才能收到该文件名?


这就是我最终的结果(是的,这是C ++代码,但C标签对这个问题有意义,因为 dlopen 与C ++和C一起使用,我的问题适用于两者,POSIX为C指定它。)。

   boost::shared_ptr<void> dl;
   if(void *handle = dlopen(libfile, RTLD_LAZY)) {
      dl.reset(handle, &dlclose);
   } else {
      printdlerr();
      return -1;
   }

   /* update sofile to be an absolute file name */
   {
      struct link_map *map;
          dlinfo(dl.get(), RTLD_DI_LINKMAP, &map);
      if(!map) {
         return -1;
      }
      char *real = realpath(map->l_name, NULL);
      if(!real)
         return -1;
      sofile.reset(real, &free);
   }

libfile 是相对/纯文件名。该映射将产生一个非普通文件名(即不是 foo.so 但可能是 ./foo.so)。后来我用了 realpath 获取最终的绝对路径名称。它工作得很好!


12659
2017-07-13 09:02


起源



答案:


你可以用

... dlinfo(handle, RTLD_DI_LINKMAP, p)
p->l_name ...

其中p的类型为Link_map **

请参阅man dlinfo了解详情


9
2017-07-13 09:39



谢谢。我做到了,它的确有效。我很快就会展示我最后的方式。 - Johannes Schaub - litb


答案:


你可以用

... dlinfo(handle, RTLD_DI_LINKMAP, p)
p->l_name ...

其中p的类型为Link_map **

请参阅man dlinfo了解详情


9
2017-07-13 09:39



谢谢。我做到了,它的确有效。我很快就会展示我最后的方式。 - Johannes Schaub - litb


唯一的解决方案是模仿系统的算法。这不是 虽然听起来很困难(尽管一如既往,魔鬼仍然存在 详细信息):我使用以下命令查找可执行文件路径:

std::string retval = our_argv0;
if ( !isAbsolute( retval ) )
{
    char const* tmp = getenv( "PATH" );
    if ( tmp == NULL )
        throw std::runtime_error( "$PATH not set" );
    std::vector<std::string> dirs( split( std::string( tmp ), ":" ) );
    std::vector<std::string>::const_iterator i = dirs.begin();
    while ( i != dirs.end() 
            && ! access( (*i + '/' + retval).c_str(), X_OK ) == 0)
        ++ i;
    if ( i == dirs.end() )
        throw std::runtime_error("Cannot find load path");
    retval = *i + '/' + retval;
}
return std::string(
    retval.begin(),
    std::find( retval.rbegin(), retval.rend(), '/' ).base() );

您应该能够使用名称来适应库 库而不是 argv[0]LD_LIBRARY_PATH 代替 PATH,和 如果没有设置,则使用适当的默认值而不是throw。那里 可能是它没有处理的特殊情况,但上述工作 让我们找到可执行文件。 (split 和 isAbsolute 是其他的 我们的库中的函数可以做很明显的事情。)


1
2017-07-13 09:45





我能想到的一个选择是使用功能 pathfind()

char *pathfind(const char *path, const char *name, const char *mode);

DL可以从以下三个位置之一加载:当前目录,exec所在的目录和LD_LIBRARY_PATH - 您可以检查最后两个 - 并使用 pathfind 随着 getenv("LD_LIBRARY_PATH") 对于 path 尝试搜索另一个的参数。


0
2017-07-13 09:19



你在哪里找到 pathfind?我在Posix文档中找不到它,甚至在Linux文档中也找不到它。 - James Kanze