Статьи по Assembler

       

Макросы first и second


Автор: Бордачев Андрей Юльевич (glareboa@mail.ru)

С другими интересами автора вы можете познакомиться здесь.

Комментарии: assembler.ru

Макросы - это мощный, удобный и гибкий инструмент. По сути дела, это целый язык программирования, имеющий единственную цель - совершенствование языка ассемблера.

И он прекрасно справляется с этой задачей. Возможны и существуют технические решения, построенные исключительно на макросредствах, превращающие язык ассемблера в полноценный структурированный язык (то есть содержащий полностью функциональный набор структурных операторов if-else-endif, while-next, do-while, continue, break и т.д.) или даже в некоторое довольно близкое подобие объектно-ориентированного языка. При этом все достоинства ассемблерного программирования сохраняются.

Здесь приведены два варианта макросов, решающих одну и ту же задачу - групповую загрузку в стек и восстановление из стека регистров и переменных. Основная особенность этих макросов - сохранение очередности упоминания параметров в загружающем и восстанавливающем вызовах. Например:

pushr eax,ecx,edi,vasya,edx,petya;...popr eax,ecx,edi,vasya,edx,petya

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

Эту же задачу решает пара макросов @push и @pop, описанных в файле @struct.inc для проекта MyCall.

Такое разнообразие демонстрирует нам гибкость макроязыка и гамму возможных приемов, которые он дает.

;#################################################################### ;Вариант FIRST

;//////////////////////////////////////////////////////////////////// ;Макрос pushr

;В процессе макрорасширения (встраивания макроса в тело программы ;во время ее компиляции) проверяется, сколько параметров из 8 ;максимально возможных указал программист, и формируется столько ;последовательных команд push, сколько нужно. Очевидно, что ;максимальное число параметров макроса без труда может быть увеличено ;настолько, насколько нужно. ;==================================================================== pushr MACRO R1,R2,R3,R4,R5,R6,R7,R8 IFNB <R1> push R1 ENDIF IFNB <R2> push R2 ENDIF IFNB <R3> push R3 ENDIF IFNB <R4> push R4 ENDIF IFNB <R5> push R5 ENDIF IFNB <R6> push R6 ENDIF IFNB <R7> push R7 ENDIF IFNB <R8> push R8 ENDIF ENDM ;==================================================================== ;Макрос popr




;Работает так же, как и pushr, за одним исключением: очередность проверки ;обратная. Это позволяет программисту не менять очередности упоминания ;параметров при использовании макроса в программе. ;==================================================================== popr MACRO R1,R2,R3,R4,R5,R6,R7,R8 IFNB <R8> pop R8 ENDIF IFNB <R7> pop R7 ENDIF IFNB <R6> pop R6 ENDIF IFNB <R5> pop R5 ENDIF IFNB <R4> pop R4 ENDIF IFNB <R3> pop R3 ENDIF IFNB <R2> pop R2 ENDIF IFNB <R1> pop R1 ENDIF ENDM ;#################################################################### ;Вариант SECOND

;//////////////////////////////////////////////////////////////////// ;Вспомогательные макросы

;==================================================================== makevar MACRO name,ext,val ;формирует имя операнда &name&ext EQU

ENDM

makevarn MACRO name,ext ;формирует команду push push &name&ext ENDM

makevarm MACRO name,ext ;формирует команду pop pop &name&ext ENDM ;==================================================================== ;Макрос pushr

;В отличие от варианта First, макрос производит опрос параметров в цикле, ;построенном на директиве IRP. Благодаря этому больше не существует ;ограничения на число параметров. ;==================================================================== pushr MACRO args ;синтаксис указания параметров: <eax,ebx,ecx,...> fcnt=0 ;создание списка операндов IRP s,&args fcnt=fcnt+1 makevar t1,%fcnt,s ENDM fcnt=0 ;создание набора команд push операнд

IRP s,&args fcnt=fcnt+1 makevarn t1,%fcnt ENDM ENDM ;==================================================================== ;Макрос popr

;==================================================================== popr MACRO args ;синтаксис указания параметров: <eax,ebx,ecx,...> fcnt=0 ;создание списка операндов IRP s,&args fcnt=fcnt+1 makevar t2,%fcnt,s ENDM IRP s,&args ;создание набора команд pop операнд

makevarm t2,%fcnt fcnt=fcnt-1 ;знак "-" обеспечивает обратный порядок следования команд! ENDM ENDM



Эта статья не ставит задач изучения макроязыка. Если вы хотите узнать, почему в варианте Second параметры надо брать в угловые скобки, что означает амперсанд в записи &args и знак процента в записи %fcnt, каковы возможности директив IFNB и IRP,- воспользуйтесь документацией на ваш компилятор, и немножко поэкспериментируйте. Будьте уверены: ваши усилия многократно окупятся повышением производительности труда.

Читайте также другие статьи Андрея Бордачева: О формате PCX и Как изменить способности компьютера.

 обсуждение статьи 

Нам прислал письмо Argus (Мельников Василий Юрьевич, vasily@geolog.kmv.ru, http://www.halyava.ru/club477), в котором справедливо напоминает, что макросы в макроассемблере обладают замечательным свойством рекурсии, позволяющим создавать компактные и изящные программные конструкции. В частности, обсуждаемые в этой статье макросы pushr и popr в рекурсивной версии, предложенной Argus'ом, будут выглядеть так:

;#################################################################### ;Вариант THIRD

;//////////////////////////////////////////////////////////////////// ;Макрос pushr

;Рекурсия обеспечивается тем, что в теле макроса pushr присутствует ;вызов этого же макроса, но без первого аргумента. Легко видеть, что ;рекурсивные итерации макрорасширения будут происходить до тех пор, ;пока не исчерпается весь действительный список аргументов. ;==================================================================== pushr MACRO R1,R2,R3,R4,R5,R6,R7,R8 IFNB <R1> push R1 pushr R2,R3,R4,R5,R6,R7,R8 ENDIF endm ;==================================================================== ;Макрос popr

;Видно, что этот макрос также рекурсивный, но количество итераций ;макрорасширения определяется в нем не числом фактических аргументов, ;как в pushr, а числом формальных параметров (здесь - 8), пока все ;они, сдвигаясь вправо, не заменятся заглушкой dummy. При этом ;реальный код команд pop будет сформирован только для параметров, ;которым соответствуют действительные фактические аргументы. ;==================================================================== popr MACRO R1,R2,R3,R4,R5,R6,R7,R8 IFNB <R8> IFIDN <R8>,<dummy> EXITM ENDIF pop R8 ENDIF popr dummy,R1,R2,R3,R4,R5,R6,R7 ENDM

Рекомендуем обратить внимание на суть заглушки dummy. Это - не константа и не переменная, она не требует объявления или описания. Здесь мы наблюдаем прием, характерный в ассемблере исключительно для макросов, поскольку они способны работать с литералами (текстовыми фрагментами), а dummy здесь - именно литерал. (Естественно, вместо слова dummy можно применить любую другую комбинацию символов). Он используется в формировании макровызовов, а не макрорасширений, то есть участвует в формировании исходного текста программы, а не исполняемого кода.


Содержание раздела