以下では:
#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クロバーにa、b、c、dがリストされているので、これは私を驚かせます
http://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints
明示的にすることで、clobber 制約を修正できます。
"%rax", "%rbx", "%rcx", "%rdx" // clobbered registers
しかし、私はそうしなければならないことに驚いていますか?これは x86_64 で動作するために必要なだけですが、コードが後で i386 でも必要になった場合に備えて、"a"、"b"、"c"、"d" スタイルの制約の方が適切だと思いました。
編集: 最初に間違った 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
) ;
}
ただし、すべてのクロバーは出力であるため、クロバー制約の要件をまったく回避していることに注意してください。それはおそらくそれを行う正しい方法ですが、gcc ドキュメントを読んだ後でも、ジェネリック reg 名「a」、「b」、「c」、「d」を clobber 制約で使用できないことにまだ驚いています。代わりに、「%eax」、「%rax」などを使用する必要があります...