C/C++ 检测CPU是否支持AES-NI硬件指令集

发布于:2025-06-13 ⋅ 阅读:(21) ⋅ 点赞:(0)

注意

本代码仅用于X86/X64平台:

GUN ATT格式

// 检查 CPU 是否支持 AES-NI
bool supports_aes_ni() {
    unsigned int ecx = 0;
    __asm__ __volatile__ (
        "cpuid"
        : "=c" (ecx)
        : "a" (1)
        : "%ebx", "%edx"
    );

    return (ecx & (1 << 25)) != 0;
}

MSVCRT

#include <intrin.h>  // 包含 __cpuid 等函数

bool supports_aes_ni() {
    int cpuInfo[4] = {-1};  // EAX, EBX, ECX, EDX
    
    // 使用 __cpuid 内部函数替代内联汇编
    __cpuid(cpuInfo, 1);
    
    // 检查 ECX 寄存器的第 25 位 (AES-NI 标志位)
    return (cpuInfo[2] & (1 << 25)) != 0;
}

基于X86内嵌汇编的方式(INTEL格式) 

bool supports_aes_ni() {
    int ecxValue;
    
    __asm {
        mov eax, 1        ; 功能号 1 = 处理器特征信息
        cpuid             ; 执行 CPUID 指令
        mov ecxValue, ecx ; 保存 ECX 寄存器值
    }
    
    // 检查 ECX 的第 25 位 (AES-NI 标志)
    return (ecxValue & (1 << 25)) != 0;
}

基于 __cpuidex 函数:

#include <intrin.h>

bool supports_aes_ni() {
    int registers[4]; // 用于存储 EAX, EBX, ECX, EDX
    
    // 使用 __cpuidex 获取 CPU 信息
    __cpuidex(registers, 1, 0);
    
    // registers[2] 对应 ECX 寄存器
    const int ecx = registers[2];
    
    // 检查第 25 位 (AES-NI)
    return (ecx & (1 << 25)) ? true : false;
}

基于编译器内置函数(扩展),但这需要 Visual Studio C/C++ 2015+:

#include <immintrin.h>

bool supports_aes_ni() {
    // 使用 _may_i_use_cpu_feature 内部函数
    return _may_i_use_cpu_feature(_FEATURE_AES);
}

捕获处理器支援指令集的技术实现原理:

即:通过处理器提供的CPUID指令来获取某个指令集是否是存在的,每个指令集都是存在静态数值代号的。

如测试处理器是否支持:AES-NI、SSE4.2、AVX 指令。

#include <intrin.h>

void print_cpu_features() {
    int info[4];
    __cpuid(info, 1);
    
    std::cout << "AES-NI: " << (info[2] & (1 << 25) ? "YES" : "NO") << "\n";
    std::cout << "SSE4.2: " << (info[2] & (1 << 20) ? "YES" : "NO") << "\n";
    std::cout << "AVX:    " << (info[2] & (1 << 28) ? "YES" : "NO") << "\n";
}

Windows 平台上X86/X64的兼容实现:

#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
#include <intrin.h>
#else
#include <cpuid.h>
#endif

bool supports_aes_ni() {
    int info[4];
    
#if defined(_MSC_VER)
    __cpuidex(info, 1, 0);
#else
    __cpuid_count(1, 0, info[0], info[1], info[2], info[3]);
#endif

    return (info[2] & (1 << 25)) != 0;
}