Hank
Hank

Reputation: 3497

Error: invalid instruction suffix for `cmpxchg'

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

Answers (1)

srking
srking

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

Related Questions