Oracle® Solaris 11.2 リンカーとライブラリガイド

印刷ビューの終了

更新: 2014 年 7 月
 
 

LOAD_SEGMENT/NOTE_SEGMENT/NULL_SEGMENT 指令

セグメントは出力オブジェクトの連続する部分で、セクションを含みます。mapfile セグメント指令では、3 つの異なるセグメントタイプの指定が可能です。

  • LOAD_SEGMENT

    読み込み可能セグメントは、実行時にプロセスのアドレス空間にマップされるコードまたはデータを含みます。リンカーは割り当て可能な各セグメントに対して PT_LOAD プログラムヘッダーエントリを作成し、実行時リンカーはこれらを使用してセグメントを見つけ、マップします。

  • NOTE_SEGMENT

    注釈セグメントには注釈セクションが含まれています。リンカーは、セグメントを参照する PT_NOTE プログラムヘッダーエントリを作成します。注釈セグメントは割り当てできません。

  • NULL_SEGMENT

    ヌルセグメントは出力オブジェクトに含まれるセクションを保持しますが、そのセクションは実行時にオブジェクトで使用できません。そのようなセクションの一般的な例として、.symtab シンボルテーブルや、デバッガのために生成されるさまざまなセクションがあります。ヌルセグメントのプログラムヘッダーは作成されません。

セグメント指令は、出力ファイルに新しいセグメントを作成したり、既存のセグメントの属性値を変更したりするために使用されます。既存のセグメントとは、以前に定義したものか、定義済みセグメントで説明されている組み込みセグメントのいずれかです。新しいセグメントはそれぞれオブジェクトに追加され、同じタイプの最後のセグメントの後に置かれます。読み込み可能なセグメントが最初に追加され、その次が注釈セグメントで、最後がヌルセグメントです。これらのセグメントに関連付けられたプログラムヘッダーは、セグメントと同じ相対順序でプログラムヘッダー配列に配置されます。デフォルトの配置は、読み込み可能なセグメントの場合は明示的にアドレスを設定するか、または SEGMENT_ORDER 指令を使用すると変更できます。

segment_name が事前に存在するセグメントの場合、指定された属性によって既存のセグメントが変更されます。それ以外の場合、新しいセグメントが作成され、指定された属性が新しいセグメントに適用されます。リンカーは、明示的に指定されていない属性にデフォルト値を設定します。


注 - セグメント名を選択するとき、リンカーの将来のバージョンで、新しい定義済みセグメントが追加される可能性があることに留意してください。ユーザーのセグメント指令に使用する名前がこの新しい名前と一致した場合、新しい定義済みセグメントによって、ユーザーの mapfile は、新規セグメントの作成から既存のセグメントの変更へと意味が変わります。この状況を回避するためのもっとも良い方法は、セグメントに一般的な名前を使用することを避け、すべてのセグメント名に対して企業識別子、プロジェクト識別子、プログラムの名前などの固有の接頭辞を追加することです。たとえば、hello_world という名前のプログラムの場合、hello_world_data_segment というセグメント名を使用できます。

3 つすべてのセグメント指令は、中核となる一連の共通属性を共有します。セグメント宣言は次のようになり、directiveLOAD_SEGMENTNOTE_SEGMENTNULL_SEGMENT のいずれかで置き換えます。

        directive segment_name {
                ASSIGN_SECTION [assign_name];
                ASSIGN_SECTION [assign_name] {
                        FILE_BASENAME = file_basename;
                        FILE_OBJNAME = objname;
                        FILE_PATH = file_path;
                        FLAGS = section_flags;
                        IS_NAME = section_name;
                        TYPE = section_type;
                };
 
                DISABLE;

                IS_ORDER  = assign_name....;
                IS_ORDER += assign_name....;

                OS_ORDER  = section_name....;
                OS_ORDER += section_name....;
        };

LOAD_SEGMENT 指令は、読み込み可能セグメントに固有の一連の追加属性を受け入れます。これらの追加属性の構文は次のとおりです。

        LOAD_SEGMENT segment_name {
               ALIGN = value;

               FLAGS  = segment_flags;
               FLAGS += segment_flags;
               FLAGS -= segment_flags;

               MAX_SIZE = value;

               NOHDR;

               PADDR = value;
               ROUND = value;

               SIZE_SYMBOL  = symbol_name....;
               SIZE_SYMBOL += symbol_name....;

               VADDR = value;
        };

