SH-3のBrainfuckEXEコンパイラをNode.jsで作る。半分まで。
アセンブリを16進数でNode.jsに手入力して、それをバイナリでファイルに吐くという簡単なお仕事。
+-<>.まで対応する。たぶんKernel VMには間に合わない。
流れ
DLLを呼び出す命令をBFまわりの命令の前にレジスタで定義して、値を入れておく。 BRA命令でその部分はジャンプする。
これは、C言語をsh-elf-gccでコンパイルして、sh-elf-objdumpで逆アセンブルすると、アセンブリがどういう使い方をなされているかがなんとなく分かる。
— 炭鉱ハッカー shigemk2 (@shigemk2) 2014, 10月 12
なお、BRA命令のあとにはNOP命令が来る。これを遅延スロットというが、どこまでジャンプするかはアセンブラで指定している。
SH-3 bra命令のジャンプ先の数え方 pic.twitter.com/ftRAknE92x
— 炭鉱ハッカー shigemk2 (@shigemk2) 2014, 10月 12
R8-R13はPermanent Registersと呼ばれ、値が不変であることから、putcharやgetcharなどの命令はR8-R11に格納する。
ハンドアセンブル pic.twitter.com/wUUU22F6QE
— 炭鉱ハッカー shigemk2 (@shigemk2) 2014, 10月 12
関数の初期化とレジスタへと代入でDLL呼び出しを楽にする pic.twitter.com/ErwiEzlFBC
— 炭鉱ハッカー shigemk2 (@shigemk2) 2014, 10月 12
例によってファイルサイズがデカすぎるとうまくEXEコンパイルしてくれないので、もろもろのヘッダの値を修正する pic.twitter.com/Kgi0rFujZu
— 炭鉱ハッカー shigemk2 (@shigemk2) 2014, 10月 12
binutilsでsh-pe用のgccはまともに使えないからsh-elfで代用する pic.twitter.com/7GSS4XVabf
— 炭鉱ハッカー shigemk2 (@shigemk2) 2014, 10月 12
gccがbinutilsのパッケージを呼んでる話 pic.twitter.com/Qd2R77jCIy
— 炭鉱ハッカー shigemk2 (@shigemk2) 2014, 10月 12
やっている作業はまあだいたいこんな感じ。
sh-elfでコンパイル、逆アセンブルしたものをJSに突っ込んでEXEコンパイルして、そらをsh-peで逆アセンブルする pic.twitter.com/BuvUJExmHK
— 炭鉱ハッカー shigemk2 (@shigemk2) 2014, 10月 12
CPU-ファイルフォーマット、みたいな感じ。
SH-PEとか、SH-ELFとか。なお、fileコマンドでファイルの形式を知ることが出来る。
sh-peでもsh-elfでもCPUは一緒なので、出てくるアセンブラも同じ pic.twitter.com/m5hc7WN948
— 炭鉱ハッカー shigemk2 (@shigemk2) 2014, 10月 12
PEとELFの大まかな構造の違い pic.twitter.com/UTigYg6Nq1
— 炭鉱ハッカー shigemk2 (@shigemk2) 2014, 10月 12
gccでコンパイルするときにOオプションをつけると最適化してくれる。O2ってやるともっと最適化してくれる。gオプションをつけると逆アセンブル時にデバッグ情報を付与してくれる。
+部分のアセンブル pic.twitter.com/OvL8kCT9g1
— 炭鉱ハッカー shigemk2 (@shigemk2) 2014, 10月 12
完成品(未完成)
EXEコンパイラ
makebrainfuckexe-sh3.2014101222.js
BFコード
実行結果
スクリーンショットはXPCEを使用。