Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

Вы можете определить функцию on-load для библиотеки linux с помощью механизма .init. Это то же самое, что и указание точки входа времени загрузки для двоичного файла (например, использование чего-то другого, кроме основного, как точки входа для программы).

При непосредственном соединении с помощью ld вы используете:

-init <function name>

или если вы используете cc/gcc для связи, вы используете:

-Wl,-init,<function name>

Это самый простой уровень.

Edit Для деструкторов/финализаторов используется механизм .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/С++.

Для языка программирования 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

Проверьте имена функций attach/detach:

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

свяжите файлы .c.o и .d.o вместе, используя:

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

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

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

Ответ 2

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

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

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

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

Ответ 4

Для С++ вы можете создать класс и использовать его конструктор и деструктор для инициализации библиотеки.

После этого вам нужно всего лишь определить переменную для этого класса.

Пример инициализации openssl в библиотеке:

class InitLibrary {
public:
  InitLibrary() {
    CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL use
    SSL_library_init(); // Initialize OpenSSL 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;