セグメントの宣言により、出力ファイルに新しいセグメントを作成したり、既存のセグメントの属性値を変更したりできます。既存のセグメントとは、以前に定義したもの、あるいは次に述べる 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 |
V number |
physical_address |
Pnumber |
length |
Lnumber |
rounding |
Rnumber |
alignment |
Anumber |
4 つの組み込みセグメントが存在し、次のデフォルト属性値を保持します。
text – LOAD、?RX、virtual_address と physical_address と length は指定なし。alignment 値は CPU タイプごとにデフォルトに設定。
data – LOAD、?RWX、virtual_address と physical_address と length は指定なし。alignment 値は CPU タイプごとにデフォルトに設定。
bss – 無効、LOAD、?RWX、virtual_address と physical_address と length は指定なし。alignment 値は CPU タイプごとにデフォルトに設定。
note – NOTE.
デフォルトでは、bss セグメントは無効に設定されています。この唯一の入力部分である SHT_NOBITS タイプのセクションは、データセグメント内でキャプチャーされます。表 7–5 セクションの詳細は、Table 7–5 を参照してください。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 セグメントにできます 。空の LOAD セグメントは、実行可能ファイルに対してのみ指定できます。これらのセグメントは、指定されたサイズと整列を保持する必要があります。これらのセグメントにより、プロセスの起動時にメモリー予約が作成されます。LOAD セグメントは複数定義できます。
?N フラグにより、ELF ヘッダー、および任意のプログラムヘッダーを最初の読み込み可能なセグメントの一部分として含めるかどうかを制御できます。デフォルトでは、 ELF ヘッダーおよびプログラムヘッダーは、最初のセグメントに含まれます。これらのヘッダー内の情報は、対応付けられたイメージ内で (通常は実行時リンカーにより) 使用されます。?N オプションを使用すると、イメージの仮想アドレス計算が最初のセグメントの最初のセクションで開始されます。
?O フラグを使用すると、出力ファイル内のセクションの順序を制御できます。このフラグは、コンパイラの -xF オプションと合わせて使うようになっています。ファイルを -xF オプションを使ってコンパイルすると、そのファイル内の各関数が、.text セクションと同じ属性を持つ別個のセクションに置かれます。これらのセクションは、.text%function_name (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 番目の形式は、結果が予測できないため、お勧めしません。