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

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

2013/12/27(Fri)

[386BSD(の子孫)ソースコードシリーズ (334)][な阪関無] a.out フォーマットを読み解く(その1)

またしても sys/cdefs.h の話から西か北かの如く脱線(意味深)していきますが、その日の気分で書いてるだけなので気にしてはいけない(戒め)

ニッキンキョーイク?!デンシャナンデ?!

@ NetBSD における a.out の実装

まず a.out(5) の構造を知る為に、 sys/exec_aout.h を読み解いていきましょう。

45 struct exec {
46         u_long  a_midmag;       /* htonl(flags<<26 | mid<<16 | magic) */
47         u_long  a_text;         /* text segment size */
48         u_long  a_data;         /* initialized data size */
49         u_long  a_bss;          /* uninitialized data size */
50         u_long  a_syms;         /* symbol table size */
51         u_long  a_entry;        /* entry point */
52         u_long  a_trsize;       /* text relocation size */
53         u_long  a_drsize;       /* data relocation size */
54 };

これがいわゆる a.out ヘッダ情報といわれるものです、この時点でファッ!?となった人は良く訓練されたパラノイド。

上記のとおり NetBSD において a.out ヘッダの各フィールドは MD(Machine Dependent) な u_long(=unsigned long) で定義されとります。 これ sizeof(struct exec) が i386 のような ILP32 環境では 32、amd64 のような LP64 環境だと 64 になってしまうので、file magic からの format 判定が辛いさんですやね。

ところがどっこいこれ心配ゴム無用なんですな。NetBSD において初の 64bit arch であった NetBSD/alpha ですが、こいつは a.out ではなく DEC Alpha マシンの上で動作する正妻である DEC OSF/1 → Digital UNIX → Tru64 UNIX と同じ ECOFF フォーマット *1を採用しており、その後改めて elf(5) フォーマットに移行しています *2

つまり 64bit な NetBSD において native な a.out バイナリって存在しないのですわ。

そしてここ重要、このヘッダファイルは 32bit arch 専用であって 64bit arch 上で includeしてはならない(戒め)

sysの下にあろうとも、あなたの予想に反して決して正しいヘッダ情報は得られません。 いつもの「MD/MIは分離されている(MD/MIは分離されてるとは言っていない)」ですやね、はぁ(溜息)。

@ 他の *BSDの場合

FreeBSD も OpenBSD もそんなアホな状態で放置せずにちゃんと s/u_long/uint32_t/ して MI(Machine Independent) になっとります。 FreeBSD では こんなん

112 struct exec {
113      uint32_t   a_midmag;       /* flags<<26 | mid<<16 | magic */
114      uint32_t   a_text;         /* text segment size */
115      uint32_t   a_data;         /* initialized data size */
116      uint32_t   a_bss;          /* uninitialized data size */
117      uint32_t   a_syms;         /* symbol table size */
118      uint32_t   a_entry;        /* entry point */
119      uint32_t   a_trsize;       /* text relocation size */
120      uint32_t   a_drsize;       /* data relocation size */
121 };

ただし本当はこれ exec_aout32 という名前の方が好ましいのかもしれません。

とゆーのも、ワイは現物見たことないのですが 64bit a.out 形式というトンデモ環境も存在するようで、 GNU binutils などに含まれる BFD(Binary Format Descripter) のドキュメントには 64bit a.out 形式についての言及があったりします、まーでもこれ demo64.c だから実際に採用した OS は存在しないっぽいね *3

@ えっ…これで COMPAT_NETBSD32 + EXEC_AOUT って動くの?

勘のいい人はピーンと来るかと思いますが、この sys/exec_*.h というのは execve(2) で kernel が実行形式を読み込むのに使うものなので、こんなダメダメな状態だとすると NetBSD/amd64 上の i386 互換モードで a.out 形式のサポートは期待するだけ無駄です。

事実 GENERIC kernel configでは

options         COMPAT_NETBSD32

はあれど

options         EXEC_AOUT

が無いのでデフォルトでは動きませんし、指定したところでそもそも src/sys/arch/amd64/amd64/netbsd32_machdep.c の中では

#ifdef EXEC_AOUT
/*
 * There is no native a.out -- this function is required
 * for i386 a.out emulation (COMPAT_NETBSD32+EXEC_AOUT).
 */
int
cpu_exec_aout_makecmds(struct lwp *p, struct exec_package *e)
{

	return ENOEXEC;
}
#endif

と ENOEXEC を返してるので、execve(2)は実行フォーマットエラーになりやがりますな。

まぁでもこんなん気にするパラノイアはおらんと思いますがね。他の *BSD では FreeBSD は 5 系で a.out サポートは叩っ切りましたし OpenBSDも最近消しましたな、いちおう src/sys/kern/exec_aout.cとか、MI化されてたんじゃないかって気はしますが。

@ NetBSD って後方互換性に自信ニキじゃなかったの?

さぁ?(投げやり) 最近は破壊に自信ニキしかおらんのでは?

まぁWin64環境ではWin16が動かなくなった程度のMicrosoftさんの互換性に対する努力には勝てませんやね。

@ 次回

まーた枝葉で1回分使ってしまった、次回はちゃんとヘッダの中身の説明をします。


*1:COFFとその子孫はまた次の機会に説明したいと思いますがまぁ a.out の進化系ですやね。
*2:kernel だけ elf(5)、userland は ECOFF な時期とかもあった模様。
*3:もしかして DEMOS (それは無い)。


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