本文記錄瞭解決
--hash-style
兼容性問題的過程。
問題
dlopen failed: empty/missing DT_HASH in "libxxx.so" (built with --hash-style=gnu?)
最近,穩定性監控平臺,被這一行錯誤日誌霸榜,剛看到時也一臉懵逼,下面我們來逐步分析。
名詞解釋
首先需要查閱一下相關文檔,瞭解一下其中的”新朋友
”。
DT_HASH
ELF 中的一個 Sections,保存了一個用於查找符號的散列表,用於支持符號表的訪問,能夠提高符號搜索速度。
--hash-style=style
(以下解釋摘自man ld
)
Set the type of linker's hash table(s). style can be either "sysv" for classic ELF ".hash" section, "gnu" for new style GNU ".gnu.hash" section or "both" for both the classic ELF ".hash" and new style GNU ".gnu.hash" hash tables. The default is "sysv".
實驗
通過查閱 --hash-style=style
參數,發現 style
支持三種配置:sysv
、gnu
和both
,廢話不多說,先試一把。
gcc -Wl,--hash-style=sysv
$ readelf -S libxxx.so | grep "hash"
[ 4] .hash HASH 0000000000003120 00003120
gcc -Wl,--hash-style=gnu
$ readelf -S libxxx.so | grep "hash"
[ 4] .gnu.hash GNU_HASH 0000000000003120 00003120
gcc -Wl,--hash-style=both
$ readelf -S libxxx.so | grep "hash"
[ 4] .gnu.hash GNU_HASH 0000000000003120 00003120
[ 5] .hash HASH 00000000000035f8 000035f8
-Wl
用於編譯器向鏈接器傳遞參數。
如上,發現使用不同的配置,Sections Name
不同。
.gnu.hash
段,提供了與hash
段相同的功能;但是與hash
相比,增加了某些限制(附加規則),導致了不兼容,帶來了50%
的動態鏈接性能提升,具體參見 https://blogs.oracle.com/solaris/gnu-hash-elf-sections-v2。
分析
結合實驗結果,我先翻譯一下問題中的那一行錯誤日誌:
動態庫加載失敗,libxxx.so 中 DT_HASH 爲空或者丟失,是不是用了 --hash-style=gnu 編譯?
結合上表,若 --hash-style=gnu
,那麼 Section Name
就是 .gnu.hash
了,當然找不到.hash
了。
再查閱一下 Makefile
配置,發現並沒有相關配置,懷疑是編譯器的默認配置:
$ gcc -dumpspecs | grep "hash"
... --hash-style=gnu ...
-dumpspecs
參數可以打印編譯器的內置規範。
果不其然,默認的 --hash-style
配置爲了 gnu
。
結論
輸出的動態庫的 --hash-style
爲 gnu
,而目標系統並不能正確讀取 --hash-style
爲 gnu
的動態庫,導致瞭如上的錯誤。
解決方案
配置 --hash-style
爲 both
:
LDFLAGS += -Wl,--hash-style=both
參考
- Only one --hash-style in embedded Linux. Why?
- Binaries built on RHEL5 or FC6 do not work on RHEL4 or FC5!
- Android NDK UnsatisfiedLinkError: “dlopen failed: empty/missing DT_HASH”
- Trouble understanding gcc linker options
微信公衆號同步更新,微信搜索"AnSwEr不是答案"或者掃描二維碼,即可訂閱。
- GitHub:AnSwErYWJ
- Blog:http://www.answerywj.com
- Email:[email protected]
- Weibo:@AnSwEr不是答案