Linux

為什麼(以及如何)在我的共享庫中有(看似!)重複的符號?

  • June 6, 2019

我碰巧需要從導出的共享庫符號的平面列表中找出哪個庫導出了哪些符號。列表中有足夠的符號(20 個左右),我不會手動交叉引用每個符號。

我發現這nm -A -D -f sysv <library-name>似乎產生了有用的輸出——我可以搜尋包含FUNC在第二列中也列出了地址的行。所以我對 中的所有內容都執行了這個命令/usr/lib,並將其重定向到一個文件。

令我驚訝的是,我為解析文件而編寫的腳本中的健全性檢查報告說存在重複的符號!經調查發現庫似乎在導出重複符號?!?

我使用一些 shell 腳本驗證了這一點,並且我能夠將我使用的命令變成這個(技術上)單行:

readlink -f /lib/* /usr/lib/* \
 | grep -F .so. | sort | uniq \
 | while read x; do nm -A -D -f sysv $x; done \
 | grep FUNC | cut -d'|' -f1 | sort -g | uniq -c | sort -g \
 | sed -n '/^ \+1/!{s/^ \+[0-9]\+ \+//p}' | sed 's/ //g' \
 | tr '\n' '\v' \
 | sed ':1;s/\([^ ]\+\):\([^\v$]\+\)\v\1:/\1:\2|/g;t1' \
 | tr '\v' '\n' \
 | while IFS=: read -a x; do \
    nm -A -D -f sysv "${x[0]}" | grep ":\\(${x[1]//|/\\|}\\).*FUNC"; \
 done

上面的命令將使您的磁碟搜尋一小段時間。如果需要,您可以將其分解為重定向到臨時文件的塊。輸出也會很寬(~150 cols)。

我最初在我正在使用的 Debian Squeeze chroot 上執行原始腳本,但出於好奇,我在我的主機系統上執行了上述腳本,以查明 chroot 是否不正常。

嗯…… chroot 報告了超過 90 個重複項,但我的主機(Arch)系統顯然有大約 267 個。

該命令通過 greppingnm的輸出工作,因此結果有點嘈雜,但看起來像這樣:

/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_access|00043700|   T  |              FUNC|00000037|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_access|000436c0|   T  |              FUNC|0000003c|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_access_mask|000458f0|   T  |              FUNC|00000058|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size|000432a0|   T  |              FUNC|00000037|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size|00043260|   T  |              FUNC|0000003c|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size_max|00044ff0|   T  |              FUNC|0000003c|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size_max|00045030|   T  |              FUNC|00000037|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size_min|000453c0|   T  |              FUNC|00000037|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size_min|00045380|   T  |              FUNC|0000003c|     |.text

注意每個符號有兩個。地址是不同的,是的,但是……我認為動態連結是通過符號名稱工作的,就是這樣。(如果您在上面的列表中向右滾動)這些符號都是類型FUNC並且來自該.text部分,這使我更加困惑。

我發布這篇文章是為了了解這裡的引擎蓋下正在發生什麼有趣的魔法。(因為我的系統正在工作……)

如果有人有什麼好主意,我可以轉儲大約 600 行文本 - Pastebin 似乎不再流行,而且我不使用 GitHub - 我很樂意分享完整的輸出。

符號出現重複是因為提供的資訊nm不完整:有問題的符號是版本化的。你可以看到這個objdump -T

0000000000059d00 g    DF .text  0000000000000044 (ALSA_0.9)   snd_pcm_hw_params_get_access
0000000000056040 g    DF .text  000000000000004b  ALSA_0.9.0rc4 snd_pcm_hw_params_get_access

ornm--with-symbol-versions選項:

/usr/lib/x86_64-linux-gnu/libasound.so.2.0.0:snd_pcm_hw_params_get_access|0000000000059d00|   T  |              FUNC|0000000000000044|     |.text@ALSA_0.9
/usr/lib/x86_64-linux-gnu/libasound.so.2.0.0:snd_pcm_hw_params_get_access|0000000000056040|   T  |              FUNC|000000000000004b|     |.text@@ALSA_0.9.0rc4

二進製文件與特定版本的符號連結,它們將在連結時獲得正確的符號。這允許在保持向後兼容性的同時更改 API。

引用自:https://unix.stackexchange.com/questions/523231