Uma macro-instrução é um sinônimo para um grupo de instruções que pode ser usado como uma instrução ao longo do código-fonte. O uso de macros facilita a especificação de trechos repetitivos de código, que podem ser invocados pelo programador como um única linha no programa. Por esse motivo, diversos montadores apresentam extensões com funcionalidades para a definição e utilização de macros.
Na sua forma mais simples, uma macro é simplesmente uma abreviatura para um grupo de instruções. A forma geral de definição de uma macro é
nome MACRO [argumentos] corpo ENDM
A pseudo-instrução MACRO marca o início da definição da macro-instrução. Toda macro tem um nome, especificado como o rótulo da pseudo-instrução e que será utilizado pelo programador para invocar a macro, e um corpo, que será usado pelo macro-montador para substituir o nome usado pelo programador pela seqüência de instruções nele especificados. A pseudo-instrução ENDM marca o fim da definição.
Uma macro pode opcionalmente receber argumentos, que serão usados para adaptar a expansão do corpo da macro. Assim, a seqüência de instruções especificadas no corpo da macro podem ser parametrizadas pelos argumentos. Os parâmetros formais na definição de uma macro-instrução são precedidos pelo símbolo &.
A definição de TOLOWER, exemplo apresentado abaixo, cria uma macro-instrução com dois parâmetros. O primeiro, &IN, é interpretado como a referência a um endereço de memória de um byte cujo conteúdo será copiado para o registrador D0, onde o sexto bit será setado. O conteúdo resultante será copiado para a posição indicada pelo segundo argumento, &OUT:
TOLOWER MACRO &IN,&OUT MOVE.B &IN,D0 ORI.B 32,D0 MOVE.B D0,&OUT ENDM
Uma vez que uma macro esteja definida, seu nome pode ser utilizado como se fosse uma operação válida do montador. A associação entre os argumentos da invocação da macro e os parâmetros formais da definição é feita pela posição da variável na declaração e invocação, assim como ocorre em subrotinas nas linguagens de alto nível.
Considerando a definição acima, o uso da macro TOLOWER dar-se-ia como em
SIZE EQU 5 CHARS_I DC.B 'EA876' CHARS_O DS.B SIZE PROG001 MOVEA.L #CHARS_I,A0 MOVEA.L #CHARS_O,A1 MOVE.W #SIZE,D0 LOOP TOLOWER (A0),(A1) ADDA.W #1,A0 ADDA.W #1,A1 DBF D0,LOOP RTS END PROG001
Após passar pela etapa de processamento de macros, o código acima seria expandido para o seguinte código assembly:
SIZE EQU 5 CHARS_I DC.B 'EA876' CHARS_O DS.B SIZE PROG001 MOVEA.L #CHARS_I,A0 MOVEA.L #CHARS_O,A1 MOVE.W #SIZE,D0 LOOP MOVE.B (A0),D0 ORI.B 32,D0 MOVE.B D0,(A1) ADDA.W #1,A0 ADDA.W #1,A1 DBF D0,LOOP RTS END PROG001
Outra facilidade geralmente associada a macro-instruções é a possibilidade de definir expansões condicionais de trechos de código. Para tanto, a pseudo-instrução AIF é definida. Assim, é possível definir trechos da definição da macro que poderão não estar incluídos na respectiva expansão.
O formato dessa pseudo instrução é
AIF cond .mrotonde cond é a condição que deve ser avaliada e .mrot é o rótulo na macro onde a expansão deverá continuar se a condição for verdade; caso contrário, a expansão continua na linha seguinte. A condição envolve tipicamente operadores relacionais de comparação de strings, aqui denotados EQ e NE para expressar ``igual a'' e ``diferente de'', respctivamente. O rótulo de macro é sempre iniciado por um ponto, uma forma de diferenciá-lo dos rótulos que serão incluídos no código expandido.
Para ilustrar esse conceito, considere novamente a definição da macro TOLOWER, que usa o registrador D0 para realizar a operação desejada. Se um dos argumentos para a macro for esse registrador, uma das instruções MOVE não deve ser incluída na sua expansão. Usando AIF, uma nova definição para essa macro que considera essa possibilidade é
TOLOWER MACRO &IN,&OUT AIF (&IN EQ 'D0') .PULA MOVE.B &IN,D0 .PULA ORI.L 32,D0 AIF (&OUT EQ 'D0') .FIM MOVE.L D0,&OUT .FIM ENDM
No Apêndice C.7 apresenta-se o pré-processador C, uma facilidade para definição de macros associada a uma linguagem de alto nível.