
- •140010, Г. Люберцы, Московской обл., Октябрьский пр-т, 403.
- •Глава 1. Архитектура реального режима
- •1.1. Память и процессор
- •Глава 1
- •Глава 1
- •1.2. Распределение адресного пространства
- •Глава 1
- •1.3. Регистры процессора
- •Глава 1
- •Глава 1
- •9 7H Шестнадцатернчное обозначение числа
- •Глава 1
- •1.4. Сегментная структура программ
- •Глава 1
- •Глава 1
- •Глава 1
- •1.5. Стек
- •Глава 1
- •1.6. Система прерываний
- •Глава 1
- •Глава I
- •1.7. Система ввода-вывода
- •Глава I
- •Глава 1
- •Глава 2. Основы программирования
- •2.1. Подготовка и отладка программы
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •2.2. Представление данных
- •Глава 2
- •Глава 2
- •2.3. Описание данных
- •Глава 2
- •Глава 2
- •2.4. Структуры и записи
- •Глава 2
- •Глава 2
- •2.5. Способы адресации
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •2.7. Вызовы подпрограмм
- •Глава 2
- •2.8. Макросредства ассемблера
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 3. Команды и алгоритмы
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •3.2. Циклы и условные переходы
- •Глава 3
- •Глава 3
- •3.3. Обработка строк
- •Глава 3
- •3.4. Использование подпрограмм
- •Глава 3
- •Глава 3
- •3.5. Двоично-десятичные числа
- •Глава 3
- •Глава 3
- •3.6. Программирование аппаратных средств
- •Глава 3
- •37Ah Порт управлсш!я
- •Глава 3
- •Глава 3
- •Глава 4. Расширенные возможности
- •4.1. Архитектурные особенности
- •Глава 4
- •4.2. Дополнительные режимы адресации
- •Глава 4
- •4.3. Использование средств 32-разрядных процессоров в программировании
- •Глава 4
- •Глава 4
- •Глава 4
- •4.4. Основы защищенного режима
- •Глава 4
- •Глава 4
- •Глава 4
- •Глава 4
- •Idiv Деление целых чисел со знаком
- •Imul Умножение целых чисел со знаком
- •In Ввод из порта
- •Inc Инкремент (увеличение на 1)
- •Int Программное прерывание
- •Into Прерывание по переполнению
- •Iret Возврат из прерывания
- •1 Lods Загрузка операнда из строки : lodsb Загрузка байта из строки lodsw Загрузка слова из строки
- •Операнд
- •Xadd память, регистр
- •Xchg Обмен данными между операндами
- •Xlat Табличная трансляция
- •Xor Логическое исключающее или
- •Содержание
Глава 2
Основы программирования
89
jmp S+2 ;выполнения
jrap S+2 ;трех команд jmp
in AL,301h ;Следующее обращение к оборудованию
Здесь используется обозначение счетчика текущего адреса S- При трансляции любой команды в счетчике текущего адреса содержится адрес этой команды (смещение ее первого байта). Команда короткого перехода занимает 2 байт, поэтому команда jmp S+2 осуществляет переход на команду, идущую следом.
Часто в подобных случаях ограничиваются одной командой jmp, которая создает необходимую задержку в доли микросекунды. В тех случаях, однако, когда устройство сопряжения с оборудованием работает заметно медленнее процессора, приходится включать между командами обращения к портам 5-6 команд jmp. Такой фрагмент можно оформить в виде блока повторения:
rept 6 jmp S+2 end m
Это, пожалуй, проще, чем писать 6 команд jmp. Макросы повторения имеют несколько разновидностей, которые мы не будем здесь рассматривать.
Макрокоманды
Программы, написанные на языке ассемблера, часто содержат повторяющиеся участки текста с одинаковой структурой. Такой участок текста можно оформить в виде макроопределения, характеризующегося произвольным именем и необязательным списком формальных аргументов. После того, как такое определение сделано, появление в программе строки, содержащей имя макроопределения и список фактических аргументов (все это вместе называют макрокомандой), приводит к генерации всего требуемого текста, называемого макрорасширением. Варьируя фактические аргументы, можно, сохраняя неизменной структуру макрорасширения, изменить отдельные его элементы.
Макроопределение должно начинаться строкой с именем макроопределения и директивой macro, в поле аргументов которой указывается список формальных аргументов. Заканчивается макроопределение директивой endm.
Пусть в программе требуется неоднократно сохранять в стеке содержимое трех регистров, но в каждом конкретном случае номера регистров и их порядок отличаются. Оформим эти действия в виде макроопределения:
psh
macroa,b,c push a push b push с endm
Появление в исходном тексте программы строки psh АХ, ВХ, СХ
приведет к генерации следующего фрагмента текста:
АХ ВХ СХ
push push push
Если же в исходном тексте имеется строка psh DX, ES, ВР то соответствующее макрорасширение будет иметь вид:
DX
ES
BP
push push push
В качестве фактических аргументов могут выступать любые обозначения ассемблера, допустимые для данной команды. В частности, макровызов
push
push push
psh mem,[BX],ES:[17h] приведет к следующему макрорасширению:
mem [ВХ] ES:[17h]
Если какие-то строки макроопределения должны быть помечены (например, с целью организации циклов), то обозначения меток следует объявить локальными с помощью оператора local. В этом случае ассемблер, генерируя макрорасширения, будет создавать собственные обозначения меток, не повторяющиеся при повторных вызовах одной и той же макрокоманды:
delay macro
local point
mov CX,200 point: loop point
endm
Макрос delay создает задержку фиксированной длительности. Если в текст программы включить две макрокоманды delay
delay
delay
to их макрорасширения, подставленные в текст программы, будут выглядеть следующим образом:
'Основы программирования
91
raov loop
mov loop
??0000:
CX.20000 ??0000
CX.20000 ??0001
??0001:
При повторных подстановках макроопределения транслятор заменяет
обозначение метки point на различающиеся обозначения "0000, "0001 и т.д., обеспечивая тем самым правильное выполнение команд циклов и переходов.
Макрокоманды схожи с подпрограммами в том отношении, что в обоих случаях мы описываем некоторый программный фрагмент один раз, а обращаемся к нему многократно, возможно, с передачей различных параметров. Однако эти вычислительные средства различаются как по способу использования, так и по своим возможностям.
Подпрограммы позволяют сократить объем выполнимого файла за счет описания повторяющихся участков программы лишь однажды. При каждом вызове подпрограммы командой call происходит переход на один и тот же фрагмент программы, содержащий подпрограмму, а после выполнения подпрограммы — возврат назад в точку вызова. Текст подпрограммы полностью определяется на этапе ее написания, и изменения в ходе выполнения подпрограммы возможны только за счет передачи ей тех или иных конкретных значений.
Механизм использования макроса иной. Каждая макрокоманда, встретившаяся транслятору в тексте программы, заменяется им на полный текст макроопределения. Если макрокоманда содержит параметры, то в процессе этой замены происходит подстановка параметров в текст макроопределения. Образованное таким образом макрорасширение составляет часть текста программы, неотличимо от остальных предложений программы и не нуждается в каких-либо вызовах. В силу этих обстоятельств макрокоманды оказываются несколько эффективнее подпрограмм по скорости выполнения, особенно, если учесть время, требуемое для подготовки параметров перед вызовом подпрограммы (например, проталкивание их в стек). Вряд ли стоит, однако, проводить такое сравнение. Подпрограммы и макрокоманды имеют различные области применения.
Подпрограммы служат для сокращения объема программы, повышения ее наглядности и упрощения перестройки алгоритма выполнения всего программного комплекса путем изменения состава и порядка вызываемых подпрограмм. При этом активное использование подпрограмм может уменьшить размер всей программы в десятки раз.
Смысл использования макрокоманд совсем иной. Макрокоманды позволяют упростить процесс написания программы и, можно сказать, являются средством автоматизации программирования. При этом язык макрокоманд предоставляет большие возможности по изменению текста макрорасширения в зависимости от указываемых в макрокоманде параметров. Проиллюстрируем эти возможности на простом примере макрокоманды
вывода на экран символа. Такой макрокомандой можно пользоваться в процессе отладки сложных программ, чтобы получать информацию о содержимом любых ячеек памяти. Пример оформлен в виде законченной программы, которая носит чисто демонстрационный характер.
;Пример 2-1. Использование макрокоманды
sym |
macro с ; |
push |
AX ; |
push |
DX ; |
mov |
AH,02h ;< |
mov |
DL,c ;: |
int |
21h ; |
pop |
DX ; |
pop |
AX ;i |
cndm |
?• |
code |
segment |
assume cs:code |
|
main |
proc |
sym |
V ;< |
sym |
ES:0 ;: |
sym |
CS:msg ;: |
lea |
BX,msg+l ;, |
sym |
[BX] ;] |
mov |
AX,40h ;; |
mov |
DS,AX ;i |
sym |
DS:49h ;] |
mov |
AX,4COOh ;: |
int |
21h |
main |
cndp |
msg |
db 'OK' |
code |
ends |
;Имя и формальный аргумент
;Сохраним используемые
;в макроопределении регистры
;функция DOS вывода символа
;3аберем символ
; Вызов DOS
восстановим
;регистры
;Конец макроопределения
;Символ указан непосредственно
; Вывод первого байта PSP
; Вывод первой буквы из nisg
;Адрес второй буквы из nisg
;Вывод второй буквы
; Настроим DS
;на начало памяти
;Вывод номера видеорежима
;3авершение программы
Тексты макроопределений обычно размещаются в самом начале программы, что дает возможность вызывать макрокоманды из любых точек программы. Содержательная часть макроса syni состоит в вызове функции 021i DOS, которая выводит на экран символ из регистра DL. Поскольку макрос использует регистры АХ и DX, они в начале макроса сохраняются в стеке, а перед его завершением восстанавливаются. В качестве параметра макрокоманды можно использовать любое обозначение ассемблера, которое может интерпретироваться, как адрес символа.
Сама программа умышленно построена несколько нестандартным образом. В ней имеется единственный сегмент с текстом программы, в конце которого помещена строка данных (слово 'ОК'). Такое расположение данных допустимо, однако для обращения к ним необходимо использовать замену сегмента (как это сделано в третьей строке программы), так как программный сегмент адресуется через регистр CS. Сегмент стека в Программе отсутствует, что не очень хорошо, но для небольших программ Допустимо. Фактически под стек будет использован самый низ сегмента
92