简单指令编码

Simple instruction encode

让我们采用以下汇编指令:

add    %cl,%bl

二进制编码为:00 cb00000000 11001011。将 cb 放入 ModR/M 位域,它看起来像:

  1   1   0   0   1   0  1   1
+---+---+---+---+---+---+---+---+
|  mod  |    reg    |    r/m    |
+---+---+---+---+---+---+---+---+

并且,客栈查找register field here我们得到:

而且,我相信 000000dsadd 指令,而 d=s=0 因为它们都是寄存器。这是对该指令编码方式的正确理解吗?此外,对于 'full encoding' 方案,以下是否准确(以字节而不是位为单位):

[empty]         0x0         0b11001011     [empty]        [empty]          [empty]
_ _ _ _        _ _             _              _           _ _ _ _          _ _ _ _
Prefix      Instruction    Mod-reg-r/m      Scale       displacement      immediate

我在尝试 'decoding' 指令时是否遗漏了什么?

是的,看起来不错。

用于编码 op r/m, rop r, r/m 以及 8 位与 16/32 位的一般模式(用于可追溯到 8086 的“传统”ALU 指令)确实使用低常规模式中的 2 位操作码字节,但没有必要依赖它。

英特尔在他们的第 2 卷手册中确实完整地记录了每条指令的每种编码的确切情况。请参阅 Op/En 列和 add for example. (See also https://ref.x86asm.net/coder64.htm 的操作数编码 table,其中还指定了每个操作码的操作数)。这些都让您知道哪些操作码采用 ModRM 字节,哪些不采用。

这些当然要用Intel-syntax命令。尝试遵循手册和教程,同时使用 AT&T 语法,这种语法颠倒了 operand-list 与 Intel 和 AMD 手册的顺序,这让您的生活变得更加复杂。

例如00 /rlisted作为MR操作数编码,从table中我们可以看出是操作数1=ModRM:r/m (r, w),所以是读写的,编码为r/m 字段。操作数 2 = ModRM:reg (r),因此它是由 reg 字段编码的 read-only 源。

有趣的事实:00 00add [rax], al,或 AT&T add %al, (%rax)

请注意,您可以要求 GAS 选择任一编码:

{load}  add    %cl,%bl        # 02 d9
{store} add    %cl,%bl        # 00 cb

另见