Автоматически выполняемые функции при загрузке общих библиотек

при загрузке общих библиотек в Windows,LoadLibrary() называть причины DllMain в библиотеке, чтобы выполнить для каждого нового процесса и потока библиотека придает, и для каждого процесса и потока библиотека из deattaches.

существует ли аналогичный механизм для Mac OS X, Linux и, возможно, других POSIX-совместимых ОС?

4 ответов


вы можете определить функцию on-load для библиотеки 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)) semantic является наиболее предпочтительным механизмом для языка программирования 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 DLL и в спецификации языка относящиеся к статическим конструкторам / деструкторам.

редактировать 3 вам нужно будет связать в .o что экспортирует процедуры конструктора/деструктора, что позволит использовать статические инициализаторы. Как и все, что он должен сделать, это вызвать Runtime.initialize (), это фактически вызывает все статические конструкторы/деструкторы в D код.

заглушка D код для инициализатора (в файле с именем myshared.d):

import core.runtime;

extern (C) {
    void attach();
    void detach();
}

export void attach() {
    Runtime.initialize();
}

export void detach() {
    Runtime.terminate();
}

создать .О, этот огрызок:

 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

ссылка .С. О, а также .д.o файлы вместе с помощью:

cc -o libmyshared.dylib -m32 -shared myshared.o export.o -lphobos2

предполагая, что библиотека phobos2 находится в вашем стандартном пути поиска компоновщика. Обрывки -m32 параметры для компилятора и компоновщика заключаются в том, что версия D компилятор, который я построил локально, поддерживал только 32bit.

это производит .dylib, с которым можно связать. Кажется, он работает на основе ограниченного тестирования, которое я выполнил. Похоже, поддержка общих объектов / динамических библиотек очень ограничена, поэтому есть хороший шанс, что будет еще одно препятствие для преодоления.


чтобы функция выполнялась при загрузке или выгрузке общей библиотеки, вы можете пометить конструктор и функцию деструктора, используя синтаксис атрибута GCC:

__attribute__((constructor)) void init(void) { ... }
__attribute__((destructor))  void fini(void) { ... }

потому что различные части среды C зависят от того, что инициализируется в стандарте .init код добавлен GCC за кулисами, напрямую используя -Wl,-init,<function name> может привести к сбою вашей программы.

для получения дополнительной информации см. Libary HOWTO on библиотека конструктора и функции деструктора.


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;