Навигация
Главная
Поиск
Форум
FAQ's
Ссылки
Карта сайта
Чат программистов

Статьи
-Delphi
-C/C++
-Turbo Pascal
-Assembler
-Java/JS
-PHP
-Perl
-DHTML
-Prolog
-GPSS
-Сайтостроительство
-CMS: PHP Fusion
-Инвестирование

Файлы
-Для программистов
-Компонеты для Delphi
-Исходники на Delphi
-Исходники на C/C++
-Книги по Delphi
-Книги по С/С++
-Книги по JAVA/JS
-Книги по Basic/VB/.NET
-Книги по PHP/MySQL
-Книги по Assembler
-PHP Fusion MOD'ы
-by Kest
Professional Download System
Реклама
Услуги

Автоматическое добавление статей на сайты на Wordpress, Joomla, DLE
Заказать продвижение сайта
Программа для рисования блок-схем
Инженерный калькулятор онлайн
Таблица сложения онлайн
Популярные статьи
OpenGL и Delphi... 65535
Форум на вашем ... 65535
HACK F.A.Q 65535
Бип из системно... 65535
Гостевая книга ... 65535
Invision Power ... 65535
Содержание сайт... 65535
Организация зап... 65535
Вызов хранимых ... 65535
Программируемая... 65535
Эмулятор микроп... 65535
Подключение Mic... 65535
Создание потоко... 65535
Приложение «Про... 65535
Оператор выбора... 65535
Создание отчето... 63889
Модуль Forms 63622
ТЕХНОЛОГИИ ДОСТ... 60470
Пример работы с... 59827
Имитационное мо... 55932
Реклама
Сейчас на сайте
Гостей: 6
На сайте нет зарегистрированных пользователей

Пользователей: 13,079
новичок: Openair
Новости
Реклама
Выполняем курсовые и лабораторные по разным языкам программирования
Подробнее - курсовые и лабораторные на заказ
Delphi, Turbo Pascal, Assembler, C, C++, C#, Visual Basic, Java, GPSS, Prolog, 3D MAX, Компас 3D
Заказать программу для Windows Mobile, Symbian

Файл записей с выводом обратного заголовка на Turbo Pascal
Метод конечных разностей для интерполяции/экстраполяции на Delphi
Калькулятор на Delphi с переводом в другую систему исчисления + Блок схемы

Реклама



Подписывайся на YouTube канал о программировании, что бы не пропустить новые видео!

ПОДПИСЫВАЙСЯ на канал о программировании
СТРУКТУРНОЕ ПРОГРАММИРОВАНИЕ 1: ИНСТРУМЕНТАЛЬНЫЕ
Потребность в короткой записи операторов
Введение в МАКРОСЫ
Условное ассемблирование
Условное ассемблирование и МАКРОСЫ
Структурные операторы управления в языке Ассемблер
Макросы данных
Макросы генерации программного кода
Применение директивы STRUC

Когда программисты-фанатики собираются в своем кругу для об-
суждения тайн структурного программирования, разговор обычно кон-
центрируется на небольшом наборе конструкций языка типа
IF-THEN-ELSE. Приверженец языков Паскаль или Си будет читать лек-
цию о преимуществах языков высокого уровня по сравнению с языками
ассемблерного типа. Вероятно, будут приведены горячие аргументы
по поводу использования оператора GOTO. Несмотря на все предыду-
щие обсуждения, ясно, что сказано далеко не все. В действитель-
ности, подобное обсуждение фокусируется только на структурном
программировании. Как Вы скоро увидите, структурное программиро-
вание возможно на любом языке. Модные структуры управления языков
высокого уровня поддерживают даже некоторые ассемблеры. Одним из
таких ассемблеров является Макро Ассемблер фирмы Майкрософт для
операционной системы MS-DOS, широко известный под названием MASM.

Потребность в короткой записи операторов
Прежде чем представить структуры управления высокого уровня в
языке Ассемблера мы рассмотрим некоторые преимущества языков вы-
сокого уровня. Так или иначе все заканчивается на уровне ассемб-
лера. Что же выигрывается от использования языка высокого уровня?
Возможность выражать программистскую идею в форме, легко пони-
маемой программистом или специалистом. Предположим, что каждому
оператору ассемблера в большей или меньшей степени соответствует
одна машинная команда.С другой стороны, один оператор языка высо-
кого уровня может расширяться до десятков или даже сотен машинных
инструкций. (Тот, кто сомневается в расширении до сотен, может
проверить это, проанализировав работу вычислительной подпрограм-
мы на языке Фортран, имеющей множество аргументов).
На Рис.1-1 показан фрагмент одной и той же программы, реализо-
ванный на Фортране и языке Ассемблера 8086. Этот фрагмент вычис-
ляет сумму 1... NUM для данного NUM. Нет сомнений, что программа
на ассемблере прежде всего может быть оптимизирована с целью

Фортран Aссемблер

sum = 0 mov sum,0
DO 100 I = 1, NUM mov ax,1
100 SUM =SUM +I loop1: cmp ax,num
jg loop1_end
add sum,ax
inc ax
jmp loop1
loop1_end:


Рис. 1-1. Сравнение Фортрана с Ассемблером

- 1-2 -
уменьшения или количества выполняемых команд, или времени выпол-
нения программы. Но вне зависимости от того, как к этому подойти,
легче написать программу на Фортране, чем на Ассемблере. Для на-
писания программы на Ассемблере должно быть принято гораздо боль-
ше решений. В силу значительной сложности работы по программиро-
ванию на ассемблере ошибки кодирования более вероятны. Я могу
быть уверен, что программа на Фортране будет выполняться превос-
ходно, но я не могу сказать этого о программе на ассемблере. По-
чему возникают такие сомнения? Потому что каждая строка программы
на Фортране представляет собой законченную мысль, в то время как
ассемблерная программа требует для реализации той же мысли мно-
жества строк.
Короче говоря, использование конструкций высокого уровня при-
водит к облегчению процесса программирования и повышению надеж-
ности программ. Такие конструкции делают программирование менее
сложным, что позволяет программисту сконцентрироваться на логике
программы. Естественно, что программисты хотели бы быть уверены в
правильности результатов своей работы. Инструментальные средства,
поддерживающие такую уверенность, приводятся в нижеследующих раз-
делах.

