Автоматически выполняемые функции при загрузке общих библиотек
При загрузке общих библиотек в Windows, LoadLibrary()
причины вызова DllMain
в библиотеке, чтобы выполнить для каждого нового процесса и присоединения библиотеки потоков, и для каждого процесса и отсоединения библиотеки потоков от.
Существует ли подобный механизм для Mac OS X, Linux и, возможно, других POSIX-совместимых ОС?
4 ответа
Вы можете определить функцию загрузки для библиотеки linux, используя .init
механизм. Это то же самое, что и указание точки входа во время загрузки для двоичного файла (например, использование в качестве точки входа для программы чего-то другого, кроме main).
При использовании ссылок ld
непосредственно вы используете:
-init <function name>
или если вы используете cc / gcc для ссылки, вы используете:
-Wl,-init,<function name>
Это на самом простом уровне.
Редактировать Для деструкторов / финализаторов, вы используете .fini
механизм. Это работает так же, как опция init, и вы используете:
-fini <function name>
при вызове ld
, Доступность ограничена -init
вариант на платформе Mac OSX.
Вы также должны быть в состоянии использовать __attribute__((constructor))
Синтаксис для GCC:
static void con() __attribute__((constructor));
void con() {
printf("I'm a constructor\n");
}
Что, вероятно, является более переносимым способом, чем использование вариантов компоновщика. Все конструкторы должны вызываться во время загрузки, но не зависят от порядка их инициализации, что приводит к безумию и невоспроизводимым ошибкам, которые требуют времени и усилий для отладки.
Редактировать 2 Использование __attribute__((constructor))/__attribute__((destructor))
семантика является наиболее предпочтительным механизмом для языка программирования C/C++.
Для D
Язык программирования, вы действительно должны использовать статический модуль конструктор / деструктор:
static this() {
printf("static this for mymodule\n");
}
static ~this() {
printf("static ~this for mymodule\n");
}
Или конструктор статического класса:
class Foo {
static this() {
printf("static this for Foo\n");
}
}
На это настоятельно намекают в написании Win32 DLLS и в спецификации языка, относящейся к статическим конструкторам / деструкторам.
Изменить 3 Вам нужно будет ссылку в .o
который экспортирует подпрограммы конструктора / деструктора, что позволит использовать статические инициализаторы. Как все, что он должен сделать, это вызвать Runtime.initialize(), это на самом деле вызывает все статические конструкторы / деструкторы в D
код.
Код заглушки для инициализатора (в файле с именем myshared.d
):
import core.runtime;
extern (C) {
void attach();
void detach();
}
export void attach() {
Runtime.initialize();
}
export void detach() {
Runtime.terminate();
}
Создайте.o для этой заглушки:
dmd -m32 -c myshared.d
Проверьте названия функций прикрепления / отсоединения:
nm myshared.o
Показывает (среди прочего выход):
0000001c S _D8myshared6attachFZv
00000034 S _D8myshared6detachFZv
Пример кода.c для вызова этого (в данном случае называется export.c), мы ссылаемся на имена экспортированных подпрограмм из my shared.o
файл:
extern void D8myshared6attachFZv(void);
extern void D8myshared6detachFZv(void);
void __attach(void) __attribute__((constructor));
void __detach(void) __attribute__((destructor));
void __attach(void)
{
D8myshared6attachFZv();
}
void __detach(void)
{
D8myshared6detachFZv();
}
Обратите внимание, что extern void
ссылки должны использовать искаженное имя экспортируемой функции. Они должны совпадать, иначе код не будет ссылаться.
скомпилируйте код C, используя:
gcc -m32 -c export.c
свяжите файлы.co и.do вместе, используя:
cc -o libmyshared.dylib -m32 -shared myshared.o export.o -lphobos2
Предполагая, что библиотека phobos2 находится в вашем стандартном пути поиска компоновщика. Smatterings of -m32
варианты компилятора и компоновщика объясняются тем, что версия компилятора D, которую я создал локально, поддерживает только 32-битную версию.
Это создает.dylib, который может быть связан с. Кажется, это работает на основе ограниченного тестирования, которое я провел. Похоже, что поддержка общих объектов / динамических библиотек очень ограничена, поэтому есть хороший шанс, что будет преодолено еще одно препятствие.
Чтобы функция выполнялась всякий раз, когда разделяемая библиотека загружается или выгружается, вы можете пометить функцию конструктора и деструктора, используя синтаксис атрибута GCC:
__attribute__((constructor)) void init(void) { ... }
__attribute__((destructor)) void fini(void) { ... }
Потому что различные части среды C зависят от того, что инициализируется в стандарте. .init
код, добавленный GCC за кулисами, непосредственно с помощью -Wl,-init,<function name>
может вызвать сбой вашей программы.
Для получения дополнительной информации см. Libary HOWTO о функциях конструктора и деструктора библиотеки.
GCC, а также clang AFAIK, поддерживают конструктор GCC и атрибуты деструктора. Для получения дополнительной информации см. Как именно работает __attribute__((конструктор))?
Для C++ вы можете создать класс и использовать его конструктор и деструктор для инициализации библиотеки.
После этого вам нужно только определить переменную для этого класса.
Пример инициализации openssl в библиотеке:
class InitLibrary {
public:
InitLibrary() {
CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
SSL_library_init(); // Initialize OpenSSL's SSL libraries
SSL_load_error_strings(); // Load SSL error strings
ERR_load_BIO_strings(); // Load BIO error strings
OpenSSL_add_all_algorithms(); // Load all available encryption algorithms
}
~InitLibrary() {
ERR_remove_state(0);
CRYPTO_cleanup_all_ex_data();
ENGINE_cleanup();
}
};
и только добавить эту строку в файл cpp:InitLibrary InitLib;