Reputation: 3497
I'm trying to compile another project's code, and I keeping getting Error: invalid instruction suffix for 'cmpxchg'
. The line of code the error keeps pointing to is:
inline bool CAS(long *ptr, long oldv, long newv) {
unsigned char ret;
/* Note that sete sets a 'byte' not the word */
__asm__ __volatile__ (
" lock\n"
" cmpxchgq %2,%1\n"
" sete %0\n"
: "=q" (ret), "=m" (*ptr)
: "r" (newv), "m" (*ptr), "a" (oldv)
: "memory");
return ret;
}
I was wondering if anyone knew what could be the cause of the error and what is a possible solution?
Upvotes: 1
Views: 1603
Reputation: 4732
As commentors mention, the problem is the 'q' at the end of cmpxchg. Assemblers use instruction suffix characters to indicate the bit-width when it would otherwise be ambiguous.
This code compiles fine with gcc for a 64-bit target. You get this output for your cmpxchgq instruction.
f0 48 0f b1 16 lock cmpxchg %rdx,(%rsi)
That f0 is the LOCK prefix and 48 is the REX.W prefix. The real opcode is 0f b1.
Compiling for a 32-bit target (gcc option -m32), causes the suffix error.
If you need this code to work on a 32-bit machine, you have a porting headache here. sizeof(long) is 8 on a 64-bit machine and 4 on a 32-bit machine for Linux. IF and it's a big if, the entire program is resilient enough to tolerate a 'long' going from 8 to 4 bytes, you could get away with just changing the 'q' suffix to an 'l' (that's a lower-case L). This gives you the '0f b1' instruction in it's 32-bit form:
f0 0f b1 16 lock cmpxchg %edx,(%esi)
If not, then you could attempt to rewrite the assembly for a 32-bit target to use CMPXCHG8B which is a different instruction with different register touching behavior. CMPXCHG8B is not a drop-in replacement!
Upvotes: 2