ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
リンカーとライブラリ Oracle Solaris 10 8/11 Information Library (日本語) |
5. アプリケーションバイナリインタフェースとバージョン管理
LOAD_SEGMENT/NOTE_SEGMENT/NULL_SEGMENT 指令
SIZE_SYMBOL 属性 (LOAD_SEGMENT のみ)
SYMBOL_SCOPE/SYMBOL_VERSION 指令
定義済みセグメントとエントランス基準のための mapfile 指令
mapfile 指令は複数の行に渡ることができ、改行を含む空白文字を任意の数だけ含めることができます。
すべての構文説明について、次の表記が適用されます。
空白文字または改行は、名前または値の中を除いてどこにでも入れられます。
ハッシュ文字 (#) で始まり改行で終わるコメントは、空白文字を入れることができる場所であれば、どこにでも入れられます。コメントはリンカーによって解釈されず、文書化のためのみに使用されます。
すべての指令はセミコロン (;) で終了します。{...} セクション内の最後のセミコロンは省略できます。
固定幅のすべての文字エントリ、すべてのコロン (:)、セミコロン (;)、代入 (=, +=, -=)、および括弧 {...} は、そのままの文字を入力します。
「斜体文字」で示されたエントリはすべて、適切なもので置き換える。
[ ... ] 括弧は省略可能な構文を示すために使用されます。括弧は入力しません。実際の指令内には現れません。
名前は大文字と小文字の区別がある文字列です。表 9-2 には、mapfile 内で一般的に見られる名前およびその他の文字列のリストが含まれています。名前は 3 つの異なる形式で指定できます。
引用符なし
引用符なしの名前は英字および数字のシーケンスです。最初の文字は英字である必要があり、0 個以上の英字または数字が後に続きます。パーセント (%)、斜線 (/)、ピリオド (.)、および下線 (_) は英字としてカウントされます。ドル記号 ($)、およびハイフン (-) は数字としてカウントされます。
単一引用符
単一引用符 (') で囲んだ名前は、単一引用符または改行以外のすべての文字を含むことができます。すべての文字はリテラル文字として解釈されます。この引用形式は、引用符なしの名前では許可されない通常のプリント可能文字を含むファイルパスやその他の名前を指定する場合に便利です。
二重引用符
二重引用符 (") で囲んだ名前は、二重引用符または改行以外のすべての文字を含むことができます。バックスラッシュ (\) はエスケープ文字です。C プログラミング言語の文字列リテラル内で使用される場合と同じように機能します。表 9-1 で示すように、前にバックスラッシュが付いた文字は、それらが表す文字に置換されます。表 9-1 に示す文字以外の文字がバックスラッシュの後に続くと、エラーになります。
value は数値を表し、整数定数について C 言語で使用される規則に従って、16 進数、10 進数、または 8 進数が使えます。すべての値は符号なしの整数値で、32 ビット出力オブジェクトの場合は 32 ビット、64 ビット出力オブジェクトの場合は 64 ビットです。
segment_flags には、表 9-3 に示す値の空白区切りのリストとしてメモリーアクセス権を指定します。これらの値は <sys/elf.h> 内に定義されている PF_ 値に対応します。
表 9-1 二重引用符テキストのエスケープシーケンス
|
表 9-2 mapfile 内で一般的に使用される名前およびその他の文字列
|
表 9-3 セグメントフラグ
|
コメントまたは空白でない mapfile 内の先頭行には、mapfile のバージョン宣言が期待されます。この宣言によって、ファイルの残りの部分で使用される mapfile 言語のバージョンが確立されます。このマニュアルに記載されている mapfile 言語はバージョン 2 です。
$mapfile_version 2
バージョン宣言で開始されない mapfile は、AT&T によって System V Release 4 Unix (SVR4) 用に定義されたオリジナルの mapfile 言語で記述されていると見なされます。リンカーはこのような mapfile を処理する能力を保持しています。この構文は、付録 E System V Release 4 (バージョン 1) Mapfileに記載されています。
mapfile 内の行は、特定の ELFCLASS (32 ビットまたは 64 ビット) あるいは機械タイプにのみ適用されるように条件付けできます。
$if expr ... [$elif expr] ... [$else] ... $endif
条件付き入力式は、論理的な true または false の値に評価されます。それぞれの指令 ($if、$elif、$else、および $endif) は 1 行に 1 つ記述します。$if 行と後続の $elif 行の中の式は、true と評価される式が見つかるまで順番に評価されます。false の値を持つ行に続くテキストは、破棄されます。true の指令の行に続くテキストは、通常どおり処理されます。この説明のテキストとは、条件文の一部でない任意の内容を表します。true となる $if または $elif が見つかり、そのテキストが処理されると、後続の $elif および $else 行に加え、それらのテキストも破棄されます。すべての式がゼロで、$else がある場合、$else に続くテキストが通常どおり処理されます。
$if 指令の範囲は、複数の mapfile を超えることはできません。$if 指令は、$if 指令を使用する mapfile 内で、対応する $endif によって終了する必要があり、終了しない場合はリンカーはエラーを生成します。
リンカーは、$if および $elif によって評価される論理式に使用できる名前の内部テーブルを保持します。このテーブルは起動時に、次の表内のそれぞれの名前で初期化され、作成中の出力オブジェクトに適用されます。
表 9-4 定義済みの条件式の名前
|
名前は大文字と小文字を区別して、示されたとおりの名前を使用する必要があります。たとえば、true は定義されていますが、TRUE は定義されていません。これらのすべての名前は、それ自体を論理式として使用できます。次に例を示します。
$if _ELF64 ... $endif
出力オブジェクトが 64 ビットの場合、この例は true に評価され、リンカーは囲まれたテキストを処理します。これらの論理式では数値は許可されませんが、特殊な例外として、値 1 は true に評価され、0 は false に評価されます。
未定義のすべての名前は false に評価されます。一般的に、無条件にスキップする必要がある入力行を指定するために、未定義の名前 false を使用します。
$if false ... $endif
次の表に示す演算子を使用すると、さらに複雑な論理式を記述できます。
表 9-5 条件式の演算子
|
式は左から右に評価されます。式の一部は、それを囲む式の前に評価されます。
たとえば、x86 プラットフォーム用の 64 ビットオブジェクトを構築するとき、次の構造構文が評価されます。
$if _ELF64 && _x86 ... $endif
$add 指令を使用すると、リンカーの既知の名前テーブルに新しい名前を追加できます。前の例を使用すると、$if 指令を簡素化するために、64 ビット x86 オブジェクトを表す amd64 という名前を定義すると便利な場合もあります。
$if _ELF64 && _x86 $add amd64 $endif
これを使用すると、前の例を簡素化できます。
$if amd64 ... $endif
$clear 指令は $add 指令の逆です。これは内部テーブルから名前を削除するために使用されます。
$clear amd64
$add 指令の効果は、$add を使用する mapfile の終わりを超えて持続し、同じリンク操作内でリンカーによって処理される後続の mapfile でも使用できます。この動作を望まない場合は、$add が含まれる mapfile の最後で $clear を使用して定義を削除します。
最後に、$error 指令を使用すると、リンカーは行の残りのすべてのテキストを重大なエラーとして出力し、リンク操作を停止します。$error 指令は、プログラマがオブジェクトを新しい機械タイプに移植する際、必要な mapfile 定義が欠落した正しくないオブジェクトを暗黙のうちに構築できないようにするために使用できます。
$if _sparc ... $elif _x86 ... $else $error unknown machine type $endif
C 言語のプログラマであれば、mapfile の条件付き入力に使用される構文は、C プリプロセッサのマクロ言語の構文と似ていることがわかります。この類似性は意図的なものです。ただし、mapfile の条件付き入力の指令は、設計上、C プリプロセッサによって提供されるものよりも、ずっと機能が劣ります。クロスプラットフォーム環境でのリンク操作をサポートするために必要なもっとも基本的な機能のみが提供されます。
2 つの言語の大きな違いは次のとおりです。
C プリプロセッサは完全なマクロ言語を定義し、マクロはソーステキストと、#if および #elif プリプロセッサステートメントによって評価される式の両方に適用されます。リンカーの mapfile にはマクロ機能が実装されていません。
C プリプロセッサによって評価される式には、数値の型と豊富な演算子セットが含まれます。mapfile 論理式には、ブール型の true および false 値と、限定された演算子セットが含まれます。
C プリプロセッサ式は、マクロとして定義されることがある任意の数値を含み、指定のマクロが定義されたものかどうかを評価するために defined() が使用されます。これによって、true (ゼロ以外) または false (ゼロ) 値が生成されます。mapfile 論理式ではブール値のみを操作でき、名前は defined() 操作を使用せずに直接使用されます。指定された名前はリンカーの既知の名前テーブルにある場合は true と見なされ、そうでない場合は false と見なされます。
高度なマクロ処理が必要な場合、m4(1) などの外部マクロプロセッサの使用を検討する必要があります。
mapfile 指令は、出力オブジェクトのさまざまな側面を指定するために存在します。これらの指令は共通の構文を共有しています。属性に名前と値のペアを使用し、階層およびグループを表すために {...} 構文を使用します。
mapfile 指令の構文は、次の一般的な形式に基づきます。
もっとも簡単な形式は、値を持たない指令の名前です。
directive;
次の形式は、指令の名前に、値または空白区切りの値のリストが付いたものです。
directive = value...;
示されている「=」代入演算子のほかに、「+=」および「-=」形式の代入も使用できます。「=」演算子は、指定された指令を、指定された値または値リストに設定します。「+=」演算子は、右側の値を現在の値に追加するために使用され、「-=」演算子は値を削除するために使用されます。
さらに複雑な指令では、複数の属性を {...} 括弧で囲んで、複数の属性を 1 つの単位としてグループ化して操作します。
directive [name] { attribute [directive = value]; ... } [name];
開き括弧 ({) の前に名前を置くことができ、指定されたステートメントの結果に名前を付けるために使用されます。同様に、閉じ括弧 (}) の後ろで終端のセミコロン (;) の前に、1 つ以上のオプションの名前を置くことができます。これらの名前は、定義される項目が、ほかの名前付き項目と関係があることを表すために使用されます。
グループ内の属性の形式は、上記で説明した同じ構文を使用します。つまり、単純な指令に、値が付いたものか、代入演算子 (=、+=、-=) の後に値が付いたものか、または空白区切りの値のリストが付いたもので、セミコロン (;) で終了します。
指令が持つ属性にはサブ属性を持たせることができます。そのような場合、サブ属性も階層を示すために、入れ子の {...} 括弧でグループ化されます。
directive [name] { attribute { subatribute [= value]; ... }; } [name...];
mapfile 構文の文法では、入れ子が許可される深さに制限がありません。入れ子の深さは、指令の要件のみに依存します。