Skip to content

Commit be34878

Browse files
author
Davi Arnaut
committed
Bug#52419: x86 assembly based atomic CAS causes test failures
The problem was that the x86 assembly based atomic CAS (compare and swap) implementation could copy the wrong value to the ebx register, where the cmpxchg8b expects to see part of the "comparand" value. Since the original value in the ebx register is saved in the stack (that is, the push instruction causes the stack pointer to change), a wrong offset could be used if the compiler decides to put the source of the comparand value in the stack. The solution is to copy the comparand value directly from memory. Since the comparand value is 64-bits wide, it is copied in two steps over to the ebx and ecx registers.
1 parent 91392cd commit be34878

1 file changed

Lines changed: 10 additions & 8 deletions

File tree

include/atomic/x86-gcc.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,21 +111,23 @@
111111
On some platforms (e.g. Mac OS X and Solaris) the ebx register
112112
is held as a pointer to the global offset table. Thus we're not
113113
allowed to use the b-register on those platforms when compiling
114-
PIC code, to avoid this we push ebx and pop ebx and add a movl
115-
instruction to avoid having ebx in the interface of the assembler
116-
instruction.
114+
PIC code, to avoid this we push ebx and pop ebx. The new value
115+
is copied directly from memory to avoid problems with a implicit
116+
manipulation of the stack pointer by the push.
117117
118118
cmpxchg8b works on both 32-bit platforms and 64-bit platforms but
119119
the code here is only used on 32-bit platforms, on 64-bit
120120
platforms the much simpler make_atomic_cas_body32 will work
121121
fine.
122122
*/
123123
#define make_atomic_cas_body64 \
124-
int32 ebx=(set & 0xFFFFFFFF), ecx=(set >> 32); \
125-
asm volatile ("push %%ebx; movl %3, %%ebx;" \
126-
LOCK_prefix "; cmpxchg8b %0; setz %2; pop %%ebx" \
127-
: "=m" (*a), "+A" (*cmp), "=c" (ret) \
128-
: "m" (ebx), "c" (ecx), "m" (*a) \
124+
asm volatile ("push %%ebx;" \
125+
"movl (%%ecx), %%ebx;" \
126+
"movl 4(%%ecx), %%ecx;" \
127+
LOCK_prefix "; cmpxchg8b %0;" \
128+
"setz %2; pop %%ebx" \
129+
: "=m" (*a), "+A" (*cmp), "=c" (ret) \
130+
: "c" (&set), "m" (*a) \
129131
: "memory", "esp")
130132
#endif
131133

0 commit comments

Comments
 (0)