diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2012-07-04 08:32:03 +0400 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2012-07-22 12:41:48 +0400 |
commit | 6c81a6bda886a3cd2894b27a734b75bb40586ef5 (patch) | |
tree | 34fd124cd688c48564b4bcf0d11caeddc2839587 | |
parent | 7015c8dba082842c57aa9f788f0633720eaf41b5 (diff) | |
download | libatomic_ops-6c81a6bda886a3cd2894b27a734b75bb40586ef5.tar.gz |
Fix AO_compare_double_and_swap_double_full for gcc-4.2.1/x86 in PIC mode
* src/atomic_ops/sysdeps/gcc/x86.h
(AO_compare_double_and_swap_double_full): Use EDI register for
"new_val1" argument in PIC mode only for GCC 4.3+ to workaround
a problem with older compiler versions (e.g., GCC 4.2.1 [FreeBSD])
that do not recognize 'D' as a valid register specification; update
comment.
-rw-r--r-- | src/atomic_ops/sysdeps/gcc/x86.h | 28 |
1 files changed, 20 insertions, 8 deletions
diff --git a/src/atomic_ops/sysdeps/gcc/x86.h b/src/atomic_ops/sysdeps/gcc/x86.h index df02a46..b4fb525 100644 --- a/src/atomic_ops/sysdeps/gcc/x86.h +++ b/src/atomic_ops/sysdeps/gcc/x86.h @@ -138,19 +138,31 @@ AO_compare_double_and_swap_double_full(volatile AO_double_t *addr, { char result; #if __PIC__ - /* If PIC is turned on, we can't use %ebx as it is reserved for the - GOT pointer. We can save and restore %ebx because GCC won't be - using it for anything else (such as any of the m operands) */ - /* We use %edi (for new_val1) instead of a memory operand and swap */ - /* instruction instead of push/pop because some GCC releases have */ - /* a bug in processing memory operands (if address base is %esp) in */ - /* the inline assembly after push. */ - __asm__ __volatile__("xchg %%ebx,%6;" /* swap GOT ptr and new_val1 */ + /* If PIC is turned on, we can't use %ebx as it is reserved for the */ + /* GOT pointer. We can save and restore %ebx because GCC won't be */ + /* using it for anything else (such as any of the m operands). */ +# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) + /* Starting from GCC 4.3, we use %edi (for new_val1) instead of a */ + /* memory operand and swap instruction instead of push/pop because */ + /* some GCC releases have a bug in processing memory operands (if */ + /* address base is %esp) in the inline assembly after push. */ + __asm__ __volatile__("xchg %%ebx,%6;" /* swap GOT ptr and new_val1 */ "lock; cmpxchg8b %0; setz %1;" "xchg %%ebx,%6;" /* restore ebx and edi */ : "=m"(*addr), "=a"(result) : "m"(*addr), "d" (old_val2), "a" (old_val1), "c" (new_val2), "D" (new_val1) : "memory"); +# else + /* For older compiler releases, we continue to use push/pop as at */ + /* least GCC 4.2.1 does not recognize 'D' as a valid register name. */ + __asm__ __volatile__("pushl %%ebx;" /* save ebx used for PIC GOT ptr */ + "movl %6,%%ebx;" /* move new_val1 to %ebx */ + "lock; cmpxchg8b %0; setz %1;" + "pop %%ebx;" /* restore %ebx */ + : "=m"(*addr), "=a"(result) + : "m"(*addr), "d" (old_val2), "a" (old_val1), + "c" (new_val2), "m" (new_val1) : "memory"); +# endif #else /* We can't just do the same thing in non-PIC mode, because GCC * might be using %ebx as the memory operand. We could have ifdef'd |