简体   繁体   English

在进入嵌入式程序集之前,如何确定其他人没有使用通用寄存器?

[英]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. 以下是一段GCC内联汇编代码。 It increases the input *Value by one in an atomic fashion. 它以原子方式将输入*Value增加一。 And return the increased value. 并返回增加的值。

In the assembly code, it uses the EAX register. 在汇编代码中,它使用EAX寄存器。 How can I know EAX is not being used by others before this function is called? 在调用此函数之前,我怎么能知道别人没有使用EAX 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) ...整数值和内存地址在EAX寄存器中返回...(cdecl调用约定)

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? 这是否意味着如果我遵循cdecl调用约定,则编译器将确保在进入汇编函数时可以安全地使用 EAX If I use some other general purpose register, say EBX , I must put it in the clobber section ? 如果我使用其他通用寄存器(例如EBX ,则必须将其放入“ Clobber”部分中 Ie after the last colon? 即在最后一个冒号之后?

You're using an "=a" output operand, so the compiler knows that your asm writes that register. 您使用的是"=a"输出操作数,因此编译器知道您的asm会写入该寄存器。

It will plan accordingly, using a different register for anything it wants to still have after your asm runs. 它将进行相应的计划,在您的asm运行后,使用其他寄存器来存储所需的内容。 It's up to you to accurately describe your asm to the compiler with constraints, because it's a black box otherwise. 由您决定是否要在有约束的情况下向编译器准确描述自己的asm,因为否则它是一个黑匣子。

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. 使用内联asm代替GNU C内置的__atomic_add_fetch这样做没有任何好处,后者会根据是否使用结果进行编译以lock xaddlock add https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html . 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. 如果您确实坚持使用内联asm,请对两个输入/输出操作数使用"+r""+m"约束,并且只需在asm模板中使用lock xadd Let the compiler do the rest, so write that in C (setting the register input to 1 before the asm, and incrementing it after). 让编译器完成剩下的工作,然后用C编写(将寄存器输入设置为asm之前的1 ,之后再递增)。 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. GCC知道如何将1放入寄存器,以及如何递增。

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. 当然,gcc也知道如何使用lock指令,这就是为什么您应该使用内置指令或C ++ 11 std :: atomic使其lock

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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