我试图找到一条将替换MOVZX的指令,因为我使用的是EMU8086(模拟不支持MOVZX的8086)。

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

我有什么选择?一条指令就能做到吗?

最佳答案

movzx指令对宽度较小的值进行零扩展以适合较大宽度的寄存器。例如,movzx将用于将16位值移入32位寄存器。 (这与movsx形成对比,除了使用符号扩展名外,它执行相同的操作。当对值进行无符号签名时,将使用movzx;对值进行签名时,则使用movsx。)

如您所指出的,这些指令直到386才被引入,因此,如果您针对的是较早的处理器,则需要找到替代方法。


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

movzx  edx, WORD PTR [bx]


可以替换为:

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


在现代处理器上,这要比movzx慢,但实际上在movzx相对较慢的386和486上会快。当然,在不存在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位值进行零扩展,则可以利用以下事实:可以在x86上独立访问16位寄存器的高8位和低8位,而将高8位简单地置零。例如:

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


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


幸运的是,在这些较旧的体系结构上零扩展的需求比在现代体系结构上要少得多,因为您不必积极地防范部分寄存器停顿和错误的依赖关系。




在评论中,有人担心movzx的所有替代都需要一条以上的指令。当然是这样。如果有一种方法可以在一条指令中完成,则不需要386引入movzx。如果您担心执行速度,请考虑我在上面所说的xor + movmovzx一样快(如果不是可用的话)。



如果您担心指令的数量,请放心,更少的代码不一定意味着更快的代码。实际上,在许多情况下,添加其他指令可以使程序执行更快。如果您要优化特定的代码块,建议您在此处或在Code Review上询问有关此问题的信息(我们在那里需要更多的汇编语言问题!)。

关于assembly - 还有另一条与MOVZX类似但在8086上受支持的指令吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31357528/

10-11 15:41