Введение в МАКРОСЫ

Таким образом, программирование на языке Ассемблера может быть
значительно облегчено, если иметь возможность создавать "стеног-
рамму" часто используемых операторов. MASM обеспечивает эту воз-
можность через средства макро. Макро представляют собой "суперко-
манды", которые разгружают MASM от части лишней и часто
повторяющейся работы по обработке ассемблерной программы. При по-
мощи макросов программисты определяют блоки ассемблерных операто-
ров, а затем, используя конкретные ссылки, указывают MASM на
включение соответствующих блоков в ассемблерную программу. В этой
главе мы рассмотрим некоторые из таких макросов и понемногу ра-
зовьем Ваши способности по написанию собственных инструментариев.
Все это позволит Вам соединить скорость выполнения ассемблерной
программы с мощностью языка высокого уровня.
Для создания и использования макро необходимо выполнить 2 ша-
га:
Шаг 1. Определение макро

;; Определить "Требуемую функцию" типа @DosCall
@DosCall MACRO
int 21h ;для выполнения функции обра-
ENDM ;титься к MS-DOS
Шаг 2. Использование макро

@DosCall <--- вызов макро



В листинге появится следующее:

@DosCall <--- вызов макро
1 int 21h ;для выполнения функции обра-
;титься к MS-DOS


При ассемблировании программы оператор DosCall заменяется на
оператор int 21h, включая комментарий. Файл листинга содержит
строку DosCall как ссылку, однако объектный файл содержит только

- 1-3 -
код для инструкции int 21h. Такая операция известна под названием
"подстановка макро" или " расширение макро".
Заметьте, что в предыдущем примере ассемблер вставил в файл
листинга символ, обозначающий код расширенного макро. В MASM вер-
сии 4 и выше "1" помещается в строки, принадлежащие первому уров-
ню макрорасширения, "2" используется для второго уровня и т.д. В
MASM версии 3 и предыдущих версий все строки макрорасширения вне
зависимости от уровня помечаются символом плюс (+).
При обработке ассемблером ссылка на макро заменяется на прог-
раммный код, который это макро представляет. Макро не вырабатыва-
ет команду СALL (вызвать), обращенную к коду макро, хотя ссылки
на макро порой и используют такой путь.
Подобно другим конструкциям в программировании макросы должны
следовать строгим правилам. Форма описания макроса следующая:

mname MACRO argument_list
.
. <--- тело макрокода
.
ENDM




Имя макро определяется как mname, а argument_list представляет
собой список аргументов, разделенных запятыми. Если макро не со-
держит аргументов (как в нашем примере с @DosCall), список аргу-
ментов может быть пуст.
Выше был приведен простейший пример. Если это было бы все, что
умеет делать макро, то тогда оно было бы довольно примитивным об-
разованием. К счастью, макросы можно подгонять к конкретным усло-
виям применения, используя секцию аргументов. Следующее макро яв-
ляет собой пример подобной настройки.

;; Определить "Печать символа" как PrintChr
@PrintChr MACRO char
mov ah,05
mov dl,&char
@DosCall
ENDM



И теперь при использовании макро мы пишем:

@PrintChr 'A' <--- вызов макро,




и в нашем листинге появляется следующее:

@PrintChr 'A' <--- вызов макро
1 mov ah,05
1 mov dl,'A'
2 int 21h ;для выполнения функции обратиться к MS-DOS




Конструкция "&char" в макроописании была заменена после вызова
макро на "A". (Да, мы ссылаемся на макро, как если бы стоял вызов
call. Это удобно, особенно если вспомнить, что команда CALL в яв-
ном виде не используется.) Цифра, появляющаяся в начале строки,
представляет собой способ, при помощи которого MASM сообщает
программисту, что текущий код является результатом макрорасшире-
ния. Также заметим, что макро @PrintChr содержит ссылку на ранее
определенное макро @DosCall, которое расширяется в оператор
int 21h, его представляющий. MASM продолжает "раскручивать" вы-

- 1-4 -
зовы макро до такого уровня, до которого они вложены, пока не пе-
реполнится область памяти таблицы символов. Вложенность являет
собой другой способ сообщения, что макро может вызвать макро, ко-
торое в свою очередь может вызвать следующее макро и т.д.
Имя char в макро @PrintChr называется формальным аргументом.
Всякий раз, когда формальный аргумент char появляется в макро, он
заменяется на значение, использованное при вызове макро. В приме-
ре с @PrintChr замена char означает, что все появления сhar в
макро заменяются на "A".
Заметим, что любое имя, выбранное для формального аргумен-
та,используется исключительно для этого аргумента. Таким образом,
если Вы для формального аргумента выбрали имя AX, Вы не можете в
данном макро ссылаться на регистр AX!
Аналогичное предупреждение действует и для именования собс-
твенно макро. Как только для описания макро Вы выбрали имя add,Вы
найдете, что все ссылки на код операции ADD будут вырабатывать в
данной программе расширение макро add. При желании, таким обра-
зом, можно изменять директивы MASM. Однако очень важно не созда-
вать для имен конфликтные ситуации.
Символ "&" перед char в макро @PrintChr используется для до-
бавления в строку mov dl, значения char. Символ "&" не нужен для
раскрутки формального аргумента, что происходит и так, а нужен
для сообщения MASM, что char является формальным аргументом, а не
частью более длинной строки "mov dl,char". Как показано в следую-
щем примере, оператор "&" особенно важен, если формальные аргу-
менты содержатся в длинных строках.

Макроописание Макрорасширение
@Example MACRO arg @Example Y
mov dl,arg 1 mov dl,y <-правильно
mov dl,&arg 1 mov dl,y <-правильно
mov dl,argZ 1 mov dl,argZ
mov dl,&argZ 1 mov dl,argZ
mov dl,arg&Z 1 mov dl,YZ <-правильно
mov dl,Xarg 1 mov dl,Xarg
mov dl,X&arg 1 mov dl,XY <-правильно
mov dl,XargZ 1 mov dl,XargZ
mov dl,X&argZ 1 mov dl,XargZ
mov dl,Xarg&Z 1 mov dl,XargZ
mov dl,X&arg&Z 1 mov dl,XYZ <-правильно
ENDM



