今日はゼロフラグを利用した条件分岐を行う。本来ならCMP命令などを使うのだが今回は手抜きでADD命令でゼロフラグを更新する。読み込むプログラムはこちら
add_je
内容は
MOV AL, 0x00 ADD AL, 0x00 JE mov16 loop: JMP loop mov16: MOV AL, 0x10 JMP loop
をnasmでアセンブルしたもの。単純にALに0を代入して、その後ALに0を足している。そしてこの演算の結果ゼロフラグが立っていればJE(別名JZ)でmov16に進んで16(0x10)をALに代入して無限ループに入る。ゼロフラグが立ってない場合はmov16にいかずにそのまま無限ループに入る。これをエミュレータで実行するために./vm/instruction/jump/JE.rbを作成する。
JE.rb
class JE def execute(vm) if(vm.eflags().zero?()) then vm.add_eip!(vm.get_signed_code8(1)) end vm.add_eip!(2) end end
内容は簡単で、EFlagsのゼロフラグが立っていればプログラムカウンタの値にオペコードの次の値を加算している。その後、命令長である2をプログラムカウンタに足している。これを実行するためにInstructionMapに変更を加える
@instructions[0x74] = JE.new()
requireも忘れずに
require "./vm/instruction/jump/JE.rb"
この変更を加えれば実行できるのだが値の確認をするためにVMクラスのexecute!でEAXの値を出力しておく
def execute!() code = get_code8() instruction = @instructions.getInstruction(code) if instruction == nil then raise NotImplementedException, "Not Implmeneted 0x" << code.to_s(16) end instruction.execute(self) #命令コードと実行したクラスを表示 puts "0x" << code.to_s(16) << ": " << instruction.class().to_s() puts "EAX = 0x" + @registers[EAX].to_s(16) end
これで無限ループに入った後にプログラムを止めれば、AL(EAXの一番下の8bit)が16(0x10)になっているのを確認できるはず。あとゼロフラグが立たないプログラムも載せておく
add_jne
内容は
MOV AL, 0x01 ADD AL, 0x00 JE mov16 loop: JMP loop mov16: MOV AL, 0x10 JMP loop
このプログラムではゼロフラグが立たないためmov16にはいかずにALには0x01が入ったまま無限ループに入る。次回は引き算かCMP命令を扱おうと思う