Макросредства ассемблера
Макрокоманды схожи с подпрограммами в том отношении, что в обоих случаях мы описываем некоторый программный фрагмент один раз, а обращаемся к нему многократно, возможно, с передачей различных параметров. Однако эти вычислительные средства различаются как по способу использования, так и по своим возможностям.
Подпрограммы позволяют сократить объем выполнимого файла за счет описания повторяющихся участков программы лишь однажды. При каждом вызове подпрограммы командой call происходит переход на один и тот же фрагмент программы, содержащий подпрограмму, а после выполнения подпрограммы – возврат назад в точку вызова. Текст подпрограммы полностью определяется на этапе ее написания, и изменения в ходе выполнения подпрограммы возможны только за счет передачи ей тех или иных конкретных значений.
Механизм использования макроса иной. Каждая макрокоманда, встретившаяся транслятору в тексте программы, заменяется им на полный текст макроопределения. Если макрокоманда содержит параметры, то в процессе этой замены происходит подстановка параметров в текст макроопределения. Образованное таким образом макрорасширение составляет часть текста программы, неотличимо от остальных предложений программы и не нуждается в каких-либо вызовах. В силу этих обстоятельств макрокоманды оказываются несколько эффективнее подпрограмм по скорости выполнения, особенно, если учесть время, требуемое для подготовки параметров перед вызовом подпрограммы (например, проталкивание их в стек). Вряд ли стоит, однако, проводить такое сравнение. Подпрограммы и макрокоманды имеют различные области применения.
Подпрограммы служат для сокращения объема программы, повышения ее наглядности и упрощения перестройки алгоритма выполнения всего программного комплекса путем изменения состава и порядка вызываемых подпрограмм. При этом активное использование подпрограмм может уменьшить размер всей программы в десятки раз.
Смысл использования макрокоманд совсем иной. Макрокоманды позволяют упростить процесс написания программы и, можно сказать, являются средством автоматизации программирования. При этом язык макрокоманд предоставляет большие возможности по изменению текста макрорасширения в зависимости от указываемых в макрокоманде параметров. Проиллюстрируем эти возможности на простом примере макрокоманды вывода на экран символа. Такой макрокомандой можно пользоваться в процессе отладки сложных программ, чтобы получать информацию о содержимом любых ячеек памяти. Пример оформлен в виде законченной программы, которая носит чисто демонстрационный характер.
Пример 2.1. Использование макрокоманды.
sym macroc; Имя и формальный аргумент push AX; Сохраним используемые push DX; в макроопределении регистры mov АН, 02h; Функция DOS вывода символа mov DL,c; Заберем символ int 21h; Вызов DOS pop DX; Восстановим pop AX; регистры endm; Конец макроопределения code segment assume cs:code main proc sym 'w'; Символ указан непосредственно sym ES: 0; Вывод первого байта PSP sym CS:msg; Вывод первой буквы из msg lea BX,msg-t-l; Адрес второй буквы из msg sym [BX]; Вывод второй буквы mov AX, 40h; Настроим DS mov DS,AX; на начало памяти sym DS:49h; Вывод номера видеорежима mov AX,4C00h; Завершение программы int 21h main endp msg db 'OK' code ends
Тексты макроопределений обычно размещаются в самом начале программы, что дает возможность вызывать макрокоманды из любых точек программы. Содержательная часть макроса sym состоит в вызове функции 02h DOS, которая выводит на экран символ из регистра DL. Поскольку макрос использует регистры АХ и DX, они в начале макроса сохраняются в стеке, а перед его завершением восстанавливаются. В качестве параметра макрокоманды можно использовать любое обозначение ассемблера, которое может интерпретироваться, как адрес символа.
Сама программа умышленно построена несколько нестандартным образом. В ней имеется единственный сегмент с текстом программы, в конце которого помещена строка данных (слово 'ОК'). Такое расположение данных допустимо, однако для обращения к ним необходимо использовать замену сегмента (как это сделано в третьей строке программы), так как программный сегмент адресуется через регистр CS. Сегмент стека в программе отсутствует, что не очень хорошо, но для небольших программ допустимо. Фактически под стек будет использован самый низ сегмента команд, начиная с адреса FFFEh. Поскольку наша программа имеет размер, существенно меньше 64К, такое расположение стека не приведет ни к каким неприятностям (при большом размере программы стек мог бы начать затирать нижние строки программы).