movzx 指令零扩展具有较小宽度的值以适应较大宽度的寄存器。例如,movzx 将用于将 16 位值移动到 32 位寄存器中。 (这与 movsx 形成对比,除了 符号扩展 之外,它做同样的事情。当值是无符号时你会使用 movzx,当值是有符号时你会使用 movsx。)
正如您所指出的,这些指令直到 386 才引入,因此如果您的目标是较早一代的处理器,那么您需要找到替代方案。
正如其他人在 cmets 中指出的那样,基本策略是首先将目标寄存器置零,然后将较小的值移入。这将完成与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 慢,但实际上在 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 位。
幸运的是,这些旧架构对零扩展的需求比现代架构要少得多,因为您不必那么严格地防范部分寄存器停顿和错误依赖。
在 cmets 中,有人担心movzx 的所有替代方案都需要一条以上的指令。当然,这是真的。如果有一种方法可以在一条指令中完成,那么 386 就不需要引入movzx。如果您担心执行速度,请考虑我上面所说的xor+mov 将与movzx 一样快,如果它可用的话,如果不是更快的话。
如果您担心指令的数量,那么请放心,less 代码并不一定意味着 更快 代码。事实上,在很多情况下,添加额外的指令可以让你的程序执行得更快。如果您正在尝试优化特定代码块,我鼓励您在此处或 Code Review 上提出有关它的问题(我们需要更多汇编语言问题!)。