下面摘录自GCC手册的扩展Asm文档,关于使用Asm
关键字在C中嵌入汇编指令:
如果一个输出参数(a)允许寄存器约束,而另一个输出参数(b)允许存储器约束,也会出现同样的问题。GCC生成的用于访问b中的存储器地址的代码可以包含可能由a共享的寄存器,并且GCC认为这些寄存器是ASM的输入。如上所述,GCC假设这样的输入寄存器在写入任何输出之前就被消耗了。如果asm语句在使用B之前写入a,则此假设可能导致不正确的行为。将'&'修饰符与a上的register约束结合起来确保修改a不会影响B引用的地址。否则,如果在使用b之前修改了a,则未定义b的位置。
斜体句子表示,如果asm语句在使用b
之前写入a
中,则可能存在“不正确的行为”。
如果我们只有一个带有一个核心的CPU,请出示一个可能产生这种不正确行为的asm代码,即修改A
会影响B
引用的地址,使得B
的位置未定义。
我唯一熟悉的汇编语言是Intel x86汇编语言,所以请让示例针对那个平台。
请考虑以下示例:
extern int* foo();
int bar()
{
int r;
__asm__(
"mov $0, %0 \n\t"
"add %1, %0"
: "=r" (r) : "m" (*foo()));
return r;
}
通常的调用约定将返回值放入eax
寄存器。因此,编译器很有可能决定在整个过程中使用eax
,以避免不必要的复制。生成的程序集可能如下所示:
subl $12, %esp
call foo
mov $0, %eax
add (%eax), %eax
addl $12, %esp
ret
请注意,mov$0,%eax
在下一条指令尝试使用eax
引用输入参数之前将eax
置零,因此此代码将崩溃。使用早期的clobber,您会强制编译器选择不同的寄存器。在我的例子中,得到的代码是:
subl $12, %esp
call foo
mov $0, %edx
add (%eax), %edx
addl $12, %esp
movl %edx, %eax
ret
subl $12, %esp
call foo
mov %eax, %edx
mov $0, %eax
add (%edx), %eax
addl $12, %esp
ret
谢谢你的帮助。
尝试使用gcc:https://github.com/wolf9466/cpuminer-multi/blob/master/cryptonight_aesni.c编译此源文件时遇到此错误 “CRYPTONIGT_AESNI.c:162:4:错误:操作数约束不一致”
我正在尝试同时处理MSVC和GCC编译器,同时更新这个代码库以在GCC上工作。但我不确定GCCs内联ASM是如何工作的。现在我并不擅长将ASM转换为C,否则我就会使用C而不是ASM。 我假设ROR13的工作方式类似于,但代码不会产生相同的输出。 什么是将这个内联ASM翻译成GCC的正确方法,或者这个代码的C翻译是什么?
有没有人要对我说或评论? 跟随生成的程序集 多亏了弄臣的解决之道:
我的理解是,当编写gcc样式的内联asm时,您必须非常具体和准确地了解所有的输入和输出参数(和clobbers),这样编译器就会确切地知道如何为代码分配寄存器,以及它可以对那些寄存器的值和asm代码可能读取和/或修改的任何内存假设什么。编译器使用这些信息尽可能地优化周围的代码(如果它认为内联asm对任何东西都没有影响,甚至完全删除它)。对此不够具体可能会导致不正确的行为,因为编译器是根据您的不正确
我在函数中有以下代码: 现在我不知道为什么这不起作用。Gcc说:“错误:'asm'操作数有不可能的约束”我一直在学习Gcc内联汇编教程,我认为这是将参数从c代码带到内联汇编块的正确方法。 我还使用了为32位x86构建的gcc交叉编译器。