使用 g++ -march=x86-64 构建的代码可以在 32 位操作系统上运行吗?

问题描述

我想我对 x86-64/i686 架构和 32 位/64 位操作系统感到困惑。

如果我在 32 位操作系统(例如 Ubuntu 14.04)上使用 g++ 构建应用程序,则 -m64 不是有效选项,我无法构建 64 位二进制文​​件。但是,g++ 不会抱怨使用 -march=x86-64。 (硬件为酷睿 i7。)

然后,如果我在 64 位操作系统(例如 Ubuntu 20.04)上构建,我可以在 -m32-m64 之间切换并构建 32 位或 64 位二进制文​​件。

所以,我的理解是...

-m32-m64 决定了我可以在哪些操作系统上使用二进制文件。 (包括在 64 位操作系统上使用的 32 位二进制文​​件以及适当的库)

并且 -march 定义将用于代码生成的指令集 - 无论它注定要运行的操作系统是什么。

所以我的主要问题是...

鉴于我可以使用 -m32 -march=x86-64 在 32 位操作系统上构建和运行二进制文件,这是否意味着 x86-64 指令可以在 32 位操作系统上使用?位操作系统?

解决方法

不,64 位指令不能在 32 位操作系统下使用(甚至不能在 64 位内核下的 32 位用户空间中使用),这不是 -march=x86-64 的意思。


-march=x86-64 表示目标 CPU 支持 x86-64 保证的基线 ISA 扩展集:SSE2、P6 功能,如 CMOV、CPUID、RDTSC 等。但是如果没有 -m64,代码仍然可以在 32 位模式下工作。

(对于 x86-64 的目标 ISA,它们本身并不是“扩展”。但我们仍然通常说 x86-64 意味着 SSE 和 SSE2,因为这是对那些在 XMM 上运行的指令进行分类的方便方法寄存器。如果我们将 x86-64 本身视为 x86 的扩展,这是有道理的。)

所以 -march=x86-64-march=k8-march=nocona(特定于早期的 x86-64 CPU)非常相似。就像这些选项一样,它对 -m32 完全有效,并不意味着制作 64 位代码。 GCC 仍然知道(来自 -m32)它的目标是 32 位模式(受保护或兼容模式),而不是 64 位长模式。

由于这些模式使用不兼容的机器代码格式,因此在制作 16 位代码以让编译器使用 32 位代码时,您可能期望 -march=i386 的 16 位到 32 位转换完全不同寄存器。在 x86-64 中,64 位寄存器只能用于长模式,不能用于兼容模式或遗留模式的任何子模式(例如保护模式)。见https://en.wikipedia.org/wiki/X86-64#Operating_modes

这里的关键点是,在兼容模式下(在 64 位内核下),32 位进程无法执行在保护模式下(在 32 位内核下)无法执行的任何操作。 x86-64 没有为 32 位进程提供在 64 位内核下运行的优势。 (除了将远 jmp 转换为 64 位代码段,但大多数操作系统不支持这一点,编译器肯定不会发出代码来做到这一点。当然使用完整的 4GB 地址空间,但就实际的机器代码指令什么都没有。)因此,没有任何您希望编译器使用的功能只能在 64 位内核下以 32 位模式运行。


TL:DR:-m32 -march=x86-64 可以解释为“通用 x86-64 CPU 的目标兼容/保护模式”。

实际上它实际上只是意味着“启用这组 ISA 扩展”,并且 该名称对于 GCC 来说没有比 -march=foobarbaz-mtune=intel 更有意义,它只是一个文本字符串调整和 ISA 扩展设置表。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...