2012-03-18 7 views
30

Durante il caricamento di librerie condivise in Windows, la chiamata LoadLibrary() causa DllMain nella libreria da eseguire per ogni nuovo processo e allegati di librerie di thread ae da ciascun deattaches di libreria di processi e thread.Funzioni eseguite automaticamente durante il caricamento di librerie condivise

Esiste un meccanismo simile per Mac OS X, Linux e probabilmente altri SO compatibili con POSIX?

+0

https://stackoverflow.com/q/2053029/4361073 – parasrish

risposta

42

È possibile definire una funzione di caricamento per una libreria Linux utilizzando il meccanismo .init. Questo equivale a specificare il punto di ingresso del tempo di caricamento per un binario (ad esempio utilizzando qualcosa di diverso da main come punto di ingresso per un programma).

Quando si collega usando ld direttamente si utilizza il:

-init <function name> 

o se si sta utilizzando cc/gcc di collegare, si utilizza:

-Wl,-init,<function name> 

Questo è al suo livello più semplice.

Modifica Per distruttori/finalizzatori, si utilizza il meccanismo .fini. Questo funziona nello stesso modo come l'opzione di init, e si utilizza:

-fini <function name> 

quando si richiama ld. La disponibilità è limitata all'opzione -init sulla piattaforma Mac OSX.

Si dovrebbe anche essere in grado di utilizzare la sintassi __attribute__((constructor)) per gcc:

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

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

che è probabilmente un modo più portatile piuttosto che avvitare con le opzioni di linker. Tutti i costruttori devono essere richiamati al momento del caricamento, ma non è il dipendente dall'ordine della loro inizializzazione, che porta alla follia e bug non riproducibili che costano tempo e fatica per il debug.

Modifica 2 L'uso della semantica __attribute__((constructor))/__attribute__((destructor)) è il meccanismo più preferibile per il linguaggio di programmazione C/C++.

Per la lingua D di programmazione si dovrebbe davvero utilizzare la statica del modulo costruttore/distruttore:

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

o la classe costruttore statico:

class Foo { 
    static this() { 
     printf("static this for Foo\n"); 
    } 
} 

Questo è fortemente accennato nel writing win32 DLLS e in la specifica della lingua relating to static constructors/destructors.

Modifica 3 È necessario collegare in un .o che esporta le routine di costruzione/distruttore, che consentiranno l'utilizzo degli inizializzatori statici. Come tutto ciò che dovrebbe fare è chiamare Runtime.initialize(), questo in realtà richiama tutti i costruttori/distruttori statici nel codice D.

Stub codice d per l'inizializzazione (in un file chiamato myshared.d):

import core.runtime; 

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

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

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

Creare il .o per questo stub:

dmd -m32 -c myshared.d 

controllare i nomi delle funzioni di aggancio/sgancio:

nm myshared.o 

Spettacoli (tra gli altri in uscita):

0000001c S _D8myshared6attachFZv 
00000034 S _D8myshared6detachFZv 

esempio di codice .c di richiamo di questa (chiamato export.c in questo caso), ci riferimento ai nomi delle routine esportate dal file 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(); 
} 

Si noti che i riferimenti devono extern void usa il nome storpiato della funzione esportata. Questi devono corrispondere o il codice non si collegherà.

compila il codice C utilizzando:

gcc -m32 -c export.c 

link .c.o ei file .d.o insieme utilizzando:

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

Supponendo che la libreria phobos2 è nel percorso di ricerca linker standard. Le infarinature delle opzioni -m32 per il compilatore e il linker sono perché la versione del compilatore D che ho creato localmente supportava solo 32 bit.

Questo produce un .dylib che può essere collegato a. Sembra funzionare sulla base dei test limitati che ho eseguito. Sembra che il supporto per gli oggetti condivisi/le librerie dinamiche sia molto limitato, quindi ci sono buone probabilità che ci sia un altro ostacolo da superare.

+0

Sembra che la soluzione è più accettabile per me, dato che sto scrivendo in D, non in C, e la tua soluzione non riguarda roba specifica per GCC. Le uniche cose da chiamare in questi costruttori e distruttori sono l'inizializzazione e la terminazione del runtime D. – toriningen

+0

Puoi anche suggerire, qual è il flag ld per specificare i distruttori? – toriningen

+1

L'equivalente per il finalizzatore/distruttore è quello di utilizzare l'opzione -fini . – Petesh

9

avere una funzione eseguita ogni volta che la libreria condivisa viene caricato o scaricato, è possibile contrassegnare una funzione di costruzione e distruttore utilizzando GCC-specifica sintassi dell'attributo:

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

Perché varie parti di un ambiente C dipendono da cose l'inizializzazione nel codice standard .init aggiunto da GCC dietro le quinte, utilizzando direttamente -Wl,-init,<function name> potrebbe causare l'arresto anomalo del programma.

Per ulteriori informazioni, consultare la guida di Libary su Library constructor and destructor functions.

0

Per C++ è possibile creare una classe e utilizzare il suo costruttore e distruttore per inizializzare la libreria.

Dopo, è necessario definire una variabile per questa classe.

Esempio inizializzazione OpenSSL nella biblioteca:

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

e solo aggiungere questa riga nel file di cpp: InitLibrary InitLib;