The Man Who Fell From The Wrong Side Of The Sky:2013年12月28日分

[最新版] [一覧] [前月] [今月] [翌月]

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 で、上から

という構造になっています。

マジックナンバーには以下の種類があります。

このうち 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の違いについて説明する予定ですが、図を描かないとならんのでちょっと時間かかるかも。


*1:さすがに元ネタ観た事ないんですが、面白いんですかね?


[ホームへ] [ページトップへ]