当前位置: 首页 > 知识库问答 >
问题:

为什么在64模式下默认操作数大小为32位?

高晋
2023-03-14

我不知道为什么,为什么我不能使用完整的64位空间例如int操作数?和Sign有关吗?或者为什么会有这个限制?(那么,C无符号int是否使用rex.w前缀对int进行操作(正如前面提到的,前缀只适用于特定指令,而不适用于整个段,它应该是(大小,地址或操作数)默认值,并包含在段描述符中)。

我理解正确吗?

共有1个答案

乌鸿宝
2023-03-14

TL:Dr:你有两个独立的问题。1关于C类型大小,另一个关于x86-64机器码如何编码32和64位操作数大小。编码选择是相当任意的,可能会有所不同。但是int是32位的,因为这是编译器开发人员选择的,与机器代码无关。

int是32位的,因为这仍然是一个有用的大小。它使用int64_t内存带宽/缓存占用量的一半。大多数用于64位ISA的C实现都有32位int,包括用于x86-64(x86-64 System V和Windows)的主流ABIs。在Windows上,即使long也是32位类型,可能是为了与为32位编写的代码兼容,这些代码假设了类型大小。

此外,AMD的整数乘法器在当时的32位比64位快一些,这是在Ryzen之前的情况。(第一代AMD64硅是AMD的K8微架构;有关指令表,请参见https://agner.org/optimize/。)

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,或者0x66operand-size将其设置为16。如果不需要R8...R15,这可能会导致更小的机器代码,用于处理无论如何都必须是64位的东西(通常是指针)的代码。

使用R8..R15也需要REX前缀(即使作为寻址模式的一部分),因此需要大量寄存器的代码经常发现自己在大多数指令上使用REX前缀,即使使用默认操作数大小。

很多代码确实使用int来处理很多东西,所以32位操作数大小并不罕见。正如上面提到的,它有时更快。因此,让最快的指令最紧凑是有意义的(如果你避免R8D..R15D)。

如果在32位和64位模式下,相同的操作码以相同的方式解码而没有前缀,它也可能让解码器硬件更简单。我想这是AMD选择这个设计的真正动机。他们当然可以清理很多x86的缺点,但选择不这样做,可能也是为了保持更类似于32位模式的解码。

https://en.wikipedia.org/wiki/x86-64#opmodes有一个有用的模式表,包括长模式(以及64位与32位和16位compat模式)与旧模式(如果您引导的内核不支持x86-64)。

在64位模式下,有些操作码是不同的,push/pop和其他堆栈指令操作码的操作数大小默认为64位。

在这种模式下,32位机器码将不正确地解码。例如,0x40在compat模式下是inc eax,但在64位模式下是REX前缀。请参阅x86-32/x86-64多语机器代码片段,该片段在运行时检测64位模式?举个例子。

  • x86-x64中不同或完全删除的x86 32位操作码
  • 程序集:为什么某些x86操作码在x64中无效?

64位模式解码主要类似于共享解码器中的晶体管,而不是二进制兼容性。对于像03 add r,r/m这样的操作码,解码器只有2个与模式相关的默认操作数大小(16或32位)可能会更容易,而不是3。只有像push/pop这样的操作码才有特殊的大小写。(还要注意,rex.w=0不允许对push r32进行编码;操作数大小保持在64位。)

AMD的设计决策似乎一直集中在尽可能多地共享解码器晶体管上,也许是为了防止AMD64没有流行起来,他们被困在支持它而没有人使用它。

 类似资料:
  • 问题内容: 限制Java JVM上Permgen空间大小的目的是什么?为什么不总是将其设置为等于最大堆大小?Java为什么默认为这么少的64MB?他们是否正在试图通过这种方式迫使人们注意代码中的Permgen问题? 如果我的应用使用85MB的permgen,那么将其设置为96MB可能是安全的,但是如果它只是主堆的一部分,为什么还要设置得如此之小呢?允许JVM使用堆允许的PermGen效率不高吗?

  • 我阅读了关于64位模式下地址计算的英特尔手册。假设我们有64位模式,默认地址大小是64位。另外,假设所讨论的指令前面有地址大小覆盖前缀,因此地址大小变成32位。 现在,假设指令用寄存器号0(RAX/EAX/AX...)指定的地址编码内存操作数。 现在我不完全理解的是,CPU是只查看eax值并在内部扩展它以形成“本地”64位地址,还是查看整个rax值并将其截断到有效的32位范围(例如,rax包含类似

  • 问题内容: 我已经从python.org的python-2.7.amd64.msi包中安装了Python 2.7。它可以正确安装并运行,但尽管安装程序是64位安装程序,但似乎处于32位模式。 如何安装Python,使其真正以64位模式运行? 问题答案: 请参阅此处的讨论。它来自2.6.1,但似乎仍然适用。至少在任何地方我都没有看到相反的证据。事由(从该链接引用)是: 这是设计使然。微软决定用“不定

  • 问题内容: 正如甲骨文所说 来自 Oracle Docs的 参考 扩展基元转换19个特定于基元类型的转换称为扩展基元转换: 字节到short,int,long,float或double 短至int,long,float或double char转换为int,long,float或double int转换为long,float或double 多长时间浮动或翻倍 ? 浮动到两倍 如果浮点数具有32位,而

  • 加宽基元转换19基元类型上的特定转换称为加宽基元转换: 字节到短、int、long、float或double 短到int、long、float或double 字符为int、long、float或double 从int到long、float或double 长时间浮动还是加倍? 浮动到双倍 如果浮点数为32位,而长点数为64位,那该如何被认为是加宽的呢?这难道不应该被认为是缩小范围吗?

  • 问题内容: 最近,我一直在对我公司的数据库产品的写入性能进行一些基准测试,并且发现仅切换到64位JVM可以使性能持续提高20-30%。 我不允许详细介绍我们的产品,但基本上它是面向列的数据库,已针对存储日志进行了优化。基准测试包括向其提供几GB的原始日志,并确定分析它们并将其作为结构化数据存储在DB中所需的时间。CPU和I / O的处理非常繁重,尽管很难说是什么比例。 有关设置的一些注意事项: 两