我正在尝试为ia32的CMPXCHG8B编写GCC内联asm。不,我不能使用__sync_bool_compare_and_swap。它必须与-fPIC和不与-fPIC一起使用。

到目前为止,我最好的(编辑:毕竟行不通,有关详细信息,请参阅下面的我自己的答案)是

register int32 ebx_val asm("ebx")= set & 0xFFFFFFFF;
asm ("lock; cmpxchg8b %0;"
     "setz %1;"
     : "+m" (*a), "=q" (ret), "+A" (*cmp)
     : "r" (ebx_val), "c" ((int32)(set >> 32))
     : "flags")


但是我不确定这是否正确。

由于PIC,我无法对ebx_val执行"b" ((int32)(set & 0xFFFFFFFF)),但显然register asm("ebx")变量已被编译器接受。

奖励:ret变量用于分支,因此代码最终看起来像这样:

cmpxchg8b [edi];
setz cl;
cmp cl, 0;
je foo;


任何想法如何描述输出操作数,使其变为:

cmpxchg8b [edi]
jz foo




谢谢。

最佳答案

以下内容怎么样?在一个小测试中,以下内容似乎对我有用:

int sbcas(uint64_t* ptr, uint64_t oldval, uint64_t newval)
{
    int changed = 0;
    __asm__ (
        "push %%ebx\n\t" // -fPIC uses ebx, so save it
        "mov %5, %%ebx\n\t" // load ebx with needed value
        "lock\n\t"
        "cmpxchg8b %0\n\t" // perform CAS operation
        "setz %%al\n\t" // eax potentially modified anyway
        "movzx %%al, %1\n\t" // store result of comparison in 'changed'
        "pop %%ebx\n\t" // restore ebx
        : "+m" (*ptr), "=r" (changed)
        : "d" ((uint32_t)(oldval >> 32)), "a" ((uint32_t)(oldval & 0xffffffff)), "c" ((uint32_t)(newval >> 32)), "r" ((uint32_t)(newval & 0xffffffff))
        : "flags", "memory"
        );
    return changed;
}


如果这也被错误编译,您能否提供一个触发此行为的小片段?

关于奖励问题,我认为不可能使用cmpxchg8b指令中的条件代码在汇编程序块之后分支(除非您使用asm goto或类似功能)。从GNU C Language Extensions


寻找一种方法来访问汇编指令留下的条件代码是很自然的想法。但是,当我们尝试实现此功能时,我们找不到使它可靠运行的方法。问题在于输出操作数可能需要重新加载,这将导致其他后续的“存储”指令。在大多数机器上,这些指令会在没有时间对其进行测试之前更改条件代码。普通的“测试”和“比较”指令不会出现此问题,因为它们没有任何输出操作数。


编辑:我找不到任何指定一种方式或其他方式的源,也可以使用%N输入值来修改堆栈(This古代链接说“您甚至可以将寄存器推入堆栈,请使用它们,然后放回去。”,但该示例没有输入)。

但是应该可以不将值固定在其他寄存器上而这样做:

int sbcas(uint64_t* ptr, uint64_t oldval, uint64_t newval)
{
    int changed = 0;
    __asm__ (
        "push %%ebx\n\t" // -fPIC uses ebx
        "mov %%edi, %%ebx\n\t" // load ebx with needed value
        "lock\n\t"
        "cmpxchg8b (%%esi)\n\t"
        "setz %%al\n\t" // eax potentially modified anyway
        "movzx %%al, %1\n\t"
        "pop %%ebx\n\t"
        : "+S" (ptr), "=a" (changed)
        : "0" (ptr), "d" ((uint32_t)(oldval >> 32)), "a" ((uint32_t)(oldval & 0xffffffff)), "c" ((uint32_t)(newval >> 32)), "D" ((uint32_t)(newval & 0xffffffff))
        : "flags", "memory"
        );
    return changed;
}

07-24 09:45
查看更多