このセクションは、オブジェクトファイル情報と、プログラムの実行イメージを作成するシステム動作を記述します。ここで説明する情報の大半は、すべてのシステムに適用されます。プロセッサに固有の情報はその旨が示されたセクションに存在します。
実行可能オブジェクトファイルと共有オブジェクトファイルは、アプリケーションプログラムを静的に表現します。このようなプログラムを実行するためには、システムはこれらのファイルを使用して動的なプログラムの表現、すなわちプロセスイメージを作成します。プロセスイメージには、テキスト、データ、スタックなどがあるセグメントが存在します。この項の主な細目は以下のとおりです。
プログラムヘッダーでは、プログラム実行に直接関係するオブジェクトファイルの構造を記述する。重要なデータ構造体であるプログラムヘッダーテーブルは、ファイル内のセグメントイメージの位置を示す。また、このプログラムヘッダーテーブルは、プログラムのメモリーイメージの作成に必要な他の情報が存在する
プログラムの読み込み (プロセッサ固有)では、メモリーにプログラムを読み込むために使用する情報を記述する
実行時リンカーでは、プロセスイメージのオブジェクトファイル間でシンボル参照を指定、解決するために使用する情報を記述する
実行可能オブジェクトファイルまたは共有オブジェクトファイルのプログラムヘッダーテーブルは、構造体の配列です (各構造体は、実行されるプログラムを準備するためにシステムが必要とするセグメントなどの情報を記述する) 。各オブジェクトファイルセグメントには、セグメントの内容で説明しているように、1 つ以上のセクションが存在します。
プログラムヘッダーは、実行可能オブジェクトファイルと共有オブジェクトファイルに対してのみ意味があります。プログラムヘッダーサイズは、ELF ヘッダーの e_phentsize 構成要素と e_phnum 構成要素で指定されます。
プログラムヘッダーの構造体 (sys/elf.h で定義) は、次のとおりです。
typedef struct { Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_Word p_flags; Elf32_Word p_align; } Elf32_Phdr; typedef struct { Elf64_Word p_type; Elf64_Word p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Addr p_paddr; Elf64_Xword p_filesz; Elf64_Xword p_memsz; Elf64_Xword p_align; } Elf64_Phdr;
この構造体の要素を次に示します。
この配列要素が記述するセグメント型、または配列要素情報の解釈方法。型の値とその意味は、表 7–35 を参照してください。
ファイルの先頭から、セグメントの先頭バイトが存在する位置までのオフセット。
セグメントの物理アドレス (物理アドレス指定が適切なシステムの場合)。本システムはアプリケーションプログラムに対して物理アドレス指定を無視するので、この構成要素には実行可能ファイルと共有オブジェクトに対する指定されていない内容が存在します。
セグメントのファイルイメージのバイト数 (0 の場合もある)。
セグメントのメモリーイメージのバイト数 (0 の場合もある)。
セグメントに関係するフラグ。型の値とその意味については、表 7–36 を参照してください。
読み込み可能なプロセスセグメントは、ページサイズを基にして、p_vaddr と p_offset に対して同じ値を保持する必要があります。この構成要素は、セグメントがメモリーとファイルにおいて整列される値を与えます。値 0 と 1 は、整列が必要ないことを意味します。その他の値の場合、p_align は 2 の正整数累乗でなければならず、また p_vaddr は p_align を法として p_offset に等しくなければなりません。詳細は、プログラムの読み込み (プロセッサ固有)を参照してください。
エントリの中には、プロセスセグメントを記述するものもあります。それ以外のエントリは補足情報を与え、プロセスイメージには関与しません。セグメントエントリが現れる順序は、明示されている場合を除き任意です。定義されている型の値を、次の表に示します。
表 7–35 ELF セグメント型
名前 |
値 |
---|---|
PT_NULL |
0 |
PT_LOAD |
1 |
PT_DYNAMIC |
2 |
PT_INTERP |
3 |
PT_NOTE |
4 |
PT_SHLIB |
5 |
PT_PHDR |
6 |
PT_TLS |
7 |
PT_LOSUNW |
0x6ffffffa |
PT_SUNWBSS |
0x6ffffffa |
PT_SUNWSTACK |
0x6ffffffb |
PT_HISUNW |
0x6fffffff |
PT_LOPROC |
0x70000000 |
PT_HIPROC |
0x7fffffff |
使用しません。他の構成要素の値は不定です。この型を使用すると、プログラムヘッダーテーブルに、無視されるエントリを入れることができます。
p_filesz と p_memsz により記述される読み込み可能セグメントを指定します。ファイルのバイト列は、メモリーセグメントの先頭に対応付けられます。セグメントのメモリーサイズ (p_memsz) がファイルサイズ (p_filesz) より大きい場合、不足するバイトは、値 0 を保持しセグメントの初期化領域に続くように定義されます。ファイルサイズがメモリーサイズより大きくなることは許可されません。プログラムヘッダーテーブルの読み込み可能セグメントエントリは、p_vaddr 構成要素で整列され、昇順に現れます。
動的リンクに関する情報を指定します。詳細は、動的セクションを参照してください。
インタプリタとして呼び出される、ヌル文字で終了しているパス名の位置とサイズを指定します。動的実行可能ファイルの場合、このセグメント型は必須であり、共有オブジェクトの場合、このセグメント型は指定可能です。このセグメント型を、ファイル内に複数指定することはできません。このセグメント型が存在する場合、このセグメント型は読み込み可能セグメントエントリの前に存在しなければなりません。詳細は、プログラムインタプリタを参照してください。
補助情報の位置とサイズを指定します。詳細は、注釈セクションを参照してください。
このセグメント型は、予約済みですが、解釈の方法は定義されていません。
プログラムヘッダーテーブル自身の、ファイル、およびプログラムのメモリーイメージにおける位置とサイズを指定します。このセグメント型を、ファイル内に複数指定することはできません。また、このセグメント型は、プログラムヘッダーテーブルがプログラムのメモリーイメージの一部になる場合に限り存在できます。このセグメント型が存在する場合、このセグメント型は読み込み可能セグメントエントリの前に存在しなければなりません。詳細は、プログラムインタプリタを参照してください。
スレッド固有領域のテンプレートを指定します。詳細は、スレッド固有領域 (TLS) セクションを参照してください。
PT_LOAD 要素と同じ属性で、.SUNW_bss セクションの記述に使用します。
プロセススタックを記述します。現在のところ、そういった要素は 1 つのみ存在し、p_flags フィールドで定義されているアクセスパーミッションのみが有用です。
他の箇所で特に要求されない限り、すべてのプログラムヘッダーセグメントタイプはそれぞれ存在することもありますし、存在しないこともあります。ファイルのプログラムヘッダーテーブルには、このプログラムの内容に関係する要素のみが存在できます。
実行可能オブジェクトファイルと共有オブジェクトファイルには、ベースアドレス (プログラムのオブジェクトファイルのメモリーイメージに関連付けられている最下位仮想アドレス) が存在します。ベースアドレスは、たとえば動的リンク時にプログラムのメモリーイメージを再配置するために使用されます。
実行可能オブジェクトファイルと共有オブジェクトファイルのベースアドレスは、実行時に 3 つの値 (プログラムの読み込み可能セグメントのメモリー読み込みアドレス、最大ページサイズ、最下位仮想アドレス) から計算されます。プログラムヘッダーの仮想アドレスは、プログラムのメモリーイメージの実際の仮想アドレスを表さないことがあります。詳細は、プログラムの読み込み (プロセッサ固有)を参照してください。
ベースアドレスを計算するには、PT_LOAD セグメントの最下位 p_vaddr 値に関連付けられているメモリーアドレスを判定します。次に、メモリーアドレスを最大ページサイズの最近倍数に切り捨てることで、ベースアドレスが求められます。メモリーに読み込まれるファイルの種類によって、メモリーアドレスは p_vaddr 値に一致しない場合もあります
システムで読み込まれるプログラムには、少なくとも 1 つの読み込み可能セグメントが存在しなければなりません (ただし、このことはファイル形式では要求されていません)。システムは、読み込み可能セグメントのメモリーイメージを作成するとき、p_flags 構成要素で指定されるアクセス権を与えます。PF_MASKPROC マスクのすべてのビットは、プロセッサ固有のセマンティクスに対して予約されます。
表 7–36 ELF セグメントフラグ
名前 |
値 |
意味 |
---|---|---|
PF_X |
0x1 |
実行 |
PF_W |
0x2 |
書き込み |
PF_R |
0x4 |
読み取り |
PF_MASKPROC |
0xf0000000 |
指定なし |
アクセス権ビットが 0 の場合、その種類のアクセスは拒否されます。実際のメモリーアクセス権は、メモリー管理ユニット (システムによって異なることがある) に依存します。すべてのフラグ組み合わせが有効ですが、システムは要求以上のアクセスを与えることがあります。ただしどんな場合も、特に断りが明示的に記述されていない限り、セグメントは書き込み権を持ちません。次の表に、正確なフラグ解釈と許容されるフラグ解釈を示します。
表 7–37 ELF セグメントへのアクセス権
フラグ |
値 |
正確なフラグ解釈 |
許容されるフラグ解釈 |
---|---|---|---|
None |
0 |
すべてのアクセスが拒否される |
すべてのアクセスが拒否される |
PF_X |
1 |
実行のみ |
読み取り、実行 |
PF_W |
2 |
書き込みのみ |
読み取り、書き込み、実行 |
PF_W+PF_X |
3 |
書き込み、実行 |
読み取り、書き込み、実行 |
PF_R |
4 |
読み取りのみ |
読み取り、実行 |
PF_R + PF_X |
5 |
読み取り、実行 |
読み取り、実行 |
PF_R+PF_W |
6 |
読み取り、書き込み |
読み取り、書き込み、実行 |
PF_R + PF_W + PF_X |
7 |
読み取り、書き込み、実行 |
読み取り、書き込み、実行 |
たとえば、標準的なテキストセグメントは読み取り権と実行権を持っていますが、書き込み権は持っていません。データセグメントは通常、読み取り権、書き込み権、および実行権を持っています。
オブジェクトファイルセグメントは、1 つまたは複数のセクションで構成されます。ただし、プログラムヘッダーはこの事実には関与しません。ファイルセグメントに 1 つのセクションが存在するか複数のセクションが存在するかもまた、プログラム読み込み時に重要ではありません。しかし、さまざまなデータが、プログラム実行時や動的リンク時などには存在しなければなりません。以下に、セグメントの内容を示します。 セグメント内のセクションの順序と帰属関係は、異なることがあります。
テキストセグメントには、読み取り専用の命令/データが存在します。データセグメントには、書き込み可能のデータ/命令が存在します。すべての特殊セクションの一覧については、表 7–16を参照してください。
PT_DYNAMIC プログラムヘッダー要素は、.dynamic セクションを指し示します。さらに、.got セクションと .plt セクションには、位置に依存しないコードと動的リンクに関係する情報が存在します。
.plt は、テキストセグメントまたはデータセグメントに存在できます (どちらのセグメントに存在するかはプロセッサに依存します)。詳細は、大域オフセットテーブル (プロセッサ固有)と プロシージャのリンクテーブル (プロセッサ固有)を参照してください。
.bss セクションには、SHT_NOBITS 型が存在します。このセクションはファイル領域を占めませんが、セグメントのメモリーイメージに与えられます。通常、これらの初期化されていないデータはセグメントの終わりに存在し、その結果、関連付けられているプログラムヘッダー要素において p_memsz が p_filesz より大きくなります。
システムは、プロセスイメージを作成または拡張するとき、ファイルのセグメントを仮想メモリーセグメントに論理的にコピーします。システムがファイルをいつ物理的に読み取るかは、プログラムの挙動やシステムの負荷などに依存します。
プロセスは実行時に論理ページを参照しない限り物理ページを必要とせず、また一般に多くのページを未参照状態のままにします。したがって、物理読み取りを遅延させると、これらの物理読み取りが不要になり、システム性能が向上します。この効率性を実際に実現するには、実行可能オブジェクトファイルと共有オブジェクトファイルには、ファイルオフセットと仮想アドレスがページサイズを法として同じであるセグメントイメージが存在しなければなりません。
32 ビットのセグメントの仮想アドレスとファイルオフセットは、64K (0x10000) を法として同じです。64 ビットのセグメントの仮想アドレスとファイルオフセットは、1M バイト (0x100000) を法として同じです。 セグメントを最大ページサイズに整列すると、ファイルは物理ページサイズには関係なくページング処理に対して適切になります。
デフォルトでは 64 ビット SPARC プログラムは開始アドレス (0x100000000) にリンクされます。プログラム全体 (テキスト、データ、ヒープ、スタック、共有オブジェクトの依存関係を含む) は、4G バイトより上に存在します。そうすることにより、プログラムがポインタを切り捨てると、アドレス空間の最下位 4G バイトでフォルトが発生することになるので、64 ビットプログラムが正しく作られたことを確認することがより容易になります。64 ビットプログラムは4G バイトより上でリンクされていますが、コンパイラあるいはリンカーに mapfile および -M オプションを使用することにより、4G バイト未満でリンクすることも可能です。詳細は、/usr/lib/ld/sparcv9/map.below4G を参照してください。
次の図に、SPARC バージョンの実行可能ファイルを示します。
次の表に、前の図に示した読み込み可能セグメント要素の定義を示します。
表 7–38 SPARC: ELF プログラムヘッダーセグメント (64K に整列)
構成要素 |
テキスト |
データ |
---|---|---|
p_type |
PT_LOAD |
PT_LOAD |
p_offset |
0x0 |
0x4000 |
p_vaddr |
0x10000 |
0x24000 |
p_paddr |
指定なし |
指定なし |
p_filesize |
0x3a82 |
0x4f5 |
p_memsz |
0x3a82 |
0x10a4 |
p_flags |
PF_R + PF_X |
PF_R + PF_W + PF_X |
p_align |
0x10000 |
0x10000 |
次の図に、x86 バージョンの実行可能ファイルの例を示します。
次の表に、前の図に示した読み込み可能セグメント要素の定義を示します。
表 7–39 x86: ELF プログラムヘッダーセグメント (64K に整列)
構成要素 |
テキスト |
データ |
---|---|---|
p_type |
PT_LOAD |
PT_LOAD |
p_offset |
0x0 |
0x4000 |
p_vaddr |
0x8050000 |
0x8064000 |
p_paddr |
指定なし |
指定なし |
p_filesize |
0x32fd |
0x3a0 |
p_memsz |
0x32fd |
0xdc4 |
p_flags |
PF_R + PF_X |
PF_R + PF_W + PF_X |
p_align |
0x10000 |
0x10000 |
例に示したファイルオフセットと仮想アドレスは、テキストとデータの両方に対して最大ページサイズを法として同じですが、最大 4 ファイルページ (ページサイズとファイルシステムブロックサイズに依存) に、純粋ではないテキストやデータが含まれます。
先頭テキストページには、ELF ヘッダー、プログラムヘッダーテーブル、および他の情報が存在する
最終テキストページには、データの始まりのコピーが存在する
先頭データページには、テキストの終わりのコピーが存在する
最後のデータページには、実行中プロセスに関連していないファイル情報が存在できる。論理的にはシステムは、あたかも各セグメントが完全であり分離されているようにメモリーアクセス権を設定する。セグメントのアドレスは調整され、アドレス空間の各論理ページに同じアクセス権セットが確実に存在するようになる。上の例では、テキストの終わりとデータの始まりを保持しているファイル領域が 2 回対応付けされる (1 回はテキストに関して 1 つの仮想アドレスで対応付けされ、もう 1 回はデータに関して別の仮想アドレスで対応付けされる)
上記の例は、テキストセグメントを丸めた、典型的な Solaris のシステムバイナリを反映したものです。
データセグメントの終わりは、初期化されていないデータに対して特別な処理を必要とします (初期値が 0 になるようにシステムで定義されている)。ファイルの最後のデータページに、論理メモリーページに存在しない情報が存在する場合、これらのデータは 0 に設定しなければなりません (実行可能ファイルの未知の内容のままにしてはならない)。
他の 3 ページに存在する純粋でないテキストまたはデータは、論理的にはプロセスイメージの一部ではありません。システムがこれらの純粋でないテキストまたはデータを除去するかどうかについては、規定されていません。このプログラムのメモリーイメージが 4K バイト (0x1000) ページを使用する例を、次の図に示します。単純化するために次の図では、1 ページのサイズのみを示しています。
セグメント読み込みは、実行可能ファイルと共有オブジェクトでは異なる側面が 1 つ存在します。実行可能ファイルのセグメントには、標準的には絶対コードが存在します。プロセスを正しく実行するには、セグメントは実行可能ファイルを作成するために使用された仮想アドレスに存在しなければなりません。システムは変化しない p_vaddr 値を仮想アドレスとして使用します。
一方、通常は共有オブジェクトのセグメントには、位置に依存しないコードが存在します。したがって、セグメントの仮想アドレスは、実行動作を無効にすることなくプロセスごとに変化させることができます。
システムは個々のプロセスごとに仮想アドレスを選択しますが、セグメントの相対位置は維持します。位置に依存しないコードはセグメント間で相対アドレス指定を使用するので、メモリーの仮想アドレス間の差は、ファイルの仮想アドレス間の差に一致しなければなりません。
以下の表は、いくつかのプロセスに対する共有オブジェクト仮想アドレスの割り当ての例で、一定の相対位置になることを示しています。これらの表は、ベースアドレスの計算も示しています。
表 7–40 SPARC: ELF 共有オブジェクトセグメントアドレスの例
出所 |
テキスト |
データ |
ベースアドレス |
---|---|---|---|
ファイル |
0x0 |
0x4000 |
0x0 |
プロセス 1 |
0xc0000000 |
0xc0024000 |
0xc0000000 |
プロセス 2 |
0xc0010000 |
0xc0034000 |
0xc0010000 |
プロセス 3 |
0xd0020000 |
0xd0024000 |
0xd0020000 |
プロセス 4 |
0xd0030000 |
0xd0034000 |
0xd0030000 |
表 7–41 x86: ELF 共有オブジェクトセグメントアドレスの例
出所 |
テキスト |
データ |
ベースアドレス |
---|---|---|---|
ファイル |
0x0 |
0x4000 |
0x0 |
プロセス 1 |
0x8000000 |
0x8004000 |
0x80000000 |
プロセス 2 |
0x80081000 |
0x80085000 |
0x80081000 |
プロセス 3 |
0x900c0000 |
0x900c4000 |
0x900c0000 |
プロセス 4 |
0x900c6000 |
0x900ca000 |
0x900c6000 |
動的リンクを開始する動的実行可能ファイルまたは共有オブジェクトは、1 つの PT_INTERP プログラムヘッダー要素を保持できます。exec(2) の実行時に、システムは PT_INTERP セグメントからパス名を取り出し、インタプリタファイルのセグメントから初期プロセスイメージを作成します。インタプリタはシステムから制御を受け取り、アプリケーションプログラムに対して環境を提供する必要があります。
Solaris オペレーティング環境では、インタプリタは実行時リンカー、ld.so.1(1) として知られています。
リンカーは、動的リンクを開始する動的オブジェクトを作成する際、 PT_INTERP 型のプログラムヘッダー要素を実行可能ファイルに付加します。この要素は、実行時リンカーをプログラムインタプリタとして呼び出すようにシステムに指示します。exec(2) と実行時リンカーは、協調してプログラムのプロセスイメージを作成します。
リンカーはまた、実行時リンカーを支援する、実行可能ファイルと共有オブジェクトファイル用のさまざまなデータを作成します。これらのデータは読み込み可能セグメントに存在するため、実行時に使用可能です。これらのセグメントには、以下が含まれます。
SHT_DYNAMIC 型の .dynamic セクションには、さまざまなデータが存在する。このセクションの始まりに存在する構造体には、他の動的リンク情報のアドレスが存在する。
SHT_PROGBITS 型の .got セクションと .plt セクションには、2 つの別個のテーブルが存在する。つまり、大域オフセットテーブルとプロシージャのリンクテーブルが存在する。次の項では、オブジェクトファイルのメモリーイメージを作成するために実行時リンカーがテーブルをどのように使用するかを説明する
共有オブジェクトは、ファイルのプログラムヘッダーテーブルに記録されているアドレスとは異なる仮想メモリーアドレスを占有することが可能です。実行時リンカーは、アプリケーションが制御を取得する前に、メモリーイメージを再配置して絶対アドレスを更新します。
オブジェクトファイルが動的リンクに関係している場合、このオブジェクトファイルのプログラムヘッダーテーブルには、PT_DYNAMIC 型の要素が存在します。このセグメントには、.dynamic セクションが存在します。特殊なシンボル _DYNAMIC は、このセクションを示します。このセクションには、以下の構造体 (sys/link.h で定義される) の配列が存在します。
typedef struct { Elf32_Sword d_tag; union { Elf32_Word d_val; Elf32_Addr d_ptr; Elf32_Off d_off; } d_un; } Elf32_Dyn; typedef struct { Elf64_Xword d_tag; union { Elf64_Xword d_val; Elf64_Addr d_ptr; } d_un; } Elf64_Dyn;
このタイプの各オブジェクトの場合、d_tag は d_un の解釈に影響します。
このオブジェクトは、さまざまに解釈される整数値を表します。
このオブジェクトは、プログラムの仮想アドレスを表わします。ファイルの仮想アドレスは、実行時にメモリーの仮想アドレスに一致しないことがあります。実行時リンカーは、動的構造体に存在するアドレスを解釈するとき、元のファイル値とメモリーのベースアドレスに基づいて実際のアドレスを計算します。整合性のため、ファイルには動的構造体内のアドレスを補正するための再配置エントリは存在しません。
ツールによる動的セクションエントリの内容の解釈をシンプルにするために、各タグの値 (2 つの特別な互換性範囲を除く) で d_un union の解釈を決定します。 偶数の値を持つタグは、d_ptr を使用する動的セクションのエントリを示します。奇数の値を持つタグは、d_val を使用する動的セクションのエントリ、または d_ptr と d_val のどちらも使用しない動的セクションのエントリを示します。特殊値 DT_ENCODING より小さい値を持つタグ、および DT_HIOS と DT_LOPROC 間の範囲に入る値を持つタグは、これらの規則には従いません。
表 7–42 は、実行可能オブジェクトファイルと共有オブジェクトファイルのタグ要求についてまとめています。タグに「必須」という印が付いている場合、動的リンク配列にはその型のエントリが存在しなければなりません。また、「任意」は、タグのエントリが現れてもよいですが必須ではないことを意味します
表 7–42 ELF 動的配列タグ
名前 |
値 |
d_un |
実行可能ファイル |
共有オブジェクトファイル |
---|---|---|---|---|
DT_NULL |
0 |
無視される |
必須 |
必須 |
DT_NEEDED |
1 |
d_val |
任意 |
任意 |
DT_PLTRELSZ |
2 |
d_val |
任意 |
任意 |
DT_PLTGOT |
3 |
d_ptr |
任意 |
任意 |
DT_HASH |
4 |
d_ptr |
必須 |
必須 |
DT_STRTAB |
5 |
d_ptr |
必須 |
必須 |
DT_SYMTAB |
6 |
d_ptr |
必須 |
必須 |
DT_RELA |
7 |
d_ptr |
必須 |
任意 |
DT_RELASZ |
8 |
d_val |
必須 |
任意 |
DT_RELAENT |
9 |
d_val |
必須 |
任意 |
DT_STRSZ |
10 |
d_val |
必須 |
必須 |
DT_SYMENT |
11 |
d_val |
必須 |
必須 |
DT_INIT |
12 |
d_ptr |
任意 |
任意 |
DT_FINI |
13 |
d_ptr |
任意 |
任意 |
DT_SONAME |
14 |
d_val |
無視される |
任意 |
DT_RPATH |
15 |
d_val |
任意 |
任意 |
DT_SYMBOLIC |
16 |
無視される |
無視される |
任意 |
DT_REL |
17 |
d_ptr |
必須 |
任意 |
DT_RELSZ |
18 |
d_val |
必須 |
任意 |
DT_RELENT |
19 |
d_val |
必須 |
任意 |
DT_PLTREL |
20 |
d_val |
任意 |
任意 |
DT_DEBUG |
21 |
d_ptr |
任意 |
無視される |
DT_TEXTREL |
22 |
無視される |
任意 |
任意 |
DT_JMPREL |
23 |
d_ptr |
任意 |
任意 |
DT_BIND_NOW |
24 |
無視される |
任意 |
任意 |
DT_INIT_ARRAY |
25 |
d_ptr |
任意 |
任意 |
DT_FINI_ARRAY |
26 |
d_ptr |
任意 |
任意 |
DT_INIT_ARRAYSZ |
27 |
d_val |
任意 |
任意 |
DT_FINI_ARRAYSZ |
28 |
d_val |
任意 |
任意 |
DT_RUNPATH |
29 |
d_val |
任意 |
任意 |
DT_FLAGS |
30 |
d_val |
任意 |
任意 |
DT_ENCODING |
32 |
指定なし |
指定なし |
指定なし |
DT_PREINIT_ARRAY |
32 |
d_ptr |
任意 |
無視される |
DT_PREINIT_ARRAYSZ |
33 |
d_val |
任意 |
無視される |
DT_LOOS |
0x6000000d |
指定なし |
指定なし |
指定なし |
DT_SUNW_RTLDINF |
0x6000000e |
d_ptr |
任意 |
任意 |
DT_HIOS |
0x6ffff000 |
指定なし |
指定なし |
指定なし |
DT_VALRNGLO |
0x6ffffd00 |
指定なし |
指定なし |
指定なし |
DT_CHECKSUM |
0x6ffffdf8 |
d_val |
任意 |
任意 |
DT_PLTPADSZ |
0x6ffffdf9 |
d_val |
任意 |
任意 |
DT_MOVEENT |
0x6ffffdfa |
d_val |
任意 |
任意 |
DT_MOVESZ |
0x6ffffdfb |
d_val |
任意 |
任意 |
DT_FEATURE_1 |
0x6ffffdfc |
d_val |
任意 |
任意 |
DT_POSFLAG_1 |
0x6ffffdfd |
d_val |
任意 |
任意 |
DT_SYMINSZ |
0x6ffffdfe |
d_val |
任意 |
任意 |
DT_SYMINENT |
0x6ffffdff |
d_val |
任意 |
任意 |
DT_VALRNGHI |
0x6ffffdff |
指定なし |
指定なし |
指定なし |
DT_ADDRRNGLO |
0x6ffffe00 |
指定なし |
指定なし |
指定なし |
DT_CONFIG |
0x6ffffefa |
d_ptr |
任意 |
任意 |
DT_DEPAUDIT |
0x6ffffefb |
d_ptr |
任意 |
任意 |
DT_AUDIT |
0x6ffffefc |
d_ptr |
任意 |
任意 |
DT_PLTPAD |
0x6ffffefd |
d_ptr |
任意 |
任意 |
DT_MOVETAB |
0x6ffffefe |
d_ptr |
任意 |
任意 |
DT_SYMINFO |
0x6ffffeff |
d_ptr |
任意 |
任意 |
DT_ADDRRNGHI |
0x6ffffeff |
指定なし |
指定なし |
指定なし |
DT_RELACOUNT |
0x6ffffff9 |
d_val |
任意 |
任意 |
DT_RELCOUNT |
0x6ffffffa |
d_val |
任意 |
任意 |
DT_FLAGS_1 |
0x6ffffffb |
d_val |
任意 |
任意 |
DT_VERDEF |
0x6ffffffc |
d_ptr |
任意 |
任意 |
DT_VERDEFNUM |
0x6ffffffd |
d_val |
任意 |
任意 |
DT_VERNEED |
0x6ffffffe |
d_ptr |
任意 |
任意 |
DT_VERNEEDNUM |
0x6fffffff |
d_val |
任意 |
任意 |
DT_LOPROC |
0x70000000 |
指定なし |
指定なし |
指定なし |
DT_SPARC_REGISTER |
0x70000001 |
d_val |
任意 |
任意 |
DT_AUXILIARY |
0x7ffffffd |
d_val |
指定なし |
任意 |
DT_USED |
0x7ffffffe |
d_val |
任意 |
任意 |
DT_FILTER |
0x7fffffff |
d_val |
指定なし |
任意 |
DT_HIPROC |
0x7fffffff |
指定なし |
指定なし |
指定なし |
_DYNAMIC 配列の終わりを示します。
ヌル文字で終わっている文字列の DT_STRTAB 文字列テーブルオフセットであり、必要な依存性の名前を示します。動的配列には、この型の複数のエントリが存在できます。これらのエントリの相対順序は意味がありますが、他の型のエントリに対するこれらのエントリの相対順序には意味がありません。詳細は、共有オブジェクトの依存性を参照してください。
プロシージャのリンクテーブルに関連付けられている再配置エントリの合計サイズ (単位: バイト)。プロシージャのリンクテーブル (プロセッサ固有)を参照してください。
プロシージャのリンクテーブルまたは大域オフセットテーブルに関連付けられるアドレス。詳細は、プロシージャのリンクテーブル (プロセッサ固有) および 大域オフセットテーブル (プロセッサ固有)を参照してください。
シンボルハッシュテーブルのアドレス。このテーブルは、DT_SYMTAB 要素で示されるシンボルテーブルを参照します。詳細は、ハッシュテーブルセクションを参照してください。
文字列テーブルのアドレス。文字列テーブルには、実行時リンカーが必要とするシンボル名、依存性名、および他の文字列が存在します。詳細は、文字列テーブルセクションを参照してください。
シンボルテーブルのアドレス。詳細は、シンボルテーブルセクションを参照してください。
再配置テーブルのアドレス。詳細は、再配置セクションを参照してください。
オブジェクトファイルには、複数の再配置セクションを指定できます。リンカーは、実行可能オブジェクトファイルまたは共有オブジェクトファイルの再配置テーブルを作成するとき、これらのセクションを連結して単一のテーブルを作成します。これらの各セクションはオブジェクトファイル内で独立している場合がありますが、実行時リンカーは単一のテーブルとして扱います。実行時リンカーは、実行可能ファイルのプロセスイメージを作成したり、またはプロセスイメージに共有オブジェクトを付加したりするとき、再配置テーブルを読み取り、関連付けられている動作を実行します。
この要素が存在する場合、DT_RELASZ 要素と DT_RELAENT 要素も存在する必要があります。再配置がファイルに対して必須の場合、DT_RELA または DT_REL が使用可能です。
DT_RELA 再配置テーブルの合計サイズ (単位: バイト)。
DT_RELA 再配置エントリのサイズ (単位: バイト)。
DT_STRTAB 文字列テーブルの合計サイズ (単位: バイト)。
DT_SYMTAB シンボルエントリのサイズ (単位: バイト)。
初期化関数のアドレス。詳細は、初期設定および終了セクションを参照してください。
終了関数のアドレス。詳細は、初期設定および終了セクションを参照してください。
ヌル文字で終わっている文字列の DT_STRTAB 文字列テーブルオフセットで、共有オブジェクトの名前を示します。共有オブジェクト名の記録を参照
ヌル文字で終わっているライブラリ検索パス文字列の DT_STRTAB 文字列テーブルオフセット。この要素の使用は、DT_RUNPATH に置き換えられました。 実行時リンカーが検索するディレクトリを参照してください。
オブジェクトが、リンク編集中に適用されたシンボリック結合を含むことを示します。この要素の使用は、DF_SYMBOLIC フラグに置き換えられました。 詳細は、-B symbolic の使用を参照してください。
DT_RELA に似ていますが、テーブルに暗黙の加数が存在する点が異なります。この要素が存在する場合、DT_RELSZ 要素と DT_RELENT 要素も存在する必要があります。
DT_REL 再配置テーブルの合計サイズ (単位: バイト)。
DT_REL 再配置エントリのサイズ (単位: バイト)。
プロシージャのリンクテーブルが参照する再配置エントリの型 (DT_REL または DT_RELA ) を示します。1 つのプロシージャのリンクテーブルでは、すべての再配置は、同じ再配置を使用しなければなりません。詳細は、プロシージャのリンクテーブル (プロセッサ固有)を参照してください。この要素が存在する場合、DT_JMPREL 要素も存在する必要があります。
デバッグに使用されます。
1 つまたは複数の再配置エントリが書き込み不可セグメントに対する変更を要求する可能性があり、実行時リンカーはそれに応じて対応できることを示します。この要素の使用は、DF_TEXTREL フラグに置き換えられました。 位置に依存しないコードを参照してください。
プロシージャのリンクテーブルにのみ関連付けられている再配置エントリのアドレス。詳細は、プロシージャのリンクテーブル (プロセッサ固有)を参照してください。これらの再配置エントリを分離しておくと、遅延結合が有効の場合、実行時リンカーはオブジェクトの読み込み時にこれらの再配置エントリを無視します。この要素が存在する場合、DT_PLTRELSZ 要素と DT_PLTREL 要素も存在する必要があります。
直後の DT_ 要素に適用されるさまざまな状態フラグ。詳細は、表 7–45 を参照してください。
プログラムに制御を渡す前に、このオブジェクトについてのすべての再配置を処理するよう実行時リンカーに指示します。環境または dlopen(3DL) で指定された場合、このエントリは遅延結合の使用指示よりも優先されます。この要素の使用は、DF_BIND_NOW フラグに置き換えられました。 詳細は、再配置が実行されるときを参照してください。
初期設定関数へのポインタの配列のアドレス。この要素が存在する場合、DT_INIT_ARRAYSZ 要素も存在する必要があります。詳細は、初期設定および終了セクションを参照してください。
終了関数へのポインタの配列のアドレス。この要素が存在する場合、DT_FINI_ARRAYSZ 要素も存在する必要があります。詳細は、初期設定および終了セクションを参照してください。
DT_INIT_ARRAY 配列の合計サイズ (単位: バイト)。
DT_FINI_ARRAY 配列の合計サイズ (単位: バイト)。
ヌル文字で終わっているライブラリ検索パス文字列の DT_STRTAB 文字列テーブルオフセット。実行時リンカーが検索するディレクトリを参照してください。
このオブジェクトに特有のフラグ値。詳細は、表 7–43 を参照してください。
DT_ENCODING と等しいかそれより大きく、かつ DT_HIOS と等しいかそれより小さい値は、d_un union の解釈の規則に従います。
「初期設定前」関数へのポインタの配列のアドレス。この要素が存在する場合、DT_PREINIT_ARRAYSZ 要素も存在する必要があります。この配列は、実行可能ファイル内でのみ処理されます。共有オブジェクト内に含まれている場合は無視されます。詳細は、初期設定および終了セクションを参照してください。
DT_PREINIT_ARRAY 配列の合計サイズ (単位: バイト)。
この範囲の値 (両端の値を含む) は、オペレーティングシステム固有の意味のために予約されています。このような値はすべて、d_un union の解釈の規則に従います。
実行時リンカーによる使用のために予約されています。
シンボル情報テーブルのアドレス。この要素が存在する場合、DT_SYMINENT 要素と DT_SYMINSZ 要素も存在する必要があります。詳細は、Syminfo テーブルセクションを参照してください。
DT_SYMINFO 情報エントリのサイズ (単位: バイト)。
DT_SYMINFO テーブルのサイズ (単位: バイト)。
バージョン定義テーブルのアドレス。このテーブル内の要素には、文字列テーブル DT_STRTAB のインデックスが含まれます。この要素が存在する場合、DT_VERDEFNUM 要素も存在する必要があります。詳細は、バージョン定義セクションを参照してください。
DT_VERDEF テーブルのエントリ数。
バージョン依存性テーブルのアドレス。このテーブル内の要素には、文字列テーブル DT_STRTAB のインデックスが含まれます。この要素が存在する場合、DT_VERNEEDNUM 要素も存在する必要があります。詳細は、バージョン依存セクションを参照してください。
DT_VERNEEDNUM テーブルのエントリ数
すべての Elf32_Rela (または Elf64_Rela) RELATIVE 再配置は連結されていることを示し、このエントリにより、RELATIVE 再配置カウントが指定されます。詳細は、再配置セクションの結合を参照してください。
すべての Elf32_Rel RELATIVE 再配置は連結されていることを示し、このエントリにより、RELATIVE 再配置カウントが指定されます。詳細は、再配置セクションの結合を参照してください。
ヌル文字で終わっている DT_STRTAB 文字列テーブルオフセットで、1 つ以上の補助「フィルティー」の命名を行います。詳細は、補助フィルタの生成を参照してください。
ヌル文字で終わっている DT_STRTAB 文字列テーブルオフセットで、1 つ以上の標準「フィルティー」の命名を行います。詳細は、標準フィルタの生成を参照してください。
オブジェクトの選択されたセクションの簡単なチェックサム。詳細は、gelf_checksum(3ELF) のマニュアルページを参照してください。
DT_MOVETAB 移動エントリのサイズ (単位: バイト)。
DT_MOVETAB テーブルの合計サイズ (単位: バイト)。
移動テーブルのアドレス。この要素が存在する場合、DT_MOVEENT 要素と DT_MOVESZ 要素も存在する必要があります。詳細は、移動セクションを参照してください。
ヌル文字で終わっている DT_STRTAB 文字列テーブルオフセットで、構成ファイルを定義します。構成ファイルは、実行可能ファイルでのみ有効であり、通常このオブジェクトに固有のファイルです。詳細は、デフォルトの検索パスの設定を参照してください。
ヌル文字で終わっている DT_STRTAB 文字列テーブルオフセットで、1 つ以上の監査ライブラリを定義します。詳細は、実行時リンカーの監査インタフェースを参照してください。
ヌル文字で終わっている DT_STRTAB 文字列テーブルオフセットで、1 つ以上の監査ライブラリを定義します。詳細は、実行時リンカーの監査インタフェースを参照してください。
このオブジェクトに特有のフラグ値。表 7–44 を参照してください。
このオブジェクト特有の機能を示す値。詳細は、機能チェックを参照してください。
この範囲の値は、動的構造体内の d_un.d_val フィールドで使用されます。
この範囲の値は、動的構造体内の d_un.d_ptr フィールドで使用されます。ELF オブジェクトが作成後に調整された場合、これらのエントリも更新する必要があります。
DT_SYMTAB シンボルテーブル内の STT_SPARC_REGISTER シンボルのインデックス。シンボルテーブルの各 STT_SPARC_REGISTER シンボルには、1 つのエントリが存在します。詳細は、レジスタシンボルを参照してください。
この範囲の値は、プロセッサ固有の使用方法に予約されます。
動的配列の最後にある DT_NULL 要素と、DT_NEEDED と DT_POSFLAG_1 要素の相対的な順序を除くと、エントリはどの順序で現れてもかまいません。表に示されていないタグ値は予約されています。
表 7–43 ELF 動的フラグ DT_FLAGS
名前 |
値 |
意味 |
---|---|---|
DF_ORIGIN |
0x1 |
$ORIGIN 処理が必要 |
DF_SYMBOLIC |
0x2 |
シンボリックシンボル解決が必要 |
DF_TEXTREL |
0x4 |
テキストの再配置が存在する |
DF_BIND_NOW |
0x8 |
非遅延結合が必要 |
DF_STATIC_TLS |
0x10 |
オブジェクトは静的なスレッド固有領域方式を使用する |
オブジェクトに $ORIGIN 処理が必要であることを示します。関連する依存関係の配置を参照してください。
オブジェクトが、リンク編集中に適用されたシンボリック結合を含むことを示します。詳細は、-B symbolic の使用を参照してください。
1 つまたは複数の再配置エントリが書き込み不可セグメントに対する変更を要求する可能性があり、実行時リンカーはそれに応じて対応できることを示します。位置に依存しないコードを参照してください。
プログラムに制御を渡す前に、このオブジェクトについてのすべての再配置を処理するよう実行時リンカーに指示します。環境または dlopen(3DL) で指定された場合、このエントリは遅延結合の使用指示よりも優先されます。詳細は、再配置が実行されるときを参照してください。
静的なスレッド固有領域方式を使用するコードがオブジェクトに含まれていることを示します。静的なスレッド固有領域は、dlopen(3DL) または遅延読み込みを使用して動的に読み込まれるオブジェクトでは使用できません。この制限のため、リンカーは静的なスレッド固有領域を必要とする共有オブジェクトの作成をサポートしていません。
名前 |
値 |
意味 |
---|---|---|
DF_1_NOW |
0x1 |
完全な再配置処理を行います |
DF_1_GLOBAL |
0x2 |
未使用 |
DF_1_GROUP |
0x4 |
オブジェクトがグループの構成要素であることを示します |
DF_1_NODELETE |
0x8 |
オブジェクトがプロセスから削除できないことを示します |
DF_1_LOADFLTR |
0x10 |
「フィルティー」の即時読み込みを保証します |
DF_1_INITFIRST |
0x20 |
オブジェクトの初期化を最初に実行します |
DF_1_NOOPEN |
0x40 |
オブジェクトを dlopen(3DL) で使用できません |
DF_1_ORIGIN |
0x80 |
$ORIGIN 処理が必要です |
DF_1_DIRECT |
0x100 |
直接結合が有効です |
DF_1_INTERPOSE |
0x400 |
オブジェクトは割り込み処理です |
DF_1_NODEFLIB |
0x800 |
デフォルトのライブラリ検索パスを無視します |
DF_1_NODUMP |
0x1000 |
オブジェクトを dldump(3DL) でダンプできません |
DF_1_CONFALT |
0x2000 |
オブジェクトは代替構成です |
DF_1_ENDFILTEE |
0x4000 |
「フィルティー」がフィルタの検索を終了します |
DF_1_DISPRELDNE |
0x8000 |
ディスプレイスメント再配置の終了 |
DF_1_DISPRELPND |
0x10000 |
ディスプレイスメント再配置の保留 |
DF_1_NODIRECT |
0x20000 |
オブジェクトは間接的な結合を含みます |
プログラムに制御を渡す前に、このオブジェクトについてのすべての再配置を処理するよう実行時リンカーに指示します。環境または dlopen(3DL) で指定された場合、このフラグは遅延結合の使用指示よりも優先されます。詳細は、再配置が実行されるときを参照してください。
オブジェクトがグループの構成要素であることを示します。このフラグは、リンカーの -B group オプションを使用してオブジェクトに記録されます。詳細は、オブジェクト階層を参照してください。
オブジェクトがプロセスから削除できないことを示します。オブジェクトは、dlopen(3DL) で直接または依存性としてプロセスに読み込まれた場合、dlclose(3DL) で読み込み解除できません。このフラグは、リンカーの -z nodelete オプションを使用してオブジェクトに記録されます。
これは、「フィルタ」に対してのみ意味があります。関連付けられているすべての「フィルティー」が直ちに処理されることを示します。このフラグは、リンカーの -z loadfltr オプションを使用してオブジェクトに記録されます。詳細は、「フィルティー」の処理を参照してください。
このオブジェクトと共に読み込まれたほかのオブジェクトよりも先に、このオブジェクトの初期化セクションが実行されることを示します。このフラグは特殊なシステムライブラリでのみ使用するもので、リンカーの -z initfirst オプションを使用してオブジェクトに記録されます。
dlopen(3DL) を使ってオブジェクトを実行中のプロセスに追加できないことを示します。このフラグは、リンカーの -z nodlopen オプションを使用してオブジェクトに記録されます。
オブジェクトに $ORIGIN 処理が必要であることを示します。関連する依存関係の配置を参照してください。
オブジェクトが直接結合情報を使用することを示します。直接結合を参照してください。
オブジェクトシンボルテーブルの割り込みが、一次読み込みオブジェクト (通常は実行可能ファイル) 以外のすべてのシンボルの前で発生します。このフラグは、リンカーの -z interpose オプションを使用して記録されます。直接結合を参照してください。
このオブジェクトの依存関係を検索する際、デフォルトのライブラリ検索パスがすべて無視されることを示します。このフラグは、リンカーの -z nodefaultlib オプションを使用してオブジェクトに記録されます。実行時リンカーが検索するディレクトリを参照してください。
このオブジェクトが dldump(3DL) によってダンプされないことを示します。このオプションの候補には、再配置を保持しないオブジェクトが含まれ、これらのオブジェクトは、crle(1) を使用して代替オブジェクトを生成する際に含めることができます。このフラグは、リンカーの -z nodump オプションを使用してオブジェクトに記録されます。
このオブジェクトが、crle(1) によって生成された代替構成オブジェクトであることを示します。このフラグにより実行時リンカーがトリガーされ、構成ファイル $ORIGIN/ld.config.app-name が検索されます。
「フィルティー」に対してのみ意味があります。以降の「フィルティー」に対するフィルタ検索は行われません。このフラグは、リンカーの -z endfiltee オプションを使用してオブジェクトに記録されます。詳細は、「フィルティー」検索の縮小を参照してください。
このオブジェクトにディスプレイスメント再配置が適用されたことを示します。再配置が適用されると再配置レコードは破棄されるため、オブジェクト内のディスプレイスメント再配置レコードはもはや存在しません。詳細は、ディスプレイスメント再配置 を参照してください。
このオブジェクトのディスプレイスメント再配置が保留されていることを示します。ディスプレイスメント再配置はオブジェクト内部で終了するため、実行時に完了できます。詳細は、ディスプレイスメント再配置 を参照してください。
このオブジェクトに、直接結合できないシンボルが含まれることを示します。追加シンボルの定義を参照してください。
名前 |
値 |
意味 |
---|---|---|
DF_P1_LAZYLOAD |
0x1 |
遅延読み込みされた依存関係を示す |
DF_P1_GROUPPERM |
0x2 |
グループの依存関係を示す |
後続の DT_NEEDED エントリが遅延読み込み対象のオブジェクトであることを示します。このフラグは、リンカーの -z lazyload オプションを使用してオブジェクトに記録されます。動的依存関係の遅延読み込みを参照してください。
後続の DT_NEEDED エントリがグループとして読み込まれるオブジェクトであることを示します。このフラグは、リンカーの -z groupperm オプションを使用してオブジェクトに記録されます。詳細は、グループの分離を参照してください。
名前 |
値 |
意味 |
---|---|---|
DTF_1_PARINIT |
0x1 |
部分的な初期化機能が必要 |
DTF_1_CONFEXP |
0x2 |
構成ファイルが必要 |
オブジェクトが部分的な初期化を必要とすることを示します。詳細は、移動セクションを参照してください。
このオブジェクトが、crle(1) によって生成された代替構成オブジェクトであることを示します。このフラグにより実行時リンカーがトリガーされ、構成ファイル $ORIGIN/ld.config.app-name が検索されます。このフラグの効果は、DF_1_CONFALT と同じです。
一般に位置に依存しないコードには絶対仮想アドレスは存在できません。大域オフセットテーブルは、内部で使用するデータ内に絶対アドレスを保持します。このため、位置からの独立性とプログラムのテキストの共有性を低下させることなくアドレスが使用可能になります。プログラムは、位置に依存しないアドレス指定を使用して大域オフセットテーブルを参照し、絶対値を抽出します。この方法により、位置に依存しない参照を、絶対位置にリダイレクトできます。
最初は、大域オフセットテーブルには再配置エントリで要求される情報を保持します。システムが読み込み可能オブジェクトファイルのメモリーセグメントを作成したあと、実行時リンカーが再配置エントリを処理します。これらの再配置エントリのいくつかは、R_SPARC_GLOB_DAT 型 (SPARC の場合) または R_386_GLOB_DAT 型 (x86 の場合) であり、大域オフセットテーブルを参照します。
実行時リンカーは、関連付けられているシンボル値を判定し、絶対アドレスを計算し、適切なメモリーテーブルエントリに正しい値を設定します。リンカーがオブジェクトファイルを作成するとき、絶対アドレスは認識されていませんが、実行時リンカーはすべてのメモリーセグメントのアドレスを認識しており、したがって、これらのメモリーセグメントに存在するシンボルの絶対アドレスを計算できます。
プログラムがシンボルの絶対アドレスへの直接アクセスを必要とする場合、このシンボルには大域オフセットテーブルエントリが存在します。実行可能ファイルと共有オブジェクトには別個の大域オフセットテーブルが存在するので、シンボルのアドレスはいくつかのテーブルに現れることがあります。実行時リンカーは、すべての大域オフセットテーブルの再配置を処理してから、プロセスイメージ内のいずれかのコードに制御を渡します。この処理により、実行時に絶対アドレスが利用可能になります。
テーブルのエントリ 0 は、_DYNAMIC シンボルで参照される動的構造体のアドレスを保持するために予約されています。このシンボルを利用することにより、実行時リンカーなどのプログラムは、再配置エントリを処理していなくても自身の動的構造体を見つけることができます。この方法は、実行時リンカーにとって特に重要です。なぜなら、実行時リンカーは他のプログラムに頼ることなく自身を初期化してメモリーイメージを再配置しなければならないからです。
システムは、異なるのプログラムの同じ共有オブジェクトに対して、異なるメモリーセグメントアドレスを与えることがあります。さらに、システムはプログラムを実行するごとに異なるライブラリアドレスを与えることさえあります。しかし、プロセスイメージがいったん作成されると、メモリーセグメントのアドレスは変更されません。プロセスが存在する限り、そのプロセスのメモリーセグメントは固定仮想されたアドレスに存在します。
大域オフセットテーブルの形式と解釈は、プロセッサに固有です。SPARC プロセッサと x86 プロセッサの場合、_GLOBAL_OFFSET_TABLE_ シンボルは、テーブルをアクセスするために使用できます。このシンボルは、.got セクションの中央に存在可能であるため、負の添字と負でない添字の両方をアドレスの配列に含めることができます。シンボルタイプは、32 ビットコードの場合、Elf32_Addr の配列で、64 ビットコードの場合、Elf64_Addr の配列です。
extern Elf32_Addr _GLOBAL_OFFSET_TABLE_[]; extern Elf64_Addr _GLOBAL_OFFSET_TABLE_[];
大域オフセットテーブルは位置に依存しないアドレスの計算を絶対位置に変換します。同様に、プロシージャのリンクテーブルは位置に依存しない関数呼び出しを絶対位置に変換します。リンカーは、ある 1 つの実行可能オブジェクトまたは共有オブジェクトから別の実行可能オブジェクトまたは共有オブジェクトへの実行転送 (関数呼び出しなど) を解決できません。このため、リンカーはプログラム転送制御をプロシージャのリンクテーブルのエントリに与えます。このようにして実行時リンカーは、位置からの独立性とプログラムのテキストの共有性を低下させることなくエントリをリダイレクトします。実行可能ファイルと共有オブジェクトファイルには、別個のプロシージャのリンクテーブルが存在します。
32 ビット SPARC 動的オブジェクトの場合、プロシージャのリンクテーブルは専用データ内に存在します。実行時リンカーは、宛先の絶対アドレスを判定し、これらの絶対アドレスに従ってプロシージャのリンクテーブルのメモリーイメージに変更を加えます。
最初の 4 つのプロシージャのリンクテーブルエントリは、予約されています。表 7–47 に例示されてはいますが、これらのエントリの元の内容は指定されていません。テーブル内の各エントリは 3 ワード (12 バイト) を占めており、最後のテーブルエントリの後には nop 命令が続きます。
再配置テーブルは、プロシージャのリンクテーブルに関連付けられています。_DYNAMIC 配列の DT_JMP_REL エントリは、最初の再配置エントリの位置を与えます。再配置テーブルには、予約されていないプロシージャのリンクテーブルエントリごとに 1 つのエントリが同じ順番で存在します。各エントリの再配置タイプは、R_SPARC_JMP_SLOT です。再配置オフセットは関連付けられているプロシージャのリンクテーブルエントリの先頭バイトのアドレスを指定します。シンボルテーブルインデックスは適切なシンボルを参照します。
プロシージャのリンクテーブル機能を説明するため、表 7–47 に 4 つのエントリが示されています。最初の 2 つのエントリは予約されている最初の 4 つのエントリの内の 2 つであり、3 番目のエントリは name101 に対する呼び出しであり、4 番目のエントリは name102 に対する呼び出しです。この例では、name102 のエントリがテーブルの最後のエントリであることを前提としており、後に続く nop 命令が示されています。左欄は、動的リンクが行われる前のオブジェクトファイルの命令を示しています。右欄は、実行時リンカーがプロシージャのリンクテーブルエントリを変更した結果を示しています。
表 7–47 SPARC: プロシージャのリンクテーブルの例
実行時リンカーとプログラムは、以下の手順に従ってプロシージャのリンクテーブル内のシンボル参照を協調して解決します。ただし、以下に記述されている手順は、単に説明用のためのものです。実行時リンカーの正確な実行時動作については、記述されていません。
実行時リンカーは、プログラムのメモリーイメージを最初に作成するとき、プロシージャのリンクテーブルの初期エントリに、実行時リンカー自身のルーチンの 1 つに制御を渡すように変更を加える。実行時リンカーはまた、識別情報 (identification) を 2 番目のエントリに格納する。実行時リンカーは、制御を受け取る際、このワードを調べることで、このルーチンを呼び出したオブジェクトを見つけることができる
他のすべてのプロシージャのリンクテーブルエントリは、最初は先頭エントリに渡される。これで、実行時リンカーは各テーブルエントリの最初の実行時に制御を取得する。たとえば、プログラムが name101 を呼び出すと、制御がラベル .PLT101 に渡される
sethi 命令は、現在のプロシージャのリンクテーブルエントリ (.PLT101) と最初のプロシージャのリンクテーブルエントリ (.PLT0) の距離を計算する。この値は、%g1 レジスタの最上位 22 ビットを占める
次に、ba,a 命令が .PLT0 にジャンプして、スタックフレームを作成し、実行時リンカーを呼び出す
実行時リンカーは、識別情報の値を使うことによってオブジェクトのデータ構造体 (再配置テーブルを含む) を取得する
実行時リンカーは、%g1 値をシフトしプロシージャのリンクテーブルエントリのサイズで除算することで、 name101 の再配置エントリのインデックスを計算する。0再配置エントリ 101 はタイプ R_SPARC_JMP_SLOT を保持し、そのオフセットは .PLT101 のアドレスを指定し、また、そのシンボルテーブルインデックスは name101 を参照する。したがって、実行時リンカーはシンボルの実際の値を取得し、スタックを戻し、プロシージャのリンクテーブルエントリに変更を加え、本来の宛先に制御を渡す
実行時リンカーは、メモリーセグメント欄に示された命令シーケンスを必ずしも作成するとは限りません。ただし、作成する場合は、いくつかの点でより詳細な説明が必要です。
コードを再入可能にするため、プロシージャのリンクテーブルの命令に、特定の順番で変更が加えられる。実行時リンカーが関数のプロシージャのリンクテーブルエントリを修正中に信号が到達した場合、信号処理コードは、予想可能かつ正しい結果を与える元の関数を呼び出すことができなければならない
実行時リンカーは、エントリを変換するために 3 つのワードを変更する。実行時リンカーは、命令を実行する際、ワード単位でのみ不可分に更新できる。このため、各ワードを逆順に更新して再入を可能にする。再入可能関数呼び出しが最後のパッチの直前に発生した場合、実行時リンカーは再度制御を取得する。実行時リンカーに対する両方の呼び出しで、同じプロシージャのリンクテーブルエントリに変更が加えられるが、これらの変更は互いに干渉しない
プロシージャのリンクテーブルエントリの最初の sethi 命令は、1 つ前のエントリの jmp1 命令の遅延スロットを埋める。sethi は %g1 レジスタの値を変更するが、以前の内容を捨てても問題はない
変換後、最後のプロシージャのリンクテーブルエントリ (.PLT102) は、jmp1 の遅延命令を必要とする。要求されている後続の nop は、この遅延スロットを埋める
.PLT101 と .PLT102 の命令シーケンスの違いから、関連する宛先に合わせた最適化の方法を知ることができます。
LD_BIND_NOW
環境変数は、動的リンク動作を変更します。この環境変数の値がヌル文字列以外の場合、実行時リンカーは、プログラムに制御を渡す前に R_SPARC_JMP_SLOT 再配置エントリ (プロシージャのリンクテーブルエントリ) を処理します。
64 ビット SPARC 動的オブジェクトの場合、プロシージャのリンクテーブルは専用データ内に存在します。実行時リンカーは、宛先の絶対アドレスを判定し、これらの絶対アドレスに従ってプロシージャのリンクテーブルのメモリーイメージに変更を加えます。
最初の 4 つのプロシージャのリンクテーブルエントリは、予約されています。表 7–48 で例示されてはいますが、これらのエントリの元の内容は指定されていません。テーブル内の先頭 32,768 エントリは、それぞれ 8 ワード (32 バイト) を占め、32 バイト境界で整列する必要があります。テーブル全体は 256 バイト境界で整列する必要があります。32,768 を超えるエントリが必要な場合、残りのエントリは 6 ワード (24 バイト) および 1 つのポインタ (8 バイト) で構成されます。 命令は、160 エントリのブロックにまとめられ、その次に 160 個ポインタが続きます。最後のグループのエントリとポインタは、160 未満でもかまいません。パディングの必要はありません。
32,768 および 160 という数字は、それぞれ分岐と読み込み置換の制限に基づいており、また、キャッシュの効率を向上させるために、コードとデータの間の区分を 256 バイト境界に合わせています。
再配置テーブルは、プロシージャのリンクテーブルに関連付けられています。_DYNAMIC 配列の DT_JMP_REL エントリは、最初の再配置エントリの位置を与えます。再配置テーブルには、予約されていないプロシージャのリンクテーブルエントリごとに 1 つのエントリが同じ順番で存在します。各エントリの再配置タイプは、R_SPARC_JMP_SLOT です。最初の 32,767 スロットでは、再配置オフセットは関連するプロシージャのリンクテーブルエントリの先頭バイトのアドレスを指定します。加数フィールドはゼロになります。シンボルテーブルインデックスは適切なシンボルを参照します。32,768 以後のスロットでは、再配置オフセットは関連するポインタの先頭バイトのアドレスを指定します。加数フィールドは、再配置されていない値 -(.PLTN + 4) になります。シンボルテーブルインデックスは適切なシンボルを参照します。
プロシージャのリンクテーブルの機能を説明するため、表 7–48 にエントリがいくつか示されています。最初の 3 つのエントリは、予約済みの初期エントリを示します。続く 3 つのエントリは、32,768 エントリの初期状態と、それぞれ、対象アドレスがエントリの +/- 2G バイト以内の場合、アドレス空間の下位 4G バイト以内の場合、およびその他の場合に適用されると考えられる、変換された状態を示しています。最後の 2 つのエントリは、命令とポインタのペアで構成される、後のエントリの例を示します。左欄は、動的リンクが行われる前のオブジェクトファイルの命令を示しています。右欄は、実行時リンカーがプロシージャのリンクテーブルエントリを変更した結果を示しています。
表 7–48 64-bit SPARC: プロシージャのリンクテーブルの例
実行時リンカーとプログラムは、以下の手順に従ってプロシージャのリンクテーブル内のシンボル参照を協調して解決します。ただし、以下に記述されている手順は、単に説明用のためのものです。実行時リンカーの正確な実行時動作については、記述されていません。
実行時リンカーは、プログラムのメモリーイメージを最初に作成するとき、プロシージャのリンクテーブルの初期エントリに、実行時リンカー自身のルーチンの 1 つに制御を渡すように変更を加える。実行時リンカーはまた、識別情報 (identification) の拡張ワードを 3 番目のエントリに格納する。実行時リンカーは、制御を受け取ると、この拡張ワードを調べることで、このルーチンを呼び出したオブジェクトを見つけることができる
他のすべてのプロシージャのリンクテーブルエントリは、最初、先頭または 2 番目のエントリに渡される。これらのエントリは、スタックフレームを確立して、実行時リンカーを呼び出す
実行時リンカーは、識別情報の値を使うことによってオブジェクトのデータ構造体 (再配置テーブルを含む) を取得する
実行時リンカーは、テーブルスロットの再配置エントリのインデックスを計算する
インデックス情報に関しては、実行時リンカーはシンボルの実際の値を取得し、スタックを戻し、プロシージャのリンクテーブルエントリを変更してから、制御を宛先に渡す
実行時リンカーは、メモリーセグメント欄に示された命令シーケンスを必ずしも作成する必要はありません。ただし、作成する場合は、いくつかの点でより詳細な説明が必要です。
コードを再入可能にするため、プロシージャのリンクテーブルの命令に、特定の順番で変更が加えられる。実行時リンカーが関数のプロシージャのリンクテーブルエントリを修正中に信号が到達した場合、信号処理コードは、予想可能かつ正しい結果を与える元の関数を呼び出すことができなければならない
実行時リンカーは、8 ワードまで変更を加えてエントリを変換できる。実行時リンカーは、命令を実行する際、ワード単位でのみ不可分に更新できる。このため、64 ビットストアを使用している場合、再入可能性は、まず nop 命令を置換命令で上書きし、次に ba、a および sethi をパッチ適用することで実現される。再入可能関数呼び出しが最後のパッチの直前に発生した場合、実行時リンカーは再度制御を取得する。実行時リンカーに対する両方の呼び出しで、同じプロシージャのリンクテーブルエントリに変更が加えられるが、これらの変更は互いに干渉しない
最初の sethi 命令が変更されると、この命令を変更するには nop を使用する必要がある
エントリの 2 番目のフォームに示すように、ポインタの変更は、単一の不可分 64 ビットストアを使用して行われます。
.PLT101、.PLT102、および .PLT103 の命令シーケンスの違いから、関連する宛先に合わせた最適化の方法を知ることができます。
LD_BIND_NOW
環境変数は、動的リンク動作を変更します。この環境変数の値がヌル文字列以外の場合、実行時リンカーは、プログラムに制御を渡す前に R_SPARC_JMP_SLOT 再配置エントリ (プロシージャのリンクテーブルエントリ) を処理します。
32 ビット x86 動的オブジェクトの場合、プロシージャリンクテーブルは共有テキスト内に存在しますが、非公開の大域オフセットテーブル内のアドレスを使用します。 実行時リンカーは、宛先の絶対アドレスを判定し、これらの絶対アドレスに従って大域オフセットテーブルのメモリーイメージに変更を加えます。このようにして実行時リンカーは、位置からの独立性とプログラムのテキストの共有性を低下させることなくエントリをリダイレクトします。実行可能ファイルと共有オブジェクトファイルには、別個のプロシージャのリンクテーブルが存在します。
表 7–49 x86: 絶対プロシージャのリンクテーブルの例
.PLT0: pushl got_plus_4 jmp *got_plus_8 nop; nop nop; nop .PLT1: jmp *name1_in_GOT pushl $offset jmp .PLT0@PC .PLT2: jmp *name2_in_GOT pushl $offset jmp .PLT0@PC |
表 7–50 x86: 位置に依存しないプロシージャリンクテーブルの例
.PLT0: pushl 4(%ebx) jmp *8(%ebx) nop; nop nop; nop .PLT1: jmp *name1@GOT(%ebx) pushl $offset jmp .PLT0@PC .PLT2: jmp *name2@GOT(%ebx) pushl $offset jmp .PLT0@PC |
前述の例が示すとおり、プロシージャリンクテーブルの命令は、絶対コードと位置に依存しないコードで異なるオペランドアドレス指定モードを使用します。それでも、実行時リンカーへのインタフェースは同一です。
実行時リンカーとプログラムは、以下の手順に従ってプロシージャのリンクテーブル内と大域オフセットテーブル内のシンボル参照を協調して解決します。
実行時リンカーは、プログラムのメモリーイメージを最初に作成するとき、大域オフセットテーブルの 2 番目と 3 番目のエントリに特殊な値を設定する。これらの値については、以下の手順で説明する
プロシージャのリンクテーブルが位置に依存していない場合、大域オフセットテーブルのアドレスは、%ebx に存在しなければならない。プロセスイメージにおける各共有オブジェクトファイルには自身のプロシージャのリンクテーブルが存在しており、制御は同じオブジェクトファイル内からのみプロシージャのリンクテーブルエントリに渡される。したがって、呼び出し側関数は、プロシージャのリンクテーブルエントリを呼び出す前に、大域オフセットテーブルベースレジスタをセットしなければならない
たとえば、プログラムが name1 を呼び出すと、制御が .PLT1 に渡される
最初の命令は、name1 の大域オフセットテーブルエントリのアドレスにジャンプする。大域オフセットテーブルは最初は、後続の pushl 命令のアドレスを保持する (name1 の実アドレスは保持しない)
プログラムは再配置オフセット (offset) をスタックにプッシュする。再配置オフセットは、再配置テーブルへの 32 ビットの負ではないバイトオフセット。指定された再配置エントリには R_386_JMP_SLOT が存在しており、オフセットは、前の jmp 命令で使用された大域オフセットテーブルエントリを指定する。再配置エントリにはシンボルテーブルインデックスも存在しており、実行時リンカーはこれを使って参照されたシンボル name1 を取得する
プログラムは、再配置オフセットをプッシュした後、.PLT0 (プロシージャのリンクテーブルの先頭エントリ) にジャンプする。pushl 命令は、2 番目の大域オフセットテーブルエントリ (got_plus_4 または 4(%ebx)) の値をスタックにプッシュして、実行時リンカーに 1 ワードの識別情報を与える。プログラムは次に、3 番目の大域オフセットテーブルエントリ (got_plus_8 または 8(%ebx)) のアドレスにジャンプして、実行時リンカーにジャンプする
実行時リンカーはスタックを戻し、指定された再配置エントリを調べ、シンボルの値を取得し、name1 の実際のアドレスを大域オフセットテーブルエントリに格納し、そして宛先にジャンプする
その後のプロシージャのリンクテーブルエントリに対する実行は、name1 に直接渡される (実行時リンカーの再呼び出しは行われない)。.PLT1 における jmp 命令は、pushl 命令にジャンプする代わりに、name1 にジャンプする
LD_BIND_NOW
環境変数は、動的リンク動作を変更します。この環境変数の値がヌル文字列以外の場合、実行時リンカーは、プログラムに制御を渡す前に R_386_JMP_SLOT 再配置エントリ (プロシージャのリンクテーブルエントリ) を処理します。