- •1. Предварительные сведения 6
- •2. Процессоры intel в реальном режиме 11
- •3. Директивы и операторы ассемблера 51
- •Введение
- •1. Предварительные сведения
- •1.1. Подготовка программ на языке ассемблера
- •1.2. Представление данных в компьютерах
- •1.2.1. Двоичная система счисления
- •1.2.2. Биты, байты и слова
- •1.2.3. Шестнадцатеричная система счисления
- •1.2.4. Числа со знаком
- •1.2.5. Логические операции
- •1.2.6. Коды символов
- •2. Процессоры intel в реальном режиме
- •2.1. Регистры процессора
- •2.1.1. Регистры общего назначения
- •2.1.2. Модели памяти и сегментные регистры
- •2.1.3. Стек
- •2.1.4. Регистр флагов
- •2.2.4. Косвенная адресация
- •2.2.5. Адресация по базе со смещением
- •2.2.6. Косвенная адресация с масштабированием
- •2.2.7. Адресация по базе с индексированием
- •2.2.8. Адресация по базе с индексированием и масштабированием
- •2.3. Основные непривилегированные команды
- •2.3.1. Пересылка данных
- •2.3.2. Двоичная арифметика
- •2.3.3. Десятичная арифметика
- •2.3.4. Логические операции
- •2.3.5. Сдвиговые операции
- •2.3.6. Операции над битами и байтами
- •2.3.7. Команды передачи управления
- •2.3.8. Строковые операции
- •2.3.9. Управление флагами
- •2.3.10. Загрузка сегментных регистров
- •2.3.11. Другие команды
- •3. Директивы и операторы ассемблера
- •3.1. Структура программы
- •3.2. Директивы распределения памяти
- •3.2.1. Псевдокоманды определения переменных
- •3.2.2. Структуры
- •3.3. Организация программы
- •3.3.1. Сегменты
- •3.3.2. Модели памяти и упрощенные директивы определения сегментов
- •3.3.4. Процедуры
- •3.3.5. Конец программы
- •3.3.6. Директивы задания набора допустимых команд
- •3.3.7. Директивы управления программным счетчиком
- •3.3.8. Глобальные объявления
- •3.3.9. Условное ассемблирование
- •3.4. Выражения
- •3.5. Макроопределения
- •3.5.1. Блоки повторений
- •3.5.2. Макрооператоры
- •3.5.3. Другие директивы, используемые в макроопределениях
- •3.6. Другие директивы
- •3.6.1. Управление файлами
- •3.6.2. Управление листингом
- •3.6.3. Комментарии
- •Литература
2.1.3. Стек
Стек — это специальным образом организованный участок памяти, используемый для временного хранения переменных, для передачи параметров вызываемым подпрограммам и для сохранения адреса возврата при вызове процедур и прерываний. Процессор имеет особые команды для записи в стек (PUSH) и считывания из стека (POP). Элемент, записанный в стек последним, считывается из него первым и наоборот. Таким образом, если записать в стек числа 1, 2, 3, то считываться они будут в обратном порядке — 3, 2, 1. Стек располагается в сегменте памяти, описываемом регистром SS, текущее смещение вершины стека (последней заполненной ячейки) записано в регистре ESP, причем при записи в стек значение этого смещения уменьшается, то есть стек растет в направлении от максимально возможного адреса к меньшим (младшим) адресам (рис. 4). Такое расположение стека может быть необходимо, например в бессегментной модели памяти, когда все сегменты, включая сегмент стека и сегмент кода, занимают одну и ту же область — всю память. Тогда программа исполняется в нижней области памяти, в области малых адресов, и EIP растет, а стек располагается в верхней области памяти, и ESP уменьшается.
-
Дно стека
FFFFFFFC
FFFFFFF8
Параметры
FFFFFFF4
FFFFFFF0
EBP = FFFFFFF0
FFFFFFEC
Локальные переменные
FFFFFFE8
FFFFFFE4
ESP = FFFFFFE4
Рис. 4. Стек
Если необходимо обращаться к ячейкам стека без использования команд PUSH и POP (например, при обращении в процедуре к параметрам, переданным в стеке), сделать это можно при помощи регистра EBP. Адрес сегмента при этом будет вычисляться с использованием регистра SS.
2.1.4. Регистр флагов
Еще один важный регистр, использующийся при выполнении большинства команд, — регистр флагов EFLAGS (условное название). Как и раньше, его младшие 16 бит, соответствующие этому регистру до 80386, называются FLAGS. В этом регистре каждый бит является флагом, то есть устанавливается в 1 при определенных условиях или установка его в 1 изменяет поведение процессора. Все флаги, расположенные в старшем слове регистра EFLAGS, имеют отношение к управлению защищенным режимом, поэтому здесь рассмотрен только регистр FLAGS (рис. 5).
0 |
NT |
IOPL |
OF |
DF |
IF |
TF |
SF |
ZF |
0 |
AF |
0 |
PF |
1 |
CF |
15 0
Рис. 5. Регистр флагов FLAGS
CF — флаг переноса. Устанавливается в 1, если результат предыдущей операции не уместился в приемнике и произошел перенос из старшего бита или если требуется заем (при вычитании), иначе устанавливается в 0. Например, после сложения слова 0FFFFh и 1, если регистр, в который надо поместить результат, — слово, в него будет записано 0000h и флаг CF установится (CF = 1).
PF — флаг четности. Устанавливается в 1, если младший байт результата предыдущей команды содержит четное число бит, равных 1, устанавливается в 0, если нечетное. (Это не то же самое, что делимость на два. Число делится на два без остатка, если его самый младший бит равен нулю, и не делится, если он равен 1).
AF — флаг полупереноса или вспомогательного переноса. Устанавливается в 1, если в результате предыдущей операции произошел перенос (или заем) из третьего бита в четвертый. Этот флаг используется автоматически командами двоично-десятичной коррекции.
ZF — флаг нуля. Устанавливается в 1, если результат предыдущей команды — ноль.
SF — флаг знака. Этот флаг всегда равен старшему биту результата.
TF — флаг ловушки. Этот флаг был предусмотрен для работы отладчиков, не использующих защищенный режим. Установка его в 1 приводит к тому, что после выполнения каждой команды программы управление временно передается отладчику (вызывается прерывание 1 — см. описание команды INT).
IF — флаг прерываний. Установка этого флага в 1 приводит к тому, что процессор перестает обрабатывать прерывания от внешних устройств (см. описание команды INT). Обычно его устанавливают на короткое время для выполнения критических участков кода.
DF — флаг направления. Этот флаг контролирует поведение команд обработки строк — когда он установлен в 1, строки обрабатываются в сторону уменьшения адресов, когда DF = 0 — наоборот.
OF — флаг переполнения. Этот флаг устанавливается в 1, если результат предыдущей арифметической операции над числами со знаком выходит за допустимые для них пределы. Например, если при сложении двух положительных чисел получается число со старшим битом, равным единице, то есть отрицательное, и наоборот. Флаги IOPL (уровень привилегий ввода-вывода) и NT (вложенная задача) применяются в защищенном режиме.
2.2. Способы адресации
Большинство команд процессора вызываются с аргументами, которые в ассемблере принято называть операндами. Например: команда сложения содержимого регистра с числом требует задания двух операндов — содержимого регистра и числа. Далее рассмотрены все существующие способы задания адреса хранения операндов — способы адресации.
2.2.1. Регистровая адресация
Операнды могут располагаться в любых регистрах общего назначения и сегментных регистрах. В этом случае в тексте программы указывается название соответствующего регистра, например команда, копирующая в регистр АХ содержимое регистра ВХ, записывается как
mov ax,bx
2.2.2. Непосредственная адресация
Некоторые команды (все арифметические команды, кроме деления) позволяют указывать один из операндов непосредственно в тексте программы, например команда
mov ax,2
помещает в регистр АХ число 2.
2.2.3. Прямая адресация
Если известен адрес операнда, располагающегося в памяти, можно использовать этот адрес прямо в команде. Если, например, операнд — слово, находящееся в сегменте, на который указывает ES, со смещением от начала сегмента 0001, то команда
mov ax,es:0001
поместит это слово в регистр AX. В реальных программах обычно для задания статических переменных используют директивы определения данных, которые позволяют ссылаться на статические переменные не по адресу, а по имени. Тогда, если в сегменте, указанном в ES, была описана переменная word_var размером в слово, можно записать ту же команду как
mov ax,es:word_var
В таком случае ассемблер сам заменит имя “word_var” на соответствующий адрес. Если селектор сегмента данных находится в DS, имя сегментного регистра при прямой адресации можно не указывать, DS используется по умолчанию. Прямая адресация иногда называется адресацией по смещению.
Адресация отличается для реального и защищенного режимов. В реальном режиме (так же как и в режиме V86) смещение всегда 16-битное; это значит, что ни непосредственно указанное смещение, ни результат сложения содержимого разных регистров в более сложных методах адресации не могут превышать границ слова. В защищенном режиме смещение не может превышать границ двойного слова.