请考虑以下代码:
#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的实现太不透明/怪异/其他并且最好只是在每种情况下都避免它?
答案 0 :(得分:2)
为了使用=r
输出说明符,你需要让gcc自由选择它想要使用的寄存器。您可以通过为输出指定输入和输出一般为%0
,为第一个输入指定以%1
开头的输入。
在您的情况下,您说num
可以在注册表中。但asm指令中没有任何内容使用输出寄存器。所以gcc基本上会忽略这一点。
如果您对CPUID
说明发表评论或未对CPUID
说明发表评论,那么您获得不同价值的原因是eax
可以写入ebx
,ecx
,{ {1}}和edx
。我在我的系统上尝试了你的例子,并在两种情况下得到了0
。但我注意到生成的程序集正在打印eax
的值。所以我想我在运行此计划时CPUID
正在将0
写入eax
。
如果您确实想使用=r
约束,则需要执行以下操作:
asm("CPUID \n\t"
"movl $1, %0 \n\t"
"andl $0, %0 \n\t"
:"=r"(num) );
否则,如果您的asm代码专门提到了一个寄存器,那么您需要在约束列表中指定它。在您的示例中,这意味着使用=c
。