ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
Oracle Solaris 11.1 リンカーとライブラリガイド Oracle Solaris 11.1 Information Library (日本語) |
7. システムのパフォーマンスを最適化するオブジェクトの構築
LOAD_SEGMENT/NOTE_SEGMENT/NULL_SEGMENT 指令
SIZE_SYMBOL 属性 (LOAD_SEGMENT のみ)
定義済みセグメントとエントランス基準のための mapfile 指令
パート IV ELF アプリケーションバイナリインタフェース
次の指令がリンカーで受け入れられます。
表 8-6 mapfile 指令
|
サポートされる各 mapfile 指令の具体的な構文については、後続のセクションで示します。
再配置可能オブジェクトのハードウェア、ソフトウェア、マシン、およびプラットフォームの機能は通常、コンパイル時にオブジェクト内部に記録されます。リンカーは入力再配置可能オブジェクトの機能を組み合わせて、出力ファイルの最終機能セクションを作成します。mapfile 内で機能を定義して、入力再配置可能オブジェクトから指定される機能に追加したり、完全に置き換えたりすることができます。
CAPABILITY [capid] { HW = [hwcap_flag...]; HW += [hwcap_flag...]; HW -= [hwcap_flag...]; HW_1 = [value...]; HW_1 += [value...]; HW_1 -= [value...]; HW_2 = [value...]; HW_2 += [value...]; HW_2 -= [value...]; MACHINE = [machine_name...]; MACHINE += [machine_name...]; MACHINE -= [machine_name...]; PLATFORM = [platform_name...]; PLATFORM += [platform_name...]; PLATFORM -= [platform_name...]; SF = [sfcap_flag...]; SF += [sfcap_flag...]; SF -= [sfcap_flag...]; SF_1 = [value...]; SF_1 += [value...]; SF_1 -= [value...]; };
オプションの capid の名前が存在する場合、この名前はオブジェクト機能のシンボリック名を提供し、結果として出力オブジェクト内に CA_SUNW_ID 機能エントリができます。複数の CAPABILITY 指令が存在する場合、最後の指令の capid が使用されます。
空の CAPABILITY 指令を使用すると、機能の値を何も指定せずにオブジェクト機能の capid を指定できます。
CAPABILITY capid;
各タイプの機能について、リンカーは現在の値 (value) と、除外する一連の値 (exclude ) を保持します。ハードウェアおよびソフトウェア機能の場合、これらの値はビットマスクです。マシンおよびプラットフォームの機能の場合、これらは名前のリストです。mapfile を処理する前に、すべての機能の value および exclude の値がクリアされます。代入演算子の機能を次に示します。
「+=」演算子を使用すると、指定された値はその機能の現在の value に追加され、その機能の exclude 値から削除されます。
「-=」演算子を使用すると、指定された値はその機能の exclude 値に追加され、その機能の現在の value から削除されます。
「=」演算子を使用すると、以前の value は指定された値に置き換わり、exclude が 0 にリセットされます。また、「=」を使用すると、入力ファイル処理から収集されたすべての機能がオーバーライドされます。
入力オブジェクトは mapfile が読み込まれたあとに処理されます。入力オブジェクトによって指定された機能の値は、mapfile からの値とマージされます。ただし、「=」演算子が使用された場合は、入力オブジェクト内に見つかった機能は無視されます。つまり、「=」演算子は入力オブジェクトをオーバーライドし、「+=」演算子は機能を追加します。
結果の機能の値を出力オブジェクトに書き込む前に、リンカーは「-=」演算子で指定されたすべての機能の値を削除します。
指定された機能を出力オブジェクトから完全に除去するには、「=」演算子と空の値リストを使用すれば十分です。たとえば次の例は、入力オブジェクトによって提供されるすべてのハードウェア機能を抑制します。
$mapfile_version 2 CAPABILITY { HW = ; };
ELF オブジェクト内では、ハードウェアとソフトウェアの機能は、オブジェクトの機能セクションから検出される 1 つ以上のビットマスク内でのビット割り当てとして表現されます。HW および SF mapfile 属性は、この実装の抽象的なビューを提供し、リンカーによって適切なマスクおよびビットに変換される、空白区切りのシンボリック機能名のリストを受け入れます。番号付き属性 (HW_1 、HW_2、SF_1) は、ベースとなる機能ビットマスクへの直接数値アクセスを可能にするために存在します。これらは正式に定義されていない機能ビットを指定するために使用できます。可能な場合、HW および SF 属性を使用することをお勧めします。
ハードウェア機能は、空白区切りのシンボリック機能名のリストとして指定されます。SPARC プラットフォームでは、ハードウェア機能は <sys/auxv_SPARC.h>の AV_ の値として定義されます。x86 プラットフォームでは、ハードウェア機能は <sys/auxv_386.h> の AV_ の値として定義されます。mapfile では同じ名前を使用し、AV_ 接頭辞を付けません。たとえば、x86 の AV_SSE ハードウェア機能は mapfile 内では SSE と呼ばれます。このリストには、CA_SUNW_HW_ 機能マスク用に定義されたすべての機能名を含めることができます。
HW_1 および HW_2 属性には、CA_SUNW_HW_1 および CA_SUNW_HW_2 機能マスクを数値として直接指定したり、そのマスクに対応するシンボリックハードウェア機能名として指定したりできます。
MACHINE 属性は、オブジェクトが実行可能なシステムのマシンハードウェア名を指定します。システムのマシンハードウェア名は、ユーティリティー uname(1) に -m オプションを付けて実行すると表示できます。CAPABILITY 指令は複数のマシン名を指定できます。それぞれの名前は出力オブジェクト内の CA_SUNW_MACH 機能エントリになります。
PLATFORM 属性は、オブジェクトが実行可能なシステムのプラットフォーム名を指定します。システムのプラットフォーム名は、ユーティリティー uname(1) に -i オプションを付けて実行すると表示できます。CAPABILITY 指令は複数のプラットフォーム名を指定できます。それぞれの名前は出力オブジェクト内の CA_SUNW_PLAT 機能エントリになります。
ソフトウェア機能は、空白区切りのシンボリック機能名のリストとして指定されます。ソフトウェア機能は、<sys/elf.h> の SF1_SUNW_ の値として定義されます。mapfile では同じ名前を使用し、SF1_SUNW_ 接頭辞を付けません。たとえば、SF1_SUNW_ADDR32 ソフトウェア機能は mapfile 内では ADDR32 と呼ばれます。このリストには、CA_SUNW_SF_1 用に定義されたすべての機能名を含めることができます。
SF_1 属性には、CA_SUNW_SF_1 機能マスクを数値として直接指定したり、そのマスクに対応するシンボリックソフトウェア機能名として指定したりできます。
共有可能オブジェクトをリンクするとき、オブジェクトからエクスポートされるすべてのバージョンのシンボルが、通常はリンカーで使用可能になります。DEPEND_VERSIONS 指令は、指定したバージョンへのアクセスに限定するために使用されます。バージョンアクセスの制限は、古いバージョンのシステムで使用できない可能性がある新しい機能が出力オブジェクトで使用されないようにするために使用できます。
DEPEND_VERSIONS 指令には次の構文があります。
DEPEND_VERSIONS objname { ALLOW = version_name; REQUIRE = version_name; ... };
objname は、コマンド行で指定された共有オブジェクトの名前です。-l コマンド行オプションを使用してオブジェクトを指定する一般的な場合、これは指定された名前に lib 接頭辞が付いたものになります。たとえば、libc はコマンド行で一般的に -lc と参照されるため、DEPEND_VERSIONS 指令内では libc.so と指定されます。
ALLOW 属性は、指定されたバージョンと、そのバージョンによって継承されたバージョンが、出力オブジェクト内のシンボルを解決するためにリンカーによって使用可能であることを指定します。リンカーは、このバージョンを含む継承の連鎖内で使用されるもっとも高いバージョンの要件を、出力オブジェクトの要件に追加します。
REQUIRE は、リンク操作の要件を満たすために指定されたバージョンが実際に必要かどうかによらず、そのバージョンを出力オブジェクトの要件に追加します。
すべての ELF オブジェクトには、ファイル内のオフセット 0 に ELF ヘッダーがあります。実行可能ファイルおよび共有可能オブジェクトにはプログラムヘッダーもあり、これらは ELF ヘッダーを経由してアクセスされます。リンカーは通常、これらの項目が、読み込み可能な先頭セグメントの一部として組み込まれるように配置します。したがって、これらのヘッダーに含まれる情報は、マップされたイメージ内で可視となり、通常は実行時リンカーによって使用されます。HDR_NOALLOC 指令はこれを防ぎます。
HDR_NOALLOC;
HDR_NOALLOC が指定されると、ELF ヘッダーおよびプログラムヘッダー配列は、結果として生じる出力オブジェクトファイルの先頭に引き続き示されますが、読み込み可能なセグメントには含まれず、イメージの仮想アドレス計算は、ELF ヘッダーのベースでなく先頭セグメントの先頭セクションから開始されます。
PHDR_ADD_NULL 指令によって、リンカーは、タイプが PT_NULL の指定された数のプログラムヘッダーエントリを、プログラムヘッダー配列の末尾に追加します。追加の PT_NULL エントリは、事後処理ユーティリティーで使用できます。
PHDR_ADD_NULL = value;
value は正の整数値である必要があり、作成する追加の PT_NULL エントリの数を指定します。結果として生じるプログラムヘッダーエントリのすべてのフィールドは、0 に設定されます。
セグメントは出力オブジェクトの連続する部分で、セクションを含みます。mapfile セグメント指令では、3 つの異なるセグメントタイプの指定が可能です。
LOAD_SEGMENT
読み込み可能セグメントは、実行時にプロセスのアドレス空間にマップされるコードまたはデータを含みます。リンカーは割り当て可能な各セグメントに対して PT_LOAD プログラムヘッダーエントリを作成し、実行時リンカーはこれらを使用してセグメントを見つけ、マップします。
NOTE_SEGMENT
注釈セグメントには注釈セクションが含まれています。リンカーは、セグメントを参照する PT_NOTE プログラムヘッダーエントリを作成します。注釈セグメントは割り当てできません。
NULL_SEGMENT
ヌルセグメントは出力オブジェクトに含まれるセクションを保持しますが、そのセクションは実行時にオブジェクトで使用できません。そのようなセクションの一般的な例として、.symtab シンボルテーブルや、デバッガのために生成されるさまざまなセクションがあります。ヌルセグメントのプログラムヘッダーは作成されません。
セグメント指令は、出力ファイルに新しいセグメントを作成したり、既存のセグメントの属性値を変更したりするために使用されます。既存のセグメントとは、以前に定義したものか、「定義済みセグメント」で説明されている組み込みセグメントのいずれかです。新しいセグメントはそれぞれオブジェクトに追加され、同じタイプの最後のセグメントの後に置かれます。読み込み可能なセグメントが最初に追加され、その次が注釈セグメントで、最後がヌルセグメントです。これらのセグメントに関連付けられたプログラムヘッダーは、セグメントと同じ相対順序でプログラムヘッダー配列に配置されます。デフォルトの配置は、読み込み可能なセグメントの場合は明示的にアドレスを設定するか、または SEGMENT_ORDER 指令を使用すると変更できます。
segment_name が事前に存在するセグメントの場合、指定された属性によって既存のセグメントが変更されます。それ以外の場合、新しいセグメントが作成され、指定された属性が新しいセグメントに適用されます。リンカーは、明示的に指定されていない属性にデフォルト値を設定します。
注 - セグメント名を選択するとき、リンカーの将来のバージョンで、新しい定義済みセグメントが追加される可能性があることに留意してください。ユーザーのセグメント指令に使用する名前がこの新しい名前と一致した場合、新しい定義済みセグメントによって、ユーザーの mapfile は、新規セグメントの作成から既存のセグメントの変更へと意味が変わります。この状況を回避するためのもっとも良い方法は、セグメントに一般的な名前を使用することを避け、すべてのセグメント名に対して企業識別子、プロジェクト識別子、プログラムの名前などの固有の接頭辞を追加することです。たとえば、hello_world という名前のプログラムの場合、hello_world_data_segment というセグメント名を使用できます。
3 つすべてのセグメント指令は、中核となる一連の共通属性を共有します。セグメント宣言は次のようになり、directive は LOAD_SEGMENT、NOTE_SEGMENT、NULL_SEGMENT のいずれかで置き換えます。
directive segment_name { ASSIGN_SECTION [assign_name]; ASSIGN_SECTION [assign_name] { FILE_BASENAME = file_basename; FILE_OBJNAME = objname; FILE_PATH = file_path; FLAGS = section_flags; IS_NAME = section_name; TYPE = section_type; }; DISABLE; IS_ORDER = assign_name...; IS_ORDER += assign_name...; OS_ORDER = section_name...; OS_ORDER += section_name...; };
LOAD_SEGMENT 指令は、読み込み可能セグメントに固有の一連の追加属性を受け入れます。これらの追加属性の構文は次のとおりです。
LOAD_SEGMENT segment_name { ALIGN = value; FLAGS = segment_flags; FLAGS += segment_flags; FLAGS -= segment_flags; MAX_SIZE = value; NOHDR; PADDR = value; ROUND = value; SIZE_SYMBOL = symbol_name...; SIZE_SYMBOL += symbol_name...; VADDR = value; };
どのセグメント指令も空の指令として指定できます。空のセグメント指令によって新しいセグメントが作成されると、すべてのセグメント属性にデフォルト値が設定されます。空のセグメントは次のように宣言されます。
LOAD_SEGMENT segment_name; NOTE_SEGMENT segment_name; NULL_SEGMENT segment_name;
1 つ以上のセグメント指令によって受け入れられるすべての属性について、次に説明します。
ALIGN 属性は、読み込み可能セグメントの配置を指定するために使用されます。指定された値は、セグメントに対応するプログラムヘッダーの p_align フィールドに設定されます。セグメント配置は、セグメントの最初の仮想アドレスを計算する際に使用されます。
指定される配置は 2 のべき乗である必要があります。デフォルトでは、リンカーによって、セグメントの配置は組み込みのデフォルトに設定されます。デフォルトは CPU により異なり、ソフトウェアのリビジョンによっても異なる場合があります。
ALIGN 属性は PADDR および VADDR 属性と相互に排他的で、これらと一緒に使用できません。PADDR または VADDR が指定されると、対応するプログラムヘッダーの p_align フィールドはデフォルト値に設定されます。
ASSIGN_SECTION は、指定されたセグメントへの割り当て用にセクションを集合的に修飾する、セクション名、タイプ、およびフラグなどのセクション属性の組み合わせです。このような属性のセットは、エントランス基準と呼ばれます。セクションが一致するのは、セクション属性がこれらのエントランス基準と正確に一致するときです。ASSIGN_SECTION は、属性を何も指定しない場合、基準が比較される任意のセクションと一致します。
指定されたセグメントに対して複数の ASSIGN_SECTION 属性を指定できます。ASSIGN_SECTION 属性は、それぞれ互いに独立しています。セクションがセグメントに割り当てられるのは、そのセグメントに関連付けられているいずれかの ASSIGN_SECTION 定義とセクションが一致する場合です。セグメントに 1 つ以上の ASSIGN_SECTION 属性が存在しない場合、リンカーはセクションをセグメントに割り当てません。
リンカーはセクションをセグメントに割り当てるために、エントランス基準の内部リストを使用します。mapfile 内で見つかった ASSIGN_SECTION 宣言は、見つかった順序でこのリストに配置されます。「定義済みセグメント」で説明した組み込みセグメントのエントランス基準は、このリスト内で最後の mapfile 定義済みエントリの直後に配置されます。
エントランス基準には、オプションの名前 (assign_name) を指定できます。この名前は IS_ORDER 属性と一緒に使用すると、入力セクションが出力セクションに配置される順序を指定できます。
入力セクションを配置するには、リンカーはエントランス基準リストの先頭から開始し、セクションの属性を各エントランス基準と順番に比較します。セクションは、セクション属性に正確に一致した最初のエントランス基準に関連付けられているセグメントに割り当てられます。一致がない場合、一般的なすべての割り当て不可のセクションの場合と同じように、セクションはファイルの末尾に配置されます。
ASSIGN_SECTION は次を受け入れます。
FILE_BASENAME、FILE_OBJNAME、FILE_PATH
これらの属性を使用すると、属性を取得したファイルのパス (FILE_PATH)、ベース名 (FILE_BASENAME)、またはオブジェクト名 (FILE_OBJNAME) に基づいてセクションを選択できます。
ファイルパスは、UNIX 標準のスラッシュ区切りの表記規則を使用して指定されます。最後のパスセグメントはパスのベース名で、単純にファイル名 としても知られています。アーカイブの場合、ベース名はアーカイブメンバーの名前を使用して拡張でき、archive_name(component_name) という形式を使用します。たとえば、/lib/libfoo.a(bar.o) は /lib/libfoo.a という名前のアーカイブにあるオブジェクト bar.o を指定します。
FILE_BASENAME と FILE_OBJNAME はアーカイブ以外に適用された場合は同等で、指定された名前をファイルのベース名と比較します。アーカイブに適用される場合、FILE_BASENAME はアーカイブ名のベース名を調べます。一方、FILE_OBJNAME はアーカイブ内に格納されているオブジェクトの名前を調べます。
それぞれの ASSIGN_SECTION は、FILE_BASENAME 、FILE_PATH、および FILE_OBJNAME のすべての値のリストを保持します。これらの定義のいずれかが入力ファイルと一致すると、ファイルが一致したことになります。
IS_NAME
入力セクションの名前。
TYPE
ELF の section_type を指定します。<sys/elf.h> 内で定義されている任意の SHT_ 定数を指定できます。SHT_ 接頭辞は削除します (PROGBITS、SYMTAB、NOBITS など)。
FLAGS
FLAGS 属性には、section_flags を使用して表 8-7 に示す値の空白区切りのリストとしてセクション属性を指定します。これらの値は <sys/elf.h> 内に定義されている SHF_ 値に対応します。個々のフラグの前に感嘆符 (!) が付いている場合は、その属性が存在してはいけないことを明示しています。次の例では、セクションは割り当て可能だが書き込み不可と定義されています。
ALLOC !WRITE
section_flags リストに明示されていないフラグは無視されます。上記の例では、指定されたフラグに対してセクションを照合するときに、ALLOC および WRITE の値のみが検査されます。ほかのセクションフラグは任意の値を持つことができます。
表 8-7 セクションフラグの値
|
DISABLE 属性を使用すると、リンカーはセグメントを無視します。無効にされたセグメントには、セクションが割り当てられません。セグメントは後続のセグメント指令によって参照されると、自動的にふたたび有効化されます。したがって、空の参照のみで、無効にされたセクションをふたたび有効にできます。
segment segment_name;
FLAGS 属性は、表 8-3 のアクセス権の空白区切りのリストとして、セグメントのアクセス権を指定します。デフォルトでは、ユーザー定義のセグメントは READ、WRITE、および EXECUTE アクセス権を受け入れます。「定義済みセグメント」で説明されている定義済みセグメント用のデフォルトフラグがリンカーによって指定され、場合によってはプラットフォーム依存になります。
3 つの形式を使用できます。
FLAGS = segment_flags...; FLAGS += segment_flags...; FLAGS -= segment_flags...;
シンプルな「=」代入演算子は現在のフラグを新しいセットで置き換え、「+=」形式は既存のセットに新規フラグを追加し、「-=」形式は指定されたフラグを既存のセットから削除します。
リンカーは通常、見つかった順序で出力セクションをセグメントに配置します。同様に、出力セクションを構成する入力セクションも、見つかった順序で配置されます。IS_ORDER 属性は、入力セクションのこのデフォルトの配置を変更するために使用できます。IS_ORDER は、エントランス基準名 (assign_name) の空白区切りのリストを指定します。これらのいずれかのエントランス基準に一致したセクションは、出力セクションの先頭に配置され、IS_ORDER で指定された順序で並べ替えられます。IS_ORDER リストに見つからないエントランス基準に一致したセクションは、並べ替えられたセクションの後方に、見つかった順序で配置されます。
「=」形式の代入を使用すると、指定されたセグメントの IS_ORDER の以前の値は破棄され、新しいリストで置き換わります。「+=」形式の IS_ORDER の場合、既存のリストの末尾に新しいリストを連結します。
IS_ORDER 属性が特に注目されるのは、コンパイラの -xF オプションと合わせて使用する場合です。ファイルを -xF オプションを使ってコンパイルすると、そのファイル内の各関数が、.text セクションと同じ属性を持つ別個のセクションに置かれます。これらのセクションは、.text%function_name (function_name は関数名) という名前です。
たとえば、main()、foo()、および bar() の 3 つの関数を持つファイルを -xF オプションを使ってコンパイルすると、再配置可能オブジェクトファイルが作成され、3 つの関数のテキストが .text%main、.text%foo、および .text%bar という名前のセクションに配置されます。リンカーがこれらのセクションを出力に配置するとき、% と、% の後続のすべてが削除されます。したがって、これら 3 つの関数はすべて、.text 出力セクションに配置されます。IS_ORDER 属性は、.text 出力セクション内で特定の相対的な順序で配置することを強制するために使用できます。
次のユーザー定義の mapfile を検討します。
$mapfile_version 2 LOAD_SEGMENT text { ASSIGN_SECTION text_bar { IS_NAME = .text%bar }; ASSIGN_SECTION text_main { IS_NAME = .text%main }; ASSIGN_SECTION text_foo { IS_NAME = .text%foo }; IS_ORDER = text_foo text_bar text_main; };
これら 3 つの関数がソースコード内で検出された順序や、リンカーによって見つけられた順序に関係なく、出力オブジェクトの text セグメント内での順序は foo()、bar()、main() となります。
リンカーはデフォルトで、セグメントの内容が必要とするサイズにまで、セグメントが大きくなることを許可します。セグメントの最大サイズを指定するために、MAX_SIZE 属性を使用できます。MAX_SIZE が設定されると、セグメントが指定されたサイズを超えて大きくなった場合にリンカーはエラーを生成します。
NOHDR 属性が設定されたセグメントが、出力オブジェクトの最初の読み込み可能セグメントになった場合、ELF およびプログラムヘッダーはセグメントに含まれません。
NOHDR 属性が最上位の HDR_NOALLOC 指令と異なる点は、HDR_NOALLOC はセグメントごとの値であり、セグメントが最初の読み込み可能セグメントになった場合にのみ有効だということです。この機能は主に、古い mapfile との互換性を確保するために存在します。詳細は、付録 B System V Release 4 (バージョン 1) Mapfileを参照してください。
セグメントの NOHDR 属性よりも HDR_NOALLOC 指令を優先させることをお勧めします。
リンカーは通常、見つかった順序で出力セクションをセグメントに配置します。OS_ORDER 属性は、出力セクションのこのデフォルトの配置を変更するために使用できます。OS_ORDER は、出力セクション名 ( section_name) の空白区切りのリストを指定します。リストされたセクションは、セグメントの先頭に配置され、OS_ORDER で指定された順序で並べ替えられます。OS_ORDER にリストされていないセクションは、並べ替えられたセクションの後方に、見つかった順序で配置されます。
「=」形式の代入を使用すると、指定されたセグメントの OS_ORDER の以前の値は破棄され、新しいリストで置き換わります。「+=」形式の OS_ORDER の場合、既存のリストの末尾に新しいリストを連結します。
PADDR 属性は、セグメントの物理アドレスを明示するために使用されます。指定された値は、セグメントに対応するプログラムヘッダーの p_addr フィールドに設定されます。デフォルトでは、リンカーはセグメントの物理アドレスを 0 に設定します。この理由は、このフィールドはユーザーモードオブジェクトについては意味がなく、主にオペレーティングシステムのカーネルなど「ユーザーランド以外」のオブジェクトに関係があるためです。
ROUND 属性は、セグメントのサイズを指定された値に丸める必要があることを指定するために使用されます。丸める値の指定は 2 のべき乗である必要があります。デフォルトでは、リンカーはセグメントの丸め係数を 1 に設定し、これはセグメントサイズが丸められないことを意味します。
SIZE_SYMBOL 属性は、リンカーによって作成される、セクションのサイズシンボル名の空白区切りのリストを定義します。サイズシンボルは、セグメントのサイズをバイト数で示す大域絶対シンボルです。これらのシンボルは、オブジェクトファイル内で参照できます。コード内でシンボルにアクセスするには、symbol_name が言語内で正当な識別子であることを確認する必要があります。シンボルをほかの言語からアクセスできる可能性が高くするため、C プログラミング言語のシンボル命名規則が推奨されます。
「=」形式の代入は初期値を設定するために使用でき、リンカーのセッションにつき 1 回のみ使用できます。「+=」形式の SIZE_SYMBOL の場合、既存のリストの末尾に新しいリストを連結し、必要な回数だけ使用できます。
VADDR 属性は、セグメントの仮想アドレスを明示するために使用されます。指定された値は、セグメントに対応するプログラムヘッダーの p_vaddr フィールドに設定されます。デフォルトでは、リンカーは出力ファイルが作成されるとき、仮想アドレスをセグメントに割り当てます。
SEGMENT_ORDER 指令は、出力オブジェクト内のセグメントのデフォルト以外の順序付けを指定するために使用されます。
SEGMENT_ORDER は、セグメント名の空白区切りのリストを受け入れます。
SEGMENT_ORDER = segment_name...; SEGMENT_ORDER += segment_name...;
「=」形式の代入を使用すると、以前のセグメント順序リストは破棄され、新しいリストで置き換わります。「+=」形式の代入の場合、既存のリストの末尾に新しいリストを連結します。
デフォルトでは、リンカーは次の順序でセグメントを順序付けします。
アドレスによって並べ替えられた、LOAD_SEGMENT 指令の VADDR 属性を使用してアドレスを明示した読み込み可能セグメント。
SEGMENT_ORDER 指令を使用して、指定された順序で並べ替えられたセグメント。
アドレスが明示されていない読み込み可能セグメントで、SEGMENT_ORDER リストに見つからないもの。
アドレスが明示されていない注釈セグメントで、SEGMENT_ORDER リストに見つからないもの。
アドレスが明示されていないヌルセグメントで、SEGMENT_ORDER リストに見つからないもの。
注 - ELF には、整形オブジェクトが従う必要がある暗黙の規約があります。
最初の読み込み可能セグメントは、読み取り専用、割り当て可能、および実行可能であることが期待され、ELF ヘッダーとプログラムヘッダー配列を受け取ります。これは通常、定義済みのテキストセグメントです。
実行可能ファイル内の最後の読み込み可能セグメントは、書き込み可能であることが期待され、動的ヒープの先頭は通常、同じ仮想メモリー割り当て内のすぐ後に配置されます。
mapfile を使用すると、これらの要件に違反するオブジェクトを作成できます。そのようなオブジェクトの実行結果は定義されていないため、この操作は回避する必要があります。
HDR_NOALLOC 指令が指定されないかぎり、リンカーは、最初のセグメントが注釈セグメントやヌルセグメントでなく、読み込み可能セグメントであるという要件を強制します。HDR_NOALLOC は 「ユーザーランド」のオブジェクト用に使用できないため、あまり実用的ではありません。この機能はオペレーティングシステムのカーネルを構築するときに使用されます。
STACK 指令はプロセススタックの属性を指定します。
STACK { FLAGS = segment_flags...; FLAGS += segment_flags...; FLAGS -= segment_flags...; };
FLAGS 属性は、表 8-3 に記載されている任意の値で構成される空白区切りのリストで、セグメントのアクセス権を指定します。
3 つの形式を使用できます。シンプルな「=」代入演算子は現在のフラグを新しいセットで置き換え、「+=」形式は既存のセットに新規フラグを追加し、「-=」形式は指定されたフラグを既存のセットから削除します。
デフォルトのスタックアクセス権はプラットフォーム ABI によって定義され、プラットフォームによって異なります。ターゲットプラットフォームの値はセグメントフラグ名 STACK を使用して指定します。
一部のプラットフォームでは、デフォルトのアクセス権に EXECUTE を含めることが ABI によって要求されます。EXECUTE が必要とされることはほとんどなく、一般的には潜在的なセキュリティーリスクと見なされます。EXECUTE アクセス権をスタックから削除することをお勧めします。
STACK { FLAGS -= EXECUTE; };
STACK 指令は出力 ELF オブジェクト内の PT_SUNWSTACK プログラムヘッダーエントリに反映されます。
STUB_OBJECT 指令は、mapfile によって記述されたオブジェクトがスタブオブジェクトとして作成できることをリンカーに通知します。
STUB_OBJECT;
スタブ共有オブジェクトは、コマンド行で指定された mapfile 内の情報から完全に作成されます。スタブオブジェクトを作成するために -z stub オプションを指定する場合、STUB_OBJECT 指令が mapfile に存在することが必須で、リンカーはシンボルの ASSERT 属性内の情報を使用して、実オブジェクトのシンボルと一致する大域シンボルを作成します。
SYMBOL_SCOPE および SYMBOL_VERSION 指令は、大域シンボルのスコープと属性を指定するために使用されます。SYMBOL_SCOPE は、命名されていないベースシンボルバージョンのコンテキストで動作し、SYMBOL_VERSION は、明示的に命名された大域バージョンにシンボルを収集するために使用されます。SYMBOL_VERSION 指令を使用すると、下位互換性を保ちながらオブジェクトの進化をサポートできる安定したインタフェースを作成できます。
SYMBOL_VERSION の構文は次のとおりです。
SYMBOL_VERSION version_name { symbol_scope: *; symbol_name; symbol_name { ASSERT = { ALIAS = symbol_name; BINDING = symbol_binding; TYPE = symbol_type; SIZE = size_value; SIZE = size_value[count]; VALUE = value; }; AUXILIARY = soname; FILTER = soname; FLAGS = symbol_flags...; SIZE = size_value; SIZE = size_value[count]; TYPE = symbol_type; VALUE = value; }; } [inherited_version_name...];
SYMBOL_SCOPE はバージョン名を受け入れませんが、それ以外は同一です。
SYMBOL_SCOPE { ... };
SYMBOL_VERSION 指令では、version_name がこの一連のシンボル定義のラベルを提供します。このラベルは、出力オブジェクト内のバージョン定義を指定します。1 つ以上の継承されたバージョン (inherited_version_name) を空白区切りで指定できます。この場合、新しく定義されたバージョンは、指定されたバージョンを継承します。第 9 章インタフェースおよびバージョン管理を参照してください。
symbol_scope は SYMBOL_SCOPE または SYMBOL_VERSION 指令内でシンボルのスコープを定義します。デフォルトでは、シンボルは大域スコープを持つものと想定されます。これは symbol_scope の後ろにコロン (:) を付けて指定することによって変更できます。これらの行は、後続のスコープ宣言によって変更されるまで、後に続くすべてのシンボルのシンボルスコープを決定します。可能性のあるスコープ値と意味を、次の表に示します。
表 8-8 シンボルのスコープのタイプ
|
symbol_name はシンボルの名前です。この名前により、修飾属性に応じて、シンボル定義またはシンボル参照が生成されます。修飾属性のないもっとも簡潔な形式で、シンボル参照が作成されます。この参照は、「-u オプションを使用した追加シンボルの定義」で説明した -u オプションを使用して生成する参照とまったく同じものです。 通常、このシンボル名に修飾属性が付いている場合には、シンボル定義は、関連する属性を使用して生成されます。
local スコープが定義された場合、シンボル名を特別な「*」自動縮小 (auto-reduction) 指令として定義できます。可視性が明示的に定義されていないシンボルは、生成される動的オブジェクト内のローカル結合に降格されます。明示的な可視性の定義は、mapfile 定義、再配置可能オブジェクト内にカプセル化された可視性定義のいずれかに起因します。同様に、eliminate スコープが定義された場合、シンボル名を特別な「*」自動削除 (auto-elimination) 指令として定義できます。可視性が明示的に定義されていないシンボルは、生成される動的オブジェクトから削除されます。
SYMBOL_VERSION 指令が指定されるか、SYMBOL_VERSION または SYMBOL_SCOPE のいずれかで自動縮小が指定された場合、作成されるイメージにバージョン情報が記録されます。このイメージが実行可能プログラムまたは共有オブジェクトである場合には、シンボル縮小も適用されます。
作成されるイメージが再配置可能オブジェクトである場合は、デフォルトにより、シンボル縮小は適用されません。この場合、シンボル縮小はバージョン情報の一部として記録されます。これらの縮小は、再配置可能オブジェクトが最終的に実行可能ファイルまたは共有オブジェクトの生成に使用されるときに適用されます。リンカーの -B reduce オプションを使用すると、再配置可能オブジェクトを生成するときに、強制的にシンボル縮小を実行できます。
バージョン情報の詳細は、第 9 章インタフェースおよびバージョン管理に記載されています。
注 - インタフェース定義を確実に安定させるためには、シンボル名の定義に対しワイルドカードによる拡張を行わないようにします。
シンボルをバージョンに割り当てたり、そのスコープを指定したり、またはその両方を行うには、symbol_name 自体をリストすると簡単です。オプションのシンボル属性は {} 括弧内で指定できます。有効な属性を次に示します。
ASSERT 属性は、シンボルの予期される特性を指定するために使用されます。リンカーは、リンク編集で得られたシンボル特性と、ASSERT 属性によって指定されたシンボル特性を比較します。表明された属性と実際の属性が一致しない場合、重大なエラーが発生し、出力オブジェクトは作成されません。
ASSERT 属性の解釈は、STUB_OBJECT 指令または -z stub コマンド行オプションが使用されるかどうかによって異なります。次の 3 つの場合が考えられます。
STUB_OBJECT 指令を使用しない場合、ASSERT 属性は不要です。ただし、ASSERT 属性が存在する場合、属性はリンク編集で収集された実際の値に対して検証されます。いずれかの ASSERT 属性が、関連付けられている実際の値と一致しない場合、リンク編集はエラーで終了します。
STUB_OBJECT 指令が使用され、-z stub コマンド行オプションが指定された場合、リンカーは ASSERT 指令を使用して、オブジェクトによって提供される大域シンボルの属性を定義します。「スタブオブジェクト」を参照してください。
STUB_OBJECT 指令が使用され、-z stub コマンド行オプションが指定されない場合、リンカーは、結果として生成されるオブジェクト内のすべての大域データが、対応する ASSERT 指令を持つことを要求します。この指令では、大域データをデータとして宣言し、サイズを指定する必要があります。このモードで、TYPE ASSERT 属性が指定されない場合、GLOBAL が想定されます。同様に、SH_ATTR が指定されない場合、デフォルト値 BITS が想定されます。これらのデフォルト値によって、スタブと実オブジェクトのデータ属性が互換性を持つことが保証されます。結果の ASSERT ステートメントは、上記の最初の場合と同じ方法で評価されます。「STUB_OBJECT 指令」を参照してください。
ASSERT は次を受け入れます。
ALIAS
以前定義されたシンボルの別名を定義します。別名シンボルは、メインシンボルと同じタイプ、値、サイズを持ちます。ALIAS 属性は、TYPE、SIZE、および SH_ATTR 属性と一緒に使用できません。ALIAS が指定された場合、タイプ、サイズ、およびセクションの属性は、別名シンボルから取得されます。
BIND
ELF の symbol_binding を指定します。<sys/elf.h> 内で定義されている任意の STB_ 値を指定できます。STB_ 接頭辞は削除します。たとえば、GLOBAL または WEAK です。
TYPE
ELF の symbol_type を指定します。<sys/elf.h> 内で定義されている任意の STT_ 定数を指定できます。STT_ 接頭辞は削除します。たとえば、OBJECT、COMMON、または FUNC となります。 また、ほかの mapfile 使用法との互換性を維持するために、FUNCTION および DATA をそれぞれ STT_FUNC および STT_OBJECT に指定できます。TYPE は ALIAS と同時に使用できません。
SH_ATTR
シンボルに関連付けられているセクションの属性を指定します。指定できる section_attributes を、表 8-9 に示します。SH_ATTR は ALIAS と同時に使用できません。
SIZE
予想されるシンボルサイズを指定します。SIZE は ALIAS と同時に使用できません。size_value 引数の構文は、SIZE 属性の説明にあるとおりです。「SIZE 属性」を参照してください。
VALUE
予想されるシンボル値を指定します。
表 8-9 SH_ATTR の値
|
このシンボルが共有オブジェクト名 (soname) の補助フィルタであることを示します。「補助フィルタの生成」を参照してください。
このシンボルが共有オブジェクト名 (name) のフィルタであることを示します。「標準フィルタの生成」を参照してください。フィルタシンボルは、入力再配置可能オブジェクトから提供される補助実装を必要としません。したがって、シンボルの種類を定義してこの指令を使用し、絶対シンボルテーブルエントリを作成します。
symbol_flags は、次の値が 1 つ以上含まれる空白区切りリストとしてシンボル属性を指定します。
表 8-10 シンボルフラグの値
|
サイズ属性を設定します。この属性により、シンボル定義が作成されます。
size_value 引数には、数値またはシンボリック名 addrsize を指定できます。addrsize はメモリーアドレスを保持できるマシンワードのサイズを表します。リンカーは addrsize に対し、32 ビットオブジェクトを作成するときは値 4 を、64 ビットオブジェクトを構築するときは値 8 を代入します。addrsize は、条件付き入力の使用を必要としないで 32 ビットおよび 64 ビットオブジェクトに合わせて自動的に調節されるため、ポインタ変数および C 変数の long 型のサイズを表す際に使用すると便利です。
size_value 引数にはオプションで count 値を角括弧で囲んで接尾辞として追加できます。count が存在する場合、size_value と count が掛け合わされて最終的なサイズの値が取得されます。
シンボルのタイプ属性です。この属性は、COMMON、 DATA、または FUNCTION のいずれかです。COMMON を指定すると、一時的なシンボル定義になります。DATA および FUNCTION を指定すると、セクションシンボル定義または絶対的なシンボル定義になります。「シンボルテーブルセクション」を参照してください。
データ属性を指定すると、OBJT シンボルが作成されます。サイズを指定し値を指定しないデータ属性を指定すると、セクションシンボルが ELF セクションに関連付けられて作成されます。このセクションは、ゼロで埋められます。関数属性を指定すると、FUNC シンボルが作成されます。
サイズを指定し値を指定しない関数属性を指定すると、セクションシンボルが ELF セクションに関連付けられて作成されます。このセクションには、リンカーによって生成される void 関数が、次のシグニチャーを使用して割り当てられます。
void (*)(void)
値が指定されたデータまたは関数属性を指定すると、絶対値を表す ABS セクションインデックスを伴う適切なシンボルタイプが生成されます。
セクションデータシンボルの作成は、フィルタの作成時に役立ちます。実行可能ファイルからフィルタのセクションデータシンボルへの外部参照により、生成中のコピーが適切に再配置されます。「コピー再配置」を参照してください。
値の属性を示します。この属性により、シンボル定義が作成されます。