Automatycznie wykonywane funkcje podczas ładowania bibliotek współdzielonych

Podczas wczytywania bibliotek współdzielonych w systemie Windows, wywołanie LoadLibrary() powoduje, że DllMain in library uruchamia się dla każdego nowego procesu i biblioteki wątków, do których się dołącza, oraz dla każdego procesu i biblioteki wątków deattaches from.

Czy istnieje podobny mechanizm dla Mac OS X, Linuksa i ewentualnie innych OS-ów zgodnych z POSIX?

Author: P̲̳x͓L̳, 2012-03-18

4 answers

Możesz zdefiniować funkcję on-load dla biblioteki Linuksa używając mechanizmu .init. Jest to to samo, co określenie punktu wejścia w czasie ładowania dla programu binarnego (np. użycie czegoś innego niż main jako punktu wejścia dla programu).

Podczas linkowania używając ld bezpośrednio używasz:

-init <function name>

Lub jeśli używasz cc/gcc do linkowania, używasz:

-Wl,-init,<function name>

To jest na najprostszym poziomie.

Edit W przypadku destruktorów / finalizatorów używa się .fini mechanizm. Działa to w taki sam sposób jak opcja init, a Ty używasz:

-fini <function name>

Podczas wywoływania ld. Dostępność jest ograniczona do opcji -init na platformie Mac OSX.

Powinieneś także móc używać składni __attribute__((constructor)) dla gcc:

static void con() __attribute__((constructor));

void con() {
    printf("I'm a constructor\n");
}

Który jest prawdopodobnie bardziej przenośny sposób, a nie wkręcanie w opcje linkera. Wszystkie konstruktory powinny być wywoływane w czasie ładowania, ale nie zależą od kolejności ich inicjalizacji, co prowadzi do insanity i nieodwracalne błędy, które kosztują czas i wysiłek, aby debugować.

Edit 2 użycie semantycznego __attribute__((constructor))/__attribute__((destructor)) jest najbardziej pożądanym mechanizmem dla języka programowania C / C++.

Dla D języka programowania powinieneś naprawdę użyć konstruktora/destruktora modułu statycznego:

static this() {
    printf("static this for mymodule\n");
}
static ~this() {
    printf("static ~this for mymodule\n");
}

Lub konstruktor klasy statycznej:

class Foo {
    static this() {
        printf("static this for Foo\n");
    }
}
Jest to bardzo przydatne w przypadku, gdy nie jest to możliwe. odnoszące się do statycznych konstruktorów / destruktorów.

Edytuj 3 będziesz musiał połączyć się w .o, który eksportuje procedury konstruktora/destruktora, które pozwolą na użycie statycznych inicjalizatorów. Jak wszystko, co powinno zrobić, to wywołać Runtime.initialize () wywołuje wszystkie statyczne konstruktory/destruktory w kodzie D.

Kod Stub d dla inicjalizatora (w pliku o nazwie myshared.d):

import core.runtime;

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

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

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

Create the .o dla tego stub:

 dmd -m32 -c myshared.d

Sprawdź nazwy funkcji dołączania/odłączania:

nm myshared.o

Pokazuje (między innymi):

0000001c S _D8myshared6attachFZv
00000034 S _D8myshared6detachFZv

Próbka .kod c do wywołania tego (tzw. export.c w tym przypadku), odwołujemy się do nazw wyeksportowanych procedur z pliku 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();
}

Zauważ, że odniesienia extern void muszą używać zniekształconej nazwy eksportowanej funkcji. Muszą być zgodne lub kod nie będzie łączony.

Skompiluj kod C używając:

gcc -m32 -c export.c

Link the .c. O i w .pliki d. O razem używając:

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

Zakładając, że biblioteka phobos2 znajduje się w standardowej ścieżce wyszukiwania linkera. Smatteringi opcji -m32 dla kompilatora i linkera są spowodowane tym, że wersja kompilatora D, którą zbudowałem lokalnie, obsługiwała tylko 32bit.

To daje .dylib, z którym można się połączyć. Wydaje się, że działa w oparciu o ograniczone testy, które wykonałem. Wygląda na to, że wsparcie dla współdzielonych obiektów / dynamicznych bibliotek jest bardzo ograniczone, więc jest dobry szansa, że będzie kolejna przeszkoda do pokonania.

 46
Author: Petesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-20 23:02:48

Aby funkcja była wykonywana za każdym razem, gdy biblioteka współdzielona jest ładowana lub rozładowywana, możesz oznaczyć funkcję konstruktora i destruktora używając składni atrybutów specyficznych dla GCC:

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

Ponieważ różne części środowiska C zależą od rzeczy inicjowanych w standardowym kodzie .init dodanym przez GCC za kulisami, bezpośrednie użycie -Wl,-init,<function name> może spowodować awarię programu.

Aby uzyskać więcej informacji, zobacz Libary HOWTO na konstruktor i destruktor bibliotek funkcje .

 9
Author: Daniel Roethlisberger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-18 17:06:32

GCC, a także clang AFAIK, wspierają atrybuty konstruktora i destruktora GCC. Aby uzyskać więcej informacji, zobacz Jak dokładnie działa__atrybut _ _ ((konstruktor))?

 6
Author: janneb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:10

W C++ można utworzyć klasę i użyć jej konstruktora i destruktora do zainicjowania biblioteki.

Po, wystarczy zdefiniować zmienną dla tej klasy.

Przykład inicjalizacji openssl w bibliotece:

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();
  }
};

I dodaj tylko ten wiersz w pliku cpp: InitLibrary InitLib;

 0
Author: oml,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-10 08:12:37