前回、命令表を作成しました。
今回はオペコードの構造を確認するため逆アセンブラを作ります。
オペランドのない命令
少しずつ逆アセンブラを実装していきます。
オペランドも接尾辞もない命令
- daa, das, aaa, aas, cbw, cwd, wait, pushf, popf, sahf, lahf, ret, retf, into, iret, xlat, lock, hlt, cmc, clc, stc, cli, sti, cld, std
オペランドはなく接尾辞がある命令
- movsb/movsw, cmpsb/cmpsw, stosb/stosw, lodsb/lodsw, scasb/scasw, repnz/repz
オペコードにオペランドが決め打ちで含まれている命令
- int3 (nasm流にint3とint 3を区別)
- in al/ax, dx
- out dx, al/ax
オペコードにレジスタが含まれている命令
- inc, dec, push, pop
- axとのxchg(ax同士はnop)
- セグメントプレフィックス
2バイトでオペランドのない命令
- aam, aad
オペランドが固定長の命令
分岐命令
- jo, jno, jb/jnae, jnb/jae, je/jz, jne/jnz, jbe/jna, jnbe/ja, js, jns, jp/jpe, jnp/jpo, jl/jnge, jnl/jge, jle/jng, jnle/jg
- loopnz/loopne, loopz/loope, loop
- jcxz
- jmp short
割り込み命令
- int
入出力命令
- in, out
16バイト
- mov [addr], al/ax
- mov al/ax, [addr]
- ret n
- retf n
- call
- jmp (near)
FAR
- callf, jmpf
AL/AXと即値
- add, or, adc, sbb, and, sub, xor, cmp, test
レジスタと即値
- mov reg, imm
mod r/m
アドレスを指定する部分はmod r/mと呼ばれる方式でバイナリにエンコードされます。16bitではどのレジスタでもアドレス指定に使えるわけではありませんが、32bit化されたときに拡張されます。
レジスタとmod r/mの方向とサイズを指定
- add, or, adc, sbb, and, sub, xor, cmp, mov
レジスタとmod r/mのサイズを指定
- test, xchg
レジスタとmod r/m
- lea, les, lds
セグメントレジスタとmod r/m
- mov
mod r/mのみ
- pop
mod r/mとシフト回数
- rol, ror, rcl, rcr, shl/sal, shr, sar
mod r/mとサイズ
- not, neg, mul, imul, div, idiv
- inc, dec
mod r/mのみ (FF)
- call, callf, jmp, jmpf, push
エスケープ
- esc(FPU用の予約命令)
mod r/mと即値のサイズを指定
- add, or, adc, sbb, and, sub, xor, cmp
- mov, test