リンカーとライブラリ

動的依存関係のレイジーローディング

動的依存関係を読み込むデフォルトのメソッドは、動的依存関係をまずメモリーに対応付けして、依存関係があるかどうか調べ、もし依存関係がある場合には、これらをすぐに読み込むという方法です。これらの依存関係は、次に検査が行われ、さらに追加オブジェクトの読み込みは、ツリー全体を使い果たすまで、つまりすべての内部オブジェクトが解析されるまで、継続されます。ここでの問題点は、オブジェクト内のコードが実際に現在実行中のプログラムによって参照されるかどうかに関係なく、これらのオブジェクトはすべて、メモリー内に読み込まれることです。

動的依存関係のレイジーローディングでは、代わりに初期のオブジェクトをメモリーに対応付けしてから、レイジーローディングのラベルが付いていないこれらの依存関係を読み込みます。レイジーローディングのラベルが付いたオブジェクトは、明示的に参照 (すなわち、再配置) が行われるまで読み込まれません。手続き呼び出し結合は、最初に手続きリンクテーブルを通じて呼び出されるまで手続きが延期されることを利用して、オブジェクトのメモリーへの読み込みを、オブジェクトが参照されるまで延期することができます。また、参照されないオブジェクトは、メモリーに読み込まれません。

この例としては、liblddbg.so.4 というデバッギングライブラリを持つリンカーがありますが、デバッギング出力は、ld によって使用されることはほとんどないため、リンカーが呼び出されるたびにこれが読み込まれると、経費がかさみます。ここで、デバッギングライブラリへの最初の参照が実行されるまで、このライブラリの読み込みを遅らせることによって、デバッギングライブラリを使用する呼び出しの場合にだけ、読み込みを延期することができます。これを実行するための代替メソッドは、必要に応じて、ライブラリに対して dlopen()/dlsym() を実行することです。これは、このライブラリが単純なインタフェースを伴う小さなライブラリである場合、または、リンク編集時にその名前とロケーションがわからない場合に最適です。ただし、この名前とロケーションが分かっている場合には、レイジー読み込みを実行するよりも、問題のライブラリを指定する方がずっと簡単であるため、このライブラリが読み込まれるのは、参照が行われた場合だけです。

レイジー読み込みが実行されるようにオブジェクトに指定するには、リンカーオプション -z lazyload-z nolazyload を使用して行います。これらのオプションは、リンク編集行の位置によって決まります。ここでは、レイジー読み込みが実行される libdebug.so.1 というライブラリに依存する関係を伴うプログラムを単純にコンパイルしています。また、ここでは、libdebug.so.1 とマークが付けられレイジー読み込みされる動的セクションと、そのシンボルによって libdebug.so.1 が読み込まれるように記録された Syminfo セクションを示しています。


$ cc -o prog prog.c -L. -zlazyload -ldebug -znolazyload -R'$ORIGIN'
 
$ elfdump -d prog
 
Dynamic Section:  .dynamic
     index  tag           value
       [1]  POSFLAG_1     0x1           [ LAZY ]
       [2]  NEEDED        0x123         libdebug.so.1
       [3]  NEEDED        0x131         libc.so.1
       [6]  RPATH         0x13b         $ORIGIN
...
$ elfdump -y prog
 
Syminfo section: .SUNW_syminfo
     index flgs boundto                symbol
			...
      [52] DL       [1] libdebug.so.1   debug

値に LAZY が指定された POSFLAG_1 によって、libdebug.so.1 をレイジー読み込む一方、libc.so.1prog の初期始動時に読み込むように指定していることに注意してください。

環境変数 LD_FLAGS により nolazyload、または nodirect を設定すると、レイジー、又はこれらの機能を要求する依存関係のダイレクト結合が実行できなくなります。