リンカーとライブラリ

動的依存関係の遅延読み込み

メモリーに動的オブジェクトが読み込まれる際、その動的オブジェクトに追加の依存関係がないか検査されます。デフォルトでは、依存関係があるとそれらがただちに読み込まれます。このサイクルは、依存関係のツリー全体を使い果たすまで続けられます。この時点で、再配置によって指定された内部オブジェクトの参照が、すべて解決します。

このデフォルトモデルでは、アプリケーションの依存関係がすべてメモリー内に読み込まれ、すべてのデータの再配置が実行されます。この処理は、これらの依存関係内のコードが実行中にアプリケーションによって実際に参照されるかどうかに関係なく、行われます。

遅延読み込みモデルでは、遅延読み込みのラベルが付いた依存関係は、明示的に参照が行われるまで読み込まれません。関数呼び出し遅延結合を利用して、依存関係の読み込みを最初に参照されるまで延期することができます。実際に参照されないオブジェクトは読み込まれません。

再配置参照は、即時か遅延です。即時参照はオブジェクトが初期化された時に解決される必要があるため、この参照を満たすすべての依存関係はすぐに読み込まれる必要があります。そのため、そういった依存関係を遅延読み込み可能として示すことは、あまり効果がありません。再配置が実行されるとき を参照してください。 動的オブジェクト間の即時参照は、概してあまり推奨されません。

遅延読み込みは、liblddbg というデバッギングライブラリを参照するリンカー自体によっても使用されます。デバッギングを呼び出すことはまれなので、リンカーを呼び出すたびにこのライブラリを読み込むことは不要で、コストがかさみます。このライブラリを遅延読み込みできるように指定することにより、その処理コストをデバッギング出力を必要とする読み込みに使うことができます。

遅延読み込みモデルを実行するための代替メソッドは、必要に応じて依存関係に dlopen() または dlsym() を実行することです。これは、dlsym() 参照の数が少ない場合、あるいはリンク編集時に依存関係の名前あるいはロケーションがわからない場合に最適です。名前やロケーションがわかっている依存関係のより複雑な相互作用については、通常のシンボル参照のコードを使用し、依存関係を遅延読み込みに指定する方が簡単です。

遅延読み込みあるいは通常の読み込みが実行されるようにオブジェクトに指定するには、それぞれリンカーオプション-z lazyload-z nolazyload を使用します。これらのオプションは、リンク編集コマンド行の位置によって決まります。オプションに指定した依存関係には、オプションに指定されている読み込み属性が適用されます。デフォルトでは、-z nolazyload オプションが有効です。

次の単純なプログラムでは、libdebug.so.1 に対する依存関係が指定されています。 動的セクション (.dynamic) では、libdebug.so.1 に対して遅延読み込みが指定されています。シンボル情報セクション(.SUNW_syminfo)では、libdebug.so.1 の読み込みをトリガーするシンボル参照が指定されています。


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

値に LAZY が指定された POSFLAG_1 は、次の NEEDED エントリ libdebug.so.1 が遅延読み込みされることを示しています。libc.so.1 は前に LAZY フラグがないので、プログラムの初期始動時に読み込まれます。

遅延読み込みを使用するには、アプリケーションで使用されるオブジェクト全体に渡り依存関係と実行時パスを正確に宣言しなければならない場合があります。たとえば、libX.so 内のシンボルを参照する 2 つのオブジェクト libA.solibB.so があるとします。libA.solibX.so に対する依存性を宣言していますが、libB.so はこの宣言をしていません。通常、libA.solibB.so が併用される場合、libB.solibX.so を参照できます。これは、 libA.so によってこの利用が可能になっているためです。しかし、libX.so が遅延読み込みされるように libA.so で宣言した場合には、libB.so が参照する時には libX.so を読み込めない可能性があります。libB.solibX.so を依存関係として宣言していても、その位置同定に必要な実行時パスを指定しなかった場合には、同様のエラーが発生する可能性があります。

遅延読み込みをするかしないかにかかわらず、動的オブジェクトではすべての依存関係とその位置同定方法を宣言することをお勧めします。遅延読み込みでは、この依存情報がより重要な意味合いを持ちます。


注 –

実行時に遅延読み込みを無効にするには、環境変数 LD_NOLAZYLOAD をヌル以外の値に設定します。