Linux では複数の共有ライブラリ(*.so)に同じ関数が定義されている場合、重複する関数については先に読み込まれた共有ライブラリが利用され、その他のライブラリで定義される重複シンボルについては無視されます。
共有ライブラリのロード順序は ld でのリンク順になります。
また、既存の実行可能ファイルのロード順序を調べるには ldd を使います。
$ gcc src.c -o foo -lc -lm # libc.so, libm.so の順にロード
$ ldd foo # foo では libc.so が優先されていることを確認
libc.so.6 => /lib/tls/libc.so.6 (0x00c07000)
libm.so.6 => /lib/tls/libm.so.6 (0x00d35000)
/lib/ld-linux.so.2 (0x00bed000)
$ gcc src.c -o bar -lm -lc # 同じソースに対してリンク順序を入れ替えて bar 作成。
$ ldd bar # bar では libm.so が優先されていることを確認
libm.so.6 => /lib/tls/libm.so.6 (0x00d35000)
libc.so.6 => /lib/tls/libc.so.6 (0x00c07000)
/lib/ld-linux.so.2 (0x00bed000)
今回の本題、どうやって共有ライブラリを優先するかを実行時に決めるか?ですが、
LD_PRELOAD を使うことでコンパイル時のロード順を入れ替えることができます。
>
$ # LD_PRELOAD に /lib/tls/libc.so.6 (libc.so へのパス)を指定
$ LD_PRELOAD=/lib/tls/libc.so.6
$ ldd bar # 優先順位が変わっていることを確認
/lib/tls/libc.so.6 (0x00c07000)
libm.so.6 => /lib/tls/libm.so.6 (0x00d35000)
/lib/ld-linux.so.2 (0x00bed000)
ちなみに、LD_PRELOAD を設定すると、(setuid/setgid されたプログラムなど)一部を除くほとんどのプログラムで任意のライブラリを事前ロードできます。
これを利用すると任意のプログラムのライブラリ定義関数を置き換えることが可能です(参考:hook_tcp.so)。
参考:
– 共有ライブラリの作成(HP テクニカルドキュメント)
– hook_tcp.so(チームチドリ)
What is hook_tcp.so:
LD_PRELOADを利用して、プログラム中で実行される connect()の接続先をsyslogへ記録するプログラムです。
とのことで、libc.so の CONNECT(2) を hook して動作します。
– 4.17. LIDS を使う時は、LD_PRELOAD 環境変数に注意した方がいいですか?(LIDS FAQ)