Appendice D.   Le macro dell'assembly AT&T

Nell'ultimo esempio dell'appendice C ci sono parti del codice che si ripetono in modo identico; ciò avviene nella parte iniziale per l'input dei due valori da moltiplicare.

Una cosa simile è però il più possibile da evitare, sia per eliminare la noia di dover scrivere più volte le stesse istruzioni, sia per non correre il rischio di dimenticare qualche gruppo di istruzioni nel momento che si apportano delle modifiche.

A tale proposito si può allora ricorrere alle macro che sono gruppi di istruzioni che si scrivono una volta sola e si «richiamano» dove occorre.

Chiariamo subito che il concetto di «richiamo» di una macro non ha niente a che vedere con quello analogo relativo ai sottoprogrammi; quando l'assemblatore incontra il riferimento ad una macro non fa altro che copiare fisicamente le relative istruzioni in quel punto del programma (si parla anche di «espansione» della macro).

Per questo motivo in una macro non possono esserci delle etichette, in quanto altrimenti comparirebbero più volte nel sorgente «espanso», causando errore da parte dell'assemblatore.

Nell'assembly con sintassi AT&T le macro si dichiarano, solitamente all'inizio del sorgente, con la direttiva .macro seguita da un nome, e si chiudono con la direttiva .endm; il richiamo si effettua invece scrivendo semplicemente il nome.

Usando le macro nell'esempio dell'appendice C si evita di scrivere due volte buona parte delle istruzioni relative alle fasi di input (purtroppo non tutte, perché, come detto, le parti contenenti le etichette dei cicli non possono essere inserite nelle macro), ottenendo il listato seguente.(1)

/*
Programma:     io-macro.s
Autore:        FF
Data:          gg/mm/aaaa
Descrizione:   Acquisizione e stampa con macro
*/
.bss
stringa:   .string ""                         # stringa per input
.data
invito:    .string "Immettere un valore: "    # senza a capo  
msgout:    .string "Risultato del prodotto: " # senza a capo
lun:       .long   0                          # lunghezza input
val1:      .byte   0                          # primo valore di input
val2:      .byte   0                          # secondo valore di input
strout:    .string "     \n"                  # stringa per output (5 car)
.text
.globl _start
.macro messaggio_invito
   movl $4, %eax
   movl $1, %ebx
   movl $invito, %ecx   
   movl $21, %edx
   int  $0x80
.endm   
.macro lettura_stringa
   movl $3, %eax
   movl $0, %ebx
   movl $stringa, %ecx   
   movl $4, %edx       # 4 = lun. max stringa (3 + 1 per invio)          
   int  $0x80
   movl %eax, (lun)    # lunghezza effettiva immessa
.endm
.macro prepara_ciclo
   mov $0, %esi
   xorw %ax, %ax
   movw $0xa, %bx
   movl (lun), %ecx
   decl %ecx            # per non contare anche invio
.endm
.macro corpo_ciclo
   mulw %bx             # esegue %ax = %ax * %bx ( = 10)
   movb stringa(%esi), %dl
   subb $0x30, %dl
   addb %dl, %al
   adcb $0, %ah
   inc  %esi
.endm   
_start:
// input primo valore
   messaggio_invito
   lettura_stringa
// converti primo input
   prepara_ciclo
ciclo1:
   corpo_ciclo
   loopl ciclo1
   movb %al, (val1)
// input secondo valore   
   messaggio_invito
   lettura_stringa
// converti secondo input
   prepara_ciclo
ciclo2:
   corpo_ciclo
   loopl ciclo2
   movb %al, (val2)
// elaborazione
   movb (val1), %al
   mulb (val2)         # il risultato in %ax
// converte valore del ris in stringa
   movw $0xa, %bx    
   movl $4, %esi
converti:   
   xor %dx, %dx
   divw %bx             # divido ris per 10 il resto va in %dl
   addb $0x30, %dl      # sommo 48 per avere cod. ascii
   movb %dl, strout(%esi)
   dec %esi
   orw %ax, %ax        # se quoziente %ax zero - fine
   jne converti
// stampa a video messaggio preliminare
   movl $4, %eax
   movl $1, %ebx
   movl $msgout, %ecx   
   movl $25, %edx
   int  $0x80
// stampa a video della stringa del risultato
   movl $4, %eax
   movl $1, %ebx
   movl $strout, %ecx   
   movl $6, %edx
   int  $0x80
fine:
   movl $1, %eax
   int  $0x80

1) una copia di questo file, dovrebbe essere disponibile anche qui: <allegati/programmi-assembly/io-macro.s>.