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?
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.
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 .
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))?
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;
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