今回はCMP命令とJB命令を使って条件分岐を行う。CMP命令は2つのオペランドを使い引き算を行って、フラグレジスタを更新する。ソースオペランドがデスティネーションオペランドより小さいとか大きいとか、同じ値だとかの情報をフラグレジスタに設定する。引き算の結果はレジスタには保存されない。またJB命令はフラグレジスタのCarryフラグを見てジャンプするかどうかを決める。前に行った引き算でソースオペランドがデスティネーションオペランドより小さい場合(1-2や3-5など)などを行った場合に設定される。そして今回実行するプログラムは
comp_jb
で、中身は
MOV AL, 0x04 CMP AL, 0x05 JB move16 fin: JMP fin move16: MOV AL, 0x10 JMP fin
をnasmでアセンブルしたものである。内容はほぼ前回の足し算と同じで、ADDやJEの代わりに今回はCMP命令とJBを使って分岐を行っている。これを実行するために作ったファイルは
./vm/instruction/cmp/CMPALImm8.rb ./vm/instruction/jump/JB.rb
で、ソースコードは
CMPALImm8.rb
require "./vm/util/FlagCheck.rb" require "./vm/register/RegisterIndex.rb" include RegisterIndex class CMPALImm8 def execute(vm) al = vm.get_register8(EAX) value = vm.get_code8(1) result = al - value FlagCheck.add_check(al, value, result, vm.eflags, 8) vm.add_eip!(2) end end
JB.rb
class JB def execute(vm) if(vm.eflags().carry?()) then vm.add_eip!(vm.get_signed_code8(1)) end vm.add_eip!(2) end end
となっている。これを実行するために、InstructionMapを変更する。
@instructions[0x3C] = CMPALImm8.new() @instructions[0x72] = JB.new()
requireも忘れずに
require "./vm/instruction/cmp/CMPALImm8.rb" require "./vm/instruction/jump/JB.rb"
これでcomp_jbを読み込んで実行できるようになる。comp_jbを読み込むと、ALに4が代入され、その後CMPでALと5の比較が行われる。今回はソースオペランドのALの方が小さいため、Carryフラグが立ちJB命令でmove16にたどり着く。あとは前回のADDと同じである。次回はHello World!のプログラムを読み込ませるとしよう。説明が大変そうだけど頑張る