TL:DR:您有两个单独的问题。1 关于 C 类型大小,另一个关于 x86-64 机器代码如何编码 32 与 64 位操作数大小。编码选择是相当随意的,可能会有所不同。但是int
是 32 位,因为这是编译器开发人员选择的,与机器代码无关。
int
是 32 位的,因为这仍然是一个有用的大小。它使用一半的内存带宽/缓存占用int64_t
。大多数 64 位 ISA 的 C 实现都有 32-bit int
,包括 x86-64 的主流 ABI(x86-64 System V 和 Windows)。在 Windows 上,evenlong
是 32 位类型,大概是为了与为 32 位编写的代码兼容,这些代码对类型大小做出了假设。
此外,当时 AMD 的整数乘法器在 32 位上比 64 位要快一些,直到 Ryzen 都是这种情况。(第一代 AMD64 芯片是 AMD 的 K8 微架构;请参阅https://agner.org/optimize/获取指令表。)
在 x86-64 中使用 32 位寄存器/指令的优点
x86-64 是 AMD 在 2000 年左右设计的,即 AMD64。英特尔致力于安腾,但没有参与;x86-64 的所有设计决策都是由 AMD 架构师做出的。
AMD64 在编写 32 位寄存器时设计为隐式零扩展,因此可以有效地使用 32 位操作数大小,而不会出现 8 位和 16 位模式下的部分寄存器恶作剧。
TL:DR:CPU 有充分的理由希望以某种方式提供 32 位操作数大小,并且 C 类型系统具有易于访问的 32 位类型。 使用int
它是很自然的。
如果您想要64 位操作数大小,请使用它。(然后将其描述为long long
或[u]int64_t
,如果您正在为您的 asm 全局变量或函数原型编写 C 声明)。没有什么能阻止您(除了需要您以前可能没有的 REX 前缀的代码量更大)。
所有这些都是与 x86-64 机器代码如何编码 32 位操作数大小完全不同的问题。
AMD 选择将 32 位设为默认值,而 64 位操作数大小需要 REX 前缀。
他们本可以另辟蹊径,将 64 位操作数大小设为默认值,要求 REX.W=0 将其设置为 32,或0x66
操作数大小将其设置为 16。这可能导致代码的机器代码更小如果不需要 r8..r15,它主要操作必须是 64 位的东西(通常是指针)。
使用 r8..r15 也需要 REX 前缀(即使作为寻址模式的一部分),因此需要大量寄存器的代码通常会发现自己在大多数指令上使用 REX 前缀,即使使用默认操作数 -尺寸。
很多代码确实int
用于很多东西,所以 32 位操作数大小并不少见。如上所述,它有时会更快。 所以让最快的指令最紧凑是有道理的(如果你避免使用 r8d..r15d)。
如果相同的操作码在 32 位和 64 位模式下以相同的方式解码而没有前缀,它也可能让解码器硬件更简单。 我认为这是 AMD 做出这种设计选择的真正动机。他们当然可以清理很多 x86 缺陷,但选择不这样做,可能也是为了保持解码更类似于 32 位模式。
看看您是否会为默认操作数大小为 64 位的 x86-64 版本保存整体代码大小可能会很有趣。例如调整编译器并编译一些现有的代码库。但是,您可能希望教它的优化器支持 64 位操作数而不是 32 位的传统寄存器 RAX..RDI,以尽量减少需要 REX 前缀的指令数量。
(即使您只关心低 32 位,许多指令add
也可以安全地用于 64 位操作数大小,尽管高位垃圾会影响 FLAGS 结果。)imul reg,reg
回复:评论中的错误信息:与 32 位机器代码兼容与此无关。 64 位模式与现有的 32 位机器码二进制不兼容;这就是 x86-64 引入新模式的原因。64 位内核在兼容模式下运行 32 位二进制文件,其中解码的工作方式与 32 位保护模式完全相同。
https://en.wikipedia.org/wiki/X86-64#OPMODES有一个有用的模式表,包括长模式(以及 64 位与 32 和 16 位兼容模式)与传统模式(如果你启动一个不支持 x86-64 的内核)。
在 64 位模式下,一些操作码是不同的,对于push
/pop
和其他堆栈指令操作码,操作数大小默认为 64 位。
在该模式下,32 位机器代码将无法正确解码。eg处于兼容0x40
模式inc eax
,但 REX 前缀处于 64 位模式。请参阅在运行时检测 64 位模式的 x86-32 / x86-64 多语言机器代码片段?例如。
还
64 位模式解码大多类似地是在解码器中共享晶体管的问题,而不是二进制兼容性。03 add r, r/m
据推测,对于解码器来说,对于像,而不是 3 这样的操作码只有 2 个与模式相关的默认操作数大小(16 位或 32 位)会更容易。只有像push
/pop
这样的操作码的特殊情况才能保证它。(另请注意,REX.W=0 不允许您进行编码push r32
;操作数大小保持在 64 位。)
AMD 的设计决策似乎一直专注于尽可能多地共享解码器晶体管,也许以防万一 AMD64 没有流行起来,并且在没有人使用它的情况下被困在支持它的情况下。
他们本可以做很多微妙的事情来消除 x86 令人讨厌的遗留怪癖,例如setcc
在 64 位模式下创建一个 32 位操作数大小的指令,以避免首先需要异或归零。或者 CISC 的烦恼,比如在零计数移位后标志保持不变(尽管 AMD CPU 比英特尔更有效地处理这个问题,所以他们可能故意把它留在里面。)
或者他们认为细微的调整可能会损害 asm 源代码移植,或者在短期内使编译器后端更难支持 64 位代码生成。