Путь к библиотеке при динамической загрузке?
Как я могу получить путь к общей библиотеке из самой библиотеки?
Другими словами, допустим, что библиотека X загружается с помощью dlopen()
Как я могу получить доступ к пути, который был использован для загрузки указанной библиотеки из самой библиотеки?
Обратите внимание, что у меня не может быть агента, который загрузил библиотеку в первую очередь, мне этот параметр.
ОБНОВЛЕНО: Вот способ, который работает со статическими переменными:
std::string wdir;
namespace {
class dynamic_library_load_unload_handler {
public:
dynamic_library_load_unload_handler(){
Dl_info dl_info;
dladdr((void *) NP_Initialize, &dl_info);
std::string path(dl_info.dli_fname);
wdir = path.substr( 0, path.find_last_of( '/' ) +1 );
}
~dynamic_library_load_unload_handler(){
// Code to execute when the library is unloaded
}
} dynamic_library_load_unload_handler_hook;
}
2 ответа
Динамический компоновщик фактически ищет несколько мест, чтобы найти каждую динамическую библиотеку. К ним относятся (от man ld.so):
- Пути, заданные переменной среды
LD_LIBRARY_PATH
- Пути, запеченные в двоичном файле, загружают библиотеку под
DT_RUNPATH
запись - Кеш-файл /etc/ld.so.cache
- / lib и / usr / lib
Если вы хотите получить путь для конкретной общей библиотеки, я бы порекомендовал dladdr
функция. Со страницы руководства:
Функция dladdr() берет указатель на функцию и пытается определить имя и файл, в котором она находится. Информация хранится в
Dl_info
состав:typedef struct { const char *dli_fname; /* Pathname of shared object that contains address */ void *dli_fbase; /* Address at which shared object is loaded */ const char *dli_sname; /* Name of nearest symbol with address lower than addr */ void *dli_saddr; /* Exact address of symbol named in dli_sname */ } Dl_info;
Если не найдено ни одного символа, соответствующего адресу, тогда
dli_sname
а такжеdli_saddr
установлены вNULL
,
dladdr()
возвращает 0 в случае ошибки и ненулевое значение в случае успеха.
Таким образом, вы просто даете ему указатель на функцию, и он даст вам имя файла, который его предоставляет, и кучу другой информации. Так, например, у вас может быть конструктор в библиотеке, который вызывает его сам по себе, чтобы узнать полный путь к библиотеке:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
__attribute__((constructor))
void on_load(void) {
Dl_info dl_info;
dladdr((void *)on_load, &dl_info);
fprintf(stderr, "module %s loaded\n", dl_info.dli_fname);
}
Эта функция также работает в OS X с той же семантикой.
Поскольку dl_info.dli_fname не всегда содержит полный путь в Android (см. здесь), нам нужно проанализировать /proc/self/maps, чтобы получить полный путь.
string GetSelfPath()
{
string selfPath;
Dl_info di;
dladdr((void*)GetSelfPath, &di);
LOGC("GetSelfPath:%08X,dli_fbase:%08X,dli_saddr:%08X,dli_fname:%s,dli_sname:%s", GetSelfPath, di.dli_fbase, di.dli_saddr, di.dli_fname, di.dli_sname);
//dl_info.dli_fname not always contain full path in android,see android.googlesource.com/platform/bionic/+/… line 141
if (strrchr(di.dli_fname, '/') != NULL)
{
selfPath=di.dli_fname;
}
else selfPath= GetPathByFileName(di.dli_fname);
LOGC("self path:%s", selfPath.c_str());
return selfPath;
}
string GetPathByFileName(string targetFilename)
{
FILE *fp = fopen("/proc/self/maps", "r");
if (NULL == fp) {
return "";
}
const size_t BUFFER_SIZE = 256;
char buffer[BUFFER_SIZE] = "";
char path[BUFFER_SIZE] = "";
while (fgets(buffer, BUFFER_SIZE, fp)) {
if (sscanf(buffer, "%*llx-%*llx %*s %*s %*s %*s %s", path) == 1) {
char *bname = basename(path);
LOGC("check basename[%s]", bname);
if (strcasecmp(bname, targetFilename.c_str()) == 0) {
fclose(fp);
return path;
}
}
}
fclose(fp);
return "";
}