リンカーとライブラリ

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

動的依存関係を読み込むデフォルトのモデルは、動的依存関係をメモリーに対応付けして、追加の依存関係があるかどうか調べます。もし依存関係がある場合には、これらは順番に、すぐに読み込まれます。このサイクルは、依存関係のツリー全体を使い果たすまで、つまりすべての内部オブジェクトの参照 (再配置) を解決するまで続けられます。

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

レイジーローディングモデルでは、レイジーローディングのラベルが付いた依存関係は、明示的に参照が行われるまで読み込まれません。関数呼び出しレイジー結合 (「プロシージャのリンクテーブル (プロセッサ固有)」を参照) を利用して、依存関係の読み込みを最初に参照されるまで延期することができます。実際に参照されないオブジェクトは読み込まれません。


注 -

オブジェクトへの参照は、データ項目または関数に対して行うことができます (「再配置が実行されるとき」を参照)。データへの参照はオブジェクトが初期設定された時に解決される必要があるため、1 つのデータへの参照を満たすすべての依存関係はすぐにロードされなければなりません。そのため、そういった依存関係をレイジーロード可能として示すことは、あまり効果がありません。動的オブジェクト間のデータへの参照は、概してあまり推奨されません。


レイジーローディングの例として、liblddbg.so.4 というデバッギングライブラリを参照するリンカーそのものがあります。デバッギングを呼び出すことはまれなので、リンカーを呼び出すたびにこのライブラリを読み込むことは不要で、コストがかさみます。このライブラリをレイジー読み込みできるように指定することにより、その処理コストをデバッギング出力を必要とする読み込みに使うことができます。

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

レイジー読み込みあるいは通常の読み込みが実行されるようにオブジェクトに指定するにはそれぞれ、リンカーオプション -z lazyload-z nolazyload を使用します。これらのオプションはリンク編集コマンド行の位置によって決まり、フラグを持つ依存関係が見つかると、そのフラグで指定された読み込み属性が採用されます。

ここでは、libdebug.so.1 に依存する単純なプログラムをレイジー読み込みにする例を示します。動的セクション (.dynamic) を検査すると libdebug.so.1 にレイジー読み込みのマークが付けられていることが示され、シンボル情報セクション (.SUNW_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 は、次の NEEDED エントリ libdebug.so.1 がレイジー読み込みされるように指定することに注意してください。ただし、libc.so.1 は前に LAZY フラグが無いので、prog の初期始動時に読み込まれます。


注 -

実行時にレイジーローディングを無効にするには、環境変数 LD_NOLAZYLOAD をヌル以外の値に設定します。