Как справиться с IA-32 кодом или особенности декодера Simics

в 5:25, , рубрики: x86, Блог компании Intel, виртуализация, дизассемблер, Процессоры, метки: ,

Привет, %username%!
Декодирование IA-32 кода — задача архисложная. Чтобы в этом убедиться, можете обратиться к Intel Software Development Manual или к статьям, ранее написанным на хабре: Префиксы в системе команд IA-32, Правильно ли работает ваш дизассемблер?. Давайте посмотрим, как с этой задачей борется функционально точный полноплатформенный симулятор Wind River Simics, позволяющий создать высокопроизводительное виртуальное окружение, в котором любая электронная система, начиная с одной платы и заканчивая целыми многопроцессорными, многоядерными и даже многомашинными системами, может быть определена, разработана и запущена.
Как справиться с IA 32 кодом или особенности декодера SimicsБольшинство библиотек для декодирования IA-32 инструкций генерируют или используют таблицы соответствия между кодами операций и инструкциями. Пример использования данного подхода описан в статье Дизассемблер своими руками. Однако декодирование префиксов и аргументов обычно написано руками: libopcodes, metasm, beaengine, distorm. Данный подход обладает существенным недостатком — добавление поддержки новых наборов команд потребует большого количества ручной работы.
Существуют и другие способы создания декодеров, например с помощью языка GDSL. Данный подход является универсальным и позволяет создавать декодеры для любых архитектур.
Simics же использует совершенно другой не менее универсальный подход для работы с IA-32 инструкциями, названный раздельным декодированием. Также Simics имеет возможность использования внешних декодеров, но об этом немного позже.

Ввод и вывод процедуры декодера

В реальном процессоре за задачу декодирования отвечает отдельный блок логических элементов микросхемы. В симуляторе же ему соответствует некоторая процедура, написанная на языке программирования. Рассмотрим, что подаётся на её вход и какие результаты следует от нее ожидать.

Очевидно, что на вход декодера подаётся массив байт известной длины, полученный на фазе выборки команд (англ. fetch). Кроме того, ему должен быть известен текущий режим процессора (см. Префиксы в системе команд IA-32).

В результате работы декодер должен вернуть код ошибки и результаты анализа последовательности в виде списка полей результата. При этом возможны следующие значения для кода ошибки:

  • Декодирование успешно (код возврата равен длине инструкции > 0). Массив байт был распознан как допустимая инструкция, и список полей содержит информацию о коде операции и её аргументах.
  • Декодирование не успешно (код 0). Ни одна инструкция, определённая в архитектуре, не соответствует входному массиву байт. При этом содержимое полей результата не несёт смысла. Что происходит в этой ситуации дальше на этапе исполнения? Это зависит от архитектуры. Чаще всего невозможность декодировать ведёт к генерации исключения, а в некоторых случаях некорректная инструкция может быть воспринята как NOP — отсутствие операции.
  • Для ISA с переменной длиной инструкций возможна третья ситуация — входных данных недостаточно для принятия однозначного решения (код < 0). Другими словами, на вход декодера передали только часть инструкции, и он, не имея информации о том, какие байты идут в памяти дальше, сообщает об этом.

На рисунке ниже приведён пример алгоритма, сочетающего в себе итерации фаз Fetch и Decode и позволяющего провести декодирование для инструкций с переменной длиной.

Как справиться с IA 32 кодом или особенности декодера Simics

Раздельное декодирование

Основной идеей данного подхода является разделение фазы декодирования на две стадии:

  1. Декодирование префиксов. В эту стадию входит как декодирование всех префиксов, так и проверка конфликтов между ними.
  2. Декодирование кодов операции и операндов. Данная стадия подразумевает вызов декодера, генерированного с помощью SimGen.

Алгоритм работы встроенного декодера Simics.

Само собой разумеется, что вторая фаза зависит от результата, так как в системе команд IA-32 существует такое понятие, как обязательные префиксы, которые фактически являются частью кода операции (см. Префиксы в системе команд IA-32).

Использование внешних декодеров

Simics позволяет подключать дополнительные декодеры с помощью внешних интерфейсов, описанных в Model Builder User's Guide, который поставляется вместе с симулятором. Таким образом, можно подключить множество внешних декодеров и вызывать их по очереди до тех пор, пока какой-нибудь декодер не даст положительного результата или список декодеров не кончится. В этом случае можно будет сделать вывод, что в данной модели данный код операции считается недопустимым.

Как справиться с IA 32 кодом или особенности декодера Simics

Для обеспечения гибкости внешние декодеры в Simics делятся на два типа:

  • Пользовательские декодеры (англ. user decoders) — декодеры, который могут переопределить любой существующий код операции, а также, разумеется, могут добавить возможность декодирования новых инструкций.
  • Расширяющие декодеры (англ. extension decoders) — декодеры, предназначенные для расширения способностей встроенного декодера, то есть для декодирования не поддерживаемых им инструкций.

Разница между предложенными типами декодеров заключается в том, что пользовательские декодеры запускаются первыми — еще до вызова встроенного, что позволяет переопределять результаты декодирования, зашитые в исходную модель. Расширяющие запускаются только в том случае, когда ни пользовательские, ни встроенный декодеры не смогли распознать инструкцию.

И еще одно очевидное замечание

Пользовательские декодеры определяет пользователь, тогда как расширяющие декодеры «зашиты» в модель им не могут быть изменены.
Как справиться с IA 32 кодом или особенности декодера Simics

То есть пользователь, занимаясь разработкой какого-либо ISA, может просто подсунуть свой декодер и посмотреть что изменится, не меняя исходной модели процессора.

Пример

Вам вдруг захотелось поменять местами инструкции NOP и HLT и посмотреть заработает ли ваша система. Для этого Вы просто пишите маленький декодер, который декодирует 0x90 как HLT, а 0xF4 как NOP, прикрепляете его к Simics и пытаетесь запустить систему.

Кроме того, данный подход позволяется переиспользовать уже существующие декодеры вместо написания их с нуля, что значительно сокращает время разработки модели.

Автор: yulyugin

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js