Go to main content
Oracle® Solaris 11.3 リンカーとライブラリガイド

印刷ビューの終了

更新: 2015 年 10 月
 
 

mapfile の構造と構文

mapfile ディレクティブは複数の行に渡ることができ、改行を含む空白文字を任意の数だけ含めることができます。

すべての構文説明について、次の表記が適用されます。

  • 空白文字または改行は、名前または値の中を除いてどこにでも入れられます。

  • ハッシュ文字 (#) で始まり改行で終わるコメントは、空白文字を入れることができる場所であれば、どこにでも入れられます。コメントはリンカーによって解釈されず、ドキュメント化のためのみに使用されます。

  • すべての指令はセミコロン (;) で終了します。{....} セクション内の最後のセミコロンは省略できます。

  • 固定幅のすべての文字エントリ、すべてのコロン (:)、セミコロン (;)、代入 (=, +=, -=)、および括弧 {....} は、そのままの文字を入力します。

  • 「斜体文字」で示されたエントリはすべて、適切なもので置き換える。

  • [ .... ] 括弧はオプションの構文を示すために使用されます。括弧は入力しません。実際の指令内には現れません。

  • 名前は大文字と小文字の区別がある文字列です。表 3 には、mapfile 内で一般的に見られる名前およびその他の文字列のリストが含まれています。名前は 3 つの異なる形式で指定できます。

    • 引用符なし

      引用符なしの名前は英字および数字のシーケンスです。最初の文字は英字である必要があり、0 個以上の英字または数字が後に続きます。パーセント (%)、斜線 (/)、ピリオド (.)、および下線 (_) は英字としてカウントされます。ドル記号 ($)、およびハイフン (-) は数字としてカウントされます。

    • 単一引用符

      単一引用符 (') で囲んだ名前は、単一引用符または改行以外のすべての文字を含むことができます。すべての文字はリテラル文字として解釈されます。この引用形式は、引用符なしの名前では許可されない通常のプリント可能文字を含むファイルパスやその他の名前を指定する場合に便利です。

    • 二重引用符

      二重引用符 (") で囲んだ名前は、二重引用符または改行以外のすべての文字を含むことができます。バックスラッシュ (\) はエスケープ文字です。C プログラミング言語の文字列リテラル内で使用される場合と同じように機能します。表 2 で示すように、前にバックスラッシュが付いた文字は、それらが表す文字に置換されます。表 2 に示す文字以外の文字がバックスラッシュのあとに続くと、エラーになります。

  • value は数値を表し、整数定数について C 言語で使用される規則に従って、16 進数、10 進数、または 8 進数が使えます。すべての値は符号なしの整数値で、32 ビット出力オブジェクトの場合は 32 ビット、64 ビット出力オブジェクトの場合は 64 ビットです。

  • segment_flags には、表 4 に示す 1 つ以上の値の空白区切りのリストとしてメモリーアクセス権を指定します。これらの値は <sys/elf.h> 内に定義されている PF_ 値に対応します。

表 2  二重引用符テキストのエスケープシーケンス
エスケープシーケンス
意味
\a
警告 (ベル)
\b
バックスペース
\f
用紙送り
\n
改行
\r
return
\t
水平タブ
\v
垂直タブ
\\
バックスラッシュ
\'
単一引用符
\"
二重引用符
\ooo
8 進数の定数で、ooo は 1 つから 3 つまでの 8 進数 (0....7) です
表 3  mapfile 内で一般的に使用される名前およびその他の文字列
名前
目的
segment_name
ELF セグメントの名前
section_name
ELF セクションの名前
symbol_name
ELF シンボルの名前
file_path
ELF オブジェクトまたは ELF オブジェクトを含むアーカイブを参照するために使用される、スラッシュ (/) で区切られた複数の名前から構成される UNIX のファイルパス
file_basename
file_path の最後のコンポーネント (basename(1))
objname
file_basename、またはアーカイブ内に含まれているオブジェクトの名前
soname
共有可能オブジェクトの SONAME に使用される共有可能オブジェクト名 (libc.so.1 など)
version_name
ELF バージョン管理セクション内で使用されるシンボルバージョンの名前
inherited_version_name
別のシンボルバージョンによって継承されたシンボルバージョンの名前
表 4  セグメントフラグ
フラグの値
意味
READ
セグメントは読み込み可能です
WRITE
セグメントは書き込み可能です
EXECUTE
セグメントは実行可能です
0
すべてのアクセス権フラグがクリアされます
DATA
ターゲットプラットフォーム上のデータセグメントに適した READWRITE、および EXECUTE フラグの組み合わせ
STACK
プラットフォーム ABI によって定義される、ターゲットプラットフォームに適した READWRITE、および EXECUTE フラグの組み合わせ

mapfile のバージョン

コメントまたは空白でない mapfile 内の先頭行には、mapfile のバージョン宣言が期待されます。この宣言によって、ファイルの残りの部分で使用される mapfile 言語のバージョンが確立されます。このドキュメントに記載されている mapfile 言語はバージョン 2 です。

        $mapfile_version 2

バージョン宣言で開始されない mapfile は、AT&T によって System V Release 4 Unix (SVR4) 用に定義されたオリジナルの mapfile 言語で記述されているとみなされます。リンカーはこのような mapfile を処理する能力を保持しています。この構文は、Appendix B, 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 によって評価される論理式に使用できる名前の内部テーブルを保持します。このテーブルは起動時に、次の表内のそれぞれの名前で初期化され、作成中の出力オブジェクトに適用されます。

表 5  定義済みの条件式の名前
名前
意味
_ELF32
32 ビットオブジェクト
_ELF64
64 ビットオブジェクト
_ET_DYN
共有オブジェクトファイル
_ET_EXEC
実行可能オブジェクト
_ET_REL
再配置可能オブジェクト
_sparc
SPARC マシン (32 ビットまたは 64 ビット)
_x86
x86 マシン (32 ビットまたは 64 ビット)
true
常に定義済み

名前は大文字と小文字を区別して、示されたとおりの名前を使用する必要があります。たとえば、true は定義されていますが、TRUE は定義されていません。これらのすべての名前は、それ自体を論理式として使用できます。次に例を示します。

        $if _ELF64
        ....
        $endif

出力オブジェクトが 64 ビットの場合、この例は true に評価され、リンカーは囲まれたテキストを処理します。これらの論理式では数値は許可されませんが、特殊な例外として、値 1true に評価され、0false に評価されます。

未定義のすべての名前は false に評価されます。一般的に、無条件にスキップする必要がある入力行を指定するために、未定義の名前 false を使用します。

        $if false
        ....
        $endif

次の表に示す演算子を使用すると、さらに複雑な論理式を記述できます。

表 6  条件式の演算子
演算子
意味
&&
論理 AND
||
論理 OR
( 式 )
式の一部
!
後続の式のブール値を否定します

式は左から右に評価されます。式の一部は、それを囲む式の前に評価されます。

たとえば、x86 プラットフォーム用の 64 ビットオブジェクトを構築するとき、次の構造構文が評価されます。

        $if _ELF64 && _x86
        ....
        $endif

$add 指令を使用すると、リンカーの既知の名前テーブルに新しい名前を追加できます。前の例を使用すると、$if 指令を簡素化するために、64 ビット x86 オブジェクトを表す amd64 という名前を定義すると便利な場合もあります。

        $if _ELF64 && _x86
        $add amd64
        $endif

これを使用すると、前の例を簡素化できます。

        $if amd64
        ....
        $endif

リンカーの –z mapfile-add オプションを使用することによって、リンカーの既知の名前のテーブルに新しい名前を追加することもできます。このオプションは、使用中のコンパイラなどの外部環境の属性に基づいて、mapfile 入力を条件的に有効にする必要がある場合に役立ちます。

$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 {
                        subattribute [= value];
                ....
                };
        } [name....];

mapfile 構文の文法では、入れ子が許可される深さに制限がありません。入れ子の深さは、指令の要件のみに依存します。

MATCH および MATCHREF

MATCH および MATCHREF 式は、文字列とパターンをマッチングし、元の文字列の一部を含む新しい文字列を生成する機能を提供します。具体的な使用については、後続のセクションで、これらの式をサポートする各 mapfile ディレクティブのドキュメントで説明します。

MATCH 式は、スラッシュ (/) で区切られたパターンに対して文字列をマッチングできます。

        MATCH(g/match-pattern/[i])
        MATCH(r/match-pattern/[i])
        MATCH(t/match-pattern/[i])

実行するマッチングのタイプはパターンの前に存在する単一の文字コードで指定されます。実行するマッチングのタイプは match-pattern の構文を定義します。

g

glob パターンのマッチング。match-pattern は、fnmatch(5) で説明されている glob 構文を使用して指定されます。

r

正規表現のマッチング。match-pattern は、regex(5) で説明されている拡張正規表現 (ERE) 構文を使用して指定されます。

t

標準テキストのマッチング。match-pattern は、二重引用符で囲む文字列の標準 mapfile 構文に従いますが、通常の二重引用符 (") の代わりにスラッシュ (/) を使用します。二重引用符で囲む文字列のルールは、mapfile の構造と構文で説明しています。

デフォルトでは、大文字と小文字を区別するパターンマッチングが使用されます。大文字と小文字を区別しないマッチングは、閉じスラッシュ (/) のすぐあとに「i」の文字を指定することで指定できます。

MATCHREF 式は、テンプレート文字列をベースとして新しい文字列を生成するために使用され、前の MATCH でマッチングされた部分文字列を含めることができます。MATCHREF は、特に正規表現の MATCH と組み合わせて使用することで、柔軟な名前変更メカニズムを提供します。

        MATCHREF(/template-string/)

template-string は、二重引用符で囲む文字列の標準 mapfile 構文に従いますが、通常の二重引用符 (") の代わりにスラッシュ (/) を使用します。二重引用符で囲む文字列のルールは、mapfile の構造と構文で説明しています。

template-string では、関連する MATCH 式からコピーする文字列を ${cN} の形式のトークンで示し、c には MATCH ディレクティブを識別する単一の文字を、N にはその MATCH 内の部分文字列を識別する整数を指定します。MATCHREF で許可される識別子文字は、MATCHREF を使用する mapfile ディレクティブによって異なります。MATCH および MATCHREF の使用をサポートする各 mapfile ディレクティブのドキュメントは、そのディレクティブによって許可される MATCHREF 識別文字のセットを定義します。

MATCHREF 式から生成される文字列は template-string で構成され、すべての ${cN} トークンは、それらが参照する MATCH 部分文字列で置き換えられます。ゼロ番目のトークン ${c0} は、MATCH 式でマッチングされる文字列全体を表し、これはすべての MATCH 式でサポートされます。0 より大きい値 n を指定するトークンは、正規表現の MATCH 式でのみサポートされます。正規表現で使用される場合、0 より大きい値 n は、MATCH パターン内で見つかる n 番目の開括弧に対応し、正規表現のそのサブパートでマッチングされる部分文字列を表します。

指定された ${cN}MATCH の部分文字列に対応しない場合、空 ("") の文字列が置き換えられます。これは、glob またはテキストマッチングのゼロ以外のすべての値 n、または正規表現パターン内の括弧の数よりも大きい値 n に対して行われます。

例: セクションのリダイレクト

通常、リンカーは入力セクションを出力オブジェクトにコピーして、入力と同じ名前の出力セクションを作成します。LOAD_SEGMENT ディレクティブでは、MATCH および MATCHREF を使用してセクションを名前でマッチングし、オプションとして、異なる名前が付けられた出力セクションにそれらをリダイレクトできます。次の mapfile は、文字列「.appXtext.」で始まる名前を持つ書き込み不可で割り当て可能なすべてのセクションをリダイレクトし、この接頭辞を「.text.」で置き換えて名前を付けた出力セクションに各セクションをリダイレクトします。

        $mapfile_version 2

        LOAD_SEGMENT text {
                ASSIGN_SECTION apptext {
                        IS_NAME = MATCH(r/^\.appXtext\.(.*)$/);
                        FLAGS = ALLOC !WRITE;
                        OUTPUT_SECTION {
                                NAME = MATCHREF(/.text.${n1}/);
                        };
                };
        };