EN JA
A.OUT(5)
A.OUT(5) FreeBSD File Formats Manual A.OUT(5)

名称

a.out実行可能バイナリファイルのフォーマット

書式

#include < a.out.h>

解説

インクルードファイル < a.out.h> では、3 つの構造体といくつかのマクロが宣言されています。これらの構造体は、このシステムで実行可能な機械語コードファイル (‘バイナリ’) のフォーマットを規定します。

バイナリファイルは、最大で 7 つのセクションから構成されます。これらのセクションを順にあげると以下のようになります:

exec ヘッダ
バイナリファイルをメモリ上にロードして実行するためにカーネルが用いるパラメータを含んでいます。これらのパラメータは、リンクエディタ ld(1) がバイナリファイルを他のバイナリファイルと結合する際にも用いられます。このセクションは、唯一の必須セクションです。
テキストセグメント
プログラムが実行される際にメモリ上にロードされる機械語コード及び関連データを含んでいます。読み込み専用でロードされる場合があります。
データセグメント
初期化済データを含んでいます。常に書き込み可能なメモリ上にロードされます。
テキストリロケーション
バイナリファイル結合時にテキストセグメント内のポインタを修正するために、リンクエディタによって用いられるレコードを含んでいます。
データリロケーション
前出のテキストリロケーションセクションと似ていますが、データセグメント内のポインタ修正用です。
シンボルテーブル
バイナリファイル間で名前付きの変数や関数 (‘シンボル’) のアドレス相互参照を解決するために、リンクエディタによって用いられるレコードを含んでいます。
string table
シンボル名に対応する文字列を含んでいます。

全てのバイナリファイルは、次の exec 構造体で始まります:

struct exec { 
 unsigned long a_midmag; 
 unsigned long a_text; 
 unsigned long a_data; 
 unsigned long a_bss; 
 unsigned long a_syms; 
 unsigned long a_entry; 
 unsigned long a_trsize; 
 unsigned long a_drsize; 
};

これらのフィールドは、以下の機能を持っています:

a_midmag
このフィールドは、ホストのバイト順 (host byte-order) で格納されます。このフィールドは、いくつかのサブコンポーネントを持っており、それらは、以下のマクロ N_GETFLAG(), N_GETMID(), N_GETMAGIC() で参照され、マクロ N_SETMAGIC() で設定されます。

マクロ N_GETFLAG() は、以下のフラグを返します:

EX_DYNAMIC
この実行可能ファイルがランタイムリンクエディタのサービスを要求することを示します。
EX_PIC
このオブジェクトファイルが位置独立 (position independent) なコードを含んでいることを示します。このフラグは、‘-k’フラグ指定時に as(1) によって設定され、必要なら ld(1) は、これを保存します。

EX_DYNAMIC と EX_PIC の両方がセットされている場合、そのオブジェクトファイルは、位置独立な実行可能イメージです (例: 共有ライブラリ)。これは、ランタイムリンクエディタによってプロセスのアドレス空間にロードされます。

マクロ N_GETMID() は、マシン識別コード (machine-id) を返します。これは、バイナリファイルが実行されるべきマシンを示しています。

N_GETMAGIC() は、マジックナンバを示します。マジックナンバは、バイナリファイル種別を一意に識別し、様々なロード方法を区別します。このフィールドは、以下の値のいずれか 1 つを含んでいなければなりません:

OMAGIC
テキストセグメントとデータセグメントは、ヘッダの直後にあり、連続しています。カーネルは、テキスト/データセグメントの両方を書き込み可能メモリ領域にロードします。
NMAGIC
OMAGIC と同様、テキスト/データセグメントは、ヘッダの直後にあり、連続しています。しかし、カーネルは、テキストセグメントを読み込み専用メモリ領域にロードし、テキストに続くページ境界から始まる書き込み可能メモリ領域にデータセグメントをロードします。
ZMAGIC
カーネルは、各々のページを必要に応じてバイナリからロードします。ヘッダ、テキストセグメント及びデータセグメントは、いずれも、ページサイズの倍数の大きさになるよう、リンクエディタによってパディングされます。カーネルがテキストセグメントからロードしたページは、読み込み専用ですが、データセグメントからロードしたページは、書き込み可能です。
a_text
テキストセグメントのサイズ (バイト単位) を保持します。
a_data
データセグメントのサイズ (バイト単位) を保持します。
a_bss
‘bss セグメント’のバイト数を保持します。この値は、カーネルが最初の break 値 ( brk(2)) をデータセグメントの後ろに設定するのに用いられます。カーネルは、ここに示されるサイズの書き込み可能メモリ領域がデータセグメントの後ろに用意され、それらの初期状態が 0 になるように、プログラムをロードします。 ( bss = block started by symbol:シンボルで開始するブロック)
a_syms
シンボルテーブルセクションのサイズ (バイト単位) を保持します。
a_entry
カーネルがバイナリファイルをロードした後の、プログラムのエントリポイントのメモリアドレスを保持します。カーネルは、このアドレスにある機械命令からプログラムの実行を開始します。
a_trsize
テキストリロケーションテーブルのサイズ (バイト単位) を保持します。
a_drsize
データリロケーションテーブルのサイズ (バイト単位) を保持します。

