开发者

How to get the absolute library file name corresponding to a relative path given to dlopen?

In my program I have code like the following

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

Within /* .. */, I need to read the memory map file /proc/self/maps, to find the virtual memory address at which libname is mapped to and I also need to open the library to find certain sections in it. For this, I need the absolute name that dlopen found by searching in the various places (like, in the ldconfig cache file). How can I receive that file name?


This is what I finally ended up with (yes, this is C++ code, nonetheless the C tag makes sense for this question because dlopen is used with both C++ and C and my question is eligible for both and POSIX specifies it for 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 = rea开发者_运维技巧lpath(map->l_name, NULL);
      if(!real)
         return -1;
      sofile.reset(real, &free);
   }

libfile is the relative / plain filename. The map will yield a non-plain file name (i.e not foo.so but may be ./foo.so). Afterwards I used realpath to get the final absolute path name. It works nicely!


you could use

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

where p is of type Link_map**

see man dlinfo for details


The only solution is to mimic the system's algorithm. This isn't as difficult as it sounds (although as always, the devil is in the details): I use the following to find the executable path:

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

You should be able to adapt it for a library, using the name of the library instead of argv[0], LD_LIBRARY_PATH instead of PATH, and the appropriate default instead of throwing if it isn't set. There are probably special cases which it doesn't handle, but the above works for us to find the executable. (split and isAbsolute are other functions in our library, which do the obvious things.)


One option I can think of is using function pathfind():

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

DL can be loaded from one of three locations: current directory, directory where the exec was located and LD_LIBRARY_PATH - you can check the last two - and use the pathfind with the getenv("LD_LIBRARY_PATH") for path parameter to try search for another one.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