共有ライブラリに重複したシンボルが存在するのはなぜですか (また、どのようにして重複しているように見えるのでしょうか)?

共有ライブラリに重複したシンボルが存在するのはなぜですか (また、どのようにして重複しているように見えるのでしょうか)?

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

nm -A -D -f sysv <library-name>は役に立つ出力を生成するようで、 を含む行を検索でき、FUNC2 番目の列にアドレスもリストされていることがわかりました。そこで、 内のすべての行に対してこのコマンドを実行し/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

によって提供される情報が不完全なため、シンボルが重複して表示されます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 を変更できます。

関連情報