На главную | Содержание | Назад | Вперёд
Наши друзья

 

 

Полезная нагрузка для архитектуры RISC

Во всех примерах этой главы предполагалось использование процессора Intel x86. Но описанные выше хитрости могут применяться для процессоров любого типа. Уже создано довольно много хорошей документации по написанию кода командного интерпретатора для различных платформ. Конечно, каждый тип процессора имеет свои характерные особенности, включая отложенную передачу управления (branch delay) и кэширование11.
Отложенная передача управления
В чипах на основе архитектуры RISC иногда происходит странное явление под названием отложенная передача управления (branch delay, или delay slot). При этом команда может выполняться после каждой ветви кода. Это происходит из-за того, что текущая ветвь кода не начинается, пока не выполнится следующая команда. Таким образом, следующая команда выполняется до того, как управление передается по указанному адресу положения ветви кода, т.е. даже если указана команда перехода, все равно есть команда, которая выполняется сразу после этой команды перехода без осуществления самого этого перехода. В некоторых случаях эта команда не выполняется. Например, можно отменить выполнение команды согласно отложенной передаче управления на архитектурах РА-RISC, установив "обнуляющий" бит в команде перехода.
Наиболее простым решением проблемы является установка команды NOP после каждой ветви кода. Однако опытные программисты используют преимущества отложенной передачи управления и применяют значимые команды для выполнения дополнительной работы. Например, это удобно при необходимости уменьшения размера полезной нагрузки.
Полезная нагрузка для архитектуры MIPS
Архитектура MIPS значительно отличается от архитектуры х86. Во-первых, в чипах R4x00 и R10000 используется 32 регистра и каждая команда имеет размер 32 бит. Во-вторых, применяется конвейерная организация вычислительного процесса12.
Ml PS-команды
Еще одно существенное отличие состоит в том, что для многих команд используется три регистра вместо двух. В командах с двумя операндами результат вычисления заносится в третий регистр. В архитектуре х86 результат всегда заносится в регистр для второго операнда. Наиболее важным является основной код машинной команды, так как он определяет, какая именно команда будет выполнена. Значение дополнительного кода машинной команды зависит от основного кода. В некоторых случаях дополнительный код используется для указания версии команды, в других случаях он определяет, какой регистр будет использован для основного кода.
В табл. 7.1 приведены стандартные MIPS-команды (это далеко не полный список, и мы рекомендуем читателям обратиться к источникам, содержащим более расширенный набор команд MIPS).
Таблица 7.1. Стандартные MIPS-командыТакже интересным свойством MIPS-процессоров является то, что они могут работать и с прямым порядком байтов (little endian), и с обратным порядком (big еп-dian). В DEC-компьютерах обычно применяется прямой порядок байтов, а в SGI-машинах — обратный. Как указывалось выше, от этого зависит способ сохранения чисел в памяти.
Определение положения в памяти
Одной из важнейших задач, которые должны быть реализованы в коде командного интерпретатора, является определение текущего положения в памяти указателя команд. На платформе х86 это обычно делается с помощью вызова, после которого следует вывод данных из стека (см. раздел, посвященный полезной нагрузке). Однако для платформы MIPS не предусмотрено команд для ввода и вывода данных из стека (pop and push).
Итак, у нас есть 32 регистра. Восемь из этих регистров (с 8 по 15) зарезервированы для временного использования. При необходимости мы можем использовать эти регистры.

Нашей первой командой является II. Команда 11 загружает значение непосредственно в регистр.
li register[8] , -1
Эта команда загружает-1 во временный регистр. Нашей целью является получить текущий адрес, поэтому мы выполняем условный переход, при котором сохраняется текущая позиция указателя команд. Это напоминает вызов на платформе х86. Однако на платформе MIPS адрес возврата размещается в регистр 31 и не размещается в стек.
AGAIN:
bltzal register [8], AGAIN
С помощью этой команды текущий адрес указателя команд размещается в регистр 31 и выполняется условный переход. В этом случае условный переход возвращает нас непосредственно к этой команде. И наше текущее положение теперь хранится в регистре 31. Команда bltzal выполняет условный переход, если значение в регистре 8 меньше нуля. Если мы не хотим попасть в бесконечный цикл, нам нужно гарантировать обнуление значения регистра 8. Помните о нашей ужасной отложенной передаче управления? Возможно, она не столь ужасна. Из-за отложенной передачи управления будет выполняться команда после bltzal, причем не имеет значения, какая именно это команда. Это предоставляет нам возможность обнулить значение регистра. Для обнуления регистра8 мы используем команду stli. Эта команда возвращает значение TRUE или FALSE в зависимости от значения операндов. Если opl >= ор2, то результатом выполнения команды является FALSE (нуль). Окончательный код выглядит следующим образом13.
li register[8], -1
AGAIN:
bltzal register[8] , AGAIN slti register[8] , 0, -1
В этом фрагменте кода цикл выполняется только один раз, после чего продолжается выполнение программы. Использование отложенной передачи управления для обнуления значения регистра — весьма удачная уловка. С этого момента в регистре 31 хранится текущее положение указателя команд в памяти.
Как избежать нулевых байтов в машинном коде MIPS
Коды машинных команд для MIPS имеют размер 32 бита. В большинстве случаев требуется, чтобы в машинном коде не было байтов NULL. Это ограничивает наши возможности по использованию кодов машинных команд. Положительным моментом является то, что существует большое количество различных кодов машинных команд, которые выполняют одинаковые задачи. Одной из небезопасных (при атаке) команд является move, т.е. хакер не может использовать команду move для перемещения данных из одного регистра в другой. Вместо этого придется использовать несколько хитрых трюков, чтобы в конечном регистре была размещена копия значения. Как правило, срабатывает использование оператора AND.
and register[8], register[9], -1
Эта команда позволяет скопировать значение из регистра 9 в регистр 8.
В машинном коде для платформы MIPS широко используется машинная команда siti. В этой команде отсутствуют нулевые байты. Напоминаем, что мы уже продемонстрировали, как команда stli может использоваться для обнуления значения в регистре. Очевидно, что мы можем использовать slti для занесения значения 1 в регистр. Хитрости для внесения численных значений в регистр практически ничем не отличаются от тех, что применяются для других платформ. Мы можем записать в регистр безопасное значение и после нескольких операций с регистром получить нужное нам значение. В этой связи очень полезно использовать оператор NOT. Например, если мы хотим, чтобы в регистре 9 было установлено значение MY_VALUE, то можно воспользоваться следующим кодом.
li register [8], -( MY_VALUE + 1) not register[9] , register [8]
Системные вызовы на платформе MIPS
Системные вызовы имеют критически важное значение для большинства полезных нагрузок. В среде Irix/MIPS в регистре vO записывается номер системного вызова. В регистрах от аО до аЗ содержатся аргументы для системного вызова. Специальная команда syscall применяется для активизации системного вызова. Например, системный вызов execv может использоваться для загрузки командного интерпретатора. На платформе Irix кодом системного вызова execv является 0x3F3, а в регистре аО хранится указатель на каталог (т.е. /bin/sh).

 

На главную | Содержание | Назад | Вперёд
 
Яндекс.Метрика