ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
Oracle Solaris 11.1 リンカーとライブラリガイド Oracle Solaris 11.1 Information Library (日本語) |
7. システムのパフォーマンスを最適化するオブジェクトの構築
パート IV ELF アプリケーションバイナリインタフェース
オブジェクトには、デフォルトで割り当て可能なセクションと割り当て不可のセクションの両方が含まれています。割り当て可能なセクションは、実行可能コードとそのコードが実行時に必要とするデータが含まれているセクションです。割り当て不可のセクションには、実行時にオブジェクトを実行するために必要でない補足的な情報が含まれています。これらのセクションは、デバッガおよびその他の可観測性ツールの動作をサポートします。オブジェクト内の割り当て不可のセクションは、実行時にオペレーティングシステムによってメモリーに読み込まれないため、どのようなサイズであっても、メモリーの使用やその他の実行時パフォーマンスの側面に影響を与えません。
利便性のため、割り当て可能なセクションと割り当て不可のセクションは、通常どちらも同じファイルに保持されます。しかし、これらのセクションを分離した方が有用な場合があります。
オブジェクトのサイズを減らして、広域ネットワーク経由でコピーする際の速度を向上させるため。
高度に最適化されたコードの詳細なデバッグをサポートするには、大量のデバッグデータを必要とするため。最近のシステムでは、記述されるコードよりもデバッグデータの方が簡単に大きくなります。32 ビットオブジェクトのサイズは、4G バイトまでに制限されています。非常に大きな 32 ビットオブジェクトでは、デバッグデータのためにこの制限を超え、オブジェクトを作成できなくなる可能性があります。
内部実装の詳細の露出を抑えるため。
従来は、これらの問題に対処するため、割り当て不可のセクションがオブジェクトから除去されていました。除去は有効ですが、あとで必要になる可能性があるデータも破棄されます。Solaris リンカーでは、代わりに割り当て不可のセクションを補助オブジェクトに書き込むことができます。この機能は、-z ancillary コマンド行オプションを使用すると有効になります。
$ ld ... -z ancillary[=outfile] ...
補助ファイルには、デフォルトでプライマリ出力オブジェクトと同じ名前と .anc ファイル拡張子が付けられます。ただし、-z ancillary オプションに outfile の値を指定することで、別の名前を付けることができます。
-z ancillary が指定されると、リンカーは次の処理を実行します。
すべての割り当て可能なセクションがプライマリオブジェクトに書き込まれます。さらに、SHF_SUNW_PRIMARY セクションヘッダーフラグが設定された1 つ以上の入力セクションを含むすべての割り当て不可のセクションも、プライマリオブジェクトに書き込まれます。
残りのすべての割り当て不可のセクションは、補助オブジェクトに書き込まれます。
次の割り当て不可のセクションは、プライマリオブジェクトと補助オブジェクトの両方に書き込まれます。
セクション名文字列テーブル。
完全な非動的シンボルテーブル。
.symtab に関連付けられたシンボルテーブルの拡張インデックスセクション。
.symtab に関連付けられた非動的文字列テーブル。
プライマリオブジェクトと補助オブジェクトの識別や検査しているオブジェクトの識別に必要な情報が格納されます。
プライマリオブジェクトとすべての補助オブジェクトには、同じセクションヘッダーの配列が含まれています。各セクションは、すべてのファイルで同じセクションインデックスを持っています。
プライマリオブジェクトと補助オブジェクトはいずれも同じセクションヘッダーを定義しますが、ほとんどのセクションのデータは前述のように 1 つのファイルに書き込まれます。セクションのデータが特定のファイルに存在しない場合は、SHF_SUNW_ABSENT セクションヘッダーフラグが設定され、sh_size フィールドが 0 になります。
この構成により、プライマリオブジェクトと補助オブジェクトのどちらからでも、セクションヘッダーの完全なリスト、完全なシンボルテーブル、およびプライマリオブジェクトと補助オブジェクトの完全なリストを取得できるようになっています。
次の例は、補助オブジェクトのベースとなる実装を示しています。補助オブジェクトは、ほかの点では標準的なコンパイルに -z ancillary コマンド行オプションを追加することで作成されます。file ユーティリティーは、結果として a.out という名前の実行可能ファイルと、a.out.anc という名前の関連する補助オブジェクトが生成されたことを示しています。
$ cat hello.c #include <stdio.h> int main(int argc, char **argv) { (void) printf("hello, world\n"); return (0); } $ cc -g -zancillary hello.c $ file a.out a.out.anc a.out: ELF 32-bit LSB executable 80386 Version 1 [FPU], dynamically linked, not stripped, ancillary object a.out a.out.anc: ELF 32-bit LSB ancillary 80386 Version 1, primary object a.out $ ./a.out hello world
生成されたプライマリオブジェクトは、通常の方法で実行できる普通の実行可能ファイルです。補助オブジェクトを使用せずに作成し、その後 strip または mcs コマンドを使用して割り当て不可の内容を取り除いた実行可能ファイルと比べて、実行時の違いはありません。
前述のように、プライマリオブジェクトと補助オブジェクトには同じセクションヘッダーが含まれています。このしくみを理解するには、elfdump ユーティリティーを使用してこれらのセクションヘッダーを表示して比較すると有益です。次の表に、前のリンク編集の例からヘッダーを選択するためのセクションヘッダーの情報を示します。
|
ほとんどのセクションのデータは、2 つのファイルのどちらかに存在し、もう一方のファイルには存在しません。SHF_SUNW_ABSENT セクションヘッダーフラグは、データが存在しないときに設定されます。実行時に必要な割り当て可能なセクションのデータは、プライマリオブジェクトに含まれています。デバッグに使用され、実行時には必要でない割り当て不可のセクションのデータは、補助ファイルに配置されます。割り当て不可のセクションの小さなセットが、両方のファイルにすべて存在します。これらは、プライマリオブジェクトと補助オブジェクトを関連付けるために使用される .SUNW_ancillary セクション、セクション名文字列テーブル .shstrtab、シンボルテーブル .symtab、およびその関連文字列テーブル .strtab です。
プライマリオブジェクトからシンボルテーブルを取り除くことができます。シンボルテーブルがないオブジェクトを検出したデバッガは、.SUNW_ancillary セクションを使用して補助オブジェクトを特定し、内部に含まれるシンボルにアクセスできます。
プライマリオブジェクトと関連するすべての補助オブジェクトには、すべてのオブジェクトを識別して関連付けることができる .SUNW_ancillary セクションが含まれています。
$ elfdump -T SUNW_ancillary a.out a.out.anc a.out: Ancillary Section: .SUNW_ancillary index tag value [0] ANC_SUNW_CHECKSUM 0x8724 [1] ANC_SUNW_MEMBER 0x1 a.out [2] ANC_SUNW_CHECKSUM 0x8724 [3] ANC_SUNW_MEMBER 0x1a3 a.out.anc [4] ANC_SUNW_CHECKSUM 0xfbe2 [5] ANC_SUNW_NULL 0 a.out.anc: Ancillary Section: .SUNW_ancillary index tag value [0] ANC_SUNW_CHECKSUM 0xfbe2 [1] ANC_SUNW_MEMBER 0x1 a.out [2] ANC_SUNW_CHECKSUM 0x8724 [3] ANC_SUNW_MEMBER 0x1a3 a.out.anc [4] ANC_SUNW_CHECKSUM 0xfbe2 [5] ANC_SUNW_NULL 0
両方のオブジェクトの補助セクションは、同じ数の要素を含み、最初の要素を除いて同一です。プライマリオブジェクトから先に、ファイル名を指定する MEMBER 要素と、それに続いてオブジェクトを識別する CHECKSUM によって、各オブジェクトが導入されます。この例では、プライマリオブジェクトは a.out であり、そのチェックサムは 0x8724 です。補助オブジェクトは a.out.anc であり、そのチェックサムは 0xfbe2 です。.SUNW_ancillary セクションの (プライマリオブジェクトの MEMBER 要素の前にある) 最初の要素は、常に検査しているファイルのチェックサムを含む CHECKSUM 要素です。
オブジェクトに .SUNW_ancillary セクションが存在することは、オブジェクトに関連する補助オブジェクトがあることを示しています。
プライマリオブジェクトと関連するすべての補助オブジェクトの名前は、いずれかのファイルの補助セクションから取得できます。
最初のチェックサムの値を後続する各メンバーのチェックサムと比較することにより、大規模なファイルのセットからどのファイルを検査しているかを特定できます。
デバッガおよびその他の可観測性ツールは、オブジェクトの完全なビューを作成するために、プライマリオブジェクトファイルと補助オブジェクトファイルで見つかった情報をマージする必要があります。これは、1 つのファイルの情報を処理するのとまったく同じです。このマージは、同じセクションヘッダーを含むプライマリオブジェクトと補助オブジェクト、および単一のシンボルテーブルによって簡略化されます。
デバッガでこれらのファイルに含まれる情報をまとめるには、次の手順を使用します。
プライマリオブジェクトまたはいずれかの補助オブジェクトから先に、.SUNW_ancillary セクションを見つけます。このセクションが存在することで、そのオブジェクトが補助グループの一部として特定されます。このセクションには、ファイルの完全なリストを取得し、それらのどれが現在検査しているファイルかを特定するために使用できる情報が含まれています。
検査しているオブジェクトのセクションヘッダー配列を最初のテンプレートとして使用して、メモリー内にセクションヘッダー配列を作成します。
.SUNW_ancillary セクションで識別された各ファイルを順に開き、読み取ります。ファイルごとに、SHF_SUNW_ABSENT フラグが設定されていない各セクションの情報をメモリー内のセクションヘッダー配列に埋め込みます。
この結果、すべてのセクションのデータへのポインタを含むセクションヘッダーの完全なメモリー内コピーができます。この情報を取得したあと、デバッガは単一ファイルの場合と同じように処理を続行し、実行中のプログラムにアクセスしてそれを制御できます。
注 - 補助オブジェクトの ELF 定義では、1 つのプライマリオブジェクトと任意の数の補助オブジェクトが提供されます。現時点では、Oracle Solaris リンカーはすべての割り当て不可のセクションを含む単一の補助オブジェクトのみを生成します。これは将来変更される可能性があります。デバッガおよびその他の可観測性ツールは、補助オブジェクトが複数存在する一般的なケースに対応できるように作成されるべきです。