以下内容:
#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”,...
答案 0 :(得分:1)
这让我很吃惊,因为我在gcc文档中看到了i386 clobbers中列出的a,b,c,d
clobbers不是约束。
当你告诉GCC为insn操作数分配寄存器时使用约束,约束定义了可以从中绘制寄存器的可接受寄存器类。
另一方面,如果输入/输出约束不明显,例如insn修改固定寄存器,那么另一方面,clobbers告诉GCC关于寄存器的修改,这些寄存器由insn修改。不是它的一个操作数,或者在内联汇编中使用硬编码的寄存器名称。这是必需的,所以在执行内联asm之前,GCC可以隐藏值,它恰好保留在被破坏的寄存器中。
PS。对于输入输出操作数,您可以使用"+"
修饰符:
void callcpuid( cpuidOut * p, long a, long b )
{
__asm__ ( "cpuid" : "+a"(p->a), "+b"(p->b), "=c"(p->c), "=d"(p->d)) ;
}
PS。生成32位代码:
movl (%esi), %eax ; load p->a
movl 4(%esi), %ebx ; load p->b
cpuid
movl %ebx, 4(%esi) ; write back into p->b
movl (%esp), %ebx
movl %eax, (%esi) ; write back into p->a
movl %ecx, 8(%esi) ; write p->c
movl %edx, 12(%esi) ; write p->d
生成64位代码:
movq (%rdi), %rax ; load p->a
movq 8(%rdi), %rbx ; load p->b
cpuid
movq %rbx, 8(%rdi) ; write back p->b
movq %rax, (%rdi) ; write back p->a
movq %rcx, 16(%rdi) ; write p->c
movq %rdx, 24(%rdi) ; write p->d
答案 1 :(得分:0)