a.out FormatはPDPの時代から使われているフォーマットであり、現在でもOpenBSDで使用されています(OpenBSD3.3からはELF formatに変更になりました)。PDP-11ではアドレスが16bitしかなかった為、プログラムコードのサイズは全体で64Kに制限されていました。そこで、Instructionセクションとdataセクションを分離することにより、一つのプログラムで、64Kのプログラムと64Kのデータを扱うことを可能していました。
また、2つのセクションに分けたことにより、プログラム複製がInstructionセクションを共有することが出来るので、独立したdataセクションだけ持てば良いことになり、メモリーの節約が出来るようになります。
Instructionセクションとdataセクションの分離
a.out ファイルは、さらに幾つかのセクションに分けられていて、最大で7つのセクションから構成されています。
a.outの構造
- a.out header
- バイナリファイルをメモリ上にロードして実行するためにカーネルが用いるパラメータを含んでいます。リンクエディタがバイナリファイルを他のバイナリファイルと結合する際にも用いられます。
- テキストセグメント
- プログラムが実行される際にメモリ上にロードされる機械語コード
- データセグメント
- 初期化済データを含んでいます。常に書き込み可能なメモリ上にロードされます。
- テキスト再配置情報
- バイナリファイル結合時にテキストセグメントのポインタを修正するために、リンクエディタによって用いられるレコードを含んでいます。
- データ再配置情報
- データセグメント内のポインタ修正用です。
- シンボルテーブル
- バイナリファイル間で名前付きの変数や関数(`シンボル') のアドレス相互参照を解決するために、リンクエディタによって用いられるレコードを含んでいます。
- string table
- シンボル名に対応する文字列を含んでいます。
ヘッダはUnixの種類により多少異なりますが、OpenBSDではexec_aout.hで定義されていて、下記のような構造になっています。
struct exec {
u_int32_t a_midmag;
u_int32_t a_text;
u_int32_t a_data;
u_int32_t a_bss;
u_int32_t a_syms;
u_int32_t a_entry;
u_int32_t a_trsize;
u_int32_t a_drsize;
};
マジックナンバは、バイナリファイル種別を識別し様々なロード方法を区別します。この値は下記のいずれか1つがセットされます。
- OMAGIC
-
テキストセグメントとデータセグメントはヘッダの直後にあり、連続しています。カーネルはテキスト/データセグメントの両方を書き込み可能メモリ領域にロードします。
OMAGICのロード
- NMAGIC
-
OMAGIC と同様、テキスト/データセグメントはヘッダの直後にあり、連続しています。しかし、カーネルはテキストセグメントを読み込み専用メモリ領域にロードし、テキストに続くページ境界から始まる書き込み可能メモリ領域にデータセグメントをロードします。
NMAGICのロード
- ZMAGIC
-
カーネルは各々のページを必要に応じてバイナリからロードします。ヘッダ、テキストセグメント及びデータセグメントはいずれも、ページサイズの倍数の大きさになるよう、リンクエディタによってパディングされます。カーネルがテキストセグメントからロードしたページは読み込み専用ですが、データセグメントからロードしたページは書き込み可能です。
ZMAGICのロード
また、OpenBSDには無いようだが、ZMAGICのファイルサイズをコンパクトにした(ZMAGICの場合、ヘッダ部分は数byteしか存在しないが1page分割り付けられてしまうため、ファイルサイズが大きくなる。)QMAGICと言う形式もある。
シンボルテーブルセクションのサイズ。 (バイト単位)
カーネルがバイナリファイルをロードした後の、プログラムのエントリポイントのメモリアドレスを保持します。カーネルは、このアドレスにある機械命令からプログラムの実行を開始します。
テキストリロケーションテーブルのサイズ 。(バイト単位)
データリロケーションテーブルのサイズ。 (バイト単位)