リンカーとライブラリ

再配置処理

出力ファイルを作成すると、入力ファイルからのすべてのデータセクションは新しいイメージにコピーされます。入力ファイル内に指定された再配置は、出力イメージに適用されます。生成する必要がある追加の再配置情報も、新しいイメージに書き込まれます。

再配置処理には、通常、大きな問題はありません。ただし、特定のエラーメッセージを伴うエラー状態が発生することがあります。ここでは、2 つの状態について説明しておく必要があります。1 つは、位置に依存するコード (「位置に依存しないコード」を参照) によって発生するテキスト再配置で、もう 1 つはディスプレイスメント再配置に関連して発生します。ディスプレイスメント再配置については、次の項で詳しく説明します。

ディスプレイスメント再配置

データ項目 (それ自体はコピー再配置で使用可能) にディスプレイスメント再配置が適用されていると、エラー状態が発生することがあります。コピー再配置の詳細については、「コピー再配置」を参照してください。

ディスプレイスメント再配置は、再配置されるオフセットと再配置される先のターゲットが両方とも同じ位置だけ離れている限り有効です。コピー再配置とは、共有オブジェクト内の大域データ項目を実行可能ファイルの .bss にコピーし、実行可能ファイルの読み取り専用テキストセグメントを同じ状態に保つことをいいます。コピーされるデータにディスプレイスメント再配置が適用されていたり、外部再配置がコピーされるデータへのディスプレイスメントであったりすると、ディスプレイスメント再配置は無効になります。

このようなエラーを検知するために、次の点に注意してください。

前者の項目に関する問題は、大域データに対してディスプレイスメント再配置を使用する共有オブジェクトはすでに多数あるため、このデータがコピー再配置される可能性があるという点です。リンカーが共有オブジェクトを構築する際には、共有オブジェクトに対し実行時にどのような参照がされるかは明らかではありません。したがって、フラグが立ったデータ項目は、エラーを引き起こす可能性があります。

後者の項目に関する問題は、共有オブジェクトに適用されるディスプレイスメント再配置が、リンク編集で共有オブジェクトを作成する時点で完了することがあるという点です。したがって、この共有オブジェクトを参照するアプリケーションのリンク編集では、コピー再配置されたデータでどのようなディスプレイスメントが有効になるのかはわかりません。

このような問題の診断を助けるため、リンカーは、動的オブジェクトに対してディスプレイスメント再配置が使用されていると、1 つまたは複数の動的 DT_FLAGS_1 フラグを立てます (表 7-45 を参照)。さらに、その可能性のある再配置をリンカーの -z verbose オプションを使って表示することもできます。

たとえば、大域データ項目 bar[] を持つ共有オブジェクトを作成し、このデータ項目にディスプレイスメント再配置が適用されているとします。この項目は、動的実行可能ファイルから参照されると、コピー再配置される可能性があります。リンカーは、この状態に対し次の警告を出します。


$ cc -G -o libfoo.so.1 -z verbose -Kpic foo.o
ld: warning: relocation warning: R_SPARC_DISP32: file foo.o: symbol foo: ¥
    displacement relocation to be applied to the symbol bar: at 0x194: ¥
    displacement relocation will be visible in output image

次にデータ項目 bar[] を参照するアプリケーションを作成すると、コピー再配置が行われ、ディスプレイスメント再配置が無効にされる可能性があります。リンカーはこの状況を明示的に検出できるため、-z verbose オプションが使用されていなくても、次のエラーメッセージを生成します。


$ cc -o prog prog.o -L. -lfoo
ld: warning: relocation error: R_SPARC_DISP32: file foo.so: symbol foo: ¥
    displacement relocation applied to the symbol bar at: 0x194: ¥
    the symbol bar is a copy relocated symbol

このようなエラー状態は、再配置するシンボル定義 (オフセット) と再配置のシンボルターゲットを両方ともローカルに置くことによって避けることができます。それには、静的な定義を使用するか、リンカーの範囲指定を使用します (「シンボル範囲の縮小」を参照)。共有オブジェクト内のデータにアクセスするには、機能インタフェースの使用が最も適しています。


注 -

リンカーの -d-r オプションとともに ldd(1) を使用すると、ディスプレイスメント動的フラグによって同じような再配置警告が生成されます。