asm in C“’mov’的内存引用太多了”

我看过关于同样错误的post,但我仍然得到错误:

too many memory references for `mov' junk `hCPUIDmov buffer' after expression 

…这是代码(mingw编译器/ C :: B):

 #include iostream using namespace std; union aregister { int theint; unsigned bits[32]; }; union tonibbles { int integer; short parts[2]; }; void GetSerial() { int part1,part2,part3; aregister issupported; int buffer; __asm( "mov %eax, 01h" "CPUID" "mov buffer, edx" );//do the cpuid, move the edx (feature set register) to "buffer" issupported.theint = buffer; if(issupported.bits[18])//it is supported { __asm( "mov part1, eax" "mov %eax, 03h" "CPUID" );//move the first part into "part1" and call cpuid with the next subfunction to get //the next 64 bits __asm( "mov part2, edx" "mov part3, ecx" );//now we have all the 96 bits of the serial number tonibbles serial[3];//to split it up into two nibbles serial[0].integer = part1;//first part serial[1].integer = part2;//second serial[2].integer = part3;//third } } 

您的汇编代码未正确格式化为gcc。

首先,gcc使用AT&T语法(编辑: 默认情况下,感谢nrz ),因此它需要为每个寄存器引用添加% ,并为立即操作数添加$ 。 目标操作数始终位于右侧

其次,您需要为新行传递行分隔符(例如\n\t )。 由于gcc直接将字符串传递给汇编程序,因此需要特定的语法。

您通常应该尽量减少汇编程序,因为它可能会导致优化程序出现问题。 最小化所需汇编程序的最简单方法可能是将cpuid指令分解为函数,并重用它。

 void cpuid(int32_t *peax, int32_t *pebx, int32_t *pecx, int32_t *pedx) { __asm( "CPUID" /* All outputs (eax, ebx, ecx, edx) */ : "=a"(*peax), "=b"(*pebx), "=c"(*pecx), "=d"(*pedx) /* All inputs (eax) */ : "a"(*peax) ); } 

然后只需简单地使用;

 int a=1, b, c, d; cpuid(&a, &b, &c, &d); 

另一种可能更优雅的方法是使用宏来实现 。

  1. 由于C如何工作,

     __asm( "mov %eax, 01h" "CPUID" "mov buffer, edx" ); 

    相当于

     __asm("mov %eax, 01h" "CPUID" "mov buffer, edx"); 

    这相当于

     __asm("mov %eax, 01hCPUIDmov buffer, edx"); 

    这不是你想要的。

  2. AT&T语法(GAS的默认值)将目标寄存器放在最后。

  3. AT&T语法要求immediates以$为前缀。

  4. 你不能像那样引用局部变量; 你需要将它们作为操作数传递。

维基百科的文章给出了一个返回eax的工作示例。

以下代码段可能涵盖您的用例(我不熟悉GCC内联汇编或CPUID):

 int eax, ebx, ecx, edx; eax = 1; __asm( "cpuid" : "+a" (eax), "+b" (ebx), "+c" (ecx), "+d" (edx)); buffer = edx