実行可能オブジェクトファイルまたは共有オブジェクトファイルのプログラムヘッダーテーブルは、構造体の配列です (各構造体は、実行されるプログラムを作成するためにシステムが必要とするセグメントやその他の情報を記述します) 。各オブジェクトファイルセグメントには、「セグメントの内容」に記述されているとおり、1 つまたは複数のセクションが存在します。
プログラムヘッダーは、実行可能オブジェクトファイルと共有オブジェクトファイルに対してのみ意味があります。プログラムヘッダーサイズは、ELF ヘッダーの e_phentsize 構成要素と e_phnum 構成要素で指定されます。
プログラムヘッダーの構造体 (sys/elf.h で定義) は、次のとおりです。
typedef struct { Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_Word p_flags; Elf32_Word p_align; } Elf32_Phdr; typedef struct { Elf64_Word p_type; Elf64_Word p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Addr p_paddr; Elf64_Xword p_filesz; Elf64_Xword p_memsz; Elf64_Xword p_align; } Elf64_Phdr;
この構造体の要素を次に示します。
この配列要素が記述するセグメント型、または配列要素情報の解釈方法。型の値とその意味は、表 7-35 を参照してください。
ファイルの先頭から、セグメントの先頭バイトが存在する位置までのオフセット。
セグメントの物理アドレス (物理アドレス指定が適切なシステムの場合)。本システムはアプリケーションプログラムに対して物理アドレス指定を無視するので、この構成要素には実行可能ファイルと共有オブジェクトに対する指定されていない内容が存在します。
セグメントのファイルイメージのバイト数 (0 の場合もある)。
セグメントのメモリーイメージのバイト数 (0 の場合もある)。
セグメントに関係するフラグ。型の値とその意味については、表 7-36 を参照してください。
読み込み可能なプロセスセグメントは、ページサイズを基にして、p_vaddr と p_offset に対して同じ値を保持する必要があります。この構成要素は、セグメントがメモリーとファイルにおいて整列される値を与えます。値 0 と 1 は、整列が必要ないことを意味します。その他の値の場合、p_align は 2 の正整数累乗でなければならず、また p_vaddr は p_align を法として p_offset に等しくなければなりません。詳細は、「プログラムの読み込み (プロセッサ固有)」を参照してください。
エントリの中には、プロセスセグメントを記述するものもあります。それ以外のエントリは補足情報を与え、プロセスイメージには関与しません。セグメントエントリが現れる順序は、明示されている場合を除き任意です。定義されている型の値を、次の表に示します。
表 7-35 ELF セグメント型
名前 |
値 |
---|---|
PT_NULL |
0 |
PT_LOAD |
1 |
PT_DYNAMIC |
2 |
PT_INTERP |
3 |
PT_NOTE |
4 |
PT_SHLIB |
5 |
PT_PHDR |
6 |
PT_LOSUNW |
0x6ffffffa |
PT_SUNWBSS |
0x6ffffffb |
PT_SUNWSTACK |
0x6ffffffa |
PT_HISUNW |
0x6fffffff |
PT_LOPROC |
0x70000000 |
PT_HIPROC |
0x7fffffff |
使用しません。他の構成要素の値は不定です。この型を使用すると、プログラムヘッダーテーブルに、無視されるエントリを入れることができます。
p_filesz と p_memsz により記述される読み込み可能セグメントを指定しますファイルのバイト列は、メモリーセグメントの先頭に対応付けされます。セグメントのメモリーサイズ (p_memsz) がファイルサイズ (p_filesz) より大きい場合、不足するバイトは、値 0 を保持しセグメントの初期化領域に続くように定義されます。ファイルサイズがメモリーサイズより大きくなることは許可されません。プログラムヘッダーテーブルの読み込み可能セグメントエントリは、p_vaddr 構成要素で整列され、昇順に現れます。
動的リンクに関する情報を指定します。詳細は、「動的セクション」を参照してください。
インタプリタとして呼び出される、ヌル文字で終了しているパス名の位置とサイズを指定します。動的実行可能ファイルの場合、このセグメント型は必須であり、共有オブジェクトの場合、このセグメント型は指定可能です。このセグメント型を、ファイル内に複数指定することはできません。このセグメント型が存在する場合、このセグメント型は読み込み可能セグメントエントリの前に存在しなければなりません。詳細は、「プログラムインタプリタ」を参照してください。
補助情報の位置とサイズを指定します。詳細は、「注釈セクション」を参照してください。
このセグメント型は、予約済みですが、解釈の方法は定義されていません。
プログラムヘッダーテーブル自身の、ファイル、およびプログラムのメモリーイメージにおける位置とサイズを指定します。このセグメント型を、ファイル内に複数指定することはできません。また、このセグメント型は、プログラムヘッダーテーブルがプログラムのメモリーイメージの一部になる場合に限り存在できます。このセグメント型が存在する場合、このセグメント型は読み込み可能セグメントエントリの前に存在しなければなりません。詳細は、「プログラムインタプリタ」を参照してください。
PT_LOAD 要素と同じ属性で、.SUNW_bss セクションの記述に使用します。
プロセススタックを記述します。現在のところ、そういった要素は 1 つのみ存在し、p_flags フィールドで定義されているアクセスパーミッションのみが有用です。
他の箇所で特に要求されない限り、すべてのプログラムヘッダーセグメントタイプはそれぞれ存在することもありますし、存在しないこともあります。ファイルのプログラムヘッダーテーブルには、このプログラムの内容に関係する要素のみが存在できます。
実行可能オブジェクトファイルと共有オブジェクトファイルには、ベースアドレス (プログラムのオブジェクトファイルのメモリーイメージに関連付けられている最下位仮想アドレス) が存在します。ベースアドレスは、たとえば動的リンク時にプログラムのメモリーイメージを再配置するために使用されます。
実行可能オブジェクトファイルと共有オブジェクトファイルのベースアドレスは、実行時に 3 つの値 (プログラムの読み込み可能セグメントのメモリー読み込みアドレス、最大ページサイズ、最下位仮想アドレス) から計算されます。プログラムヘッダーの仮想アドレスは、プログラムのメモリーイメージの実際の仮想アドレスを表さないことがあります。詳細は、「プログラムの読み込み (プロセッサ固有)」を参照してください。
ベースアドレスを計算するには、PT_LOAD セグメントの最下位 p_vaddr 値に関連付けられているメモリーアドレスを判定します。次に、メモリーアドレスを最大ページサイズの最近倍数に切り捨てることで、ベースアドレスが求められます。メモリーに読み込まれるファイルの種類によって、メモリーアドレスは p_vaddr 値に一致しない場合もあります
システムで読み込まれるプログラムには、少なくとも 1 つの読み込み可能セグメントが存在しなければなりません (ただし、このことはファイル形式では要求されていません)。システムは、読み込み可能セグメントのメモリーイメージを作成するとき、p_flags 構成要素で指定されるアクセス権を与えます。PF_MASKPROC マスクのすべてのビットは、プロセッサ固有のセマンティクスに対して予約されます。
表 7-36 ELF セグメントフラグ
名前 |
値 |
意味 |
---|---|---|
PF_X |
0x1 |
実行 |
PF_W |
0x2 |
書き込み |
PF_R |
0x4 |
読み取り |
PF_MASKPROC |
0xf0000000 |
指定なし |
アクセス権ビットが 0 の場合、その種類のアクセスは拒否されます。実際のメモリーアクセス権は、メモリー管理ユニット (システムによって異なることがある) に依存します。すべてのフラグ組み合わせが有効ですが、システムは要求以上のアクセスを与えることがあります。ただしどんな場合も、特に断りが明示的に記述されていない限り、セグメントは書き込み権を持ちません。次の表に、正確なフラグ解釈と許容されるフラグ解釈を示します。
表 7-37 ELF セグメントへのアクセス権
フラグ |
値 |
正確なフラグ解釈 |
許容されるフラグ解釈 |
---|---|---|---|
None |
0 |
すべてのアクセスが拒否される |
すべてのアクセスが拒否される |
PF_X |
1 |
実行のみ |
読み取り、実行 |
PF_W |
2 |
書き込みのみ |
読み取り、書き込み、実行 |
PF_W+PF_X |
3 |
書き込み、実行 |
読み取り、書き込み、実行 |
PF_R |
4 |
読み取りのみ |
読み取り、実行 |
PF_R + PF_X |
5 |
読み取り、実行 |
読み取り、実行 |
PF_R+PF_W |
6 |
読み取り、書き込み |
読み取り、書き込み、実行 |
PF_R+PF_W+PF_X |
7 |
読み取り、書き込み、実行 |
読み取り、書き込み、実行 |
たとえば、標準的なテキストセグメントは読み取り権と実行権を持っていますが、書き込み権は持っていません。データセグメントは通常、読み取り権、書き込み権、および実行権を持っています。
オブジェクトファイルセグメントは、1 つまたは複数のセクションで構成されます。ただし、プログラムヘッダーはこの事実には関与しません。ファイルセグメントに 1 つのセクションが存在するか複数のセクションが存在するかもまた、プログラム読み込み時に重要ではありません。しかし、さまざまなデータが、プログラム実行時や動的リンク時などには存在しなければなりません。以下に、セグメントの内容を示します。 セグメント内のセクションの順序と帰属関係は、異なることがあります。
テキストセグメントには、読み取り専用の命令/データが存在します。データセグメントには、書き込み可能のデータ/命令が存在します。すべての特殊セクションの一覧については、表 7-17を参照してください。
PT_DYNAMIC プログラムヘッダー要素は、.dynamic セクションを指し示します。さらに、.got セクションと .plt セクションには、位置に依存しないコードと動的リンクに関係する情報が存在します。
.plt は、テキストセグメントまたはデータセグメントに存在できます (どちらのセグメントに存在するかはプロセッサに依存します)。詳細は、「大域オフセットテーブル (プロセッサ固有)」と 「プロシージャのリンクテーブル (プロセッサ固有)」を参照してください。
.bss セクションには、SHT_NOBITS 型が存在します。このセクションはファイル領域を占めませんが、セグメントのメモリーイメージに与えられます。通常、これらの初期化されていないデータはセグメントの終わりに存在し、その結果、関連付けられているプログラムヘッダー要素において p_memsz が p_filesz より大きくなります。