Есть несколько проблем с вашей встроенной операцией сборки, большинство из которых указаны сообщениями об ошибках.
Первое сообщение об ошибке Error: operand type mismatch for `push'
, соответствует инструкции pushw %eax
. Ошибка возникает из-за того, что суффикс размера операнда, который вы использовали, w
, не соответствует фактическому размеру операнда, %eax
. Вы сказали ему использовать инструкцию для нажатия 16-битного значения в стеке, но при условии, что 32-разрядный регистр является операндом. Вы можете исправить это, используя pushw %ax
, но это не то, что вы хотите. Он сохранил бы только младшие 16 бит регистра RAX, а не весь регистр.
Другим «очевидным» решением было бы использовать pushl %eax
, но есть две проблемы с этим. Сначала, чтобы исправить другие проблемы, вам необходимо изменить весь регистр RAX, а это значит, что вам нужно сохранить все 64 бита, а не только более низкие 32 бита. Во-вторых, нет 32-разрядной команды PUSH в 64-битном режиме, поэтому вы вынуждены использовать pushq %rax
независимо.
Следующие два сообщения об ошибке: Error: unsupported for `mov'
. Эти сообщения об ошибках соответствуют инструкциям movl %cr0,%eax
и movl %eax,%cr0
. и оба являются результатом одной и той же проблемы. В 64-битном режиме нет 32-разрядной версии этих операндов. Вам нужно использовать 64-битный операнд, поэтому исправить просто использовать RAX вместо EAX. Вот где все 64-битные RAX сбиваются, и почему я сказал, что вам нужно сохранить весь регистр.
Последнее сообщение об ошибке Error: operand type mismatch for `pop'
. Это результат аналогичной проблемы, такой как первая. В этом случае вы не использовали суффикс размера операнда, а это значит, что ассемблер попытается определить размер операнда на основе операндов. Поскольку вы использовали 32-разрядный операнд, %eax
, он использует 32-разрядный размер операнда. Как и в случае с PUSH, в 64-битном режиме есть 32-разрядная команда POP, поэтому вы также не можете использовать %eax
. В любом случае, поскольку инструкция PUSH должна быть 64-разрядной, для команды POP должно быть установлено 64-битное соответствие, поэтому исправление должно использовать popq %rax
.
Наконец, одна из проблем, которая не указана сообщением об ошибке, заключается в том, что в 64-битном режиме размер CR0 расширяется до 64 бит. В то время как дополнительные 32 бита в настоящее время зарезервированы и должны быть установлены на ноль, они могут быть определены в будущих процессорах. Поэтому инструкция orl $0x40000000,%eax
должна сохранять верхние 64-битные. К сожалению, этого не происходит, он очистит верхние 32-битные биты RAX, что означает, что эта инструкция также непреднамеренно очистит любой из этих битов, которые могут дать будущие процессоры. Поэтому его следует заменить на orq $0x40000000,%rax
.
Таким образом, фиксированная последовательность команд будет:
pushq %rax
movq %cr0, %rax
orq $0x40000000, %rax
movq %rax, %cr0
wbinvd
popq %rax
Это не то, что я собираюсь предложить использовать в вашей инлайн сборки, однако. Это можно упростить, позволяя GCC выбрать используемый регистр. Таким образом, нет необходимости его сохранять. Вот что я хотел бы предложить вместо этого:
long long dummy;
asm volatile ("movq %%cr0, %0\n\t"
"orq $0x40000000, %0\n\t"
"movq %0, %%cr0\n\t"
"wbinvd"
: "=r" (dummy) : :);
не 'pushw' для размера слова (16 бит)? eax 32bit, попробуйте 'pushl' – Leeor
Привет @Leeor, Большое спасибо за ваш комментарий! но pushl сообщит об ошибке: memory.c: 645: Ошибка: недопустимый суффикс инструкции для 'push '; Я также пробовал pushq, который не работает ни – Mike