{
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