gccでatomicな64bit setを実現したい

gccでatomicに64bitの値を代入したい。
一応、以下のようなコードで実現はできるんだけど。。

#include <stdio.h>
#include <stdint.h>

#define SEN_SET_64BIT(p,v) \
  __asm__ __volatile__ ("1:\n" \
                            "\tmovl (%0), %%eax\n" \
                            "\tmovl 4(%0), %%edx\n" \
                            "\tlock; cmpxchg8b (%0)\n" \
                            "\tjnz 1b\n" \
 : \
 : "D"(p), "b"(*(((uint32_t *)&(v))+0)), "c"(*(((uint32_t *)&(v))+1)) \
 : "ax", "dx", "memory");

int
main (int argc, char *argv[]) {
  uint64_t a = 0x0123456789abcdefLL, b = 0;
  SEN_SET_64BIT(&b, a);
  printf("%016llx\n", b);
}

同じマクロを、実際使いたいプログラムに組み込むと、

error: can't find a register in class 'BREG' while reloading 'asm'

gccに怒られてしまう。


以下のブログエントリに書かれている、The atomic_ops projectでの問題と同じなのかな。


gccの__sync系関数を使いたいものの、gcc 4.1以降なんだよねえ。
悩む。

[追記]できた。

gccがどーしてもebxを使いたいらしいから、esiを犠牲にすることに。

#include <stdio.h>
#include <stdint.h>

#define SEN_SET_64BIT(p,v) \
  __asm__ __volatile__ ("\txchgl %%esi, %%ebx\n" \
                            "1:\n" \
                            "\tmovl (%0), %%eax\n" \
                            "\tmovl 4(%0), %%edx\n" \
                            "\tlock; cmpxchg8b (%0)\n" \
                            "\tjnz 1b\n" \
                            "\txchgl %%ebx, %%esi\n" \
 : \
 : "D"(p), "S"(*(((uint32_t *)&(v))+0)), "c"(*(((uint32_t *)&(v))+1)) \
 : "ax", "dx", "memory");

int
main (int argc, char *argv[]) {
  uint64_t a = 0x0123456789abcdefLL, b = 0;
  SEN_SET_64BIT(&b, a);
  printf("%016llx\n", b);
}

こんなんでいいのか…でもこれでコンパイル通るようになった。謎だ。