假设以下 x86-32 指令:
add ebx,1
有(至少)两种方法来组装这个操作码:
81 c3 01 00 00 00
或者
83 c3 01
第一个将 1 保留为 4 个字节的 dword,第二个将 1 保留为一个字节
是否有将 1 保留为 2 个字节的指令?如果没有为什么?
假设以下 x86-32 指令:
add ebx,1
有(至少)两种方法来组装这个操作码:
81 c3 01 00 00 00
或者
83 c3 01
第一个将 1 保留为 4 个字节的 dword,第二个将 1 保留为一个字节
是否有将 1 保留为 2 个字节的指令?如果没有为什么?
您偶然发现了 x86 指令集的一个怪癖。Intel 在 stem 下包含一组指令83
,其第一个操作数是 type Ev
,第二个操作数是一个立即字节,被解释为与操作数相同的大小Ev
。因此对于83 c3 01
,01
被解释为 32 位值;对于66 83 c3 01
, 01 被解释为 16 位值(目标是 16 位ax
寄存器)。push
在词干下编码的助记符6A
在其单个操作数的大小方面的行为方式相同。
您的问题的更广泛的答案是否定的,没有将 16 位常量解释为 32 位常量的编码。
资料来源:我写了一个反汇编程序。
在编程中使用小整数是很常见的——不管目标大小。好处是减少了指令编码。许多指令都支持这一点:IMUL、ADD、ADC、SUB、SBB、AND、CMP 等……此外,寻址模式支持字节大小的符号扩展偏移,以帮助减少代码大小。
至于为什么不这样做:与字节编码的节省相比,我认为增加的节省是最小的。ENTER 指令确实使用 16 位立即数,但它是无符号的并且固定用于更新寄存器 RSP/ESP/SP。
66 81 C3 01 00(在 32 位模式下为“add bx, 01”)可能被认为是它的一个例子。
没有这样的示例不需要覆盖,因为不需要它。第一个示例需要四个字节的原因是它可以跨越整个 4Gb 范围。第二个只使用一个字节,因为它被限制为 +/-128(总共 256 个值)。通过使用覆盖,我们可以将第一个示例限制为 64kb,但实际上它不是两个字节中的一个字节,它仍然是两个字节。