Search code examples
assemblymasmmasm32

MASM - Differences between procedures and macros


I was wondering what are the differences between macros and procedures in MASM ?

Is there a difference with what the program will do or how the assembler will assemble my code, if I call a macro instead of a procedure that do the exact same thing ?

If no, I might want to understand why do macros exist ?

Thanks.


Solution

  • A macro is just text replacement. So any time you "call" a macro, that call will be replaced by the full contents of the macro at compile-time. When you call a procedure, there's typically only one instance of that procedure, so you'll branch to a different place in the program.

    Consider the following example:

    .586
    .model flat, stdcall
    option casemap :none
    
    .code
    
    ; Multiply the argument by 3/2
    Mul3_2 MACRO reg
        lea reg,[reg + reg*2]
        shr reg,1
    ENDM
    
    ; Multiply the argument by 3/2 and return in eax
    Mul3_2Proc PROC arg:DWORD
        mov eax,[arg]
        lea eax,[eax + eax*2]
        shr eax,1
        ret
    Mul3_2Proc ENDP
    
    main PROC
        Mul3_2 eax
        Mul3_2 ebx
    
        invoke Mul3_2Proc,eax    ; Equivalent to push eax / call Mul3_2Proc
        invoke Mul3_2Proc,ebx   
    main ENDP
    
    END main
    

    If we let MASM's preprocessor expand our macro we get this:

    .586
    .model flat, stdcall
    option casemap :none
    
    .code
    
    ; Multiply the argument by 3/2 and return in eax
    Mul3_2Proc PROC arg:DWORD
        mov eax,[arg]
        lea eax,[eax + eax*2]
        shr eax,1
        ret
    Mul3_2Proc ENDP
    
    main PROC
        lea eax,[eax + eax*2]
        shr eax,1
        lea ebx,[ebx + ebx*2]
        shr ebx,1
    
        invoke Mul3_2Proc,eax    ; Equivalent to push eax / call Mul3_2Proc
        invoke Mul3_2Proc,ebx
    main ENDP
    
    END main
    

    As you can see, at the two places where we used the Mul3_2 macro, the contents of that macro has been inserted, with reg replaced by whatever we passed as the argument to the macro. The macro itself no longer exists in our code, because it has served its purpose.

    On the other hand, the two occurrences where we invoked the Mul3_2Proc procedure remain unchanged. At runtime there will be a jump (call) from each of those places to Mul3_2Proc, which in turn will return back to the call site when it is done.