- •Системное программирование на макроассемблере masm32
- •«Системное программирование» (часть 1)
- •Вступление
- •1Организация среды исполнения для масм
- •1.1Цель работы
- •1.2 Теоретические сведения
- •If errorlevel 0 команда2
- •If errorlevel 0 goto метка
- •1.3Выполнение работы
- •1.4Состав отчета по работе
- •1.5Контрольные вопросы
- •2.2.2Состав пакета масм
- •2.2.3Центр масм – редактор Quick Editor
- •2.3Выполнение работы
- •2.4Состав отчета по работе
- •2.5Контрольные вопросы
- •3Высокоуровневый интерфейс языка масм
- •3.1Цель работы
- •3.2 Теоретические сведения
- •3.2.1Процедуры и макросы в ассемблере
- •3.2.2Синтаксис высокого уровня масм
- •3.2.3Макрос invoke
- •3.3Выполнение работы
- •4.2.2Потоки вывода и ввода
- •4.2.3Вывод и ввод в консольных приложениях
- •4.3Выполнение работы
- •4.4Состав отчета по работе
- •4.5Контрольные вопросы
- •5Ввод и вывод в ассемблерных приложениях с графическим интерфейсом
- •5.1Цель работы
- •5.2Теоретические сведения
- •5.3Выполнение работы
- •6.3.1Фрейм кода (области 1-5)
- •6.3.2Фрейм дампа памяти (области 9,10 и 11)
- •6.3.3Фрейм регистров процессора (области 6, 7 и 8)
- •6.3.4Фрейм стека (области 12, 13 и 14)
- •6.4Выполнение работы
- •6.5Состав отчета по работе
- •6.6Контрольные вопросы
- •Приложение а Префиксы «венгерской» нотации типов данных WinApi
- •Рекомендованная литература
3.2.1Процедуры и макросы в ассемблере
Понятие процедур и функций (П и Ф) вам должно быть хорошо знакомо по базовому курсу программирования.
Напомним, что в программировании процедура – это именованный участок кода программы, который можно вызывать по его имени. Вызов процедуры синтаксически выглядит как обычный оператор. Вызов процедуры порождает в стеке программы кадр параметров процедуры, который освобождается после ее завершения, управление при этом передается оператору, следующему за операторов вызова процедуры.
Функция — это специализированный вариант процедуры. Всё, сказанное выше про процедуры, справедливо и для функций. Но функция пишется так, чтобы в точку вызова обязательно возвращать некоторое одиночное значение. Поэтому вызов функции выглядит как операнд правой части оператора присваивания или как параметр другого вызова. При завершении выполнения функции в точке ее вызова остается возвращаемое значение и продолжается выполнение оператора, в который был включен вызов функции.
Вызовы П и Ф (равно как и возвраты из них) поддерживаются аппаратно процессором в период исполнения программы (рантайм период).
Замечания о терминологии. Сказанное выше о П и Ф относится не к конкретном языку программирования, а, скорее, к общетеоретическим представлениям об этих алгоритмических абстракциях. В языке Паскаль представление о П и Ф наиболее близко к описанному теоретическому, в Си нет понятия «процедура», но зато есть возможность вызывать функции «по-процедурному», записывая их как оператор. Во всех ассемблерах, напротив, нет понятия «функция», синтаксически описываются только процедуры. Но зато всегда есть возможность организовать возвращаемое значение из процедуры, и традиционно это делается через регистр EAX. Поэтому в дальнейшем, при анализе исходных ассемблерных текстов программ всякое упоминание терминов «процедура» или «функция» подразумевает на самом деле вызов ассемблерных процедур и ничего иного.
Совсем другой сущностью являются ассемблерные макросы.
Они были придуманы программистами для облегчения повторного написания больших и/или сложных участков исходного текста программ. Так что можно определить макрос как именованный участок текста программы («тело» макроса) , который можно вставлять в текст «вызывающей его» программы, упоминая его имя. Тогда имя макроса в программе заменяется его телом, и это действие называют макрорасширением. Таким образом, при ручном написании программы разработчик за счет макросов здорово экономит усилия, но после всех макрорасширений текст программы имеет объем, больший , нежели тот, что программист написал своими руками.
Из сказанного понятно, что вся работа с макросами происходит на этапах написания исходного текста (определение макросов и вставка их «вызовов» в нужные места программы) и компиляции (именно тут компилятор сначала выполняет макрорасширения, а потом полученный текст компилирует в объектный машинный код).
Сила макропрограммирования состоит в том, что по сути применение макросов означает замену маленьких текстов на большие тексты. Никакого контроля типов тут не производится. Это же относится и к передаче параметров в макросы.
Рассмотрим простейший пример. Архитектура процессора не позволяет производить прямое присваивание значения одной переменной памяти другой переменной. То есть оператор mov Var1, Var2 (по смыслу это Var1 = Var2;) компилятором опознается как ошибочный. Обход этого неудобства прост. Определим макрос
m2m MACRO M1, M2 ; заголовок макроса
push M2 ;; тело макроса
pop M1
ENDM ; завершитель макроса
И если его вызов имеет вид m2m Var1, Var2, то в текст программы вместо него буде вставлено:
push Var2
pop Var1
что приводит к желаемому результату. Текстовые соответствия легко установить самостоятельно.
Замечание о комментариях. При макрорасширениях в текст программы вставляется всё, что содержится в теле макроса, в том числе и комментарии (они начинаются с символа «;» и идут до конца строки). Но, если комментарий начинается с «;;», то он в макрорасширение не переносится.
«Вызовы» макросов выглядят похоже на вызовы процедур в Паскале:
CallModalDialog hInstance,0,dlgproc,NULL
Но обратите внимание, что после имени макроса CallModalDialog список передаваемых ему параметров в скобки не заключается.
«Вызовы» макросов, строго говоря, вызовами не являются, хотя так и говорят. Правильнее считать такие записи «точками вставки» тел макросов. Термин «вызов» точно относится к П и Ф, но не к макросам.