使用SIGILL与CPU探测进行AVX功能检测

jww*_*jww 3 c assembly avx

我正在尝试确定一种检测英特尔和AMD处理器上AVX和AVX2可用性的有效方法.在阅读英特尔软件开发人员手册第一卷(使用XSAVE功能集管理状态,第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
Run Code Online (Sandbox Code Playgroud)

Mar*_*oom 5

首先是一点理论.

要使用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(和)支持. 由于OS 仅在存在硬件支持的情况下发出信号支持,因此测试前者就足够了. 对于AVX扩展,仍建议进行测试,因为即使不支持AVX ,操作系统也可能会设置. CPUID.1:ECX.OSXSAVEXCR0.SSEXCR0.AVX
xsave
CPUID.1:ECX.AVXXCR0.AVX

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

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

这与您发布的完全相同.


捕获异常以检测对AVX扩展的支持也将授予您可以保证捕获的异常是#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暴露给用户模式程序.

从而追赶SIGILLvzeroall或类似也会做.

  • @jww,对不起,迟到了.在使用AVX2之前,应测试"CPUID.7:EBX.AVX2 [bit 5]"位.由于AVX2只引入了新的指令而没有新的状态,这应该足够了(除了AVX测试). (2认同)