インクルードファイル < a.out.h> では、 exec 構造体を用いて一貫性をテストしたりバイナリファイル中のセクションオフセットを知るためのマクロが定義されています。

N_BADMAG( exec)
a_magic フィールドに、認識できない値が含まれている場合、非 0 を返します。
N_TXTOFF( exec)
バイナリファイルにおけるテキストセグメントの先頭のバイトオフセットを返します。
N_SYMOFF( exec)
シンボルテーブルの先頭のバイトオフセットを返します。
N_STROFF( exec)
文字列テーブルの先頭のバイトオフセットを返します。

リロケーションレコードは、 relocation_info 構造体で規定される標準フォーマットです:

struct relocation_info { 
 int  r_address; 
 unsigned int r_symbolnum : 24, 
   r_pcrel : 1, 
   r_length : 2, 
   r_extern : 1, 
   r_baserel : 1, 
   r_jmptable : 1, 
   r_relative : 1, 
   r_copy : 1; 
};

relocation_info 構造体の各フィールドは、以下のように用いられます:

r_address
リンクエディットが必要なポインタのバイトオフセットを保持します。テキストリロケーションオフセットは、テキストセグメントの先頭から、データリロケーションオフセットは、データセグメントの先頭から、それぞれ計算します。リンクエディタは、このオフセットにストアされている値を加算し、このリロケーションレコードを用いて計算した新しい値に変換します。
r_symbolnum
シンボルテーブルにおけるシンボル構造体の順序番号 (バイトオフセット ではありません) を保持します。リンクエディタは、このシンボルの絶対アドレスを解決した後、そのアドレスをリロケーション中のポインタに加算します。 (もし r_extern ビットが立っていなければ状況は異なります。以下を参照して下さい。)
r_pcrel
もしこのビットが立っていれば、リンクエディタは、PC 相対アドレッシングを用いる機械語命令の一部であるポインタを更新しているものと仮定します。リロケートされるポインタのアドレスは、実行中のプログラムがそれを用いる際に、暗黙的にその値に加算されます。
r_length
ポインタの長さを 2 を底とする対数で表したバイト単位で保持します。 1 バイトディスプレースメントなら 0、 2 バイトディスプレースメントなら 1、 4 バイトディスプレースメントなら 2 となります。
r_extern
このリロケーションが外部参照を必要としている場合にセットされます。リンクエディタは、シンボルアドレスを用いてこのポインタを更新しなければなりません。 r_extern ビットが立っていない場合、そのリロケーションは、‘ローカル’です。リンクエディタは、シンボル値の変化ではなく、各セグメントのロードアドレスの変化に応じてポインタを更新します (ただし、 r_baserel もセットされている場合 (後述) は、除きます)。この場合、 r_symbolnum フィールドの内容は、 n_type の値となります(後述)。リンクエディタは、この型フィールドから、リロケートされるポインタがどのセグメントを指しているのかの情報を得ます。
r_baserel
セットされている場合、 r_symbolnum フィールドで指定される場合のように、このシンボルは、グローバルオフセットテーブルへのオフセットにリロケートされます。実行時に、グローバルオフセットテーブル中の、このオフセット位置にあるエントリが、シンボルのアドレスを持つようにセットされます。
r_jmptable
セットされている場合、 r_symbolnum フィールドで指定される場合のように、このシンボルは、プロシージャリンケージテーブルへのオフセットにリロケートされます。
r_relative
セットされている場合、このリロケーションは、このオブジェクトファイルが含まれるイメージの (実行時の) ロードアドレスとの相対値となります。この種のリロケーションは、共有オブジェクトにのみ現れます。
r_copy
セットされている場合、このリロケーションレコードは、その内容を r_address で指定される位置にコピーしなければならないシンボルを示します。コピー処理は、実行時のリンクエディタによって、共有オブジェクト中の適切なデータアイテムから行われます。

シンボルは、名前とアドレスを対応づけます (より一般的には、文字列を値へ対応づけます)。リンクエディタがアドレスを調節するため、絶対値が割り当てられるまでは、シンボルを用いてアドレスを表現しなければなりません。シンボルは、シンボルテーブル中の固定長のレコードと、文字列テーブル中の可変長の名前から成ります。シンボルテーブルは、 nlist 構造体の配列です:

