オブジェクトファイルのシンボルテーブルには、プログラムのシンボル定義とシンボル参照の検索と再配置に必要となる情報が格納されます。シンボルテーブルインデックスは、この配列への添字です。インデックス 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)
名前 |
値 |
---|---|
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–19 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)を参照してください。割り当てができないセクションからタイプが STT_TLS のシンボルを参照する際には、この制限はありません。
この範囲の値 (両端の値を含む) は、オペレーティングシステム固有のセマンティクスのために予約されています。
この範囲の値は、プロセッサ固有のセマンティクスのために予約されています。
シンボルの可視性は、その st_other フィールドで決まります。この可視性は、再配置可能オブジェクトで指定できます。シンボルの可視性により、シンボルが実行可能ファイルまたは共有オブジェクトの一部になった後のシンボルへのアクセス方法が定義されます。
表 7–20 ELF シンボルの可視性
名前 |
値 |
---|---|
STV_DEFAULT |
0 |
STV_INTERNAL |
1 |
STV_HIDDEN |
2 |
STV_PROTECTED |
3 |
STV_DEFAULT 属性を持つシンボルの可視性は、シンボルの結合タイプで指定されたものになります。大域シンボルおよびウィークシンボルは、それらの定義するコンポーネント (実行可能ファイルまたは共有オブジェクト) の外から見ることができます。局所シンボルは、「隠されて」います。大域シンボルおよびウィークシンボルは、横取りすることもできます。別のコンポーネントの同じ名前の定義によってこれらのシンボルに割り込むこともできます。
現在のコンポーネント内で定義されたシンボルは、それがほかのコンポーネント内で参照可能であるが横取り可能ではない場合、保護されています。定義コンポーネント内からシンボルへの参照など、あらゆる参照について、コンポーネント内の定義に解決する必要があります。この解決は、シンボル定義がデフォルト規則によって割り込みを行う別のコンポーネント内に存在する場合も、実行する必要があります。STB_LOCAL 結合を持つシンボルは、STV_PROTECTED 可視性を持ちません。
現在のコンポーネント内で定義されたシンボルは、その名前がほかのコンポーネントから参照することができない場合、「隠されて」います。そのようなシンボルは、保護される必要があります。この属性は、コンポーネントの外部インタフェースの管理に使用されます。そのようなシンボルによって指定されたオブジェクトは、そのアドレスが外部に渡された場合でも、ほかのコンポーネントから参照可能です。
再配置可能オブジェクトに含まれた「隠された」シンボルは、そのオブジェクトが実行可能ファイルまたは共有オブジェクトに含まれる時には、削除されるか STB_LOCAL 結合に変換されます。
この可視性の属性は、現在予約されています。
可視性の属性は、リンク編集中、実行可能ファイルまたは共有オブジェクト内のシンボルの解決にはまったく影響をおよぼしません。このような解決は、結合タイプによって制御されます。いったんリンカーがその解決を選択すると、これらの属性は次の 2 つの必要条件を課します。どちらの必要条件も、リンクされるコード内の参照は、属性の利点を利用するために最適化されるという事実に基づくものです。
すべてのデフォルトでない可視性の属性は、シンボルの参照に適用される際、「その参照を満たす定義は、リンクされているオブジェクト内で提供されなければならない」ということを暗黙の条件としています。この種のシンボルの参照がリンクされるオブジェクト内に定義を持たない場合は、その参照は STB_WEAK 結合を持つ必要があります。この場合、参照は 0 に解決されます。
名前への参照または名前の定義がデフォルトでない可視性の属性を持つシンボルである場合、その可視性の属性はリンクされているオブジェクト内の解決シンボルへ伝達されなければなりません。シンボルの特定のインスタンスに対して異なる可視性の属性が指定されている場合は、もっとも制約の厳しい可視性の属性が、リンクされるオブジェクト内の解決シンボルへ伝達されなければなりません。属性は、もっとも制約の少ないものからもっとも制約の厳しいものの順に、STV_PROTECTED、STV_HIDDEN、STV_INTERNAL となります。
シンボル値がセクション内の特定位置を参照すると、セクションインデックスメンバー st_shndx は、セクションヘッダーテーブルへのインデックスを保持します。再配置時にセクションが移動すると、シンボル値も変化します。シンボルへの参照はプログラム内の同じ位置を指し示し続けます。いくつかの特別なセクションインデックス値は、ほかのセマンティクスが付けられています。
このシンボルは、まだ割り当てられていない共通ブロックを示します。シンボル値は、セクションの sh_addralign メンバーに類似した整列制約を与えます。リンカーは st_value の倍数のアドレスにシンボル記憶領域を割り当てます。シンボルのサイズは、必要なバイト数を示します。
このセクションテーブルインデックスは、シンボルが未定義であることを示します。リンカーがこのオブジェクトファイルを、示されたシンボルを定義するほかのオブジェクトファイルに結合すると、このシンボルに対するこのファイルの参照は定義に結び付けられます。
前述したとおり、インデックス 0 (STN_UNDEF) のシンボルテーブルエントリは予約されています。このエントリは次の値を保持します。
表 7–21 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 は仮想アドレスを保持します。これらのファイルのシンボルを実行時リンカーに対してより有用にするために、セクションオフセット (ファイル解釈) の代わりに、セクション番号が無関係な仮想アドレス (ファイル解釈) が使用されます。
シンボルテーブル値は、異なる種類のオブジェクトファイルでも似た意味を持ちますが、適切なプログラムはデータに効率的にアクセスできます。
シンボルテーブル内のシンボルは、次の順序で書き込まれます。
シンボルテーブルのインデックス 0 は、未定義のシンボルを表現するために使用されます。このシンボルテーブルの最初のエントリは常に、すべてゼロです。つまり、シンボルタイプは STT_NOTYPE です。
シンボルテーブルに局所シンボルが含まれている場合、そのシンボルテーブルの 2 番目のエントリは、ファイルの名前を示す STT_FILE シンボルです。
STT_SECTION タイプのセクションシンボル。
STT_REGISTER タイプのレジスタシンボル。
ローカルスコープに制限されている大域シンボル。
局所シンボルを使用する入力ファイルの場合は、入力ファイルの名前を示す STT_FILE シンボルとその局所シンボル。
大域シンボルのすぐあとに、シンボルテーブル内の局所シンボルが書き込まれます。最初の大域シンボルは、シンボルテーブルの sh_info 値によって識別されます。局所シンボルと大域シンボルは常にこの方法で別々に処理されるので、混在する可能性はありません。
Solaris OS には、2 つ の特別なシンボルテーブルがあります。
このシンボルテーブルには、関連する ELF ファイルを示すあらゆるシンボルが入っています。このシンボルテーブルは、通常は割り当てることができないため、プロセスのメモリーイメージ内では使用できません。
ELIMINATE キーワードと一緒に mapfile を使用すると、.symtab から大域シンボルを削除できます。「mapfile を使用した追加シンボルの定義」を参照してください。リンカーの -z redlocsym オプションを使用して、ローカルシンボルを削除することもできます。
このテーブルには、.symtab テーブルのシンボルのうち、動的リンクをサポートするために必要なシンボルだけが入っています。このシンボルテーブルは、割り当てることができるため、プロセスのメモリーイメージ内で使用できます。
.dynsym テーブルは標準 NULL シンボルで始まり、そのあとに大域シンボルが続きます。STT_FILE シンボルは通常、このシンボルテーブルにはありません。STT_SECTION シンボルは、再配置エントリが必要とする場合に存在する可能性があります。
SPARC アーキテクチャーは、レジスタシンボル (大域レジスタを初期化するシンボル) をサポートします。レジスタシンボルに対するシンボルテーブルエントリには、次の値が入ります。
表 7–22 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–23 SPARC: ELF レジスタ番号
名前 |
値 |
意味 |
---|---|---|
STO_SPARC_REGISTER_G2 |
0x2 |
%g2 |
STO_SPARC_REGISTER_G3 |
0x3 |
%g3 |
特定の大域レジスタのエントリが存在しないことは、その特定の大域レジスタがオブジェクトで使用されないことを意味します。