この章では、アセンブラとリンカーで生成されるオブジェクトファイルの実行可能リンク形式 (ELF) について説明します。オブジェクトファイルには、主に次の 3 つの種類が存在します。
再配置可能ファイルは、コードとデータが入っているセクションを保持する。再配置可能ファイルは、ほかのオブジェクトファイルとリンクして、実行可能ファイル、共有オブジェクト、または別の再配置可能オブジェクトを作成するのに適している
実行可能ファイルは、実行可能なプログラムを保持する。実行可能ファイルは、exec(2) によるプログラムのプロセスイメージの作成方法を指定する
共有オブジェクトファイルは、次の 2 つのリンクに適したコードとデータを保持する。(1) リンカーは、共有オブジェクトファイルを他の再配置可能ファイルや共有オブジェクトファイルと共に処理して、別のオブジェクトファイルを作ることができる。(2) 実行時リンカーは、共有オブジェクトファイルを動的実行可能ファイルや他の共有オブジェクトファイルと組み合わせ、プロセスイメージを作成する
ファイル形式では、オブジェクトファイルの形式、およびこの形式がプログラム作成にどのように関係しているかに焦点を当てています。動的リンクでは、この形式がプログラムの読み込みにどのように関係しているかに焦点を当てています。
オブジェクトファイルは、ELF アクセスライブラリ libelf に含まれる関数で処理できます。libelf の説明については、elf(3ELF) のマニュアルページを参照してください。libelf を使用するサンプルソースコードは、SUNWosdem パッケージに含まれており、/usr/demo/ELF ディレクトリの下に置かれています。
オブジェクトファイルはプログラムのリンクと実行の両方に関係します。利便性と効率性のため、オブジェクトファイルの形式には、リンクと実行の異なる要求に合わせて、2 つの平行した見方があります。次の図にオブジェクトファイルの編成を示します。
ELF ヘッダーはオブジェクトファイルの先頭に存在し、ファイル編成を記述する「ロードマップ」を保持します。
ELF ヘッダーの位置のみがファイル内で固定されています。ELF 形式には柔軟性があるため、ヘッダーテーブル、セクション、およびセグメントの順序は特に決まっていません。この図に示したのは、Solaris で使用される典型的なレイアウトです。
「セクション」は、ELF ファイル内で処理可能な最小単位 (これ以上分割できない単位) です。「セグメント」は、exec(2) または実行時リンカーでメモリーイメージに対応付けできる最小単位です。
セクションは、リンクの観点から見たオブジェクトファイルの情報 (命令、データ、シンボルテーブル、再配置情報など) の大部分を保持します。セクションに関しては、この章の前半で説明します。セグメントとプログラムの実行の観点から見たファイルの構造に関しては、この章の後半で説明します。
プログラムヘッダーテーブル (存在する場合) は、システムにプロセスイメージの作成方法を通知します。プロセスイメージの作成に使用されるファイル (実行可能プログラムと共有オブジェクト) には、プログラムヘッダーテーブルが存在しなければなりません。再配置可能オブジェクトには、プログラムヘッダーテーブルは必要ありません。
セクションヘッダーテーブルには、ファイルのセクションを記述する情報が入っています。セクションヘッダーテーブルには各セクションのエントリが存在します。各エントリは、セクション名、セクションサイズなどの情報が含まれます。リンク編集で使用されるファイルには、セクションヘッダーテーブルが存在しなければなりません。他のオブジェクトファイルには、セクションヘッダーテーブルは存在してもしなくてもかまいません。
オブジェクトファイルの形式は、8 ビットバイト、32 ビットアーキテクチャ、および 64 ビットアーキテクチャを持つさまざまなプロセッサをサポートしています。ただし、オブジェクトファイルの形式は拡張性が高いため、より大きな (またはより小さな) アーキテクチャに対応できます。表 7–1 と表 7–2 に、32 ビットおよび 64 ビットのデータタイプを示します。
オブジェクトファイルは、いくつかの制御データをマシンに依存しない形式で表現します。このため、オブジェクトファイルの識別、およびオブジェクトファイルの内容を共通の方法で解釈することが可能になります。オブジェクトファイルの残りのデータは、このオブジェクトファイルが作成されたマシンとは関係なく、対象となるプロセッサ用に符号化されています。
表 7–1 ELF 32 ビットデータタイプ
名前 |
サイズ |
整列 |
目的 |
---|---|---|---|
Elf32_Addr |
4 |
4 |
符号なしプログラムアドレス |
Elf32_Half |
2 |
2 |
符号なし、中程度の整数 |
Elf32_Off |
4 |
4 |
符号なしファイルオフセット |
Elf32_Sword |
4 |
4 |
符号付き整数 |
Elf32_Word |
4 |
4 |
符号なし整数 |
unsigned char |
1 |
1 |
符号なし、短い整数 |
表 7–2 ELF 64 ビットデータタイプ
名前 |
サイズ |
整列 |
目的 |
---|---|---|---|
Elf64_Addr |
8 |
8 |
符号なしプログラムアドレス |
Elf64_Half |
2 |
2 |
符号なし、中程度の整数 |
Elf64_Off |
8 |
8 |
符号なしファイルオフセット |
Elf64_Sword |
4 |
4 |
符号付き整数 |
Elf64_Word |
4 |
4 |
符号なし整数 |
Elf64_Xword |
8 |
8 |
符号なし、長い整数 |
Elf64_Sxword |
8 |
8 |
符号付き、長い整数 |
unsigned char |
1 |
1 |
符号なし、短い整数 |
オブジェクトファイルの形式で定義されるすべてのデータ構造は、該当クラスの自然なサイズと整列ガイドラインに従います。必要であれば、データ構造に明示的にパッドを入れることで、4 バイトオブジェクトに対して 4 バイト整列を保証したり構造サイズを 4 の倍数に設定したりします。また、データはファイルの先頭から適切に整列されます。したがってたとえば、Elf32_Addr 構成要素が存在する構造はファイル内において 4 バイト境界で整列され、Elf64_Addr 構成要素が存在する構造は 8 バイト境界で整列されます。
移植性を考慮して、ELF ではビットフィールドを使用していません。
いくつかのオブジェクトファイル制御構造は大きくなることがありますが、そのサイズは ELF ヘッダーに記録されます。オブジェクトファイルの形式が変わった場合、ELF 形式のファイルにアクセスするプログラムは、大きくなったり小さくなったりした制御構造体を扱うことになります。大きくなった場合は、追加された部分を無視することができるかもしれません。小さくなった場合は、無くなった部分の扱いは状況に依存しますし、形式が変更された時に規定されるでしょう。
ELF ヘッダーの構造体 (sys/elf.h 内で定義) は、以下のとおりです。
#define EI_NIDENT 16 typedef struct { unsigned char e_ident[EI_NIDENT]; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; } Elf32_Ehdr; typedef struct { unsigned char e_ident[EI_NIDENT]; Elf64_Half e_type; Elf64_Half e_machine; Elf64_Word e_version; Elf64_Addr e_entry; Elf64_Off e_phoff; Elf64_Off e_shoff; Elf64_Word e_flags; Elf64_Half e_ehsize; Elf64_Half e_phentsize; Elf64_Half e_phnum; Elf64_Half e_shentsize; Elf64_Half e_shnum; Elf64_Half e_shstrndx; } Elf64_Ehdr;
この構造体の要素を次に示します。
先頭のバイト列に、オブジェクトファイルであることを示す印と、機種に依存しない、ファイルの内容を復号化または解釈するためのデータが入ります。完全な記述は、ELF 識別で行われています。
オブジェクトファイルの種類を示します。次の種類が存在します。
表 7–3 ELF ファイル識別子
名前 |
値 |
意味 |
---|---|---|
ET_NONE |
0 |
ファイルタイプが存在しない |
ET_REL |
1 |
再配置可能ファイル |
ET_EXEC |
2 |
実行可能ファイル |
ET_DYN |
3 |
共有オブジェクトファイル |
ET_CORE |
4 |
コアファイル |
ET_LOPROC |
0xff00 |
プロセッサに固有 |
ET_HIPROC |
0xffff |
プロセッサに固有 |
コアファイルの内容は指定されていませんが、ET_CORE タイプはコアファイルを示すために予約されます。ET_LOPROC から ET_HIPROC までの値 (それぞれを含む) は、プロセッサ固有の方法で解釈されます。他の値は予約され、必要に応じて新しいオブジェクトファイルの種類に割り当てられます。
個々のファイルに必要なアーキテクチャを指定します。関連するアーキテクチャを、次の表に示します。
表 7–4 ELF 機種
名前 |
値 |
意味 |
---|---|---|
EM_NONE |
0 |
マシンが存在しない |
EM_SPARC |
2 |
SPARC |
EM_386 |
3 |
Intel 80386 |
EM_SPARC32PLUS |
18 |
Sun SPARC 32+ |
EM_SPARCV9 |
43 |
SPARC V9 |
他の値は予約され、必要に応じて新しい機種に割り当てられます (sys/elf.h を参照)。プロセッサ固有の ELF 名の識別には、機種名が使用されます。たとえば、表 7–5 で定義されたフラグでは、接頭辞 EF_ が使用されます。EM_XYZ マシンの WIDGET というフラグは、EF_XYZ_WIDGET と呼ばれます。
オブジェクトファイルのバージョンを示します。次のバージョンが存在します。
表 7–5 ELF バージョン
名前 |
値 |
意味 |
---|---|---|
EV_NONE |
0 |
無効なバージョン |
EV_CURRENT |
>=1 |
現在のバージョン |
値 1 は最初のファイル形式を示します。EV_CURRENT の値は、現在のバージョン番号を示すために必要に応じて変化します。
システムが制御を最初に渡す仮想アドレスを保持し、仮想アドレスが与えられると、プロセスが起動します。ファイルに関連するエントリポイントが存在しない場合、この構成要素は 0 を保持します。
プログラムヘッダーテーブルのファイルオフセットを保持します (単位: バイト)。ファイルにプログラムヘッダーテーブルが存在しない場合、この構成要素は 0 を保持します。
セクションヘッダーテーブルのファイルオフセットを保持します (単位: バイト)。ファイルにセクションヘッダーテーブルが存在しない場合、この構成要素は 0 を保持します。
ファイルに対応付けられたプロセッサ固有のフラグを保持します。フラグ名は、EF_machine「_flag」という形式をとります。x86 の場合、この構成要素はゼロになります。SPARC の場合のフラグを、次の表に示します。
表 7–6 SPARC: ELF フラグ
名前 |
値 |
意味 |
---|---|---|
EF_SPARC_EXT_MASK |
0xffff00 |
ベンダー拡張マスク |
EF_SPARC_32PLUS |
0x000100 |
V8+ 共通機能 |
EF_SPARC_SUN_US1 |
0x000200 |
Sun UltraSPARC™ 1 拡張 |
EF_SPARC_HAL_R1 |
0x000400 |
HAL R1 拡張 |
EF_SPARC_SUN_US3 |
0x000800 |
Sun UltraSPARC 3 拡張 |
EF_SPARCV9_MM |
0x3 |
メモリーモデルのマスク |
EF_SPARCV9_TSO |
0x0 |
トータルストアオーダリング (TSO) |
EF_SPARCV9_PSO |
0x1 |
パーシャルストアオーダリング (PSO) |
EF_SPARCV9_RMO |
0x2 |
リラックスメモリーオーダリング (RMO) |
ELF ヘッダーのサイズ (単位: バイト)。
ファイルのプログラムヘッダーテーブルの 1 つのエントリのサイズ (単位:バイト)。すべてのエントリは同じサイズです。
プログラムヘッダーテーブルのエントリ数。e_phentsize に e_phnum を掛けると、テーブルのサイズ (単位: バイト) が求められます。ファイルにプログラムヘッダーテーブルが存在しない場合、e_phnum は値 0 を保持します。
セクションヘッダーのサイズ (単位:バイト)。1 つのセクションヘッダーは、セクションヘッダーテーブルの 1 つのエントリです。すべてのエントリは同じサイズです。
セクションヘッダーテーブルのエントリ数。e_shentsize に e_shnum を掛けると、セクションヘッダーテーブルのサイズ (単位: バイト) が求められます。ファイルにセクションヘッダーテーブルが存在しない場合、e_shnum は値 0 を保持します。
セクションの数が SHN_LORESERVE (0xff00) 以上の場合、この構成要素の値は 0 となり、セクションヘッダーテーブルエントリの実際の数はセクションヘッダーの sh_size フィールドのインデックス 0 の位置に入っています。そうでない場合、当初のエントリの sh_size 構成要素には 0 が入っています。
セクション名文字列テーブルに対応するエントリのセクション ヘッダーテーブルインデックス。ファイルにセクション名文字列テーブルが存在しない場合、この構成要素は値 SHN_UNDEF を保持します。
セクション名文字列テーブルセクションのインデックスが SHN_LORESERVE (0xff00) 以上の場合、この構成要素の値は SHN_XINDEX (0xffff) となり、セクション名文字列テーブルセクションの実際のインデックスはセクションヘッダーの sh_link フィールドのインデックス 0 の位置に入っています。そうでない場合、当初のエントリの sh_link 構成要素には 0 が入っています。
ELF はオブジェクトファイルの枠組みを提供し、複数のプロセッサ、複数のデータ符号化、複数のクラスのマシンをサポートします。このオブジェクトファイルファミリをサポートするため、ファイルの初期バイトによりファイルの解釈方法が指定されます。これらの初期バイトは、問い合わせが行われるプロセッサにも、ファイルの他の内容にも依存しません。
ELF ヘッダーおよびオブジェクトファイル の初期バイトは、e_ident 構成要素に一致します。
表 7–7 ELF 識別インデックス
名前 |
値 |
目的 |
---|---|---|
EI_MAG0 |
0 |
ファイルの識別 |
EI_MAG1 |
1 |
ファイルの識別 |
EI_MAG2 |
2 |
ファイルの識別 |
EI_MAG3 |
3 |
ファイルの識別 |
EI_CLASS |
4 |
ファイルのクラス |
EI_DATA |
5 |
データの符号化 |
EI_VERSION |
6 |
ファイルのバージョン |
EI_OSABI |
7 |
オペレーティングシステム / ABI の識別 |
EI_ABIVERSION |
8 |
ABI のバージョン |
EI_PAD |
9 |
パッドバイトの開始 |
EI_NIDENT |
16 |
e_ident[] のサイズ |
これらのインデックスは、次に示す値を保持するバイトにアクセスします。
ファイルを ELF オブジェクトファイルとして識別する 4 バイトの「マジックナンバー」(次の表を参照)。
表 7–8 ELF マジックナンバー
名前 |
値 |
位置 |
---|---|---|
ELFMAG0 |
0x7f |
e_ident[EI_MAG0] |
ELFMAG1 |
'E' |
e_ident[EI_MAG1] |
ELFMAG2 |
'L' |
e_ident[EI_MAG2] |
ELFMAG3 |
'F' |
e_ident[EI_MAG3] |
バイト e_ident[EI_CLASS] は、ファイルのクラスまたは容量を示します。次の表にファイルのクラスを示します。
表 7–9 ELF ファイルのクラス
名前 |
値 |
意味 |
---|---|---|
ELFCLASSNONE |
0 |
無効なクラス |
ELFCLASS32 |
1 |
32 ビットオブジェクト |
ELFCLASS64 |
2 |
64 ビットオブジェクト |
ファイル形式は、最大マシンのサイズを最小マシンに押しつけることなしにさまざまなサイズのマシン間で互換性が維持されるように設計されています。ファイルのクラスは、オブジェクトファイルそのもののデータ構造によって使用される基本タイプを定義します。オブジェクトファイルセクションに含まれるデータは、異なるプログラミングモデルに準拠する場合があります。
クラス ELFCLASS32 は、4 ギガバイトまでのファイルと仮想アドレス空間が存在するマシンをサポートします。これは、表 7–1 で定義される基本タイプを使用します。
クラス ELFCLASS64 は、SPARC などの 64 ビットアーキテクチャに対して使用されます。これは、表 7–2 で定義される基本タイプを使用します。
バイト e_ident[EI_DATA] は、オブジェクトファイルのプロセッサ固有のデータの符号化を指定します (次の表を参照)。
表 7–10 ELF データの符号化
名前 |
値 |
意味 |
---|---|---|
ELFDATANONE |
0 |
無効な符号化 |
ELFDATA2LSB |
1 |
図 7–2 を参照 |
ELFDATA2MSB |
2 |
図 7–3 を参照 |
これらの符号化の詳細は、データの符号化 で説明します。他の値は予約され、必要に応じて新しい符号化に割り当てられます。
バイト e_ident[EI_VERSION] は、ELF ヘッダーバージョン番号を指定します。現在この値は、EV_CURRENT でなければなりません。
バイト e_ident[EI_OSABI] は、オブジェクトのターゲット先となるオペレーティングシステムおよび ABI を識別します。他の ELF 構造体内のフィールドの中には、オペレーティンシステム特有または ABI 特有の意味を持つフラグおよび値を保持するものがあります。これらのフィールドの解釈は、このバイトの値によって決定されます。
バイト e_ident[EI_ABIVERSION] は、オブジェクトのターゲット先となる ABI のバージョンを識別します。このフィールドは、ABI の互換性の無いバージョンを識別するために使用します。このバージョン番号の解釈は、EI_OSABI フィールドで識別される ABI によって異なります。プロセッサについて EI_OSABI フィールドに値が何も指定されていない場合、または EI_OSABI バイトの特定の値によって決定される ABI についてバージョンの値が何も指定されていない場合は、「指定なし」を示すものとして値 0 が使用されます。
この値は、e_ident の使用されていないバイトの先頭を示します。これらのバイトは保留され、0 に設定されます。オブジェクトファイルを読み取るプログラムは、これらのバイトを無視する必要があります。
ファイルのデータ符号化方式は、ファイルの基本オブジェクトを解釈する方法を指定します。クラス ELFCLASS32 のファイルは、1、2、および 4 バイトを占めるオブジェクトを使用します。クラス ELFCLASS64 のファイルは、1、2、4、および 8 バイトを占めるオブジェクトを使用します。定義されている符号化方式の下では、オブジェクトは以下のように表されます。バイト番号は、左上隅に示されています。
ELFDATA2LSB を符号化すると、最下位バイトが最低位アドレスを占める 2 の補数値が指定されます。
ELFDATA2MSB を符号化すると、最上位バイトが最低位アドレスを占める 2 の補数値が指定されます。
オブジェクトファイルのセクションヘッダーテーブルを使用すると、ファイルのセクションすべてを見つけ出すことができます。セクションヘッダーテーブルは、以下に示されているとおり、Elf32_Shdr 構造体または Elf64_Shdr 構造体の配列です。セクションヘッダーテーブルインデックスは、この配列への添字です。ELF ヘッダーの e_shoff 構成要素は、ファイルの先頭からセクションヘッダーテーブルまでのバイトオフセットを与えます。 e_shnum は、セクションヘッダーテーブルに存在するエントリ数を与えます。 e_shentsize は、各エントリのサイズ (単位: バイト) を与えます。
セクションの数が SHN_LORESERVE (0xff00) 以上の場合、e_shnum の値は SHN_UNDEF (0) となり、セクションヘッダーテーブルエントリの実際の数はセクションヘッダーの sh_size フィールドのインデックス 0 の位置に入っています。そうでない場合、当初のエントリの sh_size 構成要素には 0 が入っています。
セクションヘッダーテーブルインデックスの中には、インデックスサイズが制限されている文脈で予約されているものがあります。たとえば、シンボルテーブルエントリの st_shndx 構成要素、 ELF ヘッダーの e_shnum 構成要素と e_shstrndx 構成要素などがそうです。このような文脈では、予約値はオブジェクトファイル内の実際のセクションを示しません。また、このような文脈では、エスケープ値は、実際のセクションインデックスがどこかもっと大きなフィールド内に存在することを示します。
表 7–11 ELF セクションの特殊インデックス
名前 |
値 |
---|---|
SHN_UNDEF |
0 |
SHN_LORESERVE |
0xff00 |
SHN_LOPROC |
0xff00 |
SHN_BEFORE |
0xff00 |
SHN_AFTER |
0xff01 |
SHN_HIPROC |
0xff1f |
SHN_LOOS |
0xff20 |
SHN_HIOS |
0xff3f |
SHN_ABS |
0xfff1 |
SHN_COMMON |
0xfff2 |
SHN_XINDEX |
0xffff |
SHN_HIRESERVE |
0xffff |
インデックス 0 は未定義値として予約されますが、セクションヘッダーテーブルにはインデックス 0 のエントリが存在します。つまり、ELF ヘッダーの e_shnum 構成要素が、ファイルのセクションヘッダーテーブルに 6 つのエントリが存在することを示している場合、これら 6 つのエントリにはインデックス 0 から 5 までが与えられます。先頭のエントリの内容は、この項の末尾に記述します。
未定義の、失われた、関連のない、または無意味なセクション参照。たとえば、セクション番号 SHN_UNDEF に関して「定義された」シンボルは、未定義シンボルです。
SHF_LINK_ORDER および SHF_ORDERED セクションフラグと共に先頭および末尾セクションに順序付けを行います (表 7–14 を参照)。
対応する参照の絶対値。 たとえば、セクション番号 SHN_ABS からの相対で定義されたシンボルは絶対値をとり、再配置の影響を受けません。
このセクションに関して定義されたシンボルは、共通シンボルです。たとえば、FORTRAN COMMON や割り当てられていない C 外部変数です。これらのシンボルは、ときどき一時的シンボルと呼ばれることもあります。
実際のセクションヘッダーインデックスが大きすぎて保持するフィールド内に入りきらないことを示すエスケープ値。ヘッダーセクションインデックスは、このインデックスが出現する構造体に固有の別の場所に存在します。
予約されているインデックスの範囲の上限。システムは、SHN_LORESERVE から SHN_HIRESERVE までのインデックスを予約します。値は、セクションヘッダーテーブルを参照しません。セクションヘッダーテーブルには予約されているインデックスのエントリは存在しません。
セクションには、ELF ヘッダー、プログラムヘッダーテーブル、セクションヘッダーテーブルを除く、オブジェクトファイルのすべての情報が存在します。また、オブジェクトファイルのセクションは以下の条件を満たします。
オブジェクトファイルの各セクションには、そのセクションを記述するセクションヘッダーが必ず 1 つ存在する。対応するセクションが存在しないセクションヘッダーが存在することもある
各セクションは、ファイル内で連続するバイトシーケンス (空の場合もある) を占める
ファイル内のセクション同士は重ならない。ファイル内のどのバイトも複数のセクションに属することはない
オブジェクトファイルには、使用されていない領域が存在することがある。さまざまなヘッダーとセクションは、オブジェクトファイルのすべてのバイトをカバーしないことがある。使用されていないデータの内容は不定
セクションヘッダーの構造体 (sys/elf.h で定義されている) は、次のとおりです。
typedef struct { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } Elf32_Shdr; typedef struct { Elf64_Word sh_name; Elf64_Word sh_type; Elf64_Xword sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; Elf64_Xword sh_size; Elf64_Word sh_link; Elf64_Word sh_info; Elf64_Xword sh_addralign; Elf64_Xword sh_entsize; } Elf64_Shdr;
この構造体の要素を次に示します。
セクション名。値はセクションヘッダーの文字列テーブルセクションへのインデックスで、ヌル文字で終わっている文字列を示します。セクション名とその説明は、表 7–16 を参照してください。
セクションの内容と意味を分類します。セクションのタイプとその説明は、表 7–12 を参照してください。
セクションは、さまざまな属性を記述する 1 ビットフラグをサポートします。フラグの定義は、表 7–14 を参照してください。
セクションがプロセスのメモリーイメージに現れる場合、この構成要素はセクションの先頭バイトが存在しなければならないアドレスを与えます。セクションがプロセスのメモリーイメージに現れない場合、この構成要素には 0 が存在します。
ファイルの先頭からセクションの先頭バイトまでのバイトオフセット。SHT_NOBITS 型のセクションの場合はファイル内のスペースを占めないため、この構成要素は、ファイル内の概念的なオフセットを示します。
セクションのサイズ (単位: バイト)。セクションのタイプが SHT_NOBITS でない限り、セクションはファイルの sh_size バイトを占めます。タイプが SHT_NOBITS のセクションは、0 以外のサイズをとることがありますが、ファイルのスペースは占めません。
セクションヘッダーテーブルのインデックスリンク。このリンクの解釈は、セクションのタイプに依存します。値は、表 7–15 を参照してください。
追加情報。情報の解釈は、セクションのタイプに依存します。値は、表 7–15 を参照してください。
いくつかのセクションには、アドレス整列制約が存在します。たとえば、あるセクションが 2 語で構成されるデータを保持している場合、システムはそのセクション全体に対して 2 語単位の整列を保証しなければなりません。つまり、sh_addr の値は、sh_addralign の値を法として 0 でなければなりません。現在、0、および 2 の非負整数累乗のみが許可されています。値 0 と 1 は、セクションに整列制約が存在しないことを意味します。
いくつかのセクションは、サイズが一定のエントリのテーブル (シンボルテーブルなど) を保持します。このようなセクションに対してこの構成要素は、各エントリのサイズ (単位: バイト) を与えます。サイズが一定のエントリのテーブルをセクションが保持しない場合、この構成要素には 0 が格納されます。
セクションヘッダーの sh_type 構成要素は、表 7–12 に示すようにこのセクションの意味を示します。
表 7–12 ELF セクションタイプ、sh_type
名前 |
値 |
---|---|
SHT_NULL |
0 |
SHT_PROGBITS |
1 |
SHT_SYMTAB |
2 |
SHT_STRTAB |
3 |
SHT_RELA |
4 |
SHT_HASH |
5 |
SHT_DYNAMIC |
6 |
SHT_NOTE |
7 |
SHT_NOBITS |
8 |
SHT_REL |
9 |
SHT_SHLIB |
10 |
SHT_DYNSYM |
11 |
SHT_INIT_ARRAY |
14 |
SHT_FINI_ARRAY |
15 |
SHT_PREINIT_ARRAY |
16 |
SHT_GROUP |
17 |
SHT_SYMTAB_SHNDX |
18 |
SHT_LOOS |
0x60000000 |
SHT_LOSUNW |
0x6ffffff7 |
SHT_SUNW_ANNOTATE |
0x6ffffff7 |
SHT_SUNW_DEBUGSTR |
0x6ffffff8 |
SHT_SUNW_DEBUG |
0x6ffffff9 |
SHT_SUNW_move |
0x6ffffffa |
SHT_SUNW_COMDAT |
0x6ffffffb |
SHT_SUNW_syminfo |
0x6ffffffc |
SHT_SUNW_verdef |
0x6ffffffd |
SHT_SUNW_verneed |
0x6ffffffe |
SHT_SUNW_versym |
0x6fffffff |
SHT_HISUNW |
0x6fffffff |
SHT_HIOS |
0x6fffffff |
SHT_LOPROC |
0x70000000 |
SHT_SPARC_GOTDATA |
0x70000000 |
SHT_HIPROC |
0x7fffffff |
SHT_LOUSER |
0x80000000 |
SHT_HIUSER |
0xffffffff |
セクションヘッダーが使用されないことを示します。このセクションヘッダーには、関連付けられているセクションは存在しません。セクションヘッダーの他の構成要素の値は不定です。
文字列テーブルを示します。一般に、SHT_SYMTAB セクションはリンク編集に関するシンボルを示します。このセクションには完全なシンボルテーブルとして、動的リンクに不要な多くのシンボルが存在することがあります。また、オブジェクトファイルには SHT_DYNSYM セクション (動的リンクシンボルの最小セットを保持して領域を節約している) が存在することがあります。詳細は、シンボルテーブルセクションを参照してください。
文字列テーブルを示します。オブジェクトファイルには、複数の文字列テーブルセクションを指定できます。詳細は、文字列テーブルセクションを参照してください。
明示的加数が存在する再配置エントリ (32 ビットクラスのオブジェクトファイルの Elf32_Rela タイプなど) を示します。オブジェクトファイルには、複数の再配置セクションを指定できます。詳細は、再配置セクションを参照してください。
シンボルハッシュテーブルを示します。動的にリンクされたオブジェクトファイルには、シンボルハッシュテーブルが存在しなければなりません。現在、オブジェクトファイルにはハッシュテーブルは 1 つしか存在できませんが、この制約は将来、緩和されるかもしれません。詳細は、ハッシュテーブルセクションを参照してください。
動的リンクに関する情報を示します。現在、オブジェクトファイルには動的セクションを 1 つだけ含めることができます。詳細は、動的セクションを参照してください。
ファイルを示す情報を示します。詳細は、注釈セクションを参照してください。
このセクションは、ファイルの領域を占めないという点以外では SHT_PROGBITS に類似しています。このセクションにはデータは存在しませんが、sh_offset 構成要素には概念上のファイルオフセットが存在します。
明示的加数が存在しない再配置エントリ (32 ビットクラスのオブジェクトファイルの Elf32_Rel 型など) を示します。オブジェクトファイルには、複数の再配置セクションを指定できます。詳細は、再配置セクションを参照してください。
未定義のセマンティクスを保持する、予約済みのセクション。この型のセクションが存在するプログラムは、ABI に準拠しません。
初期設定関数を指すポインタの配列が存在するセクションを示します。配列内の各ポインタは、void を戻り値とする、パラメータを持たないプロシージャと見なされます。詳細は、初期設定および終了セクションを参照してください。
終了関数を指すポインタの配列が存在するセクションを示します。配列内の各ポインタは、void を戻り値とする、パラメータを持たないプロシージャと見なされます。詳細は、初期設定および終了セクションを参照してください。
ほかのすべての初期設定関数の前に呼び出される関数を指すポインタの配列が存在するセクションを示します。配列内の各ポインタは、void を戻り値とする、パラメータを持たないプロシージャと見なされます。詳細は、初期設定および終了セクションを参照してください。
セクショングループを示します。セクショングループとは、関連する一連のセクションであり、リンカーは 1 つの単位として扱う必要があります。タイプが SHT_GROUP であるセクションは、再配置可能オブジェクト内にしか存在できません。詳細は、グループセクションを参照してください。
拡張されたセクションインデックスが入ったセクション (シンボルテーブルに関連付けられている) を示します。シンボルテーブルによって参照されているセクションヘッダーインデックスのどれかにエスケープ値 SHN_XINDEX が含まれる場合は、関連する SHT_SYMTAB_SHNDX が必要です。
SHT_SYMTAB_SHNDX セクションは、Elf32_Word 値の配列です。関連するシンボルテーブルエントリごとに 1 つの値が存在します。これらの値は、シンボルテーブルエントリが定義されているセクションヘッダーインデックスを示します。一致する Elf32_Word に実際のセクションヘッダーインデックスが含まれるのは、対応するシンボルテーブルエントリの st_shndx フィールドにエスケープ値 SHN_XINDEX が含まれる場合だけです。そうでない場合、エントリは必ず SHN_UNDEF (0) です。
注釈セクションの処理は、セクション処理のデフォルトの規則に従って行われます。唯一の例外は、注釈セクションが割り当て不可能なメモリー内に存在する場合に発生します。セクションのヘッダーフラグ SHF_ALLOC が設定されていないと、リンカーは、リンク編集時に対応できない、このセクションに対するすべての再配置を黙って無視します。
デバッグ情報を識別します。このタイプのセクションは、リンカーの -s オプションを使用するか、あるいはリンク編集後に strip(1) を使用して、オブジェクトから取り除くことができます。
部分的に初期化されたシンボルを処理するデータを指定します。詳細は、移動セクションを参照してください。
同一データの複数のコピーを単一のコピーに削減することを可能にするセクション。詳細は、「COMDAT」セクションを参照してください。
追加のシンボル情報を指定します。詳細は、Syminfo テーブルセクションを参照してください。
このファイルで定義された、きめの細かいバージョンを指定します。詳細は、バージョン定義セクションを参照してください。
このファイルに必要な、きめの細かい依存関係を指定します。詳細は、バージョン依存セクションを参照してください。
シンボルとファイルに記述されたバージョン定義との関係を示すテーブルを指定します。詳細は、バージョンシンボルセクションを参照してください。
GOT からの相対アドレス指定を使用して参照される SPARC 固有のデータを識別します。つまり、シンボル _GLOBAL_OFFSET_TABLE_ に割り当てられたアドレスに対する相対的なオフセットです。64 ビット SPARC の場合、このセクション内のデータは、リンク編集時に GOT アドレスの {+-} 2^32 バイト内の場所に結合されなければなりません。
アプリケーションプログラムに対して予約されるインデックスの範囲の上限を示します。SHT_LOUSER から SHT_HIUSER までのセクション型は、現在の、または将来のシステム定義セクション型と競合することなくアプリケーションで使用できます。
他のセクション型の値は、保留されています。先に述べたとおり、インデックス 0 (SHN_UNDEF) のセクションヘッダーは存在します (このインデックスが未定義セクション参照を示してもです)。その値は表 7–13 の通りです。
表 7–13 ELF セクションヘッダーのテーブルエントリ: インデックス 0
名前 |
値 |
注意 |
---|---|---|
sh_name |
0 |
名前が存在しない |
sh_type |
SHT_NULL |
使用されない |
sh_flags |
0 |
フラグが存在しない |
sh_addr |
0 |
アドレスが存在しない |
sh_offset |
0 |
ファイルオフセットが存在しない |
sh_size |
0 |
サイズが存在しない |
sh_link |
SHN_UNDEF |
リンク情報が存在しない |
sh_info |
0 |
補助情報が存在しない |
sh_addralign |
0 |
整列が存在しない |
sh_entsize |
0 |
エントリが存在しない |
セクションヘッダーの sh_flags 構成要素は、セクションの属性を記述する 1 ビットフラグを保持します。
表 7–14 ELF セクションの属性フラグ
名前 |
値 |
---|---|
SHF_WRITE |
0x1 |
SHF_ALLOC |
0x2 |
SHF_EXECINSTR |
0x4 |
SHF_MERGE |
0x10 |
SHF_STRINGS |
0x20 |
SHF_INFO_LINK |
0x40 |
SHF_LINK_ORDER |
0x80 |
SHF_OS_NONCONFORMING |
0x100 |
SHF_GROUP |
0x200 |
SHF_TLS |
0x400 |
SHF_MASKOS |
0x0ff00000 |
SHF_ORDERED |
0x40000000 |
SHF_EXCLUDE |
0x80000000 |
SHF_MASKPROC |
0xf0000000 |
sh_flags にフラグビットが設定されると、属性がセクションに対して「オン」になります。設定されない場合は、属性が「オフ」になるか、または適用されません。定義されていない属性は保留され、0 に設定されています。
プロセス実行時にメモリーを占有するセクションを示します。いくつかの制御セクションは、オブジェクトファイルのメモリーイメージに存在しません。この属性は、これらのセクションに対してオフです。
重複を避けるためにマージ可能なデータを含むセクションを示します。同時に SHF_STRINGS フラグが設定されていない限り、このセクション内のデータ要素は統一されたサイズになります。各要素のサイズは、セクションヘッダーの sh_entsize フィールドで指定されます。同時に SHF_STRINGS フラグも設定されている場合は、データ要素はヌル文字で終わる文字列で構成されています。各文字のサイズは、セクションヘッダーの sh_entsize フィールドで指定されます。
ヌル文字で終わる文字列で構成されるセクションを示します。各文字のサイズは、セクションヘッダーの sh_entsize フィールドで指定されます。
このセクションは、リンカーに特別な順序の要求を追加します。この要求は、このセクションのヘッダーの sh_link フィールドが別のセクション (リンク先のセクション) を参照する場合に適用されます。このセクションを出力ファイル内の他のセクションと結合する場合、結合対象セクションと同じ相対的な順序で現われます。同様に、リンクされるセクションは、それが結合されるセクションに現われます。
特殊な sh_link 値である SHN_BEFORE および SHN_AFTER (表 7–11 を参照) は、順序付けされるセット内の他のすべてのセクションに対して、ソートされたセクションがそれぞれ前に付くまたは後に付くことを示します。順序付けの対象となるセクションの複数にこれらの特殊値の 1 つが存在する場合、入力ファイルが指定された順序は保存されます。
このフラグを使用する場合の典型的なものとして、アドレスの順序でテキストまたはデータセクションを参照するテーブルを構築する場合があります。
sh_link 順序付け情報が存在しない場合、出力ファイルの 1 つのセクション内で結合される 1 つの入力ファイルからのセクションは連続的になり、入力ファイル内の相対順序付けと同じ相対順序付けになります。複数の入力ファイルからの場合は、リンクコマンドで指定された順序になります。
このセクションは、正しくない動作を避けるために、特別な OS 固有の処理 (標準のリンク処理規則の範囲を越えるもの) を必要とするものです。このセクションが、これらのフィールドに対して sh_type 値を持つか、OS 固有の範囲内にある sh_flags ビットを含み、かつリンカーがこれらの値を認識しない場合は、リンカーはこのセクションを含むオブジェクトファイルを拒否し、エラーを出します。
このセクションは、1 つのセクショングループの (おそらく唯一の) 構成要素です。このセクションは、タイプ SHT_GROUP のセクションに参照されなければなりません。SHF_GROUP フラグは、再配置可能オブジェクト内に含まれるセクションに対してしか設定できません。詳細は、グループセクションを参照してください。
このセクションは、スレッド固有の領域を保持します。つまり、各個別の実行の流れは、このデータのインスタンスをそれぞれ別個に持つことを意味します。詳細は、第 8 章「スレッド固有領域 (TLS)」を参照してください。
このセクションは、同じ型の他のセクションと順序付けられます。順序付けられるセクションは、sh_link エントリでポイントされるセクション内で結合されます。順序付けられるセクションの sh_link エントリは、自身を指し示すことがあります。
順序付けられるセクションの sh_info エントリが同一入力ファイル内の有効セクションの場合、順序付けられるセクションは、sh_info エントリでポイントされるセクションの出力ファイル内の相対順序付けに基づいて整列されます。
特殊なsh_info 値である SHN_BEFORE または SHN_AFTER (表 7–11 を参照) は、整列対象セクションが順序付け対象となる他のすべてのセクションの前または後に存在することを意味します。順序付けの対象となるセクションの複数にこれらの特殊値の 1 つが存在する場合、入力ファイルが指定された順序は保存されます。
sh_info 順序付け情報が存在しない場合、出力ファイルの 1 つのセクション内で結合される 1 つの入力ファイルからのセクションは連続的になり、入力ファイル内の相対順序付けと同じ相対順序付けになります。複数の入力ファイルからの場合は、リンクコマンドで指定された順序になります。
このセクションは、実行可能オブジェクトまたは共有オブジェクトのリンク編集への入力から除かれます。このフラグは、SHF_ALLOC フラグが設定されている場合、またはセクションに対する参照が存在する場合、無視されます。
セクションヘッダーの 2 つの構成要素 sh_link と sh_info は、セクション型に従って特殊な情報を保持します。
表 7–15 ELF sh_link と sh_info の解釈
sh_type |
sh_link |
sh_info |
---|---|---|
SHT_DYNAMIC |
関連付けられている文字列テーブルのセクションヘッダーインデックス |
0 |
SHT_HASH |
関連付けられているシンボルテーブルのセクションヘッダーインデックス |
0 |
SHT_REL SHT_RELA |
関連付けられているシンボルテーブルのセクションヘッダーインデックス | |
SHT_SYMTAB SHT_DYNSYM |
関連付けられている文字列テーブルのセクションヘッダーインデックス |
最後のローカルシンボルのシンボルテーブルインデックスより 1 大きい (STB_LOCAL に対応する) |
SHT_GROUP |
関連付けられているシンボルテーブルのセクションヘッダーインデックス |
関連付けられているシンボルテーブル内のエントリの、シンボルテーブルインデックス。指定されたシンボルテーブルエントリの名前は、そのセクショングループのシグニチャを提供する |
SHT_SYMTAB_SHNDX |
関連付けられているシンボルテーブルのセクションヘッダーインデックス |
0 |
SHT_SUNW_move |
関連付けられているシンボルテーブルのセクションヘッダーインデックス |
0 |
SHT_SUNW_COMDAT |
0 |
0 |
SHT_SUNW_syminfo |
関連付けられているシンボルテーブルのセクションヘッダーインデックス |
関連付けられている .dynamic セクションのセクションヘッダーインデックス |
SHT_SUNW_verdef |
関連付けられている文字列テーブルのセクションヘッダーインデックス |
セクション内のバージョン定義数 |
SHT_SUNW_verneed |
関連付けられている文字列テーブルのセクションヘッダーインデックス |
セクション内のバージョン依存数 |
SHT_SUNW_versym |
関連付けられているシンボルテーブルのセクションヘッダーインデックス |
0 |
さまざまなセクションがプログラム情報と制御情報を保持します。以下の表に示すセクションはシステムで使用されますが、これらのセクションには指定された型と属性が存在します。
表 7–16 ELF 特殊セクション
名前 |
型 |
属性 |
---|---|---|
.bss |
SHT_NOBITS |
SHF_ALLOC + SHF_WRITE |
.comment |
SHT_PROGBITS |
なし |
.data |
SHT_PROGBITS |
SHF_ALLOC + SHF_WRITE |
.data1 |
SHT_PROGBITS |
SHF_ALLOC + SHF_WRITE |
.dynamic |
SHT_DYNAMIC |
SHF_ALLOC + SHF_WRITE |
.dynstr |
SHT_STRTAB |
SHF_ALLOC |
.dynsym |
SHT_DYNSYM |
SHF_ALLOC |
.fini |
SHT_PROGBITS |
SHF_ALLOC + SHF_EXECINSTR |
.fini_array |
SHT_FINI_ARRAY |
SHF_ALLOC + SHF_WRITE |
.got |
SHT_PROGBITS | |
.hash |
SHT_HASH |
SHF_ALLOC |
.init |
SHT_PROGBITS |
SHF_ALLOC + SHF_EXECINSTR |
.init_array |
SHT_INIT_ARRAY |
SHF_ALLOC + SHF_WRITE |
.interp |
SHT_PROGBITS |
プログラムインタプリタを参照 |
.note |
SHT_NOTE |
なし |
.plt |
SHT_PROGBITS | |
.preinit_array |
SHT_PREINIT_ARRAY |
SHF_ALLOC + SHF_WRITE |
.rela |
SHT_RELA |
なし |
.relname |
SHT_REL |
再配置セクションを参照 |
.relaname |
SHT_RELA |
再配置セクションを参照 |
.rodata |
SHT_PROGBITS |
SHF_ALLOC |
.rodata1 |
SHT_PROGBITS |
SHF_ALLOC |
.shstrtab |
SHT_STRTAB |
なし |
.strtab |
SHT_STRTAB |
後続の .strtab 記述を参照 |
.symtab |
SHT_SYMTAB | |
.symtab_shndx |
SHT_SYMTAB_SHNDX | |
.tbss |
SHT_NOBITS |
SHF_ALLOC + SHF_WRITE + SHF_TLS |
.tdata |
SHT_PROGBITS |
SHF_ALLOC + SHF_WRITE + SHF_TLS |
.tdata1 |
SHT_PROGBITS |
SHF_ALLOC + SHF_WRITE + SHF_TLS |
.text |
SHT_PROGBITS |
SHF_ALLOC + SHF_EXECINSTR |
.SUNW_bss |
SHT_NOBITS |
SHF_ALLOC + SHF_WRITE |
.SUNW_heap |
SHT_PROGBITS |
SHF_ALLOC + SHF_WRITE |
.SUNW_move |
SHT_SUNW_move |
SHF_ALLOC |
.SUNW_reloc |
SHT_REL SHT_RELA |
SHF_ALLOC |
.SUNW_syminfo |
SHT_SUNW_syminfo |
SHF_ALLOC |
.SUNW_version |
SHT_SUNW_verdef SHT_SUNW_verneed SHT_SUNW_versym |
SHF_ALLOC |
プログラムのメモリーイメージで使用される初期化されてい ないデータ。システムは、プログラムが実行を開始すると 0 でデータを初期化することになっています。このセクションは、セクション型 SHT_NOBITS で示しているとおり、ファイル領域を占めません。
コメント情報 (通常、コンパイルシステムのコンポーネントが使用)。このセクションは、mcs(1)により操作できます。
プログラムのメモリーイメージで使用される、初期化済みのデータ。
動的リンク情報。 詳細は、動的セクションを参照してください。
動的リンクに必要な文字列 (最も一般的には、シンボルテーブルエントリに関連付けられている名前を表す文字列)。
動的リンクシンボルテーブル。詳細は、シンボルテーブルセクションを参照してください。
このセクションを含む実行可能ファイルまたは共有オブジェクトの単一の終了関数で使用される実行可能命令。詳細は、初期設定および終了ルーチンを参照してください。
このセクションを含む実行可能ファイルまたは共有オブジェクトの単一の終了配列で使用される関数ポインタの配列。詳細は、初期設定および終了ルーチンを参照してください。
大域オフセットテーブル。詳細は、大域オフセットテーブル (プロセッサ固有)を参照してください。
シンボルハッシュテーブル。詳細は、ハッシュテーブルセクションを参照してください。
このセクションを含む実行可能ファイルまたは共有オブジェクトの単一の初期化関数で使用される実行可能命令。詳細は、初期設定および終了ルーチンを参照してください。
このセクションを含む実行可能ファイルまたは共有オブジェクトの単一の初期化配列で使用される関数ポインタの配列。詳細は、初期設定および終了ルーチンを参照してください。
プログラムインタプリタのパス名。詳細は、プログラムインタプリタを参照してください。
注釈セクションに記載された形式の情報。
プロシージャのリンクテーブル。詳細は、プロシージャのリンクテーブル (プロセッサ固有)を参照してください。
このセクションを含む実行可能ファイルまたは共有オブジェクトの単一の「初期設定前」の配列に使用される関数ポインタの配列。詳細は、初期設定および終了ルーチンを参照してください。
特定のセクションに適用されない再配置情報。このセクションの用途の 1 つは、レジスタの再配置です。詳細は、レジスタシンボルを参照してください。
再配置情報 (詳細は、再配置セクションを参照)。再配置が存在する読み込み可能セグメントがファイルに存在する場合、これらのセクションの属性として SHF_ALLOC ビットがオンになります。そうでない場合、このビットはオフになります。慣例により、name は再配置が適用されるセクションの名前になります。したがって、.text の再配置セクションには、通常 .rel.text または .rela.text という名前が存在します。
読み取り専用データ (通常はプロセスイメージの書き込み不可セグメントに使用)。詳細は、プログラムヘッダーを参照してください。
セクション名。
文字列 (最も一般的には、シンボルテーブルエントリに関連付けられている名前を表す文字列)。シンボル文字列テーブルが存在する読み込み可能セグメントがファイルに存在する場合、セクションの属性として SHF_ALLOC ビットがオンになります。そうでない場合、このビットはオフになります。
シンボルテーブル (詳細は、シンボルテーブルセクションを参照)。シンボルテーブルが存在する読み込み可能セグメントがファイルに存在する場合、セクションの属性として SHF_ALLOC ビットがオンになります。そうでない場合、このビットはオフになります。
このセクションには、.symtab による指定に従い、特別なシンボルテーブルセクションインデックス配列が保持されます。 関連付けられたシンボルテーブルセクションに SHF_ALLOC ビットが含まれる場合、このセクションの属性も SHF_ALLOC ビットを含みます。そうでない場合、このビットはオフになります。
このセクションは、プログラムのメモリーイメージで使用される、初期化されていないスレッド固有データを保持します。データが新しい実行フロー用に具体化されると、システムはデータを 0 で初期化します。このセクションは、セクション型 SHT_NOBITS で示しているとおり、ファイル領域を占めません。詳細は、第 8 章「スレッド固有領域 (TLS)」を参照してください。
これらのセクションは、プログラムのメモリーイメージで使用される、初期化されたスレッド固有データを保持します。その内容のコピーは、それぞれ新しい実行フロー用にシステムによって具体化されます。詳細は、第 8 章「スレッド固有領域 (TLS)」を参照してください。
プログラムの「テキスト」すなわち実行可能命令。
プログラムのメモリーイメージで使用される、共有オブジェクトの部分的に初期化されたデータ。データは実行時に初期化されます。このセクションは、セクション型 SHT_NOBITS で示しているとおり、ファイル領域を占めません。
dldump(3DL) により作成される動的実行可能ファイルのヒープ。
部分的に初期化されたデータに関する追加情報。詳細は、移動セクションを参照してください。
再配置情報 (詳細は、再配置セクションを参照)。このセクションは再配置セクションが連結されたものであり、個々の再配置レコードに対するより良い参照のローカル性 (局所性) を与えます。再配置レコード自身のオフセットのみが意味があり、したがってセクション sh_info の値は 0 です。
シンボルテーブルの追加情報。詳細は、Syminfo テーブルセクションを参照してください。
バージョン情報。詳細は、バージョン管理セクションを参照してください。
ドット (.) 接頭辞付きのセクション名はシステムにおいて予約されています。これらのセクションの既存の意味が満足できるものであれば、アプリケーションはこれらのセクションを使用できます。アプリケーションは、ドット (.) 接頭辞なしの名前を使用して、システムで予約されたセクションとの競合を回避することができます。オブジェクトファイル形式では、上記リストに記載されていないセクションが定義できます。オブジェクトファイルには、同じ名前を持つ複数のセクションが存在できます。
プロセッサアーキテクチャに対して予約されるセクション名は、アーキテクチャ名の省略形をセクション名の前に入れることで作成されます。セクション名の前に、e_machine に対して使用されるアーキテクチャ名を入れる必要があります。たとえば、.Foo.psect は、FOO アーキテクチャで定義される psect セクションです。
既存の拡張セクションは、従来から使用されている名前をそのまま使用しています。
COMDAT セクションは、セクション名 (sh_name) で一意に示されます。 リンカーが、同じセクション名の SHT_SUNW_COMDAT 型の複数のセクションと出会うと、最初のセクションが保持され、残りのセクションは捨てられます。捨てられた SHT_SUNW_COMDAT セクションに適用された再配置はすべて無視されます。捨てられたセクションで定義されたシンボルもすべて削除されます。
また、リンカーは、コンパイラに -xF オプションを指定して行うセクション再順序付けで用いられるセクション命名規約をサポートします。関数が .sectname%funcname という名前のセクションに入れられると、保持された最終的な SHT_SUNW_COMDAT セクションが、.sectname で示されるセクションに合体します。この方法を使用すると、SHT_SUNW_COMDAT セクションは最終的に .text、.data、またはほかのセクションに入れられます。
セクションの中には、相互関連のあるグループがあるものがあります。たとえば、インライン関数の out-of-line 定義では、実行可能命令を含むセクション以外にも、別の情報が必要になる場合もあります。この別の情報は、参照される文字定数を含む読み取り専用のデータセクション、1 つまたは複数のデバッギング情報セクション、およびその他の情報セクションなどです。さらに、これらのセクション間で内部参照がある場合もあります。別のオブジェクトからの重複によって、これらのセクションの 1 つが削除 (あるいは、置換) されると、このような参照は意味を成さなくなります。したがって、このようなグループをリンクされたオブジェクトに組み込んだり、オブジェクトから削除したりするときは、1 つの単位として扱います。
タイプ SHT_GROUP のセクションは、そういったセクションのグループ化を定義します。含んでいるオブジェクトのシンボルテーブルのうちの 1 つからのシンボル名が、そのセクショングループについてのシグニチャを提供します。SHT_GROUP セクションのセクションヘッダーが、識別シンボルエントリを指定します。sh_link 構成要素はそのエントリを含むシンボルテーブルセクションのセクションヘッダーインデックスを含み、sh_info 構成要素はその識別エントリのシンボルテーブルインデックスを含みます。そのセクションヘッダーの sh_flags 構成要素は、0 を含みます。そのセクションの名前 (sh_name) は指定されません。
SHT_GROUP セクションのセクションデータは、Elf32_Word エントリの配列です。最初のエントリは、フラグです。残りのエントリは、セクションヘッダーのインデックスのシーケンスです。
表 7–17 ELF グループセクションのフラグ
名前 |
値 |
---|---|
GRP_COMDAT |
0x1 |
GRP_COMDAT は COMDAT グループであることを示します。これは、同じグループシグニチャを持つものとして重複が定義されている場合には、他のオブジェクトファイル内の他の COMDAT グループと重複する可能性があります。その場合には、重複グループのうち 1 つのみがリンカーによって保持されます。残りのグループの構成要素は破棄されます。
SHT_GROUP セクション内のセクションヘッダーインデックスは、そのグループを構成するセクションを識別します。これらのセクションは、SHF_GROUP フラグを sh_flags セクションヘッダー構成要素内に設定していなければなりません。リンカーがそのセクショングループを削除することを決めた場合、リンカーはそのグループのすべての構成要素を削除します。
未決定の参照を残すことなく、シンボルテーブルの処理を最小限にしてグループの削除を行うには、次の規則に従う必要があります。
グループを形成するセクションへのそのグループの外のセクションからの参照は、STB_GLOBAL または STB_WEAK 結合とセクションインデックス SHN_UNDEF を伴うシンボルテーブルエントリを介して行わなければなりません。その参照を含むオブジェクト内に同じシンボルの定義がある場合は、その参照とは別のシンボルテーブルエントリを持つ必要があります。そのグループの外のセクションは、そのグループのセクション内に含まれるアドレスについて STB_LOCAL 結合を持つシンボルを参照しない (タイプ STT_SECTION を持つシンボルを含む) 可能性があります。
グループを形成するセクションにグループの外から非シンボル参照を行なってはなりません。たとえば、sh_link または sh_info 構成要素内でのグループ構成要素のセクションヘッダーインデックスは使用できません。
グループのセクションの 1 つに関連して定義されたシンボルテーブルエントリは、グループの構成要素が破棄されると削除されることがあります。この削除が行われるのは、シンボルテーブルエントリが含まれるシンボルテーブルセクションがグループの一部ではない場合です。
ハッシュテーブルは、シンボルテーブルへのアクセスを提供する Elf32_Word または Elf64_Word オブジェクトから構成されます。SHT_HASH セクションは、このハッシュテーブルを提供します。ハッシュが関連付けられているシンボルテーブルは、ハッシュテーブルのセクションヘッダーの sh_link エントリに指定されます。ハッシュテーブルの構造についての説明をわかりやすくするためにラベルを図 7–4 に示します。ただし、ラベルは仕様の一部ではありません。
bucket 配列には nbucket 個のエントリが存在し、chain 配列には nchain 個のエントリが存在します。インデックスは 0 から始まります。bucket と chain は、どちらもシンボルテーブルインデックスを保持します。連鎖テーブルエントリは、シンボルテーブルに対応しています。シンボルテーブルエントリ数は、nchain に等しくなければなりません。したがって、シンボルテーブルインデックスにより、連鎖テーブルエントリも選択されます。
ハッシュ関数はシンボル名を受け取り、bucket インデックスの計算に使用できる値を返します。つまり、ハッシュ関数がある名前に対して値 x を返した場合、bucket [x%nbucket] はインデックス y を返します。これは、シンボルテーブルと連鎖テーブルの両方へのインデックスです。シンボルテーブルエントリが目的の名前でなかった場合、chain[y] は、同じハッシュ値が存在する次のシンボルテーブルエントリを返します。
目的の名前を持つシンボルテーブルエントリが選択されるか、chain エントリの値が STN_UNDEF になるまで、chain リンクをたどることができます。
ハッシュ関数を次に示します。
unsigned long elf_Hash(const unsigned char *name) { unsigned long h = 0, g; while (*name) { h = (h << 4) + *name++; if (g = h & 0xf0000000) h ^= g>> 24; h &= ~g; } return h; }
一般に、ELF ファイル内では、初期設定されたデータ変数はオブジェクトファイル内で維持されます。データ変数が非常に大きく、初期設定された (ゼロ以外の) 要素が少数の場合でも、変数全体はやはりオブジェクトファイルで維持されます。
サイズの大きな部分的に初期設定されたデータ変数を含むオブジェクト (FORTRAN
COMMON ブロックなどのような) は、多大なディスクスペースオーバーヘッドをもたらすことがあります。SHT_SUNW_move セクションは、これらのデータ変数を圧縮するメカニズムを提供します。これにより、関連するオブジェクトのディスクサイズを減らすことができます。
SHT_SUNW_move セクションは、ELF32_Move または Elf64_Move 型の複数のエントリを含みます。これらのエントリはデータ変数を一時的項目 (.bss) として定義することが可能で、そのためオブジェクトファイル内にスペースを占めることなく、実行時にオブジェクトのメモリーイメージに反映させることができます。移動レコードは、完全なデータ変数を構成するためにデータについてメモリーイメージがどのように初期設定されるかを確立します。
ELF32_Move および Elf64_Move エントリは次のように定義されます。
typedef struct { Elf32_Lword m_value; Elf32_Word m_info; Elf32_Word m_poffset; Elf32_Half m_repeat; Elf32_Half m_stride; } Elf32_Move; #define ELF32_M_SYM(info) ((info)>>8) #define ELF32_M_SIZE(info) ((unsigned char)(info)) #define ELF32_M_INFO(sym, size) (((sym)<<8)+(unsigned char)(size)) typedef struct { Elf64_Lword m_value; Elf64_Xword m_info; Elf64_Xword m_poffset; Elf64_Half m_repeat; Elf64_Half m_stride; } Elf64_Move; #define ELF64_M_SYM(info) ((info)>>8) #define ELF64_M_SIZE(info) ((unsigned char)(info)) #define ELF64_M_INFO(sym, size) (((sym)<<8)+(unsigned char)(size))
これらの構造の要素は次のとおりです。
初期設定値で、この値はメモリーイメージへ移されます。
初期設定が適用されるものに関連するシンボルテーブルインデックス、および初期設定されるオフセットのサイズ (単位: バイト)。構成要素の下位 8 ビットはサイズを定義し、1、2、4、または 8 になります。上位バイトはシンボルインデックスを定義します。
初期設定が適用される関連シンボルからの相対オフセット。
繰り返し回数。
スキップの数。この値は、繰り返し初期設定を実行する際にスキップするユニットの数を示します。1 ユニットは m_info で定義された初期設定オブジェクトのサイズです。m_stride の値が 0 の場合、初期設定を m_repeat ユニット連続して行うことを示します。
次のデータ定義は、通常、オブジェクトファイル内で 0x8000 バイトを消費します。
typedef struct { int one; char two; } Data Data move[0x1000] = { {0, 0}, {1, '1'}, {0, 0}, {0xf, 'F'}, {0xf, 'F'}, {0, 0}, {0xe, 'E'}, {0, 0}, {0xe, 'E'} };
SHT_SUNW_move セクションを使用して、データ項目を .bss セクションへ移動し、関連する移動エントリで初期設定することができます。
$ elfdump -s data | fgrep move [17] 0x00020868 0x00008000 OBJT GLOB 0 .bss move $ elfdump -m data Move Section: .SUNW_move offset ndx size repeat stride value with respect to 0x8 0x17 4 1 0 0x1 move 0xc 0x17 1 1 0 0x31 move 0x18 0x17 4 2 2 0xf move 0x1c 0x17 1 2 8 0x46 move 0x28 0x17 4 2 4 0xe move 0x2c 0x17 1 2 16 0x45 move |
再配置可能オブジェクトから提供される移動セクションは連結され、リンカーにより作成されるオブジェクト内に出力されます。 ただし、次の条件が成り立つ場合、リンカーは移動エントリを処理し、その内容を従来のデータ項目に拡張します。
ソフトウェアを開発して販売する場合、オブジェクトファイルに特別な情報を付加して、他のプログラムから準拠性や互換性などを確認できるようにしたいことがあります。SHT_NOTE 型のセクションと PT_NOTE 型のプログラムヘッダー要素は、この目的に対して使用できます。
次の図に示すように、セクションとプログラムヘッダー要素内の注釈情報は、任意の数のエントリを保持します。64 ビットおよび 32 ビットのオブジェクトについては、各エントリはターゲットプロセッサの形式になっている 4 バイトワードの配列です。注釈情報の構造についての説明を容易にするためにラベルを図 7–6 に示します。ただし、ラベルは仕様の一部ではありません。
この構造体の要素を次に示します。
名前の先頭 namesz バイトには、エントリの所有者または作者を示す、ヌル文字で終わっている文字列が存在します。名前の競合を回避するための正式な機構は存在しません。慣例では、ベンダーは識別子として自身の名前 (“XYZ Computer Company” など) を使用します。name が存在しない場合、namesz は 0 になります。name の領域は、パッドを使用して、4 バイトに整列します。必要であれば namesz は、パッドの長さを含みません。
desc の先頭 descsz バイトは、注釈記述を保持します。注釈の記述が存在しない場合、descsz は 0 になります。desc の領域は、必要であればパッドを使用して、4 バイトに整列します。descsz はパットの長さを含みません。
注釈の解釈を示します。各エントリの作者は、自分で種類を管理します。1 つの type 値に関して複数の解釈が存在する場合があります。したがって、注釈の記述を認識するには、name と type の両方を認識しなければなりません。type は現在、負でない値でなければなりません。
次の図に示す注釈セグメントは、2 つのエントリを保持しています。
システムは注釈情報 (名前が存在せず (namesz == 0)、名前の長さが 0 (name[0] == '\0')) を予約していますが、現在 type を定義していません。他のすべての名前には、少なくとも 1 つのヌル以外の文字が存在しなければなりません。
再配置は、記号参照を記号定義に関連付ける処理です。たとえば、プログラムが関数を呼び出すとき、関連付けられている呼び出し命令は、実行時に適切な宛先アドレスに制御を渡さなければなりません。再配置可能ファイルには、セクション内容の変更方法を示す情報が存在しなければなりません。その結果、実行可能オブジェクトファイルと共有オブジェクトファイルは、プロセスのプログラムイメージに関する正しい情報を保持できます。再配置エントリは、これらのデータを保持します。
再配置エントリは、以下の構造体 (sys/elf.h で定義) を持つことができます。
typedef struct { Elf32_Addr r_offset; Elf32_Word r_info; } Elf32_Rel; typedef struct { Elf32_Addr r_offset; Elf32_Word r_info; Elf32_Sword r_addend; } Elf32_Rela; typedef struct { Elf64_Addr r_offset; Elf64_Xword r_info; } Elf64_Rel; typedef struct { Elf64_Addr r_offset; Elf64_Xword r_info; Elf64_Sxword r_addend; } Elf64_Rela;
この構造体の要素を次に示します。
この構成要素は、再配置処理を適用する位置を与えます。オブジェクトファイルが異なると、この構成要素の解釈が多少異なります。
再配置可能ファイルの場合、値はセクションのオフセットを示します。再配置セクション自身は、ファイル内の別セクションの変更方法を示します。再配置オフセットは、2 番目のセクション内の領域を指定します。
実行可能ファイルまたは共有オブジェクトの場合、値は再配置の影響を受ける領域の仮想アドレスを示します。この情報により、再配置エントリは、実行時リンカーにとって、より意味のあるものになります。
関連するプログラムによるアクセスの効率を高めるため、構成要素の解釈はオブジェクトファイルによって異なりますが、再配置タイプの意味は同じになります。
この構成要素は、再配置が行われなければならないシンボルテーブルインデックスと、適用される再配置の種類を与えます。たとえば、呼び出し命令の再配置エントリは、呼び出される関数のシンボルテーブルインデックスを保持します。インデックスが STN_UNDEF (未定義シンボルインデックス) の場合、再配置はシンボル値として 0 を使用します。
再配置の種類はプロセッサに固有です。再配置エントリの再配置の種類またはシンボルテーブルインデックスは、それぞれ ELF32_R_TYPE または ELF32_R_SYM をエントリの r_info 構成要素に適用した結果です。
#define ELF32_R_SYM(info) ((info)>>8) #define ELF32_R_TYPE(info) ((unsigned char)(info)) #define ELF32_R_INFO(sym, type) (((sym)<<8)+(unsigned char)(type)) #define ELF64_R_SYM(info) ((info)>>32) #define ELF64_R_TYPE(info) ((Elf64_Word)(info)) #define ELF64_R_INFO(sym, type) (((Elf64_Xword)(sym)<<32)+ \ (Elf64_Xword)(type))
Elf64_Rel および Elf64_Rela 構造の場合、r_info フィールドはさらに 8 ビットの識別子と 24 ビットの付随的なデータに分割されます。
#define ELF64_R_TYPE_DATA(info) (((Elf64_Xword)(info)<<32)>>40) #define ELF64_R_TYPE_ID(info) (((Elf64_Xword)(info)<<56)>>56) #define ELF64_R_TYPE_INFO(data, type) (((Elf64_Xword)(data)<<8)+ \ (Elf64_Xword)(type))
この構成要素は、再配置可能フィールドに格納される値の計算に使用される定数加数を指定します。
Rela エントリには、明示的加数が含まれます。Rel エントリには、変更される位置に暗黙の加数が存在します。32 ビットおよび 64 ビット SPARC では、それぞれ Elf32_Rela および Elf64_Rela 再配置エントリのみを使用します。したがって、r_addend 構成要素は再配置加数として機能します。x86 は、Elf32_Rel 再配置エントリのみを使用します。再配置対象のフィールドは、加数を保持します。すべての場合において、加数と計算された結果は同じバイト順序を使用します。
再配置セクションは、ほかに 2 つのセクションを参照することがあります。1 つは sh_info セクションヘッダーエントリにより示されるシンボルテーブルで、もう 1 つは sh_link セクションヘッダーエントリにより示される変更対象のセクションです。セクション に、各セクションの関係を示します。再配置可能オブジェクト内に再配置セクションが存在するが、実行可能ファイルおよび共有オブジェクトの場合には省略可能である場合、sh_link エントリが必要になります。再配置オフセットが存在すれば、再配置を実行できます。
再配置エントリには、次の図に示す命令およびデータフィールドの変更方法が記述されます。ビット番号はボックスの下隅に表示されます。
SPARC プラットフォームの場合、再配置エントリはバイト (byte8)、ハーフワード (half16)、またはワード (word、その他) に適用されます。
64 ビット SPARC では、再配置は拡張ワード (xword64) にも適用されます。
x86 の場合、再配置エントリはワード (word32) に適用されます。
word32 は、任意バイト整列が存在する 4 バイトを占める 32 ビットフィールドを指定します。これらの値は、x86 アーキテクチャにおけるほかのワード値と同じバイト順序を使用します。
いずれの場合でも r_offset 値は、影響が与えられる領域の先頭バイトのオフセットまたは仮想アドレスを指定します。再配置タイプは、変更されるビットと、これらのビットの値の計算方法を指定します。
以下の再配置型の計算では、操作により、再配置可能ファイルが実行可能ファイルまたは共有オブジェクトファイルに変換されることが仮定されています。概念上、リンカーは 1 つまたは複数の再配置可能ファイルを併合して出力します。リンカーは、まず入力ファイルの結合/配置方法を決めます。次にシンボル値を更新します。最後に再配置を行います。実行可能オブジェクトファイルと共有オブジェクトファイルに適用される再配置は類似しており、同じ結果を実現します。このセクションの表では、以下の表記が使用されています。
再配置可能フィールドの値を計算するために使用される加数。
実行時に共有オブジェクトがメモリーに読み込まれるベースアドレス。一般に共有オブジェクトファイルは 0 ベース仮想アドレスで作成されますが、実行アドレスは異なります。詳細は、プログラムヘッダーを参照してください。
実行時に再配置エントリのシンボルのアドレスが存在する大域オフセットテーブルへのオフセット。詳細は、大域オフセットテーブル (プロセッサ固有)を参照してください。
大域オフセットテーブルのアドレス。詳細は、大域オフセットテーブル (プロセッサ固有)を参照してください。
シンボルに対するプロシージャのリンクテーブルエントリのセクションオフセットまたはアドレス。プロシージャのリンクテーブル (プロセッサ固有)を参照してください。
再配置される領域のセクションオフセットまたはアドレス (r_offset を使用して計算)。
インデックスが再配置エントリ内に存在するシンボルの値。
次の表に示すフィールド名は、再配置型がオーバーフローを検査するかどうかを通知します。計算される再配置値は意図したフィールドより大きい場合があり、再配置型によっては値の適合を検証 (V) したり結果を切り捨てたり (T) することがあります。たとえば、V-simm13 は、計算された値が simm13 フィールドの外部に 0 以外の有意ビットを持つことがないことを意味します。
表 7–18 SPARC: ELF 再配置型
名前 |
値 |
フィールド |
計算 |
---|---|---|---|
R_SPARC_NONE |
0 |
なし |
なし |
R_SPARC_8 |
1 |
V-byte8 |
S + A |
R_SPARC_16 |
2 |
V-half16 |
S + A |
R_SPARC_32 |
3 |
V-word32 |
S + A |
R_SPARC_DISP8 |
4 |
V-byte8 |
S + A - P |
R_SPARC_DISP16 |
5 |
V-half16 |
S + A - P |
R_SPARC_DISP32 |
6 |
V-disp32 |
S + A - P |
R_SPARC_WDISP30 |
7 |
V-disp30 |
(S + A - P)>> 2 |
R_SPARC_WDISP22 |
8 |
V-disp22 |
(S + A - P)>> 2 |
R_SPARC_HI22 |
9 |
T-imm22 |
(S + A)>> 10 |
R_SPARC_22 |
10 |
V-imm22 |
S + A |
R_SPARC_13 |
11 |
V-simm13 |
S + A |
R_SPARC_LO10 |
12 |
T-simm13 |
(S + A) & 0x3ff |
R_SPARC_GOT10 |
13 |
T-simm13 |
G & 0x3ff |
R_SPARC_GOT13 |
14 |
V-simm13 |
G |
R_SPARC_GOT22 |
15 |
T-simm22 |
G>> 10 |
R_SPARC_PC10 |
16 |
T-simm13 |
(S + A - P) & 0x3ff |
R_SPARC_PC22 |
17 |
V-disp22 |
(S + A - P)>> 10 |
R_SPARC_WPLT30 |
18 |
V-disp30 |
(L + A - P)>> 2 |
R_SPARC_COPY |
19 |
なし |
なし |
R_SPARC_GLOB_DAT |
20 |
V-word32 |
S + A |
R_SPARC_JMP_SLOT |
21 |
なし |
「R_SPARC_JMP_SLOT」を参照 |
R_SPARC_RELATIVE |
22 |
V-word32 |
B + A |
R_SPARC_UA32 |
23 |
V-word32 |
S + A |
R_SPARC_PLT32 |
24 |
V-word32 |
L + A |
R_SPARC_HIPLT22 |
25 |
T-imm22 |
(L + A)>> 10 |
R_SPARC_LOPLT10 |
26 |
T-simm13 |
(L + A) & 0x3ff |
R_SPARC_PCPLT32 |
27 |
V-word32 |
L + A - P |
R_SPARC_PCPLT22 |
28 |
V-disp22 |
(L + A - P)>> 10 |
R_SPARC_PCPLT10 |
29 |
V-simm13 |
(L + A - P) & 0x3ff |
R_SPARC_10 |
30 |
V-simm10 |
S + A |
R_SPARC_11 |
31 |
V-simm11 |
S + A |
R_SPARC_HH22 |
34 |
V-imm22 |
(S + A)>> 42 |
R_SPARC_HM10 |
35 |
T-simm13 |
((S + A)>> 32) & 0x3ff |
R_SPARC_LM22 |
36 |
T-imm22 |
(S + A)>> 10 |
R_SPARC_PC_HH22 |
37 |
V-imm22 |
(S + A - P)>> 42 |
R_SPARC_PC_HM10 |
38 |
T-simm13 |
((S + A - P)>> 32) & 0x3ff |
R_SPARC_PC_LM22 |
39 |
T-imm22 |
(S + A - P)>> 10 |
R_SPARC_WDISP16 |
40 |
V-d2/disp14 |
(S + A - P)>> 2 |
R_SPARC_WDISP19 |
41 |
V-disp19 |
(S + A - P)>> 2 |
R_SPARC_7 |
43 |
V-imm7 |
S + A |
R_SPARC_5 |
44 |
V-imm5 |
S + A |
R_SPARC_6 |
45 |
V-imm6 |
S + A |
R_SPARC_HIX22 |
48 |
V-imm22 |
((S + A) ^ 0xffffffffffffffff)>> 10 |
R_SPARC_LOX10 |
49 |
T-simm13 |
((S + A) & 0x3ff) | 0x1c00 |
R_SPARC_H44 |
50 |
V-imm22 |
(S + A)>> 22 |
R_SPARC_M44 |
51 |
T-imm10 |
((S + A)>> 12) & 0x3ff |
R_SPARC_L44 |
52 |
T-imm13 |
(S + A) & 0xfff |
R_SPARC_REGISTER |
53 |
V-word32 |
S + A |
R_SPARC_UA16 |
55 |
V-half16 |
S + A |
R_SPARC_GOTDATA_HIX22 |
80 |
T-imm22 |
((S + A - GOT)>> 10) ^ ((S + A - GOT)>> 42) |
R_SPARC_GOTDATA_LOX22 |
81 |
T-imm13 |
((S + A - GOT) & 0x3ff) | (0x1c00 ^~ (((S + A - GOT)>> 50) & 0x1c00)) |
R_SPARC_GOTDATA_OP_HIX22 |
82 |
T-imm22 |
((S + A - GOT)>> 10) ^ ((S + A - GOT)>> 42) |
R_SPARC_GOTDATA_OP_LOX22 |
83 |
T-imm13 |
((S + A - GOT) & 0x3ff) | (0x1c00 ^~ (((S + A - GOT)>> 50) & 0x1c00)) |
R_SPARC_GOTDATA_OP |
84 |
Word32 |
特殊 |
スレッド固有領域の参照に使用できる再配置はほかにも存在します。これらの再配置については、第 8 章「スレッド固有領域 (TLS)」で説明しています。
いくつかの再配置型には、単純な計算を超えた意味が存在します。
R_SPARC_LO10 に似ていますが、シンボルの大域オフセットテーブルエントリのアドレスを参照する点が異なります。また、 R_SPARC_GOT10 は、大域オフセットテーブルの作成をリンカーに指示します。
R_SPARC_13 に似ていますが、シンボルの大域オフセットテーブルエントリのアドレスを参照する点が異なります。また、 R_SPARC_GOT13 は、大域オフセットテーブルの作成をリンカーに指示します。
R_SPARC_22 に似ていますが、シンボルの大域オフセットテーブルエントリのアドレスを参照する点が異なります。また、 R_SPARC_GOT22 は、大域オフセットテーブルの作成をリンカーに指示します。
R_SPARC_WDISP30 に似ていますが、シンボルのプロシージャリンクテーブルエントリのアドレスを参照する点が異なります。また、R_SPARC_WPLT30 は、プロシージャのリンクテーブル作成をリンカーに指示します。
リンカーは、この再配置型を作成して、動的実行可能ファイルが読み取り専用のテキストセグメントを保持できるようにします。この再配置型のオフセット構成要素は、書き込み可能セグメントの位置を参照します。シンボルテーブルインデックスは、現オブジェクトファイルと共有オブジェクトの両方に存在する必要があるシンボルを指定します。実行時、実行時リンカーは共有オブジェクトのシンボルに関連付けられているデータを、オフセットで指定されている位置にコピーします。コピー再配置を参照してください。
R_SPARC_32 に似ていますが、大域オフセットテーブルエントリを指定されたシンボルのアドレスに設定する点が異なります。この特殊な再配置型を使うと、シンボルと大域オフセットテーブルエントリの対応付けを判定できます。
リンカーは、動的オブジェクトが遅延結合を提供できるようにするため、この再配置型を作成します。この再配置型のオフセット構成要素は、プロシージャのリンクテーブルエントリの位置を与えます。実行時リンカーは、プロシージャのリンクテーブルエントリを変更して指定シンボルアドレスに制御を渡します。
リンカーは、動的オブジェクト用にこの再配置型を作成します。この再配置型のオフセット構成要素は、相対アドレスを表す値が存在する、共有オブジェクト内の位置を与えます。実行時リンカーは共有オブジェクトが読み込まれる仮想アドレスに相対アドレスを加算することで、対応する仮想アドレスを計算します。この型に対する再配置エントリは、シンボルテーブルインデックスに対して 0 を指定しなければなりません。
R_SPARC_32 に似ていますが、整列されていないワードを参照する点が異なります。再配置されるワードは、任意整列が存在する 4 つの別個のバイトとして処理されなければなりません (アーキテクチャの要求に従って整列されるワードとしては処理されません)。
R_SPARC_HI22 に似ていますが、妥当性検査ではなく切り捨てを行う点が異なります。
R_SPARC_PC22に似ていますが、妥当性検査ではなく切り捨てを行う点が異なります。
64 ビットアドレス空間の最上位 4G バイトに限定される実行可能ファイルに対して R_SPARC_LOX10 と共に使用されます。R_SPARC_HI22 に似ていますが、リンク値の 1 の補数を与えます。
R_SPARC_HIX22 と共に使用されます。R_SPARC_LO10 に似ていますが、必ずリンク値のビット 10 からビット 12 までを設定します。
再配置型 R_SPARC_H44 および R_SPARC_M44 と共に使用され、44 ビット絶対アドレス指定モデルを生成します。
レジスタシンボルの初期化に使用されます。この再配置型のオフセット構成要素には、初期化されるレジスタ番号が存在します。SHN_ABS 型のこのレジスタには、対応するレジスタシンボルが存在しなければなりません。
これらの再配置はコード変換に対応したものです。
再配置計算に使用される以下の表記は、64 ビット SPARC 固有のものです。
再配置可能フィールドの値を計算するために使用される二次的な加数。この加数は、ELF64_R_TYPE_DATA マクロを適用することにより r_info フィールドから抽出されます。
次の表に示す再配置型は、32 ビット SPARC 用に定義された再配置型を拡張または変更します。詳細は、SPARC: 再配置型を参照してください。
表 7–19 64-bit SPARC: ELF 再配置型
名前 |
値 |
フィールド |
計算 |
---|---|---|---|
R_SPARC_HI22 |
9 |
V-imm22 |
(S + A)>> 10 |
R_SPARC_GLOB_DAT |
20 |
V-xword64 |
S + A |
R_SPARC_RELATIVE |
22 |
V-xword64 |
B + A |
R_SPARC_64 |
32 |
V-xword64 |
S + A |
R_SPARC_OLO10 |
33 |
V-simm13 |
((S + A) & 0x3ff) + O |
R_SPARC_DISP64 |
46 |
V-xword64 |
S + A - P |
R_SPARC_PLT64 |
47 |
V-xword64 |
L + A |
R_SPARC_REGISTER |
53 |
V-xword64 |
S + A |
R_SPARC_UA64 |
54 |
V-xword64 |
S + A |
以下の再配置型には、単純な計算を超えた意味が存在します。
R_SPARC_LO10 に似ていますが、符号付き13 ビット即値フィールドを十分に使用するために余分なオフセットが追加される点が異なります。
次の表に、32 ビット x86 用に定義された再配置型を示します。
表 7–20 x86: ELF 再配置型
名前 |
値 |
フィールド |
計算 |
---|---|---|---|
R_386_NONE |
0 |
なし |
なし |
R_386_32 |
1 |
word32 |
S + A |
R_386_PC32 |
2 |
word32 |
S + A - P |
R_386_GOT32 |
3 |
word32 |
G + A |
R_386_PLT32 |
4 |
word32 |
L + A - P |
R_386_COPY |
5 |
なし |
なし |
R_386_GLOB_DAT |
6 |
word32 |
S |
R_386_JMP_SLOT |
7 |
word32 |
S |
R_386_RELATIVE |
8 |
word32 |
B + A |
R_386_GOTOFF |
9 |
word32 |
S + A - GOT |
R_386_GOTPC |
10 |
word32 |
GOT + A - P |
R_386_32PLT |
11 |
word32 |
L + A |
スレッド固有領域の参照に使用できる再配置はほかにも存在します。これらの再配置については、第 8 章「スレッド固有領域 (TLS)」で説明しています。
いくつかの再配置型には、単純な計算を超えた意味が存在します。
大域オフセットテーブルのベースからシンボルの大域オフセットテーブルエントリまでの距離を計算します。この再配置型はまた、大域オフセットテーブルを作成するようにリンカーに指示します。
シンボルのプロシージャのリンクテーブルエントリのアドレスを計算し、かつプロシージャのリンクテーブルを作成するようにリンカーに指示します。
リンカーは、この再配置型を作成して、動的実行可能ファイルが読み取り専用のテキストセグメントを保持できるようにします。この再配置型のオフセット構成要素は、書き込み可能セグメントの位置を参照します。シンボルテーブルインデックスは、現オブジェクトファイルと共有オブジェクトの両方に存在する必要があるシンボルを指定します。実行時、実行時リンカーは共有オブジェクトのシンボルに関連付けられているデータを、オフセットで指定されている位置にコピーします。コピー再配置を参照してください。
大域オフセットテーブルエントリを、指定されたシンボルのアドレスに設定します。この特殊な再配置型を使うと、シンボルと大域オフセットテーブルエントリの対応付けを判定できます。
リンカーは、動的オブジェクトが遅延結合を提供できるようにするため、この再配置型を作成します。この再配置型のオフセット構成要素は、プロシージャのリンクテーブルエントリの位置を与えます。実行時リンカーは、プロシージャのリンクテーブルエントリを変更して指定シンボルアドレスに制御を渡します。
リンカーは、動的オブジェクト用にこの再配置型を作成します。この再配置型のオフセット構成要素は、相対アドレスを表す値が存在する、共有オブジェクト内の位置を与えます。実行時リンカーは共有オブジェクトが読み込まれる仮想アドレスに相対アドレスを加算することで、対応する仮想アドレスを計算します。この型に対する再配置エントリは、シンボルテーブルインデックスに対して 0 を指定しなければなりません。
シンボルの値と大域オフセットテーブルのアドレスの差を計算します。この再配置型はまた、大域オフセットテーブルを作成するようにリンカーに指示します。
R_386_PC32 に似ていますが、計算を行う際に大域オフセットテーブルのアドレスを使用する点が異なります。この再配置で参照されるシンボルは、通常 _GLOBAL_OFFSET_TABLE_ です。この再配置型はまた、大域オフセットテーブルを作成するようにリンカーに指示します。
文字列テーブルセクションは、ヌル文字で終了する一連の文字 (一般に文字列と呼ばれている) を保持します。オブジェクトファイルは、これらの文字列を使用してシンボルとセクション名を表します。文字列をインデックスに使用して、文字列テーブルセクションを参照します。
先頭バイト (インデックス 0) は、ヌル文字を保持します。同様に、文字列テーブルの最後のバイトは、ヌル文字を保持します。したがって、すべての文字列は確実にヌル文字で終了します。したがって、すべての文字列は確実にヌル文字で終了します。インデックスが 0 の文字列は、名前を指定しないかヌル文字の名前を指定します (状況に依存する)。
空の文字列テーブルセクションが許可されており、セクションヘッダーの sh_size 構成要素に 0 が入ります。0 以外のインデックスは、空の文字列テーブルに対して無効です。
セクションヘッダーの sh_name 構成要素は、ELF ヘッダーの e_shstrndx 構成要素で示されているとおり、セクションヘッダー文字列テーブルセクションへのインデックスを保持します。次の図は、25 バイトの文字列テーブルと、さまざまなインデックスに関連付けられている文字列を示しています。
次の表に、上の図に示した文字列テーブルの文字列を示しています。
表 7–21 ELF 文字列テーブルインデックス
インデックス |
文字列 |
---|---|
0 |
なし |
1 |
name |
7 |
Variable |
11 |
able |
16 |
able |
24 |
ヌル文字列 |
例で示しているとおり、文字列テーブルインデックスはセクションのすべてのバイトを参照できます。文字列は 2 回以上出現可能です。部分文字列に対する参照は存在可能です。単一文字列は複数回参照可能です。参照されない文字列も許可されます。
オブジェクトファイルのシンボルテーブルは、プログラムのシンボル定義または参照の探索と再配置に必要な情報を保持します。シンボルテーブルインデックスは、この配列への添字です。インデックス 0 はシンボルテーブルの先頭エントリを指定し、また未定義シンボルインデックスとして機能します。詳細は、表 7–25 を参照してください。
シンボルテーブルエントリの形式 (sys/elf.h で定義されている) は、次のとおりです。
typedef struct { Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; Elf32_Half st_shndx; } Elf32_Sym; typedef struct { Elf64_Word st_name; unsigned char st_info; unsigned char st_other; Elf64_Half st_shndx; Elf64_Addr st_value; Elf64_Xword st_size; } Elf64_Sym;
この構造体の要素を次に示します。
オブジェクトファイルのシンボル文字列テーブルへのインデックス (シンボル名の文字表現を保持する)。値が 0 以外の場合、その値はシンボル名を与える文字列テーブルインデックスを表します。値が 0 の場合、シンボルテーブルエントリに名前は存在しません。
関連付けられているシンボルの値。この値は、絶対値やアドレスなど (状況に依存する) を表します。詳細は、シンボル値を参照してください。
多くのシンボルは、関連付けられているサイズを持っています。たとえば、データオブジェクトのサイズは、データオブジェクトに存在するバイト数です。この構成要素は、シンボルがサイズを持っていない場合またはサイズが不明な場合、0 を保持します。
シンボルの種類および結び付けられる属性。値と意味のリストを、表 7–22 に示します。次のコードは、値 (sys/elf.h で定義されている) の処理方法を示します。
#define ELF32_ST_BIND(info) ((info)>> 4) #define ELF32_ST_TYPE(info) ((info) & 0xf) #define ELF32_ST_INFO(bind, type) (((bind)<<4)+((type)&0xf)) #define ELF64_ST_BIND(info) ((info)>> 4) #define ELF64_ST_TYPE(info) ((info) & 0xf) #define ELF64_ST_INFO(bind, type) (((bind)<<4)+((type)&0xf))
シンボルの可視性。値とその意味のリストを、表 7–24 に示します。以下のコードは、32 ビットオブジェクトと 64 ビットオブジェクトの両方の値を操作する方法を示しています。その他のビットは 0 を含んでおり、特に意味はありません。
#define ELF32_ST_VISIBILITY(o) ((o)&0x3) #define ELF64_ST_VISIBILITY(o) ((o)&0x3)
すべてのシンボルテーブルエントリは、何らかのセクションに関して定義されます。この構成要素は、該当するセクションヘッダーテーブルインデックスを保持します。いくつかのセクションインデックスは、特別な意味を示します。表 7–11 を参照してください。
この構成要素に SHN_XINDEX が含まれる場合は、実際のセクションヘッダーインデックスが大きすぎてこのフィールドに入りません。 実際の値は、タイプ SHT_SYMTAB_SHNDX の関連するセクション内に存在します。
シンボルのバインディングは、st_info で指定され、これにより、リンクの可視性と動作が決定します。
表 7–22 ELF シンボルのバインディング、(ELF32_ST_BIND、ELF64_ST_BIND)
名前 |
値 |
---|---|
STB_LOCAL |
0 |
STB_GLOBAL |
1 |
STB_WEAK |
2 |
STB_LOOS |
10 |
STB_HIOS |
12 |
STB_LOPROC |
13 |
STB_HIPROC |
15 |
ローカルシンボル。ローカルシンボルは、ローカルシンボルの定義が存在するオブジェクトファイルの外部では見えません。同じ名前のローカルシンボルは、互いに干渉することなく複数のファイルに存在できます。
大域シンボル。大域シンボルは、結合されるすべてのオブジェクトファイルで見ることができます。あるファイルの大域シンボルの定義は、その大域シンボルへの別ファイルの未定義参照を解決します。
ウィークシンボル。ウィークシンボルは大域シンボルに似ていますが、ウィークシンボルの定義の優先順位は大域シンボルの定義より低いです。
この範囲の値 (両端の値を含む) は、オペレーティングシステム固有の意味のために予約されています。
この範囲の値は、プロセッサ固有の意味のために予約されています。
大域シンボルとウィークシンボルは、主に 2 つの点で異なります。
リンカーは、いくつかの再配置可能オブジェクトファイルを結合するとき、同じ名前の STB_GLOBAL シンボルの複数の定義を許可しない。一方、定義された大域シンボルが存在している場合、同じ名前のウィークシンボルが現れてもエラーは発生しない。リンカーは大域定義を使用し、ウィーク定義を無視する。
同様に、共通シンボルが存在している場合、同じ名前のウィークシンボルが現れてもエラーは発生しない。リンカーは共通定義を使用し、ウィーク定義を無視する。共通シンボルは、SHN_COMMON を保持する st_shndx フィールドを持つ。詳細は、シンボル解決を参照してください。
リンカーは、アーカイブライブラリの検索時に、未定義または一時的な大域シンボル定義が存在するアーカイブ構成要素を抜き出す。構成要素の定義は、大域シンボルまたはウィークシンボルになる。
リンカーはデフォルトでは、未定義のウィークシンボルを解決するためのアーカイブ構成要素を抜き出さない。解決されていないウィークシンボルは、値 0 を持つ。-z weakextract を使用すると、このデフォルトの動作が無効になる。これにより、ウィーク参照がアーカイブ構成要素を抜き出すことができる。
ウィークシンボルは、主にシステムソフトウェアでの使用を意図したものです。アプリケーションプログラムでの使用は推奨されません。
各シンボルテーブルにおいて、STB_LOCAL 結び付きが存在するすべてのシンボルは、ウィークシンボルと大域シンボルの前に存在します。セクション に記述されているとおり、シンボルテーブルセクションの sh_info セクションヘッダー構成要素は、最初のローカルではないシンボルに対するシンボルテーブルインデックスを保持します。
シンボルのタイプは st_info フィールドで指定され、これにより、関連付けられた実体の一般的な分類が決定されます。
表 7–23 ELF シンボルのタイプ (ELF32_ST_TYPE、ELF64_ST_TYPE)
名前 |
値 |
---|---|
STT_NOTYPE |
0 |
STT_OBJECT |
1 |
STT_FUNC |
2 |
STT_SECTION |
3 |
STT_FILE |
4 |
STT_COMMON |
5 |
STT_TLS |
6 |
STT_LOOS |
10 |
STT_HIOS |
12 |
STT_LOPROC |
13 |
STT_SPARC_REGISTER |
13 |
STT_HIPROC |
15 |
シンボルの種類は指定されません。
シンボルは、データオブジェクト (変数や配列など) と関連付けられています。
シンボルは、関数または他の実行可能コードに関連付けられています。
シンボルは、セクションに関連付けられています。この種類のシンボルテーブルエントリは主に再配置を行うために存在しており、通常、STB_LOCAL に結び付けられています。
慣例により、シンボルの名前はオブジェクトファイルに対応するソースファイルの名前を与えます。ファイルシンボルは STB_LOCAL に結び付けられており、セクションインデックスは SHN_ABS です。このシンボルは、存在する場合、ファイルの他の STB_LOCAL シンボルの前に存在します。 SHT_SYMTAB のシンボルインデックス 1 は、ファイル自身を表す STT_FILE シンボルです。慣例により、この後にはファイルの STT_SECTION シンボルと、ローカルシンボルに短縮されている大域シンボルが続きます。
このシンボルは、初期設定されていない共通ブロックを表します。これは、STT_OBJECT とまったく同じに扱われます。
シンボルは、スレッド固有領域の実体を指定します。定義されている場合、実際のアドレスではなく、シンボルに割り当てられたオフセットを提供します。STT_TLS 型のシンボルは、特殊なスレッド固有領域の再配置だけによって参照され、スレッド固有領域の再配置は、STT_TLS 型のシンボルだけを参照します。詳細は、第 8 章「スレッド固有領域 (TLS)」を参照してください。
この範囲の値 (両端の値を含む) は、オペレーティングシステム固有の意味のために予約されています。
この範囲の値は、プロセッサ固有の使用方法に予約されます。
シンボルの可視性は、st_other フィールドで決定され、これは、再配置可能オブジェクトの中で指定できます。シンボルの可視性により、シンボルが実行可能ファイルまたは共有オブジェクトの一部になった後のシンボルへのアクセス方法が定義されます。
表 7–24 ELF シンボルの可視性
名前 |
値 |
---|---|
STV_DEFAULT |
0 |
STV_INTERNAL |
1 |
STV_HIDDEN |
2 |
STV_PROTECTED |
3 |
STV_DEFAULT 属性を持つシンボルの可視性は、シンボルの結合タイプで指定されたものになります。つまり、大域シンボルおよびウィークシンボルは、それらの定義するコンポーネント (実行可能ファイルまたは共有オブジェクト) の外から見ることができます。ローカルシンボルは、「隠されて」います。大域シンボルおよびウィークシンボルを、「横取り可能」に設定 (別のコンポーネント内の同名定義によるオーバーライドを可能に) することもできます。
現在のコンポーネン内で定義されたシンボルは、それが他のコンポーネント内で参照可能であるが横取り可能ではない場合、保護されています。つまり、定義するコンポーネント内からのそのようなシンボルへの参照は、たとえデフォルトの規則によって間に入るような別のコンポーネントの定義があったとしても、そのコンポーネントの定義にもとづいて解決されなければなりません。STB_LOCAL 結合を持つシンボルは、STV_PROTECTED 可視性を持ちません。
現在のコンポーネント内で定義されたシンボルは、その名前が他のコンポーネントから参照することができない場合、「隠されて」います。そのようなシンボルは、保護される必要があります。この属性は、コンポーネントの外部インタフェースの管理に使用されます。そのようなシンボルによって指定されたオブジェクトは、そのアドレスが外部に渡された場合でも、他のコンポーネントから参照可能です。
再配置可能オブジェクトに含まれた「隠された」シンボルは、その再配置可能オブジェクトが実行可能ファイルまたは共有オブジェクトに含まれる時には、リンカーによって削除されるか STB_LOCAL 結合に変換されます。
この可視性の属性は、現在予約されています。
可視性の属性は、リンク編集中、実行可能ファイルまたは共有オブジェクト内のシンボルの解決には全く影響をおよぼしません。このような解決は、結合タイプによって制御されます。いったんリンカーがその解決を選択すると、これらの属性は以下の 2 つの必要条件を課します。どちらの必要条件も、リンクされるコード内の参照は、属性の利点を利用するために最適化されるという事実に基づくものです。
1 つ目に、すべてのデフォルトでない可視性の属性は、シンボルの参照に適用される際、その参照を満たすための定義は現在の実行可能ファイルまたは共有オブジェクト内で提供されなければならないという条件を課します。この種のシンボルの参照がリンクされるコンポーネント内に定義を持たない場合は、その参照は STB_WEAK 結合を持つ必要があり、0 に解決されます。
2 つ目に、名前への参照または名前の定義がデフォルトでない可視性の属性を持つシンボルである場合、その可視性の属性はリンクされるオブジェクト内の解決シンボルへ伝達されなければなりません。特定のシンボルへの参照または特定のシンボルの定義に対して異なる可視性の属性が指定されている場合は、最も制約の厳しい可視性の属性が、リンクされるオブジェクト内の解決シンボルへ伝達されなければなりません。属性は、最も制約の少ないものから最も制約の厳しいものの順に、STV_PROTECTED、STV_HIDDEN、STV_INTERNAL となります。
シンボル値がセクション内の特定位置を参照すると、セクションインデックス構成要素 st_shndx は、セクションヘッダーテーブルへのインデックスを保持します。再配置時にセクションが移動すると、シンボル値も変化します。シンボルへの参照はプログラム内の同じ位置を指し示し続けます。いくつかの特別なセクションインデックス値は、ほかの意味付けがされています。
シンボルは、絶対値 (再配置が行われても変化しない) を持ちます。
シンボルは、割り当てられていない共通ブロックを示します。シンボル値は、セクションの sh_addralign 構成要素に類似した整列制約を与えます。リンカーは st_value の倍数のアドレスにシンボル記憶領域を割り当てます。シンボルのサイズは、必要なバイト数を示します。
このセクションテーブルインデックスは、シンボルが未定義であることを意味します。リンカーがこのオブジェクトファイルを、示されたシンボルを定義する他のオブジェクトファイルに結合すると、このシンボルに対するこのファイルの参照は実際の定義に結び付けられます。
すでに説明したように、インデックス 0 (STN_UNDEF) のシンボルテーブルエントリは予約されています。このエントリは以下の値を保持します。
表 7–25 ELF シンボルテーブルエントリ: インデックス 0
名前 |
値 |
注意 |
---|---|---|
st_name |
0 |
名前が存在しない |
st_value |
0 |
値は 0 |
st_size |
0 |
サイズが存在しない |
st_info |
0 |
種類はない。ローカル結合 |
st_other |
0 |
|
st_shndx |
SHN_UNDEF |
セクションは存在しない |
異なる複数のオブジェクトファイル型のシンボルテーブルエントリは、st_value 構成要素に対してわずかに異なる解釈を持ちます。
再配置可能ファイルでは、st_value は定義されたシンボルに対するセクションオフセットを保持する。st_value は、st_shndx が識別するセクションの先頭からのオフセットになる
実行可能オブジェクトファイルと共有オブジェクトファイルでは、st_value は仮想アドレスを保持する。これらのファイルのシンボルを実行時リンカーに対してより有用にするために、セクションオフセット (ファイル解釈) の代わりに、セクション番号が無関係な仮想アドレス (ファイル解釈) が使用される
シンボルテーブル値は、異なる種類のオブジェクトファイルでも似た意味を持ちますが、適切なプログラムはデータに効率的にアクセスできます。
SPARC アーキテクチャは、レジスタシンボル (大域レジスタを初期化するシンボル) をサポートします。レジスタシンボルに対するシンボルテーブルエントリには、以下の値が入ります。
表 7–26 SPARC: ELF シンボルテーブルエントリ: レジスタシンボル
フィールド |
意味 |
---|---|
st_name |
シンボル名文字列テーブルへのインデックス。または 0 (スクラッチレジスタ) |
st_value | レジスタ番号。整数レジスタの割り当てについては、ABI マニュアルを参照 |
st_size |
未使用 (0) |
st_info | 結合は標準的には STB_GLOBAL。種類は STT_SPARC_REGISTER でなければならない |
st_other |
未使用 (0) |
st_shndx |
SHN_ABS (このオブジェクトがこのレジスタシンボルを初期化する場合)。SHN_UNDEF (それ以外の場合) |
定義済みの SPARC 用レジスタ値を、次に示します。
表 7–27 SPARC: ELF レジスタ番号
名前 |
値 |
意味 |
---|---|---|
STO_SPARC_REGISTER_G2 |
0x2 |
%g2 |
STO_SPARC_REGISTER_G3 |
0x3 |
%g3 |
特定の大域レジスタのエントリが存在しないことは、その特定の大域レジスタがオブジェクトで使用されないことを意味します。
syminfo セクションには、Elf32_Syminfo 型または Elf64_Syminfo 型の複数のエントリが存在します。関連付けられているシンボルテーブルの各エントリ (sh_link) の .SUNW_syminfo セクションには、1 つのエントリが存在します。
このセクションがオブジェクトに存在している場合、関連付けられているシンボルテーブルからシンボルインデックスを取り出し、このシンボルインデックスを使ってこのセクションに存在する対応する Elf32_Syminfo または Elf64_Syminfo エントリを見つけることで、追加シンボル情報を見つけます。関連付けられているシンボルテーブルと、Syminfo テーブルには、必ず同じ数のエントリが存在します。
インデックス 0 は、Syminfo テーブルの現バージョン (SYMINFO_CURRENT) を格納するために使用されます。シンボルテーブルエントリ 0 は必ず UNDEF シンボルテーブルエントリに対して予約されるので、矛盾は発生しません。
Syminfo エントリの形式 (sys/link.h で定義) を、次に示します。
typedef struct { Elf32_Half si_boundto; Elf32_Half si_flags; } Elf32_Syminfo; typedef struct { Elf64_Half si_boundto; Elf64_Half si_flags; } Elf64_Syminfo;
この構造体の要素を次に示します。
これは、.dynamic セクションのエントリへのインデックスで、sh_info フィールドにより示され、Syminfo フラグを増加させます。 たとえば、DT_NEEDED エントリは、Syminfo エントリに関連付けられた動的オブジェクトを示します。表 7–28 に示すエントリは、si_boundto に対して予約されています。
表 7–28 ELF si_boundto 予約値
名前 |
値 |
意味 |
---|---|---|
SYMINFO_BT_SELF |
0xffff |
自己に結びつけられるシンボル |
SYMINFO_BT_PARENT |
0xfffe |
親に結びつけられるシンボル。親は、この動的オブジェクトの読み込みを発生させる最初のオブジェクト |
SYMINFO_BT_NONE |
0xfffd |
シンボルに特別なシンボル結合は含まれない |
このビットフィールドでは、次の表に示すフラグを設定できます。
表 7–29 ELF Syminfo フラグ
名前 |
値 |
意味 |
---|---|---|
SYMINFO_FLG_DIRECT |
0x01 |
シンボル参照は、定義を含むオブジェクトへ直接関連付けられる |
SYMINFO_FLG_COPY |
0x04 |
シンボル定義はコピー再配置の結果 |
SYMINFO_FLG_LAZYLOAD |
0x08 |
遅延読み込みの必要があるオブジェクトに対するシンボル参照 |
SYMINFO_FLG_DIRECTBIND |
0x10 |
シンボル参照は定義に直接結合される必要がある |
SYMINFO_FLG_NOEXTDIRECT |
0x20 |
このシンボル定義に直接結合することを外部参照に許可しない |
リンカーで作成されるオブジェクトには、2 つの型のバージョン情報が存在できます。
これらのセクションを形成する構造体は、sys/link.h で定義されます。バージョン情報が存在するセクションには、.SUNW_version という名前が付けられます。
このセクションは、SHT_SUNW_verdef 型で定義されます。このセクションが存在する場合、SHT_SUNW_versym セクションも存在しなければなりません。これら 2 つの構造体を使用することで、シンボルとバージョン定義の関連付けがファイル内で維持されます。(バージョン定義の作成を参照)。このセクションの要素の構造体は、次のとおりです。
typedef struct { Elf32_Half vd_version; Elf32_Half vd_flags; Elf32_Half vd_ndx; Elf32_Half vd_cnt; Elf32_Word vd_hash; Elf32_Word vd_aux; Elf32_Word vd_next; } Elf32_Verdef; typedef struct { Elf32_Word vda_name; Elf32_Word vda_next; } Elf32_Verdaux; typedef struct { Elf64_Half vd_version; Elf64_Half vd_flags; Elf64_Half vd_ndx; Elf64_Half vd_cnt; Elf64_Word vd_hash; Elf64_Word vd_aux; Elf64_Word vd_next; } Elf64_Verdef; typedef struct { Elf64_Word vda_name; Elf64_Word vda_next; } Elf64_Verdaux;
この構造体の要素を次に示します。
この構成要素は、構造体自身のバージョンを示します (次の表を参照)。
表 7–30 ELF バージョン定義構造のバージョン
名前 |
値 |
意味 |
---|---|---|
VER_DEF_NONE |
0 |
無効バージョン |
VER_DEF_CURRENT |
>=1 |
現在のバージョン |
値 1 は最初のセクション形式を示し、拡張した場合は番号を大きくします。VER_DEF_CURRENT の値は、現在のバージョン番号を示すために必要に応じて変化します。
この構成要素は、バージョン定義に固有の情報を保持します (次の表を参照)。
表 7–31 ELF バージョン定義セクションのフラグ
名前 |
値 |
意味 |
---|---|---|
VER_FLG_BASE |
0x1 |
ファイル自身のバージョン定義 |
VER_FLG_WEAK |
0x2 |
ウィークバージョン識別子 |
基本バージョン定義は、バージョン定義またはシンボルの自動短縮簡約がファイルに適用されている場合、必ず存在します。基本バージョンは、ファイルの予約されたシンボルに対してデフォルトのバージョンを与えます。ウィークバージョン定義には、関連付けられているシンボルは存在しません。詳細は、ウィークバージョン定義の作成を参照してください。
バージョンインデックス。各バージョン定義には、SHT_SUNW_versym エントリを適切なバージョン定義に関連付ける一意のインデックスが存在します。
Elf32_Verdaux 配列の要素数。
バージョン定義名のハッシュ値。この値は、ハッシュテーブルセクションに記述されているハッシング機能により生成されます。
この Elf32_Verdef エントリの先頭からバージョン定義名の Elf32_Verdaux 配列までのバイトオフセット。配列の先頭要素は存在しなければなりません。これはこの構造体が定義するバージョン定義文字列を指し示します。追加要素は存在可能です。要素の番号は vd_cnt 値で示されます。これらの要素は、このバージョン定義の依存関係を表します。これらの依存関係の各々は、独自のバージョン定義構造体を持っています。
この Elf32_Verdef 構造体の先頭から次の Elf32_Verdef エントリまでのバイトオフセット。
ヌル文字で終わる文字列への文字列テーブルオフセットで、バージョン定義名を指定します。
この Elf32_Verdaux エントリの先頭から次の Elf32_Verdaux エントリまでのバイトオフセット。
バージョンシンボルセクションは SHT_SUNW_versym 型で定義されており、以下の構造を持つ要素配列からなります。
typedef Elf32_Half Elf32_Versym; typedef Elf64_Half Elf64_Versym;
配列の要素数は、関連付けられているシンボルテーブルに存在するシンボルテーブルエントリ数に等しくなければなりません。この値は、セクションの sh_link 値で決定されます。配列の各要素には 1 つのインデックスが存在し、このインデックスは表 7–32 に示す値をとることができます。
表 7–32 ELF バージョン依存インデックス
名前 |
値 |
意味 |
---|---|---|
VER_NDX_LOCAL |
0 |
シンボルにローカル適用範囲が存在する |
VER_NDX_GLOBAL |
1 |
シンボルに大域適用範囲 (基本バージョン定義に割り当てられる) が存在する |
|
>1 |
シンボルに大域適用範囲 (ユーザー定義バージョン定義に割り当てられる) が存在する |
VER_NDX_GLOBAL より大きいインデックス値は、SHT_SUNW_verdef セクションのエントリの vd_ndx 値に一致しなければなりません。VER_NDX_GLOBAL より大きいインデックス値が存在しない場合、SHT_SUNW_verdef セクションが存在する必要はありません。
バージョン依存セクションは、SHT_SUNW_verneed 型で定義されます。 このセクションは、ファイルの動的依存性から要求されるバージョン定義を示すことで、ファイルの動的依存性要求を補足します。依存性にバージョン定義が存在する場合のみ、記録がこのセクションにおいて行われます。このセクションの要素の構造体は、次のとおりです。
typedef struct { Elf32_Half vn_version; Elf32_Half vn_cnt; Elf32_Word vn_file; Elf32_Word vn_aux; Elf32_Word vn_next; } Elf32_Verneed; typedef struct { Elf32_Word vna_hash; Elf32_Half vna_flags; Elf32_Half vna_other; Elf32_Word vna_name; Elf32_Word vna_next; } Elf32_Vernaux; typedef struct { Elf64_Half vn_version; Elf64_Half vn_cnt; Elf64_Word vn_file; Elf64_Word vn_aux; Elf64_Word vn_next; } Elf64_Verneed; typedef struct { Elf64_Word vna_hash; Elf64_Half vna_flags; Elf64_Half vna_other; Elf64_Word vna_name; Elf64_Word vna_next; } Elf64_Vernaux;
この構造体の要素を次に示します。
この構成要素は、構造体自身のバージョンを示します (次の表を参照)。
表 7–33 ELF バージョン依存構造体のバージョン
名前 |
値 |
意味 |
---|---|---|
VER_NEED_NONE |
0 |
無効バージョン |
VER_NEED_CURRENT |
>=1 |
現在のバージョン |
値 1 は最初のセクション形式を示し、拡張した場合は番号を大きくします。VER_NEED_CURRENT の値は、現在のバージョン番号を示すために必要に応じて変化します。
Elf32_Vernaux 配列の要素数。
ヌル文字で終わっている文字列への文字列テーブルオフセットで、バージョン依存性が存在するファイル名を指定します。この名前は、ファイル内に存在する .dynamic 依存性のどれかに一致します。詳細は、動的セクションを参照してください。
この Elf32_Verneed エントリの先頭から、関連付けられているファイル依存性から要求されるバージョン定義の Elf32_Vernaux 配列までのバイトオフセット。少なくとも 1 つのバージョン依存性が存在しなければなりません。追加バージョン依存性は存在することができ、また番号は vn_cnt 値で示されます。
この Elf32_Verneed エントリの先頭から次の Elf32_Verneed エントリまでのバイトオフセット。
バージョン依存性の名前のハッシュ値。この値は、ハッシュテーブルセクションに記述されているハッシング機能により生成されます。
バージョン依存性に固有の情報 (次の表を参照)。
表 7–34 ELF バージョン依存構造のフラグ
名前 |
値 |
意味 |
---|---|---|
VER_FLG_WEAK |
0x2 |
ウィークバージョン識別子 |
ウィークバージョン依存性は、ウィークバージョン定義への最初の結び付きを示します。
現在、使用されていません。
ヌル文字で終わる文字列への文字列テーブルオフセット。バージョン依存性の名前を与えます。
この Elf32_Vernaux エントリの先頭から次の Elf32_Vernaux エントリまでのバイトオフセット。
このセクションは、オブジェクトファイル情報と、プログラムの実行イメージを作成するシステム動作を記述します。ここで説明する情報の大半は、すべてのシステムに適用されます。プロセッサに固有の情報はその旨が示されたセクションに存在します。
実行可能オブジェクトファイルと共有オブジェクトファイルは、アプリケーションプログラムを静的に表現します。このようなプログラムを実行するためには、システムはこれらのファイルを使用して動的なプログラムの表現、すなわちプロセスイメージを作成します。プロセスイメージには、テキスト、データ、スタックなどがあるセグメントが存在します。この項の主な細目は以下のとおりです。
プログラムヘッダーでは、プログラム実行に直接関係するオブジェクトファイルの構造を記述する。重要なデータ構造体であるプログラムヘッダーテーブルは、ファイル内のセグメントイメージの位置を示す。また、このプログラムヘッダーテーブルは、プログラムのメモリーイメージの作成に必要な他の情報が存在する
プログラムの読み込み (プロセッサ固有)では、メモリーにプログラムを読み込むために使用する情報を記述する
実行時リンカーでは、プロセスイメージのオブジェクトファイル間でシンボル参照を指定、解決するために使用する情報を記述する
実行可能オブジェクトファイルまたは共有オブジェクトファイルのプログラムヘッダーテーブルは、構造体の配列です (各構造体は、実行されるプログラムを準備するためにシステムが必要とするセグメントなどの情報を記述する) 。各オブジェクトファイルセグメントには、セグメントの内容で説明しているように、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 再配置エントリ (プロシージャのリンクテーブルエントリ) を処理します。