【问题标题】:atomic64_read works in x86 but not for x64atomic64_read 适用于 x86 但不适用于 x64
【发布时间】:2013-11-26 03:51:57
【问题描述】:

以下 atomic64_read 代码在 x86 环境下工作,但在 x64 环境下失败。

    asm volatile(
        "mov %%ebx, %%eax\n"
        "mov %%ecx, %%edx\n"
        "lock cmpxchg8b %1\n"
        : "=&A" (ret)
        : "m" (v->counter64)
        );

有趣的是,锁定操作在 x86 中指的是寄存器 'ecx'( : edx),但在 x64 中它指的是 'rax' 寄存器。

lock cmpxchg8b (%ecx) => x86

lock cmpxchg8b (%rax) => x64

考虑到 rax 和 rcx 是 64 位寄存器,我还尝试转换上面的代码,如下所示。它正确地将值移动到 rax 寄存器,但在 lock 语句中出现分段错误。

asm volatile(
    "mov %%rcx, %%rax\n"
    "lock cmpxchg8b %1\n"
    : "=&A" (ret)
    : "m" (v->counter64)
    );

【问题讨论】:

  • 为什么不使用 stdatomic.h 而不是 assembler ?也许您没有符合 C11 的编译器/运行时/c 库?

标签: gcc inline-assembly


【解决方案1】:

原始失败是因为“A”约束意味着 rax/eax/ax/al 和/或 rdx/edx/dx/dl 并且在 x64 上,rdx 仅分配给结果,因此 mov 指令会覆盖地址拉克斯。

你可以得到两半的结果:

uint32_t lo, hi;
asm volatile(
    "mov %%ebx, %%eax\n"
    "mov %%ecx, %%edx\n"
    "lock cmpxchg8b %2\n"
    : "=&a" (lo), "=&d" (hi)
    : "m" (v->counter64)
    );
ret = lo | ((uint64_t)hi << 32);

但是普通的阅读就足够了吗?

ret = *(volatile uint64_t)&v->counter64

还是内存排序不够?

【讨论】: