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を引く。