Warm tip: This article is reproduced from serverfault.com, please click

How to specify the register size (b/w/d) in a macro

发布于 2020-12-07 11:19:17

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?

Questioner
dronte7
Viewed
0
ecm 2020-12-08 02:45:06

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