Gcc 在进入内联程序集之前,如何确保其他人没有使用通用寄存器?
下面是一段GCC内联汇编代码。它以原子方式将输入的Gcc 在进入内联程序集之前,如何确保其他人没有使用通用寄存器?,gcc,inline-assembly,Gcc,Inline Assembly,下面是一段GCC内联汇编代码。它以原子方式将输入的*值增加1。并返回增加的值 在汇编代码中,它使用EAX寄存器。在调用此函数之前,我如何知道其他人没有使用EAX?如果正在使用它,则汇编代码将损坏某些内容 UINT32 __cdecl AtomicIncrement ( IN volatile UINT32 *Value ) { UINT32 Result; __asm__ __volatile__ ( "movl $1, %%eax \n\t"
*值
增加1。并返回增加的值
在汇编代码中,它使用EAX
寄存器。在调用此函数之前,我如何知道其他人没有使用EAX
?如果正在使用它,则汇编代码将损坏某些内容
UINT32
__cdecl
AtomicIncrement (
IN volatile UINT32 *Value
)
{
UINT32 Result;
__asm__ __volatile__ (
"movl $1, %%eax \n\t" ; <============== HERE, EAX is being modified.
"lock \n\t"
"xadd %%eax, %2 \n\t"
"inc %%eax "
: "=a" (Result), // %0
"=m" (*Value) // %1
: "m" (*Value) // %2
: "memory",
"cc"
);
return Result;
}
UINT32
__cdecl
原子增量(
在易失性UINT32*值中
)
{
UINT32结果;
__asm\uuuuuu挥发性(
“movl$1,%%eax\n\t”;您使用的是“=a”
输出操作数,因此编译器知道asm写入了该寄存器
它将相应地计划,在asm运行后,对它想要保留的任何内容使用不同的寄存器。这取决于您如何使用约束向编译器准确描述asm,因为否则它是一个黑盒
函数调用约定基本上与内联asm无关。
在这个函数内联后,它将在一些较大函数的中间。
使用内联asm而不是GNU C内置的\uuuuuuu atomic\u add\u fetch
,这样做没有任何好处,它将编译为lock xadd
或lock add
,具体取决于是否使用结果
如果您坚持使用内联asm,请对两个输入/输出操作数使用“+r”
和“+m”
约束,并在asm模板内设置锁xadd
。让编译器完成其余工作,以便用C编写(在asm之前将寄存器输入设置为1
,之后将其递增)。这使编译器可以在以后的操作中优化++
。GCC知道如何将1
放入寄存器,以及如何递增
当然,gcc也知道如何使用lock
ed指令,这就是为什么您应该让它使用内置的或C++11 std::atomic来实现的原因。但是没有早期的clobber修饰符,因此编译器可以对输入使用相同的寄存器operand@TimothyBaldwin:很好;内存操作数可能使用如下寻址模式<代码>(%rax)
,所以这是与OP询问的另一个危险不同的危险。这是我建议的另一个好处,如果您使用内联asm,那么内联asm中只有lock xadd
。使用内联asm执行mov
和inc
可能会导致优化失败和危险好的。