[アセンブラ]
アセンブラ(ModR/M)
最近自作のアセンブラを開発しているのだが、もっとも難しい部分について理解が得られたのでまとめておく
ModR/Mの実際の例
- IMUL命令(Signed Multiply)
- 例えば以下のような命令がある、 /r の意図がみなさんわからないのではないでしょうか?
; 0x69 /r iw IMUL r32, imm32
- CMP命令(Compare Two Operands)
- また、次のような命令、 /7 の意図がみなさんわからないのではないでしょうか?
; CMP r/m8, imm8 0x80 /7 ib
ModR/Mの構造
- ModR/M ‐ 通信用語の基礎知識
- 全体の概要についてはこのページをみたほうがよい
- Assembly Programming on x86-64 Linux (06)
- また、このページも役立つ
/rおよび/7の意味
解説をAssembly Programming on x86-64 Linux (06)から引用する
記法 | 解説 |
---|---|
/0 - /7 | ModR/M バイト の reg フィールドの 0 から 7 の数字はオペコードの拡張用に使われる。r/m フィールドだけをオペランドに使用する。 |
/r | 命令には ModR/M バイトが続き、レジスタオペランドと r/m オペランドの両方を使う。 |
cb、cw、cd、cp, co, ct | オペコードの後に 1 バイト(cb)、2 バイト(cw)、4 バイト(cd)、6 バイト(cp)、 8 バイト(co)または 10 バイト(ct)が続く。 |
ib, iw, id, io | オペコード、ModM/R バイト、または SIB の後に続く 1 バイト(ib)、2 バイト(iw)、4 バイト(id)または 8 バイト(io)の定数(即値)。 |
+rb, +rw, +rd, +ro | + の左側のオペコードに加算される 0 から 7 までのレジスタコード。 結果として 1 バイトのオペコードとなる。 |
ModR/Mバイト
- ModR/Mバイトは画像のような構造になっており、それを指定された場合アセンブラはmod/reg/r/mの形でバイナリを吐き出す
- mod
- modは、次のようにr/mの用途を切り替える。
- mod=00: [レジスター+レジスター]
- mod=01: [レジスター+disp8]
- mod=10: [レジスター+disp16/32]
- mod=11: レジスター
- reg(/0 - /7指定の場合)
- regは、/0 - /7を指定された場合はそれをそのまま使う
もちろんこれは10進数表記なので、2進数に直すと以下のようになる。ModR/Mバイトのregフィールドはこれで埋まるわけだ。
/0 - /7 | 2進数表記 |
---|---|
/0 | 000 |
/1 | 001 |
/2 | 010 |
/3 | 011 |
/4 | 100 |
/5 | 101 |
/6 | 110 |
/7 | 111 |
- reg(/0 - /7指定の場合)の実例
- 0x80 /7 ib をアセンブル
; 0x80 /7 ib CMP r/m8, imm8 ; 例 CMP CL,18 ; オペコードは0x80で確定 ; --------------------- ; ModR/Mの値は ; [mod] 11 ; [reg] 111 ; [r/m] 001 ; => "11111001" ; => 0xf9 ; --------------------- ; 18は16進数で0x12 ; --------------------- ; よって、以下がアセンブルされると CMP CL,18 ; 以下のバイナリが出力される 0x80, 0xf9, 0x12
- reg(/r指定の場合)
- regは、レジスタ番号を指定する
つまり、mod2bitに続いて、regとr/mが3bitずつ続くことになる
REGの値 | レジスタ |
---|---|
000 | al ax eax |
001 | cl cx ecx |
010 | dl dx edx |
011 | bl bx ebx |
100 | ah sp esp |
101 | ch bp ebp |
110 | dh si esi |
111 | bh di edi |
- reg(/r指定の場合)の実例
- 0x69 /r iw をアセンブル
; 0x69 /r iw IMUL r32, imm32 ; 例 IMUL ECX,4608 ; オペコードは0x69で確定 ; --------------------- ; ModR/Mの値は ; [mod] 11 ; [reg] 001 ; [r/m] 001 ; => "11001001" ; => 0xc9 ; --------------------- ; 4608は16進数で0x1200 ; リトルエンディアンのため、 0x00, 0x12と並ぶ ; --------------------- ; よって、以下がアセンブルされると IMUL ECX,4608 ; 以下のバイナリが出力される 0x69, 0xc9, 0x00, 0x12
modrm.png