Я видел некоторые эмуляторы, которые утверждают, что они выполняются, и, хотя они делают, их исходный код показывает, что они не анализируют напрямую каждые 1 и 0, чтобы определить инструкцию.
Мой вопрос заключается в том, что если эмулятор должен эмулировать точные коды операций, которые были бы у реального процессора, разве не требовалось бы анализировать правильный двоичный формат кода операции в игре, чтобы эмулировать процессор законно (или вообще)?
Например, в файле игры я храню одну инструкцию, один байт, помеченный следующим образом:
0000 1111
Моя программа должна проверить, что эта инструкция действительно означает (например, «добавить один в регистр A»), но разве ей не нужно проверять каждый ноль и один в текстовом файле, чтобы убедиться в этом?
Тогда эмуляторы будут анализировать целые байты, но целые байты, опять же, будут восьмибитными, и колеблющиеся шаблоны изменяют выходные данные операции.
Например, 0000 1111 может означать добавить один к A, но 0000 1110 может означать добавить A с A.
источник
Ответы:
Экспозиция - пытаюсь прямо ответить на вопрос
Если вы читаете исходный код для эмулятора, а он не читает определенные биты двоичного (исполняемого) файла и все еще добросовестно выполняет код, то возможны три результата:
Как работают эмуляторы
Эмулятор, который выполняет код для другой платформы и / или процессора (например, Wine ), выполняет различные действия. Некоторые этапы абсолютно необходимы для работы эмулятора; другие этапы являются необязательными и представляют возможности для оптимизации производительности.
Требуется : «Разбор» исполняемого кода (машинный код, MSIL, байт-код Java и т. Д.). Синтаксический анализ состоит из:
Требуется : «перевод» разобранного кода (обычно это какая-то абстрактная модель данных, конечный автомат, дерево абстрактного синтаксиса или что-то в этом роде) в команды высокого уровня (например, операторы в C или Java) или низкоуровневыекоманды (например, инструкции процессора для процессора x86). Команды высокого уровня имеют тенденцию быть более оптимальными. Например, если вы анализируете поток кода длинной последовательности инструкций процессора и на высоком уровне определяете, что он запрашивает воспроизведение определенного файла MP3 с диска, вы можете пропустить всю эмуляцию уровня инструкции и просто использовать свой собственный MP3-декодер платформы (который может быть оптимизирован для вашего процессора) для воспроизведения того же файла MP3. С другой стороны, если бы вы «отслеживали» выполнение эмулируемой программы в буквальном смысле, насколько это возможно, это было бы медленнее и менее оптимальным, поскольку вы бы отказались от большей части оптимизации, от которой вы выигрываете, выполняя инструкции самостоятельно.
Необязательно : «Оптимизация» и анализ потока кода большой полосы эмулируемого программного кода или всей программы для определения полной последовательности выполнения и построения очень подробной и сложной модели того, как ваш эмулятор будет эмулировать это поведение с возможностями родной платформы. Wine делает это в некоторой степени, но ему помогает тот факт, что код, который он переводит, имеет формат от x86 до x86 (это означает, что в обоих случаях процессор представляет собой один и тот же набор команд, поэтому все, что вам нужно сделать, это подключить Windows код во внешнюю среду на основе UNIX и пусть он работает "изначально").
Торт по аналогии
Рассматривая производительность эмулятора, подумайте о том, сколько листов бумаги вам понадобится, чтобы записать инструкции для себя, если вы смотрели, как кто-то на видео (со звуком) выпекает торт, в следующих сценариях:
Если вы никогда в своей жизни не двигали руками или не тренировали мышцы тела; (подсказка: вам понадобятся тысячи листов бумаги для документирования подробных шагов движения руки, координации рук и глаз, наклона, скорости, положения, базовых техник, таких как захват, хранение посуды, разминание и т. д.)
Если у вас есть базовое управление двигателем (вы можете ходить и кормить себя), но никогда в своей жизни не готовили никакой пищи; (подсказка: вам понадобятся десятки листов бумаги для документирования отдельных шагов, и вам, вероятно, понадобится много практики, чтобы освоить такие вещи, как разминание и хранение незнакомой посуды, но вы сможете документировать это гораздо реже время, чем в предыдущем случае)
Если вы никогда в своей жизни не пекли пирог, но раньше вы готовили пищу; (подсказка: вам понадобится пара листов бумаги, но не более 10; вы уже знакомы с измерением ингредиентов, перемешиванием и т. д.)
Если вы уже много раз пекли пирог и хорошо знакомы с процессом, но не знаете, как испечь этот конкретный сорт / аромат торта (подсказка: вам может понадобиться половина листа бумаги, чтобы записать основные ингредиенты и сколько нужно времени в духовке, и все тут) .
По сути, на этих возрастающих уровнях «компетенции эмулятора» эмулятор может делать более высокоуровневые вещи «изначально» (используя уже известные ему подпрограммы и процедуры), и ему приходится выполнять меньше «трассировки» (используя подпрограммы и процедуры, которыми он является. следуя буквально из эмулируемой программы).
Чтобы выразить эту аналогию в терминах компьютера, вы можете представить себе эмулятор, который эмулирует реальное оборудование , на котором будет работать эмулируемая программа, и точно отслеживает поведение этого оборудования, возможно, даже до аппаратного (схемного) уровня; это было бы очень медленно по сравнению с эмулятором, который анализирует программу до такого уровня сложности, который он понимает, когда пытается воспроизвести звуковой файл, и может «воспроизводить» этот звуковой файл «без изменений», не отслеживая инструкции эмулируемой программы. так.
О «отслеживании» (он же rote mimicry) против «нативного исполнения»
И последнее: трассировка идет медленно, главным образом потому, что вам приходится использовать много памяти для «репликации» очень подробных, запутанных компонентов того, что вы эмулируете, и вместо того, чтобы просто выполнять инструкции на центральном процессоре вашего хоста, вы должны выполнять инструкции которые выполняют инструкции (см. уровень косвенности?), что приводит к неэффективности. Если бы вы пошли на все, и эмулировали физическое оборудование компьютерной системы, а также программу, вы бы эмулировали процессор, материнскую плату, звуковую карту и т. Д., Что, в свою очередь, «отслеживало бы» выполнение программы как вашу. эмулятор «отслеживает» выполнение процессора, и при таком количестве уровней трассировки все это будет чрезвычайно медленным и громоздким.
Вот подробный пример того, где эмулятору не нужно читать каждый бит / байт программы ввода, чтобы эмулировать его.
Допустим, мы знаем об API, написанном на C или C ++ (детали не важны) для эмулируемой программной среды, где у этого API есть функция
void playSound(string fileName)
. Допустим, мы знаем, что семантика этой функции состоит в том, чтобы открыть файл на диске, прочитать его содержимое, выяснить, в какой кодировке находится файл (MP3? WAV? Что-то еще?), А затем воспроизвести его на динамиках в обычная / ожидаемая частота дискретизации и шаг. Если мы прочтем из нативного кода набор инструкций, который говорит: «войдите в процедуру playSound, чтобы начать воспроизведение звука/home/hello/foo.mp3
», мы можем прекратить чтение программного кода прямо здесь и использовать наш собственный(оптимизированная!) рутина для непосредственного открытия этого звукового файла и его воспроизведения. Нужно ли следовать эмулируемому процессору на уровне инструкций? Нет, на самом деле, нет, если мы верим, что знаем, что делает API.Дикая разница возникает! (проблема в земле высокого уровня)
Конечно, читая кучу инструкций и «выводя» высокоуровневый план выполнения, как в примере выше, вы рискуете не точно подражать поведению исходной программы, работающей на исходном оборудовании. Скажем, например, исходное оборудование могло иметь аппаратные ограничения, которые позволяли ему воспроизводить только 8 звуковых файлов одновременно. Что ж, если ваш новый компьютер может воспроизводить одновременно 128 звуковых файлов, и вы воспроизводите
playSound
процедуру на высоком уровне, что может помешать вам воспроизводить более 8 звуковых файлов одновременно? Это может вызвать ... странное поведение (в лучшую или худшую сторону) в эмулированной версии программы. Эти случаи могут быть решены путем тщательного тестирования или, возможно, путем хорошего понимания исходной среды выполнения.Например, DOSBox имеет функцию, которая позволяет преднамеренно ограничивать скорость выполнения эмулируемой программы DOS, поскольку некоторые программы DOS будут работать некорректно, если им будет разрешено работать на полной скорости; на самом деле они зависели от тактовой частоты процессора для выполнения с ожидаемой скоростью. Этот тип «функции», которая намеренно ограничивает среду выполнения, может быть использован для обеспечения хорошего компромисса между верностью выполнения (то есть обеспечением правильной работы эмулируемой программы) и эффективностью выполнения (то есть созданием представления программы, которая достаточно высокого уровня, чтобы его можно было эффективно эмулировать с минимумом отслеживания).
источник
«Разбор» означает «просмотреть текст и выяснить, что это значит». Текстовый и языковой синтаксис сложен, потому что не только отдельные «слова» означают вещи, но и значение может меняться в зависимости от их положения и близости к другим словам.
Вероятно, более точный термин для применения в отношении того, что процессор делает с потоком команд (который намного проще, чем анализ), - это «декодирование» - и да, эмулятор должен «декодировать» инструкции таким же образом. Я полагаю, что «синтаксический анализ» на самом деле не так уж плох, если учесть сложность набора инструкций x86.
Процессоры на самом деле не проверяют инструкции. Любой ЦП имеет внутренний регистр, который указывает на область памяти в ОЗУ. Процессор читает его, считывает еще пару байтов, если необходимо, и затем пытается выполнить его. Современные процессоры запустят «процесс исключения», если инструкция недопустима.
Старые процессоры, как и старый 8-битный 6502, даже не делали этого - некоторые незаконные инструкции блокировали процессор, другие делали странные, недокументированные вещи. (Некоторый поиск покажет ряд недокументированных x86-инструкций, найденных во всех процессорах в x86-пантеоне - например,
CPUID
инструкция существовала на некоторых 486-ти процессорах до того, как Intel официально зарегистрировала ее.)Хороший и точный эмулятор ЦП просто слепо жует поток команд, как реальный ЦП, хотя он может делать разные вещи в условиях, которые могут привести к блокировке системы, например, отображать диалоговое окно, сообщающее, что ваш виртуальный ЦП не работает заблокировать ваш эмулятор.
Кроме того, вы говорите «нужно проверять каждый ноль и единицу в текстовом файле», но обычно вы не кормите текстовые файлы эмуляторов. Эмулятору ЦП требуется эмулируемая память - и поскольку многие платформы используют сопоставленные с памятью операции ввода-вывода, также эмулируются устройства ввода-вывода. Для эмуляции таких вещей, как прошивка, необходимо иметь двоичные образы этой прошивки - либо легальные копии реальной прошивки, либо замену прошивки с открытым исходным кодом. Эмуляция всей платформы (например, «платформы ПК», компонентом которой является процессор x86) требует больше, чем эмуляция процессора.
источник