A.OUT(5)

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

書式
<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 {
    		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 となります。

関連項目
as(1), gdb(1), ld(1), brk(2), execve(2), nlist(3), core(5), elf(5), link(5), stab(5)

歴史
インクルードファイル a.out.h は AT&T UNIX で登場しました。

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