Один операнд INC CX ;Увеличить CX
Два операнда ADD AX,12 ;Прибавить 12 к AX
Метка, команда и операнд не обязательно должны начинаться с
какой-либо определенной позиции в строке. Однако, рекомендуется записывать
их в колонку для большей yдобочитаемости программы. Для этого, например,
редактор DOS EDLIN обеспечивает табуляцию через каждые восемь позиций.
ДИРЕКТИВЫ
________________________________________________________________
Ассемблер имеет ряд операторов, которые позволяют упpавлять процессом
ассемблирования и формирования листинга. Эти операторы называются
псевдокомандами или директивами. Они действуют только в процессе
ассемблирования программы и не генерируют машинных кодов. Большинство
директив показаны в следующих разделах. В гл.24 подробно описаны все
директивы ассемблера и приведено более чем достаточно соответствующей
информации. Гл.24 можно использовать в качестве справочника.
Директивы управления листингом: PAGE и TITLE
----------------------------------------------
Ассемблер содержит ряд директив, управляющих форматом печати (или
листинга). Обе директивы PAGE и TITLE можно использовать в любой
программе.
Д и р е к т и в а PAGE. В начале программы можно указать количество
строк, распечатываемых на одной странице, и максимальное количество
символов на одной строке. Для этой цели cлужит директива PAGE. Следующей
директивой устанавливается 60 строк на страницу и 132 символа в строке:
PAGE 60,132
Количество строк на странице может быть в пределах от 10 до 255, а
символов в строке - от 60 до 132. По умолчанию в ассемблере установлено
PAGE 66,80.
Предположим, что счетчик строк установлен на 60. В этом случае
ассемблер, распечатав 60 строк, выполняет прогон листа на начало следующей
страницы и увеличивает номер страницы на eдиницу. Кроме того можно
заставить ассемблер сделать прогон листа на конкретной строке, например, в
конце сегмента. Для этого необходимо записать директиву PAGE без
операндов. Ассемблер автоматически делает прогон листа при обработке
диpективы PAGE.
Д и р е к т и в а TITLE. Для того, чтобы вверху каждой страницы
листинга печатался заголовок (титул) программы, используется диpектива
TITLE в следующем формате:
TITLE текст
Рекомендуется в качестве текста использовать имя программы, под
которым она находится в каталоге на диске. Например, если программа
называется ASMSORT, то можно использовать это имя и описательный
комментарий общей длиной до 60 символов:
TITLE ASMSORT - Ассемблерная программа сортировки имен
В ассемблере также имеется директива подзаголовка SUBTTL, которая
может оказаться полезной для очень больших программ, содержащих много
подпрограмм.
Директива SEGMENT
-------------------
Любые ассемблерные программы содержат по крайней мере один сегмент -
сегмент кода. В некоторых программах используется сегмент для стековой
памяти и сегмент данных для определения данных. Асcемблерная директива для
описания сегмента SEGMENT имеет следующий формат:
Имя Директива Операнд
имя SEGMENT [параметры]
.
.
.
имя ENDS
Имя сегмента должно обязательно присутствовать, быть уникальным и
соответствовать соглашениям для имен в ассемблере. Директива ENDS
обозначает конец сегмента. Обе директивы SEGMENT и ENDS должны иметь
одинаковые имена. Директива SEGMENT может содержать три типа параметров,
определяющих выравнивание, объединение и класс.
1. В ы р а в н и в а н и е. Данный параметр определяет границу
начала сегмента. Обычным значением является PARA, по которому сегмент
устанавливается на границу параграфа. В этом случае начальный адрес
делится на 16 без остатка, т.е. имеет шест. адрес nnn0. В случае
отсутствия этого операнда ассемблер принимает по умолчанию PARA.
2. О б ъ е д и н е н и е. Этот элемент определяет объединяется
ли данный сегмент с другими сегментами в процессе компановки после
ассемблирования (пояснения см. в следующем разделе "Компановка
программы"). Возможны следующие типы объединений: STACK, COMMON,
PUBLIC, AT выражение и MEMORY. Сегмент стека определяется следующим
образом:
имя SEGMENT PARA STACK
Когда отдельно ассемблированные программы должны объединяться
компановщиком, то можно использовать типы: PUBLIC, COMMON и MEMORY. В
случае, если программа не должна объединяться с другими программами,
то данная опция может быть опущена.
3. К л а с с. Данный элемент, заключенный в апострофы,
используется для группирования относительных сегментов при
компановке:
имя SEGMENT PARA STACK 'Stack'
Фрагмент программы на рис.3.1. в следующем разделе иллюстрирует
директиву SEGMENT и ее различные опции.
Директива PROC
----------------
Сегмент кода содержит выполняемые команды программы. Кроме того этот
сегмент также включает в себя одну или несколько процедур, определенных
директивой PROC. Сегмент, содержащий только одну процедуру имеет следующий
вид:
имя-сегмента SEGMENT PARA
имя-процедуры PROC FAR Сегмент
. кода
. с
. одной
RET процедурой
имя-процедуры ENDP
имя-сегмента ENDS
Имя процедуры должно обязательно присутствовать, быть уникальным и
удовлетворять соглашениям по именам в ассемблере. Операнд FAR указывает
загрузчику DOS, что начало данной процедуры является точкой входа для
выполнения программы.
Директива ENDP определяет конец процедуры и имеет имя, аналогичное
имени в директиве PROC. Команда RET завершает выполнение программы и в
данном случае возвращает управление в DOS.
Сегмент может содержать несколько процедур (см. гл.7).
Директива ASSUME
------------------
Процессор использует регистр SS для адресации стека, регистр DS для
адресации сегмента данных и регистр CS для адресации cегмента кода.
Ассемблеру необходимо сообщить назначение каждого сегмента. Для этой цели
служит директива ASSUME, кодируемая в сегменте кода следующим образом:
Директива Операнд
ASSUME SS:имя_стека,DS:имя_с_данных,CS:имя_с_кода
Например, SS:имя_стека указывает, что ассемблер должен ассоциировать
имя сегмента стека с регистром SS. Операнды могут записываться в любой
последовательности. Регистр ES также может присутствовать в числе
операндов. Если программа не использует регистр ES, то его можно опустить
или указать ES:NOTHING.
Директива END
---------------
Как уже показано, директива ENDS завершает сегмент, а директива ENDP
завершает процедуру. Директива END в свою очередь полностью завершает всю
программу:
Директива Операнд
END [имя_процедуры]
Операнд может быть опущен, если программа не предназначена для
выполнения, например, если ассемблируются только определения данных, или
эта программа должна быть скомпанована с другим (главным) модулем. Для
обычной программы с одним модулем oперанд содержит имя, указанное в
директиве PROC, которое было oбозначено как FAR.
ПАМЯТЬ И РЕГИСТРЫ
________________________________________________________________
Рассмотрим особенности использования в командах имен, имен в
квадратных скобках и чисел. В следующих примерах положим, что WORDA
определяет слово в памяти:
MOV AX,BX ;Переслать содержимое BX в регистр AX
MOV AX,WORDA ;Переслать содержимое WORDA в регистр AX
MOV AX,[BX] ;Переслать содержимое памяти по адресу
; в регистре BX в регистр AX
MOV AX,25 ;Переслать значение 25 в регистр AX
MOV AX,[25] ;Переслать содержимое по смещению 25
Новым здесь является использование квадратных скобок, что потребуется
в следующих главах.
ИНИЦИАЛИЗАЦИЯ ПРОГРАММЫ
________________________________________________________________
Существует два основных типа загрузочных программ: EXE и COM.
Рассмотрим требования к EXE-программам, а COM-программы будут представлены
в гл.6. DOS имеет четыре требования для инициализации ассемблерной
EXE-программы: 1) указать ассемблеру, какие cегментные регистры должны
соответствовать сегментам, 2) сохранить в стеке адрес, находящийся в
регистре DS, когда программа начнет выполнение, 3) записать в стек нулевой
адрес и 4) загрузить в регистр DS адрес сегмента данных.
Выход из программы и возврат в DOS сводится к использованию команды
RET. Рис.3.1 иллюстрирует требования к инициализации и выходу из
программы:
1. ASSUME - это ассемблерная директива, которая устанавливает
для ассемблера соответствие между конкретными сегментами и
сегментными регистрами; в данном случае, CODESG - CS, DATASG - DS и
STACKSG - SS. DATASG и STACKSG не определены в этом примере, но они
будут представлены следующим образом:
STACKSG SEGMENT PARA STACK Stack 'Stack'
DATASG SEGMENT PARA 'Data'
Ассоциируя сегменты с сегментными регистрами, ассемблер сможет
определить смещения к отдельным областям в каждом сегменте. Например,
каждая команда в сегменте кодов имеет определенную длину: первая
команда имеет смещение 0, и если это двухбайтовая команда, то вторая
команда будет иметь смещение 2 и т.д.
2. Загрузочному модулю в памяти непосредственно предшествует
256-байтовая (шест.100) область, называемая префиксом программного
сегмента PSP. Программа загрузчика использует регистр DS для
установки адреса начальной точки PSP. Пользовательская программа
должна сохранить этот адрес, поместив его в стек. Позже, команда RET
использует этот адрес для возврата в DOS.
3. В системе требуется, чтобы следующее значение в стеке
являлось нулевым адресом (точнее, смещением). Для этого команда SUB
очищает регистр AX, вычитая его из этого же регистра AX, а команда
PUSH заносит это значение в стек.
4. Загрузчик DOS устанавливает правильные адреса стека в
регистре SS и сегмента кодов в регистре CS. Поскольку программа
загрузчика использует регистр DS для других целей, необходимо
инициализировать регистр DS двумя командами MOV, как показано на
рис.3.1. В следующем разделе этой главы "Исходная программа. Пример
II" детально поясняется инициализация регистра DS.
5. Команда RET обеспечивает выход из пользовательской программы
и возврат в DOS, используя для этого адрес, записанный в стек в
начале программы командой PUSH DS. Другим обычно используемым выходом
является команда INT 20H.