summaryrefslogtreecommitdiff
path: root/src/atomic_ops/sysdeps/gcc/x86.h
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2012-08-09 23:40:56 +0400
committerIvan Maidanski <ivmai@mail.ru>2012-08-09 23:40:56 +0400
commit4b9ad4b46378017fda4db83b95c42f809c9e3d00 (patch)
tree30c83cc83732525d14aeaa514dd74f2413f204e1 /src/atomic_ops/sysdeps/gcc/x86.h
parent5423c25786c1a1f2dd36ea9ecc5f58975236c85c (diff)
parent8559c0a41667abef0f8a707028cfcc032e08f622 (diff)
downloadlibatomic_ops-4b9ad4b46378017fda4db83b95c42f809c9e3d00.tar.gz
Merge branch 'libatomic_ops-7_2-hotfix-1' into release-7_2
Diffstat (limited to 'src/atomic_ops/sysdeps/gcc/x86.h')
-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