実行時リンカーには、アプリケーションの実行時リンクとその依存関係を詳細に追跡できるデバッグ機能が備わっています。この機能によって表示される情報の種類は変更されない予定です。ただし、この情報の正確な形式は、リリースごとに若干変更される場合があります。
実行時リンカーをよく理解していないと、デバッギング出力のなかには理解できないものがある可能性があります。しかし、多くのものが一般的な関心を惹くものでしょう。
デバッグを有効にするには、環境変数 LD_DEBUG を使用します。デバッグのすべての出力の前に、処理識別子が追加されます。この環境変数は、1 つまたは複数のトークンを使用して、必要なデバッギングタイプを示す必要があります。
LD_DEBUG で使用可能なトークンを表示するには、LD_DEBUG=help を使用します。
$ LD_DEBUG=help prog
prog は任意の動的実行可能ファイルです。制御が prog に移る前に、このプロセスはヘルプ情報を表示して終了します。実行可能ファイルの選択は重要ではありません。
デフォルトでは、すべてのデバッグ出力が標準エラー出力ファイルである stderr に送られます。output トークンを使用すると、ファイルにデバッグを出力できます。たとえば、名前が rtld-debug.txt のファイルにヘルプテキストを取り込むことができます。
$ LD_DEBUG=help,output=rtld-debug.txt prog
また、デバッグ出力は環境変数 LD_DEBUG_OUTPUT を設定することによってリダイレクトできます。LD_DEBUG_OUTPUT が使用された場合、処理識別子が接尾辞として出力ファイル名に追加されます。
LD_DEBUG_OUTPUT と output のトークンが両方指定された場合、LD_DEBUG_OUTPUT が優先されます。LD_DEBUG_OUTPUT と output のトークンが両方指定された場合、LD_DEBUG_OUTPUT が優先されます。fork(2) を呼び出すプログラムで output トークンを使用すると、それぞれのプロセスで同じファイルにデバッグ出力を書き込むことになります。デバッグ出力は順序に規則性がなく、不完全なものになります。このような場合には、LD_DEBUG_OUTPUT を使用して、個別のファイルに各プロセスのデバッグ出力を指定してください。
セキュアなアプリケーションのデバッギングは実行できません。
実行時に発生するシンボル結合の表示機能は、もっとも有効なデバッギングオプションの 1 つです。次の例では、2 つのローカル共有オブジェクト上に依存関係を持つ、非常に単純な動的実行可能プログラムを取り上げてみます。
$ cat bar.c int bar = 10; $ cc -o bar.so.1 -K pic -G bar.c $ cat foo.c int foo(int data) { return (data); } $ cc -o foo.so.1 -K pic -G foo.c $ cat main.c extern int foo(); extern int bar; int main() { return (foo(bar)); } $ cc -o prog main.c -R/tmp:. foo.so.1 bar.so.1
実行時シンボル結合は、LD_DEBUG=bindings を設定することによって表示されます。
$ LD_DEBUG=bindings prog 11753: .... 11753: binding file=prog to file=./bar.so.1: symbol bar 11753: .... 11753: transferring control: prog 11753: .... 11753: binding file=prog to file=./foo.so.1: symbol foo 11753: ....
即時再配置で必要とされるシンボル bar は、アプリケーションが制御を取得する前に結合されます。これに対して、遅延再配置で要求されたシンボル foo は、アプリケーションが制御を受け取った後、関数が最初に呼び出されたときに結合されます。この再配置は、遅延結合のデフォルトモードを示しています。環境変数 LD_BIND_NOW が設定されている場合、シンボル結合はすべて、アプリケーションが制御を受け取る前に実行されます。
LD_DEBUG=bindings,detail と設定すると、実際の結合位置の実アドレスと相対アドレスに関する追加情報が表示されます。
LD_DEBUG を使用すれば、検索パスの使用状況を表示できます。たとえば、依存関係の配置に使用される検索パスのメカニズムは、次のように LD_DEBUG=libs を設定して表示できます。
$ LD_DEBUG=libs prog 11775: 11775: find object=foo.so.1; searching 11775: search path=/tmp:. (RUNPATH/RPATH from file prog) 11775: trying path=/tmp/foo.so.1 11775: trying path=./foo.so.1 11775: 11775: find object=bar.so.1; searching 11775: search path=/tmp:. (RUNPATH/RPATH from file prog) 11775: trying path=/tmp/bar.so.1 11775: trying path=./bar.so.1 11775: ....
アプリケーション prog 内に記録された実行パスは、2 つの依存関係 foo.so.1 と bar.so.1 の検索に影響を与えます。
これと同様の方法で、各シンボルを検索する検索パスは、LD_DEBUG=symbols を設定して表示できます。symbols と bindings を組み合わせれば、シンボル再配置処理の全容を把握できます。
$ LD_DEBUG=bindings,symbols prog 11782: .... 11782: symbol=bar; lookup in file=./foo.so.1 [ ELF ] 11782: symbol=bar; lookup in file=./bar.so.1 [ ELF ] 11782: binding file=prog to file=./bar.so.1: symbol bar 11782: .... 11782: transferring control: prog 11782: .... 11782: symbol=foo; lookup in file=prog [ ELF ] 11782: symbol=foo; lookup in file=./foo.so.1 [ ELF ] 11782: binding file=prog to file=./foo.so.1: symbol foo 11782: ....
上記の例では、シンボル bar は、アプリケーション prog 内では検索されません。このようにデータ参照検索が省略される原因は、コピーの再配置時に使用される最適化にあります。この再配置タイプの詳細については、コピー再配置を参照してください。