I would like to learn a way of specifying the size of a general-register argument.
for instance:
%macro lalala 1
mov word [buff], %1w
%endmacro
it works only for r8
-r15
, but I would like to use this macro for them all rax
-rdx
,rdi
,rsi
,r8
-r15
.
How should I go about it? Is there a built-in mapping?
I put together two NASM preprocessor macros which combined allow you to take any register name (of any size) as input, along with a size, and convert that into the appropriate register name of the given size. The altreg
register names that I mentioned (documented in the NASM manual here) are not used by these macros at all. Compatibility for inputting r0
to r7
could be added without much effort though. Here are the full macros:
%imacro regindexdef 2.nolist
%push
%define _%1 256
%assign %$size 0
%assign %$exit 0
%rep 5
%ifn %$exit
%if %$size == 0
%define %$regnames "ah ch dh bh "
%elif %$size == 1
%define %$regnames "al cl dl bl spl bpl sil dil r8b r9b r10br11br12br13br14br15b"
%elif %$size == 2
%define %$regnames "ax cx dx bx sp bp si di r8w r9w r10wr11wr12wr13wr14wr15w"
%elif %$size == 4
%define %$regnames "eax ecx edx ebx esp ebp esi edi r8d r9d r10dr11dr12dr13dr14dr15d"
%elif %$size == 8
%define %$regnames "rax rcx rdx rbx rsp rbp rsi rdi r8 r9 r10 r11 r12 r13 r14 r15 "
%endif
%assign %$index 0
%rep 16
%ifn %$exit
%substr %$reg %$regnames %$index * 4 + 1, 4
%deftok %$reg %$reg
%ifnempty %$reg
%ifidni %$reg, %2
%assign _%1 %$index
%assign %$exit 1
%exitrep
%endif
%endif
%endif
%assign %$index %$index + 1
%endrep
%if %$exit
%exitrep
%endif
%assign %$size !%$size + %$size * 2
%endif
%endrep
%ifn %$exit
%error Invalid register name: %2
%endif
%pop
%endmacro
%imacro regsizedef 3.nolist
%push
%define _%1 invalidregister
%assign %$size 0
%assign %$highbyte 0
%ifidni %2, byte
%assign %$size 1
%elifidni %2, highbyte
%assign %$size 1
%assign %$highbyte 1
%elifidni %2, word
%assign %$size 2
%elifidni %2, dword
%assign %$size 4
%elifidni %2, qword
%assign %$size 8
%else
%assign %$size %2
%endif
%if %$size == 0
%error Invalid register size: %2
%else
%ifnnum %3
%error Invalid register number: %3
%elif (%3) >= 16
%error Invalid register number: %3
%elif (%3) < 0
%error Invalid register number: %3
%else
%if %$size == 1 && %$highbyte
%define %$regnames "ah ch dh bh "
%elif %$size == 1
%define %$regnames "al cl dl bl spl bpl sil dil r8b r9b r10br11br12br13br14br15b"
%elif %$size == 2
%define %$regnames "ax cx dx bx sp bp si di r8w r9w r10wr11wr12wr13wr14wr15w"
%elif %$size == 4
%define %$regnames "eax ecx edx ebx esp ebp esi edi r8d r9d r10dr11dr12dr13dr14dr15d"
%elif %$size == 8
%define %$regnames "rax rcx rdx rbx rsp rbp rsi rdi r8 r9 r10 r11 r12 r13 r14 r15 "
%else
%define %$regnames ""
%endif
%substr %$reg %$regnames (%3) * 4 + 1, 4
%deftok %$reg %$reg
%ifempty %$reg
%error Invalid register type selected
%else
%xdefine _%1 %$reg
%endif
%endif
%endif
%pop
%endmacro
Here are a few valid examples of using the macros:
bits 64
regsizedef REG, 2, 0
mov _REG, 1234h
; mov to ax
regsizedef REG, 4, 0
mov _REG, 12345678h
; mov to eax
regsizedef REG, qword, 0
%warning REG=>>_REG<<
; rax
regsizedef REG, highbyte, 2
%warning REG=>>_REG<<
; dh
regindexdef INDEX, rdi
regsizedef REG, word, _INDEX
mov _REG, 1234h
; mov to di
regindexdef INDEX, cx
regsizedef REG, qword, _INDEX
%warning REG=>>_REG<< INDEX=>>_INDEX<<
; reg rcx, index 1
I also uploaded a file including the macros, the valid test cases, and a few invalid test cases: https://ulukai.org/ecm/20201207.txt (needs lmacros from https://hg.ulukai.org/ecm/lmacros/)
Here's how to use the macros with your example:
%macro lalala 1
regindexdef INDEX, %1
regsizedef REG, word, _INDEX
mov word [buff], _REG
%endmacro