【お知らせ】プログラミング記事の投稿はQiitaに移行しました。

i8086とPDP-11のインタプリタを統合

i8086インタプリタPDP-11インタプリタを統合しました。1つのプログラムでMINIX 2とUNIX V6の両方のバイナリを動かせます。

UNIX V6のccを動かしてカーネルがビルドできることを確認しました。

V6移植ハッカソンで使うため、2年前に作ったPDP-11のインタプリタi8086インタプリタの構造に合わせて移植しました。MINIX 2とUNIX V6のUNIXとしての共通部分は基底クラスで共用しています。UNIX V6をi8086に移植する際にインタプリタシステムコールのABIを実装すれば、カーネルを移植する前にユーザーバイナリの動作確認を切り離して行えるのではないかという狙いです。

【追記】統合するために行ったクラス設計について記事を書きました。

アセンブラ

以前のPDP-11インタプリタ(v6run)にはなかった逆アセンブラを搭載しています。binutilsではシンボルの互換性がないためstripが必要でしたが、今回の実装ではシンボルを読み込んで逆アセンブラで表示できます。

簡単なプログラムを逆アセンブルした例です。

これを見ればリンカの動作まで推測できるため、バイナリの勉強には役立ちそうです。

ハマりポイント

移植の際に構造を大幅に見直した部分は書き直しています。そのため以前は正しく実装していた部分なのに、書き直しの際に見落としてハマったりしました。

(PC)

ディスプレースメントを即値と共用しているコードがあります。Cコンパイラで最適化を掛けると、可能な局面ではこのようなコードを出力するようです。レアケースです。

/lib/c2 より

0984: a3fb 0004       cmpb (pc), *4(r3)
0ca2: a3fc 0002       cmpb (pc), *2(r4)
150a: a3fb 0002       cmpb (pc), *2(r3)

第1オペランドが評価される際にPCはディスプレースメントを指しています。意味的には以下と等しいコードです。

cmpb $4, *4(r3)
cmpb $2, *2(r4)
cmpb $2, *2(r3)

r7のモードは逆アセンブルの際に特別扱いしますが、(pc)は実装していなかったため誤動作しました。使われる可能性があるため注意が必要です。

アドレス計算のオーバーフロー

これもレアケースです。

/bin/cc より

0628: 8a31 f218       clrb -0xde8(r1)

r1=0x200のときには0xf418となります。符号なし16bitとして扱っていなかったためアドレスがマイナスとなり誤動作しました。

感想

最初に実装したときは注意していたため、これらのバグは踏まなかったようです。今回は比較対象があったためすぐに気付きましたが、そうでなければ解明は難航したと思います。長いビルドのときしかバグが表面化しなかったため、ログは数GBの膨大なものでした。