Строго говоря, в макро @PrintChr символ "&" не требуется. MASM
имеет возможность определить, что char - формальный аргумент, так
как после запятой он присутствует в одиночестве. Тем не менее,
это хорошая привычка использовать символ "&", даже когда он не
требуется, так как он выделяет формальный аргумент при чтении
макро и проясняет для MASM, что имелось в виду.


Метки типа LOCAL

До сих пор макросы, использованные нами, предназначались лишь
для генерации простых ассемблерных команд. Теперь предположим,
что мы хотим создать макро, которое выбирает меньшее из двух чи-
сел и помещает результат в какую-то ячейку. Такое макро может
выглядеть, например, так:

- 1-5 -
min MACRO result,first,second
mov &result,&first
cmp &first,&second
jl order_ok
mov &result,&second
order_ok:
ENDM



Когда мы вызываем макро min, оно вырабатывает правильный код,
однако имеется одна проблема: хотя макро вычисляется превосходно,
оно может быть использовано лишь единожды. Так как метка order_ok
может быть определена в программе только один раз, при использо-
вании данного макро в двух местах программы MASM распознает мно-
жественное определение символа.
Чтобы в добавление к другим параметрам разрешить указание па-
раметра метки, мы можем выполнить небольшое изменение макро:

min MACRO result,first,second,order-ok
mov &result,&first
cmp &first,&second
jl &order_ok
mov &result,&second
оrder_ok&:
ENDM


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

min ax,bx,cx,jmp1 <- вызов макро
1 mov ax,bx
1 cmp bx,cx
1 jl jmp1
1 mov ax,cx
1 jmp1:



Такой способ создания нового имени при каждом вызове макро min
является лучшим. Именно для этой цели MASM имеет директиву LOCAL
(локальный). Когда MASM встречает LOCAL, для стоящего рядом имени
создается уникальная метка. Другой способ заключается в помещении
параметра LOCAL в список параметров MACRO, но при этом MASM про-
изводит присваивание действительного аргумента. Предупреждение:
операторы LOCAL всегда должны помещаться сразу же после строки
именования MACRO! После включения директивы LOCAL новое макро min
выглядит так:
min MACRO result,first,second
LOCAL order_ok
mov &result,&first
cmp &first,&second
jl order_ok
mov &result,&second
order_ok:
ENDM



- 1-6 -

Теперь, когда мы снова вызовем макро min, образуется листинго-
вый файл, как показано в следующем примере. Значение order_ok бу-
дет заменено на ??0000. Каждый раз при вызове макро order_ok за-
меняется на новое значение, вырабатываемое MASM.

min ax,bx,cx ;первый вызов
1 mov ax,bx
1 cmp bx,cx
1 jl ??0000
1 mov ax,cx
1 ??0000:
min ax,bx,cx ;второй вызов
1 mov ax,bx
1 cmp bx,cx
1 jl ??0001
1 mov ax,cx
1 ??0001:



Конечно, остается вероятность возникновения конфликта меток,
если Вы решите использовать метки, начинающиеся с ??. Если Вы ус-
траните использование меток, начинающихся с ??, то Вы сможете вы-
зывать макро min столько раз, сколько захотите.
Использование меток LOCAL не ограничивается только переходами
по адресам. Метки LOCAL могут также использоваться с данными, как
показано в следующем макросе. В этом случае макрос используется
для вставки текстовых строк в сегмент данных и последующего соз-
дания ссылки на них в сегменте кода.
Сравнивая исходный текст с макрорасширением в Листинге 1-1,
можно увидеть, насколько удобно использовать макрос. Листинг 1-1
также содержит некоторые полезные макросы, облегчающие решение
задачи по написанию программ .ЕХЕ. Однажды определив эти макросы,
Вы можете не беспокоиться за правильность синтаксиса программ
.ЕХЕ!

Листинг 1-1. Программа Hello World
-------------------------------------------------------------
;********************************************************
; С Е К Ц И Я М А К Р О О П И С А Н И Я
;********************************************************
;
@DosCall MACRO
int 21h ;вызвать функцию MS-DOS
ENDM
;
@InitStk MACRO ;определить размер стека
stk_seg SEGMENT stack
DB 32 dup ('stack ')
stk_seg ENDS
ENDM
;
@InitPrg MACRO segment ; инициализировать сегмент
ASSUME ds:segment ; данных
start: ; основная точка входа
mov ax,segment

- 1-7 -
mov ds,ax ;установить сегмент данных
mov es,ax ;установить внешний сегмент
ENDM
;
@Finis MACRO
mov ax,4C00h ;завершить процесс
@DosCall
ENDM
;
@DisStr MACRO string ;отобразить строку памяти
mov dx,offset string
mov ah,09h
@DosCall
ENDM
;
@TypeStr MACRO string ;определить и отобразить строку
LOCAL saddr ;установить локальную метку
cod_seg ENDS ;завершить сегмент кода
dat_seg SEGMENT ;перейти к сегменту данных
saddr DB string,'$' ;определить строку в сегм.данных
dat_seg ENDS ;завершить сегмент данных
cod_seg SEGMENT ;вернуться к сегменту кода
@DisStr saddr ;отобразить строку
ENDM
;
;
;********************************************************
; П Р О Г Р А М М Н А Я С Е К Ц И Я
;********************************************************
;
@IniStk ;установить стек
cod_seg SEGMENT ;определить сегмент кода
main PROC FAR ;главная (одна) процедура
ASSUME cs:cod_seg ;назначить сегм.кода рег.CS
@InitPrg dat_seg ;инициализ-ать сегмент кода
@TypeStr 'Hello world!' ;выдать приветствие
@Finis ;закончить программу
main ENDP ;завершить процедуру
cod_seg ENDS ;завершить сегмент кода
END start ;завершить программу и ...
;определить адрес пуска


-------------------------------------------------------

