C uses assemble: operand type mismatch for push
我正在尝试禁用/启用Linux内核空间中的缓存。
我使用的代码是
1 2 3 4 5 6 7 8 9 10 11 12 | __asm__ __volatile__( "pushw %eax \t" /*line 646*/ "movl %cr0,%eax \t" "orl $0x40000000,%eax \t" "movl %eax,%cr0 \t" "wbinvd \t" "pop %eax"); |
编译后,出现如下错误信息:
1 2 3 4 5 6 | memory.c: Assembler messages: memory.c:645: Error: operand type mismatch for `push' memory.c:646: Error: unsupported for `mov' memory.c:648: Error: unsupported for `mov' memory.c:650: Error: operand type mismatch for `pop' make[4]: *** [memory.o] Error 1 |
我的机器是3.50GHz下的Intel?Xeon?CPU E5-1650 v2。 64位机器。
谁能帮助我指出哪个部分不正确以及如何解决?
我猜这是因为指令和寄存器不匹配。 但是我对如何解决它感到困惑。 :(
提前致谢!
尽管大多数32位寄存器都保留在64位体系结构中,但它们不再能够与堆栈进行交互。因此,尝试压入或弹出
内联汇编语句存在多个问题,其中大多数由错误消息指示。
第一条错误消息
另一个"明显"的解决方法是使用
接下来的两个错误消息都是
最后一条错误消息是
最后,错误消息未指出的一个问题是,在64位模式下,CR0的大小扩展到了64位。尽管当前保留了额外的32位并且必须将其设置为零,但可以在以后的处理器中定义它们。因此,
因此,固定的指令顺序为:
1 2 3 4 5 6 | pushq %rax movq %cr0, %rax orq $0x40000000, %rax movq %rax, %cr0 wbinvd popq %rax |
但是,这不是我建议在您的内联程序集中使用的内容。让GCC选择使用的寄存器可以简化它。这样就无需保留它。这是我的建议:
1 2 3 4 5 6 7 8 9 | long long dummy; asm volatile ("movq %%cr0, %0 \t" "orq $0x40000000, %0 \t" "movq %0, %%cr0 \t" "wbinvd" :"=r" (dummy) : :); |
正确的方法是在
请注意,在x86-64上的用户空间代码中,
这里还有一个额外的缺点:
让编译器为我们选择一个寄存器可以解决此问题,并为编译器提供更大的自由度,因此还是更好。声明一个C变量,其类型在x86-64 ABI中为64位,在i386 ABI中为32位。 (例如,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // is this enable or disable? I didn't check the manual void set_caching_x86(void) { long tmp; // mov to/from cr requires a 64bit reg in 64bit mode asm volatile( "mov %%cr0, %[tmp] \t" // Note the double-% when we want a literal % in the asm output "or $0x40000000, %[tmp] \t" "mov %[tmp], %%cr0 \t" "wbinvd \t" : [tmp]"=r" (tmp) // outputs : // no inputs : // no clobbers. "memory" clobber isn't needed, this just affects performance, not contents ); } |
不管有没有
手工编写时,让操作数隐含操作数大小比较容易,而不是总是在助记符上使用后缀。即
即使在64位模式下,我们本可以使用
根据intel的说法-http://download.intel.com/products/processor/manual/325383.pdf一个字是16位,因此pushw期望使用16位操作数。寄存器eax为32位,必须使用pushl进行推送。
编辑:
您要装配32位还是64位?
如果您从未弄清楚,请在编译64位时使用