リンカーとライブラリ

プログラムヘッダー

実行可能オブジェクトファイルまたは共有オブジェクトファイルのプログラムヘッダーテーブルは、構造体の配列です (各構造体は、実行されるプログラムを作成するためにシステムが必要とするセグメントやその他の情報を記述します) 。各オブジェクトファイルセグメントには、「セグメントの内容」に記述されているとおり、1 つまたは複数のセクションが存在します。

プログラムヘッダーは、実行可能オブジェクトファイルと共有オブジェクトファイルに対してのみ意味があります。プログラムヘッダーサイズは、ELF ヘッダーの e_phentsize 構成要素と e_phnum 構成要素で指定されます。詳細は、「ELF ヘッダー」を参照してください。

プログラムヘッダーの構造体 (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;
p_type

この構成要素は、この配列要素が記述するセグメント型、または配列要素の情報のセマンティクスを与えます。型の値とその意味は、表 7-36 を参照してください。

p_offset

この構成要素は、ファイルの先頭から、セグメントの先頭バイトが存在する位置までのオフセットを与えます。

p_vaddr

この構成要素は、セグメントの先頭バイトが存在するメモリーの仮想アドレスを与えます。

p_paddr

物理アドレス指定が妥当であるシステムの場合、この構成要素はセグメントの物理アドレスに対して使用されます。本システムはアプリケーションプログラムに対して物理アドレス指定を無視するので、この構成要素には実行可能ファイルと共有オブジェクトに対する指定されていない内容が存在します。

p_filesz

この構成要素は、セグメントのファイルイメージのバイト数を与えます。この構成要素は 0 の場合もあります。

p_memsz

この構成要素は、セグメントのメモリーイメージのバイト数を与えます。この構成要素は 0 の場合もあります。

p_flags

この構成要素は、セグメントに関係するフラグを与えます。定義されているフラグ値は、表 7-37 のとおりです。

p_align

「プログラムの読み込み (プロセッサ固有)」に記述されているとおり、読み込み可能なプロセスセグメントには、ページサイズを法として p_vaddrp_offset に対して同じ値が存在しなければなりません。この構成要素は、セグメントがメモリーとファイルにおいて整列される値を与えます。値 0 と 1 は、整列が必要ないことを意味します。その他の値の場合、p_align は 2 の正整数累乗でなければならず、また p_vaddrp_align を法として p_offset に等しくなければなりません。

いくつかのエントリはプロセスセグメントを記述しますが、それ以外のエントリは補足情報を与え、プロセスイメージには関与しません。セグメントエントリが現れる順序は、以下に明確に記されている場合を除き任意です。定義されている型の値は、次のとおりです。他の値は、将来における使用に備えて保留されます。

表 7-36 セグメント型 p_type

名前 

値 

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

PT_NULL

この配列要素は使用されていません。他の構成要素の値は不定です。この型を使用すると、プログラムヘッダーテーブルに、無視されるエントリを入れることができます。

PT_LOAD

この配列要素は、p_fileszp_memsz で記述される読み込み可能セグメントを指定します。ファイルのバイト列は、メモリーセグメントの先頭に対応付けされます。セグメントのメモリーサイズ (p_memsz) がファイルサイズ (p_filesz) より大きい場合、不足するバイトは、値 0 を保持しセグメントの初期化領域に続くように定義されます。ファイルサイズがメモリーサイズより大きくなることは許可されません。プログラムヘッダーテーブルの読み込み可能セグメントエントリは、p_vaddr 構成要素で整列され、昇順に現れます。

PT_DYNAMIC

この配列要素は、動的リンク情報を指定します。詳細は、「動的セクション」を参照してください。

PT_INTERP

この配列要素は、インタプリタとして呼び出される、空文字で終了しているパス名の位置とサイズを指定します。このセグメント型は、実行可能ファイルに対してのみ意味があります (ただし、共有オブジェクトに対しても指定されることがあります)。このセグメント型は、ファイル内で複数存在することはできません。このセグメントタイプが存在する場合、このセグメント型は読み込み可能セグメントエントリの前に存在しなければなりません。詳細は、「プログラムインタプリタ」を参照してください。

PT_NOTE

この配列要素は、補助情報の位置とサイズを指定します。詳細は、「注釈セクション」を参照してください。

PT_SHLIB

このセグメント型は予約されますが、解釈の方法は定義されていません。

PT_PHDR

この配列要素が存在する場合、この配列要素は、プログラムヘッダーテーブル自身の、ファイルとプログラムのメモリーイメージにおける位置とサイズを指定します。このセグメント型は、ファイル内で複数存在することはできません。また、このセグメント型は、プログラムヘッダーテーブルがプログラムのメモリーイメージの一部になる場合に限り存在できます。このセグメント型が存在する場合、このセグメント型は読み込み可能セグメントエントリの前に存在しなければなりません。詳細は、「プログラムインタプリタ」を参照してください。

PT_LOSUNW - PT_HISUNW

この範囲の値は、Sun 固有のセマンティクスに対して予約されます。

PT_SUNWBSS

この配列要素は、PT_LOAD 要素と同じ属性を持ち、.SUNW_bss セクションを記述するために使用されます。

PT_SUNWSTACK

この配列要素はプロセススタックを記述します。現在のところ、そういった要素は 1 つのみ存在し、p_flags フィールドで定義されているアクセスパーミッションのみが有用です。

PT_LOPROC - PT_HIPROC

この範囲の値は、プロセッサ固有のセマンティクスに対して予約されます。


注 -

他の箇所で特に要求されない限り、すべてのプログラムヘッダーセグメントタイプはそれぞれ存在することもありますし、存在しないこともあります。つまり、ファイルのプログラムヘッダーテーブルには、このプログラムの内容に関係する要素のみが存在できます。


ベースアドレス

実行可能オブジェクトファイルと共有オブジェクトファイルには、ベースアドレス (プログラムのオブジェクトファイルのメモリーイメージに関連付けられている最下位仮想アドレス) が存在します。ベースアドレスは、たとえば動的リンク時にプログラムのメモリーイメージを再配置するために使用されます。

実行可能オブジェクトファイルと共有オブジェクトファイルのベースアドレスは、実行時に 3 つの値 (プログラムの読み込み可能セグメントのメモリー読み込みアドレス、最大ページサイズ、最下位仮想アドレス) から計算されます。「プログラムの読み込み (プロセッサ固有)」に記述されているとおり、プログラムヘッダーの仮想アドレスは、プログラムのメモリーイメージの実際の仮想アドレスを表さないことがあります。

ベースアドレスを計算するには、PT_LOAD セグメントの最下位 p_vaddr 値に関連付けられているメモリーアドレスを判定します。次に、メモリーアドレスを最大ページサイズの最近倍数に切り捨てることで、ベースアドレスが求められます。メモリーに読み込まれるファイルの型によって、メモリーアドレスは p_vaddr 値に一致する場合もあれば、一致しない場合もあります。

セグメントへのアクセス権

システムで読み込まれるプログラムには、少なくとも 1 つの読み込み可能セグメントが存在しなければなりません (ただし、このことはファイル形式では要求されていません)。システムは、読み込み可能セグメントのメモリーイメージを作成するとき、p_flags 構成要素で指定されるアクセス権を与えます。PF_MASKPROC マスクのすべてのビットは、プロセッサ固有のセマンティクスに対して予約されます。

表 7-37 セグメントフラグビット p_flags

名前 

値 

意味 

PF_X

0x1

実行 

PF_W

0x2

書き込み 

PF_R

0x4

読み取り 

PF_MASKPROC

0xf0000000

指定されていない 

アクセス権ビットが 0 の場合、その種類のアクセスは拒否されます。実際のメモリーアクセス権は、メモリー管理ユニット (システムによって異なることがある) に依存します。すべてのフラグ組み合わせが有効ですが、システムは要求以上のアクセスを与えることがあります。ただしどんな場合も、特に断りが明示的に記述されていない限り、セグメントは書き込み権を持ちません。表 7-38 は、正確なフラグ解釈と許容されるフラグ解釈を示しています。

表 7-38 セグメントへのアクセス権

 

値 

正確なフラグ解釈 

許容されるフラグ解釈 

なし

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 を参照してください。特定の実行可能ファイルに存在しているセクションを確認するには、dump(1) を使用してください。

PT_DYNAMIC プログラムヘッダー要素は、「動的セクション」で説明しているとおり、.dynamic セクションを指し示します。さらに、.got セクションと .plt セクションには、位置に依存しないコードと動的リンクに関係する情報が存在します。

.plt は、テキストセグメントまたはデータセグメントに存在できます (どちらのセグメントに存在するかはプロセッサに依存します)。詳細は、「大域オフセットテーブル (プロセッサ固有)」「プロシージャのリンクテーブル (プロセッサ固有)」を参照してください。

表 7-12 で記述しているとおり、.bss セクションには SHT_NOBITS 型が存在します。このセクションはファイル領域を占めませんが、セグメントのメモリーイメージに与えられます。通常、これらの初期化されていないデータはセグメントの終わりに存在し、その結果、関連付けられているプログラムヘッダー要素において p_memszp_filesz より大きくなります。