【问题标题】:Checking for ID flag in RFLAGS using inline assembly in C使用 C 中的内联汇编检查 RFLAGS 中的 ID 标志
【发布时间】:2021-06-12 14:21:52
【问题描述】:

我编写了以下内联程序集来尝试检查 ID 标志。我知道应该设置它,因为我可以使用 cpuid 指令,但是当我测试它时这个函数返回 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

【问题讨论】:

    标签: c x86-64 inline-assembly cpuid


    【解决方案1】:

    您可以并且应该在自己的代码中使用 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 位模式 Intel 语法,但很容易移植),它在 popf / pushf / pop reg 之前使用内存目标 XOR 来查看设置是否“接受”。 (然后它会恢复原来的 EFLAGS,这可能是不必要的。)

    对于 GNU C 内联 asm 实现,请参阅 GCC 自己的 cpuid.h (github),它在 __get_cpuid_max#ifndef __x86_64__ 块内完成。它甚至具有 AT&T 与 Intel 语法的方言替代方案,因此使用 #include <cpuid.h> 的代码在使用 -masm=intel 编译时不会中断。

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


    另外,你的 push/pop 在 Linux / Mac(x86-64 System V)上是不安全的你踩到了红区。你需要add $-128, %rsp之前和sub $-128, %rsp之后,以避免你的push/pop踩到编译器RSP下方的红色区域,它可能会保留本地变量。见Using base pointer register in C++ inline asm

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-26
      • 1970-01-01
      • 1970-01-01
      • 2011-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多