В 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 сложно получить правильный , и если вы ошиблись, сгенерированный код может не всегда соответствовать ожидаемому.