Как процессор / ассемблер узнает размер следующей инструкции?
Для примера представьте, что я строю виртуальную машину. У меня есть массив байтов и цикл while, как узнать, сколько байтов нужно прочитать из массива байтов для следующей инструкции, чтобы интерпретировать инструкцию intel 8086 like?
Правка: (комментируется) процессор считывает код операции по указателю инструкции, с 8086 и CISC у вас есть один байт и два байта инструкций. Как узнать, будет ли следующая инструкция F или FF?
Править: Нашел себе анзю в этом пейсе текста на http://www.swansontec.com/sintel.html
Код операции, или код операции, следует за любыми необязательными префиксами. То опкод сообщает процессору, какую команду Выполнить. Кроме того, опкоды содержат битовые поля, описывающие размер и тип операндов, к которым ожидать. Инструкция NOT, например, имеет код операции 1111011w. In этот код операции, бит w определяет, является ли операнд байтом или слово. Инструкция OR имеет код операции 000010dw. В этом коде операции, бит d определяет, какие операнды являются источником и назначением, и бит w снова определяет размер. Некоторые инструкции имеют несколько разные операционные коды. Например, когда или используется с аккумулятором регистр (AX или EAX) и константа, он имеет специальную экономию места код операции 0000110w, что исключает необходимость в отдельном байте ModR/M. С точки зрения размерного кодирования запоминание точных битов кода операции не является необходимый. Имея общее представление о том, какие типы опкодов доступны для конкретного наставления это важнее.
2 ответа:
Процессор просто декодирует инструкцию. В случае 8086 первый байт сообщает процессору, сколько еще нужно получить. Это не обязательно должен быть первый байт, первый байт должен каким-то образом указывать на то, что вам нужно больше, что больше может указывать на то, что вам нужно еще больше. С 8-битными наборами команд, такими как семейство x86, где вы начинаете с одного байта, а затем видите, сколько еще вам нужно, а также будучи не выровненным, вы должны рассматривать поток команд как байт-поток для декодирования оно.
Вы должны написать себе очень простой симулятор набора команд, только несколько инструкций, возможно, достаточно, чтобы загрузить регистр, добавить что-то к нему, а затем цикл. чрезвычайно познавательно для того, что вы пытаетесь понять, и занимает, может быть, полчаса, если что писать.
TLDR:
Решение является более сложным, чем массив фиксированного размера.
Все дело в контексте, вот почему дизассемблеры, такие как IDA, имеют сложные алгоритмы для этого.
Инструкции имеют переменную длину для x86. Но если вы знаете начало инструкции, вы знаете, где она заканчивается. Из-за этого вы можете знать, где начинается следующий. Я скоро объясню исключения. Но сначала, вот вам пример. пример:
ASM: mov eax, 0 xor eax, eax Machine: b8 00 00 00 00 31 c0
Пояснение:
Переход к eax - это
Обратите внимание, что обе инструкции (B8
, за которым следует 32-битное (4-байтовое) значение для перехода в eax (поскольку eax-32-бит). Другими словами,mov eax, immediate
всегда будет 5 байт. Таким образом, если вы знаете, что вы начинаете с инструкции (не всегда безопасное предположение), и БайтB8
, Вы знаете, что это 5-байтовая инструкция, и что следующая инструкция должна начинаться на 5 байт позже.mov eax, 0
иxor eax, eax
) эффективно делают одно и то же, clear eax до 0.Исключение:
С прыжками / вызовами могут возникнуть сложности. Можно перейти в адресное пространство, которое находится в "середине инструкции"... но все равно казнить.
Давайте посмотрим на:
mov eax, 0x90909090
Машинный код:
b8 90 90 90 90
Если бы у нас позже была команда jmp, которая прыгнула бы в адрес 3-го байта вышеупомянутой инструкции (где-то в середине ее), она просто сделала бы 3 NOPs (no operation) и упала бы на следующую инструкцию после it (не устанавливая eax на 0x90909090). Это происходит потому, что
NOP
является 1-байтовой инструкцией, состоящей из 0x90.