Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ivmai committed Jul 4, 2012
1 parent df42d45 commit 613f39d
Showing 1 changed file with 20 additions and 8 deletions.
28 changes: 20 additions & 8 deletions src/atomic_ops/sysdeps/gcc/x86.h
Expand Up @@ -183,19 +183,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
Expand Down

0 comments on commit 613f39d

Please sign in to comment.