リンカーとライブラリ

mapfile の構造と構文

次の基本的な指令を mapfile に入力できます。

それぞれの指令は複数の行にまたがることができ、最後にセミコロンを付ければ、いくつでも空白 (改行を含む) を入れることができます。

通常、セグメント宣言の後に、対応付け指令を記述します。セグメントを宣言してから、セクションがそのセグメントの一部分になる条件を定義します。対応付け先のセグメントを最初に宣言せずに、対応付け指令あるいはサイズシンボル宣言を入力した場合、組み込みのセグメント以外のセグメントには、デフォルト属性が付与されます。この種のセグメントは、「暗示的に」宣言されたセグメントになります。

サイズシンボル宣言、およびファイル制御指令は、mapfile のどこにでも入れることができます。

以後の節では、それぞれの指令について説明します。すべての構文説明について、次の表記が適用されます。

セグメントの宣言

セグメントの宣言により、出力ファイルに新しいセグメントを作成したり、既存のセグメントの属性値を変更したりできます。既存のセグメントとは、以前に定義したもの、あるいは次に述べる 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 つの組み込みセグメントが存在し、次のデフォルト属性値を保持します。

デフォルトでは、bss セグメントは無効に設定されています。この唯一の入力部分である SHT_NOBITS タイプのセクションは、データセグメント内でキャプチャーされます。表 7–5 セクションの詳細は、Table 7–5 を参照してください。bss セグメントの作成を有効にするときは、もっとも単純な bss 宣言だけでかまいません。

        bss =;

すべての SHT_NOBITS セクションは、データセグメントではなく、このセグメントによりキャプチャーされるようになります。もっとも単純な場合、ほかのセグメントにも適用されるデフォルトを使用してこのセグメントの整列が行われます。宣言を実行してセグメントの追加属性を指定することにより、セグメント作成を有効にしたり、指定した属性を付与したりすることもできます。

リンカーは、mapfile を読み取る前に、これらのセグメントが宣言されたように動作します。「mapfile オプションのデフォルト」を参照してください。

セグメント宣言を入力する場合、次のことに注意してください。


注 –

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 フラグがデフォルトのテキストセグメントに関連付けられます。

ソースファイルの関数定義の順序が、mainfoo、および bar の場合、最終的な実行プログラムには foobar、および 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 セクション属性

セクション属性 

値 

section_name

任意の有効なセクション名 

section_type

$PROGBITS

$SYMTAB

$STRTAB

$REL

$RELA

$NOTE

$NOBITS

section_flags

? [[!]A] [[!]W] [[!]X]

対応付け指令を入力する場合、次の点に注意してください。

セグメント内セクションの順序

次のような表記を使うことにより、セグメント内にセクションを配置する順序を指定できます。

        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 (共有オブジェクト名) 内のバージョン定義名が入ります。