struct nlist { 
 union { 
  const char *n_name; 
  long  n_strx; 
 } n_un; 
 unsigned char  n_type; 
 char   n_other; 
 short   n_desc; 
 unsigned long  n_value; 
};

これらのフィールドは、以下のように用いられます:

n_un.n_strx
このシンボルの名前の、文字列テーブルでのバイトオフセットを保持します。プログラムが nlist(3) 関数を用いてシンボルテーブルをアクセスする場合、このフィールドは、メモリ中の文字列へのポインタである n_un.n_name フィールドに置き換えられます。
n_type
リンクエディタがシンボル値の更新方法を決定するのに用いられます。 n_type フィールドは、ビットマスクを用いた 3 つのサブフィールドに分けられます。リンクエディタは、 N_EXT ビットがセットされているシンボルを‘external’シンボルとして扱い、他のバイナリファイルからの参照を許可します。 N_TYPE マスクは、リンクエディタに必要なビットを選択します:
N_UNDF
未定義シンボル。リンクエディタは、他のバイナリファイル中の同じ名前の外部シンボルを探してこのシンボルの絶対値を決定しなければなりません。特別な場合として、もし n_value フィールドが非 0 で、リンクエディット対象のどのバイナリファイルもこのシンボルを定義していない場合、リンクエディタは、このシンボルが bss セグメント中のアドレスであるとみなし、 n_value に等しいバイト数の領域を予約します。もしこのシンボルが複数のバイナリファイル中で未定義となっており、それらのバイナリファイル間でサイズが異なっている場合、リンクエディタは、それらのサイズの最大値を選びます。
N_ABS
絶対シンボル。リンクエディタは、絶対シンボルは更新しません。
N_TEXT
テキストシンボル。このシンボルの値は、テキストアドレスであり、リンクエディタは、バイナリファイルをマージする際、その値を更新します。
N_DATA
データシンボル。 N_TEXT と同様ですが、データアドレスを表します。テキストシンボル及びデータシンボルの値は、ファイルオフセットではなくアドレスです。ファイルオフセットを復元するために、対応するセクションの先頭のロードアドレスを見つけてそれを減じ、次にそのセクションのオフセットを加算する必要があります。
N_BSS
bss シンボル。テキストシンボルやデータシンボルと似ていますが、バイナリファイル中に対応するオフセットを持ちません。
N_FN
ファイル名シンボル。バイナリファイルをマージする際、リンクエディタは、バイナリファイルの他のシンボルの前にこのシンボルを挿入します。このシンボルの名前は、リンクエディタに与えられたファイル名で、シンボルの値は、バイナリファイルから得た先頭テキストアドレスです。ファイル名シンボルは、リンクエディト処理やロード処理には不要ですが、デバッガには、有用な情報です。

N_STAB マスクは、 gdb(1) 等のシンボリックデバッガに必要なビットを選択します。その値は、 stab(5) に示されています。

n_other
このフィールドは、 n_type フィールドで決定されるセグメントに関して、そのシンボルのロケーションとは独立したシンボルの特質に関する情報を提供します。現在のところ、 n_other フィールドの下位 4 ビットは、 AUX_FUNC あるいは AUX_OBJECT のいずれかをとります (これらの定義については、 < link.h> を参照してください)。 AUX_FUNC は、シンボルと呼び出し可能な関数を関連づけ、他方、 AUX_OBJECT は、シンボルとデータを関連づけます。これらの関連は、テキストセグメント/データセグメントの別とは無関係です。このフィールドは、 ld(1) が動的な実行可能形式を構築するために使うことを意図しています。
n_desc
デバッガ用に予約されており、リンクエディタは、このフィールドを全く変更しません。デバッガによって異なった目的に使われます。
n_value
シンボルの値を保持します。テキスト, データおよび bss シンボルの場合、その値は、アドレスです。他のシンボル (例えばデバッガシンボル等) の場合、その値は、様々です。

文字列テーブルは、 unsigned long 型の長さと、それに続くナル終端のシンボル文字列から成ります。この長さは、テーブル全体のサイズをバイト単位で表します。つまり、その最小値 (言い替えれば、最初の文字列のオフセット) は、 32 ビットマシンでは、常に 4 となります。

歴史

インクルードファイル < a.out.h> は、 Version 7 AT&T UNIX で登場しました。

バグ

必ずしも全てのサポート対象アーキテクチャが a_midmag フィールドを用いるわけではないので、あるバイナリがどのようなアーキテクチャ上で実行されるのかは、実際のマシンコードを調べない限り判定困難な可能性があります。マシン ID があったとしても、 exec ヘッダのバイト順は、マシン依存です。
June 10, 2010 FreeBSD