1

X32 允许使用在 x86_64 处理器上运行的 32 位整数、长整数和指针来编写程序。在某些用例下,使用 X32 有很多好处。(X32 与 X86 或 X64 不同;有关详细信息,请参阅x86、x32 和 x64 架构之间的差异)。

似乎某些 Windows Enterprise Server 支持 X32,但我无法找到有关它的更多信息。这基于一些英特尔 PDF,例如面向智能系统的基于英特尔® 至强® 处理器 E5-2400 系列的平台

用于智能系统操作系统支持的基于英特尔® 至强® 处理器 E5-2400 系列的平台

微软关于预定义宏的文档列出了常见的可疑对象,例如_M_X64_M_AMD64. 但它似乎没有讨论 X32 的架构选项。

如果 Microsoft 支持 X32,那么我怀疑这将是一个类似于大地址空间感知或终端服务感知的选项。

Microsoft 是否真的支持 X32(相对于 X86 和 X64)?

  • 如果是这样,我如何确定何时在 Windows 下选择了 X32?
  • 如果不是,那么英特尔为什么要专门为 Windows 调用 X32 平台呢?
4

5 回答 5

4

问题

Microsoft 是否真的支持 X32(相对于 X86 和 X64)?

TL;DR 答案

答案是“不,Microsoft 不支持它”。预处理器宏不会导致 X32 的任何标识,命令行选项和 IDE 选项不存在,并且标识此类编译器的字符串不存在。


长答案——第一部分

“X32 没有标头字符串”

无视以下事实:

  • 不存在此类功能的官方文档,
  • Visual Studio 中没有选项或cl.exe /?启用/禁用它存在,并且
  • strings -el clui.dll没有显示出这种选择的迹象,

strings -el "%VCINSTALLDIR%\bin\1033\clui.dll" | find "Microsoft (R)"也没有显示匹配标头字符串的迹象:

4Microsoft (R) C/C++ Optimizing Compiler Version %s
-for Microsoft (R) .NET Framework version %s
(Microsoft (R) C/C++ Optimizing Compiler
FMicrosoft (R) C/C++ Optimizing Compiler Version %s for MIPS R-Series
)Microsoft (R) MIPS Assembler Version %s
CMicrosoft (R) C/C++ Optimizing Compiler Version %s for Renesas SH
<Microsoft (R) C/C++ Optimizing Compiler Version %s for ARM
:Microsoft (R) C/C++ Standard Compiler Version %s for x86
<Microsoft (R) C/C++ Optimizing Compiler Version %s for x86
GMicrosoft (R) 32-bit C/C++ Optimizing Compiler Version %s for PowerPC
@Microsoft (R) C/C++ Optimizing Compiler Version %s for Itanium
<Microsoft (R) C/C++ Optimizing Compiler Version %s for x64
>Microsoft (R) C/C++ Optimizing Compiler Version %s for ARM64
Microsoft (R) MIPS Assembler

bin\x86_amd64\1033\clui.dllandbin\x86_arm\1033\clui.dll文件中可以看到相同的输出,因此并不是一个文件根本没有包含它。


长答案——第二部分

“Windows 不做数据模型”

让我们假设它做到了。你将如何检测它?在 GLIBC 的情况下,__ILP32__为 x32 和 x86 定义,而__LP64__为 amd64 定义,表示使用的数据模型。此外,__x86_64__将针对 AMD64 架构进行定义。如果__x86_64__已定义且__ILP32__已定义,则您使用的是 X32 ABI,否则您使用的是 AMD64 ABI。对于 C 来说,这才是最重要的。如果您使用的是汇编代码,这就是 X32 ABI 和 x86 ABI 之间的区别很重要的地方,因此检查__x86_64__以确定目标体系结构是 64 位并检查__ILP32__以确定是 32 位还是 64 位 ABI利用。例如:

#ifdef __x86_64__
# ifdef __ILP32__

// Use X32 version of myfunc().
extern long myfunc_x32 (const char *);
long (*myfunc)(const char *) = myfunc_x32;

# else /* !__ILP32__ */

// Use AMD64 version of myfunc().
extern long myfunc_amd64 (const char *);
long (*myfunc)(const char *) = myfunc_amd64;

# endif /* __ILP32__ */

/* !__x86_64__ */
#elif defined __i386__

// Use x86 version of myfunc().
extern long myfunc_x86 (const char *);
long (*myfunc)(const char *) = myfunc_x86;

/* !__i386__ */
#else

// Use generic version of myfunc() since no optimized versions are available.
long myfunc(const char *);

#endif /* __x86_64__ */

但是,在 Windows 上没有指示数据模型的宏。您针对以下架构之一:

  • 32 位 x86 ( _M_IX86)
  • 64 位 AMD64 ( _M_AMD64/ _M_X64)
  • (32 位?)ARM ( _M_ARM)

理论上可以用_M_AMD64and_M_X64独立判断X32是否存在,但如果_M_AMD64定义了,_M_X64也定义了。


长答案——第三部分

“坏消息”

最后,在搜索到任何东西(甚至可能是早已被遗忘的材料)之后,没有证据表明 Windows 已经支持或将支持像 Linux 这样的 X32 ABI 的编码。预处理器宏无助于识别 X32,命令行选项和 IDE 选项不存在,识别此类编译器的字符串也不存在。


