Макросредства ассемблера
Директивы условной трансляции
Директивы условной трансляции (условного ассемблирования) позволяют иметь в исходном тексте программы различные варианты отдельных фрагментов программы, и путем задания определенных условий управлять процессом трансляции. Таким образом можно, например, включать или исключать из текста программы служебные, отладочные фрагменты или настраивать программу для выполнения на заданном процессоре.
Пусть, например, в процессе отладки сложной программы мы используем подпрограмму regs вывода на экран содержимого всех регистров процессора. Включая в разные места программы вызов этой подпрограммы, мы имеем возможность контролировать ход ее выполнения, в том числе и такие тонкие моменты, как, например, расположение программы в памяти или интенсивность использование стека. Для управления процессом трансляции предусмотрим константу debug (отладка), ненулевое значение которой будет требовать отладочного варианта трансляции, а нулевое – рабочего. Начало программы, а также участки с вызовом отладочной подпрограммы будут выглядеть следующим образом:
;debug=1; Удалите символ ';' для отладочной трансляции ;debug=0; Удалите ';' для рабочей трансляции …; Текст программы if debug; Транслировать только если debug=1 call regs; Вызов отладочной подпрограммы endif; Конец блока условной трансляции …; Продолжение программы if debug; Следующее включение отладочного блока call regs endif …; Продолжение программы
Разумеется, можно отлаживать программу в отладочном варианте, а затем удалить все вызовы вспомогательной подпрограммы regs вручную и получить рабочий вариант, однако на практике обычно (или даже всегда) оказывается, что после эксплуатации программы в течение некоторого времени в ней обнаруживаются незамеченные ранее ошибки, что приводит к необходимости снова вставлять в нее отладочные строки. Часто эту процедуру приходится повторять многократно. Использование в программе директив условной трансляции сокращают процедуру преобразования программы из отладочного варианта в рабочий или наоборот до операции стирания одного символа ";" в начале программы и устраняют вероятность случайного внесения в программу новых ошибок в процессе удаления или вставки отладочных строк.
Рассмотрим еще один пример применения директив условной трансляции. Как уже отмечалось, современные процессоры предоставляют программисту значительное количество дополнительных команд, которые можно использовать в программах реального режима, но только, разумеется, если компьютер оснащен соответствующим процессором. Нетрудно составить универсальную программу', которую можно выполнять как на современных процессорах (в более эффективном режиме), так и на более старых (с некоторой потерей эффективности), если включить в нее директивы условной трансляции этих дополнительных команд. К таким командам, в частности, относятся команды сохранения в стеке всех регистров общего назначения pusha и восстановления всех регистров рора. Приведем пример условной трансляции этих команд, в котором используется конструкция макроязыка if… else… endif:
i386=l if i386 .386 endif code segment use16 assume CS:code main proc … if i386 push; Сохранение всех регистров одной командой else push AX push CX push DX push BX push BP push SI push DI endif …; Использование регистров после сохранения их значений if 1386 рора; Восстановление всех регистров одной командой else pop DI pop SI pop BP pop BX pop DX pop CX pop AX endif
Если в начале программы имеется объявление i386=1, то, во-первых, в программу будет включена директива.386, позволяющая использовать в программе дополнительные команды, а во-вторых, в последующих условных блоках будут транслироваться те их участки, которые содержат команды процессора 80386. Если же объявление i386=1 изъять, то в условных блоках будут транслироваться эквивалентные по существу, но менее эффективные последовательности команд МП 86.