Linux: как получить полное имя общего объекта, только что загруженного из конструктора?

#linux #dll #object #constructor #shared

#linux #dll #объект #constructor #общий

Вопрос:

В Windows конструктору DllMain передается несколько аргументов:

 BOOL WINAPI DllMain(  
  __in  HINSTANCE hinstDLL,  
  __in  DWORD fdwReason,  
  __in  LPVOID lpvReserved  
);
  

Из hinstDLL я могу получить полное имя файла самой библиотеки DLL, используя GetModuleFileName():

 LPTSTR str = new TCHAR[256];  
int libNameLength = GetModuleFileName(hinstDLL, str, 256);  
delete[] str;  
  

В приведенном выше примере str теперь содержит полное имя только что загруженной DLL, например, C:WindowsSystem32MyFile.dll.

В Linux конструктору общего объекта не передаются аргументы:

 void `__attribute__` ((constructor)) on_load(void);
  

Как мне получить полное имя библиотеки DLL в этом случае? Дополнительная оценка, если ваше решение работает и на Mac. 🙂

Комментарии:

1. Я не знаю, есть ли хороший способ. Мой вопрос в подобных ситуациях: «Почему вы хотите знать?». Отступив на уровень назад, вы можете обнаружить, что есть путь к вашей реальной цели, не делая шага, который в данный момент блокирует вас.

2. Хороший вопрос. Я хочу знать, потому что я разрабатываю CSP и модуль PKCS # 11 (DLL-файлы), оба из которых должны проверять свою целостность при загрузке. Оба DLL-файла загружаются ОС, поэтому моей точкой входа является конструктор. В настоящее время лучшая идея, которая у меня есть для проверки целостности DLL-файла, — это вычислить хэш DLL-файла в конструкторе, а затем отправить этот хэш на центральный сервер, который может проверить правильность хэша. Однако мне нужно имя файла DLL, чтобы иметь возможность вычислить хэш.

Ответ №1:

Я думаю, 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;
  

Если не удалось найти символ, соответствующий addr, то 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(on_load, amp;dl_info);
    fprintf(stderr, "module %s loadedn", dl_info.dli_fname);
}
  

РЕДАКТИРОВАТЬ: Похоже, что эта функция существует и в OS X с той же семантикой.

Комментарии:

1. Да, я так счастлив, что способ, о котором мы оба подумали, не является правильным ответом. 🙂

2. Этот метод не работает на Android: dli_fname содержит только имя файла, а не полный путь.

Ответ №2:

Один в высшей степени уродливый и ужасный способ сделать это — просмотреть /proc/pid /maps и найти отображение, которое охватывает адрес выполняемой on_load функции.

Комментарии:

1. Я начал идти по этому пути вчера, и я еще не отбросил его полностью , потому что на данный момент это единственное жизнеспособное решение, которое я знаю. Хотя у меня от этого тоже мурашки бегут по спине.