ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
![]() |
リンカーとライブラリ Oracle Solaris 10 8/11 Information Library (日本語) |
オブジェクトファイルはプログラムのリンクと実行の両方に関係します。利便性と効率性のため、オブジェクトファイルの形式には、リンクと実行の異なる要求に合わせて、2 つの平行した見方があります。次の図にオブジェクトファイルの編成を示します。
ELF ヘッダーはオブジェクトファイルの先頭に存在し、ファイル編成を記述する「ロードマップ」を保持します。
注 - ELF ヘッダーの位置のみがファイル内で固定されています。ELF 形式には柔軟性があるため、ヘッダーテーブル、セクション、およびセグメントの順序は特に決まっていません。この図に示したのは、Oracle Solaris OS で使用される典型的なレイアウトです。
「セクション」は、 ELF ファイル内で処理可能な最小単位 (これ以上分割できない単位) です。「セグメント」は、セクションの集合です。セグメントは、exec(2) または実行時リンカーでメモリーイメージに対応付けできる最小単位です。
セクションは、リンクの観点から見たオブジェクトファイルの情報の大部分を保持します。このデータには、命令、データ、シンボルテーブル、再配置情報などが含まれます。セクションに関しては、この章の前半で説明します。セグメントとプログラムの実行の観点から見たファイルの構造に関しては、この章の後半で説明します。
プログラムヘッダーテーブル (存在する場合) は、システムにプロセスイメージの作成方法を通知します。プロセスイメージの生成に使用されるファイル (実行可能ファイルと共有オブジェクト) には、プログラムヘッダーテーブルが存在する必要があります。再配置可能オブジェクトでは、プログラムヘッダーテーブルは必要ありません。
セクションヘッダーテーブルには、ファイルのセクションを記述する情報が入っています。セクションヘッダーテーブルには各セクションのエントリが存在します。各エントリは、セクション名、セクションサイズなどの情報が含まれます。リンク編集で使用されるファイルには、セクションヘッダーテーブルが存在しなければなりません。
オブジェクトファイルの形式は、8 ビットバイト、32 ビットアーキテクチャー、および 64 ビットアーキテクチャーを持つさまざまなプロセッサをサポートしています。しかしながら、データ表現は、より大きな、またはより小さなアーキテクチャーに拡張できるように意図されています。表 7-1 と表 7-2 に、32 ビットデータタイプと 64 ビットデータタイプの一覧を示します。
オブジェクトファイルは、いくつかの制御データをマシンに依存しない形式で表現します。この形式は、オブジェクトファイルの共通の識別および解釈を規定します。オブジェクトファイルの残りのデータは、このオブジェクトファイルが作成されたマシンとは関係なく、対象となるプロセッサ用に符号化されています。
表 7-1 ELF 32 ビットデータタイプ
|
表 7-2 ELF 64 ビットデータタイプ
|
オブジェクトファイルの形式で定義されるすべてのデータ構造は、該当クラスの自然なサイズと整列ガイドラインに従います。データ構造に明示的にパッドを入れることで、4 バイトオブジェクトに対して 4 バイト整列を保証したり構造サイズを 4 の倍数に設定したりできます。また、データはファイルの先頭から適切に整列されます。したがってたとえば、Elf32_Addr メンバーが存在する構造はファイル内において 4 バイト境界で整列されます。同様に、Elf64_Addr メンバーが存在する構造は 8 バイト境界で整列されます。
注 - 移植性を考慮して、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 識別」に記載されています。
オブジェクトファイルの種類を示します。次の種類が存在します。
|
コアファイルの内容は指定されていませんが、ET_CORE タイプはコアファイルを示すために予約されます。ET_LOPROC から ET_HIPROC までの値 (それぞれを含む) は、プロセッサ固有のセマンティクスのために予約されています。ほかの値は、将来の使用に備えて保留されます。
個々のファイルに必要なアーキテクチャーを指定します。関連するアーキテクチャーを、次の表に示します。
|
ほかの値は、将来の使用に備えて保留されます。プロセッサ固有の ELF 名の識別には、機種名が使用されます。たとえば、e_flags に定義されるフラグでは、接頭辞 EF_ が使用されます。EM_XYZ マシンの WIDGET というフラグは、EF_XYZ_WIDGET と呼ばれます。
オブジェクトファイルのバージョンを示します。次のバージョンが存在します。
|
値 1 は最初のファイル形式を示し、EV_CURRENT の値は、現在のバージョン番号を示すために必要に応じて変化します。
システムが制御を最初に渡す仮想アドレスを保持し、仮想アドレスが与えられると、プロセスが起動します。ファイルに関連するエントリポイントが存在しない場合、このメンバーは 0 を保持します。
プログラムヘッダーテーブルのファイルオフセットを保持します (単位: バイト)。ファイルにプログラムヘッダーテーブルが存在しない場合、このメンバーは 0 を保持します。
セクションヘッダーテーブルのファイルオフセットを保持します (単位: バイト)。ファイルにセクションヘッダーテーブルが存在しない場合、このメンバーは 0 を保持します。
ファイルに対応付けられたプロセッサ固有のフラグを保持します。フラグ名は、EF_machine「_flag」という形式をとります。このメンバーは、現在 x86 に対しては 0 です。SPARC の場合のフラグを、次の表に示します。
|
ELF ヘッダーのサイズ (単位: バイト)。
ファイルのプログラムヘッダーテーブルの 1 つのエントリのサイズ (単位:バイト)。すべてのエントリは同じサイズです。
プログラムヘッダーテーブルのエントリ数。e_phentsize に e_phnum を掛けると、テーブルのサイズ (単位: バイト) が求められます。ファイルにプログラムヘッダーテーブルが存在しない場合、e_phnum は値 0 を保持します。
プログラムヘッダーの数が PN_XNUM (0xffff) 以上である場合、このメンバーは値 PN_XNUM (0xffff) を保持します。プログラムヘッダーテーブルエントリの実際の数は、インデックス 0 のセクションヘッダーの sh_info フィールドに含まれます。そうでない場合、初期セクションヘッダーエントリの sh_info メンバーには値 0 が入っています。表 7-6 および表 7-7 を参照してください。
セクションヘッダーのサイズ (単位:バイト)。1 つのセクションヘッダーは、セクションヘッダーテーブルの 1 つのエントリです。すべてのエントリは同じサイズです。
セクションヘッダーテーブルのエントリ数。e_shentsize に e_shnum を掛けると、セクションヘッダーテーブルのサイズ (単位: バイト) が求められます。ファイルにセクションヘッダーテーブルが存在しない場合、e_shnum は値 0 を保持します。
セクション数が SHN_LORESERVE (0xff00) 以上の場合、e_shnum の値は 0 になります。セクションヘッダーテーブルエントリの実際の数は、インデックス 0 の sh_size フィールドに含まれます。そうでない場合、初期セクションヘッダーエントリの sh_size メンバーには値 0 が入っています。表 7-6 および表 7-7 を参照してください。
セクション名文字列テーブルに対応するエントリのセクション ヘッダーテーブルインデックス。ファイルにセクション名文字列テーブルが存在しない場合、このメンバーは値 SHN_UNDEF を保持します。
セクション名文字列テーブルセクションのインデックスが SHN_LORESERVE (0xff00) 以上の場合、このメンバーの値は SHN_XINDEX (0xffff) となり、セクション名文字列テーブルセクションの実際のインデックスはインデックス 0 のセクションヘッダーの sh_link フィールドに入っています。そうでない場合、初期セクションヘッダーエントリの sh_link メンバーには値 0 が入っています。表 7-6 および表 7-7 を参照してください。
ELF はオブジェクトファイルの枠組みを提供し、複数のプロセッサ、複数のデータ符号化、複数のクラスのマシンをサポートします。このオブジェクトファイルファミリをサポートするため、ファイルの初期バイトによりファイルの解釈方法が指定されます。これらの初期バイトは、問い合わせが行われるプロセッサにも、ファイルのほかの内容にも依存しません。
ELF ヘッダーおよびオブジェクトファイル の初期バイトは、e_ident メンバーに一致します。
表 7-3 ELF 識別インデックス
|
次のインデックスは、次の値を保持するバイトにアクセスします。
ファイルを ELF オブジェクトファイルとして識別する 4 バイトの「マジックナンバー」。次の表を参照してください。
|
バイト e_ident[EI_CLASS] は、ファイルのクラスまたは容量を示します。次の表にファイルのクラスを示します。
|
ファイル形式は、最大マシンのサイズを最小マシンに押しつけることなしにさまざまなサイズのマシン間で互換性が維持されるように設計されています。ファイルのクラスは、オブジェクトファイルコンテナのデータ構造によって使用される基本タイプを定義します。オブジェクトファイルセクションに含まれるデータは、異なるプログラミングモデルに準拠する場合があります。
クラス ELFCLASS32 は、4 ギガバイトまでのファイルと仮想アドレス空間が存在するマシンをサポートします。このクラスは、表 7-1 で定義される基本タイプを使用します。
クラス ELFCLASS64 は、64 ビット SPARC や x64 などの 64 ビットアーキテクチャー用に予約されています。このクラスは、表 7-2 で定義される基本タイプを使用します。
バイト e_ident[EI_DATA] は、オブジェクトファイルのプロセッサ固有のデータの符号化を指定します (次の表を参照)。
|
これらの符号化の詳細は、「データの符号化」で説明します。ほかの値は、将来の使用に備えて保留されます。
バイト 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 のファイルおよびクラス ELFCLASS64 のファイルは、1、2、4、および 8 バイトを占める整数を使用して、オフセット、アドレス、およびその他の情報を表現します。定義されている符号化方式の下では、オブジェクトは次の図の説明のように表されます。バイト番号は、左上隅に示されています。
ELFDATA2LSB を符号化すると、最下位バイトが最低位アドレスを占める 2 の補数値が指定されます。この符号化は、一般的にはよく「リトルエンディアン」と呼ばれます。
図 7-2 データの符号化方法 ELFDATA2LSB
ELFDATA2MSB を符号化すると、最上位バイトが最低位アドレスを占める 2 の補数値が指定されます。この符号化は、一般的にはよく「ビッグエンディアン」と呼ばれます。
図 7-3 データの符号化方法 ELFDATA2MSB
オブジェクトファイルのセクションヘッダーテーブルを使用すると、ファイルのセクションすべてを見つけ出すことができます。セクションヘッダーテーブルは、Elf32_Shdr 構造体または Elf64_Shdr 構造体の配列です。セクションヘッダーテーブルインデックスは、この配列への添字です。ELF ヘッダーの e_shoff メンバーは、ファイルの先頭からセクションヘッダーテーブルまでのバイトオフセットを示します。e_shnum メンバーは、セクションヘッダーテーブルに含まれるエントリ数を示します。e_shentsize メンバーは、各エントリのバイト単位の大きさを示します。
セクション数が SHN_LORESERVE (0xff00) 以上の場合、e_shnum の値は SHN_UNDEF (0) になります。セクションヘッダーテーブルエントリの実際の数は、インデックス 0 の sh_size フィールドに含まれます。そうでない場合、初期エントリの sh_size メンバーには値 0 が入っています。
セクションヘッダーテーブルインデックスの中には、インデックスサイズが制限されている文脈で予約されているものがあります。たとえば、シンボルテーブルエントリの st_shndx メンバー、 ELF ヘッダーの e_shnum メンバーと e_shstrndx メンバーなどがそうです。このような文脈では、予約値はオブジェクトファイル内の実際のセクションを示しません。また、このような文脈では、エスケープ値は、実際のセクションインデックスがどこかもっと大きなフィールド内に存在することを示します。
表 7-4 ELF セクションの特殊インデックス
|
注 - インデックス 0 は未定義値として予約されますが、セクションヘッダーテーブルにはインデックス 0 のエントリが存在します。つまり、ELF ヘッダーの e_shnum メンバーが、ファイルのセクションヘッダーテーブルに 6 つのエントリが存在することを示している場合、これら 6 つのエントリにはインデックス 0 から 5 までが与えられます。先頭のエントリの内容は、この項の末尾に記述します。
未定義、存在しない、無関係など、無意味なセクション参照。たとえば、セクション番号 SHN_UNDEF に関して「定義された」シンボルは、未定義シンボルです。
このセクションインデックスは、再配置可能オブジェクト内の一時的なシンボル定義を提供します。dtrace(1M) の内部使用のため予約されています。
SHF_LINK_ORDER および SHF_ORDERED セクションフラグとともに先頭および末尾のセクションの順序付けを行います。表 7-8 を参照してください。
x64 固有の共通ブロックラベル。このラベルは SHN_COMMON に似ていますが、大規模な共通ブロックの識別をサポートする点が異なります。
対応する参照の絶対値。たとえば、セクション番号 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-10 を参照してください。
セクションの内容とセマンティクスを分類します。セクションの種類とその説明は、表 7-5 を参照してください。
セクションは、さまざまな属性を記述する 1 ビットフラグをサポートします。フラグの定義は、表 7-8 を参照してください。
セクションがプロセスのメモリーイメージに現れる場合、このメンバーはセクションの先頭バイトが存在しなければならないアドレスを与えます。セクションがプロセスのメモリーイメージに現れない場合、このメンバーには 0 が存在します。
ファイルの先頭からセクションの先頭バイトまでのバイトオフセット。SHT_NOBITS 型のセクションの場合はファイル内のスペースを占めないため、このメンバーは、ファイル内の概念的なオフセットを示します。
セクションのサイズ (バイト)。セクションのタイプが SHT_NOBITS でないかぎり、セクションはファイルの sh_size バイトを占めます。タイプが SHT_NOBITS のセクションは、0 以外のサイズをとることがありますが、ファイルのスペースは占めません。
セクションヘッダーテーブルのインデックスリンク。このリンクの解釈は、セクションのタイプに依存します。値については、表 7-9 を参照してください。
追加情報。情報の解釈は、セクションのタイプに依存します。値については、表 7-9 を参照してください。このセクションヘッダーの sh_flags フィールドに属性 SHF_INFO_LINK が含まれている場合、このメンバーはセクションヘッダーテーブルインデックスを表します。
いくつかのセクションには、アドレス整列制約が存在します。たとえば、あるセクションが 2 語で構成されるデータを保持している場合、システムはそのセクション全体に対して 2 語単位の整列を保証しなければなりません。この場合、sh_addr の値は、sh_addralign の値を法として 0 でなければなりません。現在、0、および 2 の非負整数累乗のみが許可されています。値 0 と 1 は、セクションに整列制約が存在しないことを意味します。
いくつかのセクションは、サイズが一定のエントリのテーブル (シンボルテーブルなど) を保持します。このようなセクションに対してこのメンバーは、各エントリのサイズ (単位: バイト) を与えます。サイズが一定のエントリのテーブルをセクションが保持しない場合、このメンバーには 0 が格納されます。
セクションヘッダーの sh_type メンバーは、次の表に示すようにこのセクションのセマンティクスを示します。
表 7-5 ELF セクションタイプ、sh_type
|
セクションヘッダーが無効であることを示します。このセクションヘッダーには、関連付けられているセクションは存在しません。セクションヘッダーのほかのメンバーの値は不定です。
シンボルテーブルを示します。一般に、SHT_SYMTAB セクションはリンク編集に関するシンボルを示します。このテーブルには完全なシンボルテーブルとして、動的リンクに不要な多くのシンボルが存在することがあります。また、オブジェクトファイルには SHT_DYNSYM セクション (動的リンクシンボルの最小セットを保持して領域を節約している) が存在することがあります。
SHT_DYNSYM は、SHT_SUNW_LDYNSYM セクションで拡張することもできます。この追加セクションは、局所関数シンボルを実行時環境に提供しますが、動的リンクには必要ありません。このセクションを追加することで、SHT_SYMTAB を割り当てることができないために、テーブルが使用できないまたはファイルから削除されたときでも、デバッガは実行時状況で正確なスタックトレースを行うことができます。また、このセクションは、dladdr(3C) が使用する追加シンボリック情報を実行時環境に提供します。
SHT_SUNW_LDYNSYM セクションと SHT_DYNSYM セクションの両方があるときは、リンカーはそれらのデータ領域を並べて配置します。SHT_SUNW_LDYNSYM セクションは SHT_DYNSYM セクションの前に配置されます。このように配置されることで、SHT_SYMTAB の追加シンボルを含めて、これらの 2 つのテーブルを大きな 1 つの連続したシンボルテーブルとして表示することができます。
詳細は、「シンボルテーブルセクション」を参照してください。
文字列テーブルを示します。オブジェクトファイルには、複数の文字列テーブルセクションを指定できます。詳細は、「文字列テーブルセクション」を参照してください。
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) です。
機能ファミリメンバーを集めたインデックスの配列です。配列の最初の要素は連鎖バージョンメンバーです。この要素の後に来るのは、0 で終了する一連の機能シンボルインデックスです。インデックスの 0 で終了する各グループは機能ファミリを表します。各ファミリの最初の要素は機能の先頭のシンボルです。次の要素はファミリメンバーを指します。詳細については、「機能セクション」を参照してください。
シンボルテーブルエントリを機能要件に関連付けるインデックスの配列と、その先頭の機能シンボルです。シンボル機能を定義するオブジェクトには SHT_SUNW_cap セクションが含まれています。SHT_SUNW_cap セクションのヘッダー情報は、関連する SHT_SUNW_capinfo セクションを指します。SHT_SUNW_capinfo セクションのヘッダー情報は、関連するシンボルテーブルセクションを指します。詳細については、「機能セクション」を参照してください。
並んで配置される SHT_SUNW_LDYNSYM セクションと SHT_DYNSYM セクションによって作成される動的なシンボルテーブルへのインデックスの配列。これらのインデックスは、SHT_SUNW_LDYNSYM セクションの開始位置からの相対値です。インデックスはメモリーアドレスを含み、上記のシンボルを参照します。インデックスは、アドレスの昇順にシンボルを参照するようにソートされます。
並んで配置される SHT_SUNW_LDYNSYM セクションと SHT_DYNSYM セクションによって作成される動的なシンボルテーブルへのインデックスの配列。これらのインデックスは、SHT_SUNW_LDYNSYM セクションの開始位置からの相対値です。インデックスは、スレッド固有領域シンボルを参照します。第 8 章スレッド固有領域 (TLS)を参照してください。インデックスは、オフセットの昇順にシンボルを参照するようにソートされます。
非大域シンボル用の動的シンボルテーブル。すでに説明した「SHT_SYMTAB 、SHT_DYNSYM、SHT_SUNW_LDYNSYM」を参照してください。
dtrace(1M) の内部使用のため予約されています。
機能要件を指定します。詳細については、「機能セクション」を参照してください。
注釈セクションの処理は、デフォルトのセクション処理規則のすべてに従います。唯一の例外は、注釈セクションが割り当て不可能なメモリー内に存在する場合に発生します。セクションのヘッダーフラグ 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-6 ELF セクションヘッダーテーブルエントリ: インデックス 0
|
セクションまたはプログラムヘッダーの数が ELF ヘッダーデータサイズを超えた場合、セクションヘッダー 0 の構成要素を使って拡張 ELF ヘッダー属性が定義されます。その値は次の表のとおりです。
表 7-7 ELF 拡張セクションヘッダーテーブルエントリ: インデックス 0
|
セクションヘッダーの sh_flags メンバーは、セクションの属性を記述する 1 ビットフラグを保持します。
表 7-8 ELF セクションの属性フラグ
|
sh_flags にフラグビットが設定されると、属性がセクションに対して「オン」になります。設定されない場合は、属性が「オフ」になるか、または適用されません。定義されていない属性は保留され、0 に設定されています。
プロセス実行中にメモリーを占有するセクションを示します。いくつかの制御セクションは、オブジェクトファイルのメモリーイメージに存在しません。この属性は、これらのセクションに対してオフです。
マージして重複をなくすことの可能なデータを含むセクションを示します。同時に SHF_STRINGS フラグが設定されていないかぎり、このセクション内のデータ要素は統一されたサイズになります。各要素のサイズは、セクションヘッダーの sh_entsize フィールドで指定されます。同時に SHF_STRINGS フラグも設定されている場合は、データ要素はヌル文字で終わる文字列で構成されています。各文字のサイズは、セクションヘッダーの sh_entsize フィールドで指定されます。
ヌル文字で終わっている文字列で構成されるセクションを示します。各文字のサイズは、セクションヘッダーの sh_entsize フィールドで指定されます。
このセクションは、リンカーに特別な順序の要求を追加します。この要求は、このセクションのヘッダーの sh_link フィールドが別のセクション (リンク先のセクション) を参照する場合に適用されます。このセクションを出力ファイル内のほかのセクションと結合する場合、結合対象セクションと同じ相対的な順序で現われます。同様に、リンク先のセクションは、それが結合されるセクションに現われます。リンク先のセクションは順不同でなければならず、その結果 SHF_LINK_ORDER または SHF_ORDERED を指定することはできません。
特殊な sh_link 値である SHN_BEFORE および SHN_AFTER (表 7-4 を参照) は、順序付けされるセット内のほかのすべてのセクションに対して、ソートされたセクションがそれぞれ前に付くまたは後に付くことを示します。順序付けの対象となるセクションの複数にこれらの特殊値の 1 つが存在する場合、入力ファイルが指定された順序は保存されます。
このフラグを使用する場合の典型的なものとして、アドレスの順序でテキストまたはデータセクションを参照するテーブルを構築する場合があります。
sh_link 順序付け情報が存在しない場合、出力ファイルの 1 つのセクション内にまとめられた単一入力ファイルからのセクションは、連続的になります。これらのセクションの相対順序付けは、入力ファイル内のセクションの相対順序付けと同じになります。複数の入力ファイルからの場合は、リンクコマンドで指定された順序になります。
このセクションは、不適切な動作を避けるために、標準のリンク処理規則に含まれない OS 固有の特殊処理を必要とします。このセクションが、これらのフィールドに対して sh_type 値を持つか、OS 固有の範囲内にある sh_flags ビットを含み、かつリンカーがこれらの値を認識しない場合は、このセクションを含むオブジェクトファイルは拒否され、エラーが出力されます。
このセクションは、セクショングループのメンバー (おそらく唯一のメンバー) です。このセクションは、タイプ SHT_GROUP のセクションに参照されなければなりません。SHF_GROUP フラグは、再配置可能オブジェクト内に含まれるセクションに対してしか設定できません。詳細は、「グループセクション」を参照してください。
このセクションには、スレッド固有領域が格納されます。プロセス内の各スレッドは、このデータのインスタンスをそれぞれ別個に持ちます。詳細は、第 8 章スレッド固有領域 (TLS)を参照してください。
x64 用のデフォルトコンパイルモデルで使用できるのは、32 ビットのディスプレイスメントだけです。このディスプレイスメントでは、セクションのサイズ (最終的にはセグメントのサイズ) が 2G バイトに制限されます。この属性フラグは、2G バイトを超えるデータを格納できるセクションを識別します。このフラグを使えば、異なるコードモデルを使用するオブジェクトファイルのリンク処理を行えます。
SHF_AMD64_LARGE 属性フラグを含まない x64 オブジェクトファイルセクションは、小規模コードモデルを使用するオブジェクトから自由に参照できます。このフラグを含むセクションは、それよりも規模の大きいコードモデルを使用するオブジェクトからしか参照できません。たとえば、x64 中規模コードモデルのオブジェクトは、この属性フラグを含むセクション内のデータとこの属性フラグを含まないセクション内のデータを参照できます。ところが、x64 小規模コードモデルのオブジェクトは、このフラグを含まないセクション内のデータしか参照できません。
SHF_ORDERED は SHF_LINK_ORDER が提供する機能の古いバージョンであり、SHF_LINK_ORDER に置き換えられました。SHF_ORDERED は 2 つの異なる機能を提供します。1 つは、出力セクションを指定できる機能、もう 1 つは、リンカーから特別な順序付け要件を要求する機能です。
SHF_ORDERED セクションの sh_link フィールドはセクションのリンクリストを形成します。このリストは、自分自身を指す sh_link を持つ最終セクションで終了します。このリストにあるすべてのセクションは、リストの最終セクションの名前を使用して、出力セクションに割り当てられます。
順序付けられるセクションの sh_info エントリが同一入力ファイル内の有効セクションの場合、順序付けられるセクションは、sh_info エントリでポイントされるセクションの出力ファイル内の相対順序付けに基づいて整列されます。sh_info エントリによって指されたセクションは順不同でなければならず、その結果、SHF_LINK_ORDER または SHF_ORDERED を指定することができません。
特殊な sh_info 値である SHN_BEFORE および SHN_AFTER (表 7-4 を参照) は、順序付けされるセット内のほかのすべてのセクションに対して、ソートされたセクションがそれぞれ前に付くまたは後に付くことを示します。順序付けの対象となるセクションの複数にこれらの特殊値の 1 つが存在する場合、入力ファイルが指定された順序は保存されます。
sh_info 順序付け情報が存在しない場合、出力ファイルの 1 つのセクション内にまとめられた単一入力ファイルからのセクションは、連続的になります。これらのセクションの相対順序付けは、入力ファイル内で表示されるセクションの相対順序付けと同じになります。複数の入力ファイルからの場合は、リンクコマンドで指定された順序になります。
このセクションは、実行可能オブジェクトまたは共有オブジェクトのリンク編集への入力から除外されます。このフラグは、SHF_ALLOC フラグが設定されている場合、またはセクションに対する参照が存在する場合、無視されます。
セクションヘッダーの 2 つのメンバー sh_link と sh_info は、セクション型に従って特殊な情報を保持します。
表 7-9 ELF sh_link と sh_info の解釈
|
SHF_MERGE セクションフラグを使って、再配置可能オブジェクト内の SHT_PROGBITS セクションにマークすることができます。表 7-8 を参照してください。このフラグによって、そのセクションがほかのオブジェクトの互換セクションとマージできることがわかります。これらの再配置可能オブジェクトをマージすることによって、それらから構築される実行可能ファイルや共有オブジェクトのサイズを減らせる可能性があります。サイズを減らすことによって、最終オブジェクトの実行時パフォーマンスが向上することもあります。
セクションに SHF_MERGE フラグが付いていることは、次のような特性があることを示します。
セクションは読み取り専用です。このセクションを含むプログラムは、実行時にセクションデータを変更することはできません。
セクション内の各項目はそれぞれの再配置レコードからアクセスされます。プログラムコードは、セクション内の項目にアクセスするコードを生成するときに、それらの項目の相対位置についていかなる仮定を行ってはいけません。
セクションに SHF_STRINGS フラグも設定されている場合は、そのセクションには NULL で終わっている文字列だけを含めることができます。NULL 文字は文字列の最後にしか使用できません。文字列の途中に NULL 文字が現れてはいけません。
SHF_MERGE は、最適化できる可能性があることを示す、省略可能なフラグです。リンカーは、最適化を実行するか最適化を無視するかを選択できます。リンカーは、いずれの場合も有効な出力オブジェクトを作成します。リンカーは現在のところ、SHF_STRINGS フラグがマークされた文字列データを含むセクションだけに、セクションのマージを実装します。
SHF_STRINGS セクションフラグと一緒に SHF_MERGE フラグも設定されているときは、そのセクション内の文字列はほかの互換セクション内の文字列とマージできます。リンカーは、SHT_STRTAB 文字列テーブル .strtab と .dynstr の圧縮に使用される文字列圧縮アルゴリズムを使用して、このようなセクションをマージします。
重複する文字列は 1 つだけがコピーされます。
末尾の文字列は削除されます。たとえば、入力セクションに文字列「bigdog」と「dog」が含まれる場合は、短いほうの「dog」文字列が削除され、長い文字列の末尾を使って短い文字列が表現されます。
リンカーは現在のところ、バイトサイズ文字から構成され、特殊な整列制約のない文字列だけに、文字列のマージを実装します。具体的には、セクションは次の特性を備えている必要があります。
sh_entsize は 0 または 1 でなければいけません。ワイド文字を含むセクションはサポートされません。
sh_addralign が 0 または 1 であるバイト整列のセクションのみがマージされます。
さまざまなセクションがプログラム情報と制御情報を保持します。次の表に示すセクションはシステムで使用されますが、これらのセクションには指定された型と属性が存在します。
表 7-10 ELF 特殊セクション
|
プログラムのメモリーイメージで使用される、初期化されていないデータ。システムは、プログラムが実行を開始すると 0 でデータを初期化することになっています。このセクションは、セクション型 SHT_NOBITS で示しているとおり、ファイル領域を占めません。
コメント情報 (通常、コンパイルシステムのコンポーネントが使用)。このセクションは、mcs(1) により操作できます。
プログラムのメモリーイメージで使用される、初期化済みのデータ。
動的リンク情報。詳細は、「動的セクション」を参照してください。
動的リンクに必要な文字列 (もっとも一般的には、シンボルテーブルエントリに関連付けられている名前を表す文字列)。
動的リンクシンボルテーブル。詳細は、「シンボルテーブルセクション」を参照してください。
スタックを戻すために使用する呼び出しフレーム情報。
このセクションを含む実行可能ファイルまたは共有オブジェクトの単一の終了関数で使用される実行可能命令。詳細は、「初期設定および終了ルーチン」を参照してください。
このセクションを含む実行可能ファイルまたは共有オブジェクトの単一の終了配列に使用される関数ポインタの配列。詳細は、「初期設定および終了ルーチン」を参照してください。
大域オフセットテーブル。詳細は、「大域オフセットテーブル (プロセッサ固有)」を参照してください。
シンボルハッシュテーブル。詳細は、「ハッシュテーブルセクション」を参照してください。
このセクションを含む実行可能ファイルまたは共有オブジェクトの単一の初期化関数で使用される実行可能命令。詳細は、「初期設定および終了ルーチン」を参照してください。
このセクションを含む実行可能ファイルまたは共有オブジェクトの単一の初期化配列に使用される関数ポインタの配列。詳細は、「初期設定および終了ルーチン」を参照してください。
プログラムインタプリタのパス名。詳細は、「プログラムインタプリタ」を参照してください。
x64 固有の初期化されていないデータ。このデータは .bss に似ていますが、2G バイトを超えるセクションをサポートする点が異なります。
x64 固有の初期化済みデータ。このデータは .data に似ていますが、2G バイトを超えるセクションをサポートする点が異なります。
x64 固有の読み取り専用データ。このデータは .rodata に似ていますが、2G バイトを超えるセクションをサポートする点が異なります。
「注釈セクション」に記載された形式の情報。
プロシージャーのリンクテーブル。詳細は、「プロシージャーのリンクテーブル (プロセッサ固有)」を参照してください。
このセクションを含む実行可能ファイルまたは共有オブジェクトの単一の「初期設定前」の配列に使用される関数ポインタの配列。詳細は、「初期設定および終了ルーチン」を参照してください。
特定のセクションに適用されない再配置情報。このセクションの用途の 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(3C) により作成される動的実行可能ファイルのヒープ。
.SUNW_ldynsym と .dynsym の結合シンボルテーブル内のシンボルへのインデックスの配列。インデックスは、アドレスの昇順にシンボルを参照するようにソートされます。変数を表現しないシンボルまたは関数を表現しないシンボルは取り込まれません。大域シンボルとウィークシンボルが冗長な場合には、ウィークシンボルのみが残ります。詳細は、「シンボルソートセクション」を参照してください。
.SUNW_ldynsym と .dynsym の結合シンボルテーブル内のスレッド固有領域シンボルへのインデックスの配列。インデックスは、オフセットの昇順にシンボルを参照するようにソートされます。TLS 変数を表現しないシンボルは取り込まれません。大域シンボルとウィークシンボルが冗長な場合には、ウィークシンボルのみが残ります。詳細は、「シンボルソートセクション」を参照してください。
.dynsym セクションを拡張します。このセクションには、完全な .symtab セクションを使用できない状況で使用される局所関数シンボルが含まれます。リンカーは常に、.SUNW_ldynsym セクションのデータを .dynsym セクションの直前に並べて配置します。両方のセクションは常に同じ .dynstr 文字列テーブルセクションを使用します。この配置と構成により、両方のシンボルテーブルを 1 つの大きなシンボルテーブルとして処理することができます。「シンボルテーブルセクション」を参照してください。
部分的に初期化されたデータに関する追加情報。詳細は、「移動セクション」を参照してください。
再配置情報 (詳細は、「再配置セクション」を参照)。このセクションは再配置セクションが連結されたものであり、個々の再配置レコードに対するより良い参照のローカル性 (局所性) を与えます。再配置レコードのオフセットのみが意味があり、したがってセクション 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 セクションに配置された場合、保持されている最終的な 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-11 ELF グループセクションのフラグ
|
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 つに関連して定義されたシンボルテーブルエントリは、グループのメンバーが破棄されると削除されることがあります。この削除が行われるのは、シンボルテーブルエントリが含まれるシンボルテーブルセクションがグループの一部ではない場合です。
SHT_SUNW_cap セクションはオブジェクトの機能要件を指定します。これらの機能はオブジェクト機能と呼ばれます。このセクションは、オブジェクト内の関数の機能要件または初期化されたデータ項目も指定できます。これらの機能はシンボル機能と呼ばれます。このセクションには、次の構造の配列が含まれます。sys/elf.h を参照してください。
typedef struct { Elf32_Word c_tag; union { Elf32_Word c_val; Elf32_Addr c_ptr; } c_un; } Elf32_Cap; typedef struct { Elf64_Xword c_tag; union { Elf64_Xword c_val; Elf64_Addr c_ptr; } c_un; } Elf64_Cap;
この種の各オブジェクトに対して、c_tag は c_un の解釈を制御します。
このオブジェクトは、さまざまに解釈される整数値を表します。
このオブジェクトは、プログラムの仮想アドレスを表します。
次の機能タグがあります。
表 7-12 ELF 機能配列タグ
|
機能グループの最後にマークを付けます。
ハードウェア機能の値を示します。c_val 要素は、関連ハードウェア機能を表す値を含みます。SPARC プラットフォームでは、ハードウェア機能は sys/auxv_SPARC.h に定義されます。x86 プラットフォームでは、ハードウェア機能は sys/auxv_386.h に定義されます。
ソフトウェア機能の値を示します。c_val 要素は、sys/elf.h に定義される関連ソフトウェア機能を表す値を含みます。
プラットフォーム名を指定します。c_ptr 要素は、プラットフォーム名を定義する、ヌル文字で終わる文字列の文字列テーブルオフセットを含みます。
マシン名を指定します。c_ptr 要素は、マシンハードウェア名を定義する、ヌル文字で終わる文字列の文字列テーブルオフセットを含みます。
機能識別子名を指定します。c_ptr 要素は、識別子名を定義する、ヌル文字で終わる文字列の文字列テーブルオフセットを含みます。この要素は機能を定義しませんが、機能グループの参照に使用できる固有のシンボリック名を機能グループに割り当てます。この識別子名は、リンカーの -z symbolcap 処理の一部として局所シンボルに変換される、すべての大域シンボル名に追加されます。「オブジェクト機能のシンボル機能への変換」を参照してください。
再配置可能オブジェクトには、機能セクションを含めることができます。リンカーは、複数の入力再配置可能オブジェクトからの機能セクションを 1 つの機能セクションに統合します。リンカーを使用すると、オブジェクトの構築時に機能を定義することもできます。「機能要件の特定」を参照してください。
CA_SUNW_NULL で終了する複数の機能グループがオブジェクト内に存在できます。最初のグループ (インデックス 0 から開始) はオブジェクト機能を指定します。オブジェクト機能を定義する動的オブジェクトには、セクションに関連した PT_SUNWCAP プログラムヘッダーがあります。このプログラムヘッダーにより、実行時リンカーは、プロセスで利用可能なシステム機能に対してオブジェクトを確認できます。異なるオブジェクト機能を利用する動的オブジェクトは、フィルタを使用して柔軟な実行環境を提供できます。「機能固有の共有オブジェクト」を参照してください。
追加の機能グループはシンボル機能を指定します。シンボル機能によって、同じシンボルの複数のインスタンスがオブジェクト内に存在できます。各インスタンスは、そのインスタンスを使用するために利用できなければならない一連の機能に関連付けられています。シンボル機能が存在する場合、SHT_SUNW_cap セクションの sh_link 要素は関連の SHT_SUNW_capinfo テーブルを指します。シンボル機能を利用する動的オブジェクトでは、特定のシステム向けに最適化された関数を柔軟に有効化できます。「シンボル機能関数ファミリの作成」を参照してください。
SHT_SUNW_capinfo テーブルは関連のシンボルテーブルに相当します。SHT_SUNW_capinfo セクションの sh_link 要素は関連のシンボルテーブルを指します。機能に関連付けられた関数は、SHT_SUNW_cap セクション内の機能グループを指定する SHT_SUNW_capinfo テーブル内にインデックスを持ちます。
動的オブジェクト内では、SHT_SUNW_capinfo セクションの sh_info 要素は機能連鎖テーブルである SHT_SUNW_capchain を指します。このテーブルは、実行時リンカーが機能ファミリのメンバーの位置を特定するために使用されます。
SHT_SUNW_capinfo テーブルエントリの形式は次のとおりです。sys/elf.h を参照してください。
typedef Elf32_Word Elf32_Capinfo; typedef Elf64_Xword Elf64_Capinfo;
このテーブル内の要素は、次のマクロを使用して解釈されます。sys/elf.h を参照してください。
#define ELF32_C_SYM(info) ((info)>>8) #define ELF32_C_GROUP(info) ((unsigned char)(info)) #define ELF32_C_INFO(sym, grp) (((sym)<<8)+(unsigned char)(grp)) #define ELF64_C_SYM(info) ((info)>>32) #define ELF64_C_GROUP(info) ((Elf64_Word)(info)) #define ELF64_C_INFO(sym, grp) (((Elf64_Xword)(sym)<<32)+(Elf64_Xword)(grp))
SHT_SUNW_capinfo エントリの group 要素には、このシンボルに関連する SHT_SUNW_cap テーブルのインデックスが含まれています。このようにして、この要素はシンボルを機能グループに関連付けます。予約済みのグループインデックスである CAPINFO_SUNW_GLOB は、機能インスタンスファミリの先頭のシンボルを識別して、デフォルトのインスタンスを指定します。
|
SHT_SUNW_capinfo エントリの symbol 要素には、このシンボルに関連する先頭のシンボルのインデックスが含まれます。グループとシンボルの情報を使用すると、リンカーは再配置可能オブジェクトから機能シンボルファミリを処理し、すべての出力オブジェクトに必要な機能情報を作成できます。動的オブジェクトでは、グループ CAPINFO_SUNW_GLOB を使用してタグが付けられた先頭のシンボルのシンボル要素が、SHT_SUNW_capchain テーブル内へのインデックスです。このインデックスを使用すると、実行時リンカーは機能連鎖テーブルをこのインデックスからたどり、0 エントリが検出されるまでエントリを次々に検査できます。この連鎖エントリには、機能ファミリメンバーごとにシンボルインデックスが含まれています。
シンボル機能を定義している動的オブジェクトには、DT_SUNW_CAP 動的エントリと DT_SUNW_CAPINFO 動的エントリがあります。これらのエントリは、それぞれ SHT_SUNW_cap セクションと SHT_SUNW_capinfo セクションを特定します。オブジェクトには、SHT_SUNW_capchain セクション、セクションのエントリサイズ、および合計サイズを指定する DT_SUNW_CAPCHAIN、DT_SUNW_CAPCHAINENT、および DT_SUNW_CAPCHAINSZ のエントリも含まれます。これらのエントリを使用すると、実行時リンカーはシンボル機能インスタンスファミリから、使用に最適なシンボルを確立できます。
オブジェクトは、オブジェクト機能のみ、シンボル機能のみ、または両方のタイプの機能を定義できます。オブジェクト機能グループはインデックス 0 から開始します。シンボル機能グループは 0 以外のインデックスから開始します。オブジェクトでシンボル機能が定義されているが、オブジェクト機能が定義されていない場合、シンボル機能の開始を示すためにインデックス 0 に 1 つの CA_SUNW_NULL エントリが存在する必要があります。
ハッシュテーブルは、シンボルテーブルへのアクセスを提供する 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 の場合、初期化が連続した単位に対して行われることを示します。
次のデータ定義は、通常、オブジェクトファイル内で 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 symndx offset size repeat stride value with respect to [17] 8 4 1 1 0x000000000000000001 move [17] 12 4 1 1 0x000000000031000000 move [17] 24 4 2 1 0x00000000000000000f move [17] 28 4 2 1 0x000000000046000000 move [17] 48 4 1 1 0x00000000000000000e move [17] 52 4 1 1 0x000000000045000000 move [17] 64 4 1 1 0x00000000000000000e move [17] 68 4 1 1 0x000000000045000000 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 つのエントリを保持しています。
図 7-6 注釈セグメントの例
注 - システムは、名前なし (namesz == 0) の注釈情報と、長さ 0 の名前 (name[0] == '\0') を持つ注釈情報を予約していますが、現時点ではタイプは定義していません。ほかのすべての名前には、少なくとも 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))
64 ビット SPARC 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 ビット SPARC では、Elf32_Rela 再配置エントリのみを使用します。64 ビット SPARC および 64 ビット x86 では、 Elf64_Rela 再配置エントリのみを使用します。したがって、r_addend メンバーは再配置加数として機能します。x86 は、Elf32_Rel 再配置エントリのみを使用します。再配置対象のフィールドは、加数を保持します。すべての場合において、加数と計算された結果は同じバイト順序を使用します。
再配置セクションは、ほかに 2 つのセクションを参照することがあります。 1 つは sh_info セクションヘッダーエントリにより示されるシンボルテーブルで、もう 1 つは sh_link セクションヘッダーエントリにより示される変更対象のセクションです。「セクション」 に、各セクションの関係を示します。再配置オブジェクトに再配置セクションが存在するが、実行可能ファイルや共有オブジェクトが任意の場合は、sh_info エントリが必要です。再配置オフセットが存在すれば、再配置を実行できます。
再配置エントリには、次の図に示す命令およびデータフィールドの変更方法が記述されます。ビット番号は、下隅に示されています。
SPARC プラットフォームの場合、再配置エントリはバイト (byte8)、ハーフワード (half16) またはワードに適用されます。
64 ビット SPARC と x64 では、再配置は拡張ワード (xword64) にも適用されます。
x86 の場合、再配置エントリはワード (word32) に適用されます。
word32 は、任意バイト整列が存在する 4 バイトを占める 32 ビットフィールドを指定します。これらの値は、x86 アーキテクチャーにおけるほかのワード値と同じバイト順序を使用します。
いずれの場合でも r_offset 値は、影響が与えられる領域の先頭バイトのオフセットまたは仮想アドレスを指定します。再配置タイプは、変更されるビットと、これらのビットの値の計算方法を指定します。
次の再配置型の計算では、操作により、再配置可能ファイルが実行可能ファイルまたは共有オブジェクトファイルに変換されることが仮定されています。概念上、リンカーは 1 つまたは複数の再配置可能ファイルを併合して出力します。リンカーは、まず入力ファイルの結合/配置方法を決めます。次に、シンボルの値を更新し、再配置を実行します。実行可能オブジェクトファイルと共有オブジェクトファイルに適用される再配置は類似しており、同じ結果を実現します。このセクションの表では、次の表記が使用されています。
再配置可能フィールドの値を計算するために使用される加数。
実行時に共有オブジェクトがメモリーに読み込まれるベースアドレス。一般的に、共有オブジェクトファイルは、ベース仮想アドレス 0 で作成されます。ただし、共有オブジェクトの実行アドレスは異なります。「プログラムヘッダー」を参照してください。
実行時に再配置エントリのシンボルのアドレスが存在する大域オフセットテーブルへのオフセット。「大域オフセットテーブル (プロセッサ固有)」を参照してください。
大域オフセットテーブルのアドレス。「大域オフセットテーブル (プロセッサ固有)」を参照してください。
シンボルに対するプロシージャーのリンクテーブルエントリのセクションオフセットまたはアドレス。「プロシージャーのリンクテーブル (プロセッサ固有)」を参照してください。
再配置される領域のセクションオフセットまたはアドレス (r_offset を使用して計算)。
インデックスが再配置エントリ内に存在するシンボルの値。
インデックスが再配置エントリ内に存在するシンボルのサイズ。
次の表に示すフィールド名は、再配置型がオーバーフローを検査するかどうかを通知します。計算される再配置値は意図したフィールドより大きい場合があり、再配置型によっては値の適合を検証 (V) したり結果を切り捨てたり (T) することがあります。たとえば、V-simm13 は、計算された値が simm13 フィールドの外部に 0 以外の有意ビットを持つことがないことを意味します。
表 7-13 SPARC: ELF 再配置型
|
いくつかの再配置型には、単純な計算を超えたセマンティクスが存在します。
R_SPARC_LO10 に似ていますが、シンボルの GOT エントリのアドレスを参照する点が異なります。また、 R_SPARC_GOT10 は、大域オフセットテーブルの作成をリンカーに指示します。
R_SPARC_13 に似ていますが、シンボルの GOT エントリのアドレスを参照する点が異なります。また、 R_SPARC_GOT13 は、大域オフセットテーブルの作成をリンカーに指示します。
R_SPARC_22 に似ていますが、シンボルの GOT エントリのアドレスを参照する点が異なります。また、 R_SPARC_GOT22 は、大域オフセットテーブルの作成をリンカーに指示します。
R_SPARC_WDISP30 に似ていますが、シンボルのプロシージャーリンクテーブルエントリのアドレスを参照する点が異なります。また、R_SPARC_WPLT30 は、プロシージャーのリンクテーブル作成をリンカーに指示します。
リンカーは、この再配置型を作成して、動的実行可能ファイルが読み取り専用のテキストセグメントを保持できるようにします。この再配置型のオフセットメンバーは、書き込み可能セグメントの位置を参照します。シンボルテーブルインデックスは、現オブジェクトファイルと共有オブジェクトの両方に存在する必要があるシンボルを指定します。実行時、実行時リンカーは共有オブジェクトのシンボルに関連付けられているデータを、オフセットで指定されている位置にコピーします。「コピー再配置」を参照してください。
R_SPARC_32 に似ていますが、再配置は GOT エントリを指定されたシンボルのアドレスに設定する点が異なります。この特殊な再配置型を使うと、シンボルと GOT エントリの対応付けを判定できます。
リンカーは、動的オブジェクトが遅延結合を提供できるようにするため、この再配置型を作成します。この再配置型のオフセットメンバーは、プロシージャーのリンクテーブルエントリの位置を与えます。実行時リンカーは、プロシージャーのリンクテーブルエントリを変更して指定シンボルアドレスに制御を渡します。
リンカーは、動的オブジェクト用にこの再配置型を作成します。この再配置型のオフセットメンバーは、相対アドレスを表す値が存在する、共有オブジェクト内の位置を与えます。実行時リンカーは共有オブジェクトが読み込まれる仮想アドレスに相対アドレスを加算することで、対応する仮想アドレスを計算します。この型に対する再配置エントリは、シンボルテーブルインデックスに対して値 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-14 64 ビット SPARC: ELF 再配置型
|
次の再配置型には、単純な計算を超えたセマンティクスが存在します。
R_SPARC_LO10 に似ていますが、符号付き13 ビット即値フィールドを十分に使用するために余分なオフセットが追加される点が異なります。
次の表に、32 ビット x86 用に定義された再配置を示します。
表 7-15 32 ビット x86: ELF 再配置型
|
いくつかの再配置型には、単純な計算を超えたセマンティクスが存在します。
GOT のベースからシンボルの GOT エントリまでの距離を計算します。この再配置型はまた、大域オフセットテーブルを作成するようにリンカーに指示します。
シンボルのプロシージャーのリンクテーブルエントリのアドレスを計算し、かつプロシージャーのリンクテーブルを作成するようにリンカーに指示します。
リンカーは、この再配置型を作成して、動的実行可能ファイルが読み取り専用のテキストセグメントを保持できるようにします。この再配置型のオフセットメンバーは、書き込み可能セグメントの位置を参照します。シンボルテーブルインデックスは、現オブジェクトファイルと共有オブジェクトの両方に存在する必要があるシンボルを指定します。実行時、実行時リンカーは共有オブジェクトのシンボルに関連付けられているデータを、オフセットで指定されている位置にコピーします。「コピー再配置」を参照してください。
GOT エントリを、指定されたシンボルのアドレスに設定します。この特殊な再配置型を使うと、シンボルと GOT エントリの対応付けを判定できます。
リンカーは、動的オブジェクトが遅延結合を提供できるようにするため、この再配置型を作成します。この再配置型のオフセットメンバーは、プロシージャーのリンクテーブルエントリの位置を与えます。実行時リンカーは、プロシージャーのリンクテーブルエントリを変更して指定シンボルアドレスに制御を渡します。
リンカーは、動的オブジェクト用にこの再配置型を作成します。この再配置型のオフセットメンバーは、相対アドレスを表す値が存在する、共有オブジェクト内の位置を与えます。実行時リンカーは共有オブジェクトが読み込まれる仮想アドレスに相対アドレスを加算することで、対応する仮想アドレスを計算します。この型に対する再配置エントリは、シンボルテーブルインデックスに対して値 0 を指定する必要があります。
シンボルの値と GOT のアドレスの差を計算します。この再配置型はまた、大域オフセットテーブルを作成するようにリンカーに指示します。
R_386_PC32 に似ていますが、計算を行う際に GOT のアドレスを使用する点が異なります。この再配置で参照されるシンボルは、通常 _GLOBAL_OFFSET_TABLE_ です。 この再配置型はまた、大域オフセットテーブルを作成するようにリンカーに指示します。
次の表に、x64 用に定義された再配置を示します。
表 7-16 x64: ELF 再配置型
|
これらの再配置型のほとんどの特別なセマンティクスは、x86 で使用されているものと同じです。いくつかの再配置型には、単純な計算を超えたセマンティクスが存在します。
この再配置のセマンティクスは R_AMD64_GOT32 または等しい R_386_GOTPC 再配置と異なります。x64 アーキテクチャーは、命令ポインタに対して相対的なアドレス指定モードを提供します。したがって、アドレスは 1 つの命令で GOT から読み込むことができます。
R_AMD64_GOTPCREL 再配置の計算は、シンボルのアドレスを指定した GOT 内の位置と再配置を適用する位置の間の差を提供します。
計算値は 32 ビットに切り捨てられます。リンカーは、再配置のために生成された値が元の 64 ビット値にゼロ拡張されていることを確認します。
計算値は 32 ビットに切り捨てられます。リンカーは、再配置のために生成された値が元の 64 ビット値に符号拡張されていることを確認します。
これらの再配置は x64 ABI には準拠していませんが、文書化するためにここに追加しておきます。R_AMD64_8 再配置は、計算値を 8 ビットに切り詰めます。R_AMD64_16 再配置は、計算値を 16 ビットに切り詰めます。
文字列テーブルセクションは、ヌル文字で終了する一連の文字 (一般に文字列と呼ばれている) を保持します。オブジェクトファイルは、これらの文字列を使用してシンボルとセクション名を表します。文字列をインデックスに使用して、文字列テーブルセクションを参照します。
先頭バイト (インデックス 0) は、ヌル文字を保持します。同様に、文字列テーブルの最後のバイトは、ヌル文字を保持します。したがって、すべての文字列は確実にヌル文字で終了します。したがって、すべての文字列は確実にヌル文字で終了します。インデックスが 0 の文字列は、名前を指定しないかヌル文字の名前を指定します (状況に依存する)。
空の文字列テーブルセクションが許可されており、セクションヘッダーの sh_size メンバーに 0 が入ります。0 以外のインデックスは、空の文字列テーブルに対して無効です。
セクションヘッダーの sh_name メンバーは、セクションヘッダー文字列テーブルセクションへのインデックスを保持します。セクションヘッダー文字列テーブルは、ELF ヘッダーの e_shstrndx メンバーで示されます。次の図は、25 バイトの文字列テーブルと、さまざまなインデックスに関連付けられている文字列を示しています。
図 7-7 ELF 文字列テーブル
次の表に、上の図に示した文字列テーブルの文字列を示しています。
表 7-17 ELF 文字列テーブルインデックス
|
例で示しているとおり、文字列テーブルインデックスはセクションのすべてのバイトを参照できます。文字列は 2 回以上出現可能です。部分文字列に対する参照は存在可能です。単一文字列は複数回参照可能です。参照されない文字列も許可されます。
オブジェクトファイルのシンボルテーブルには、プログラムのシンボル定義とシンボル参照の検索と再配置に必要となる情報が格納されます。シンボルテーブルインデックスは、この配列への添字です。インデックス 0 はシンボルテーブルの先頭エントリを指定し、また未定義シンボルインデックスとして機能します。表 7-21 を参照してください。
シンボルテーブルエントリの形式は、次のとおりです。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-18 に示します。次のコードは、値の処理方法を示します。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-20 に示します。次のコードは、32 ビットオブジェクトと 64 ビットオブジェクトの両方の値を操作する方法を示しています。その他のビットは 0 に設定され、特に意味はありません。
#define ELF32_ST_VISIBILITY(o) ((o)&0x3) #define ELF64_ST_VISIBILITY(o) ((o)&0x3)
すべてのシンボルテーブルエントリは、何らかのセクションに関して定義されます。このメンバーは、該当するセクションヘッダーテーブルインデックスを保持します。いくつかのセクションインデックスは、特別な意味を示します。表 7-4 を参照してください。
このメンバーに SHN_XINDEX が含まれる場合は、実際のセクションヘッダーインデックスが大きすぎてこのフィールドに入りません。実際の値は、タイプ SHT_SYMTAB_SHNDX の関連するセクション内に存在します。
シンボルのバインディングは、st_info フィールドで決定されますが、これにより、リンクの可視性と動作が決定します。
表 7-18 ELF シンボルのバインディング、(ELF32_ST_BIND、ELF64_ST_BIND)
|
局所シンボル。局所シンボルは、局所シンボルの定義が存在するオブジェクトファイルの外部では見えません。同じ名前の局所シンボルは、互いに干渉することなく複数のファイルに存在できます。
大域シンボル。大域シンボルは、結合されるすべてのオブジェクトファイルで見ることができます。あるファイルの大域シンボルの定義は、その大域シンボルへの別ファイルの未定義参照を解決します。
ウィークシンボル。ウィークシンボルは大域シンボルに似ていますが、ウィークシンボルの定義の優先順位は大域シンボルの定義より低いです。
この範囲の値 (両端の値を含む) は、オペレーティングシステム固有のセマンティクスのために予約されています。
この範囲の値は、プロセッサ固有のセマンティクスのために予約されています。
大域シンボルとウィークシンボルは、主に 2 つの点で異なります。
リンカーがいくつかの再配置可能オブジェクトファイルを結合する場合は、同じ名前を持つ複数の STB_GLOBAL シンボルは定義できません。ただし、定義された大域シンボルが存在している場合、同じ名前のウィークシンボルが現れてもエラーは発生しません。リンカーは大域定義を使用し、ウィーク定義を無視します。
同様に、共有シンボルが存在している場合にそれと同じ名前のウィークシンボルが現れても、エラーは発生しません。リンカーは共通定義を使用し、ウィーク定義を無視します。共通シンボルは、SHN_COMMON を保持する st_shndx フィールドを持ちます。「シンボル解決」を参照してください。
リンカーがアーカイブライブラリを検索すると、未定義または一時的な大域シンボル定義が存在するアーカイブメンバーが抽出されます。メンバーの定義は、大域シンボルまたはウィークシンボルになります。
リンカーはデフォルトでは、未定義のウィークシンボルを解決するためのアーカイブメンバーを抽出しません。解決されていないウィークシンボルは、値 0 を持ちます。-z weakextract を使用すると、このデフォルトの動作が無効になります。このオプションを使用すると、ウィーク参照がアーカイブメンバーを抽出できます。
注 - ウィークシンボルは、主にシステムソフトウェアでの使用を意図したものです。アプリケーションプログラムでの使用は推奨されません。
各シンボルテーブルにおいて、STB_LOCAL 結合を持つすべてのシンボルは、ウィークシンボルと大域シンボルの前に存在します。「セクション」に記述されているとおり、シンボルテーブルセクションの sh_info セクションヘッダーメンバーは、最初のローカルではないシンボルに対するシンボルテーブルインデックスを保持します。
シンボルのタイプは st_info フィールドで指定され、これにより、関連付けられた実体の一般的な分類が決定されます。
表 7-19 ELF シンボルのタイプ (ELF32_ST_TYPE、ELF64_ST_TYPE)
|
シンボルの種類は指定されません。
シンボルは、データオブジェクト (変数や配列など) と関連付けられています。
シンボルは、関数またはほかの実行可能コードに関連付けられています。
シンボルは、セクションに関連付けられています。この種類のシンボルテーブルエントリは主に再配置を行うために存在しており、通常、STB_LOCAL に結び付けられています。
慣例により、シンボルの名前はオブジェクトファイルに対応するソースファイルの名前を与えます。ファイルシンボルは STB_LOCAL に結び付けられており、セクションインデックスは SHN_ABS です。このシンボルは、存在する場合、ファイルのほかの STB_LOCAL シンボルの前に存在します。
SHT_SYMTAB のシンボルインデックス 1 は、そのオブジェクトファイルを表す STT_FILE シンボルです。慣例により、このシンボルの後にはファイル STT_SECTION シンボルが続きます。これらのセクションシンボルの後には、ローカルになった大域シンボルが続きます。
このシンボルは、初期設定されていない共通ブロックを表します。このシンボルは、STT_OBJECT とまったく同じに扱われます。
シンボルは、スレッド固有領域の実体を指定します。定義されている場合、実際のアドレスではなく、シンボルに割り当てられたオフセットを提供します。
スレッドローカルストレージの再配置では、タイプが STT_TLS のシンボルしか参照できません。割り当て可能なセクションからタイプが STT_TLS のシンボルを参照するには、特別なスレッドローカルストレージ再配置を使用するしか方法がありません。詳細は、第 8 章スレッド固有領域 (TLS)を参照してください。割り当てができないセクションからタイプが STT_TLS のシンボルを参照する際には、この制限はありません。
この範囲の値 (両端の値を含む) は、オペレーティングシステム固有のセマンティクスのために予約されています。
この範囲の値は、プロセッサ固有のセマンティクスのために予約されています。
シンボルの可視性は、その st_other フィールドで決まります。この可視性は、再配置可能オブジェクトで指定できます。シンボルの可視性により、シンボルが実行可能ファイルまたは共有オブジェクトの一部になった後のシンボルへのアクセス方法が定義されます。
表 7-20 ELF シンボルの可視性
|
STV_DEFAULT 属性を持つシンボルの可視性は、シンボルの結合タイプで指定されたものになります。大域シンボルおよびウィークシンボルは、それらの定義するコンポーネント (実行可能ファイルまたは共有オブジェクト) の外から見ることができます。局所シンボルは、「隠されて」います。大域シンボルおよびウィークシンボルは、横取りすることもできます。別のコンポーネントの同じ名前の定義によってこれらのシンボルに割り込むこともできます。
現在のコンポーネント内で定義されたシンボルは、それがほかのコンポーネント内で参照可能であるが横取り可能ではない場合、保護されています。定義コンポーネント内からシンボルへの参照など、あらゆる参照について、コンポーネント内の定義に解決する必要があります。この解決は、シンボル定義がデフォルト規則によって割り込みを行う別のコンポーネント内に存在する場合も、実行する必要があります。STB_LOCAL 結合を持つシンボルは、STV_PROTECTED 可視性を持ちません。
現在のコンポーネント内で定義されたシンボルは、その名前がほかのコンポーネントから参照することができない場合、「隠されて」います。そのようなシンボルは、保護される必要があります。この属性は、コンポーネントの外部インタフェースの管理に使用されます。そのようなシンボルによって指定されたオブジェクトは、そのアドレスが外部に渡された場合でも、ほかのコンポーネントから参照可能です。
再配置可能オブジェクトに含まれた「隠された」シンボルは、そのオブジェクトが実行可能ファイルまたは共有オブジェクトに含まれる時には、削除されるか STB_LOCAL 結合に変換されます。
この可視性の属性は、現在予約されています。
この可視性属性によって、シンボルのスコープが大域に維持されます。ほかのどのようなシンボル可視性テクニックを使っても、この可視性を降格または削除することはできません。STB_LOCAL 結合を持つシンボルは、STV_EXPORTED 可視性を持ちません。
この可視性属性によって、シンボルのスコープが大域に維持され、プロセス内のすべての参照はシンボル定義の 1 つのインスタンスだけにバインドされます。ほかのどのようなシンボル可視性テクニックを使っても、この可視性を降格または削除することはできません。STB_LOCAL 結合を持つシンボルは、STV_SINGLETON 可視性を持ちません。STV_SINGLETON に直接バインドすることはできません。
この可視性属性は STV_HIDDEN を継承します。現在のコンポーネント内でこの属性が定義されたシンボルは、ほかのコンポーネントから見えません。このシンボルは、そのコンポーネントを使用する動的実行可能ファイルまたは共有オブジェクトのシンボルテーブルには書き込まれません。
STV_SINGLETON 可視性属性は、リンク編集中、実行可能ファイルまたは共有オブジェクト内のシンボルの解決に影響する可能性があります。プロセス内の参照には、シングルトンの 1 つのインスタンスだけをバインドできます。
STV_SINGLETON は STV_DEFAULT 可視性属性と一緒に使用できますが、STV_SINGLETON が優先されます。STV_EXPORT は STV_DEFAULT 可視性属性とと一緒に使用できますが、STV_EXPORT が優先されます。STV_SINGLETON または STV_EXPORT 可視性は、それ以外の可視性属性とは一緒に使用できません。そのような場合、リンク編集にとって致命的とみなされます。
ほかの可視性の属性は、リンク編集中、実行可能ファイルまたは共有オブジェクト内のシンボルの解決にはまったく影響をおよぼしません。このような解決は、結合タイプによって制御されます。いったんリンカーがその解決を選択すると、これらの属性は次の 2 つの必要条件を課します。どちらの必要条件も、リンクされるコード内の参照は、属性の利点を利用するために最適化されるという事実に基づくものです。
すべてのデフォルトでない可視性の属性は、シンボルの参照に適用される際、「その参照を満たす定義は、リンクされているオブジェクト内で提供されなければならない」ということを暗黙の条件としています。この種のシンボルの参照がリンクされるオブジェクト内に定義を持たない場合は、その参照は STB_WEAK 結合を持つ必要があります。この場合、参照は 0 に解決されます。
名前への参照または名前の定義がデフォルトでない可視性の属性を持つシンボルである場合、その可視性の属性はリンクされているオブジェクト内の解決シンボルへ伝達されなければなりません。シンボルの特定のインスタンスに対して異なる可視性の属性が指定されている場合は、もっとも制約の厳しい可視性の属性が、リンクされるオブジェクト内の解決シンボルへ伝達されなければなりません。属性は、もっとも制約の少ないものからもっとも制約の厳しいものの順に、STV_PROTECTED、STV_HIDDEN、STV_INTERNAL となります。
シンボル値がセクション内の特定位置を参照すると、セクションインデックスメンバー st_shndx は、セクションヘッダーテーブルへのインデックスを保持します。再配置時にセクションが移動すると、シンボル値も変化します。シンボルへの参照はプログラム内の同じ位置を指し示し続けます。いくつかの特別なセクションインデックス値は、ほかのセマンティクスが付けられています。
このシンボルは、まだ割り当てられていない共通ブロックを示します。シンボル値は、セクションの sh_addralign メンバーに類似した整列制約を与えます。リンカーは st_value の倍数のアドレスにシンボル記憶領域を割り当てます。シンボルのサイズは、必要なバイト数を示します。
このセクションテーブルインデックスは、シンボルが未定義であることを示します。リンカーがこのオブジェクトファイルを、示されたシンボルを定義するほかのオブジェクトファイルに結合すると、このシンボルに対するこのファイルの参照は定義に結び付けられます。
前述したとおり、インデックス 0 (STN_UNDEF) のシンボルテーブルエントリは予約されています。このエントリは次の値を保持します。
表 7-21 ELF シンボルテーブルエントリ: インデックス 0
|
異なる複数のオブジェクトファイル型のシンボルテーブルエントリは、st_value メンバーに対してわずかに異なる解釈を持ちます。
再配置可能ファイルでは、st_value は定義されたシンボルに対するセクションオフセットを保持します。st_value は、st_shndx が識別するセクションの先頭からのオフセットになります。
実行可能オブジェクトファイルと共有オブジェクトファイルでは、st_value は仮想アドレスを保持します。これらのファイルのシンボルを実行時リンカーに対してより有用にするために、セクションオフセット (ファイル解釈) の代わりに、セクション番号が無関係な仮想アドレス (ファイル解釈) が使用されます。
シンボルテーブル値は、異なる種類のオブジェクトファイルでも似た意味を持ちますが、適切なプログラムはデータに効率的にアクセスできます。
シンボルテーブル内のシンボルは、次の順序で書き込まれます。
シンボルテーブルのインデックス 0 は、未定義のシンボルを表現するために使用されます。このシンボルテーブルの最初のエントリは常に、すべてゼロです。つまり、シンボルタイプは STT_NOTYPE です。
シンボルテーブルに局所シンボルが含まれている場合、そのシンボルテーブルの 2 番目のエントリは、ファイルの名前を示す STT_FILE シンボルです。
STT_SECTION タイプのセクションシンボル。
STT_REGISTER タイプのレジスタシンボル。
ローカルスコープに制限されている大域シンボル。
局所シンボルを使用する入力ファイルの場合は、入力ファイルの名前を示す STT_FILE シンボルとその局所シンボル。
大域シンボルのすぐあとに、シンボルテーブル内の局所シンボルが書き込まれます。最初の大域シンボルは、シンボルテーブルの sh_info 値によって識別されます。局所シンボルと大域シンボルは常にこの方法で別々に処理されるので、混在する可能性はありません。
Oracle Solaris OS には、3 つの特別なシンボルテーブルがあります。
このシンボルテーブルには、関連する ELF ファイルを示すあらゆるシンボルが入っています。このシンボルテーブルは、通常は割り当てることができないため、プロセスのメモリーイメージ内では使用できません。
ELIMINATE キーワードと一緒に mapfile を使用すると、.symtab から大域シンボルを削除できます。「シンボル削除」および 「SYMBOL_SCOPE/SYMBOL_VERSION 指令」を参照してください。リンカーの -z redlocsym オプションを使用して、ローカルシンボルを削除することもできます。
このテーブルには、.symtab テーブルのシンボルのうち、動的リンクをサポートするために必要なシンボルだけが入っています。このシンボルテーブルは、割り当てることができるため、プロセスのメモリーイメージ内で使用できます。
.dynsym テーブルは標準 NULL シンボルで始まり、そのあとに大域シンボルが続きます。STT_FILE シンボルは通常、このシンボルテーブルにはありません。STT_SECTION シンボルは、再配置エントリが必要とする場合に存在する可能性があります。
.dynsym テーブル内で見つかる情報を拡張する省略可能なシンボルテーブル。.SUNW_ldynsym テーブルには局所関数シンボルが含まれます。このシンボルテーブルは、割り当てることができるため、プロセスのメモリーイメージ内で使用できます。このセクションを追加することで、.symtab を割り当てることができないために、テーブルが使用できないまたはファイルから削除されたときでも、デバッガは実行時状況で正確なスタックトレースを行うことができます。また、このセクションは、dladdr(3C) が使用する追加シンボリック情報を実行時環境に提供します。
.SUNW_ldynsym テーブルが存在するには、.dynsym テーブルが存在している必要があります。.SUNW_ldynsym セクションと .dynsym セクションの両方があるときは、リンカーはそれらのデータ領域を並べて配置します (.SUNW_ldynsym が最初)。このように配置されることで、2 つのテーブルを大きな 1 つの連続したシンボルテーブルとして表示することができます。このシンボルテーブルは、すでに説明した標準レイアウト規則に従います。
.SUNW_ldynsym テーブルを削除するには、リンカーの -z noldynsym オプションを使用します。
並んで配置される .SUNW_ldynsym セクションと .dynsym セクションによって作成される動的なシンボルテーブルを使って、メモリーアドレスを対応するシンボルにマッピングできます。このマッピングを使って、特定のアドレスがどの関数または変数を表現するかを判断できます。ただし、シンボルテーブルを解析してマッピングを判断することは、シンボルがシンボルテーブルに書き込まれる順番が原因で、複雑な作業になります。「シンボルテーブルのレイアウトと規則」を参照してください。このレイアウトによって、アドレスをシンボル名に関連付ける作業は複雑になります。
シンボルがアドレスでソートされていないため、テーブル全体を地道に上から順番に検索する必要があります。
特定のアドレスを複数のシンボルが参照していることがあります。これらのシンボルは有効で正しいのですが、それらの等価の名前のうち、デバッグツールがどれを使用するかを選択するかが明確でないことがあります。ツールごとに異なる名前が使用されることもあります。こうした問題によって、ユーザーが混乱する可能性があります。
多くのシンボルがアドレス以外の情報を提供しています。それらのシンボルを検索に含めるべきではありません。
これらの問題を解決するために、シンボルソートセクションを使用します。シンボルソートセクションは、Elf32_Word または Elf64_Word オブジェクトの配列です。この配列の各要素は、.SUNW_ldynsym と .dynsym の結合シンボルテーブルへのインデックスです。この配列の要素は、参照されるシンボルがソート順に提供されるようにソートされます。関数または変数を表現するシンボルのみが取り込まれます。ソート配列に関連付けられたシンボルは、 -S オプション付きで elfdump(1) に使用することで表示できます。
通常のシンボルとスレッド固有領域シンボルを一緒にソートすることはできません。通常のシンボルの値は、そのシンボルが参照している関数または変数のアドレスです。スレッド固有領域シンボルの値は、変数のスレッドオフセットです。したがって、通常のシンボルとスレッド固有領域シンボルでは、異なる 2 つのソートセクションが使用されます。
SHT_SUNW_SYMSORT タイプのセクション。.SUNW_ldynsym と .dynsym の結合シンボルテーブル内の通常のシンボルへのインデックスが含まれます (アドレスでソート) 。変数または関数を表現しないシンボルは取り込まれません。
SHT_SUNW_TLSSORT タイプのセクション。.SUNW_ldynsym と .dynsym の結合シンボルテーブル内の TLS シンボルへのインデックスが含まれます (オフセットでソート) 。このセクションは、オブジェクトファイルに TLS シンボルが含まれる場合にだけ作成されます。
リンカーは、ソートセクションがどのシンボルを参照するかを選択するために、次の規則を記載順に使用します。
シンボルは関数タイプまたは変数タイプである必要がある: STT_FUNC、STT_OBJECT、STT_COMMON、または STT_TLS。
次のシンボルは常に取り込まれる (存在する場合): _DYNAMIC、_end、_fini、_GLOBAL_OFFSET_TABLE_、 _init、_PROCEDURE_LINKAGE_TABLE_、および _start。
同じ項目を参照する大域シンボルとウィークシンボルが見つかった場合は、ウィークシンボルが取り込まれ、大域シンボルは除外される。
シンボルは未定義であってはいけない。
シンボルはゼロ以外のサイズである必要がある。
これらの規則によって、コンパイラとリンカーが自動的に生成するシンボルは除外されます。選択されるシンボルは、ユーザーに関係するものです。ただし、次の 2 つの場合には、選択処理を改善するために手動による介入が必要になる場合があります。
規則によって、必要とする特殊シンボルが選択されなかった場合。たとえば、サイズがゼロの特殊シンボルなど。
不要で余分なシンボルが選択される場合。たとえば、共有オブジェクトには、同じアドレスを参照し、同じサイズのシンボルを複数定義できます。これらの別名シンボルは同じ項目を参照することになります。ソートセクション内で、複数のシンボルファミリの 1 つだけを取り込みたい場合があります。
mapfile のキーワード DYNSORT および NODYNSORT により、シンボルをきめ細かく選択できます。「SYMBOL_SCOPE/SYMBOL_VERSION 指令」を参照してください。
ソートセクションに含める必要があるシンボルを指定します。シンボルタイプは STT_FUNC、STT_OBJECT、STT_COMMON、または STT_TLS である必要があります。
たとえば、あるオブジェクトのシンボルテーブル定義が次のようになっているとします。
$ elfdump -sN.symtab foo.so.1 | egrep "foo$|bar$" [37] 0x000004b0 0x0000001c FUNC GLOB D 0 .text bar [38] 0x000004b0 0x0000001c FUNC WEAK D 0 .text foo
シンボル foo と bar は別名ペアを表現しています。デフォルトでは、ソートされた配列を作成するときに、シンボル foo だけが表現されます。
$ cc -o foo.so.1 -G foo.c $ elfdump -S foo.so.1 | egrep "foo$|bar$" [13] 0x000004b0 0x0000001c FUNC WEAK D 0 .text foo
リンカーによって同じ項目を参照する大域シンボルとウィークシンボルが検出された場合は、通常はウィークシンボルが選択されます。ウィークシンボル foo に関連付けられたので、シンボル bar はソートされた配列から除外されます。
次の mapfile を実行すると、シンボル bar がソートされた配列内で表現されています。シンボル foo は表示されません。
$ cat mapfile { global: bar = DYNSORT; foo = NODYNSORT; }; $ cc -M mapfile -o foo.so.2 -Kpic -G foo.c $ elfdump -S foo.so.2 | egrep "foo$|bar$" [13] 0x000004b0 0x0000001c FUNC GLOB D 0 .text bar
.SUNW_dynsymsort セクションと .SUNW_dyntlssort セクションには、.SUNW_ldynsym セクションの存在が必要です。したがって、- z noldynsym オプションを使用すると、すべてのソートセクションが作成されなくなります。
SPARC アーキテクチャーは、レジスタシンボル (大域レジスタを初期化するシンボル) をサポートします。レジスタシンボルに対するシンボルテーブルエントリには、次の値が入ります。
表 7-22 SPARC: ELF シンボルテーブルエントリ: レジスタシンボル
|
定義済みの SPARC 用レジスタ値を、次に示します。
表 7-23 SPARC: ELF レジスタ番号
|
特定の大域レジスタのエントリが存在しないことは、その特定の大域レジスタがオブジェクトで使用されないことを意味します。
syminfo セクションには、Elf32_Syminfo 型または Elf64_Syminfo 型の複数のエントリが存在します。.SUNW_syminfo セクションには、関連付けられているシンボルテーブル (sh_link) のエントリごとに 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 エントリに関連付けられた動的オブジェクトを示します。次の表に示すエントリは、si_boundto に対して予約されています。
|
このビットフィールドでは、次の表に示すフラグを設定できます。
|
リンカーで作成されるオブジェクトには、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;
このメンバーは、構造体のバージョンを示します (次の表を参照)。
|
値 1 は最初のセクション形式を示し、拡張した場合は、より大きい番号の新しいバージョンが必要です。VER_DEF_CURRENT の値は、現在のバージョン番号を示すために必要に応じて変化します。
このメンバーは、バージョン定義に固有の情報を保持します (次の表を参照)。
|
基本バージョン定義は、バージョン定義またはシンボルの自動短縮簡約がファイルに適用されている場合、必ず存在します。基本バージョンは、ファイルの予約されたシンボルに対してデフォルトのバージョンを与えます。ウィークバージョン定義には、関連付けられているシンボルは存在しません。「ウィークバージョン定義の作成」を参照してください。
バージョンインデックス。各バージョン定義には、SHT_SUNW_versym エントリを適切なバージョン定義に関連付ける一意のインデックスが存在します。
Elf32_Verdaux 配列の要素数。
バージョン定義名のハッシュ値。この値は、「ハッシュテーブルセクション」に記述されているのと同じハッシング機能により生成されます。
この Elf32_Verdef エントリの先頭からバージョン定義名の Elf32_Verdaux 配列までのバイトオフセット。配列の先頭要素は存在しなければなりません。この要素はこの構造体が定義するバージョン定義文字列を指し示します。追加要素は存在可能です。要素の番号は vd_cnt 値で示されます。これらの要素は、このバージョン定義の依存関係を表します。これらの依存関係の各々は、独自のバージョン定義構造体を持っています。
この Elf32_Verdef 構造体の先頭から次の Elf32_Verdef エントリまでのバイトオフセット。
ヌル文字で終わる文字列への文字列テーブルオフセットで、バージョン定義名を指定します。
この Elf32_Verdaux エントリの先頭から次の Elf32_Verdaux エントリまでのバイトオフセット。
バージョン依存セクションは、タイプ 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;
このメンバーは、構造体のバージョンを示します (次の表を参照)。
|
値 1 は最初のセクション形式を示し、拡張した場合は、より大きい番号の新しいバージョンが必要です。VER_NEED_CURRENT の値は、現在のバージョン番号を示すために必要に応じて変化します。
Elf32_Vernaux 配列の要素数。
ヌル文字で終わっている文字列への文字列テーブルオフセットで、バージョン依存性のファイル名を指定します。この名前は、ファイル内に存在する .dynamic 依存性のどれかに一致します。「動的セクション」を参照してください。
この Elf32_Verneed エントリの先頭から、関連付けられているファイル依存性から要求されるバージョン定義の Elf32_Vernaux 配列までのバイトオフセット。少なくとも 1 つのバージョン依存性が存在する必要があります。追加バージョン依存性は存在することができ、また番号は vn_cnt 値で示されます。
この Elf32_Verneed エントリの先頭から次の Elf32_Verneed エントリまでのバイトオフセット。
バージョン依存性の名前のハッシュ値。この値は、「ハッシュテーブルセクション」に記述されているのと同じハッシング機能により生成されます。
バージョン依存性に固有の情報 (次の表を参照)。
|
ウィークバージョン依存性は、ウィークバージョン定義への最初の結び付きを示します。
ゼロでない場合、この依存関係バージョンに割り当てられたバージョンインデックス。SHT_SUNW_versym 内でこのインデックスを使用して、大域シンボル参照をこのバージョンに割り当てます。
Solaris 10 のリリースまで、バージョンシンボルインデックスは依存関係バージョンに割り当てられていませんでした。これらのオブジェクトでは、vna_other の値は 0 です。
ヌル文字で終わる文字列への文字列テーブルオフセット。バージョン依存性の名前を与えます。
この Elf32_Vernaux エントリの先頭から次の Elf32_Vernaux エントリまでのバイトオフセット。
バージョンシンボルセクションは、タイプ SHT_SUNW_versym によって定義されます。このセクションは、次の構造を持つ要素配列で構成されます。
typedef Elf32_Half Elf32_Versym; typedef Elf64_Half Elf64_Versym;
配列の要素数は、関連付けられているシンボルテーブルに存在するシンボルテーブルエントリ数に等しくなければなりません。この値は、セクションの sh_link 値で決定されます。配列の各要素には 1 つのインデックスが存在し、このインデックスは次の表に示す値をとることができます。
表 7-24 ELF バージョン依存インデックス
|
シンボルが、予約された特別なインデックス 0 に割り当てられる場合があります。このインデックスには次のいずれかの理由のために割り当てられます。
非大域シンボルは常に VER_NDX_LOCAL に割り当てられます。しかし、これは実際にはほとんどありません。多くの場合、バージョン管理セクションは、大域シンボルだけを含む動的シンボルテーブル .dynsym と合わせてのみ作成されます。
SHT_SUNW_verdef バージョン定義セクションがないオブジェクト内に定義された大域シンボル。
SHT_SUNW_verneed バージョン依存関係セクションがないオブジェクト内に定義された未定義大域シンボル。または、バージョン依存関係のセクションがバージョンインデックスを割り当てないオブジェクト内に定義された未定義大域シンボル。
シンボルテーブルの最初のエントリは常に NULL です。このエントリは常に VER_NDX_LOCAL を受け取りますが、その値には特別な意味はありません。
オブジェクトで定義されたバージョンは、1 から始まるバージョンインデックスが割り当てられ、バージョンごとに 1 増加します。インデックス 1 は最初の大域バージョンに予約されています。オブジェクトに SHT_SUNW_verdef バージョン定義セクションがない場合、そのオブジェクトで定義されたすべての大域シンボルはインデックス 1 を受け取ります。オブジェクトにバージョン定義セクションがない場合、VER_NDX_GLOBAL は前述の最初のバージョンを参照するだけです。
ほかの SHT_SUNW_verneed 依存関係からオブジェクトが要求したバージョンには、最終のバージョン定義インデックスの後に 1 を加えた値から始まるバージョンインデックスが割り当てられます。これらのインデックスもバージョンごとに 1 増加します。インデックス 1 は常に VER_NDX_GLOBAL に予約されているため、依存関係のバージョンが取り得るの最初のインデックスは 2 となります。
Solaris 10 リリースまで、バージョンインデックスは SHT_SUNW_verneed 依存関係バージョンに割り当てられていませんでした。このようなオブジェクトでは、いずれのシンボル参照のバージョンインデックスも、バージョン管理情報が該当のシンボルで使用できないことを表す 0 になります。