下面的怎么样,这在一个小测试中似乎对我有用:
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 语言扩展 http://tigcc.ticalc.org/doc/gnuexts.html#SEC94:
寻找一种方法来访问汇编指令留下的条件代码是一个很自然的想法。然而,当我们尝试实现这一点时,我们发现没有办法让它可靠地工作。问题是输出操作数可能需要重新加载,这将导致额外的后续“存储”指令。在大多数机器上,这些指令会在有时间测试之前更改条件代码。对于普通的“测试”和“比较”指令,不会出现此问题,因为它们没有任何输出操作数。
编辑:我找不到任何指定一种方式或另一种方式是否可以在使用时修改堆栈的来源%N
输入值(This http://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html古老的链接说“你甚至可以将寄存器压入堆栈,使用它们,然后将它们放回去。”但该示例没有输入)。
但应该可以通过将值固定到其他寄存器来做到这一点:
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;
}