2012-03-18 129 views
30

當在Windows加載共享庫時自動執行功能,LoadLibrary()調用導致DllMain庫執行爲每個新進程和線程庫重視,併爲每個進程和線程庫deattaches。加載共享庫

是否有類似的機制,適用於Mac OS X,Linux和其他可能的POSIX兼容的操作系統?

+0

https://stackoverflow.com/q/2053029/4361073 – parasrish 2018-01-08 10:07:35

回答

42

您可以定義一個帶載功能使用.init機制的Linux庫。這與指定二進制文件的加載時間入口點相同(例如,使用除main以外的內容作爲程序的入口點)。

當使用ld鏈接直接使用:

-init <function name> 

,或者如果你正在使用CC/gcc的鏈接,您可以使用:

-Wl,-init,<function name> 

這是在它的最簡單的層面。

編輯 對於析構函數/終結器,可以使用.fini機制。這個工作在相同的方式初始化選項,並使用:

-fini <function name> 

調用ld時。可用性僅限於Mac OSX平臺上的-init選項。

你也應該能夠使用__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"); 
    } 
} 

這是在writing win32 DLLS和強烈暗示語言規範relating to static constructors/destructors

編輯3您將需要在.o鏈接導出構造函數/析構函數例程,這將允許使用靜態初始值設定項。因爲它應該做的就是調用Runtime.initialize(),這實際上調用D代碼中的所有靜態構造函數/析構函數。用於初始化

存根d代碼(在一個名爲myshared.d):

dmd -m32 -c myshared.d 

檢查的附加/分離功能的名稱:

import core.runtime; 

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

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

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

這個存根創建的.o: (其他輸出):

用於調用這個(在這種情況下,所謂的export.c)
0000001c S _D8myshared6attachFZv 
00000034 S _D8myshared6detachFZv 

樣本.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。它似乎基於我執行的有限測試工作。看起來對共享對象/動態庫的支持非常有限,所以很有可能會有另一個障礙需要克服。

+0

看來你的解決方案對我來說是最可以接受的,因爲我用D編寫而不用C編寫,而且你的解決方案不涉及GCC特定的東西。在這些構造函數和析構函數中唯一要調用的是D運行時初始化和終止。 – toriningen 2012-03-18 17:18:39

+0

你還可以提示,指定析構函數的ld標誌是什麼? – toriningen 2012-03-18 17:20:13

+1

終結器/析構函數的等價物是使用-fini <函數名稱>選項。 – Petesh 2012-03-18 21:03:41

9

要具有每當共享庫加載或卸載執行的功能,則可以使用特定GCC-屬性語法標記構造和析構函數:

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

因爲一個C環境的各個部分依賴於事被GCC在後臺添加的標準.init代碼初始化後,直接使用-Wl,-init,<function name>可能會導致你的程序崩潰。

欲瞭解更多信息,請參閱Library constructor and destructor functions的Libary HOWTO。

0

對於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;