【お知らせ】プログラミング記事の投稿はQiitaに移行しました。

i8086の逆アセンブラ

前回、命令表を作成しました。

今回はオペコードの構造を確認するため逆アセンブラを作ります。

オペランドの分類

写経した命令表をオペランドで分類して並べ替えました。

オペランドのない命令

少しずつ逆アセンブラを実装していきます。

オペランドも接尾辞もない命令
  • 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

まとめ

以上でi8086の全命令を逆アセンブルできるようになりました。

ここまでのコードです。安直に一本のswitchで分岐しています。