機械語の勉強会に参加したので8086の逆アセンブラをGoで書いてみてる
HHVM の話を聴いてからというもの、VM というものにどうにも興味がわいて仕方がない今日この頃。世の中の言語処理系も中身は VM だったりするわけで、そもそも VM ってどうやって作るのかな − とか考えてたら
@riywo PDP-11のVM作って、Unix V6動かせば、一石何鳥になることやら
— sakamoto.kazuki (@splhack) October 1, 2014
というご意見をもらって、初めて PDP-11 というものを調べ始めました。UNIX V6 の本とかを買って読み始めてみたり、言語処理系の作り方の本にも手をだしてみました。
PDP-11/UNIX V6 の勉強会があった
そんな中、@7shiさんが主催されている「池袋バイナリ勉強会」の存在を知りました。なんと、ついこの間まで PDP-11 の逆アセンブラ(機械語のバイナリからアセンブリ言語を出力する)を作ったりしていたと!参加者の中にはそのままインタプリタまで実装してしまった人もいるではないですか!
これは!と思いこの間開催されいてた機械語入門に参加してきました。Haskell を初めて書きました。
最近は 8086 という PDP-11 よりは現代に近い CPU に移行したとのことで、今回も 8086 の機械語を学びました。16bit の CPU で、現代の x86 や x86_64 に直接つながる CPU なので胸熱です。ちなみに x86 は以前 Coursera のこちらの講義で軽く学習したことがあります。この講義はマジでおすすめ。
逆アセンブラを作るということ
普通機械語とか計算機を理解するときには、レジスタがどうのとかオペランドがどうのとか、構成を理解するところからはじめると思います。実際、僕もなんとなくの雰囲気は聞いたことありました。でもそれでインタプリタとか VM とかが作れるかというと全然無理ですね。
@7shi さんはまず構成はどうでもいいので、与えられる機械語を 1:1 に対応するアセンブリ言語にただ翻訳する行為を通じて、まず機械語の表現力を学ぶことがとっかかりとして大事とおっしゃっていましたが、実際やってみて強く同感しました。
勉強会では以下のテキストに従って説明 8、練習問題 2 という感じで進んでいって、データシートからバイナリを作成し、ndisasm
という既存の逆アセンブラを使って正解を見つつテスト駆動で逆アセンブラを Haskell で実装する方法をばっちり習得してきました。
Go で書いてみた
ただ、このまま Haskell で書き進めても他の人と同じだし、なんか違う感じにしたいなと思って、かねてから勉強したかった Go で書いてみることにしました。
とりあえず MOV 命令については@7shi さんの Haskell 実装があるので、基本それを移植して完成させました。パターンマッチが無いのが辛いですが、それ以外は特に大きく困ることはなかったです。2 進数の扱いとかは標準ライブラリを使って逃げましたが。。。
8086tiny を目指す
あと、C 言語でたった 800 行程で実装された 8086 の VM であるところの 8086tiny を見つけて興奮してました。動かしてみたら実際 Windows 3.0 が Mac の上で動きましたよ。。。恐ろしい。。。
BIOS とかのめんどくさいところの実装がすでにあるので、大いに活用させてもらいつつ、8086tiny の Go 言語版を目指して残りの命令の逆アセンブラ実装、およびそれが終わったら VM の実装を進めていきたいなと思っています。
なんか色々遠回りしてる感もしますが、コンピュータのいい勉強になっています。