长答案——新的希望破灭了

“这些不是您要查找的宏”

可以假设使用当前存在的宏进行检查,但在这种情况下它没有帮助,因为 Windows 的 X32 不存在。它与 GLIBC 检查没有什么不同,尽管如果__ILP32__未定义则启用 X32,而不是启用 X32 _M_X64

#ifdef _M_AMD64
# ifndef _M_X64
#  define ABI_STR "X32"
# else
#  define ABI_STR "AMD64"
# endif
#elif defined _M_IX86
# define ABI_STR "X86"
#else
# error unsupported CPU/architecture
#endif

当然,如果_M_AMD64定义了,那么_M_X64也定义了,进一步强化了 Windows 没有 X32 的证据。

于 2015-09-20T16:04:17.873 回答
2

Windows 没有x32 ABI。但是,它有一个功能,即仅在低 2GB 的地址空间中为您提供内存。只需禁用该/LARGEADDRESSAWARE标志(默认情况下,它为 64 位二进制文​​件启用),然后您可以在 64 位应用程序中使用 32 位指针

这些二进制文件中的用户空间指针会将最高位归零,因此它本质上类似于 Linux 上的 x32 ABI。long在 Windows 中一直是 32 位类型,因此它也与在 x32 ABI 中相同,其中long指针是 32 位宽

默认情况下,基于 Microsoft Windows 的 64 位应用程序具有数 TB 的用户模式地址空间。有关精确值,请参阅Windows 和 Windows Server 版本的内存限制。但是,应用程序可以指定系统应为应用程序分配低于 2 GB 的所有内存。如果满足以下条件,则此功能对 64 位应用程序有益:

  • 2 GB 地址空间就足够了。
  • 该代码有许多指针截断警告。
  • 指针和整数可以自由混合。
  • 该代码具有使用 32 位数据类型的多态性。

所有指针仍然是 64 位指针,但系统确保每次内存分配都低于 2 GB 限制,因此如果应用程序截断指针,不会丢失任何重要数据。指针可以被截断为 32 位值,然后通过符号扩展零扩展扩展为 64 位值。

虚拟地址空间

但如今,即使是 Linux内核开发人员也在讨论放弃 x32 支持


检测是否/LARGEADDRESSAWARE启用有点棘手。由于它是链接时选项,因此您无法在编译时使用任何宏对其进行检查。但是,您可以通过向VS 项目和该配置中添加新配置(例如 x32)来解决此问题

  • 添加一个宏(例如_WIN_X32_ABI),以便您可以在编译时检查配置

  • 添加运行以下命令的构建后事件

      call "$(DevEnvDir)..\tools\vsvars32.bat
      editbin /largeaddressaware:no $(TargetPath)
    

或者,使用property从 VS 扩展程序以编程方式设置选项。现在只需使用此配置进行构建,您将获得“x32 ABI”可执行文件VCLinkerTool.LargeAddressAware

要检查另一个进程或可执行文件的IMAGE_FILE_LARGE_ADDRESS_AWARE标志,只需读取LOADED_IMAGE::Characteristics. 确定当前进程的标志可能比较棘手,所以最好只使用上面创建的宏在编译时执行它


英特尔编译器还可以选择在 64 位 Windows/Linux/macOS 上使用ILP32 模型,称为-auto-ilp32and/Qauto-ilp32

指示编译器分析程序以确定是否有 64 位指针可以安全地收缩为 32 位指针,以及是否有 64 位长(在 Linux* 系统上)可以安全地收缩为 32 位长.

还有-auto-p32只收缩指针而不是 64 位长

但是我找不到检查该行为的方法,以及如何确定指针是否已缩小到 32 位。我已经尝试过-auto-ilp32 -xCORE-AVX512 -O2 -ipoGodbolt,但它似乎不影响结果。如果有人知道如何输出带有 32 位指针的可执行文件,请告诉我

于 2019-04-01T17:12:31.397 回答
1

phuclv 关于禁用/LARGEADDRESSAWARE给定进程的答案的小脚注:在某些情况下,当数据结构有利时,并且采取必要步骤在 64 位模式下实际使用 32 位指针时,Windows 上的性能提升潜力太大,就像在 Linux 上一样,尽管没有那么大。请参阅:Windows 上 64 位代码中 32 位指针的基准测试

于 2019-06-16T01:05:57.357 回答
1

Microsoft 是否真的支持 X32(相对于 X86 和 X64)?

不。

于 2015-09-20T03:47:35.290 回答
0

很抱歉迟到的答案(以及对大卫的不公正)。

ml64.exeMASM for x64 (ml64.exe)上阅读,我在汇编程序中遇到了32 位地址模式。它提供 X32 地址大小覆盖。

因此,Windows 工具似乎确实提供了与 X32 相关的支持。它还解释了英特尔如何生成 X32 二进制文件和驱动程序。我只是在猜测,但我怀疑英特尔可能正在使用自定义分配器或VirtualAlloc确保指针地址在一定范围内。

Windows 操作系统似乎也没有自定义构建的内核,比如 Debian 8,它是从操作系统提供的。也就是说,由开发人员确保整数、长整数和指针也在 32 位范围内。

于 2015-10-13T22:36:30.170 回答