使用SIGILL与CPU探测进行AVXfunction检测

我正在尝试确定一种检测英特尔和AMD处理器上AVX和AVX2可用性的有效方法。 在阅读英特尔软件开发人员手册第一卷( 使用XSAVEfunction集管理状态 ,第310页)时,我更加惊讶地发现它更接近SSE和XSAVE。

英特尔发布了一些用于在启用Is AVX时检测AVX可用性的代码? 代码如下所示,并不太痛苦。 问题是,Visual Studio是一个痛点,因为我们需要将代码从C / C ++文件中移出到X64的ASM文件中。

其他人似乎采用SIGILL方法来检测AVX可用性。 或者他们无意中使用了SIGILL方法。 例如,请参阅AVX指令上的SIGILL 。

我的问题是,使用SIGILL方法检测AVX可用性是否安全? 这里, “安全”表示当CPU和OS支持AVX时,AVX指令不会生成SIGILL ; 否则它会生成一个SIGILL


下面的代码适用于32位计算机,它来自英特尔博客是否已启用AVX? 令我担心的是操纵控制寄存器。 读取和写入某些X86和ARM控制寄存器有时需要超级用户/管理员权限。 这是我更喜欢SIGILL (并避免控制寄存器)的原因。

 ; int isAvxSupported(); isAvxSupported proc xor eax, eax cpuid cmp eax, 1 ; does CPUID support eax = 1? jb not_supported mov eax, 1 cpuid and ecx, 018000000h ; check 27 bit (OS uses XSAVE/XRSTOR) cmp ecx, 018000000h ; and 28 (AVX supported by CPU) jne not_supported xor ecx, ecx ; XFEATURE_ENABLED_MASK/XCR0 register number = 0 xgetbv ; XFEATURE_ENABLED_MASK register is in edx:eax and eax, 110b cmp eax, 110b ; check the AVX registers restore at context switch jne not_supported supported: mov eax, 1 ret not_supported: xor eax, eax ret isAvxSupported endp 

首先是一点理论。

要使用AVX指令集,必须满足以下几个条件:

  1. CR4.OSXSAVE[bit 18]必须为1。
    该标志由OS设置,以通知处理器它支持xsave扩展。
    xsave扩展是保存AVX状态的唯一方法( fxsave不保存ymm寄存器),因此操作系统必须支持它们。

  2. XCR0.SSE[bit 1]XCR0.AVX[bit 2]必须为1。
    这些标志由OS设置,以通知处理器它支持保存和恢复SSE和AVX状态(通过xsave )。

  3. CPUID.1:ECX.AVX[bit 28] = 1
    当然,处理器必须首先支持AVX扩展。

所有这些寄存器都是用户模式可读的,但对于CR4
幸运的是, CR4.OSXSAVE位反映在CPUID.1:ECX.OSXSAVE[bit 27] ,因此所有信息都是用户模式可访问的。 不涉及特权指示。

为了使用AVX扩展,必须同时存在硬件( CPUID.1:ECX.AVXCPUID.1:ECX.XSAVE )和OS( CPUID.1:ECX.OSXSAVEXCR0.SSEXCR0.AVX )支持。
由于操作系统仅在存在硬件支持的情况下发出支持xsave信号,因此测试前者就足够了。
对于AVX扩展,仍建议测试CPUID.1:ECX.AVX因为即使不支持AVX,操作系统也可能设置XCR0.AVX

这导致英特尔官方强烈推荐的算法:

用于AVX检测的官方英特尔算法。手册第14.3节1

这与您发布的完全相同。


捕获exception以检测对AVX扩展的支持也将被授予您可以保证捕获的exception是#UD
例如,通过执行vzeroall ,唯一可能的例外是#UD#NM
第一个只在以下情况下抛出:

如果XCR0 [2:1]≠’11b’。
如果CR4.OSXSAVE [bit 18] = 0。
如果CPUID.01H.ECX.AVX [bit 28] = 0。
如果VEX.vvvv≠1111B。

因此,除非您的汇编程序/编译器损坏,否则它完全等同于开头所述的条件。

后者被抛出作为保存AVX状态的优化,因此,它不会被OS暴露给用户模式程序。

因此,在vzeroall或类似的地方捕获SIGILL也可以。