[英]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 xadd
或lock 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.