SUB命令(r-imm→r)
レジスタに対するSUB命令です。
0: 2c 7f sub $0x7f,%al 2: 80 eb 7f sub $0x7f,%bl 5: 80 e9 7f sub $0x7f,%cl 8: 80 ea 7f sub $0x7f,%dl b: 66 2d ff 7f sub $0x7fff,%ax f: 66 81 eb ff 7f sub $0x7fff,%bx 14: 66 81 e9 ff 7f sub $0x7fff,%cx 19: 66 81 ea ff 7f sub $0x7fff,%dx 1e: 2d ff ff ff 7f sub $0x7fffffff,%eax 23: 81 eb ff ff ff 7f sub $0x7fffffff,%ebx 29: 81 e9 ff ff ff 7f sub $0x7fffffff,%ecx 2f: 81 ea ff ff ff 7f sub $0x7fffffff,%edx
SUB命令も、al/ax/eaxレジスタについては特別なオペコードを割り当てているようです。
あと、eb/e9/eaというのがあやしい…。つまり、これもMod/RMフィールドのReg/OpeCodeビットの値で、同じオペコードを持つADD命令と区別し、また、R/Mビットでレジスタ番号を指定してるんじゃないか…と予測できます。
で、各ニーモニックについて、ModR/Mフィールドを分解してみました。
命令 | オペコード部 | ModR/Mフィールド | Mod | Reg/OpeCode | R/M | |
---|---|---|---|---|---|---|
sub %al [imm8] | 2C | - | - | - | - | |
sub %bl [imm8] | 80 | EB | 11 | 101 | 101 | |
sub %cl [imm8] | 80 | E9 | 11 | 101 | 001 | |
sub %dl [imm8] | 80 | EA | 11 | 101 | 010 | |
sub %ax [imm16] | 66 2D | - | - | - | - | |
sub %bx [imm16] | 66 81 | EB | 11 | 101 | 101 | |
sub %cx [imm16] | 66 81 | E9 | 11 | 101 | 001 | |
sub %dx [imm16] | 66 81 | EA | 11 | 101 | 010 | |
sub %eax [imm32] | 2D | - | - | - | - | |
sub %ebx [imm32] | 81 | EB | 11 | 101 | 101 | |
sub %ecx [imm32] | 81 | E9 | 11 | 101 | 001 | |
sub %edx [imm32] | 81 | EA | 11 | 101 | 010 |
思った通り、Reg/OpeCodeビットに固定で「101」をセットすることで、同じオペコード「80/81」を持つ他の命令(ADD命令など)と区別しているようです。実際、Intelの資料では、オペコードの「/digit」に「/5」が指定されています(/digitはReg/OpeCodeビットにセットする値)。また、お決まりですが、R/Mビットでレジスタ番号を指定しています。
7 6 5 4 3 2 1 0 +-----------------------------+ | Mod | Reg/ | R/M | | | OpeCode | | +-----------------------------+
SUB命令のフォーマットをまとめると、AL/AX/EAXレジスタについては、
命令 | オペコード | 説明 |
---|---|---|
sub AL imm8 | 2C imm8 | ALレジスタからimm8を引く。 |
sub AX imm16 | 66 2D imm16 | AXレジスタからimm16を引く。 |
sub EAX imm32 | 2D imm32 | AXレジスタからimm32を引く。 |
その他のレジスタについては、
命令 | オペコード | 説明 |
---|---|---|
sub r/m8 imm8 | 80 E8+rb | r/m8からimm8を引く。 |
sub r/m16 imm16 | 66 81 E8+rw | r/m16からimm16を引く。 |
sub r/m32 imm32 | 81 E8+rd | r/m32からimm32を引く。 |