バイナリをつつく9ー電波ソムリエ1
とはいえ、やっぱり難しい命令は嫌だからHLTの次に簡単そうな命令を探すピヨ。
えっと、これはどうかな?PUSH(Push Word or Doubleword onto the Stack)
うわぁ、正式名長すぎる。
では早速PUSH君をいつものマニュアルのA-61バイトのオペコード・マップ(左側)で調べよう。 この表によると、5行目の0~7列は全てPUSH君に関する事で、プッシュするレジスタが違うだけだ。 さらにオペコード・マップ(右側)を見るとPOPとPUSHが対照的に決まっている。
Intelさん、粋な計らいするねぇー。これは判りやすいピヨ。
そこには、eAXとか変なレジスタが書いてあるけど、これは僕がレジスタを忘れていたのじゃない。 これは、CPUが32ビットならばEAX、16ビットならばAXという意味の記号だよ。
じゃあこれ簡単だから実装してしまおう。
ピヨッとその前に、オペコードの情報が簡単にわかるメソッドがあれば便利だと思わない?
あれば毎回調べなくてもいいしね。
ということで、CPUオブジェクトにstaticメソッドを実装してみた。
実装の抜粋
public static OpeCodeInfo SearchOpeCode( byte value ) {
OpeCodeInfo info = new OpeCodeInfo( value ); //オペコード・マップの情報
byte row = ( byte ) ( value & 0x11110000 ); //バイトから行を抽出
byte col = ( byte ) ( value & 0x00001111 ); //バイトから列を抽出
//途中省略
switch ( row ) {
case 5:
switch ( col ) {
#region Push
case 0:
info.Name= CommandName.PUSH; //命令の名前
info.NextType = NextInfoType.VaryRegister; //レジスタ未決定
info.OneReg = Register.eAX; //EAXまたはAXであることを示す
break;
//途中省略
#region Pop
case 8:
info.Name = CommandName.POP; //命令の名前
info.NextType = NextInfoType.VaryRegister; //レジスタ未決定
info.OneReg = Register.eAX; //EAXまたはAXであることを示す
break;
//途中省略
}
このコードを読んだみんなはOpeCodeInfo構造体のNextTypeプロパティが気になると思う。このプロパティを設定したわけは、次に必要な情報が色々あるからなんだ。
実例としてADD命令を考えてみよう。
この命令は、ADD EAXレジスタ 32ビットの即値 という場合もあるし ADD 任意の16ビットレジスタ 8ビットの即値 などピね。 他にもいろいろな場合がある。1と0だけで判断しているからいっぱい必要になるんだね。これら様々なバリエーションの構造体を定義していれば面倒くさいし、クラスにして関数の戻り値の型を抽象型にしても、キャストばかり必要となってしまう。
だから僕は、OpeCodeInfo構造体に次にどんな種類の情報が必要なのか定義することにしたんだ。 じゃあ、早速PUSHとPOPの動作を実装してみよう!っといいたいところだけど、先ほどのADD命令のような命令フォーマットの場合どうするかを先に考えておきたいと思う。
今晩はこれにておしまい。次回まで少し待ってね。