你如何使用XADD增加内存中的值?

时间:2013-02-12 01:06:53

标签: c assembly x86 mutex atomic

我正在尝试编写一个简单的接口来原子地递增一些值。我尝试执行以下操作(在C中)

void foo()
{
    int counter = 0;
    assembly_xadd(&counter);
    printf("counter is %d\n");
}
  
    

计数器为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

3 个答案:

答案 0 :(得分:1)

你想要的是XADDL %eax, (%edi)。请记住,使用gas语法时,目标始终是第二个值,并且您希望更改地址%edi处的内存。您只需在地址%edi中添加一个并将其存储在%eax中。在genearl中,带有两个寄存器的xadd是无用的(原子存储器访问方式),因为寄存器操作总是原子的。

您使用MOVL 0x8(%ebp),%edi正在做的是将32位整数的地址移动到%edi。此外,如果您想要返回原始值(我认为是MOVL %edi,%eax),则不应该执行MOVL %edi,%eax%eax已包含先前的(%edi)值。

答案 1 :(得分:0)

查看Linux内核中的原子变量实现,include/arch/x86/include/asm/atomic.h(链接是3.8-rc7中的版本)

答案 2 :(得分:0)

xadd在内联汇编程序中实现here

除非您的整个程序是汇编程序,否则您可能需要内联,因为即使调用单独函数的代码空间开销也大于xadd占用的空间。如果你在汇编中编写整个程序(因为受虐狂?不合理的空间限制?),你可能只想直接使用xadd。当然,有一些例子,汇编函数是一个合理的想法,例如,如果你想将它链接到Perl或Python代码中(但如果你不是非常非常小心,那本身就会产生危险的后果) ),或者如果你需要在某处传递函数指针。但即使这样,我也会实现内联汇编程序,然后在C中创建函数部分。