3

考虑以下代码:

#include <stdio.h>

void main() {
    uint32_t num = 2;

    __asm__ __volatile__ ("CPUID");
    __asm__ __volatile__ ("movl $1, %%ecx":);
    __asm__ __volatile__ ("andl $0, %%ecx": "=r"(num));

    printf("%i\n", num);
}

我最初的期望是这段代码会打印0,如果我注释掉该CPUID行,它会打印,但它给了我垃圾。经过一些试验、错误和研究,我意识到我得到了一个随机寄存器的值。显然 GCC 并不认为我想要执行语句的结果。

问题是我已经看到(其他人的)代码依赖于该语句正确地获得 AND 的结果,而不管其他寄存器发生了什么。鉴于我的观察,显然这样的代码被破坏了,"=r"应该用"=c".

我的问题是,我们能否始终依赖于"=r"约束行为一致或根据明显的期望?还是 GCC 的实现太不透明/奇怪/其他,最好在每种情况下都避免它?

4

1 回答 1

2

为了使用=r输出说明符,您需要让 gcc 自由选择它想要使用的寄存器。您可以通过为输出指定输入和输出%0以及从第一个输入开始的输入来完成此操作%1

在您的情况下,您是说num可以在寄存器中。但是 asm 指令中没有使用输出寄存器的内容。所以 gcc 基本上会忽略这一点。

如果您评论或不评论CPUID指令,您将获得不同值的原因是CPUID可以写入eaxebxecxedx. 我在我的系统上尝试了您的示例,并0在两种情况下都得到了结果。但我注意到生成的程序集正在打印eax. 所以我想当我运行这个程序时CPUID正在写入.0eax

如果您确实想使用=r约束,则需要执行以下操作:

  asm("CPUID \n\t"
      "movl $1, %0 \n\t"
      "andl $0, %0 \n\t"
      :"=r"(num) );

否则,如果您的 asm 代码特别提到了一个寄存器,那么您需要在约束列表中指定它。在您的示例中,这意味着使用=c.

于 2012-05-29T22:27:53.850 回答