正确的方法来包装CMPXCHG8B在GCC内联汇编,32位 [英] Correct way to wrap CMPXCHG8B in GCC inline assembly, 32 bits

查看:419
本文介绍了正确的方法来包装CMPXCHG8B在GCC内联汇编,32位的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写GCC内联汇编为CMPXCHG8B的IA32。不,我不能使用 __ sync_bool_compare_and_swap 。它具有与无-fPIC工作

I'm trying to write GCC inline asm for CMPXCHG8B for ia32. No, I cannot use __sync_bool_compare_and_swap. It has to work with and without -fPIC.

迄今为止最好的我已经(修改:不工作毕竟,详见下文我自己的答案)是

So far the best I've (EDIT: does not work after all, see my own answer below for details) is

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")

不过我不知道,如果这其实就是正确的。

However I'm not sure if this is in fact correct.

我做不到B((INT32)(设置和放大器; 0xFFFFFFFF的))为由于PIC ebx_val,但显然注册ASM( EBX)变量是由编译器所接受。

I cannot do "b" ((int32)(set & 0xFFFFFFFF)) for ebx_val due to PIC, but apparently register asm("ebx") variable is accepted by the compiler.

BONUS :在RET变量用于分支,所以code最终看起来是这样的:

BONUS: the ret variable is used for branching, so the code ends up looking like this:

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

不知道如何来形容输出操作数,使之成为:

Any idea how to describe output operands so that it becomes:

cmpxchg8b [edi]
jz foo

感谢您。

推荐答案

怎么样以下,这似乎是我在一个小的测试工作:

How about the following, which seems to work for me in a small test:

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;
}

如果这也被编译错误可以请包括一个小片段触发这种行为?

If this also gets miscompiled could you please include a small snippet that triggers this behavior?

至于奖金问题,我不认为这是可能使用从 CMPXCHG8B 指令的条件code(汇编块之后分支,除非您使用 ASM转到或类似功能)。从 GNU C语言扩展

Regarding the bonus question I don't think it is possible to branch after the assembler block using the condition code from the cmpxchg8b instruction (unless you use the asm goto or similar functionality). From GNU C Language Extensions:

这是一个自然的想法去寻找一种方式让访问由汇编指令留下的条件code。然而,当我们试图实现这一点,我们没有发现任何办法让它可靠地工作。问题是输出操作数可能需要重新加载,这将导致额外的以下存储的指示。在大多数机器上,之前有时间来测试它这些指令会改变的条件code。不会出现这个问题对于普通的测试和比较指令,因为他们没有任何输出操作数。

It is a natural idea to look for a way to give access to the condition code left by the assembler instruction. However, when we attempted to implement this, we found no way to make it work reliably. The problem is that output operands might need reloading, which would result in additional following "store" instructions. On most machines, these instructions would alter the condition code before there was time to test it. This problem doesn't arise for ordinary "test" and "compare" instructions because they don't have any output operands.

编辑:我无法找到指定一个或其他方式是否是确定修改堆栈,同时还使用%N 输入值(任意源< A HREF =htt​​p://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html相对=nofollow>此内容古老的链接说:你甚至可以把你的寄存器到堆栈中,使用他们,并把他们回来了。但这个例子不具有输入)。

I Can't find any source that specifies one way or the other whether it is OK to modify the stack while also using the %N input values (This ancient link says "You can even push your registers onto the stack, use them, and put them back." but the example doesn't have input).

但应可能的,而不做由值固定到其它寄存器

But it should be possible to do without by fixing the values to other registers:

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;
}

这篇关于正确的方法来包装CMPXCHG8B在GCC内联汇编,32位的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