问题描述
在 x86-64 英特尔手册导览,我读了
也许最令人惊讶的事实是,MOV EAX, EBX
等指令会自动将 RAX
寄存器的高 32 位清零.
同一来源引用的英特尔文档(3.4.1.1 General-Purpose Registers in 64-Bit Mode in manual Basic Architecture)告诉我们:
The Intel documentation (3.4.1.1 General-Purpose Registers in 64-Bit Mode in manual Basic Architecture) quoted at the same source tells us:
- 64 位操作数在目标通用寄存器中生成 64 位结果.
- 32 位操作数生成 32 位结果,零扩展到目标通用寄存器中的 64 位结果.
- 8 位和 16 位操作数生成 8 位或 16 位结果.目标通用寄存器的高 56 位或 48 位(分别)不会被操作修改.如果 8 位或 16 位运算的结果用于 64 位地址计算,请明确将寄存器符号扩展到完整的 64 位.
在 x86-32 和 x86-64 汇编中,16 位指令如
In x86-32 and x86-64 assembly, 16 bit instructions such as
mov ax, bx
不要表现出这种eax的高位字被归零的奇怪"行为.
don't show this kind of "strange" behaviour that the upper word of eax is zeroed.
因此:引入这种行为的原因是什么?乍一看似乎不合逻辑(但原因可能是我习惯了 x86-32 汇编的怪癖).
Thus: what is the reason why this behaviour was introduced? At a first glance it seems illogical (but the reason might be that I am used to the quirks of x86-32 assembly).
推荐答案
我不是 AMD 或代表他们,但我会以同样的方式做.因为将上半部分归零不会对先前的值产生依赖性,所以 CPU 将不得不等待.如果不这样做,注册重命名机制基本上会失效.
I'm not AMD or speaking for them, but I would have done it the same way. Because zeroing the high half doesn't create a dependency on the previous value, that the CPU would have to wait on. The register renaming mechanism would essentially be defeated if it wasn't done that way.
通过这种方式,您可以在 64 位模式下使用 32 位值编写快速代码,而不必一直显式地打破依赖关系.如果没有这种行为,64 位模式下的每条 32 位指令都必须等待之前发生的某些事情,即使那部分几乎永远不会被使用.(使 int
64 位会浪费缓存占用空间和内存带宽;x86-64 最有效地支持 32 位和 64 位操作数大小)
This way you can write fast code using 32-bit values in 64-bit mode without having to explicitly break dependencies all the time. Without this behaviour, every single 32-bit instruction in 64-bit mode would have to wait on something that happened before, even though that high part would almost never be used. (Making int
64-bit would waste cache footprint and memory bandwidth; x86-64 most efficiently supports 32 and 64-bit operand sizes)
8 位和 16 位操作数大小的行为很奇怪.依赖疯狂是现在避免使用 16 位指令的原因之一.x86-64 从 8 位的 8086 和 16 位的 386 继承了这一点,并决定让 8 位和 16 位寄存器在 64 位模式下的工作方式与在 32 位模式下的工作方式相同.
The behaviour for 8 and 16-bit operand sizes is the strange one. The dependency madness is one of the reasons that 16-bit instructions are avoided now. x86-64 inherited this from 8086 for 8-bit and 386 for 16-bit, and decided to have 8 and 16-bit registers work the same way in 64-bit mode as they do in 32-bit mode.
另见 为什么 GCC 不使用部分寄存器?真实 CPU 如何处理对 8 位和 16 位部分寄存器的写入(以及对完整寄存器的后续读取)的详细信息.
See also Why doesn't GCC use partial registers? for practical details of how writes to 8 and 16-bit partial registers (and subsequent reads of the full register) are handled by real CPUs.
这篇关于为什么 32 位寄存器上的 x86-64 指令将整个 64 位寄存器的上半部分归零?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!