Ассемблер для начинающих
Эта статья начинает цикл, посвященный более глубокому изучению ассемблера. Теперь каждая статья будет разделена на две части. В первой части будут рассматриваться некоторые теоретические свнедения, а во второй - новые команды, примеры кода и приемы программирования на ассемблере.
В настоящее время существует несколько сотен (если не больше) языков программирования, но почти все компиляторы транслируют программы в язык ассемблера. Ассемблер, в свою очередь, транслирует программу в особые комбинации нулей и единиц - машинный язык (язык машинных команд), единственный язык, который понимает компьютер. На первых компьютерах все программы писались на машинном языке, но в 50-х гг. стали использовать его символический аналог - язык ассемблера.
Давайте посмотрим, каким машинных командам соответствуют команды ассемблера. Рассмотрим простейшую команду:
mov ebx, eax
На машинном языке это будет выглядеть так:
8B D8
Здесь 8B - код операции. Рассмотрим другой пример:
mov ecx, 128
На машинном языке ей соответствует:
B9 00000080
Код операции - B9. Можно сделать вывод, что прямого соответствия между командой ассемблера и соответствующей машинной командой нет. Команда в примере одна и та же, а коды операций машинного языка - разные. Дело в том, что большинство команд ассемблера имеют несколько возможных вариантов сочетания операндов, а машинная команда всегда однозначна по отношению к производимым действиям на уровне аппаратуры. Код операции является номером микропрограммы в блоке микропрограммного управления. Для каждой конкретной команды ассемблера с конкретным вариантом сочетания операндов существует своя микропрограмма и свой код операции.
Любая команда ассемблера содержит несколько элементов:
Последовательно работает очень мало программ. Обычно в программе есть точки, в которых принимается решение о том, какая команда будет выполняться следующей. Это решение может быть безусловным (управление передается конкретной команде, которая находится на некотором удалении от текущей) и условным (команда, которая будет выполняться следующей, определяется на основе анализа некоторых условий и данных). Но каким же образом обозначается место, куда необходимо передать управление? Оно обозначается с помощью меток. Метка - символическое имя определенной ячейки памяти, предназначенное для использования в командах передачи управления в качестве операнда. Транслятор ассемблера присваивает каждой метке три атрибута:
Определить метку можно двумя способами:
Используя оператор ":", можно определить метку только ближнего типа (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, они позволяют проверить:
Все команды условного перехода имеют одинаковый синтаксис:
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 |
Теперь, используя эту таблицу, Вы сможете с легкостью применять команды условного перехода. На этом мы закончим. Удачи!