]> granicus.if.org Git - libatomic_ops/commitdiff
Fix AO_compare_double_and_swap_double_full for gcc-4.2.1/x86 in PIC mode
authorIvan Maidanski <ivmai@mail.ru>
Wed, 4 Jul 2012 04:32:03 +0000 (08:32 +0400)
committerIvan Maidanski <ivmai@mail.ru>
Sun, 22 Jul 2012 08:41:48 +0000 (12:41 +0400)
* 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.

src/atomic_ops/sysdeps/gcc/x86.h

index df02a4613ea4bb2769bbd4aee40cef96cd939148..b4fb5250ee19ccea0804fdf09ebeea17797b47dc 100644 (file)
@@ -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