ЯЗЫК МАКРОАССЕМБЛЕРА IBM PC (Справочное пособие)
Составитель: В.Н.Пильщиков (МГУ, ВМК) (январь 1992 г.)
В пособии рассматривается язык макроассеблера для персональных ЭВМ типа IBM PC (язык MASM, версия 4.0).
Пособие состоит из 4 глав. В главе 1 рассмотрены особенности персональных компьютеров типа IBM PC и приведены начальные сведения о языке MASM. В главе 2 описывается система команд этих компьютеров. Глава 3 посвящена посвящена собственно языку MASM. В главе 4 приведены примеры фрагментов программ и полных программ на MASM для решения различных задач.
В пособии не рассматриваются вопросы, связанные с обработкой двоично-десятичных чисел и работой арифметического сопроцессора 8087 или 80287.
Под термином "ПК" в пособии понимается персональный компьютер типа IBM PC c микропроцессором 8088/8086, 80186 или 80286.
ГЛАВА 1. ОСОБЕННОСТИ ПК. ВВЕДЕНИЕ В MASM.
1.1. ОПЕРАТИВНАЯ ПАМЯТЬ. РЕГИСТРЫ.
1.1.1 Оперативная память
Объем оперативной памяти ПК - 2^20 байтов (1 Мб). Байты нумеруются начиная с 0, номер байта называется его адресом. Для ссылок на байты памяти используются 20-разрядные адреса: от 00000 до FFFFF (в 16-ричной системе).
Байт содержит 8 разрядов (битов), каждый из которых может принимать значение 1 или 0. Разряды нумеруются справа налево от 0 до 7:
-----------------
| | | | | | | | |
-----------------
7 6 5 4 3 2 1 0
Байт - это наименьшая адресуемая ячейка памяти. В ПК используются и более крупные ячейки - слова и двойные слова. Слово - это два соседних байта, размер слова - 16 битов (они нумеруются справа налево от 0 до 15). Адресом слова считается адрес его первого байта (с меньшим адресом); этот адрес может быть четным и нечетным. Двойное слово - это любые четыре соседних байта (два соседних слова), размер такой ячейки - 32 бита; адресом двойного слова считается адрес его первого байта.
Байты используются для хранения небольших целых чисел и символов,
слова - для хранения целых чисел и адресов, двойные слова - для хранения "длинных" целых чисел и т.н. адресных пар (сегмент:смещение).
1.1.2 Регистры
Помимо ячеек оперативной памяти для хранения данных (правда, кратковременного) можно использовать и регистры - ячейки, входящие в состав процессора и доступные из машинной программы. Доступ к регистрам осуществляется значительно быстрее, чем к ячейкам памяти, поэтому использование регистров заметно уменьшает время выполнения программ.
Все регистры имеют размер слова (16 битов), за каждым из них закреплено определенное имя (AX, SP и т.п.). По назначению и способу использования регистры можно разбить на следующие группы:
- регистры общего назначения (AX, BX, CX, DX, BP, SI, DI, SP);
- сегментные регистры (CS, DS, SS, ES);
- счетчик команд (IP);
- регистр флагов (Flags).
(Расшифровка этих названий: A - accumulator, аккумулятор; B - base, база; C - counter, счетчик; D - data, данные; BP - base pointer, указатель базы; SI - source index, индекс источника; DI - destination index, индекс приемника; SP - stack pointer, указатель стека; CS -
code segment, сегмент команд; DS - data segment, сегмент данных; SS stack segment, сегмент стека; ES - extra segment, дополнительный сегмент; IP - instruction pointer, счетчик команд.)
Регистры общего назначения можно использовать во всех арифметических и логических командах. В то же время каждый их них имеет определенную специализацию (некоторые команды "работают" только с определенными регистрами). Например, команды умножения и деления требуют, чтобы один из операндов находился в регистре AX или в регистрах AX и DX (в зависимости от размера операнда), а команды управления циклом используют регистр CX в качестве счетчика цикла. Регистры BX и BP очень часто используются как базовые регистры, а SI и DI - как индексные. Регистр SP обычно указывает на вершину стека, аппаратно поддерживаемого в ПК.
Регистры AX, BX, CX и DX конструктивно устроены так, что возможен независимый доступ к их старшей и младшей половинам; можно сказать, что каждый из этих регистров состоит из двух байтовых регистров, обозначаемых AH, AL, BH и т.д. (H - high, старший; L - low, младший):
----------- ----------- ----------- -----------
AX | AH | AL | BX | BH | BL | CX | CH | CL | DX | DH | DL |
----------- ----------- ----------- -----------
15 8 7 0
Таким образом, с каждым из этих регистров можно работать как с единым целым, а можно работать и с его "половинками". Например, можно записать слово в AX, а затем считать только часть слова из регистра AH или заменить только часть в регистре AL и т.д. Такое устройство регистров позволяет использовать их для работы и с числами, и с символами.
Все остальные регистры не делятся на "половинки", поэтому считать или записать их содержимое (16 битов) можно только целиком.
Сегментные регистры CS, DS, SS и ES не могут быть операндами никаких команд, кроме команд пересылки и стековых команд. Эти регистры используются только для сегментирования адресов (см. 1.4).
Счетчик команд IP всегда содержит адрес (смещение от начала программы) той команды, которая должна быть выполнена следующей (начало программы хранится в регистре CS). Содержимое регистра IP можно изменить только командами перехода.
1.1.3 Флаги
И, наконец, в ПК имеется особый регистр флагов. Флаг - это бит, принимающий значение 1 ("флаг установлен"), если выполнено некоторое условие, и значение 0 ("флаг сброшен") в противном случае. В ПК ис-
пользуется 9 флагов, каждому из них присвоено определенное имя (ZF, CF и т.д.). Все они собраны в регистре флагов (каждый флаг - это один из разрядов регистра, часть его разрядов не используется):
-------------------------------------------------
Flags | x| x| x| x|OF|DF|IF|TF|SF|ZF| x|AF| x|PF| x|CF|
-------------------------------------------------
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Некоторые флаги принято называть флагами условий; они автоматически меняются при выполнении команд и фиксируют те или иные свойства их результата (например, равен ли он нулю). Другие флаги называются флагами состояний; они меняются из программы и оказывают влияние на дальнейшее поведение процессора (например, блокируют прерывания).
Флаги условий:
CF (carry flag) - флаг переноса. Принимает значение 1, если при сложении целых чисел появилась единица переноса, не "влезающая" в разрядную сетку, или если при вычитании чисел без знака первое из них было меньше второго. В командах сдвига в CF заносится бит, вышедший за разрядную сетку. CF фиксирует также особенности команды умножения.
OF (overflow flag) - флаг переполнения. Устанавливается в 1, если при сложении или вычитании целых чисел со знаком получился результат, по модулю превосходящий допустимую величину (произошло переполнение мантиссы и она "залезла" в знаковый разряд).
ZF (zero flag) - флаг нуля. Устанавливается в 1, если результат команды оказался равным 0.
SF (sign flag) - флаг знака. Устанавливается в 1, если в операции над знаковыми числами получился отрицательный результат.
PF (parity flag) - флаг четности. Равен 1, если результат очередной команды содержит четное количество двоичных единиц. Учитывается обычно только при операциях ввода-вывода.
AF (auxiliary carry flag) - флаг дополнительного переноса. Фиксирует особенности выполнения операций над двоично-десятичными числами.
Флаги состояний:
DF (direction flag) - флаг направления. Устанавливает направление просмотра строк в строковых командах: при DF=0 строки просматриваются "вперед" (от начала к концу), при DF=1 - в обратном направлении.
IF (interrupt flag) - флаг прерываний. При IF=0 процессор перестает реагировать на поступающие к нему прерывания, при IF=1 блокировка прерываний снимается.
TF (trap flag) - флаг трассировки. При TF=1 после выполнения каждой команды процессор делает прерывание (с номером 1), чем можно воспользоваться при отладке программы для ее трассировки.
1.2. ПРЕДСТАВЛЕНИЕ ДАННЫХ. АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ
Здесь рассматривается машинное представление целых чисел, строк и адресов. Представление двоично-десятичных чисел, используемых достаточно редко, не рассматривается. Что касается вещественных чисел, то в ПК нет команд вещественной арифметики (операции над этими числами реализуются программным путем или выполняются сопроцессором) и потому нет стандартного представления вещественных чисел. Кроме того, рассматриваются некоторые особенности выполнения арифметических операций.
Шестнадцатиричные числа записываются с буквой h на конце, двоичные
числа - с буквой b (так принято в MASM).
1.2.1 Представление целых чисел.
В общем случае под целое число можно отвести любое число байтов, однако система команд ПК поддерживает только числа размером в байт и слово и частично поддерживает числа размером в двойное слово. Именно эти форматы и будут рассмотрены.
В ПК делается различие между целыми числами без знака (неотрицательными) и со знаком. Это объясняется тем, что в ячейках одного и того же размера можно представить больший диапазон беззнаковых чисел, чем неотрицательных знаковых чисел, и если известно заранее, что некоторая числовая величина является неотрицательной, то выгоднее рассматривать ее как беззнаковую, чем как знаковую.
Целые числа без знака.
Эти числа могут быть представлены в виде байта, слова или двойного слова - в зависимости от их размера. В виде байта представляются целые от 0 до 255 (=2^8-1), в виде слова - целые от 0 до 65535 (=2^16-1), в виде двойного слова - целые от 0 до 4 294 967 295 (=2^32-1). Числа записываются в двоичной системе счисления, занимая все разряды ячейки. Например, число 130 записывается в виде байта 10000010b (82h).
Числа размером в слово хранятся в памяти в "перевернутом" виде: младщие (правые) 8 битов числа размещаются в первом байте слова, а старшие 8 битов - во втором байте (в 16-ричной системе: две правые цифры - в первом байте, две левые цифры - во втором байте). Например, число 130 (=0082h) в виде слова хранится в памяти так:
-----------
| 82 | 00 |
-----------
(Отметим, однако, что в регистрах числа хранятся в нормальном виде: -----------
AX | 00 | 82 |
-----------
AH AL )
"Перевернутое" представление используется и при хранении в памяти целых чисел размером в двойное слово: в первом его байте размещаются младшие 8 битов числа, во втором байте - предыдущие 8 битов и т.д. Например, число 12345678h хранится в памяти так: