Как получить абсолютное имя файла библиотеки, соответствующее относительному пути, заданному 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++ , так и С, и мой вопрос подходит для обоих, и 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
- относительное / простое имя файла. Карта даст не простое имя файла (i.e не foo.so
но может быть ./foo.so
). Впоследствии я использовал realpath
чтобы получить окончательное абсолютное имя пути. Отлично работает!
3 ответов
можно использовать
... dlinfo(handle, RTLD_DI_LINKMAP, p)
p->l_name ...
где p имеет тип Link_map**
Подробнее см. man dlinfo
единственное решение-имитировать алгоритм системы. Это не так трудно, как это звучит (хотя, как всегда, дьявол находится в подробности): я использую следующее, чтобы найти исполняемый путь:
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
, и
соответствующее значение по умолчанию вместо throwing, если оно не установлено. Там
вероятно, это особые случаи, которые он не обрабатывает, но выше завод
для нас, чтобы найти исполняемый. (split
и isAbsolute
другие
функции в нашей библиотеке, которые делают очевидные вещи.)
один из вариантов, который я могу придумать, - это использование функции pathfind()
:
char *pathfind(const char *path, const char *name, const char *mode);
DL можно загрузить из одного из трех мест: текущий КАТАЛОГ, КАТАЛОГ, в котором находился exec и LD_LIBRARY_PATH - вы можете проверить последние два-и использовать pathfind
С getenv("LD_LIBRARY_PATH")
на