【问题标题】:Why does std atomic insert 5 to the stack为什么std atomic将5插入堆栈
【发布时间】:2019-06-19 08:52:09
【问题描述】:

我想看看std::atomic 是如何翻译成汇编的。为此,我编写了以下代码,但有些地方我不明白。

以下代码:

int main(void)
{
    std::atomic<int> a;
    a.fetch_add(0);
    return 0;
}

由 GCC 编译为:

1 |  push    rbp
2 |  mov     rbp, rsp
3 |  mov     DWORD PTR [rbp-4], 0
4 |  mov     DWORD PTR [rbp-8], 5
5 |  mov     edx, DWORD PTR [rbp-4]
6 |  lea     rax, [rbp-12]
7 |  lock xadd       DWORD PTR [rax], edx
8 |  mov     eax, 0
9 |  pop     rbp
10|  ret

为什么 GCC 将“5”(第 4 行)压入堆栈?

【问题讨论】:

  • 尝试使用优化进行编译。现场稍作修改:godbolt.org/z/4pio0o(确保使用a
  • 这似乎只在对象上使用fetch_add() 时添加,即使godbolt 将其标记为std::atomic 声明的结果。不知道它是什么。 godbolt.org/z/6p89Xd
  • 我怀疑,5memory_order_seq_cst 模式的值。

标签: c++ assembly g++


【解决方案1】:

如果您将 Richard Critten 非常有帮助地发布在评论中的上帝螺栓链接更改为使用 -O0,文字 5 会重新出现。很明显,它也出现在

std::__atomic_base<int>::operator int() const:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 32
        ...
        mov     DWORD PTR [rbp-12], 5
        mov     eax, DWORD PTR [rbp-12]
        mov     esi, 65535
        mov     edi, eax
        call    std::operator&(std::memory_order, std::__memory_order_modifier)

所以文字 5 最终作为参数传递给该调用,在 %edi

由于参数是std::memory_order,我们可以看看documentation看看

typedef enum memory_order {
    memory_order_relaxed,
    memory_order_consume,
    memory_order_acquire,
    memory_order_release,
    memory_order_acq_rel,
    memory_order_seq_cst
} memory_order;

从字面上实现,将提供memory_order_seq_cst = 5

请注意,memory_order_seq_cstfetch_add 的排序参数的默认值,因此您希望看到它作为参数传递。

【讨论】:

  • -O0 是默认值,显然是 OP 在编译时使用的。 (您可以通过制作帧指针来判断,使用mov eax,0 而不是xor eax,eax,并且在不使用fetch_add 的结果时不优化为lock add 而不是xadd。)
  • 如果fetch_add编译成lock xadd,是不是说明enum memory_order没有被使用?
猜你喜欢
  • 1970-01-01
  • 2021-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-05
  • 1970-01-01
  • 2021-07-19
  • 2018-02-08
相关资源
最近更新 更多