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

Illegal instruction from VS C++ on Windows

本文关键字:非法 指令 Windows VS C++ 来自      更新时间:2023-10-16

我有一个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指令。AVX 从 Intel Sandy Bridge(第 2 代 i3/i5/i7 系列(2xxx 及更高版本(,2011 年左右推出(和 Bulldozer 的 AMD 开始支持 AVX。

在较旧的CPU(或当前的奔腾/赛扬或低功耗Atom/Silvermont(上,指令将捕获非法指令错误。

您应该在没有 AVX 支持的情况下重新编译您的应用和/或使用__cpuid来检查 CPU 功能,并在需要时将执行委托给"慢速"版本。

默认情况下,

虚拟机可能不会通过 AVX 支持,但这是可配置的。 如果来宾操作系统在 CPUID 标志中看不到 AVX,则它不会设置允许 AVX 指令执行而不会出错的控制寄存器位。 (此必须启用机制可防止使用 AVX 的用户空间的状态被无法识别 AVX 的操作系统上的上下文切换损坏。

因此,与BMI2等其他扩展不同,如果真正的硬件支持它们(无论虚拟化CPUID如何(,则可以使用BMI2,而引入新架构状态的扩展则不是这种情况:AVX和AVX-512。

虚拟机可能默认为没有 AVX 的客户机,因此可以将虚拟机迁移到没有 AVX 的主机。

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

不太直接的是,可能有两种情况。一个是,正如已经告诉您的那样,处理器可能太旧而无法获得AVX支持。另一个,即使对你来说晚了一年,也是我的兴趣,是操作系统可能故意没有启用处理器的AVX功能。

Windows 7对此特别影响。AVX 指令出现故障,除非操作系统已启用 AVX 状态组件以与 XSAVE 一起使用以保存和恢复上下文切换上的 AVX 状态。与FXSAVE相比,AVX是第一个需要XSAVE的功能。因此,如果Microsoft编写其XSAVE支持而不计划AVX,那将是一个历史之谜。XSAVE支持从最初的Windows 7开始。

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

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

但请注意:即使对于SP1,系统的AVX支持是否完全正确尚不清楚。当然存在问题,甚至有些问题当时Microsoft承认。Microsoft的用户模式文档到处都有 SP1 要求,但直到今天,内核模式文档都没有提到 SP1。

那么,总结一下,Windows 7,甚至SP1上的AVX都有些麻烦,Microsoft可以说是不太开放。十年后,没有人应该被这抓住。