使用 C 中的内联汇编检查 RFLAGS 中的 ID 标志

Checking for ID flag in RFLAGS using inline assembly in C

我编写了以下内联程序集来尝试检查 ID 标志。我知道应该设置它,因为我可以使用 cpuid 指令,但是这个函数 returns 0 当我测试它时。

_Bool /* Checks whether the cpu has the cpuid instruction available */
cpu_has_cpuid(void) {
        uint64_t out;
        asm ("pushfq\n\t"
             "popq %[out]\n\t"
             : [out] "=r" (out)
             :: "memory");
        return out & 0x200000;
}

有谁知道我在这里做错了什么,你能帮帮我吗?

如果有帮助,我在没有位掩码的情况下得到的值是 582

您可以而且应该在自己的代码中使用 GNU C #include <cpuid.h> 而不是 GNU C 内联汇编。 (How do I call "cpuid" in Linux?) Example on Godbolt 它是如何编译的,包括 CPUID 可用性的 32 位模式检查。


x86-64保证CPUID可用;如果您的代码可能 运行 在 486 或更早版本上,您只需要检查它。但是 486 不能 运行 64 位代码放在第一位。

您的代码的实际问题是它不会尝试翻转 ID 位。 显然0对于目前的状态来说是正常的。 https://wiki.osdev.org/CPUID#Checking_CPUID_availability 显示标准检测代码(针对 32 位模式英特尔语法,但很容易移植)在 popf / pushf / pop reg 之前使用内存目标 XOR 来查看设置是否“成功”。 (然后它恢复原来的 EFLAGS,这可能是不必要的。)

对于 GNU C 内联 asm 实现,请参阅 GCC 自己的 cpuid.h (github),它在 __get_cpuid_max#ifndef __x86_64__ 块内完成。它甚至有针对 AT&T 与 Intel 语法的方言替代方案,因此如果使用 -masm=intel.

编译,使用 #include <cpuid.h> 的代码不会中断

如果您好奇的话,将其移植到 x86-64 可以让您验证它是否确实有效。


此外,您的 push/pop 在 Linux / Mac(x86-64 系统 V)上 不安全:你踩到了红区。您需要在之前 add $-128, %rsp 之后 sub $-128, %rsp ,以避免您的 push/pop 踩到编译器 RSP 下面的红色区域,它可能会保留本地变量。参见

-128 适合 imm8 但 +128 不适合,这就是为什么我建议 add/sub $-128 而不是 sub/add 8.