以下の 5 つの基本的な指示を mapfile に入力できます。
セグメント宣言
対応付け指示
セクションからセグメントへの順序付け
サイズシンボル宣言
ファイル制御指示
それぞれの指示は複数の行にまたがることができ、最後にセミコロンを付ければ、いくつでも空白 (改行を含む) を入れることができます。
通常、セグメント宣言の後に、対応付け指示を記述します。セグメントを宣言してから、セクションがそのセグメントの一部分になる条件を定義します。対応付け先のセグメントを最初に宣言せずに、対応付け指示あるいはサイズシンボル宣言を入力した場合、組み込みのセグメント以外のセグメントには、デフォルト属性が付与されます。この種のセグメントは、「暗示的に」宣言されたセグメントになります。
サイズシンボル宣言、およびファイル制御指示は、mapfile のどこにでも入れることができます。
以後の節では、それぞれの指示について説明します。すべての構文説明について、次の表記が適用されます。
固定幅の文字のエントリ、すべてのコロン、セミコロン、等符号、@ 記号は、そのままの文字を入力する
「斜体文字」で示されたエントリはすべて、適切なもので置き換える
{ ... }* は、「無しまたはそれ以上」を意味する
{ ... }+ は、「1 つまたはそれ以上」を意味する
[ ... ] は、「任意指定」を意味する
section_names と segment_names は、C 識別子と同じ規則に従い、ピリオド (.) は文字として扱われる。たとえば、.bss は正当な名前
section_names、segment_names、file_names、および symbol_names には大文字と小文字の区別がある。それ以外のものには大文字と小文字の区別は無い
空白文字 (あるいは改行文字) は、数字の前および名前や値の間以外はどこにでも入れられる
# で始まり改行で終わるコメントは、空白文字を入れることができる場所であれば、どこにでも入れられる
セグメントの宣言により、出力ファイルに新しいセグメントを作成したり、既存のセグメントの属性値を変更したりできます。既存のセグメントとは、以前に定義したもの、あるいは以下に述べる 4 つの組み込みセグメントの 1 つのことです。
セグメントの宣言は以下の構文で行います。
segment_name = {segment_attribute_value}*;
各 segment_name に対して、任意の数の segment_attribute_values を任意の順序で指定し、それぞれは空白文字で区切ります。セグメント属性ごとに 1 つの値だけを指定できます。 セグメント属性および有効な値を、次の表に示します。
表 9–1 Mapfile セグメント属性
属性 |
値 |
---|---|
segment_type |
LOAD | NOTE | STACK |
segment_flags |
? [E] [N] [O] [R] [W] [X] |
virtual_address |
Vnumber |
physical_address |
Pnumber |
length |
Lnumber |
rounding |
Rnumber |
alignment |
Anumber |
4 つの組み込みセグメントが存在し、以下のデフォルト属性値を保持します。
テキスト – LOAD、?RX、virtual_address と physical_address と length は指定なし、alignment 値は CPU タイプごとにデフォルトに設定
データ – LOAD、?RWX、virtual_address と physical_address と length は指定なし、alignment 値は CPU タイプごとにデフォルトに設定
bss – 無効、LOAD、?RWX、virtual_address と physical_address と length は指定なし、alignment 値は CPU タイプごとにデフォルトに設定
注釈 – NOTE
デフォルトでは、bss セグメントは無効に設定されています。この唯一の入力部分である SHT_NOBITS タイプのセクションは、データセグメント内でキャプチャされます。SHT_NOBITS セクションの詳細は、表 7–12 を参照してください。もっとも単純な bss 宣言を次に示します。
bss =;
この宣言で、bss セグメント作成を有効にできます。すべての SHT_NOBITS セクションは、データセグメントではなく、このセグメントによりキャプチャされるようになります。最も単純な場合、他のセグメントにも適用されるデフォルトを使用してこのセグメントの整列が行われます。宣言を実行してセグメントの追加属性を指定することにより、セグメント作成を有効にしたり、指定した属性を付与したりすることもできます。
リンカーは、mapfile を読み取る前に、これらのセグメントが宣言されたように動作します。詳細は、mapfile オプションの初期値を参照してください。
セグメント宣言を入力する場合、以下のことに注意してください。
数字には、C 言語と同じ形式で、16 進数、10 進数、あるいは 8 進数が使える
V、P、L、R、あるいは A と数字の間には空白文字を入れてはいけない
segment_type 値は、LOAD、NOTE、または STACK のいずれか。未指定の場合、デフォルトの LOAD に設定される
segment_flags 値は、R は読み取り可能 、W は書き込み可能、X は実行可能、O は順番を表す。疑問符 ? と segment_flags 値を構成する個々のフラグの間には、空白文字を入れてはいけない
LOAD セグメントの segment_flags 値は、初期値で RWX になる
NOTE セグメントには、segment_type 以外のセグメント属性値は割り当てられない
STACK 値の segment_type が 1 つ許可される。segment_flags から選択されたセグメントのアクセス要求だけを指定できる
暗示的に宣言されたセグメントでは、segment_type 値は LOAD、segment_flags 値は RWX、 virtual_address と physical_address と整列値は初期値、そして長さは無制限になる
リンカーは、1 つ前のセグメントの属性値に基づいて、現在のセグメントのアドレスや長さを計算します。
LOAD セグメントには、 virtual_address 値または physical_address 値、および最大セグメント長値を明示的に指定できる
セグメントに ? の segment_flags 値があってあとに何もない場合、値は読み取り不可、書き込み不可、および実行不可になる
alignment 値は、セグメントの最初の仮想アドレスを計算する際に使われる。この整列は、整列指定されたセグメントにだけ影響する。その他のセグメントは、その alignment が変更されない限り、デフォルトの整列が使われる
属性値 virtual_address、physical_address、length のいずれかが設定されていない場合、リンカーは出力ファイルを作成する際に、これらの値を計算する
セグメントに対して alignment 値が指定されていない場合、組み込みの初期値に設定される。初期値は CPU により異なり、ソフトウェアのバージョンによっても異なる場合がある
virtual_address と整列値の両方がセグメントに対して指定されている場合、virtual_address の方が優先される
virtual_address 値がセグメントに対して指定されている場合、プログラムヘッダーの整列フィールドには、初期値の整列値が設定される
rounding 値がセグメントに対して設定されている場合、そのセグメントの仮想アドレスは与えられた値に一致する次のアドレスに丸められる。この値は、指定の対象となるセグメントにしか効力はない。値が入力されないと、丸めは行われない
virtual_address 値が指定されている場合、セグメントはその仮想アドレスに置かれます。システムカーネルの場合、この方法で正しい結果が生成されます。exec(2) を介して開始するファイルの場合、この方法では、セグメントがページ境界に対応する正しいオフセットを保持しないため、不正な出力ファイルが作成されることになります。
?E フラグにより、空のセグメントが作れます。この空のセグメントには、関連付けられたセクションが存在しません。このセグメントは実行プログラムについてのみ指定でき、LOAD 型で、長さおよび整列が指定されていなければなりません。この種類のセグメントは複数定義することもできます。
?N フラグにより、ELF ヘッダー、および任意のプログラムヘッダーを最初の読み込み可能なセグメントの一部分として含めるかどうかを制御できます。特に指定しない場合、 ELF ヘッダーおよびプログラムヘッダーは、最初のセグメントに含まれます。これらのヘッダー内の情報は、対応付けられたイメージ内で (通常は実行時リンカーにより) 使用されます。?N オプションを使用すると、イメージの仮想アドレス計算が最初のセグメントの最初のセクションで開始されます。
?O フラグを使用すると、出力ファイル内のセクションの順序を制御できます。このフラグは、コンパイラの -xF オプションと合わせて使うようになっています。ファイルを -xF オプションを使ってコンパイルすると、そのファイル内の各関数が、.text セクションと同じ属性を持つ別個のセクションに置かれます。これらのセクションは、 .text%function_name という名前になります。
たとえば、main()、foo()、および bar() の 3 つの関数を持つファイルを -xF オプションを使ってコンパイルすると、再配置可能オブジェクトファイルが作成され、3 つの関数のテキストが .text%main、.text%foo、および .text%bar という名前のセクションに配置されます。-xF オプションは 1 つのセクションに 1 つの関数を割り当てるので、セクションの順番を制御するために ?O フラグを使うと、実際には関数の順番を制御することになります。
次のユーザー定義の mapfile を検討します。
text = LOAD ?RXO; text: .text%foo; text: .text%bar; text: .text%main;
最初の宣言により、?O フラグがデフォルトのテキストセグメントに関連付けられます。
ソースファイルの関数定義の順序が、main、foo、および bar の場合、最終的な実行プログラムには foo、bar、および main の順序で関数が含まれます。
同じ名前の静的関数を対象とする場合、ファイル名も指定する必要があります。?O フラグを指定すると、mapfile で指定されたとおりにセクションの順序付けが行われます。たとえば、静的関数 bar() がファイル a.o および b.o にあって、ファイル a.o の関数 bar() を、ファイル b.o の関数 bar() の前に置く場合、mapfile のエントリは次のようになります。
text: .text%bar: a.o; text: .text%bar: b.o;
次のエントリも構文上は可能です。
text: .text%bar: a.o b.o;
しかし、ファイル a.o の関数 bar() がファイル b.o の関数 bar() の前に置かれることは保証されません。2 番目の形式は、結果が予測できないため、お勧めしません。
対応付け指示は、入力セクションをどのように出力セグメントに対応付けするかをリンカーに伝えます。基本的には、対応付け先のセグメントの名前を指定し、名前を指定したセグメントに対応付けするためにセクションの属性をどうすべきかを指定します。特定のセグメントに対応付けするためにセクションが持っていなければならないセクション属性値 (section_attribute_values) のセットは、そのセグメントの「エントランス基準」と呼ばれます。出力ファイル内の指定されたセグメントにセクションを置くには、セクションがセグメントのエントランス基準に正確に合致している必要があります。
対応付け指示には以下のような構文があります。
segment_name : {section_attribute_value}* [: {file_name}+];
セグメント名 (segment_name) に対して、任意の数のセクション属性値 (section_attribute_values) を任意の順序で指定し、それぞれは空白文字で区切ります。セクション属性ごとに 1 つの値だけを指定できます。file_name 宣言を使用して、特定の .o ファイルに由来するセクションだけに限定することも可能です。セクション属性とその有効値は表 9–2 に示すとおりです。
表 9–2 セクション属性
セクション属性 |
値 |
---|---|
section_name |
任意の有効なセクション名 |
section_type |
$PROGBITS $SYMTAB $STRTAB $REL $RELA $NOTE $NOBITS |
section_flags |
? [[!]A] [[!]W] [[!]X] |
対応付け指示を入力する場合、以下の点に注意してください。
上に挙げた section_types から 1 つの値を選択する。上記の section_types は組み込まれている。section_types の詳細については、セクションを参照
section_flags 値は、A は割り当て可能 、W は書き込み可能、X は実行可能。個々のフラグの前に感嘆符 (!) がついている場合、リンカーは、フラグが設定されていないことを確認する。section_flags 値を構成する疑問符、感嘆符、および個々のフラグの間には空白文字を入れてはいけない
file_name には、ファイル名として正当な名前を *filename または archive_name(component_name) の形式で指定できる (例、 /usr/lib/libc.a(printf.o)) 。リンカーは、ファイル名の構文をチェックしない
file_name が *filename の形式になっている場合、リンカーはコマンド行で指定されたファイル名に対し basename(1) と同等の処理を行なって、指定された filename との一致を調べる。言い換えれば、mapfile で指定する filename は、コマンド行で指定されたファイル名の最後の部分だけが合致すればよい。詳細は 対応付けの例を参照
リンク編集の際に -l オプションを使っていて、-l オプションの後のライブラリが現在のディレクトリにある場合、mapfile 内のライブラリと一致させるために mapfile 内のライブラリの前に ./ (あるいはパス名全体) を付ける必要がある
特定の出力セグメントについて複数の指示行を指定できる。たとえば、次に示す一連の指示を行うことができる
S1 : $PROGBITS; S1 : $NOBITS;
1 つのセグメントに対して複数の対応付け命令行を指示することは、複数のセクション属性値を指定するための唯一の方法です。
1 つのセクションは複数のエントランス基準に合致することがある。その場合、mapfile で最初にエントランス基準が合致したセグメントが使われる。たとえば、mapfile が以下のようになっているとする
S1 : $PROGBITS; S2 : $PROGBITS;
この場合、$PROGBITS セクションは、セグメント S1 に対応付けられます。
以下のような表記を使うことにより、セグメント内にセクションを配置する順序を指定できます。
segment_name | section_name1; segment_name | section_name2; segment_name | section_name3;
上記の形式で指定されたセクションは、すべての名前なしセクションの前に、mapfile に列挙されている順序で配置されます。
サイズシンボル宣言を使って、指定したセグメントのサイズをバイトで示す大域絶対シンボルを定義できます。このシンボルは、オブジェクトファイル内で参照できます。サイズシンボルは次の構文で宣言します。
segment_name @ symbol_name;
symbol_name には、任意の正当な C 識別子を指定できます。リンカーは、symbol_name の構文をチェックしません。
ファイル制御指示により、共有オブジェクト内のどのバージョンの定義をリンク編集時に使用可能にするかを指定できます。ファイル制御構文で宣言します。
shared_object_name - version_name [ version_name ... ];
version_name (バージョン名) には、指定した shared_object_name (共有オブジェクト名) 内のバージョン定義名が入ります。