Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.
Не претендую на создание чего-то нового и гениального, но макросы довольно полезные. Часть из того, что я сделал, уже делали другие. Тем не менее, большинство макросов придумано и сделано мною с нуля, остальной код переписан по-своему
Вот эти макросы (полный вариант, только заголовки):
Код:
;############################################
;## ##
;## -= EXTRA MACROSES (FULL EDITION) =- ##
;## МАКРОСЫ ДЛЯ MASM/TASM (16/32) ##
;## Полный вариант ##
;## [ v1.00 :: 09.01.2017 ] ##
;## ##
;## (c) 2017 by Jin X (jin.x@sources.ru) ##
;## xk7.ru/p/a/i ##
;## ##
;############################################
xmacro_ver = 100h ; версия данного файла (word: старший байт - целая часть, младший - дробная)
;-------------------------------------------------------------------------------
@ equ <offset>
$b equ <byte ptr>
$w equ <word ptr>
$d equ <dword ptr>
$f equ <fword ptr>
$q equ <qword ptr>
$t equ <tbyte ptr>
$s equ <short>
$n equ <near>
$f equ <far>
; Выполнение инструкций/директив/макросов, заданных одной строкой
_ macro p1, p2, p3, p4, p5, p6, p7, p8, p9, p10
;-------------------------------------------------------------------------------
;-- УСЛОВНЫЕ МАКРОСЫ -----------------------------------------------------------
;-------------------------------------------------------------------------------
; Если cond, исполнить do1; иначе do0
ifel macro cond:req, do1, do0
ifdo equ <ifel>
ifn equ <ife>
; Если НЕ cond, исполнить do1; иначе do0
ifnel macro cond:req, do1, do0
ifeel equ <ifnel>
; Если cond1, исполнить do1; иначе если cond2, исполнить do2; иначе do0
ifelif macro cond1:req, do1, cond2:req, do2, do0
; ifdef id (если идентификатор определён), исполнить do1; иначе do0
ifdefel macro id:req, do1, do0
; ifndef id (если идентификатор НЕ определён), исполнить do1; иначе do0
ifndefel macro id:req, do1, do0
; ifb exp (если выражение пустое), исполнить do1; иначе do0
ifbel macro exp, do1, do0
; Если выражение exp пустое или состоит из пробелов, исполнить do1; иначе do0
ifbbel macro exp, do1, do0
; ifnb exp (если выражение НЕпустое), исполнить do1; иначе do0
ifnbel macro exp, do1, do0
; Если выражение exp НЕпустое и НЕ состоит из пробелов, исполнить do1; иначе do0
ifnbbel macro exp, do1, do0
; ifidn exp1, exp2 (если значения совпадают С учётом регистра символов), исполнить do1; иначе do0
ifidnel macro exp1:req, exp2:req, do1, do0
; ifidni cond (если значения совпадают БЕЗ учёта регистра символов), исполнить do1; иначе do0
ifidniel macro exp1:req, exp2:req, do1, do0
; ifidn exp1, exp2 (если значения различаются С учётом регистра символов), исполнить do1; иначе do0
ifdifel macro exp1:req, exp2:req, do1, do0
; ifidni cond (если значения различаются БЕЗ учёта регистра символов), исполнить do1; иначе do0
ifdifiel macro exp1:req, exp2:req, do1, do0
; Если cond1 или cond2 (условие cond2 проверяется только в том случае, если cond1 не выполнилось), исполнить do1; иначе do0
iforel macro cond1:req, cond2:req, do1, do0
; Если cond1 и cond2 (условие cond2 проверяется только в том случае, если cond1 выполнилось), исполнить do1; иначе do0
ifandel macro cond1:req, cond2:req, do1, do0
; Аналогично ifel, но условие подставляется слитно с if, например: ifelx <def debug>, <int 3>, nop
ifelx macro cond:req, do1, do0
ifx equ <ifelx>
; Аналогично ifnel, но условие подставляется слитно с if, например: ifnelx <def debug>, nop, <int 3>
ifnelx macro cond:req, do1, do0
ifeelx equ <ifnelx>
; Аналогично ifelif, но условия подставляются слитно с if, например: ifelifx <def debug>, <int 3>, <idn <spec>, <stosb>>, stosb, nop
ifelifx macro cond1:req, do1, cond2:req, do2, do0
; Аналогично iforel, но условия подставляются слитно с if
iforelx macro cond1:req, cond2:req, do1, do0
; Аналогично ifandel, но условия подставляются слитно с if
ifandelx macro cond1:req, cond2:req, do1, do0
;-------------------------------------------------------------------------------
; Установить значение var = true, если выполняется хотя бы одно из условий cX; иначе установить var = false
setifor macro var:req, c1:req, c2:req, c3, c4, c5, c6, c7, c8
; Установить значение var = true, если выполняются все условия cX; иначе установить var = false
setifand macro var:req, c1:req, c2:req, c3, c4, c5, c6, c7, c8
; Установить значение var1 = true, а var2 = false, если выполняется условие cond (которые подставляются слитно с if); иначе установить var1 = false, а var2 = true
setifelx macro cond:req, var1, var2
; Установить значение var = true, если выполняется хотя бы одно из условий cX (которые подставляются слитно с if); иначе установить var = false
setiforx macro var:req, c1:req, c2:req, c3, c4, c5, c6, c7, c8
; Установить значение var = true, если выполняются все условия cX (которые подставляются слитно с if); иначе установить var = false
setifandx macro var:req, c1:req, c2:req, c3, c4, c5, c6, c7, c8
;-------------------------------------------------------------------------------
; Если идентификатор value определён, установить значение const = value, иначе установить значение _const = defval
defdef macro const:req, value:req, defval:req
; Если константа const определена, установить значение _const = const, иначе установить значение _const = defval
_defdef macro const:req, defval:req
;-------------------------------------------------------------------------------
; Вывод сообщения txt об ошибке (одинаковый синтаксис для MASM и TASM)
?err macro txt
; Вывод сообщения txt об ошибке при выполнении условия cond
?errif macro cond:req, txt
; Аналогично ?errif, но условие подставляется слитно с if, например: ?errifx <ndef ok>, <Error message>
?errifx macro cond:req, txt
;-------------------------------------------------------------------------------
; Следующие идентификаторы определены для более удобного использования вложенных условных директив компиляции, например:
; if abc
; ?if def
; ??if ghi
; ...
; ??endif
; ?endif
; endif
?if equ <if>
?ifdef equ <ifdef>
?ifndef equ <ifndef>
?ifb equ <ifb>
?ifnb equ <ifnb>
?ifidn equ <ifidn>
?ifidni equ <ifidni>
?ifdif equ <ifdif>
?ifdifi equ <ifdifi>
?if1 equ <if1>
?if2 equ <if2>
?else equ <else>
?elseif equ <elseif>
?elseifdef equ <elseifdef>
?elseifndef equ <elseifndef>
?elseifb equ <elseifb>
?elseifnb equ <elseifnb>
?elseifidn equ <elseifidn>
?elseifidni equ <elseifidni>
?elseifdif equ <elseifdif>
?elseifdifi equ <elseifdifi>
?elseif1 equ <elseif1>
?elseif2 equ <elseif2>
?endif equ <endif>
??if equ <if>
??ifdef equ <ifdef>
??ifndef equ <ifndef>
??ifb equ <ifb>
??ifnb equ <ifnb>
??ifidn equ <ifidn>
??ifidni equ <ifidni>
??ifdif equ <ifdif>
??ifdifi equ <ifdifi>
??if1 equ <if1>
??if2 equ <if2>
??else equ <else>
??elseif equ <elseif>
??elseifdef equ <elseifdef>
??elseifndef equ <elseifndef>
??elseifb equ <elseifb>
??elseifnb equ <elseifnb>
??elseifidn equ <elseifidn>
??elseifidni equ <elseifidni>
??elseifdif equ <elseifdif>
??elseifdifi equ <elseifdifi>
??elseif1 equ <elseif1>
??elseif2 equ <elseif2>
??endif equ <endif>
Продолжение следует (весь код не помещается в одно сообщение)...
Полный код см. в аттаче
asm7x
;===============================================================================
;-------------------------------------------------------------------------------
;-- ОПРЕДЕЛЕНИЕ ЗНАЧЕНИЙ КОНСТАНТ ----------------------------------------------
;-------------------------------------------------------------------------------
false = 0
true = not false
; Установка isTASM = true и isMASM = false, если текущий компилятор - TASM, иначе наоборот
setifelx <def ??Version>, isTASM, isMASM
; Установка идентификатора @32Bit (32-битный режим) в MASM
ifdo isMASM, <@32Bit = (@WordSize eq 4)>
; Разрешены ли инструкции/регистры процессоров (в TASM @Cpu = 0 в режиме .586)
@186 = (@Cpu and 2) or (@Cpu eq 0)
@286 = (@Cpu and 3) or (@Cpu eq 0)
@386 = (@Cpu and 8) or (@Cpu eq 0)
@486 = (@Cpu and 10h) or (@Cpu eq 0)
@586 = (@Cpu and 20h) or (@Cpu eq 0)
@686 = @Cpu and 40h
; Включить режим оптимизации и использования локальных меток, начинающихся на @@
ifdo isTASM, <_ smart, locals>
; Проверка требуемой версии данного include-файла, заданной через константу xmacro_ver_req или xmac_ver_req
ifx <def xmacro_ver_req>, <?errif <xmacro_ver_req gt xmacro_ver>, <Version of 'xmacro.inc' is less than required :(>>
ifx <def xmac_ver_req>, <?errif <xmac_ver_req gt xmacro_ver>, <Version of 'xmacro.inc' is less than required :(>>
;===============================================================================
;-------------------------------------------------------------------------------
;-- МАКРОСЫ, ОПИСЫВАЮЩИЕ ИЛИ УПРОЩАЮЩИЕ ИСПОЛЬЗОВАНИЕ ИНСТРУКЦИЙ ПРОЦЕССОРА ----
;-------------------------------------------------------------------------------
; Недокументированная инструкция salc (setalc)
salc macro
setalc equ <salc>
; Инструкция rdtsc
if isTASM
rdtsc macro
endif
;-------------------------------------------------------------------------------
; Прыжок через 1 байт; если указан 1-байтовый регистр reg, его значение изменяется, но сохраняются флаги, иначе изменяются флаги, но сохраняются регистры
jmp_1 macro reg
; Прыжок через 2 байта; если указан 2-байтовый регистр reg, его значение изменяется, но сохраняются флаги, иначе изменяются флаги, но сохраняются регистры
jmp_2 macro reg
; Прыжок через 4 байта; если указан 4-байтовый регистр reg, его значение изменяется, но сохраняются флаги, иначе изменяются флаги, но сохраняются регистры
jmp_4 macro reg
jmps equ <jmp short>
jmpn equ <jmp near>
; jmp far seg:ofs (если seg:ofs не указан, генерируется только 1 байт опкода)
jmpf macro seg, ofs
; call far seg:ofs (если seg:ofs не указан, генерируется только 1 байт опкода)
callf macro seg, ofs
; call int (pushf + callf)
calli macro seg, ofs
; Определяет nop'ы в количестве cnt штук
nops macro cnt:req
;-------------------------------------------------------------------------------
; Выполнение присвоения значения регистру с помощью mov или xor (если src = 0)
; Чтобы передать в параметре src константу, необходимо поставить перед ней % (movx ax,%val), иначе xor не выполнится
movx macro dst:req, src:req
; Выполнение сравнение регистра с помощью cmp или test (если src = 0)
; Чтобы передать в параметре src константу, необходимо поставить перед ней % (cmpx ax,%val), иначе test не выполнится
cmpx macro dst:req, src:req
; Выполнение присвоения op = val через стек
movp macro op:req, val:req
; Выполнение присвоения op = val через временный регистр temp (по умолчанию ax; например, movt ds,@data или movt es,0A000h,dx)
movt macro op:req, val:req, temp:=<ax>
; Обмен значениями op1 и op2 через стек
; Макрос не проверяет соответствие разрядности операндов !!!
xchgp macro op1:req, op2:req
; Сохранение регистров в одну строку: push ax bx cx dx
pushx macro regs:vararg
; Восстановление регистров в одну строку: pop dx cx bx ax
popx macro regs:vararg
; Восстановление регистров в обратном порядке: popb ax bx cx dx
popb macro regs:vararg
; Запись ip (адрес следующей строки) в op, используя стек
; Макрос не проверяет соответствие разрядности кода и операнда !!!
getip macro op:req
; Запись флагов в op, используя стек
; Макрос не проверяет соответствие разрядности флагов и операнда !!!
getf macro op:req
; Запись слова флагов в op, используя стек
; Макрос не проверяет соответствие разрядности флагов и операнда !!!
getfw macro op:req
; Запись двойного слова флагов в op, используя стек
; Макрос не проверяет соответствие разрядности флагов и операнда !!!
getfd macro op:req
; Запись op в регистр флагов, используя стек
; Макрос не проверяет соответствие разрядности флагов и операнда !!!
setf macro op:req
; Запись слова op в регистр флагов, используя стек
; Макрос не проверяет соответствие разрядности флагов и операнда !!!
setfw macro op:req
; Запись двойного слова op в регистр флагов, используя стек
; Макрос не проверяет соответствие разрядности флагов и операнда !!!
setfd macro op:req
; Установка флага ZF=ZR=1 (влияет и на другие флаги: CF=0, PF=1, AF=0, SF=0, OF=0)
stz macro
; Получить абсолютное (положительное) значение op (минимальное отрицательное значение остаётся неизменным, при этом SF=1, OF=1, иначе SF=0, SF=0)
absx macro op:req
; Получить абсолютное (положительное) значение регистра al (значение -128 остаётся неизменным, при этом SF=1, OF=1, иначе SF=0, SF=0)
; Работает быстрее, чем absx; при этом: ah = 0 и CF=0, если исходное значение al положительное, иначе ah = -1, CF=1
absal macro
; Получить абсолютное (положительное) значение регистра ax (значение -32768 остаётся неизменным, при этом SF=1, OF=1, иначе SF=0, SF=0)
; Работает быстрее, чем absx; при этом: dx = 0 и CF=0, если исходное значение ax положительное, иначе dx = -1, CF=1
absax macro
; Получить абсолютное (положительное) значение регистра ax (значение -2147483648 остаётся неизменным, при этом SF=1, OF=1, иначе SF=0, SF=0)
; Работает быстрее, чем absx; при этом: edx = 0 и CF=0, если исходное значение eax положительное, иначе edx = -1, CF=1
abseax macro
;-------------------------------------------------------------------------------
; lodsb/lodsw/lodsd с использованием сегментов, отличных от ds:
; lodsb_seg, lodsw_seg, lodsd_seg с названием сегментного регистра в качестве аргумента (например, lodsb_seg es)
; lodsb_es, lodsb_cs, lodsb_ss, lodsb_fs, lodsb_gs,
; lodsw_es, lodsw_cs, lodsw_ss, lodsw_fs, lodsw_gs,
; lodsd_es, lodsd_cs, lodsd_ss, lodsd_fs, lodsd_gs без аргументов
; outsb/outsw/outsd с использованием сегментов, отличных от ds:
; outsb_seg, outsw_seg, outsd_seg с названием сегментного регистра в качестве аргумента (например, outsb_seg es)
; outsb_es, outsb_cs, outsb_ss, outsb_fs, outsb_gs,
; outsw_es, outsw_cs, outsw_ss, outsw_fs, outsw_gs,
; outsd_es, outsd_cs, outsd_ss, outsd_fs, outsd_gs без аргументов
;-------------------------------------------------------------------------------
; Вызов прерывания no с установкой регистров reg1 = val1, reg2 = val2...
; Если указан только reg1 без val1, то значение reg1 заносится в ah (или ax, если число > 0FFh)
; Например: intfn 16h,0 или intfn 15h,ah,86h,cx,0,dx,10000
intfn macro no:req, reg1:req, val1, reg2, val2, reg3, val3, reg4, val4, reg5, val5
Также имеется краткий вариант, в котором отсутствует примерно половина этих макросов (специфических).
-= ИСТОРИЯ ВЕРСИЙ =-
v1.01 (26.01.2017)
[+] Добавлены идентификаторы $ax, $bx, $cx, $dx, $si, $di, $bp, $sp, $word, j$cxz, cwdq$, pushf$, popf$.
[+] Добавлен псевдоним ifndo.[*] В макросы defdef и _defdef добавлен дополнительный параметр, позволяющий делать проверку ещё одной константы.[*] В макросы ?err, ?errif, ?errifx добавлен дополнительный параметр, позволяющий добавлять к сообщению 3 восклицательных знака.[*] Исправлен баг в макросе movt.
v1.00 (09.01.2017)
[!] Самая первая версия.
xmac.inc:
Код:
-= ИСТОРИЯ ВЕРСИЙ =-
v1.01 (26.01.2017)
[+] Добавлены идентификаторы $ax, $bx, $cx, $dx, $si, $di, $bp, $sp, $word, j$cxz, cwdq$, pushf$, popf$.
[+] Добавлены макросы iforel, ifandel, iforelx, ifandelx (из полной редакции).
[+] Добавлен псевдоним ifndo.[*] В макросы defdef и _defdef добавлен дополнительный параметр, позволяющий делать проверку ещё одной константы.[*] В макросы ?err, ?errif, ?errifx добавлен дополнительный параметр, позволяющий добавлять к сообщению 3 восклицательных знака.
[-] Из данной редакции удалены макросы movt, movp, xchgp, calli, outsXXX, intfn.
[-] Из данной редакции удалена проверка xmacro_ver_req (поскольку это могло явиться причиной сообщения об ошибке при включении обеих редакций).
v1.00 (09.01.2017)
[!] Самая первая версия.
-= ИСТОРИЯ ВЕРСИЙ =-
v1.02 (01.02.2017)
[+] Добавлен макрос loopx, генерирующий dec + jnz (jns).
[*] (В ПОЛНОЙ РЕДАКЦИИ) В макросе movt значение параметра temp по умолчанию изменено с ax на $ax.
[*] В макросе ?err для добавления ' !!!' в конец сообщения параметр exclam должен быть <> 0 (до этого достаточно было задать любое значение, в т.ч. 0).
p.s. В секции [code][/code] на форуме почему-то строки, начинающиеся на [*], не переносятся, а продолжают предыдущую строку. Приходится ставить между ними пустую строку, что в предыдущих сообщениях я не делал (поэтому некоторые изменения между версиями 1.00 и 1.01 можно упустить из вида).
Последний раз редактировалось 7in; 01.02.2017 в 13:44.
-= ИСТОРИЯ ВЕРСИЙ =-
v1.03 (08.03.2017)
[+] Добавлены макросы doif, doifn и doifx, работающие аналогично ifdo, ifndo и ifx, но позволяющие указывать параметр do без <угловых скобок> (ifdo, ifndo и ifx сохранены для обратной совместимости).
[+] Добавлены макросы doifset, doifnset, doifsete и ifsetel, проверяющие и определение идентификатора, и его значение.
[+] Добавлены макросы aligndata, aligncode, alignd, alignc, alignds, aligncs.
[+] Добавлен идентификатор dw$, определяющий dw или dd в зависимости от разрядности кода.
[+] Добавлены идентификаторы proto = procdesc и invoke = call для TASM.
[+] По умолчанию данный include-файл включает директивы locals и smart для TASM; если нужно их отключить, установите константу xnodir = 1 ДО включения файла.
[+] Требуемую версию данного include-файла можно теперь проверять не только через константу xmacro_ver_req, но и через макрос check_xmacro_ver (после подключения файла), что исключает возможность опечатки.
[*] Сделаны некоторые перестановки и изменения в макросах (например, ifel переписан без использования вложенных макросов, что должно увеличить скорость и упростить обнаружение ошибок в коде).
(изменения приведены для полной версии xmacro.inc).
-= ИСТОРИЯ ВЕРСИЙ =-
v1.04 (10.03.2017)
[!] Обнаружен баг, который появился вместе с макросами doifXXX в предыдущей версии (1.03), и я пока не знаю как его исправить (если знаете, напишите мне) !!!
MASM выдаёт ошибку при совместном использовании макросов doifXXX и _ с параметрами, содержащими запятые в угловых скобках (например, doif x, _ <mov ax,bx>), параметр
макроса _ разделяется на несколько, будто угловых скобок нет (данный пример работает аналогично doif x, _ mov ax,bx; т.е. макрос _ получает 2 параметра: mov ax и bx).
Пока я вижу только два варианта решения данной проблемы:
1. использовать макросы ifXXX, заключая также и макрос _ в угловые скобки (ifdo x, <_ <mov ax,bx>>) - это ЛУЧШИЙ ВАРИАНТ,
2. использовать двойные угловые скобки (doif x, _ <<mov ax,bx>>), однако этот вариант НЕ работает в TASM, что плохо, учитывая, что данный include-файл является универсальным для TASM и MASM.
p.s. Эта проблема проявляется у макросов doifXXX не только с макросом _, но и с другими, принимающими несколько параметров, которые могут содержать запятые (например, doif x, ?errif <hello, world>).
[+] Добавлены макросы ifnsetel и ifseteel (в дополнение к ifsetel) и псевдонимы для всех 3-х макросов: ifset, ifnset и ifsete.
[+] Добавлен макрос fastnops и константа fastnopsprefix, а макрос aligncode получил дополнительный параметр prefix и использует (так же, как и alignc и aligncs) nop'ы с префиксами.
[*] Исправлена ошибка в макросе ifsetel, возникающая при использовании угловых скобок в do1 и/или do0.
[*] Макрос _ расширен до 16 параметров.
[*] Макрос ifelif переписан без использования вложенных макросов, в других макросах doif-подобные макросы заменены на ifdo-подобные.
(изменения приведены для полной редакции xmacro.inc, в сокращённой xmac.inc их чуть меньше).