我试图找到一个替换MOVZX
的指令,因为我正在使用EMU8086(模拟不支持MOVZX
的8086)。
我找到的最接近的指令是CBW
,它将值放在寄存器AX
中,但它仅用于签名值。我需要一些适用于无符号值的东西。
我有什么选择?是否可以通过一条指令来完成它?
答案 0 :(得分:3)
movzx
指令零扩展一个宽度较小的值,以适应更大宽度的寄存器。例如,movzx
将用于将16位值移动到32位寄存器中。 (与movsx
形成对比,除了使用符号扩展之外,它会做同样的事情。当值为无符号时,您将使用movzx
,而当值为无符号时,则使用movsx
价值已签署。)
正如您所指出的那样,这些说明直到386才被引入,因此,如果您要定位前一代处理器,那么您需要找到替代方案。
正如其他人在评论中指出的那样,基本策略是首先将归零目标寄存器,然后将中的较小值移动。这将完成与movzx
完全相同的事情。将寄存器归零的明显方法是mov reg, 0
,但使用xor reg, reg
进行it is smaller and faster。因此,代码如:
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 代码并不一定意味着更快的代码。事实上,在许多情况下,添加其他指令可以使您的程序执行得更快。如果您正在尝试优化特定的代码块,我建议您在此处或Code Review上询问有关它的问题(我们需要更多的汇编语言问题!)。 功能