Я пытаюсь скомпилировать код другого проекта, и я продолжаю получать Error: invalid instruction suffix for 'cmpxchg'
, Строка кода, на которую постоянно указывает ошибка:
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;
}
Мне было интересно, если бы кто-нибудь знал, что может быть причиной ошибки и каково возможное решение?
Как отмечают комментаторы, проблема заключается в ‘q’ в конце cmpxchg. Ассемблеры используют символы суффикса инструкции, чтобы указать ширину в битах, когда это было бы неоднозначно.
Этот код прекрасно компилируется с gcc для 64-битной цели. Вы получаете этот вывод для вашей инструкции cmpxchgq.
f0 48 0f b1 16 lock cmpxchg %rdx,(%rsi)
Это f0 — префикс LOCK, а 48 — префикс REX.W. Реальный код операции 0f b1.
Компиляция для 32-битной цели (опция gcc -m32) вызывает ошибку суффикса.
Если вам нужен этот код для работы на 32-битной машине, у вас возникает головная боль при портировании. sizeof (long) — 8 для 64-битной машины и 4 для 32-битной для Linux. ЕСЛИ и это большая проблема, если вся программа достаточно устойчива, чтобы выдерживать ‘long’, идущий от 8 до 4 байтов, вы можете просто изменить суффикс ‘q’ на ‘l’ (это L в нижнем регистре) , Это дает вам инструкцию ‘0f b1’ в ее 32-битной форме:
f0 0f b1 16 lock cmpxchg %edx,(%esi)
Если нет, то вы можете попытаться переписать сборку для 32-разрядной цели, чтобы использовать CMPXCHG8B, которая представляет собой другую инструкцию с другим поведением касания регистров. CMPXCHG8B не является заменой!
Других решений пока нет …