Э. Таненбаум - Архитектура компьютера (1127755), страница 144
Текст из файла (страница 144)
Уровень ассемблера Директивы РЙОС и ЕМОР определяют начало и конец ассемблерных процедур. Процедуры в ассемблере выполняют ту же роль, что и в языках программирования высокого уровня. Директивы МАСЙО и ЕМОМ определяют начало и конец макроса. О макросах мы поговорим в следующем разделе. Директивы РОВС!С и ЕХТЕЙМ определяют видимость (доступность) символов. Программы часто пишут в виде совокупности файлов. Иногда процедуре, находящейся в одном файле, нужно вызвать процедуру или получить доступ к данным, определенным в другом файле. Чтобы такие перекрестные ссылки между файлами стали возможными, символ (имя), который нужно сделать доступным для других файлов, экспортируется с помощью директивы РОВС!С. Чтобы ассемблер не выдавал предупреждений по поводу использования символа, который не определен в данном файле, этот символ может быть обьявлен внешним (ЕХТЕЙМ), то есть определенным в другом файле.
Символы, которые не определены ни в одной из этих директив, могут использоваться только в пределах одного файла. Поэтому даже если, например, символ ЕОО встречается в нескольких файлах, это не вызовет никакого конфликта, поскольку указанный символ локален по отношению к каждому файлу. Директива 1МСЕООЕ заставляет ассемблер вызвать другой файл и включить его в текущий. Такие включенные файлы часто содержат определения, макросы и другие элементы, необходимые для разных файлов. Многие языки ассемблера, в том числе МАЯМ, поддерживают условное ассемблирование программы. Например: ИОЙ0517Е ЕОО 16 !Е ИОР0517Е ОТ 16 И517Е: ОИ37 Е15Е И5!76' ОИ 16 ЕИ011 Эта программа выделяет в памяти одно 32-разрядное слово и вызывает его адрес И517Е.
Этому слову придается одно из значений: либо 32, либо 16 в зависимости от значения ИОЙ0517Е (в данном случае — 16). Такая конструкция может использоваться в программах для 16-разрядных (как 8088) или 32-разрядных машин (как Репйшп 4). Если в начале и в конце машинно-зависимого кола вставить директивы 1Е и ЕМ01Е, а затем изменить единственное определение, ИОЙ0517Е, программу можно автоматически настроить на один из двух размеров. Применяя такой подход, можно задействовать одну такую исходную программу для нескольких разных машин.
В большинстве случаев все машинно-зависимые определения, такие как ИОЙ0517Е, сохраняются в одном файле, причем для разных машин должны быть разные файлы. Путем включения файла с нужными определениями программу можно легко перекомпилировать для разных машин. Директива СОММЕМТ позволяет пользователю заменить символ начала комментария (точку с запятой) чем-либо другим.
Директива РАВЕ используется для управления листингом программы. Наконец, директивой ЕМО помечается конец программы. В ассемблере МАЯМ есть еще много директив. Другие ассемблеры Репйшп 4 содержат другой набор директив, поскольку эти директивы определяются не архитектурой машины, а вкусами разработчиков ассемблера. Макросы 567 Макросы Обычно программистам, пишущим на языке ассемблера, приходится многократно повторять одни и те же цепочки команд. Хотя проще всего писать нужные команды всякий раз, когда они требуются, это занятие становится утомительным, особенно если последовательность достаточно длинная или если ее нужно повторять слишком часто.
Альтернативный подход — оформить эту последовательность в процедуру и вызывать ее в случае необходимости. У такой стратегии тоже есть свои недостатки, поскольку в этом случае каждый раз придется выполнять специальную команду вызова процедуры и команду возврата. Если гюследовательности команд короткие (например, всего две команды), но используются часто, то вызовы процедур могут значительно сказаться на быстродействии программы. Простым и эффективным решением этой проблемы являются макросы. Макроопределение, макровызов и макрорасширение Макроопределение — это способ дать имя фрагменту кода, После того как макрос определен, программист может вместо фрагмента кода писать имя макроса.
В сущности, макрос — это просто имя фрагмента кода. В листинге 7А приведена ассемблерная программа для Репкош 4, которая дважды меняет местами значения переменных Р и О. Вот как выглядит основная цепочка операторов: РОЧ ЕАХ.Р МОЧ ЕВХ О МОЧ О,ЕАХ МОН Р,ЕВХ В листинге 7.5 эта последовательность определяется как макрос 5ИАР.
Листинг 7.4. Смена значений переменных Р и О без использования макроса МОН ЕАХ.Р МОН ЕВХ.О МОН О,ЕАХ МОН Р.ЕВХ МОЧ ЕАХ,Р МОЧ ЕВХ,О МОЧ О,ЕАХ МОЧ Р,ЕВХ Листинг 7.5. Смена значений переменных Р и 0 с использованием макроса 5ЫАР МАЕВО МОЧ ЕАХ,Р МОЧ ЕВХ.О МОЧ О.ЕЯХ МОЧ Р.ЕВХ ЕМОМ 5ИЯР 5ИЯР 568 Глава 7. Уровень ассемблера Таблице 7.3. Сравнение макровызовов и вызовов процедур Макровызов Вызов процедуры Когда совершается вызов? Во время ассемблирования Во время выполнения программы Вставляется ли тело макроса или процедуры в объектную программу каждый раз, когда совершается вызов? Нет Вставляется ли в обьектную программу, команда вызова процедуры, которая затем выполняется? Нет Нужно ли после вызова использовать команду возврата? Нет Сколько копий тела макровызова или процедуры появляется в объектной программе? Одна на каждый макровызов Одна Можно считать, что процесс ассемблирования проходит в два прохода.
На первом проходе сохраняются все макроопределения, а макровызовы расширяются. На втором проходе обрабатывается полученный в результате текст. Иными словами, исходная программа считывается, а затем трансформируется в другую программу, из которой удалены все макроопределения и в которой каждый макровызов заменен телом макроса. Полученная программа без макросов затем поступает в ассемблер. Хотя в разных языках ассемблера определение макроса выглядит немного по-разному, во всех оно состоит из одних и тех же базовых частей: + заголовок макроса, в котором дается имя определяемого макроса; + текст, в котором приводится тело макроса; + директива, которая завершает определение (например, ГМЮМ).
Когда ассемблер наталкивается на макроопределение в программе, он сохраняет его в таблице макроопределений для последующего использования. Всякий раз, когда в программе в качестве кода операции будет появляться макрос (в нашем примере — ЯДР), ассемблер заменит его телом макроса. Использование имени макроса в качестве кода операции называется макровызовом, а его замена телом макроса — макрорасширением.
Макрорасширение происходит в ходе ассемблирования, а не во время выполнения программы. Этот момент очень важен. Программы, приведенные в листингах 7.4 и 7.5, порождают один и тот же машинный код. По программе на машинном языке невозможно определить, использовались макросы при ее порождении или нет. В полученной программе никаких признаков макросов не остается. Макровызовы не следует путать с вызовами процедур. Основное отличие состоит в том, что макровызов — это команда ассемблеру заменить имя макроса телом макроса.
Вызов процедуры — это машинная команда, которая, будучи вставлена в объектную программу, позднее должна быть выполнена для вызова процедуры. В табл. 7.3 сравниваются макровызовы и вызовы процедур. Макросы 569 Важно иметь в виду, что программа представляет собой строку символов, каковыми могут быть буквы, цифры, пробелы, знаки пунктуации и символы возврата каретки (перехода на новую строку). При макрорасширении определенные подстроки из этой строки заменяются другими символьными строками.
Макросы — средство манипулирования символьными строками без изменения их значения. Макросы с параметрами Описанные в предыдущем подразделе макросы можно использовать для сокращения объема программ, в которых часто повторяется одна и та же последовательность команд. Однако иногда программа содержит несколько похожих, но не идентичных последовательностей команд. Например, в листинге 7.6 первая последовательность меняет местами значения переменных Р и О, а вторая — переменных Н и 5.
Листинг 7.6. Смена значений двух пар переменных без использования макроса ИОН ЕАХ.Р МОН ЕВХ.О Иои О,ЕЯХ ИОН Р,ЕВХ МОН ЕЯХ В ИОН ЕВХ,5 МОН 5.ЕАХ МОН В.ЕВХ Для работы с такими почти идентичными последовательностями предусмотрены макроопределения, предлагающие формальные параметры, и макровызовы, в которых формальные параметры заменяются фактическими параметрами.
Фактические параметры помещаются в поле операндов макровызова. В листинге 7.7. представлена программа из листинга 7.6, в которую включен макрос с двумя параметрами. Символы Р1 и Р2 — это формальные параметры. Во время расширения макроса каждый символ Р1 внутри тела макроса заменяется первым фактическим параметром, а символ Р2 — вторым фактическим параметром. Пример: СНЯМВЕ Р.О В этом макровызове Р— это первый фактический параметр, а Π— второй фактический параметр. Таким образом, программы в листингах 7.6 и 7.7 идентичны. Листинг 7.7.
Смена значений двух пар переменных с использованием макроса СНАНОЕ ИЯСВО Р1,Р2 МОН ЕАХ.Р1 ИОН ЕВХ,Р2 ИОН Р2.ЕАХ ИОН Р1,ЕВХ ЕНОМ СНАИОЕ Р,О СНАНОЕ В,5 570 Глава 7. Уровень ассемблера Дополнительные возможности Большинство макропроцессоров поддерживают целый ряд дополнительных функций, которые упрощают работу программиста, пишущего на языке ассемблера. В этом подразделе мы рассмотрим несколько дополнительных функций ассемблера МАЯМ. Для всех ассемблеров характерна проблема: дублирование меток. Предположим, что макрос содержит команду условного перехода и метку, к которой совершается переход.