在下面的:
#include <string.h>
struct cpuidOut
{
long a ;
long b ;
long c ;
long d ;
} ;
void callcpuid( cpuidOut * p, long a )
{
memset( p, 0xFF, sizeof(*p) ) ;
p->a = a ;
__asm__ ( "cpuid"
: "+a"(p->a), "=b"(p->b), "=c"(p->c), "=d"(p->d) // output
: // no (only) inputs
: "a", "b", "c", "d" // clobbered registers
) ;
}
我得到一个编译错误:
t.C:22: error: unknown register name 'd' in 'asm'
t.C:22: error: unknown register name 'c' in 'asm'
t.C:22: error: unknown register name 'b' in 'asm'
t.C:22: error: unknown register name 'a' in 'asm'
(来自 g++ 或 clang++ 的相同类型的错误)
这让我很吃惊,因为我在 gcc 文档的 i386 clobbers 中看到了 a、b、c、d
http://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints
我可以通过明确来修复clobber约束:
"%rax", "%rbx", "%rcx", "%rdx" // clobbered registers
但我很惊讶我必须这样做?我只需要它在 x86_64 上工作,但我认为“a”、“b”、“c”、“d”样式约束会更好,以防以后在 i386 上也需要代码。
编辑:我最初发布了错误的asm,经过几次调整以使其正常工作,并在此过程中弄混了。上面的 asm 与我最初的问题一致,但是会导致编译器无法调度 A 寄存器的编译错误。这似乎可行:
void callcpuid( cpuidOut * p, long a, long b )
{
__asm__ ( "cpuid"
: "=a"(p->a), "=b"(p->b), "=c"(p->c), "=d"(p->d) // output
: "0"(a), "1"(b) // inputs
) ;
}
但请注意,它完全避免了对任何 clobber 约束的要求,因为所有 clobber 都是输出。这可能是正确的方法,尽管在阅读 gcc 文档后我仍然感到惊讶,我不能在 clobber 约束中使用通用的 reg 名称“a”、“b”、“c”、“d”,而不是必须使用 "%eax", "%rax", ...