遇到如下情況,主程序通過dlopen來打開.so文件,但是.so用到了主程序的log函數(shù)。
編譯so時,通過引用主程序頭文件來編譯通過,頭文件有l(wèi)og函數(shù)聲明:
extern "C" {
void print()
}
在主程序的.c文件里有函數(shù)的具體實現(xiàn)。
但是dlopen后運行so中函數(shù)時,出現(xiàn)找不到相應的symbol。
這時候就需要在編譯主程序ld時加上參數(shù)-rdynamic,該參數(shù)的作用是:將指示連接器把所有符號(而不僅僅只是程序已使用到的外部符號,但不包括靜態(tài)符號,比如被static修飾的函數(shù))都添加到動態(tài)符號表(即.dynsym表)里,以便那些通過dlopen()或backtrace()(這一系列函數(shù)使用.dynsym表內(nèi)符號)這樣的函數(shù)使用。
-rdynamic
Pass the flag ‘-export-dynamic’ to the ELF linker, on targets that support
it. This instructs the linker to add all symbols, not only used ones, to the
dynamic symbol table. This option is needed for some uses of dlopen or to
allow obtaining backtraces from within a program.
-g是編譯選項,而-rdynamic是鏈接選項
參考:http://www.lenky.info/archives/2013/01/2190
小例子:
a.cc
foo.h
foo.cc
main.cc
Makefile
運行dynamic后輸出為:
--whole-archive 可以把 在其后面出現(xiàn)的靜態(tài)庫包含的函數(shù)和變量輸出到動態(tài)庫,--no-whole-archive 則關掉這個特性
使用readelf -s libso.so | grep fun來查看libso.so的符號表里是否有fun這個函數(shù)暴露出來。有--whole-archive的可以查到fun,而沒有--whole-archive的,則找不到fun
先理清一下code
可執(zhí)行文件dynamic依賴與libso.so,而libso.so有包含liba.a,在liba.a的函數(shù)fun調(diào)用dlopen來打開libtmp.so
主函數(shù)調(diào)用liba.a的函數(shù)來打開libtmp.so
-fvisibility=hidden
設置默認的ELF鏡像中符號的可見性為隱藏。使用這個特性可以非常充分的提高連接和加載共享庫的性能,生成更加優(yōu)化的代碼,提供近乎完美的API輸出和防止符號碰撞。我們強烈建議你在編譯任何共享庫的時候使用該選項。
-fvisibility-inlines-hidden
默認隱藏所有內(nèi)聯(lián)函數(shù),從而減小導出符號表的大小,既能縮減文件的大小,還能提高運行性能,我們強烈建議你在編譯任何共享庫的時候使用該選項
所以編譯的時候也不能有-fvisibility=hidden和-fvisibility-inlines-hidden。如果有,也會在dlopen時造成錯誤:undefined symbol
總結:
本實例雖小,但用到了不少編譯選項
a: __attribute__((constructor))
主程序main函數(shù)之前被執(zhí)行或dlopen時被執(zhí)行
b: -rdynamic
ld時將動態(tài)庫的的所有符號都輸出到符號表,以便dlopen和backtrace也能調(diào)用
c: --whole-archive -la -Wl,--no-whole-archive
靜態(tài)庫的符號導入到動態(tài)庫的符號表中,默認是hidden的
d: -fvisibility=hidden和-fvisibility-inlines-hidden
ELF鏡像中符號的可見性為隱藏(在實驗過程中不太好用,待研究)
在編譯nodejs第三方模塊時都會碰到這樣的問題,第三方模塊依賴與nodejs進行編譯,而第三方模塊又是通過dlopen來打開的,這就要求nodejs編譯時將一下第三方模塊需要的函數(shù)都暴露出來。
參考:
http://www.fx114.net/qa-225-106759.aspx
http://os.chinaunix.net/a2010/0112/1060/000001060902_3.shtml
版權聲明:本文為博主原創(chuàng)文章