Ошибка встроенной сборки GCC: неверный суффикс инструкции для `lidt ' - PullRequest
1 голос
/ 03 июня 2019

Я пытаюсь вызвать некоторый ассемблерный код из C. Я недавно переключил программу с x86 на x86-64 и до того, как она заработала. У меня есть этот код:

__asm__ __volatile__("lidtl (%0)" : : "r" (&idt_reg));

Где &idtreg - ссылка на структуру. Компиляция этого с GCC дает мне эту ошибку:

неверный суффикс инструкции для `lidt '

Когда я добавляю токен $:

__asm__ __volatile__("lidtl $(%0)" : : "r" (&idt_reg));

Я получаю эту ошибку:

недопустимый операнд немедленного регистра (% rax)

Почему возникает эта проблема и как я могу ее решить?

1 Ответ

4 голосов
/ 03 июня 2019

В 32-битном коде операнд памяти для LIDT является 32-битным.В синтаксисе AT & T суффикс инструкции L заставляет ассемблер всегда принимать long (32-бит).В 64-битном коде операнды памяти являются 64-битными.Если вы используете суффикс инструкции, тогда он должен быть Q (quadword).Квадратное слово - 64-битное.

Ассемблер достаточно умен, чтобы знать размер LIDT в зависимости от того, генерирует ли он 32-битный или 64-битный код.Лучшая альтернатива - позволить ассемблеру определять размер, не указывая размер в суффиксе инструкции.Просто используйте LIDT вместо этого.Код может выглядеть следующим образом:

__asm__ ("lidt %0" : : "m" (idt_reg));

Я отбросил volatile, поскольку это неявно, когда нет выходных операндов.Я использую m (операнд памяти) в качестве ограничения, чтобы избежать проблем с передачей адресов памяти через регистр.Передача адреса через регистр требует использования memory Clobber или аналогичного механизма, чтобы гарантировать, что данные по этому адресу будут доступны в памяти до того, как будет выпущена встроенная сборка.Из документации GCC :

Clobber "memory" сообщает компилятору, что код сборки выполняет чтение или запись в память элементов, отличных от перечисленных ввходные и выходные операнды (например, , доступ к памяти, на которую указывает один из входных параметров ).Чтобы убедиться, что память содержит правильные значения, GCC может потребоваться сбросить определенные значения регистра в память перед выполнением asm.

Если вы использовали ограничение r (в этом нет необходимости), тогдакод был бы:

__asm__ ("lidt (%0)" : : "r" (&idt_reg) : "memory");

Сноски

  • Удалив суффикс инструкции L или Q, эта версия должна компилироваться, генерируя 32-битную или 64-битную-битные программы.
  • Встроенная сборка GCC сложно получить правильный , и если вы ошиблись, сгенерированный код может не всегда соответствовать ожидаемому.
...