Программу можно вводить точно так, как она приведена, а затем
ее ассемблировать и выполнять. Слова "Hello world!" подлежат
отображению на экране.Сам по себе результат не очень выразителен,
однако, если используемый макрос сохранен в файле include (вклю-
чить), написание .EXE-программ значительно облегчается. Давайте
посмотрим на распечатку расширения программы, приведенного в Лис-
тинге 1-2.


- 1-8 -
Листинг 1-2. Макрорасширение программы Hello World
-------------------------------------------------------------
;********************************************************
; П Р О Г Р А М М Н А Я С Е К Ц И Я
;********************************************************
;
; @InitStk ;установить стек
1 stk_seg SEGMENT stack
1 DB 32 dup ('stack ')
1 stk_seg ENDS
cod_seg SEGMENT ;определить сегмент кода
main PROC FAR ;главная (одна) процедура
ASSUME cs:cod_seg ;назначить сегм.кода рег.CS
@InitPrg dat_seg ;инициализ-ать сегмент данных
1 start: ;главная точка входа
1 mov ax,dat_seg
1 mov ds,ax ;установить сегмент данных
1 mov es,ax ;установить внешний сегмент
@TypeStr 'Hello World!' ;выдать приветствие
1 cod_seg ENDS ;приостановить сегмент кода
1 dat_seg SEGMENT ;перейти к сегменту данных
1 ??0000 DB 'Hello world!,'$' ;определить строку
1 dat_seg ENDS ;приостановить сегмент данных
1 cod_seg SEGMENT ;вернуться к сегменту кода
2 mov dx,offset ??0000
2 mov ah,09h
3 int 21h ;вызвать функцию MS-DOS
@Finis ;завершить программу
1 mov ax,4C00h ;завершить процесс
2 int 21h ;вызвать функцию MS-DOS
main ENDP ;закончить процедуру
cod_seg ENDS ;закончить сегмент кода
END start ;закончить программу ...




Прежде всего необходимо заметить, что используемый локальный
адрес (saddr) в @TypeStr отлично работает как метка оператора
данных. При связывании меток с данными не используйте двоеточие
(:). Далее посмотрим, как макрорасширение использует зарезервиро-
ванное слово SEGMENT (сегмент) в макро @InitPrg. Нет проблем!
Вспомните, что имена формальных аргументов в списке аргументов
перекрывают все другие описания MASM.
Обратите внимание, что некоторые строки не включены в листин-
говый файл. Например, оператор ASSUME ds:data_seg из @InitPrg
опущен. Оператор был отассемблирован, но MASM подавил вывод его
расширения.
Все это произошло по причине специфики обработки макросов. По
умолчанию, исходные строки, не вырабатывающие исполнительного ко-
да, в листинге подавляются. Оператор ASSUME является директивой
MASM, которая не вырабатывает собственного кода; таким образом,
он в листинге отсутствует. С другой стороны, директивы завершения
сегмента ENDS приводятся в листинге, хотя программный код не вы-
рабатывают. Есть в MASM тайны, над которыми всем нам стоит пораз-
мышлять.
Представленную программу не следует рассматривать, как эталон
хорошего программирования. Хотя идея использования макросов в
вводной и заключительной части .EXE-программ и замечательна,
включение имен "важных" символов в сами макросы применяется ред-
ко. Если имя сегмента данных отличается от dat _seg, в программе
может возникнуть нежелательная конфликтная ситуация. Например,
когда макро @TypeStr должно передать имя dat_seg в качестве аргу-

- 1-9 -
мента или макро @InitPrg полагает, что сегмент данных называется
dat_seg.

Директивы листинга макро

Если вы хотите увидеть полный листинг макро, поместите в файл
с ассемблерной программой директиву MASM .LALL. Затем получите
файл .LST и сравните его с первоначальным листингом нашего приме-
ра. Теперь оператор ASSUME ds:data_seg будет в листинге. Для из-
менения режима листинга на обратный используйте директиву .XALL.
Она вернет MASM в режим, устанавливаемый по умолчанию. Если Вы
хотите подавить все макрорасширения, используйте директиву .SALL.


Макробиблиотеки

Термин "макробиблиотека" не совсем верен. В действительности,
макробиблиотеки совсем не то, что под этим могли бы понимать
программные средства LINK /редактор/ и LIB /обработчик библиотек/
фирмы Майкрософт.Макросы должны подключаться во время компиляции,
так как они представляют собой директивы для MASM и только для
MASM. Средства LINK и LIB не знают, что делать с ними. Вместо
этого макробиблиотеки являют собой файлы типа include (включить).
Они могут определяться в отдельном файле, называемом MYLIB.MAC
или STANDARD. MLB или как-нибудь еще (Вы можете выбрать любое
допустимое имя), и подключаться при ассемблировании посредством
помещения в исходный текст программы директивы include. Например,

INCLUDE C:\ASМ\LIB\STANDARD.MLB \*

Правила написания имени и указания накопителя те же, что и для
всей системы. В файле листинга строки, полученные из файла
include, начинаются с буквы "C", равно как строки макрорасширения
начинаются с плюса "+" (в версиях MASM ниже 4.0) или номера уров-
ня расширения. Конечно, если у Вас большая библиотека и Вы не хо-
тите загромождать файл .LST макроописаниями, при помощи директивы
.XLIST "выключите" листинг перед include, а затем "включите" его
обратно (после include), применяя директиву .LIST.
Использование макробиблиотек обосновывает введение следующих
макродиректив. Хотя довольно редко сначала определяют макро в
программе, а затем отменяют такое определение (Вы бы его скорее
просто уничтожили!), для использования нескольких макроопределе-
ний Вы вполне можете подключить макробиблиотеку. Оставшиеся мак-
роопределения занимают значительное пространство памяти в таблице
символов MASM и в области памяти макро. Вернуть эту память можно
при помощи директивы PURGE (очистить). PURGE позволяет изъять
описания указанных макро. Для изъятия макроописаний предыдущего
примера следует выдать директиву:

PURGE @DosCall,@InitStk,@InitPrg,@Finis,@DisStr,@TypeStr




Она очищает все пространство памяти, занятое макроописаниями,
и позволяет нам использовать его для других целей.





- 1-10 -
Макродиректива повторения - REPT

