简体   繁体   中英

How can I be sure a general purpose register is not being used by others before entering a inline assembly?

Below is a piece of GCC inline assembly code. It increases the input *Value by one in an atomic fashion. And return the increased value.

In the assembly code, it uses the EAX register. How can I know EAX is not being used by others before this function is called? If it is being used, the assembly code will corrupt something.

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;
}

I read from here that:

...Integer values and memory addresses are returned in the EAX register... (the cdecl call convention)

So does it mean that if I follow the cdecl call convention, the compiler will make sure the EAX can be safely used when entering an assembly function? If I use some other general purpose register, say EBX , I must put it in the clobber section ? Ie after the last colon?

You're using an "=a" output operand, so the compiler knows that your asm writes that register.

It will plan accordingly, using a different register for anything it wants to still have after your asm runs. It's up to you to accurately describe your asm to the compiler with constraints, because it's a black box otherwise.

Function calling conventions have basically zero relevance for inline asm. After this function inlines, it will be in the middle of some larger function.


There is no benefit to doing this with inline asm instead of GNU C builtin __atomic_add_fetch , which will compile to lock xadd or lock add depending on whether the result is used or not. https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html .

If you do insist on using inline asm, use a "+r" and a "+m" constraint for the two input/output operands and just have lock xadd inside the asm template. Let the compiler do the rest, so write that in C (setting the register input to 1 before the asm, and incrementing it after). That lets the compiler optimize the ++ into some later operation if it wants. GCC knows how to put 1 in a register, and how to increment.

Of course, gcc also knows how to use lock ed instructions, which is why you should let it do so by using builtins, or C++11 std::atomic.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM