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"

下面是一段GCC内联汇编代码。它以原子方式将输入的
*值
增加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
可能会导致优化失败和危险好的。