MASM обеспечивает возможность повторять блок макрокода. Су-
ществует три варианта повтора, причем каждый из них имеет свое
особое предназначение.
В качестве первого примера предположим, что мы хотим создать в
сегменте данных область для обработки файлов. Для получения досту-
па к файлам мы используем метод описателя файла и, так как мы хо-
тим работать более чем с одним файлом, мы пишем программу, присва-
ивая каждому блоку уникальное имя.

file_head MACRO fnum
file_hand_&fnum dw ? ;заголовок файла
file_nmax_&fnum db 49 ;макс.длина имени файла
file_nlen_&fnum db ? ;действит.длина имени файла
file_name_&fnum db 50 dup (?) ;буфер имени файла
ENDM



Почему для fnum (номер файла) мы не использовали директиву
LOCAL? Потому, что для самого макро эти метки не являются локаль-
ными. К ним должен осуществляться доступ из других частей прог-
раммы с целью установки имени файла, получения возможности опери-
рования с блоком управления файлом и т.д. Это макро может быть
усовершенствовано. Что необходимо сообщить программе пофайлового
копирования, если мы хотим одновременно обрабатывать два файла?
Нам следует дважды вызвать file_head (описатель файла):

file_head 1 ;1-ый блок файла
file_head 2 ;2-ой блок файла



Вместо этого, используя директиву REPT (повторить), мы можем
написать file_head так, чтобы он определял столько блоков, сколь-
ко необходимо. Такой макрос приведен в Листинге 1-3.

Листинг 1-3. Описание блока доступа к файлу
------------------------------------------------------------

fcnt = 0 ;определить и иниц-ать символ
file_head2 MACRO fnum
file_hand_&fnum dw ? ;заголовок файла
file_nmax_&fnum db 49 ;макс.длина имени файла
file_nlen_&fnum db ? ;действ.длина имени файла
file_name_&fnum db 50 dup (?) ;буфер имени файла
ENDM
file_head MACRO fnum
REPT fnum ;повторить блок "fnum" раз
file_head2 %fcnt ;создать блок #"fcnt"
fcnt = fcnt + 1
ENDM ;закончить блок повторения
ENDM ;закончить макро file_head


-------------------------------------------------------------

Как показано в Листинге 1-4, при вызове макро file_head оно, в
свою очередь, дважды вызывает макро file_head2, используя каждый
раз новое значение fnum. Конечно, это макрорасширение со значени-
ем статуса листинга, установленного по умолчанию, не показывает
явно обращения к file_head2. Однако результат работы REPT мы мо-
жем видеть по двум созданным блокам управления файлами. Заметим,

- 1-11 -
что директива REPT должна заканчиваться строкой ENDM, равно как и
директива MACRO. Вcе блоки повторения должны заканчиваться ENDM
(конец макро). Аналогично ENDM должно появляться в конце каждого
макроопределения.

Листинг 1-4. Макрорасширение блока описания доступа к файлу
-----------------------------------------------------------------

file_head 2
3 file_hand_0 dw ? ;заголовок файла
3 file_nmax_0 db 49 ;макс. длина имени файла
3 file_nlen_0 db ? ;действит.длина имени файла
3 file_name_0 db 50 dup (?) ;буфер имени файла
3 file_hand_1 dw ? ;заголовок файла
3 file_nmax_1 db 49 ;макс. длина имени файла
3 file_nlen_1 db ? ;действит.длина имени файла
3 file_name_1 db 50 dup (?) ;буфер имени файла


------------------------------------------------------------------

В добавление к директиве REPT мы также использовали счетчик.
Счетчик - это переменная, имеющая цифровое значение. Так как его
значение может меняться, он должен быть определен при помощи опе-
ратора присваивания (=). (В MASM для определения переменных, име-
ющих статические значения, используется оператор equ (прирав-
нять), в то время как для определения переменных, чьи значения
могут изменяться, применяется знак равенства (=).) Счетчик, при-
меняемый в макро file_head, называется fcnt (счетчик файла).
Счетчик fcnt увеличивается на 1 при каждом проходе file_head. Но
почему метки находятся в file_head2, file_hand_0 и т.д., а не в
file_hand_fcnt? Каким образом имя fcnt заменяется на свое значе-
ние? Ответ заключается в операторе "%",стоящем в вызове
file_head2 перед fcnt. Знак процента предписывает замену символа
на его значение. Так как мы использовали знак процента, нам необ-
ходимы два макро. Если бы мы попытались вычислить и подставить
fcnt в одно маkро:

REPT fnum ;повторить блок "fnum" раз
file_hand_&%fcnt dw ? ;заголовок файла ,

возникла бы ошибка символа:


file_hand_fcnt dw ? ;заголовок файла


Оператор процента (%) работает только в аргументах макровызо-
ва! Кроме того, значение символа должно быть абсолютной (непере-
мещаемой) константой.
Другим важным аспектом наших макро является то, что счетчик
fcnt инициализируется вне макроблока. Это делается потому, что мы
не хотим устанавливать fcnt в 0 всякий раз при вызове file_head
(что может вызвать дублирование меток). Однако, fcnt должен быть
где-то инициализирован, или оператор:

fcnt = fcnt + 1


- 1-12 -
вызовет появление сообщения об ошибке "Символ не определен".


Более подробно о макродирективах повторения - IRP и IRPC

Кроме директивы REPT MASM поддерживает еще две директивы мак-
роповторений. Это - IRP (неограниченное повторение) и IRPC (не-
ограниченное повторение символа). В действительности, ничто не
повторяется бесконечно. Вместо этого повторения происходят до тех
пор, пока в списке аргументов есть хоть один аргумент. В Листинге
1-5 приведен пример макроповторения, названного test_vac и пред-
назначенного для добавления элементов в сегмент данных.

Листинг 1-5. Пример макро повторения IRP и его расширение
------------------------------------------------------------------

test_mac MACRO args ;определить "test_mac"
IRP dummy,<&args>
db dummy ;добавить элемент
ENDM ;закончить "IRP"
ENDM ;закончить "test_mac"

test_mac 'one' <-- 1-ый вызов
2 db 'one' ;добавить элемент
test_mac <'two','three','four'> <-- 2-ой вызов
2 db 'two' ;добавить элемент
2 db 'three' ;добавить элемент
2 db 'four' ;добавить элемент


