Oracle® Solaris 11.2 リンカーとライブラリガイド

印刷ビューの終了

更新: 2014 年 7 月
 
 

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

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

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

ディスプレイスメント再配置の問題を検知するために、次の 2 つの領域で検証が試みられます。

  • 最初は、共有オブジェクトの生成時に行われます。コピー再配置可能なデータ項目がディスプレイスメント再配置を伴うと問題が発生する可能性がある場合は、それらに対しフラグが立てられます。リンカーが共有オブジェクトを構築する際には、データ項目に対しどのような外部参照がされるかは不明です。したがって、フラグが立てられたデータ項目は、エラーを引き起こす可能性があります

  • 次の検証は、実行可能ファイルの生成時に行われます。コピー再配置のデータがディスプレイスメント再配置を伴う場合は、コピー再配置の作成に対しフラグが立てられます。

    しかし、リンク編集で共有オブジェクトを作成するときに、共有オブジェクトに適用されたディスプレイスメント再配置が完了することがあります。これらのディスプレイスメント再配置には、フラグが立てられていない可能性があります。フラグの立てられていない共有オブジェクトを参照する実行可能ファイルのリンク編集では、コピー再配置のデータで有効になっているディスプレイスメントは不明となります。

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

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

$ cc -G -o libfoo.so.1 -z verbose -K pic 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

注 -  ldd(1)–d–r のいずれかのオプションを指定すると、ディスプレイスメント動的フラグによって同じような再配置警告が生成されます。

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