linux 动态库构造函数,Linux共享库全局构造函数的相互依赖性
操作系統(tǒng)Centos 5.6 i686 2.6.18-53.1.4.el5vm.
gcc版本4.1.2 20080704(Red Hat 4.1.2-48)
ld版本2.17.50.0.6-6.el5 20061020
我以這種方式編譯:
gcc -c -fnon-call-exceptions -fexceptions -Wall -DUNICODE -D_UNICODE -D_REENTRANT -I.
并以這種方式鏈接:
gcc -lstdc -pthread -ldl -lrt –no-relocate -Wl,-rpath,$SO_DIR -L $SO_DIR $LIBRARIES
我有3個(gè)庫(kù)和一個(gè)可執(zhí)行文件:A.so,B.so,C.so,ElfExec
B.so取決于A.so.
C.so取決于B.so.
在代碼A.so中具有通過(guò)其公開(kāi)功能A.h的標(biāo)頭,在代碼中B.so具有B.h標(biāo)頭,其中包括A.h和B的功能.代碼中的C.so包括B.h.
A.h定義了一個(gè)靜態(tài)變量K,該類型可以在且僅當(dāng)初始化A.so的靜態(tài)內(nèi)存管理器時(shí)使用.變量K在頭文件A.h中直接定義,因此,它的初始化在組成B.so和C.so的所有對(duì)象的全局構(gòu)造函數(shù)中傳播.
我像這樣鏈接所有內(nèi)容:
gcc“所有B模塊” -lstdc -pthread -ldl -lrt –no-relocate -Wl,-rpath,$SO_DIR -L $SO_DIR A.so
gcc“所有C模塊” -lstdc -pthread -ldl -lrt-無(wú)重定位-Wl,-rpath,$SO_DIR -L $SO_DIR B.so
gcc“所有ElfExec模塊” -lstdc -pthread -ldl -lrt –no-relocate -Wl,-rpath,$SO_DIR -L $SO_DIR C.so
我也嘗試過(guò):
gcc“所有ElfExec模塊” -lstdc -pthread -ldl -lrt –no-relocate -Wl,-rpath,$SO_DIR -L $SO_DIR A.so B.so C.so
ElfExec在運(yùn)行時(shí)會(huì)收到SIGSEGV,因?yàn)樗鼤?huì)在初始化A.so的靜態(tài)內(nèi)存管理器之前嘗試初始化變量K.
這是因?yàn)镃.so的全局構(gòu)造函數(shù)在A.so的全局構(gòu)造函數(shù)之前被調(diào)用.
如果我制作只需要B.so的應(yīng)用程序ElfExec2
gcc“所有ElfExec1模塊” -lstdc -pthread -ldl -lrt –no-relocate -Wl,-rpath,$SO_DIR -L $SO_DIR B.so
這正常工作.
對(duì)于ElfExec1,鏈接器看到需要先調(diào)用A.so中的全局構(gòu)造函數(shù),然后再調(diào)用B.so中的全局構(gòu)造函數(shù).
在ElfExec的情況下,這不會(huì)受到限制.
我的解決方案是這樣鏈接C.so:
gcc“所有C模塊” -lstdc -pthread -ldl -lrt –no-relocate -Wl,-rpath,$SO_DIR -L $SO_DIR A.so B.so
這使C.so與A.so直接相關(guān).
還有另一種方式可以告訴鏈接程序全局構(gòu)造函數(shù)調(diào)用的順序嗎?
解決方法:
如您所見(jiàn),不要相信鏈接器比您更了解.如果順序很重要,則需要以編程方式指定順序.不要只是試圖欺騙鏈接器.
如果這些不是庫(kù),那就是您要做的,對(duì)吧?以正確的順序互相調(diào)用的構(gòu)造函數(shù)/初始化函數(shù)?
我的第一選擇是將庫(kù)設(shè)計(jì)為不具有或使用全局變量.
如果您不能這樣做,那么我的第二個(gè)選擇是為每個(gè)需要初始化全局變量以具有init方法的庫(kù).庫(kù)的使用者需要先調(diào)用該init方法,然后才能執(zhí)行任何操作,并且?guī)毂仨殗L試阻止使用/構(gòu)造,直到正確完成init為止.也許將它們靜態(tài)化為init方法,然后設(shè)置指向它們的全局指針(K * k)可能有助于實(shí)現(xiàn).這應(yīng)該足以使初始化鏈以正確的順序組合在一起.
最后,如果讓任何庫(kù)的用戶(對(duì)于A表示B,對(duì)于C表示B,對(duì)于C而言,C)的用戶都遇到障礙,則可以對(duì)gcc使用如下語(yǔ)言擴(kuò)展:
extern "C" __attribute__ ((constructor)) void A_lib_ctor()
{
// ....
}
extern "C" __attribute__ ((destructor)) void A_lib_dtor()
{
// ....
}
在加載庫(kù)時(shí)自動(dòng)執(zhí)行所需的操作.這犧牲了一些可移植性.可能會(huì)犧牲更多,較新版本的gcc支持構(gòu)造函數(shù)(優(yōu)先級(jí))語(yǔ)法.
我的最后選擇是使用dlopen手動(dòng)加載庫(kù)的復(fù)雜步驟.
對(duì)于您而言,最重要的選擇是設(shè)計(jì)更好,而后來(lái)的選擇則更糟.
標(biāo)簽:gcc,linker,ld,linux
來(lái)源: https://codeday.me/bug/20191102/1991358.html
總結(jié)
以上是生活随笔為你收集整理的linux 动态库构造函数,Linux共享库全局构造函数的相互依赖性的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: c语言 1 %3c%3c -253,结构
- 下一篇: mysql 分页 order_Mysql