どのセグメント指令も空の指令として指定できます。空のセグメント指令によって新しいセグメントが作成されると、すべてのセグメント属性にデフォルト値が設定されます。空のセグメントは次のように宣言されます。

        LOAD_SEGMENT segment_name;

        NOTE_SEGMENT segment_name;

        NULL_SEGMENT segment_name;

1 つ以上のセグメント指令によって受け入れられるすべての属性について、次に説明します。

ALIGN 属性 (LOAD_SEGMENT のみ)

ALIGN 属性は、読み込み可能セグメントの配置を指定するために使用されます。指定された値は、セグメントに対応するプログラムヘッダーの p_align フィールドに設定されます。セグメント配置は、セグメントの最初の仮想アドレスを計算する際に使用されます。

指定される配置は 0 であるか、2 のべき乗である必要があります。デフォルトでは、リンカーによって、セグメントの配置は組み込みのデフォルトに設定されます。デフォルトは CPU により異なり、ソフトウェアのリビジョンによっても異なる場合があります。

ALIGN 属性は、PADDR 属性と VADDR 属性に関連しており、これらと互換性がある必要があります。

ASSIGN_SECTION 属性

ASSIGN_SECTION は、指定されたセグメントへの割り当て用にセクションを集合的に修飾する、セクション名、タイプ、およびフラグなどのセクション属性の組み合わせです。このような属性のセットは、エントランス基準と呼ばれます。セクションが一致するのは、セクション属性がこれらのエントランス基準と正確に一致するときです。ASSIGN_SECTION は、属性を何も指定しない場合、基準が比較される任意のセクションと一致します。

指定されたセグメントに対して複数の ASSIGN_SECTION 属性を指定できます。ASSIGN_SECTION 属性は、それぞれ互いに独立しています。セクションがセグメントに割り当てられるのは、そのセグメントに関連付けられているいずれかの ASSIGN_SECTION 定義とセクションが一致する場合です。セグメントに 1 つ以上の ASSIGN_SECTION 属性が存在しない場合、リンカーはセクションをセグメントに割り当てません。

リンカーはセクションをセグメントに割り当てるために、エントランス基準の内部リストを使用します。mapfile 内で見つかった ASSIGN_SECTION 宣言は、見つかった順序でこのリストに配置されます。定義済みセグメントで説明した組み込みセグメントのエントランス基準は、このリスト内で最後の mapfile 定義済みエントリの直後に配置されます。

エントランス基準には、オプションの名前 (assign_name) を指定できます。この名前は IS_ORDER 属性と一緒に使用すると、入力セクションが出力セクションに配置される順序を指定できます。

入力セクションを配置するには、リンカーはエントランス基準リストの先頭から開始し、セクションの属性を各エントランス基準と順番に比較します。セクションは、セクション属性に正確に一致した最初のエントランス基準に関連付けられているセグメントに割り当てられます。一致がない場合、一般的なすべての割り当て不可のセクションの場合と同じように、セクションはファイルの末尾に配置されます。

ASSIGN_SECTION は次を受け入れます。

FILE_BASENAMEFILE_OBJNAMEFILE_PATH

これらの属性を使用すると、属性を取得したファイルのパス (FILE_PATH)、ベース名 (FILE_BASENAME)、またはオブジェクト名 (FILE_OBJNAME) に基づいてセクションを選択できます。

ファイルパスは、UNIX 標準のスラッシュ区切りの表記規則を使用して指定されます。最後のパスセグメントはパスのベース名で、単純にファイル名 としても知られています。アーカイブの場合、ベース名はアーカイブメンバーの名前を使用して拡張でき、archive_name(component_name) という形式を使用します。たとえば、/lib/libfoo.a(bar.o)/lib/libfoo.a という名前のアーカイブにあるオブジェクト bar.o を指定します。

FILE_BASENAMEFILE_OBJNAME はアーカイブ以外に適用された場合は同等で、指定された名前をファイルのベース名と比較します。アーカイブに適用される場合、FILE_BASENAME はアーカイブ名のベース名を調べます。一方、FILE_OBJNAME はアーカイブ内に格納されているオブジェクトの名前を調べます。

それぞれの ASSIGN_SECTION は、FILE_BASENAME FILE_PATH、および FILE_OBJNAME のすべての値のリストを保持します。これらの定義のいずれかが入力ファイルと一致すると、ファイルが一致したことになります。

