リンカーとライブラリ

位置に依存しないコード

コンパイラは、-K pic オプションによって、位置に依存しないコードを生成します。動的実行可能ファイル内のコードは、通常、メモリー内の固定アドレスに結合されていますが、位置に依存しないコードは、プロセスのアドレス空間内にある任意の場所に読み込みできます。このコードは、特定のアドレスに結合されていないため、それを使用する各プロセスの異なるアドレスでページ変更を行わなくても、正しく実行されます。このコードを使用してプログラムを作成すれば、実行時のページ変更が最も少なくて済みます。

位置に依存しないコードを使用すると、再配置可能な参照は、共有オブジェクトのデータセグメント内のデータを使用する間接参照として生成されます。テキストセグメントコードは読み取り専用のままになり、すべての再配置更新がデータセグメント内の対応するエントリに適用されます。これらの 2 つのセクションの使用方法については、大域オフセットテーブル (プロセッサ固有)プロシージャのリンクテーブル (プロセッサ固有)を参照してください。

共有オブジェクトが位置に依存しないコードから構築される場合、テキストセグメントでは通常、実行時に大量の再配置を実行する必要があります。この再配置を処理するために実行時リンカーが用意されていますが、この処理によるシステムオーバーヘッドによって深刻な性能低下が生じるおそれがあります。

共有オブジェクトのうち、テキストセグメントに対して再配置を必要とするものを識別することができます。dump(1) を使用して、TEXTREL エントリの出力を調べます。次に例を示します。


$ cc -o libfoo.so.1 -G -R. foo.c
$ dump -Lv libfoo.so.1 | grep TEXTREL
[9]     TEXTREL  0

注 –

TEXTREL エントリの値は不適切です。共有オブジェクトにこの値が存在する場合は、テキスト再配置があることを示しています。


テキスト再配置を含む共有オブジェクトの作成を防止するには、リンカーの-z text フラグを使用します。このフラグを使用すると、リンカーは、入力として使用された、位置に依存しないコード以外のコードのソースを示す診断を生成します。このようなコードは、意図した共有オブジェクトの生成に失敗します。次に例を示します。


$ cc -o libfoo.so.1 -z text -G -R. foo.c
Text relocation remains                       referenced
    against symbol                  offset      in file
foo                                 0x0         foo.o
bar                                 0x8         foo.o
ld: fatal: relocations remain against allocatable but \
non-writable sections

ファイル foo.o から位置に依存しないコード以外のコードが生成されたために、テキストセグメントに対して 2 つの再配置が生成されています。これらの診断は、可能な場合、再配置の実行に必要なシンボリック参照すべてを示します。この場合、再配置はシンボル foobar に対するものです。

共有オブジェクトの生成時にテキスト再配置が作成されるもう 1 つの一般的な原因は、位置に依存しない適切なプロトタイプによって符号化されていない手書きアセンブラコードを含めているというものです。


注 –

いくつかの単純なソースファイルをテストしながら、位置に依存しないコードを決定することもできます。中間アセンブラ出力を生成するコンパイラ機能を使用してください。


SPARC: -K pic-K PIC オプション

SPARC バイナリでは、-K pic オプションと -K PIC オプションの動作がわずかに違っており、大域オフセットテーブルエントリの参照方法が異なります。詳細は、大域オフセットテーブル (プロセッサ固有)を参照してください。

大域オフセットテーブルはポインタの配列で、エントリのサイズは、32 ビット (4 バイト) および 64 ビット (8 バイト) に固定です。-K pic を使用して生成される次のコード例は、エントリを参照します。


        ld    [%l7 + j], %o0    ! load &j into %o0

%l7 には、あらかじめ計算された参照元オブジェクトのシンボル _GLOBAL_OFFSET_TABLE_ の値が代入されます。

このコード例は、大域オフセットテーブルのエントリ用に 13 ビットの変位定数を提供します。つまり、この変位は、32 ビットのオブジェクトの場合は 2048 個の一意のエントリを提供し、64 ビットのオブジェクトの場合は 1024 個の一意のエントリを提供します。返されるエントリ数より多くのエントリを要求するオブジェクトの場合、リンカーは致命的なエラーを生成します。


$ cc -K pic -G -o lobfoo.so.1 a.o b.o ... z.o
ld: fatal: too many symbols require `small' PIC references:
        have 2050, maximum 2048 -- recompile some modules -K PIC.

このエラー状態を解決するには、入力再配置可能オブジェクトの一部をコンパイルするときに、-K PIC オプションを指定します。 このオプションは、32 ビットの定数を大域オフセットテーブルエントリに使用します。


        sethi %hi(j), %g1
        or    %g1, %lo(j), %g1    ! get 32-bit constant GOT offset
        ld    [%l7 + %g1], %o0    ! load &j into %o0

elfdump(1)-G オプションと共に使用すれば、オブジェクトの大域オフセットテーブルの要件を調べることができます。リンカーのデバッグトークン -D got,detail を使用すれば、リンク編集中のこれらのエントリの処理を確認することもできます。

頻繁にアクセスするデータ項目に対しては、-K pic を使用する方法が有利です。どちらの方法でもエントリを参照することはできます。しかし、再配置可能オブジェクトをどちらの方法でコンパイルしたらいいのか決めるのには時間がかかる上、性能はわずかしか改善されません。すべての再配置型オブジェクトを -K PIC オプションを指定して再コンパイルする方が一般には簡単です。