我正试图编写一个简单的接口来原子地增加一些值。我尝试做以下(在C中)
void foo()
{
int counter = 0;
assembly_xadd(&counter);
printf("counter is %dn");
}
计数器为0
这是我在汇编中的代码,我不确定我是否正确使用了xadd:
.global assembly_xadd
assembly_xadd:
PUSHL %ebp
MOVL %esp,%ebp
PUSHL %edi
MOVL $0x1,%eax
MOVL 0x8(%ebp),%edi
XADDL %edi,%eax
MOVL %edi,%eax
POPL %edi
MOVL %ebp,%esp
POPL %ebp
RET
您想要的是XADDL %eax, (%edi)
。请记住,使用gas语法,目的地始终是第二个值,并且您希望更改地址为%edi
的内存。而是将一个添加到地址%edi
,并将其存储在%eax中。在genearl中,具有两个寄存器的xadd
是无用的(原子内存访问),因为寄存器操作总是原子的。
使用MOVL 0x8(%ebp),%edi
所要做的是将32位整数的地址移动到%edi
。此外,如果您想返回原始值,也就是我认为MOVL %edi,%eax
的作用,则不应该执行MOVL %edi,%eax
。CCD_ 9已经包含CCD_。
看看Linux内核中的原子变量实现,位于include/arch/x86/include/asm/atomic.h
(链接到3.8-rc7中的版本)
xadd在内联汇编程序中实现。
除非整个程序是汇编程序,否则您可能需要内联,因为即使调用单独函数的代码空间开销也大于xadd所占用的空间。如果你在汇编中编写整个程序(因为受虐狂?不合理的空间限制?),你可能只想直接使用xadd。当然,在一些情况下,汇编函数是一个合理的想法,例如,如果你想将它链接到Perl或Python代码中(但如果你不非常、非常小心,这本身可能会产生危险的后果),或者如果你需要将函数指针传递到某个地方。但即便如此,我还是会实现内联汇编程序,然后在C.中创建函数部分