IS_NAME

入力セクションの名前。

TYPE

ELF の section_type を指定します。<sys/elf.h> 内で定義されている任意の SHT_ 定数を指定できます。SHT_ 接頭辞は削除します。(PROGBITSSYMTABNOBITS など)。

FLAGS

FLAGS 属性には、section_flags を使用してTable 8–7 に示す値の空白区切りのリストとしてセクション属性を指定します。これらの値は <sys/elf.h> 内に定義されている SHF_ 値に対応します。個々のフラグの前に感嘆符 (!) が付いている場合は、その属性が存在してはいけないことを明示しています。次の例では、セクションは割り当て可能だが書き込み不可と定義されています。

        ALLOC !WRITE

section_flags リストに明示されていないフラグは無視されます。上記の例では、指定されたフラグに対してセクションを照合するときに、ALLOC および WRITE の値のみが検査されます。ほかのセクションフラグは任意の値を持つことができます。

表 8-7  セクションフラグの値
フラグの値
意味
ALLOC
セクションは割り当て可能です
WRITE
セクションは書き込み可能です
EXECUTE
セクションは実行可能です
AMD64_LARGE
セクションは 2G バイトより大きくすることができます

DISABLE 属性

DISABLE 属性を使用すると、リンカーはセグメントを無視します。無効にされたセグメントには、セクションが割り当てられません。セグメントは後続のセグメント指令によって参照されると、自動的にふたたび有効化されます。したがって、空の参照のみで、無効にされたセクションをふたたび有効にできます。

segment segment_name;

FLAGS 属性 (LOAD_SEGMENT のみ)

FLAGS 属性は、Table 8–3 のアクセス権の空白区切りのリストとして、セグメントのアクセス権を指定します。デフォルトでは、ユーザー定義のセグメントは READWRITE、および EXECUTE アクセス権を受け入れます。定義済みセグメントで説明されている定義済みセグメント用のデフォルトフラグがリンカーによって指定され、場合によってはプラットフォーム依存になります。

3 つの形式を使用できます。

        FLAGS  = segment_flags....;
        FLAGS += segment_flags....;
        FLAGS -= segment_flags....;

シンプルな「=」代入演算子は現在のフラグを新しいセットで置き換え、「+=」形式は既存のセットに新規フラグを追加し、「-=」形式は指定されたフラグを既存のセットから削除します。

IS_ORDER 属性

リンカーは通常、見つかった順序で出力セクションをセグメントに配置します。同様に、出力セクションを構成する入力セクションも、見つかった順序で配置されます。IS_ORDER 属性は、入力セクションのこのデフォルトの配置を変更するために使用できます。IS_ORDER は、エントランス基準名 (assign_name) の空白区切りのリストを指定します。これらのいずれかのエントランス基準に一致したセクションは、出力セクションの先頭に配置され、IS_ORDER で指定された順序で並べ替えられます。IS_ORDER リストに見つからないエントランス基準に一致したセクションは、並べ替えられたセクションの後方に、見つかった順序で配置されます。

=」形式の代入を使用すると、指定されたセグメントの IS_ORDER の以前の値は破棄され、新しいリストで置き換わります。「+=」形式の IS_ORDER の場合、既存のリストの末尾に新しいリストを連結します。

IS_ORDER 属性が特に注目されるのは、コンパイラの –xF オプションと合わせて使用する場合です。ファイルを –xF オプションを使ってコンパイルすると、そのファイル内の各関数が、.text セクションと同じ属性を持つ別個のセクションに置かれます。これらのセクションは、.text%function_name (function_name は関数名) という名前です。

たとえば、main()foo()、および bar() の 3 つの関数を持つファイルを –xF オプションを使ってコンパイルすると、再配置可能オブジェクトファイルが作成され、3 つの関数のテキストが .text%main.text%foo、および .text%bar という名前のセクションに配置されます。リンカーがこれらのセクションを出力に配置するとき、% と、% の後続のすべてが削除されます。したがって、これら 3 つの関数はすべて、.text 出力セクションに配置されます。IS_ORDER 属性は、.text 出力セクション内で特定の相対的な順序で配置することを強制するために使用できます。

次のユーザー定義の mapfile を検討します。

        $mapfile_version 2
        LOAD_SEGMENT text {
                ASSIGN_SECTION text_bar  { IS_NAME = .text%bar };
                ASSIGN_SECTION text_main { IS_NAME = .text%main };
                ASSIGN_SECTION text_foo  { IS_NAME = .text%foo };
                IS_ORDER = text_foo text_bar text_main;
        };

