GCC/LD編譯連接潛規則 (第五彈) : 爲何會有undified symbol?

問題一:
你是否遇到過: 常常遇到加載一些so時, 提示undified symbol,致使加載失敗, 但是makefile明明包含了指定的庫呀, 怎麼還會undified ?

問題二:
你是否還遇到過, 經過ldd -r 查看so, 發現輸出包含有undified symbol, 但卻仍能正常加載.

問題一的解決之道
咱們要解決的是, 如何讓so正確的找到symbol.
可能緣由之一:
假設咱們知道undified symbol的符號肯定存在xxx.a裏面.
雖然使用了Makefile裏面加上了xxx.a的依賴, 可是, 必定要把xxx.a放在最後面. 由於有可能so依賴的其餘的.a庫也用到了xxx.a.
(PS:爲何要放在後面, 參考本系列的其餘文章)

現實案例:
某次編譯so時, 對編譯結果so文件ldd -r, 發現有undified symbol, 可是明明連接了對應的open_l5庫, 爲什麼還提示未找到符號?
file bin/spp_appwork.so
bin/spp_appwork.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped

ldd -r bin/spp_appwork.so 2>&1 | grep -v "tbase\|Tencent\|write_log\|dl"
linux-gate.so.1 => (0xbfffe000)
libpthread.so.0 => /lib/libpthread.so.0 (0xb7e7e000)
libz.so.1 => /usr/lib/libz.so.1 (0xb7e6c000)
libcrypto.so.0.9.8 => /usr/lib/libcrypto.so.0.9.8 (0xb7d40000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7c5f000)
libm.so.6 => /lib/libm.so.6 (0xb7c3a000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7c2f000)
libc.so.6 => /lib/libc.so.6 (0xb7b0f000)
/lib/ld-linux.so.2 (0x80000000)
undefined symbol: _ZN7COpenL54LoadEii (bin/spp_appwork.so)
undefined symbol: _ZN7COpenL56UpdateEi (bin/spp_appwork.so)

經過調整open_l5庫的位置, 問題解決.

可能緣由之二:
該符號原本是應該屬於其所依賴的某個so的, 可是因爲當前環境的so版本較低, 沒有包含指定的符號.

該猜想經過以下方式驗證

// 按照正常的流程編譯ld_so, 能夠正常運行
nemo@vm04_sles10:[ld_so]$ g++ -o ld_so ld_so.cpp -L. -la
nemo@vm04_sles10:[ld_so]$ ./ld_so 
lalala
call in funa()

// 找一個其餘的so替換liba.so, 
nemo@vm04_sles10:[ld_so]$ cp liba.so liba.so.bk
nemo@vm04_sles10:[ld_so]$ cp d.so liba.so

// 啓動時會發現undefined symbol
nemo@vm04_sles10:[ld_so]$ ./ld_so 
lalala // <========== 程序的前半部分代碼執行了, 輸出了lalala
./ld_so: symbol lookup error: ./ld_so: undefined symbol: _Z4funav // <========== 報錯了.

// 經過ldd -r 查看, 也能夠看出未定義的符號.
nemo@vm04_sles10:[ld_so]$ ldd -r ld_so
undefined symbol: _Z4funav (./ld_so) // <============= 未定義的符號.
linux-gate.so.1 => (0xbfffe000)
liba.so (0xb7f87000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e9d000)
libm.so.6 => /lib/libm.so.6 (0xb7e78000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7e6d000)
libc.so.6 => /lib/libc.so.6 (0xb7d4c000)
/lib/ld-linux.so.2 (0xb7f8a000)

現實案例二:
本人在製做綠色版lamp時也遇到相似問題. 在啓動apache時, 提示加載libphp5.so失敗: undefined symbol: xmlTextReaderSetup
經排查發現, 系統的/usr/local/bin目錄存在一個libxml2.so, 和我在當時編譯php時使用的libxml2的版本不一致, 經過修改 LD_LIBRARY_PATH, 使之優先尋找我指定目錄下的的libxml2庫解決.

問題二的解決之道
即便有undefined symbol:, 只要代碼在執行的過程當中用不到 也能正常加載so ? 
是的. 可是, 一旦在用到的時候, 就會報錯了. 就好比上面的例子, 執行ld_so輸出了lalala, 而後才報錯未找到符號undefined symbol: _Z4funav.

說明: 
ld 在連接生成so的時候, 容許undefined symbol, 由於這些確實的符號可能在so被加載時就解決了. 
ld 在連接生成可執行文件的時候, 是不容許undefined symbol的php

相關文章
相關標籤/搜索