summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--src/atomic_ops/sysdeps/gcc/x86.h27
2 files changed, 26 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index 46039a5..e68ab4c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2008-02-11 Hans Boehm <Hans.Boehm@hp.com>
+ (Really Ian Wienand & Debian maintainers)
+ * src/atomic_ops/sysdeps/gcc/x86.h
+ (AO_compare_double_and_swap_double_full): Correctly account for
+ ebx usage with PIC.
+
2008-01-09 Hans Boehm <Hans.Boehm@hp.com>
* src/atomic_ops/sysdeps/standard_ao_double_t.h: Let
double_ptr_storage default to long long; define everywhere.
diff --git a/src/atomic_ops/sysdeps/gcc/x86.h b/src/atomic_ops/sysdeps/gcc/x86.h
index 0b344a7..96fd2cb 100644
--- a/src/atomic_ops/sysdeps/gcc/x86.h
+++ b/src/atomic_ops/sysdeps/gcc/x86.h
@@ -141,14 +141,27 @@ AO_compare_double_and_swap_double_full(volatile AO_double_t *addr,
AO_t new_val1, AO_t new_val2)
{
char result;
- register AO_t nv1 asm("%ebx") = new_val1;
- /* The above hack seems to avoid a gcc error complaining */
- /* that ebx is unavailable. */
-
- __asm__ __volatile__("lock; cmpxchg8b %0; setz %1"
+ #if __PIC__
+ /* If PIC is turned on, we can't use %ebx as it is reserved for the
+ GOT poiner. 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_val2 to %ebx */
+ "lock; cmpxchg8b %0; setz %1;"
+ "pop %%ebx;" /* restore %ebx */
+ : "=m"(*addr), "=q"(result)
+ : "m"(*addr), "d" (old_val2), "a" (old_val1),
+ "c" (new_val2), "m" (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
+ * in a clobber, but there's no point doing the push/pop if we don't
+ * have to. */
+ __asm__ __volatile__("lock; cmpxchg8b %0; setz %1;"
: "=m"(*addr), "=q"(result)
- : "m"(*addr), "a" (old_val1), "d" (old_val2),
- "b" (nv1), "c" (new_val2) : "memory");
+ : "m"(*addr), "d" (old_val2), "a" (old_val1),
+ "c" (new_val2), "b" (new_val1) : "memory");
+ #endif
return (int) result;
}