Конспект лекций Системное программирование (семестр 2) Возле названия каждой лекции написано число пар, в течение которых она будет читаться (+ ср обозначает

Вид материалаКонспект
Лекция 11. Макросредства языка ассемблера (2 пары)
Псевдооператоры equ и =
Подобный материал:
1   ...   45   46   47   48   49   50   51   52   ...   57

Лекция 11. Макросредства языка ассемблера (2 пары)

  • Понятие о макросредствах языка ассемблера
  • Псевдооператоры equ и =
  • Макрокоманды
  • Макродирективы
  • Директивы условной компиляции

Любопытный читатель к этому занятию, вероятно, попытался самостоятельно написать хотя бы несколько программ на ассемблере.

Скорее всего, эти программы были предназначены для решения небольших, чисто исследовательских задач, но даже на примере этих маленьких по объему программ вам, наверное, стали очевидны некоторые из перечисленных здесь проблем:
  • плохое понимание исходного текста программы, особенно по прошествии некоторого времени после ее написания;
  • ограниченность набора команд;
  • повторяемость некоторых идентичных или незначительно отличающихся участков программы;
  • необходимость включения в каждую программу участков кода, которые уже были использованы в других программах;
  • и многое другое

Если бы мы писали программу на машинном языке, то данные проблемы были бы принципиально не решаемыми. Но язык ассемблера, являясь символическим аналогом машинного языка, предоставляет для их решения ряд средств.

Основной целью, которая при этом преследуется, является повышение удобства написания программ.

В общем случае эта цель достигается по нескольким направлениям за счет следующего:
  • расширения набора директив;
  • введения некоторых дополнительных команд, не имеющих аналогов в системе команд микропроцессора. За примером далеко ходить не нужно — команды setfield и getfield, которые скрывают от программиста рутинные действия и генерируют наиболее эффективный код;
  • введения сложных типов данных.

Но это все глобальные направления, по которым развивается сам транслятор от версии к версии.

Что же делать программисту для решения его локальной задачи, для облегчения работы в определенной проблемной области?

Для этого разработчики компиляторов ассемблера включают в язык и постоянно совершенствуют аппарат макросредств. Этот аппарат является очень мощным и важным.

В общем случае есть смысл говорить о том, что транслятор ассемблера состоит из двух частей — непосредственно транслятора, формирующего объектный модуль, и макроассемблера (рис. 1).



Рис. 1. Макроассемблер в общей схеме трансляции программы на TASM

Если вы знакомы с языком С или С++, то конечно помните широко применяемый в них механизм препроцессорной обработки. Он является некоторым аналогом механизма заложенного в работу макроассемблера. Для тех, кто ничего раньше не слышал об этих механизмах, поясню их суть.

Основная идея — использование подстановок, которые замещают определенным образом организованную символьную последовательность другой символьной последовательностью. Создаваемая таким образом последовательность может быть как последовательностью, описывающей данные, так и последовательностью программных кодов. Главное здесь то, что на входе макроассемблера может быть текст программы весьма далекий по виду от программы на языке ассемблера, а на выходе обязательно будет текст на чистом ассемблере, содержащем символические аналоги команд системы машинных команд микропроцессора.

Таким образом, обработка программы на ассемблере с использованием макросредств неявно осуществляется транслятором в две фазы(рис. 1).

На первой фазе работает часть компилятора, называемая макроассемблером, функции которого на идейном уровне мы описали чуть выше.

На второй фазе трансляции работает непосредственно ассемблер, задачей которого является формирование объектного кода, содержащего текст исходной программы в машинном виде.

Далее мы обсудим основной набор макросредств, доступных при использовании компилятора TASM. Отметим, что большинство этих средств доступно и в компиляторе с языка ассемблера фирмы Microsoft.

Обсуждение начнем с простейших средств и закончим более сложными.

Псевдооператоры equ и =


К простейшим макросредствам языка ассемблера можно отнести псевдооператоры equ и "=" (равно).

Их мы уже неоднократно использовали при написании программ.

Эти псевдооператоры предназначены для присвоения некоторому выражению символического имени или идентификатора. Впоследствии, когда в ходе трансляции этот идентификатор встретится в теле программы, макроассемблер подставит вместо него соответствующее выражение.

В качестве выражения могут быть использованы константы, имена меток, символические имена и строки в апострофах. После присвоения этим конструкциям символического имени его можно использовать везде, где требуется размещение данной конструкции.

Синтаксис псевдооператора equ:

имя_идентификатора equ строка или числовое_выражение

Синтаксис псевдооператора “=”:

имя_идентификатора = числовое_выражение

Несмотря на внешнее и функциональное сходство псевдооператоры equ и “=” отличаются следующим:
  • из синтаксического описания видно, что с помощью equ идентификатору можно ставить в соответствие как числовые выражения, так и текстовые строки, а псевдооператор “=” может использоваться только с числовыми выражениями;
  • идентификаторы, определенные с помощью “=”, можно переопределять в исходном тексте программы, а определенные с использованием equ — нельзя.

Ассемблер всегда пытается вычислить значение строки, воспринимая ее как выражение. Для того чтобы строка воспринималась именно как текстовая, необходимо заключить ее в угловые скобки: <строка>.

Кстати сказать, угловые скобки являются оператором ассемблера, с помощью которого транслятору сообщается, что заключенная в них строка должна трактоваться как текст, даже если в нее входят служебные слова ассемблера или операторы. Хотя в режиме Ideal это не обязательно, так как строка для equ в нем всегда трактуется как текстовая.

Псевдооператор equ удобно использовать для настройки программы на конкретные условия выполнения, замены сложных в обозначении объектов, многократно используемых в программе, более простыми именами и т. п.

К примеру:

masm

model small

stack 256

mas_size equ 10 ;размерность массива

akk equ ax ;переименовать регистр

mas_elem equ mas[bx][si] ;адресовать элемент массива

.data

;описание массива из 10 байт:

mas db mas_size dup (0)

.code

mov akk,@data ;фактически mov ax,@data

mov ds,akk ;фактически mov ds,ax

...

mov al,mas_elem ;фактически — mov al,mas[bx][si]

Псевдооператор “=” удобно использовать для определения простых абсолютных (то есть не зависящих от места загрузки программы в память) математических выражений.

Главное условие то, чтобы транслятор мог вычислить эти выражения во время трансляции.

К примеру:

.data

adr1 db 5 dup (0)

adr2 dw 0

len = 43

len = len+1 ;можно и так, через предыдущее определение

len = adr2-adr1

Как видно из примера, в правой части псевдооператора “=” можно использовать метки и ссылки на адреса — главное, чтобы в итоге получилось абсолютное выражение.

Компилятор TASM, начиная с версии 3.00, содержит директивы, значительно расширяющие его возможности по работе с текстовыми макросами. Эти директивы аналогичны некоторым функциям обработки строк в языках высокого уровня. Под строками здесь понимается текст, описанный с помощью псевдооператора equ.

Набор этих директив следующий:
  • директива слияния строк catstr:
  • идентификатор catstr строка_1,строка_2,... — значением этого макроса будет новая строка, состоящая из сцепленной слева направо последовательности строк строка_1,строка_2,...
  • В качестве сцепляемых строк могут быть указаны имена ранее определенных макросов.
  • К примеру:

    pre equ Привет,

    name equ < Юля>

    privet catstr pre,name ;privet= “Привет, Юля”


  • директива выделения подстроки в строке substr:
  • идентификатор substr строка,номер_позиции,размер — значением данного макроса будет часть заданной строки, начинающаяся с позиции с номером номер_позиции и длиной, указанной в размер.
  • Если требуется только остаток строки, начиная с некоторой позиции, то достаточно указать только номер_позиции без указания размера.
  • К примеру:

    ;продолжение предыдущего фрагмента:

    privet catstr pre,name ;privet= “Привет, Юля”

    name substr privet,7,3 ;name=“Юля”


  • директива определения вхождения одной строки в другую instr:
  • идентификатор instr номер_нач_позиции,строка_1,строка_2 — после обработки данного макроса транслятором идентификатору будет присвоено числовое значение, соответствующее номеру (первой) позиции, с которой совпадают строка_1 и строка_2.
  • Если такого совпадения нет, то идентификатор получит значение 0;
  • директива определения длины строки в текстовом макросе sizestr:
  • идентификатор sizestr строка — в результате обработки данного макроса значение идентификатор устанавливается равным длине строки.

;как продолжение предыдущего фрагмента:

privet catstr pre,name ;privet= “Привет, Юля”

len sizestr privet ;len=10



Эти директивы очень удобно использовать при разработке макрокоманд, которые являются следующим макросредством, предоставляемым компилятором ассемблера.