リンカーとライブラリ

mapfile の構造と構文

以下の 4 つの基本的な指示を mapfile に入力できます。

それぞれの指示は複数の行にまたがることができ、最後にセミコロンを付ければ、いくつでも空白 (改行を含む) を入れることができます。mapfile に指示をまったく入れないことも、複数入れることもできます (指示をまったく入れない場合、リンカーは mapfile を無視し、自らの初期値を使います)。

通常、セグメント宣言の後には、対応付け指示がきます。つまり、セグメントを宣言し、次にセクションがそのセグメントの一部分になる条件を定義するわけです。対応付け先のセグメントを最初に宣言しないで、対応付け指示あるいはサイズシンボル宣言を入力した場合、後で説明する組み込みのセグメント以外のセグメントには、以下で説明するように初期値の属性が与えられます。この場合このようなセグメントは「暗示的に宣言されたセグメント」 になります。

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

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

セグメントの宣言

セグメントの宣言により、a.out に新しいセグメントを作ったり、既存のセグメントの属性値を変更したりできます (既存のセグメントとは、以前に定義したもの、あるいは以下に述べる 3 つの組み込みセグメントの 1 つのことです)。

セグメントの宣言は以下の構文で行います。


segment_name = {segment_attribute_value}*;

segment_names について、任意の数の segment_attribute_values を任意の順序で指定でき、それぞれは空白文字で区切ります (セグメント属性ごとに、1 つの値だけ指定できます)。セグメント属性と、それらの有効な値は以下のとおりです。

表 8-1 mapfile セグメント属性

属性 

値 

segment_type

LOAD|NOTE

segment_flags

?[E][N][O][R][W][X]

virtual_address

Vnumber

physical_address

Pnumber

長さ

Lnumber

丸め

Rnumber

整列

Anumber

3 つの組み込みセグメントが存在し、以下のような初期値の属性値を持っています。

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

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

?E フラグにより、空のセグメントが作れます。これは、関連するセクションがないセグメントです。このセグメントは実行プログラムについてのみ指定でき、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;

ソースファイルの関数定義の順序が、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;

次の構文を使用することも可能ですが、ファイル a.o の関数 bar() が、ファイル b.o の関数 bar() の前に置かれることが保障されません。2 番目の形式は、結果が予測できないため、お勧めしません。


text: .text%bar: a.o b.o;

注 -

virtual_address が指定されている場合、セグメントはその仮想アドレスに置かれます。これは、システムカーネルに対して、正しい結果を出します。exec(2) を介して開始するファイルの場合、この方法では、セグメントにそのページ境界に対応する正しいオフセットがないため、間違った a.out ファイルが作成されることになります。


対応付け指示

対応付け指示は、入力セクションをどのように出力セグメントに対応付けするかをリンカーに伝えます。基本的には、対応付け先のセグメントの名前を指定し、名前を指定したセグメントに対応付けするためにセクションの属性をどうすべきかを指定します。特定のセグメントに対応付けするためにセクションが持っていなければならないセクション属性値 (section_attribute_values) は、そのセグメントの「入口条件」と呼ばれます。a.out の指定したセグメントにセクションを置くには、セクションはセグメントの入口条件に正確に合致していなければなりません。

対応付け指示には以下のような構文があります。


segment_name : {section_attribute_value}* [: {file_name}+];

セグメント名 (segment_name) に対して、任意の数のセクション属性値 (section_attribute_values) を任意の順序で指定し、それぞれは空白文字で区切ります (セクション属性ごとに 1 つの値だけ指定できます)。ファイル名 (file_name) を指定して、特定の .o ファイルからセクションを持ってこなければならないというように指定することもできます。セクション属性とその有効値は以下のとおりです。

表 8-2 セクション属性

セクション属性 

値 

section_name

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

section_type

$PROGBITS

$SYMTAB

$STRTAB

$REL

$RELA

$NOTE

$NOBITS

section_flags

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

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


S1 : $PROGBITS; 
S1 : $NOBITS; 

1 つのセグメントに対して複数の対応付け命令行を指示することは、複数のセクション属性値を指定するための唯一の方法です。


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 (共有オブジェクト名) 内のバージョン定義名が入ります。バージョン制御の詳細については、「バージョン結合の指定」を参照してください。