これら 3 つの関数がソースコード内で検出された順序や、リンカーによって見つけられた順序に関係なく、出力オブジェクトの text セグメント内での順序は foo()bar()main() となります。

MAX_SIZE 属性 (LOAD_SEGMENT のみ)

リンカーはデフォルトで、セグメントの内容が必要とするサイズにまで、セグメントが大きくなることを許可します。セグメントの最大サイズを指定するために、MAX_SIZE 属性を使用できます。MAX_SIZE が設定されると、セグメントが指定されたサイズを超えて大きくなった場合にリンカーはエラーを生成します。

NOHDR 属性 (LOAD_SEGMENT のみ)

NOHDR 属性が設定されたセグメントが、出力オブジェクトの最初の読み込み可能セグメントになった場合、ELF およびプログラムヘッダーはセグメントに含まれません。

NOHDR 属性が最上位の HDR_NOALLOC 指令と異なる点は、HDR_NOALLOC はセグメントごとの値であり、セグメントが最初の読み込み可能セグメントになった場合にのみ有効だということです。この機能は主に、古い mapfile との互換性を確保するために存在します。詳細は、Appendix B, System V Release 4 (バージョン 1) Mapfileを参照してください。

セグメントの NOHDR 属性よりも HDR_NOALLOC 指令を優先させることをお勧めします。

OS_ORDER 属性

リンカーは通常、見つかった順序で出力セクションをセグメントに配置します。OS_ORDER 属性は、出力セクションのこのデフォルトの配置を変更するために使用できます。OS_ORDER は、出力セクション名 ( section_name) の空白区切りのリストを指定します。リストされたセクションは、セグメントの先頭に配置され、OS_ORDER で指定された順序で並べ替えられます。OS_ORDER にリストされていないセクションは、並べ替えられたセクションの後方に、見つかった順序で配置されます。

=」形式の代入を使用すると、指定されたセグメントの OS_ORDER の以前の値は破棄され、新しいリストで置き換わります。「+=」形式の OS_ORDER の場合、既存のリストの末尾に新しいリストを連結します。

PADDR 属性 (LOAD_SEGMENT のみ)

PADDR 属性は、セグメントの物理アドレスを明示するために使用されます。指定する値は 0 であるか、2 のべき乗である必要があります。指定された値は、セグメントに対応するプログラムヘッダーの p_addr フィールドに設定されます。デフォルトでは、リンカーはセグメントの物理アドレスを 0 に設定します。この理由は、このフィールドはユーザーモードオブジェクトについては意味がなく、主にオペレーティングシステムのカーネルなど「ユーザーランド以外」のオブジェクトに関係があるためです。

ROUND 属性 (LOAD_SEGMENT のみ)

ROUND 属性は、セグメントのサイズを指定された値に丸める必要があることを指定するために使用されます。丸める値の指定は 0 であるか、2 のべき乗である必要があります。デフォルトでは、リンカーはセグメントの丸め係数を 1 に設定し、これはセグメントサイズが丸められないことを意味します。

SIZE_SYMBOL 属性 (LOAD_SEGMENT のみ)

SIZE_SYMBOL 属性は、リンカーによって作成される、セクションのサイズシンボル名の空白区切りのリストを定義します。サイズシンボルは、セグメントのサイズをバイト数で示す大域絶対シンボルです。これらのシンボルは、オブジェクトファイル内で参照できます。コード内でシンボルにアクセスするには、symbol_name が言語内で正当な識別子であることを確認する必要があります。シンボルをほかの言語からアクセスできる可能性が高くするため、C プログラミング言語のシンボル命名規則が推奨されます。

=」形式の代入は初期値を設定するために使用でき、リンカーのセッションにつき 1 回のみ使用できます。「+=」形式の SIZE_SYMBOL の場合、既存のリストの末尾に新しいリストを連結し、必要な回数だけ使用できます。

VADDR (LOAD_SEGMENT のみ)

VADDR 属性は、セグメントの仮想アドレスを明示するために使用されます。指定された値は、セグメントに対応するプログラムヘッダーの p_vaddr フィールドに設定されます。デフォルトでは、リンカーは出力ファイルが作成されるとき、仮想アドレスをセグメントに割り当てます。