------------------------------------------------------------------

При каждом проходе блока повторения в качестве значения dummy
используется очередное значение списка аргументов. Используя ди-
рективу IRP, мы можем для выполнения трех действий применить
только один вызов макро. При повторном вызове test_ mac блок IRP
повторяется db раз для каждой из трех строк списка аргументов.
Введем для макросов два специальных символа - угловые скобки
(< и >). Макро test_mac предполагает наличие только одного аргу-
мента, а мы хотим переслать ему список аргументов. Угловые скобки
выполняют эту функцию, преобразуя текст, заключенный в них, в
одиночный литерал. Таким образом, 'two','three','four' интерпре-
тируется как один аргумент, а не три. Однако сами угловые скобки
принимающему макро не пересылаются. Внутри test_mac args имеет
значение 'two','three','four', а не <'two','three','four'>. Вот
почему в директиве IRP были добавлены угловые скобки.
Однако это объяснение не применимо к строкам! Одиночные кавыч-
ки, в которые заключаются строки, не допускаются, а добавление
еще одного уровня приводит к путанице . Если мы используем опера-
тор define byte (определить байт) так:

db 'dummy' ;добавить элемент



MASM разворачивает строку следующим образом:

2 db 'dummy' ;добавить элемент



что может создать нам довольно много значений dummy, но не

- 1-13 -
сделает то, что мы хотим. Мы можем вызвать использование дей-
ствительного аргумента через

db '&dummy' ;добавить элемент

но MASM развернет эту строку в

2 db "one" ;добавить элемент

Это приведет к появлению специальной ошибки "Чтение текста
после конца". Такая же ошибка возникает, если Вы случайно создали
бесконечный рекурсивный вызов макро. В общем случае MASM выберет
всю память для сохранения всех используемых символов. Будьте вни-
мательны! Это сообщение об ошибке выдается до тех пор, пока Вы не
прекратите работу MASM, нажав "Cоntrоl-C".

Резюме по использованию макро

Из того , что мы изучили, видно - макросы используют некоторый
тип "стенографического" программирования. Так, если вы определили
некоторый блок программы, Вы можете включать его многократно че-
рез простой вызов макро. Мы видели, что макросы определяются при
помощи оператора MACRO, который присваивает макро имя и дополни-
тельно может снабжать его аргументами. Макроописание заканчивает-
ся оператором ENDM. После выполнения макроописания вызов макро
осуществляется по его имени, за которым могут следовать некоторые
параметры.
Мы также видели, как MASM, используя директиву LOCAL, может
вырабатывать уникальные метки и как применяются директивы повто-
рения. Наши знания о директивах повторения и их использовании бу-
дут расширены в следующей главе.
Справочное Руководство Программиста для Операционной Системы
MS-DOS фирмы Майкрософт содержит макроописания всех системных вы-
зовов. Кроме того, в нем также содержатся некоторые основные мак-
росы, предназначенные для решения общих задач (например, переме-
щение строки). Это руководство является хорошим пособием по
применению макросов и их структурированию. Ниже приводятся три
таблицы, которые наверняка окажутся Вам полезными. В Табл. 1-1
приводится свод макродиректив, используемых MASM. В Табл. 1-2 пе-
речисляются специальные макрооператоры; а в Табл. 1-3 собраны
макродирективы управления листингом.
Теперь мы прошли полпути в изучении макросов для структуриро-
ванных программ. Для выполнения работы по созданию этих макросов
нам необходимо знать, когда и что ассемблируется в программу. Это
тема следующего раздела.

Условное ассемблирование

При написании программ на Ассемблере очень неплохо иметь воз-
можность включения некоторых программных секций. Используя макро-
команды, было бы также неплохо иметь возможность выбирать различ-
ные направления работы программы в зависимости от аргументов,
передаваемых в макро. MASM обеспечивает эти возможности через ус-
ловное ассемблирование.

- 1-14 -

Когда может потребоваться условное ассемблировние? Предполо-
жим, что Вы пишите большую программу, которая, подобно большинс-
тву таких программ, имеет какие-то ошибки. Для выяснения обстоя-
тельств работы программы Вы решаете поместить в нее некоторые
отладочные операторы. Однако , когда у Вас появится уверенность,
что программа выполняется правильно, Вы захотите изъять эти опе-
раторы, чтобы программа выполнялась без лишних кодов. Но так как
программа, вероятно, содержит еще много ошибок, отладочные опера-
торы придется выполнять снова. Добавление и удаление операторов
утомительно. Для решения этой проблемы может быть использовано
условное ассемблирование. В Листинге 1-6 показано воздействие пе-
реключателя "DEBUG" (отладить) на операторы блока при условном
ассемблировании. Реализован хороший способ редактирования прог-
раммы, а переключатель .SALL использован для подавления некоторой
части макрорасширения @TypeStr. Наш интерес обращен только к
строкам, связанным с условным ассемблированием.

Таблица 1-1. Макродирективы

--------------------------------------------------------
Директива Переменная Описание применения
--------------------------------------------------------
mname MACRO parameter_list МАКРООПИСAHИЕ
Сигнализирует о нача-
ле блока макроописа-
ния; parameter_list
определяет формальные
аргументы, используе-
мые в блоке.

ENDM КОНЕЦ МАКРО
Сигнализирует конец
макроописания или бло-
ка повторения REPT,IRP
или IRPC. Наличие обя-
зательно!

EXITM ВЫХОД ИЗ МАКРО
При достижении выход из
макро. Наиболее часто
используется при ус-
ловном ассемблировании.

LOCAL symbol_list ЛОКАЛЬНЫЙ СИМВОЛ
Определяет для ассембле-
ра символы из списка
symbol_list как уникаль-
ные символы.
Расширяется в ??ххх, где
ххх - шестнадцатиричные
числа.

PURGE macro_list УДАЛИТЬ МАКРООПИСAHИЕ
Уничтожает описание макро
из списка macro_list.


- 1-15 -
--------------------------------------------------------
Директива Переменная Описание применения
--------------------------------------------------------
REPT выражение ПОВТОРИТЬ
Повторяет блок команд,
размещенных между REPT
и ENDM,столько раз,сколь-
ко задано в выражении.

