summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2012-07-04 08:32:03 +0400
committerIvan Maidanski <ivmai@mail.ru>2012-07-22 12:41:48 +0400
commit6c81a6bda886a3cd2894b27a734b75bb40586ef5 (patch)
tree34fd124cd688c48564b4bcf0d11caeddc2839587
parent7015c8dba082842c57aa9f788f0633720eaf41b5 (diff)
downloadlibatomic_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.h28
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