a.outのマジックナンバー
a.out*1のヘッダの先頭にはマジックナンバーが埋め込まれていて、これによっていわゆるOMAGICとかNMAGIC、ZMAGICとかに分類される(詳細はWikipediaのここ)。OMAGICはヘッダのすぐ後にテキストとデータセグメントが続き、それら両方は書込み可能なメモリにロードされる。テキストセグメントがread onlyになったのはNMAGICから。ZMAGICではデマンドページングに対応している。
さて、V1カーネルのa.outはOMAGICよりもさらに古そうだ。OMAGICのマジックナンバーは0407だけど、V1のは0405なのだ。ちなみに、OMAGICになったのはV2からで、unix-jun72プロジェクトのカーネルではOMAGICサポートが追加されている。配布されているasはV2から持ってきたコードらしく、実際、asでアセンブルしたa.outはOMAGICだった。
これらマジックナンバーの0405などは適当に決めた値ではなく、実はbr命令でヘッダに続くテキストセグメントの先頭アドレスへジャンプすることを意味している。ヘッダが拡張されてオフセットが大きくなるにしたがいマジックナンバーも変更されているのだ。当然、この仕掛けはPDP-11以外のアーキテクチャでは機能しないので今となっては形骸化してしまっているが、こんなところにPDP-11の名残を留めているというのが面白い。
「Plan9のa.outフォーマット」については以前書いたが、マジックナンバーにはアーキテクチャのIDがエンコードされていて、x86の場合は0x1ebになる。
#define HDR_MAGIC 0x00008000 /* header expansion */ #define _MAGIC(f, b) ((f)|((((4*(b))+0)*(b))+7)) #define A_MAGIC _MAGIC(0, 8) /* 68020 */ #define I_MAGIC _MAGIC(0, 11) /* intel 386 */ #define J_MAGIC _MAGIC(0, 12) /* intel 960 (retired) */ #define K_MAGIC _MAGIC(0, 13) /* sparc */ #define V_MAGIC _MAGIC(0, 16) /* mips 3000 BE */ #define X_MAGIC _MAGIC(0, 17) /* att dsp 3210 (retired) */ #define M_MAGIC _MAGIC(0, 18) /* mips 4000 BE */ #define D_MAGIC _MAGIC(0, 19) /* amd 29000 (retired) */ #define E_MAGIC _MAGIC(0, 20) /* arm */ #define Q_MAGIC _MAGIC(0, 21) /* powerpc */ #define N_MAGIC _MAGIC(0, 22) /* mips 4000 LE */ #define L_MAGIC _MAGIC(0, 23) /* dec alpha */ #define P_MAGIC _MAGIC(0, 24) /* mips 3000 LE */ #define U_MAGIC _MAGIC(0, 25) /* sparc64 */ #define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */ #define T_MAGIC _MAGIC(HDR_MAGIC, 27) /* powerpc64 */
*1:もちろんELFとかCOFF以前の話である。