summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2012-03-07 19:12:49 +0400
committerIvan Maidanski <ivmai@mail.ru>2012-03-07 19:12:49 +0400
commit30cea1b9ea06c4c25cc219e1197dfac8dfa52083 (patch)
treee9cc3c9ed1f071c4d7e6ee671ab9fc7bc30e21f4
parent04eeeb6479b21f498ea482c49ece997bbfc04420 (diff)
downloadlibatomic_ops-30cea1b9ea06c4c25cc219e1197dfac8dfa52083.tar.gz
Fix AO_compare_double_and_swap_double_full for gcc/x86 (PIC mode)
* src/atomic_ops/sysdeps/gcc/x86.h (AO_compare_double_and_swap_double_full): Use EDI register for "new_val1" argument instead of a memory operand and use XCHG assembler instruction instead of push/pop in case of PIC mode (to workaround a bug in GCC 4.6.1); update the comment.
-rw-r--r--src/atomic_ops/sysdeps/gcc/x86.h11
1 files changed, 7 insertions, 4 deletions
diff --git a/src/atomic_ops/sysdeps/gcc/x86.h b/src/atomic_ops/sysdeps/gcc/x86.h
index a2314b6..cc75dc2 100644
--- a/src/atomic_ops/sysdeps/gcc/x86.h
+++ b/src/atomic_ops/sysdeps/gcc/x86.h
@@ -186,13 +186,16 @@ AO_compare_double_and_swap_double_full(volatile AO_double_t *addr,
/* 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) */
- __asm__ __volatile__("pushl %%ebx;" /* save ebx used for PIC GOT ptr */
- "movl %6,%%ebx;" /* move new_val1 to %ebx */
+ /* 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;"
- "pop %%ebx;" /* restore %ebx */
+ "xchg %%ebx,%6;" /* restore ebx and edi */
: "=m"(*addr), "=a"(result)
: "m"(*addr), "d" (old_val2), "a" (old_val1),
- "c" (new_val2), "m" (new_val1) : "memory");
+ "c" (new_val2), "D" (new_val1) : "memory");
#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