12

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

/* 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获取最终的绝对路径名。它工作得很好!

4

3 回答 3

10

你可以使用

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

其中 p 是 Link_map 类型**

有关详细信息,请参阅 man dlinfo

于 2011-07-13T09:39:30.637 回答
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,以及适当的默认值而不是在未设置时抛出。可能存在它无法处理的特殊情况,但以上内容可以帮助我们找到可执行文件。(split并且isAbsolute是我们库中的其他函数,它们可以做显而易见的事情。)

于 2011-07-13T09:45:50.667 回答
0

我能想到的一种选择是使用函数pathfind()

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

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

于 2011-07-13T09:19:01.240 回答