ITP dummy, НЕОГРAHИЧЕННОЕ ПОВТОРЕНИЕ

Повторяет блок команд
между IRP и ENDM для
каждого значения из para-
meter_list,заменяя фор-
мальный параметр (dummy)на
значение параметра из каж-
дого расширения.

IRPC dummy, строка СИМВОЛ НЕОГРAHИЧЕННОГО
ПОВТОРЕНИЯ
Повторяет блок команд
между IRPC и ENDM для
каждого символа строки,
заменяя формальный пара-
метр на символ из каж-
дого расширения.
---------------------------------------------------------

Таблица 1-2. Специальные символы в макрокомандах
---------------------------------------------------------
Символ Описание применения
---------------------------------------------------------
&argument Соединяет формальные аргументы или сим-
волы с текстом. Особенно необходим для
подстановки вместо формальных аргументов
в строках, заключенных в кавычки.

;;comment text Обозначает комментарий. Такой
комментарий никогда не приводится в
макроописании.

!char Указывает, что следующий далее символ
является литералом. Используется для
включения &, % и т.д. в макрорасширения,
когда эти символы могут быть интерпре-
тированы не как специальные.

%symbol Используется для преобразования символа
или выражения в число текущей системы
счисления.
Угловые скобки (< и >) используются для
определения текста, заключенного между
ними, как литерала. Все, что заключено
в такие скобки, может быть передано в
макро как одиночный аргумент.
----------------------------------------------------------

- 1-16 -


Таблица 1-3. Директивы управления листингом в
макрокомандах

----------------------------------------------------------
Директива Описание применения
----------------------------------------------------------

.XALL Приводит исходный и объектный код макрорасши-
рений, исключая исходные строки, которые не
вырабатывают исполнительного кода. Устанав-
ливается по умолчанию.

.LALL Приводит все строки макрорасширения, исключая
комментарии, начинающиеся с удвоенных точкой
с запятой /;;/.

.SALL Исключает код, вырабатываемый макрорасшире-
нием.

.LIST Приводит строки исходного текста программы.
Действие противоположно .XLIST, однако сос-
тояние листинга, определяемое директивами
.XALL, .LALL или .SALL не изменяет.

.XLIST Подавляет любую выдачу. Перекрывает все
другие директивы.
---------------------------------------------------------


Листинг 1-6. Условное ассемблирование операторов DEBUG -
FALSE
----------------------------------------------------------------
;часть А - листинг исходного текста
FALSE EQU 0
TRUE EQU 0FFFFh
DEBUG EQU FALSE
.
.
.
@TypeStr 'hello world!'
IF DEBUG <--- начало условного блока
@TypeStr 'Hi -I made it to this point in the program'
ENDIF <--- конец условного блока
.
.
.
;часть В - листинг MASM

@TypeStr 'hello world!'
1 mov dx,offset ??0000
1 mov ax,09h
1 int 21h ;вызвать функцию MS-DOS
ENDIF
----------------------------------------------------------------


- 1-17 -

Данный пример был ассемблирован со значением переключателя
DEBUG - FALSE (ложь). В результате от условного блока в листинге
MASM после расширения @TypeStr появляется только оператор ENDIF.
Таким образом MASM сообщает, что условный блок присутствовал, но
он не ассемблировался. Когда значение переключателя DEBUG изменя-
ется на TRUE (истина), MASM вырабатывает другую программу, приве-
денную в Листинге 1-7.


Листинг 1-7. Условное ассемблирование операторов DEBUG -
TRUE
------------------------------------------------------------------

;листинг MASM
DEBUG EQU TRUE
.
.
.
@TypeStr "hello world"
1 mov dx,offset ??0001
1 mov ax,09h
2 int 21h ;вызвать функцию MS-DOS
IF DEBUG
@TypeStr 'Hi -I made it to this point in the program'
1 mov dx,offset ??0002
1 mov ah,09h
2 int 21h ;вызвать функцию MS-DOS
ENDIF
----------------------------------------------------------------
Все это время отладочные операторы присутствовали в программе.
MASM также включает в листинг строку, вызывающую ассемблирование
операторов. Если Вы предпочитаете увидеть в файле листинга все
директивы условного ассемблирования вне зависимости от того, име-
ют они значение TRUE или FALSE, используйте директиву .LFCOND
(включить список ложных состояний). Позднее Вы можете подавить
выдачу ложных состояний при помощи директивы .SFCOND (подавить
выдачу ложных состояний). В основном, блок условного ассемблиро-
вания начинается с одной из разновидностей оператора IF (если)
(см. полный список в Табл. 1-4) и заканчивается оператором ENDIF.
Обычно использование переключателей TRUE/FALSE в условном ас-
семблировании возникает при программировании систем (программиро-
вание операционных систем компьютеров). Если для Вашего компьюте-
ра имеется исходный текст операционной системы на языке ассембле-
ра, просмотрите его. Вы наверняка найдете, что условное ассембли-
рование используется в нем весьма интенсивно. Условное ассембли-
рование позволяет проектировщику писать одну операционную
систему, а через использование переключателей - конфигурировать
ее на конкретный набор аппаратных средств. Эти переключатели, по-
добно переключателю DEBUG из нашего примера, позволяют сгенериро-
вать работающую систему для данного типа, количества или конфигу-
рации памяти, пульта, периферийных устройств, драйверов и т.д.
Некоторые выражения, которые при вычислении дают 0 или имеют
значение 0, MASM рассматривает как FALSE. Ненулевые значения
рассматривает как TRUE. Обычно для символа TRUE используется
шестнадцатиричное значение FFFFh. Это разрешает использовать TRUE
в любых битовых операциях. Например, поразрядное выполнение AND

- 1-18 -
(логическое И) над 0001 и 1000 равно 0000, так как хотя оба зна-
чения и истинны, их логическое произведение должно быть ложно.
Вспомните, что MASM использует одни и те же операторы как для ло-
гических, так и для битовых операций.


Таблица 1-4. Директивы условного ассемблирования

---------------------------------------------------------
Директива Переменная Описание применения
---------------------------------------------------------

