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

时间:2011-07-13 09:02:18

标签: c++ c linux posix 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一起使用,我的问题符合条件both和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来获取最终的绝对路径名。它工作得很好!

3 个答案:

答案 0 :(得分:9)

你可以使用

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

其中p的类型为Link_map **

请参阅man dlinfo了解详情

答案 1 :(得分:1)

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

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。那里 可能是它没有处理的特殊情况,但上述工作 让我们找到可执行文件。 (splitisAbsolute是另一个 我们的库中的函数可以做很明显的事情。)

答案 2 :(得分:0)

我能想到的一个选项是使用函数pathfind()

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

可以从三个位置之一加载DL:当前目录,exec所在的目录和LD_LIBRARY_PATH - 您可以检查最后两个 - 并使用pathfindgetenv("LD_LIBRARY_PATH")进行{{ 1}}参数尝试搜索另一个。