是否有另一个类似于 MOVZX 的指令,但在 8086 上受支持?

Is there another instruction similar to MOVZX, but supported on the 8086?

我正在尝试寻找一条指令来替代 MOVZX,因为我使用的是 EMU8086(它模拟了一个不支持 MOVZX 的 8086)。

我找到的最接近的指令是 CBW,它将值放入寄存器 AX,但它仅适用于有符号值。我需要一些适用于无符号值的东西。

我有哪些选择?是否可以通过一条指令完成?

movzx 指令零扩展 宽度较小的值以适应宽度较大的寄存器。例如,movzx 将用于将 16 位值移动到 32 位寄存器中。 (它与 movsx 形成对比,除了 符号扩展 之外,它做同样的事情。当值是无符号时,你会使用 movzx,而 movsx 当值被签名时。)

正如您所指出的,这些指令直到 386 才被引入,因此如果您的目标是较早一代的处理器,那么您需要寻找替代方案。


正如其他人在评论中指出的那样,基本策略是先将目标寄存器 归零,然后将较小的值移入 。这将完成与 movzx 完全相同的事情。将寄存器清零的明显方法是使用 mov reg, 0,但 使用 xor reg, reg 来完成。因此,代码如下:

movzx  edx, WORD PTR [bx]

可以替换为:

xor    edx, edx
mov    dx,  WORD PTR [bx]

在现代处理器上,这比 movzx 慢,但实际上在 386 和 486 上会更快,其中 movzx 相对较慢。当然,在 movzx 不存在的处理器上,您别无选择。您可以通过更早地发出 xor 指令,将其散布在其他代码中来进一步降低成本。


这种方法的一个显着缺点是您不能对存储在寄存器中的值进行就地零扩展。也就是说,当你有这样的代码时,没有办法使用这个技巧:

movzx  edx, dx

相反,您必须使用临时寄存器:

xor  eax, eax
mov  ax,  dx
mov  dx,  ax    ; optional, if you really needed the result to be in DX


或者,如果您对 8 位值进行零扩展,则可以利用 16 位寄存器的高 8 位和低 8 位可以在 x86 上独立访问这一事实,只需将高 8 位归零.例如:

mov    al, BYTE PTR [bx]
xor    ah, ah
; now read from value in AX

请注意,这适用于就地零扩展——只需将高 8 位归零。但是,此技术不能用于对 16 位值进行零扩展,因为无法仅访问 32 位寄存器的高 16 位。


幸运的是,与现代架构相比,这些旧架构对零扩展的需求要少得多,因为您不必像现代架构那样大力防范部分寄存器停顿和错误依赖。


在评论中,有人担心 movzx 的所有替代方案都需要不止一条指令。当然,这是真的。如果有一种方法可以在一条指令中完成,那么 386 就不需要引入 movzx。如果您担心执行速度,请考虑我上面所说的 xor+mov 将与 movzx 一样快,如果它可用的话,如果不是更快的话。

如果您担心指令数量,请放心,less 代码并不一定意味着 faster 代码。事实上,在很多情况下,添加额外的指令可以让你的程序执行得更快。如果您正在尝试优化特定的代码块,我鼓励您在这里或 Code Review 上提出有关它的问题(我们需要更多的汇编语言问题!)。