IF выражение IF TRUE (если истина)
Если значение выражения не
нулевое, операторы условно-
го блока ассемблируются.

IFE выражение IF FALSE (если ложь)
Если значение выражения рав-
но нулю, операторы условного
блока ассемблируются.

ELSE ELSE (иначе)
Если значение условной ди-
рективы ассемблирования рав-
но FALSE (ложь) (условный
блок не ассемблируется),
ассемблируются альтернатив-
ные операторы блока ELSE.
Завершает блок IFXXXX, хотя
после должно следовать ENDIF.
Действительно только после
оператора IFXXXX.

ENDIF END блока IF (конец блока IF)
Завершает блок IFхххх или
ELSE.

IF1,IF2 IF MASM проход 1, IF MASM
проход 2
Ассемблирует условный блок,
если MASM-ассемблер осущест-
вляет указанный проход.
См.взаимозависимость между IF1
и IF2 и IFDEF и IFNDEF.

IFDEF символ IF cимвол DEFINED (если сим-
вол определен)
IFNDEF символ IF символ NОT DEFINED (если
символ не определен)
Выясняет, определен ли сим-
вол или он имеет внешнее
объявление. IFNDEF противо-
положно IFDEF. См. взаимо-
связь с проходами ассемблера.

IFB <аргумент> IF аргумент BLANK (если ар-
гумент пуст).

- 1-19 -
---------------------------------------------------------
Директива Переменная Описание применения
---------------------------------------------------------
IFNB <аргумент> IF аргумент NOT BLANK (если
аргумент не пуст).
Выясняет, пуст ли аргумент.
Используется для определения
передаваемых параметров мак-
ро. IFNB противоположноIFB.
Наличие угловых скобок обя-
зательно.
IFIDN , IF строка1 IDENTICAL TO
строка2 (если строка1 иден-
тична строке2)
IFDIF , IF строка1 DIFFERENT FROM
строка2 (если строка1 отлич-
на от строки2)
Определяет, идентичны ли
строка1 и строка2. IFDIF
противоположно IFIDN.
Наличие угловых скобок обя-
зательно.
---------------------------------------------------------

Операторы отношений

Кроме использования символов с предопределенными значениями и
арифметических выражений MASM поддерживает операторы отношений,
которые могут применяться для управления операторами условного
ассемблирования. Операторами отношений являются операторы, выра-
жающие взаимосвязь между двумя значениями. Less than (меньше
чем), greater than (больше чем), equal to (равно) и not equal to
(не равно) - примеры операторов отношений.
Эти операторы позволяют выполнять специальные действия по про-
верке на попадание в диапазон. Использование операторов отношений
разрешает создавать довольно сложные программные структуры, кото-
рые автоматически настраиваются на конкретную среду функциониро-
вания (например, определение размера области данных для запомина-
ния резервной области памяти). Однако, используя операторы
отношений, MASM не всегда выполняет то, что планировалось.
Работая с целыми со знаком, вы можете посчитать OFFFFh и -1 за
одно и то же значение. За некоторым исключением MASM также ис-
пользует взаимозаменяемость значений. Хотя ранние версии MASM при
работе с отрицательными числами имели некоторые сложности, более
новые версии (1.2 и выше) знают, что -1 равно 0FFFFh, однако при
сравнении величин двух чисел MASM рассматривает их по-разному.
Это иллюстрирует следующий пример:
True FFFF dw 1 gt -1 очевидно
False 0000 dw 1 gt 0FFFFh 65535, а не -1
True FFFF dw -1 ge 0FFFFh -1=-1
False 0000 dw -1 gt 0FFFFh -1 не больше -1

В примере показано, что MASM рассматривает 0FFFFh как положи-
тельное целое число 65535, однако при сравнении с -1 0FFFFh ин-
терпретируется как -1. Об этом можно заметить: "Кто предостере-
жен, тот вооружен".
Полный спис
Опубликовал Kest January 27 2009 00:35:35 · 0 Комментариев · 7109 Прочтений · Для печати

• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •


Комментарии
Нет комментариев.
Добавить комментарий
Имя:



smiley smiley smiley smiley smiley smiley smiley smiley smiley
Запретить смайлики в комментариях

Введите проверочный код:* =
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Гость
Имя

Пароль



Вы не зарегистрированны?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Поделиться ссылкой
Фолловь меня в Твиттере! • Смотрите канал о путешествияхКак приготовить мидии в тайланде?
Загрузки
Новые загрузки
iChat v.7.0 Final...
iComm v.6.1 - выв...
Visual Studio 200...
CodeGear RAD Stud...
Шаблон для новост...

Случайные загрузки
Краснов М. - Open...
NotePad Pro [Исхо...
Панель для реклам...
Распознавание иде...
PHP: настольная к...
Printgrid
INSTANT BOOSTER v...
HTMLredaktor
Система баннеро...
Abc_component
MiniChat
Мод "register.php...
index.php + мод ...
CoolControls v3.0...
Импорт новостей ...
Переработанный пл...
Отключение и вклю...
Программирование ...
Развивающийся фла...
Scrrlcaptoin

Топ загрузок
Приложение Клие... 100449
Delphi 7 Enterp... 85804
Converter AMR<-... 20067
GPSS World Stud... 12518
Borland C++Buil... 11573
Borland Delphi ... 8504
Turbo Pascal fo... 7023
Visual Studio 2... 4989
Калькулятор [Ис... 4739
FreeSMS v1.3.1 3536
Случайные статьи
сервером проекта с...
Взаимодействие ком...
Внедрение решения
Режимы экспозиции ...
Набор данных к вар...
Съемка Canon по ос...
Implementation exp...
VIRTUAL expected
Программа содержит...
Межмодульные перем...
Большой босс
Логотипы и символы...
Управление потокам...
Что писать в инфог...
Вмешательство в пр...
Внимание к ключево...
Управление изменен...
Ввод программ
Шаг к реализации с...
Структура коллекци...
Направления дальне...
10.5. Хорновские...
Сброс элементов TLB
Простая программа ...
Логическое «НЕ»
Статистика



Друзья сайта
Программы, игры


Полезно
В какую объединенную сеть входит классовая сеть? Суммирование маршрутов Занимают ли таблицы память маршрутизатора?