Windows 上来自 VS C++ 的非法指令

Illegal instruction from VS C++ on Windows

我有一个 C++ 应用程序在某些 Windows 7 位用户启动时崩溃。我无法在自己的机器上重现该错误,但使用 breakpad 生成了一个 .dmp 文件,该文件显示代码因初始化静态 std::vector 数组的“非法指令”而崩溃。这可能意味着什么?

异常: Unhandled exception at 0x000000013F121362 (myApp.exe) in myApp.exe.4328.dmp: 0xC000001D:

Illegal Instruction.myApp.exe! dynamic initializer for Keyboard::key_freqs_() Line 11 C++

反汇编:

const std::vector<double> Keyboard::key_freqs_ = std::vector<double>({
**Crashed here->** 000000013F121362  vmovaps     ymm0,ymmword ptr [__ymm@404059fbe76c8b44403ede353f7ced91403d228f5c28f5c3403b800000000000 (01408B7DE0h)]  
000000013F12136A  movzx       r9d,byte ptr [rsp+20h]  
000000013F121370  lea         r8,[rbp+1F0h]  
000000013F121377  vmovups     ymmword ptr [rsp+30h],ymm0  
000000013F12137D  vmovaps     ymm0,ymmword ptr [__ymm@404499fbe76c8b44404371eb851eb85240425a9fbe76c8b4404152f1a9fbe76d (01408B7E00h)]  
000000013F121385  vmovups     ymmword ptr [rsp+50h],ymm0  
000000013F12138B  vmovaps     ymm0,ymmword ptr [__ymm@4049f4dd2f1a9fbe40487fdf3b645a1d40471fdf3b645a1d4045d3b645a1cac1 (01408B7E20h)]  
000000013F121393  vmovups     ymmword ptr [rsp+70h],ymm0  
000000013F121399  vmovaps     ymm0,ymmword ptr [__ymm@405059fbe76c8b44404ede147ae147ae404d22b020c49ba6404b800000000000 (01408B7E40h)]  
000000013F1213A1  vmovups     ymmword ptr [rbp-70h],ymm0  
000000013F1213A6  vmovaps     ymm0,ymmword ptr [__ymm@40549a0c49ba5e354053720c49ba5e3540525a9fbe76c8b4405152f1a9fbe76d (01408B7E60h)]  
000000013F1213AE  vmovups     ymmword ptr [rbp-50h],ymm0  
000000013F1213B3  vmovaps     ymm0,ymmword ptr [__ymm@4059f47ae147ae1440587fef9db22d0e40571fef9db22d0e4055d3a5e353f7cf (01408B7E80h)]  
000000013F1213BB  vmovups     ymmword ptr [rbp-30h],ymm0  
000000013F1213C0  vmovaps     ymm0,ymmword ptr [__ymm@406059eb851eb852405ede147ae147ae405d228f5c28f5c3405b800000000000 (01408B7EA0h)]  
000000013F1213C8  vmovups     ymmword ptr [rbp-10h],ymm0  
...

编辑:正如答案所暗示的,我使用的是 /arch:AVX 编译标志,它不适用于所有机器。

vmovups 是一条 AVX 指令。从 Intel Sandy Bridge(第二代 i3/i5/i7 系列(2xxx 及更高版本),2011 年左右推出)和 Bulldozer 的 AMD 开始支持 AVX。

在较旧的 CPU(或当前 Pentium/Celeron 或低功耗 Atom/Silvermont)上,该指令将陷入非法指令错误。

您应该在没有 AVX 支持的情况下重新编译您的应用程序 and/or 使用 __cpuidcheck CPU 功能,并将执行委托给“慢速”版本,如果需要。


虚拟机 默认情况下可能不会通过 AVX 支持,但这是可以配置的。如果来宾 OS 在 CPUID 标志中没有看到 AVX,它不会设置让 AVX 指令无故障执行的控制寄存器位。 (这种必须启用的机制可防止使用 AVX 的用户 space 的状态被 AVX 不感知 OS 上的上下文切换破坏。)

因此,与 BMI2 等其他扩展不同,如果真正的硬件支持它们(无论虚拟化 CPUID,您可以使用它们),引入新架构状态的扩展并非如此:AVX 和 AVX-512 .

VM 可能默认为没有 AVX 的来宾,因此可以将 VM 迁移到没有 AVX 的主机。

您的直接答案是:您已经针对 AVX 寄存器和指令进行了编译,并且代码假设 AVX 可用,但有些用户 运行 在 AVX 不可用的情况下使用您的代码。

不太直接的是可能有两种情况。一是,正如已经告诉您的那样,处理器可能太旧而无法支持 AVX。另一个,我感兴趣的是操作系统可能故意不启用处理器的 AVX 功能。

Windows 7特别受此影响。 AVX 指令错误,除非操作系统已启用 AVX 状态组件以与 XSAVE 一起使用以在上下文切换时保存和恢复 AVX 状态。与 FXSAVE 相比,AVX 是第一个需要 XSAVE 的功能。因此,如果微软在没有计划 AVX 的情况下编写其 XSAVE 支持,那将是一个历史谜团。 XSAVE 支持开头为 Windows 7.

奇怪的是,最初的 Windows 7 会启用 AVX(如果处理器有),但实际上从未启用过。原因是 hwpolicy.sys 驱动程序资源中的策略。原始 Windows 7 具有对 AVX 和 XSAVE 的操作系统支持,但政策禁止将 AVX 与 XSAVE 一起使用! (我还没有发现这个曾经被发表过,不是我擅长Google。)

Windows 7 SP1 中的政策允许 AVX,但仅适用于 GenuineIntel 和 AuthenticAMD 处理器(这可能是另一回事)。如果您希望您的 AVX 在原始 Windows 7 上启用,您可以通过更新策略来获得它!

但请注意:系统对 AVX 的支持是否对 SP1 来说是正确的尚不清楚。肯定存在问题,甚至微软当时也承认存在一些问题。 Microsoft 的用户模式文档中到处都是 SP1 要求,但迄今为止的内核模式文档对 SP1 只字未提。

总结一下,Windows 7 上的 AVX,甚至 SP1,都有点麻烦,可以说微软对此并不公开。十年后,没有人应该被这个抓住。