Question Details

No question body available.

Tags

assembly macros nasm preprocessor

Answers (1)

March 20, 2026 Score: 3 Rep: 3,087 Quality: Medium Completeness: 80%

This is a well-known problem of NASM's preprocessor.

You can't pass a define name to operate on to an mmacro, if the define is possibly defined already, because the mmacro parameter expansion (%1 and friends) will not only expand "once" (var1) but "fully" (to the text that var1 was defined to).

I have worked around this problem by using well-known fixed prefixes to the define names.

In one instance in my macro collection, numdef to create a numeric define, the prefix is . The numdef mmacro detects whether %1 is already defined (usually from the NASM command line) and acts differently depending on this status. The prefix avoids the problem, because %ifdef %1 will expand the %1 text to the variable name without the prefix (which shouldn't be used as a define itself) and then the prefix is prepended without expanding the full %1 to the already-defined content.

In another instance, also in the macro collection, the lframe family of macros uses ? as a prefix. This was chosen primarily to distinguish from non-lframe variable names in our software, however it does have the same advantage for your problem: You can check, define, re-define, or undefine variables with a name like ?%1 if %1 isn't a define itself. I'm using this property in the lleaveundefinelabels mmacro to do something similar to your use case: Pass a list of smacro names (without the ? prefix), then undefine or reset / re-define the smacros (with the ? prefix) to restore their state prior to the starting lframe and the smacro definitions in the lpar, lvar, or lequ mmacros.

If your variable names do actually all start with var (not just as an example) then you could use %undef var%1 so that var is your prefix in the same way I use and ?


I looked through the old NASM bug reports and found one in which I talked about the same problem:

#177 Don't want implicit mmac parameter expansion

2010-09-11

Attached is a simple test case that shows how the consequent introduction of the macro indirection operator %[...] affected existing code. Note that really expanding list1 and list4 here (such as in the db, or for %warning) ends with an "interminable macro recursion" error, which makes macro indirection necessary for such lists. (Anything involving %assign still works without it, because it always expands.) To produce the expected result (a list consisting of "0,1,2,3,4") you additionally have to use list3 (not list2), i.e. put a macro indirection around the smac to be appended too. Otherwise, the smac's name is appended, not the smac's value.

That's all well (besides breaking existing macros), but unfortunately mmacro parameters still are implicitly expanded. I have some mmacros that would ordinarily require their parameters unexpanded and thus currently only work with an ugly workaround. Thus, I request that either mmacro parameters should require explicit macro indirection as all the smacros do now, or there should be an alternative way to access macro parameters without implicit expansion.

I'll also attach a file which shows the basic reason why my mmacros need mmacro parameters without implicit expansion, and how they fail currently with the implicit expansion. My current workaround is shown too.

List creation with the preprocessor: Shows how macro indirection is required. test.asm:

%define list1 0
%define list2 0
%define list3 0
%define list4 0

%macro makelist 1.nolist %assign var %1 %define list1 list1,var %define list2 %[list2],var %define list3 %[list3],%[var] %define list4 list4,%[var] %endmacro

makelist 1 makelist 2 makelist 3 makelist 4

%ifdef TW1 %warning List1: list1 %endif %warning List2: list2 %warning List3: list3 %ifdef TW4 %warning List4: list4 %endif

%ifdef TDB1 db list1 nop nop nop %endif db list2 nop nop nop db list3 nop nop nop %ifdef TDB4 db list4 nop nop nop %endif

Implicit parameter expansion does not allow parameters to be used as smacro names for %define verbatim. mmacroparameters.mac:


%macro def 1.nolist
%define %1 38
%endmacro

%macro def2 1.nolist %define %1 38 %endmacro

def SMAC ; works as expected (unless SMAC already defined) def SMAC ; does not work, because the mmacro implicitly fully expands %1

def2 SMAC ; this is the workaround, which works (even multiple times) def2 SMAC ; but defines the smacro SMAC, not SMAC


This last example exactly addresses the same problem as your question, to operate on a possibly already defined smacro passed to an mmacro.