Низкоуровневое программирование для Дzenствующих
| Вид материала | Документы |
- Низкоуровневое программирование, 108.99kb.
- Курс является базовым как для изучения других математических дисциплин, так и для более, 36.89kb.
- 1 Обобщенное программирование. Обобщенное программирование это еще одна парадигма программирования,, 55.18kb.
- Введение в линейное программирование линейное программирование (ЛП), 139.72kb.
- Учебно-методический комплекс для студентов заочного обучения специальности Прикладная, 63.23kb.
- Аттестационное тестирование в сфере профессионального образования, 72.49kb.
- Лекции по дисциплине «Социальное моделирование и программирование», 44.69kb.
- Программа дисциплины Линейное программирование Семестр, 17.93kb.
- Программа дисциплины "Программирование" для направления, 488.76kb.
- Рабочая программа по дисциплине Программирование на языке высокого уровня для специальности, 182.97kb.
III. Макромир MASM
Макрос представляет собой именованный участок исходного текста программы, который обрабатывается компилятором каждый раз в том месте, где вызывается макрос.
| -= Подробней =- |
| Пример: Создайте небольшой модуль с именем macro.asm. И напишите в нём несколько строчек .386 .data .code echo Hello!!! echo Ты должен увидеть во время компиляции end Так действует директива echo. С помощью неё можно подсмотреть значения переменных. Mycount = 1 %echo @CatStr(%Mycount) Если вы не знаете, как это работает, не волнуйтесь, обо всём будет рассказано. А пока несколько экспериментов: Напишите: MyMacro macro reg dec reg endm .code mov eax,5 MyMacro reg MyMacro reg Взгляните на код программы под отладчиком. Что у вас получилось? Что будет, если вы измените текст внутри макроопределения? Теперь напишите: MyVar = 1 MyMacro macro MyVar = MyVar+1 %echo MyVar = @CatStr(%MyVar) endm MyMacro MyMacro MyMacro MyMacro Каким будет вывод на экран во время компиляции? |
С этого момента вам придётся различать в ассемблере ML две подсистемы: препроцессор и компилятор. Если компилятор переводит код мнемоник в машинный код, вычисляет значения меток и смещений, то препроцессор занимается вычислением выражений этапа компиляции, и что самое важное – процессом раскрытия макросов.
Подобно многим объектам мира программирования макро имеет два состояния в исходном тексте: определение, и использование.
Таким образом, мы будем иметь дело с определением макроса (макроопределением), и его вызовом (использованием макроса).
Макроопределением называется любой текст, заключённый между ключевыми словами:
MacroName macro paramlist
макроопределение
endm
При каждом вызове макро, а именно:
…
MacroName
или
mov eax, MacroName()
…
Будет анализироваться и исполнятся текст, заключённый в макро. Именно так это и реализовано в ML. Поскольку текст в макроопределении не компилируется, то естественно, вы не увидите сообщений об ошибке, даже если с точки зрения ассемблера эта ошибка будет в теле макроопределения. Однако ошибка появится при попытке вызова макроопределения, её могут выдать вам, либо сам препроцессор, либо компилятор, если текст, сгенерированный препроцессором является неверным с точки зрения компилятора.
Каждый раз, когда препроцессор встречает макроопределение, он помещает его имя в специальную таблицу, и копирует его тело к себе в память (это не обязательно именно так, но вам должна быть понятна суть). Встретив макроопределение, препроцессор не проверяет, а есть ли макро с таким же именем. Это значит, что макро можно переопределять.
MyMacro macro
echo Это макро 1
endm
MyMacro macro
echo Это макро 2
endm
MyMacro
Вы можете самостоятельно удалять макроопределения, из памяти препроцессора используя директиву PURGE:
PURGE macroname
После этой директивы макро с именем macroname перестаёт существовать. И вы освобождаете память для компилятора.
Конечно же, использование макро было бы бесполезным, если бы макро не имел формальных параметров. При вызове макро, препроцессор заменяет все имена формальных параметров их непосредственными значениями в теле макроопределения. Список формальных параметров разделяется запятой, и может иметь вид:
MyMacro macro param0, param1:REQ, param2 := <0>,param3:VARARG
Здесь:
Param0 – пример определения параметра.
Param1:REQ – ключевое слово REQ указывает на то, что этот параметр обязательный. То есть, если он не будет указан, вы получите ошибку этапа компиляции.
Param2:=<0> – пример параметра, который имеет значение по умолчанию. То есть если этот параметр не будет указан при вызове макро, он будет равен этому значению.
| Заметьте, что при вызове макро параметр может быть не определён: MyMacro param1,,param3 Значение второго параметра неопределенно. |
Param3:vararg – становится именем параметра, который воспринимает всё остальное как строку. При этом запятые между параметрами так же попадают в строку, а значит число параметров макроса в принципе неограниченно.
| Ограничениям являются особенности архитектуры компилятора. Так, например, компилятор имеет ограничение на длину логической строки, которая равна 512 байтам. |
Конечно же, после параметра с директивой vararg не возможно объявить другие параметры.
| Обратите внимание, что если при определении формального параметра в макро нет директивы – он считается необязательным параметром. Более подробно о вызове макро и значении параметров я расскажу далее. |
| -= Подробней =- |
| Пример: Так что же происходит с формальными параметрами? Посмотрите, как работает препроцессор ML: MyMacro macro param1,param2 mov eax, param1 mov ebx, param2 endm MyMacro var, 123 1. Препроцессор берёт текст внутри макро, и заменяет в нём все слова param1, param2, на их значения: « mov eax, var mov ebx, 123 » 2. Полученный текст вставляет на место вызова макро, и передаёт компилятору. Вот интересно, а что будет если: MyMacro macro param1,param2 MyMacro2 macro param1 mov eax, param1 mov ebx, param2 endm endm MyMacro var, 123 |
Можно различать два вида макро – макропроцедуры и макрофункции.
| В официальном руководстве MASM различается четыре основных вида макро. Text macros – текстовый макрос Macro procedures – макро-процедура Repeat blocks – блок повторения Macro functions – макро-функция Однако автор считает, что разделение макро на два вида – лучше систематизирует материал, и отражает суть темы. |
Макрофункции в отличие от макропроцедур могут возвращать результат, и получают список формальных параметров в скобках, подобно функциям в С. Например:
mov eax,@GetModuleHandle()
Заметьте, что к макрофункции невозможно обратится как к макро, вы всегда должны заключать формальные параметры макрофункции между «()», иначе MASM не будет распознавать её как макрофункцию:
mov eax,@GetModuleHandle
error A2148: invalid symbol type in expression
: @GetModuleHandle
Препроцессор MASM анализирует текст макроопределения на наличие директивы exitm, и помечает макрос как макрофункцию.
Ключевое слово exitm
| Таким образом, окончательно будем считать, что макро, не имеющие в себе вызова директивы exitm – это макропроцедуры, а макро, которые имеют exitm – это макрофункции. |
;#######################################################
@GetModuleHandle macro
Invoke GetModuleHandle,0
exitm
endm
.code
; Это макрофункция так нельзя
@GetModuleHandle ;;– ошибка
; Так можно
@GetModuleHandle()
;########################################################
@GetModuleHandle macro
Invoke GetModuleHandle,0
endm
.code
; Это макрос. Так правильно
@GetModuleHandle
; Так можно, но всё равно это вызывает ошибку ?
; warning A4006: too many arguments in macro call
@GetModuleHandle()
; Это макро, а не макрофункция так нельзя!!!
mov eax,@GetModuleHandle
; И так нельзя
mov eax,@GetModuleHandle()
;########################################################
| Что касается директивы endm, которая заканчивает каждое макроопределение, в руководстве написано, что при помощи неё так же можно указать возвращаемый параметр: endm Однако на практике это не так. ? Очень странно, хотя об этом чётко написано в руководстве. |
Заметьте, что макропроцедура может быть вызвана только в начале строки:
@GetModuleHandle
;; Но не так:
mov eax,@MyMacro
Макрофункция может быть вызвана в любых выражениях:
;; Так:
mov eax,@GetModuleHandle()
;; И так:
@FunMacro()
;; И так:
@GetModuleHandle() EQU eax
0>0>
