Эта статья начинает цикл, посвященный более глубокому изучению
ассемблера. Теперь каждая статья будет разделена на две части. В первой
части будут рассматриваться некоторые теоретические сведения, а во
второй - новые команды, примеры кода и приемы программирования на
ассемблере.
Формат машинных команд IA-32
В настоящее время существует несколько сотен (если не больше) языков
программирования, но почти все компиляторы транслируют программы в язык
ассемблера. Ассемблер, в свою очередь, транслирует программу в особые
комбинации нулей и единиц - машинный язык (язык машинных команд),
единственный язык, который понимает компьютер. На первых компьютерах
все программы писались на машинном языке, но в 50-х гг. стали
использовать его символический аналог - язык ассемблера.
Давайте посмотрим, каким машинных командам соответствуют команды ассемблера. Рассмотрим простейшую команду:
mov ebx, eax
На машинном языке это будет выглядеть так:
8B D8
Здесь 8B - код операции. Рассмотрим другой пример:
mov ecx, 128
На машинном языке ей соответствует:
B9 00000080
Код операции - B9. Можно сделать вывод, что прямого соответствия
между командой ассемблера и соответствующей машинной командой нет.
Команда в примере одна и та же, а коды операций машинного языка -
разные. Дело в том, что большинство команд ассемблера имеют несколько
возможных вариантов сочетания операндов, а машинная команда всегда
однозначна по отношению к производимым действиям на уровне аппаратуры.
Код операции является номером микропрограммы в блоке микропрограммного
управления. Для каждой конкретной команды ассемблера с конкретным
вариантом сочетания операндов существует своя микропрограмма и свой код
операции.
Любая команда ассемблера содержит несколько элементов:
- Элемент, описывающий, что делать, называется кодом операции (далее КОП).
Элементы, описывающие объекты, с которыми нужно что-то делать,
называются операндами. Операнды могут не задаваться явно, а
подразумеваться по умолчанию
Элементы, описывающие, как делать, называются типами операндов. Они
обычно задаются неявно.
Команды передачи управления
Последовательно работает очень мало программ. Обычно в программе
есть точки, в которых принимается решение о том, какая команда будет
выполняться следующей. Это решение может быть безусловным (управление
передается конкретной команде, которая находится на некотором удалении
от текущей) и условным (команда, которая будет выполняться следующей,
определяется на основе анализа некоторых условий и данных). Но каким же
образом обозначается место, куда необходимо передать управление? Оно
обозначается с помощью меток. Метка - символическое имя определенной
ячейки памяти, предназначенное для использования в командах передачи
управления в качестве операнда. Транслятор ассемблера присваивает
каждой метке три атрибута:
- Имя сегмента кода, в котором эта метка описана
- Смещение, то есть расстояние в байтах от начала этого сегмента
- Тип метки
Метки бывают двух типов:
- near. Переход на такую метку возможен только в пределах того сегмента кода, в котором она описана
- far. Переход на метку возможен в результате межсегментной передачи управления
Определить метку можно двумя способами:
- с помощью директивы LABEL
- с помощью оператора ":" (двоеточие).
Используя оператор ":", можно определить метку только ближнего типа (near). Например:
m: mov eax,1
Используя оператор LABEL, можно определить метку любого типа. Например:
m label near mov eax,1
или
m label far mov eax,1
Применение меток оправдано во многих случаях. В одних лучше
использовать метки ближнего типа, в других - дальнего. В следующих
уроках мы рассмотрим эти случаи и научимся правильно выбирать тип метки.
Синтаксис команды безусловного перехода такой:
jmp [модификатор] адрес_перехода
Существует несколько кодов машинных команд, соответствующих JMP. Они
отличаются дальностью перехода и способом задания целевого адреса.
Операнд адрес_перехода может находиться в текущем сегменте(близкий
переход) кода или в другом (дальний переход). Адресом перехода может
являться имя метки:
jmp m m: mov eax,1
Есть еще такой вариант (указывается не адрес перехода, а место, где он хранится):
lea eax,m jmp eax m: mov eax,1
Теперь перейдем к командам условного перехода. В таких командах
решение о том, какая команда будет выполняться следующей, принимается в
зависимости от некоторых условий, различных для разных команд перехода
. Таких команд 18, они позволяют проверить:
- отношение операндов со знаком (больше либо меньше)
- отношение операндов без знака (выше или ниже)
- состояние арифметических флагов ZF, SF, CF, OF, PF(но не AF)
Все команды условного перехода имеют одинаковый синтаксис:
jcc метка_перехода
Любая из них начинается с символа "j" (от слова jump), а вместо "cc"
указывается конкретное условие, которое должна проанализировать
программа. Метка перехода может находиться только в пределах текущего
сегмента! Поэтому необходимость в модификаторе отпадает (всегда near).
Условие обязательно должно быть сформировано до команды передачи
управления. Его источником может служить любая команда, изменяющая
состояние арифметических флагов или регистра ECX/CX.
В большинстве случаев Вы будете пользоваться командой CMP. Поэтому
сейчас я немного расскажу вам о ней. Команда CMP производит практически
те же действия, что и команда SUB, только она не записывает результат
вычитания на место первого операнда, а просто устанавливает флаги (нас
интересует флаг знака результата, и флаг нулевого результата). Вот ее
синтаксис:
cmp операнд_1, операнд_2
Флаги, устанавливаемые командой CMP, можно проанализировать
командами условного перехода. Понимание принципа формирования названий
команд условного перехода облегчит их запоминание и дальнейшее
практическое использование (см. табл. 1).
|
Таблица 1. Принцип формирования элемента "сс" команд условного перехода |
| Мнемоническое обозначение |
Оригинальный термин |
Перевод |
Тип операндов |
| e
| Equal |
Равно |
Любые |
| n |
Not |
Нет |
Любые |
| g |
Greater |
Больше |
Числа со знаком |
| l |
Less |
Меньше |
Числа со знаком |
| a |
Above |
Выше(то есть больше) |
Числа без знака |
| b |
Below |
Ниже(то есть меньше) |
Числа без знака |
Привожу пример программы, которая обнуляет поле pole_m длинной n байт:
.data n equ 50 pole_m db n dup (?) .code ;... xor bx, bx ; очищаем bx m1: mov mem[bx], 0 ; заносим в mem[bx] 0 inc bx ; увеличение bx на 1 cmp bx, n ; сравниваем bx с n (вычитаем n из bx) jne m1 ; если bx не равен n, то повторяем все завново exit: ;...
В табл. 2 перечислены команды условного перехода, которые можно использовать после команды cmp:
|
Таблица 2. Команды условного перехода |
| Типа операндов |
Мнемокод команды условного перехода |
Критерий условного перехода |
Значения флагов для перехода |
| Любые |
JE |
операнд_1=операнд_2 |
ZF=1 |
| Любые |
JNE |
операнд_1<>операнд_2 |
ZF=0 |
| Со знаком |
JL/JNGE |
операнд_1<операнд_2 |
SF<>OF |
| Со знаком |
JLE/JNG |
операнд_1<=операнд_2 |
SF<>OF или ZF=1 |
| Со знаком |
JG/JNLE |
операнд_1>операнд_2 |
SF=OF или ZF=0 |
| Со знаком |
JGE/JNL |
операнд_1=>операнд_2 |
SF=OF |
| Без знака |
JB/JNAE |
операнд_1<операнд_2 |
CF=1 |
| Без знака |
JBE/JNA |
операнд_1<=операнд_2 |
CF=1 или ZF=1 |
| Без знака |
JA/JNBE |
операнд_1>операнд_2 |
CF=0 и ZF=0 |
| Без знака |
JAE/JNB |
операнд_1=>операнд_2 |
CF=0 |
Теперь, используя эту таблицу, Вы сможете с легкостью применять команды условного перехода. На этом мы закончим. Удачи! Автор: miksayer |