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

При загрузке общих библиотек в 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;

Другие вопросы по тегам