- •Введение Основные определения
- •Системы счисления Основные определения
- •Двоичная, восьмеричная и шестнадцатеричная системы счисления
- •Смешанные системы счисления
- •Перевод чисел из одной системы счисления в другую
- •Арифметические действия в системах счисления с основанием, отличным от 10
- •Двоично-восьмеричные и двоично-шестнадцатеричные преобразования
- •Обратный и дополнительный коды и их применение в операциях с отрицательными числами
- •Сложение и вычитание чисел со знаком в дополнительном коде
- •Архитектура персонального компьютера История развития вычислительной техники
- •Основные термины и определения
- •Функциональная структура компьютера
- •Архитектура микропроцессора
- •Регистры общего назначения и сегментные регистры
- •Управляющие регистры Регистр cr0.
- •Память компьютера
- •Структура программы на языке Ассемблера Формат кодирования в языке Ассемблера
- •Структура программы на ассемблере
- •Простейшая программа в ос Windows
- •Типы и форматы данных в ассемблере
- •Базовая система команд микропроцессора ia-32
- •Операнды языка ассемблер
- •Стандартные директивы сегментации
- •Макрокоманды
- •Процедуры (функции)
- •Организация интерфейса с процедурой
- •Возврат результата из процедуры
- •Связь ассемблера с языками высокого уровня
- •Обработка прерываний
- •Создание исполняемого файла
- •Отладка программы
- •Математический сопроцессор
- •Представление чисел с плавающей точкой в разрядной сетке вычислительной машины
- •Архитектура сопроцессора
- •Система команд сопроцессора
- •Команды передачи данных
- •Команды загрузки констант
- •Команды сравнения данных
- •Арифметические команды
- •Команды управления математическим сопроцессором
- •Пример программы с использованием команд сопроцессора
- •Сложные типы данных Структуры
- •Объединения
- •Программирование для windows
- •Основы программирования в ос Windows
- •Консольные приложения Windows
- •Работа с файлами в системе Windows
- •Вывод чисел в консоль
- •Оконные (каркасные) приложения Windows
- •Графика в оконных приложениях Windows
- •Ресурсы в Windows-приложениях
- •Приложение 1
Макрокоманды
При программировании достаточно серьезной задачи, появляются повторяющиеся участки кода. Они могут быть небольшими, а могут занимать и достаточно много места. В последнем случае эти фрагменты будут существенно затруднять чтение текста программы, снижать ее наглядность, усложнять отладку и служить неисчерпаемым источником ошибок. В языке ассемблера есть несколько средств, решающих проблему дублирования участков программного кода. К ним относятся:
макроассемблер;
механизм процедур;
механизм прерываний.
Макрокоманда представляет собой строку, содержащую некоторое символическое имя — имя макрокоманды, предназначенную для того, чтобы быть замещенной одной или несколькими другими строками. Имя макрокоманды может сопровождаться параметрами. Для написания макрокоманды вначале необходимо задать ее шаблон-описание, который называют макроопределением.
Синтаксис макроопределения следующий:
имя_макрокоманды macro список_формальных_аргументов
тело макроопределения
endm
Макроопределение обрабатывается транслятором особым образом. Для того чтобы использовать описанное макроопределение в нужном месте программы, оно должно быть активизировано с помощью макрокоманды указанием следующей синтаксической конструкции:
имя_макрокоманды список_фактических_аргументов
Результатом применения данной синтаксической конструкции в исходном тексте программы будет ее замещение строками из конструкции тела макроопределения. Но это не простая замена. Обычно макрокоманда содержит некоторый список аргументов — список_фактических_аргументов, которыми корректируется макроопределение. Места в теле макроопределения, которые будут замещаться фактическими аргументами из макрокоманды, обозначаются с помощью так называемых формальных аргументов. Таким образом, в результате применения макрокоманды в программе формальные аргументы в макроопределении замещаются соответствующими фактическими аргументами; в этом и заключается учет контекста. Процесс такого замещения называется макрогенерацией, а результатом этого процесса является макрорасширение.
Макрокоманды в ассемблере схожи с директивой #define в языке Си, но, в отличие от нее, могут принимать аргументы.
Есть три варианта размещения макроопределений:
в начале исходного текста программы, до кода и данных с тем, чтобы не ухудшать читаемость программы. Этот вариант следует применять в случаях, если определяемые макрокоманды актуальны только в пределах одной этой программы;
в отдельном файле. Этот вариант подходит при работе над несколькими программами одной проблемной области. Чтобы сделать доступными эти макроопределения в конкретной программе, необходимо в начале исходного текста этой программы записать директиву include имя_файла, например:
.586
.model flat, stdcall
include show.inc ;сюда вставляется текст файла show.inc
в макробиблиотеке. Универсальные макрокоманды, которые используются практически во всех программах целесообразно записать в так называемую макробиблиотеку. Сделать актуальными макрокоманды из этой библиотеки можно также с помощью директивы include. Недостаток этого и предыдущего способов в том, что в исходный текст программы включаются абсолютно все макроопределения. Для исправления ситуации можно использовать директиву purge, в качестве операндов которой через запятую перечисляются имена макрокоманд, которые не должны включаться в текст программы. К примеру:
include iomac.inc
purge outstr,exit
В данном случае в исходный текст программы перед началом трансляции MASM вместо строки include iomac.inc вставит строки из файла iomac.inc. Но вставленный текст будет отличаться от оригинала тем, что в нем будут отсутствовать макроопределения outstr и exit.
Каждый фактический аргумент представляет собой строку символов, для формирования которой применяются следующие правила:
Строка может состоять:
из последовательности символов без пробелов, точек, запятых, точек с запятой;
из последовательности любых символов, заключенных в угловые скобки: <...>. В этой последовательности можно указывать как пробелы, так и точки, запятые, точки с запятыми.
Для того чтобы указать, что некоторый символ внутри строки, представляющей фактический параметр, является собственно символом, а не чем-то иным, например, некоторым разделителем или ограничивающей скобкой, применяется специальный оператор «!». Этот оператор ставится непосредственно перед описанным выше символом, и его действие эквивалентно заключению данного символа в угловые скобки.
Если требуется вычисление в строке некоторого константного выражения, то в начале этого выражения нужно поставить знак %:
%константное_выражение — значение константное_выражение вычисляется и подставляется в текстовом виде в соответствии с текущей системой счисления.
В процессе генерации макрорасширения транслятор ассемблера ищет в тексте тела макроопределения последовательности символов, совпадающие с теми последовательностями символов, из которых состоят формальные параметры. После обнаружения такого совпадения формальный параметр из тела макроопределения замещается соответствующим фактическим параметром из макрокоманды. Этот процесс называется подстановкой аргументов. В общем случае список формальных аргументов содержит не только перечисление формальных элементов через запятую, но и некоторую дополнительную информацию. Полный синтаксис формального аргумента следующий:
имя_формального_аргумента[: тип]
где тип может принимать значения:
REQ – требуется обязательное явное задание фактического аргумента при вызове макрокоманды;
=<любая_строка> — если аргумент при вызове макрокоманды не задан, то в соответствующие места в макрорасширении будет вставлено значение по умолчанию, соответствующее значению любая_строка. Символы, входящие в любая_строка, должны быть заключены в угловые скобки.
Но не всегда ассемблер может распознать в теле макроопределения формальный аргумент. Это, например, может произойти в случае, когда он является частью некоторого идентификатора. В этом случае последовательность символов формального аргумента отделяют от остального контекста с помощью специального символа &. Этот прием часто используется для задания модифицируемых идентификаторов и кодов операций. Например,
.686p
.model flat, stdcall
def_table macro t:REQ, len:=<1>
tabl_&t d&t len dup(5)
endm
.data
def_table d, 10
def_table b
.code
main proc
mov al, [tabl_b]
mov ah, [tabl_b+1]
mov ebx, [tabl_d]
ret
main endp
end main
После трансляции текста программы, содержащего строки секции данных, получится
def_table d, 10 ;tabl_d dd 10 dup(5)
def_table b ;tabl_b db 1 dup(5)
Заметим, что строка программы mov ah, [tabl_b+1] поместит в ah число отличное от 5, поскольку память для tabl_b распределена только под 1 элемент массива длиной 1 байт со значением 5.
Символ & можно применять и для распознавания формального аргумента в строке, заключенной в кавычки "".
Если тело макроопределения содержит метку или имя в директиве резервирования и инициализации данных, и в программе данная макрокоманда вызывается несколько раз, то в процессе макрогенерации возникнет ситуация, когда в программе один идентификатор будет определен несколько раз, что, естественно, будет распознано транслятором как ошибка. Для выхода из подобной ситуации применяют директиву local, которая имеет следующий синтаксис:
local список_идентификаторов
Эту директиву необходимо задавать непосредственно за заголовком макроопределения. Результатом работы этой директивы будет генерация в каждом экземпляре макрорасширения уникальных имен для всех идентификаторов, перечисленных в список_идентификаторов. Эти уникальные имена имеют вид ??хххх, где хххх — шестнадцатеричное число. Для первого идентификатора в первом экземпляре макрорасширения хххх=0000, для второго — хххх=0001 и т. д. Контроль за правильностью размещения и использования этих уникальных имен берет на себя ассемблер.
Для примера использования макроопределений рассмотрим программу вывода имени в диалоговое окно.
.686P
.MODEL FLAT, STDCALL
PrintName macro Name
local STR1, STR2, METKA
jmp METKA
STR1 DB "Программа",0
STR2 DB "Меня зовут: &Name ",0
METKA:
PUSH 0
PUSH OFFSET STR1
PUSH OFFSET STR2
PUSH 0
CALL MessageBoxA@16
endm
Init macro
EXTERN MessageBoxA@16:NEAR
endm
Init
.CODE
START:
PrintName <Лена>
PrintName <Таня>
PrintName <Алёша>
RET
END START
При использовании макроопределений код программы становится более читаемым.
Функционально макроопределения похожи на процедуры. Сходство их в том, что и те, и другие достаточно один раз где-то описать, а затем вызывать их многократно специальным образом. Различия макроопределений и процедур в зависимости от целевой установки можно рассматривать и как достоинства, и как недостатки:
в отличие от процедуры, текст которой неизменен, макроопределение в процессе макрогенерации может меняться в соответствии с набором фактических параметров. При этом коррекции могут подвергаться как операнды команд, так и сами команды. Процедуры в этом отношении менее гибки;
при каждом вызове макрокоманды ее текст в виде макрорасширения вставляется в программу. При вызове процедуры микропроцессор осуществляет передачу управления на начало процедуры, находящейся в некоторой области памяти в одном экземпляре. Код в этом случае получается более компактным, хотя быстродействие несколько снижается за счет необходимости осуществления переходов.