2013/12/28(Sat)
○[386BSD(の子孫)ソースコードシリーズ (334)][な阪関無] a.out フォーマットを読み解く(その2)
そういえば書き忘れていましたが a.out の語源は Assembler Output という何の捻りも無いアレです。
そもそもプログラミングに関する命名って捻りのない名前の方がいいよね、料理長が料理本で調理法をナイフとか意味不明な命名されるとギャー(3枚におろされました)。
@a.out はひとつ!じゃない!!
複数のバージョンが存在します、これはa.outヘッダのmagicで区別することができます。 magicは exec 構造体の a_midmag から取得できます。
ソースコードのコメントに
htonl(flags<<26 | mid<<16 | magic)
書かれているとおり a_midmag は network byte order な 32bit で、上から
- 6bit - flags フラグ情報
- 10bit - mid マシンID情報
- 16bit - magic マジックナンバー
という構造になっています。
マジックナンバーには以下の種類があります。
- OMAGIC ... 263 0407 0x0107
- NMAGIC ... 264 0410 0x0108
- ZMAGIC ... 267 0413 0x010b
- QMAGIC ... 204 0314 0x00cc
- CMAGIC ... 273 0421 0x0111
このうち NetBSD でサポートされるものは 定数マクロになってます。
57 #define OMAGIC 0407 /* old impure format */
58 #define NMAGIC 0410 /* read-only text */
59 #define ZMAGIC 0413 /* demand load format */
60 #define QMAGIC 0314 /* "compact" demand load format; deprecated */
このマジックを表示するための簡単なプログラムを書くとこんな感じ、昨日も書いたような理由で NetBSD 1.4/i386 でしか動作しないっす。
$ cat >magic.c
#include <sys/types.h>
#include <sys/exec_aout.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
int
main(int argc, const char *argv[])
{
int fd;
struct stat st;
struct exec *ex;
if (argc != 2)
abort();
fd = open(argv[1], O_RDONLY);
if (fd == -1)
abort();
if (fstat(fd, &st) == -1)
abort();
if (!S_ISREG(st.st_mode))
abort();
ex = mmap(NULL, (size_t)st.st_size, PROT_READ,
MAP_FILE|MAP_PRIVATE, fd, (off_t)0);
if (ex == MAP_FAILED)
abort();
printf("magic : %#lo\n", N_GETMAGIC(*ex));
exit(EXIT_SUCCESS);
}
^D
$ make magic
cc -O2 -o magic magic.c
$ ./magic /netbsd
magic : 0413
$ ./magic /bin/sh
magic : 0413
$ ./magic /usr/bin/vi
magic : 0413
だー mmap(2) めんどくさいんじゃ、あと fcntl.h とかいう名前、何年Cやってても fctrl.h と typo するんや ちくしょーめ!
ちゅーことで a.out な NetBSD kernel/userland のマジックは8進で 0413 つまり ZMAGIC であることが判りますやな。
@OMAGIC
OMAGIC(Old MAGIC) の名前は NMAGIC(New MAGIC) 登場後に便宜上つけられたものですが、フォーマット自体の歴史は古く既に Third Edition Unix の マニュアルにはすでに登場しています。
The header always contains 8 words: 1 A magic number (407(8)) 2 The size of the program text segment 3 The size of the initialized data segment 4 The size of the uninitialized (bss) segment 5 The size of the symbol table 6 The entry location (always 0 at present) 7 The stack size required (0 at present) 8 A flag indicating relocation bits have been suppressed
マジック 0407、おっベイスターズが優勝するまでに必要な勝ち数か何かかな?
ちなみに OMAGIC は NMAGIC や ZMAGIC 登場後も *.o のようなリンク前のオブジェクトファイルとして使用されています。 もちろん NetBSD でも使われてとりまして
$ ./magic /usr/src/sys/arch/i386/compile/GENERIC/vers.o
magic : 0407
$ ./magic /usr/obj/bin/sh/main.o
magic : 0407
$ ./magic /usr/obj/usr.bin/vi/build/main.o
magic : 0407
ちゅう感じ。
OMAGIC より更に古い a.out としては First Edition Unix の マニュアルを読むと
The header always contains 6 words: 1 a "br .+14" instruction (205(8)) 2 The size of the program text 3 The size of the symbol table 4 The size of the relocation bits area 5 The size of a data area 6 A zero word (unused at present)
とあって、最初はマジックナンバーではなく PDP-11のBR命令(無条件分岐、コード 0004xx)とそのオフセット(+14ワード)だったようです、こんな古い環境知らんがな(白目)。
@NMAGIC
おっ、21世紀になるかならないかの頃モバイル用途で広く使われたが XFree86 が動かなくてみんな嘆いたGPUかな?(それは NeoMagic)
Forth Edition Unix の マニュアルで登場します。
The header always contains 8 words: 1 A magic number (407 or 410(8))
Sixth Edition Unix の マニュアルだと更に NMAGIC と ZMAGIC の中間に
The header always contains 8 words: 1 A magic number (407, 410, or 411(8))
と 0411 のマジックナンバーを持つものも存在してます。
0410 と 0411 の違いについては Seventh Edition Unix の マニュアルに詳しいですが、これはまた回を改めて説明します。
ちなみに [ON]MAGIC の名前がついたのはもっと後世で、この頃の ヘッダファイルでは
#define A_MAGIC1 0407 /* normal */
#define A_MAGIC2 0410 /* read-only text */
#define A_MAGIC3 0411 /* separated I&D */
#define A_MAGIC4 0405 /* overlay */
のように、MAGIC1~4と番号振られてるだけですな。番号なんかで呼ぶな!私は自由なソフトウェアだ *1。
また 2.9BSD では
#define A_MAGIC5 0430 /* auto-overlay (nonseparate) */
#define A_MAGIC6 0431 /* auto-overlay (separate) */
ほげっ…さらに増えてるのね…
@ZMAGIC
こいつは 3BSD で登場したようです、こっちも
#define A_MAGIC1 0407 /* normal */
#define A_MAGIC2 0410 /* read-only text */
#define A_MAGIC3 0411 /* separated I&D (not on VAX) */
#define A_MAGIC4 0405 /* overlay */
#define A_MAGIC5 0413 /* demand page read-only text */
と、この時点では無名だった模様。
名前が [ONZ]MAGIC に整理されたのは 4BSD になってからですな。
#define OMAGIC 0407 /* old impure format */
#define NMAGIC 0410 /* read-only text */
#define ZMAGIC 0413 /* demand load format */
@QMAGIC
これワイ調べたけど由来が良くわかりません、 Linkers & Loader には BSD で採用されてるような事が書かれているのですが、 ZMAGICの改良版(省ファイルサイズ)みたいですやね。
NetBSD だと commitlog は 残ってるようですが、ちょうど例の裁判によって CVS から消されてるわでよう判りません。
FreeBSD の場合も この差分の
The big 4.4BSD Lite to FreeBSD 2.0.0 (Development) patch.
という、な特雑コ(雑なコミットログ)によって放り込まれてるしなぁ。
ところが、 4.4BSD のソースみても無いんですよな…
/* Description of the object file header (a.out format). */
struct exec {
#define OMAGIC 0407 /* old impure format */
#define NMAGIC 0410 /* read-only text */
#define ZMAGIC 0413 /* demand load format */
long a_magic; /* magic number */
しかもこれ定数マクロが宣言されてるだけで、execve(2)のコード追っても QMAGIC の実行はサポートもしておらん風味、ふしぎ! まぁコメントに deprecated とあることだし忘れましょう(ぉ
@CMAGIC
これは a.out 時代の Linux の core dumps がこの形式だったようです、 include/uapi/linux/a.out.h に定義されてますな。
/* Code indicating core file. */
#define CMAGIC 0421
@次回
[ONZ]MAGICの違いについて説明する予定ですが、図を描かないとならんのでちょっと時間かかるかも。