web-dev-qa-db-ja.com

共有ライブラリに(一見!)重複するシンボルがあるのはなぜ(そしてどのように)ですか?

エクスポートされた共有ライブラリシンボルのフラットリストから、どのシンボルがどのライブラリによってエクスポートされたかを調べる必要がありました。リストには十分な数のシンボル(20程度)が含まれていたため、それぞれを手動で相互参照することはしませんでした。

nm -A -D -f sysv <library-name>が有用な出力を生成しているように見えることがわかりました。2番目の列にも住所がリストされているFUNCを含む行を検索できました。そこで、このコマンドを/usr/lib内のすべてに対して実行し、ファイルにリダイレクトしました。

驚いたことに、ファイルを解析するために作成したスクリプトのサニティチェックでは、シンボルが重複していることが報告されました。調査の結果、ライブラリが重複したシンボルをエクスポートしているように見えましたか?!?

いくつかのシェルスクリプトを使用してこれを確認し、使用したコマンドをこれに変換することができました 技術的に 一発ギャグ:

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列)

最初は、作業中のDebian Squeeze chrootで元のスクリプトを実行しましたが、好奇心から、ホストシステムで上記を実行して、chrootが何らかの理由で正常でないかどうかを確認しました。

ええと... chrootは90を少し超える重複を報告しましたが、私のホスト(Arch)システムには明らかに約267があります。

このコマンドはnmの出力をgrepすることで機能するため、結果は少しうるさいですが、次のようになります。

/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

各シンボルが2つあることに注意してください。 アドレスが異なります、はい、しかし...動的リンクはシンボル名で機能すると思いました。それだけでした。私の混乱は、(上記のリストを右にスクロールした場合)シンボルがすべてタイプFUNCであり、.textセクションからのものであるという事実によって悪化します。

私はこれを投稿して、ここで内部でどのような興味深い魔法が起こっているかを学びます。 (私のシステムが機能しているので...)

誰かが私が約600行のテキストをダンプできる良いアイデアを持っているなら-Pastebinはもう流行していないようで、私はGitHubを使用していません-私は完全な出力を共有したいと思います。

1
i336_

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

またはnm--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を変更できます。

2
Stephen Kitt