Linguaggio assembly: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
Nessun oggetto della modifica
 
(101 versioni intermedie di 49 utenti non mostrate)
Riga 1:
{{Nota disambigua||Assembly (disambigua)|Assembly}}
{{NN|informatica|febbraio 2024}}
{{Linguaggio di programmazione
|nome = Assembly
|immagine = Motorola 6800 Assembly Language.png
|didascalia = Codice in Assembly per processore Motorola 680068000
|autore =
|data = risale ai primi [[computer a programma memorizzato]]
|versione =
|utilizzo = linguaggio general-purpose
|paradigmi = programmazione genericaimperativa
|tipizzazione = nessuna
|specifiche =
Riga 18 ⟶ 19:
|sito_web =
}}
Il '''linguaggio assembly''', detto anche '''linguaggio assemblativo'''<ref>{{cita|adc||Tanenbaum 2006}}</ref> o '''linguaggio assemblatore'''<ref>{{treccani|linguaggio-assemblatore|linguaggio assemblatore}}</ref>, è, tra i [[linguaggio di programmazione|linguaggi di programmazione]], quello più vicino al [[linguaggio macchina]] vero e proprio, pur essendo [[Linguaggio macchina#Assembly|differente]] rispetto a quest'ultimo. Erroneamente viene spesso chiamato "[[assembler]]", ma quest'ultimo termine identifica solo il [[programma (informatica)|programma]] "assemblatore" che converte il linguaggio assembly in linguaggio macchina.
 
Un '''linguaggio assembly''' (detto anche '''linguaggio assemblativo'''<ref>{{cita|Tanenbaum 2006||adc}}.</ref> o '''linguaggio assemblatore'''<ref>{{treccani|linguaggio-assemblatore|linguaggio assemblatore}}</ref> o semplicemente '''assembly''') è un [[linguaggio di programmazione]] molto simile ai [[linguaggio macchina|linguaggi macchina]]. Si differenzia da questi ultimi principalmente per l'utilizzo di identificatori mnemonici, valori simbolici e altre caratteristiche che lo rendono più agevole da scrivere e leggere per gli esseri umani.
==Caratteristiche generali dell'assembly==
L'assembly ha lo scopo generale di consentire al programmatore di ignorare il formato [[bit (informatica)|binario]] del linguaggio macchina. Ogni [[codice operativo]] del linguaggio macchina viene sostituito, nell'assembly, da una sequenza di caratteri che lo rappresenta in forma ''mnemonica''; per esempio, il codice operativo per la [[addizione|somma]] potrebbe essere trascritto come<code>ADD</code>e quello per il [[GOTO|salto]] come<code>JMP</code>. In secondo luogo, i dati e gli [[indirizzi di memoria]] manipolati dal programma possono essere scritti, in assembly, nella [[sistema di numerazione|base numerica]] più consona al momento: [[Sistema numerico esadecimale|esadecimale]], [[Sistema numerico binario|binaria]], [[Sistema numerico decimale|decimale]], [[Sistema numerico ottale|ottale]] ma anche in forma simbolica, utilizzando stringhe di testo (identificatori). Il programma assembly risulta in questo modo relativamente più [[leggibilità|leggibile]] di quello in linguaggio macchina, con il quale mantiene però un totale (o quasi totale) [[isomorfismo]]. Il programma scritto in assembly non può essere eseguito direttamente dal processore; esso deve essere tradotto nel linguaggio macchina (binario) corrispondente, usando un programma [[compilatore]] detto [[assembler]].
 
Erroneamente viene spesso chiamato ''[[assembler]]'', ma quest'ultimo termine identifica solo l'[[applicazione (informatica)|applicativo]] che converte i [[programma (informatica)|programmi]] scritti in assembly nell'equivalente in linguaggio macchina.
==Non univocità dell'assembly==
 
In generale ogni istruzione in linguaggio assembly corrisponde univocamente a un'istruzione in linguaggio macchina. Difatti quest'ultime sono semplicemente stringhe di bit, lunghe uno o più [[byte]], che in assembly vengono rappresentate sotto forma di [[testo|testo strutturato]] facilmente comprensibile agli umani. Per questo motivo è possibile vedere il linguaggio assembly come un'implementazione ''human-friendly'' dell{{'}}''[[instruction set]]'' di un dato processore, a cui sarà necessariamente legato.
 
== Descrizione ==
=== Scopo ===
L'assembly ha lo scopo generale di consentire al programmatore di ignorare il formato [[bit (informatica)|binario]] del linguaggio macchina. Ogni [[codice operativo]] del linguaggio macchina viene sostituito, nell'assembly, da una sequenza di caratteri che lo rappresenta in forma ''mnemonica''; per esempio, il codice operativo per la [[addizione|somma]] potrebbe essere trascritto come <code>ADD</code> e quello per il [[GOTO|salto]] come <code>JMP</code>. In secondo luogo, i dati e gli [[indirizzi di memoria]] manipolati dal programma possono essere scritti, in assembly, nella [[sistema di numerazione|base numerica]] più consona al momento: [[Sistema numerico esadecimale|esadecimale]], [[Sistema numerico binario|binaria]], [[Sistema numerico decimale|decimale]], [[Sistema numerico ottale|ottale]] ma anche in forma simbolica, utilizzando stringhe di testo (identificatori). Il programma assembly risulta in questo modo relativamente più [[leggibilità|leggibile]] di quello in linguaggio macchina, con il quale mantiene però un totale (o quasi totale) [[isomorfismo]]. Il programma scritto in assembly non può essere eseguito direttamente dal processore; esso deve essere tradotto nel linguaggio macchina (binario) corrispondente, usando un programma [[compilatore]] detto [[assembler]].
 
=== Portabilità ===
A causa di questa "vicinanza" all'hardware, non esiste un unico linguaggio assembly. Al contrario, ogni [[CPU]] o famiglia di CPU ha un suo proprio assembly, diverso dagli altri. Ad esempio, sono linguaggi assembly ben diversi quelli per i processori [[Intel]] [[Architettura X86|x86]], per i [[Motorola 68000]] e per i [[Dec Alpha]]. Questo significa che conoscere un certo linguaggio assembly significa saper scrivere programmi solo su una determinata CPU o famiglia di CPU. Passare ad altre CPU però è relativamente facile, perché molti meccanismi sono analoghi o del tutto identici, quindi spesso il passaggio si limita all'apprendimento di nuovi codici mnemonici, nuove modalità di indirizzamento ed altre varie peculiarità del nuovo processore.
 
Molto meno facile è invece [[Portabilità|portare]] un programma scritto in assembly su macchine con processori diversi o con architetture diverse: quasi sempre significa dover riscrivere il programma da cima a fondo, perché i linguaggi assembly dipendono completamente dalla piattaforma per cui sono stati scritti. Molti compilatori assembly supportano sistemi di [[Macro (informatica)|macro]] che potrebbero essere impiegati per ovviare in parte a questo problema, ma si tratta di una soluzione poco efficace.
 
=== Usabilità ===
Inoltre l'assembly non offre alcun "[[Type checking|controllo sui tipi]]" (non esiste alcunché di vagamente simile al concetto di "[[Tipo di dato|tipo]]" nella programmazione ''low-level''), ma lascia al programmatore la responsabilità di occuparsi di ogni singolo dettaglio della gestione della macchina e richiede molta disciplina e un esteso lavoro di commento per non scrivere codice che risulti assolutamente illeggibile (ad altri programmatori come anche a se stessi dopo qualche tempo).
 
Scrivere (buon) codice in assembly è dispendioso in termini di tempo, difficile e quindi molto costoso, soprattutto in prospettiva (future modifiche): per questo, raramente l'assembly è il solo linguaggio usato in un progetto mainstream, a meno che questo non sia di dimensioni e portata limitate. In genere si usa in combinazione con altri linguaggi: la maggior parte del codice viene scritta in un [[linguaggio ad alto livello]], mentre le parti più critiche (per motivi di performance, precisione del timing o affidabilità) si scrivono in assembly.
A fronte di questi svantaggi l'assembly offre un'efficienza senza pari e il controllo completo e assoluto sull'hardware: i programmi in assembly sono, in linea di principio, i più piccoli e veloci che sia possibile scrivere su una data macchina.
 
Scrivere (buon) codice in assembly è dispendioso in termini di tempo, difficile e quindi molto costoso, soprattutto in prospettiva (future modifiche): per questo, raramente l'assembly è il solo linguaggio usato in un progetto mainstream, a meno che questo non sia di dimensioni e portata limitate. In genere si usa in combinazione con altri linguaggi: la maggior parte del codice viene scritta in un [[linguaggio di programmazione|linguaggio]] ad alto livello, mentre le parti più critiche (per motivi di performance, precisione del timing o affidabilità) si scrivono in assembly.
 
Tali problematiche sono riscontrabili principalmente su piattaforme come i ''personal computer'' attuali, dove la vastità quantitativa e l'enorme gamma qualitativa dell'hardware disponibile crea alle applicazioni low-level un oggettivo problema mai risolto (e presumibilmente non risolvibile) a livello di unificazione e standard. A ciò si aggiunga l'evoluzione costante verso una sempre maggiore stratificazione dei comuni sistemi operativi, caratterizzata da numerosi vincoli e virtualizzazioni delle periferiche fisiche e dei canali di comunicazione, che non rendono agevole lo sviluppo di un software che interagisca direttamente con l'hardware sottostante e ne gestisca direttamente le caratteristiche.
 
=== Utilizzi ===
Si possono però citare due esempi, peraltro correlati, di totale inversione di questo paradigma generale:
 
* Ha ampiamente senso creare programmi interamente in assembly destinati ad [[hardware]] caratterizzato architetturalmente da documentazione esaustiva, grande predicibilità, stabilità e scarsa variabilità temporale del design: per esempio, si possono citare gli ''home computer'' degli [[anni 1980|anni ottanta]], come i [[Commodore]] [[Vic-20]] e [[Commodore 64|C64]] o il [[Sinclair ZX Spectrum]].
* Ha parimenti senso, ed un forte riscontro nella pratica invalsa negli ultimi trenta anni, operare prevalentemente o esclusivamente in assembly nel vastissimo mercato dei [[sistemi embedded]], per la programmazione di [[microcontrollore|microcontroller]] e [[Digital Signal Processor|DSP]], eventualmente anche sotto forma di ''core'' implementati tramite [[Application specific integrated circuit|ASIC]], [[CPLD]] ed [[Field programmable gate array|FPGA]], al fine di massimizzare performance e rispetto dei vincoli temporali, minimizzando nel contempo il ''footprint''. Ciò trova riscontro a tutti i livelli della filiera produttiva, a partire dalla progettazione dei chip e del relativo linguaggio utilizzando [[instruction set|ISA]] di tipo [[Reduced instruction set computer|RISC]] e fortemente ortogonali, la cui ottimizzazione (in spazio o in performance) è altamente semplificata. Questo approccio è fondamentale in quanto consente grandi economie di scala nei progetti tipici del mondo ''embedded'', caratterizzati dalla capacità di assorbire costi iniziali (''NRE, non-recurrent engineering costs'') anche elevati, purché finalizzati ad una forte compressione del costo unitario del prodotto finale, anche per volumi medio-bassi.
Riga 43 ⟶ 49:
Ecco allora che la possibilità di utilizzare un microcontroller con limitatissime risorse di memoria [[Read only memory|ROM]] e [[RAM]] scrivendo il [[firmware]] integralmente in assembly diventa essenziale al fine di minimizzare i costi, l'ingombro in piastra, la suscettibilità elettromagnetica, aumentando anche l'affidabilità (processori più "datati" hanno un incolmabile vantaggio in termini di milioni di ore di test e funzionamento sul campo, ossia la "merce" di gran lunga più preziosa per i sistemi embedded variamente critici) ed ottimizzando numerosi altri fattori.
 
== Struttura dei programmi ==
==RISC e CISC==
{{Organizzare|La sezione ha un'impostazione da manuale didattico più che da enciclopedia|informatica|febbraio 2024}}
Il linguaggio assembly costituisce il cosiddetto [[instruction set|ISA]] (''Instruction Set Architecture'') di un processore.
I diversi ISA possono essere divisi in due grandi gruppi: i [[Reduced instruction set computer|RISC]] (''Reduced Instruction Set Computer'') e i [[Complex instruction set computer|CISC]] (''Complex Instruction Set Computer''). Il primo gruppo tende ad avere operazioni semplici e veloci, con grande abbondanza di [[registro (informatica)|registri]] per memorizzare i risultati intermedi. Il secondo mette a disposizione del programmatore istruzioni più complesse, che a volte mimano quelle dei linguaggi di livello più alto (ad esempio, la copia di stringhe nei processori x86). In entrambi i casi, i migliori set di istruzioni tendono ad essere quelli cosiddetti ''ortogonali'', dove i diversi [[metodo di indirizzamento|metodi di indirizzamento]] e i diversi registri possono essere usati indifferentemente in tutte le istruzioni. Famosi set di istruzioni ortogonali sono quelli del Motorola 68000 (CISC) e del [[Architettura MIPS|MIPS]] (RISC). L'ISA dei processori Intel x86 era originariamente ben poco ortogonale, ed è andata via via migliorando.
 
La distinzione tra ''set'' di istruzioni RISC e CISC è oggi un po' sfumata, perché la maggior parte dei processori consumer sono oggi dei [[CRISP]], cioè un misto fra i due. Inoltre, alcuni processori traducono l'ISA originale in un set di istruzioni interno, per ragioni diverse e con modalità diverse:
* nel caso dell'[[Intel]] [[Pentium 4]] e dell'[[Advanced Micro Devices|AMD]] [[Athlon]], è per liberarsi dalle limitazioni causate da un'ISA retrocompatibile ormai arcaica, e la conversione è eseguita direttamente da hardware dedicato che effettua la necessaria ''decodifica'';
* nel caso dei processori [[Transmeta]], è per poter "tradurre" ISA di altri processori esistenti come se fossero proprie, e la traduzione è fatta da qualcosa di concettualmente molto simile a ''routine'' firmware (denominate ''microcodice'') memorizzate in un'area [[Read only memory|ROM]] ricavata sul silicio del microprocessore.
 
==Struttura==
La struttura di un tipico listato [[Assembly x86]] per PC si articola, a grandi linee, nei seguenti termini:
* intestazione, in cui possiamo inserire, tramite dei commenti, il nome e la funzione del programma.
* segmento dati, in cui andiamo a dichiarare formalmente le variabili usate dal programma (in pratica allochiamo delle zone di memoria nel segmento puntantopuntando dal DS data segment)
* segmento di stack, in cui definiamo la struttura dello stack associato al programma (parleremo dello stack in seguito)
* segmento di codice, in cui è presente il codice del programma
* chiusura
Vale la pena di ribadire che tale struttura, nella sua generalità, dipende quasi per intero dalla piattaforma e anche dall'assembler utilizzato e quindi non è in alcun modo universalizzabile. Architetture diverse, dai mainframe ai microcontroller, con relativi assemblatori e cross-assembler, impongono strutture di sorgente a volte nettamente diverse dal semplice esempio illustrato, relativo ai comuni PC. Per un controesempio banale, nelle architetture Harvard usate dalla quasi totalità dei microcontroller e da molte architetture di supercalcolo:
* il segmento di codice non risulta scrivibile durante la normale elaborazione: ne consegue, tra l'altro, l'assoluta impossibilità di creare codice self-morphing ([[Codice automodificante|automodificante]]), ma anche un modo generalmente diverso di referenziare variabili (a rigore, label corrispondenti ad una o più locazioni in memoria dati) e codice nel sorgente;
* i dati a loro volta risiedono in memorie fisicamente separate, talora dotate anche di persistenza tra le sessioni ([[EPROM]], Flash EEPROM, RAM "tamponate" ossia dotate di batteria di backup...), e tutto ciò si riflette in modo esplicito e pervasivo nella sintassi supportata dall'assembler, nelle direttive specifiche e nella struttura effettiva di un sorgente Assembly;
* ultimo, ma non meno importante: registri come DS e SS (stack segment) sono altre peculiarità della piattaforma x86, sovente lo stack di chiamata non è neppure direttamente accessibile nei core MCU più diffusi.
 
=== Esempio di codice ===
Esempio di programma "[[Hello world]]" in assembly Intel x86 con sintassi [[Intel]] (sfrutta le chiamate al sistema operativo DOS). Non è compatibile con le versioni Assembly [[UNIX]] [[GNU]]
<sourcesyntaxhighlight lang="asm" line="1">
 
MODEL SMALL
Riga 81:
INT 21H
END
</syntaxhighlight>
</source>
 
Questo invece è l'esempio del programma scritto per sintassi AT&T (per le architetture [[UNIX]] [[GNU]])
<sourcesyntaxhighlight lang="asm" line="1">
 
.section .data
Riga 105:
movl hello_len, %edx # copia del contenuto della variabile. carica la lunghezza della variabile
 
int $0x80 # system call (int sarebbe "interrupt"); con 0x80 si lancia una interaction generale
# dichiarata (in base ai valori caricati precedentemente nei registri)
Riga 114:
int $0x80
 
</syntaxhighlight>
</source>
 
== Caratteristiche generali ==
==Microistruzioni==
Quando si esegue un'istruzione Assembly, il [[processore]] (in base all'architettura presa in considerazione) esegue una serie di operazioni chiamate "Microistruzioni Assembly", cioè delle operazioni hardware che servono per configurare i registri e gli operatori della [[CPU]] in modo che possa essere eseguita quella istruzione.
 
=== Sezioni ===
Tale processo si divide, nel caso delle CPU Intel x86 e di alcune altre, in 3 parti:
{{...|informatica}}
 
=== Costanti di programma ===
* Fetch: fase di caricamento in cui si incrementa il registro PC e si prepara la CPU a compiere l'operazione;
{{...|informatica}}
* Decode: si configurano i [[multiplexer]] interni alla CPU e viene eseguita una codifica dell'istruzione qualora sia necessario (indirizzamenti indiretti, a spiazzamento, ecc...)
* Execute: il momento in cui si esegue veramente l'operazione
 
=== Istruzioni ===
Da qui la sigla FDE, Fetch-Decode-Execute, riportata nei testi di architettura e nei datasheet.
{{...|informatica}}
 
=== Il costrutto di sequenza ===
Per fare un esempio per l'architettura dell'Intel 80x86 con un singolo BUS, in sintassi AT&T, questa istruzione:
In assembly è possibile definire sequenze di istruzioni attraverso l'uso delle "[[etichetta (informatica)|etichette]]" (''label''). Si tratta di semplici stringhe di [[testo ASCII]] seguite dai due punti di specificazione, che marcano in modo univoco un determinato punto del listato di istruzioni.
<source lang="asm">
ADD %EBX, %EAX
</source>
in cui si somma il contenuto del registro EAX con il contenuto del registro EBX e il risultato verrà salvato in EAX, vengono svolte queste microoperazioni:
<source lang="asm">
1. PCout, SELECT[4], ADD, Zin, MARin, READ ;viene incrementato il PC per eseguire l'operazione successiva
2. Zout, PCin, WMFC ;si aspetta che sia avvenuta la lettura in memoria
3. MDRout, IRin ;viene inviata l'istruzione prossima in IR
4. EAXout, Vin ;viene inviato il contenuto di EAX in un registro temporaneo
5. EBXout, SELECT[V], ADD, Zin ;viene sommato il contenuto di EBX tramite la ALU con EAX
6. Zout, EAXin, END ;il risultato viene copiato in EAX
</source>
 
<syntaxhighlight lang="asm" line="0">
Su alcune architetture tali fasi risultano invece essere quattro (ad esempio, nei PIC Microchip, negli Intel 8051 e in numerosissimi core analoghi), da cui risulta anche l'effettivo rapporto tra velocità di clock ossia frequenza del quarzo esterno (es. 10&nbsp;MHz) e numero di istruzioni effettivamente eseguite in un secondo. Per i PIC (famiglie ''baseline'' e ''midrange'' in particolare) tale rapporto è pari ad 1/4, poiché ad ogni ciclo di clock il core esegue effettivamente una singola fase Fetch-Decode-Execute-Write e dunque sono necessari quattro cicli del clock esterno per completare una singola istruzione. Su architetture di microcontroller e core più arcaiche o comunque di diversa concezione, sono necessari anche più cicli di clock per ciascuna fase (ad esempio tre o quattro), da cui il diverso rapporto tra clock e MIPS, che nel caso del design 8051 originale richiede ad esempio 12 cicli di clock per ciascuna singola istruzione. Si ricordi infine che talune istruzioni, tra le quali tipicamente i salti incondizionati, richiedono su un numero notevole di piattaforme (sia RISC che CISC, concepite in varie epoche) un numero di cicli superiore alle altre, a causa delle operazioni accessorie (non parallelizzabili) richieste dall'aggiornamento del registro IP e di eventuali code di prefetch interne.
label1:
nop
nop
label2:
nop
</syntaxhighlight>
 
=== Il costrutto di selezione ===
==C-asm==
Il costrutto di selezione, detto anche scelta, è uno degli elementi fondamentali del [[paradigma di programmazione|paradigma]] di [[programmazione strutturata]]. È il metodo più semplice per la gestione del [[flusso di controllo]], e permette di scegliere tra due sequenze alternative di istruzioni.
Talvolta, nella programmazione ad alto livello in ambienti come il DOS, c'è la necessità di effettuare alcune operazioni che sono molto più veloci usando delle istruzioni di linguaggi a basso livello (in Windows invece a causa delle protezioni della memoria si ricorre più frequentemente alle chiamate [[WINAPI]], le chiamate in L/M sono usate per lo più per procedure matematiche accelerate o dai [[driver]]). Tra i linguaggi ad alto livello che permettono questo vi sono il [[C (linguaggio)|C]] e il [[C++]], in cui possono essere inserite nei propri sorgenti parti scritte in assembly che, in fase di compilazione, verranno tradotte con un procedimento noto come [[assembler inline]]. Un esempio di codice scritto in C-asm (usando l'assembly Intel x86), che visualizza in binario un numero dato in input, è il seguente:
In assembly questo viene generalmente implementato utilizzando un'istruzione di salto condizionato in capo a due sequenze specificate in successione.
<source lang="asm">
#include <stdio.h>
#include <iostream.h>
#include <conio.h>
int main()
{
int a;
 
<syntaxhighlight lang="asm" line="0">
/* Acquisizione del valore numerico */
beq $t1,$0,else # Se t1 = 0 salta all'etichetta "else"
printf("Inserisci un valore compreso tra -32768 e 32768: ");
nop # Attendi la prossima istruzione (sequenza interna n°1)
scanf("%d", &a);
j cont # Salta all'etichetta "cont"
else:
move $t2,$0 # Imposta t2 = 0 (sequenza interna n°2)
cont:
</syntaxhighlight>
 
=== Il costrutto di iterazione ===
/* Visualizzazione del messaggio di risposta */
Il costrutto di [[iterazione]], detto anche ciclo (''loop''), è uno degli elementi fondamentali del [[paradigma di programmazione|paradigma]] di [[programmazione strutturata]], e consente di definire la ripetizione ciclica di sequenze di istruzioni. In assembly questo viene generalmente implementato come variante notevole del costrutto di selezione.
printf("Il valore corrispondente in binario è: ");
/* Keyword per delimitare le sezioni di codice Assembly */
asm
{
/* Visualizzazione della stringa di bit corrispondente */
MOV BX,WORD PTR a
MOV CX,00Ah
}
 
<syntaxhighlight lang="asm" line="0">
/* Etichetta esterna */
# Iterazione con controllo in testa
Ciclo:
loop:
asm
beq $t1,$0,end # Se t1 = 0 salta all'etichetta "end"
{
addi $t1,$t1,-1 # Decrementa t1 di 1 unità (sequenza interna)
/* Estrazione di un bit */
j loop MOV DL,00H # Salta all'etichetta "loop"
end:
RCL BX,1 /* Il valore del bit viene posto nel flag di carry */
</syntaxhighlight>
ADC DL,'0' /* Determino il carattere da visualizzare */
MOV AH,02H /* Visualizzazione */
INT 21h
Loop Ciclo
}
return 0;
}
</source>
 
Le caratteristiche peculiari del ciclo sono diverse:
Per la maggioranza delle applicazioni ''mainstream'', è ormai convinzione comune nella comunità dei programmatori applicativi che fattori come le ottimizzazioni generate automaticamente dai compilatori nei linguaggi di più elevato livello, l'evoluzione di librerie a loro volta sempre più ottimizzate (almeno in linea di principio) e la sempre maggiore potenza elaborativa delle piattaforme comunemente diffuse rendano meno necessario rispetto al passato il ricorso alla verticalizzazione tramite assembly inline o moduli assembly, anche in favore della [[portabilità]] e leggibilità del codice. Tuttavia, non mancano numerose eccezioni in totale controtendenza rispetto a tale diffusa concezione: in particolare nel mondo dei sistemi dedicati, basato quasi per definizione su un paradigma ben diverso, come ricordato al paragrafo "Non c'è un solo assembly", ma anche in numerose nicchie specialistiche ai margini del ''mainstream'', dai sistemi CAD/CAM al calcolo numerico, alle applicazioni scientifiche di varia natura, fino allo sviluppo di driver e altro software di sistema.
* le due etichette sono poste rispettivamente all'inizio e alla fine del blocco, permettendo di scegliere di volta in volta se ripetere la sequenza o meno.
* l'istruzione di salto condizionato verifica ciclicamente l'esistenza di una condizione, in base alla quale viene deciso se interrompere il ciclo o meno;
* L'istruzione finale di salto incondizionato punta alla prima etichetta, realizzando così il comportamento ciclico.
 
È possibile realizzare una variante del costrutto di iterazione in cui l'istruzione di salto condizionato viene posta per ultima. Notare come in questo caso non sia necessaria un'istruzione di salto incondizionato per realizzare il comportamento ciclico, come pure l'etichetta "end" che viene mantenuta puramente per fini illustrativi. La particolarità di questa variante è che la sequenza interna viene eseguita sempre almeno una volta, a causa del deferimento della verifica della condizione di iterazione.
==Strutture di controllo in Assembly x86==
Il processore esegue le istruzioni così come si presentano, una dopo l'altra. Tuttavia, attraverso particolari strutture, si può controllare il flusso esecutivo in base ad una determinata condizione. In questo modo si può creare strutture di semplice selezione o di tipo iterativo (cicli). Le istruzioni assembly che vengono utilizzate per questo scopo sono principalmente di due tipo: salto e confronto.
 
<syntaxhighlight lang="asm" line="0">
I salti possono essere incondizionati o condizionati. JMP effettua un salto incondizionato. In genere l'indirizzo di riferimento è un'etichetta. La condizione del salto è sempre dettata dai valori del registro dei flag. I flag più usati per i salti sono:
# Iterazione con controllo in coda
* ZF (flag zero) indica se l'ultima istruzione ha generato come risultato 0
loop:
* SF (flag segno) indica se l'ultima istruzione ha generato un risultato di segno negativo
addi $t1,$t1,-1 # Decrementa t1 di 1 unità (sequenza interna)
* OF (flag overflow) indica se l'ultima istruzione ha generato un overflow (con troncamento del bit più significativo del risultato)
bne $t1,$0,loop # Se t1 non è 0 salta all'etichetta "loop"
end:
</syntaxhighlight>
 
== Note ==
'''Il costrutto di selezione (if, else)'''
<references />
 
La selezione è una struttura che permette di eseguire un blocco di istruzioni oppure un altro in base al verificarsi di una condizione.''<nowiki/>''
se
blocco istruzioni 1
altrimenti
blocco istruzioni 2
fine se
''in assembly, attraverso la logica dei salti, viene rappresentato così:''
se:
JNcondizione altrimenti
blocco istruzioni 1
JMP fine_se
altrimenti:
blocco istruzioni 2
fine_se:
 
'''Il ciclo a controllo in coda (do...while)'''
 
L'iterazione è una struttura che permette di ripetere più volte un'istruzione sotto il controllo di una condizione.
ripeti
istruzioni
finché condizione
''in assembly, attraverso la logica dei salti, viene rappresentato così:''
inizio_ciclo:
istruzioni
Jcondizione inizio_ciclo
''esempio:''
MOV AX, 0000h
inizio_ciclo:
INC AX
CMP AX, 000Ah ;confronta AX e il valore 0Ah (10d)
JNE inizio_ciclo ;salta all'inizio (e ripete il ciclo) se diverso
''Dato che il controllo della condizione viene eseguito alla fine del ciclo, le istruzioni in sequenza vengono eseguite comunque almeno una volta, anche se la condizione era già verificata in partenza. In pratica:''
MOV AX, 000Ah
inizio_ciclo:
INC AX
CMP AX, 000Ah
JNE inizio_ciclo
''Questo spezzone di codice dovrebbe controllore se AX = 10d, e in caso contrario incrementare AX. In caso favorevole uscire dal ciclo. Vediamo però che AX vale già 10d, tuttavia tale registro viene comunque incrementato (alla fine varrà 000Bh). Inoltre, in questo particolare programma, il ciclo non finirà mai: AX varrà 11, poi 12, poi 13 e non diventerà mai uguale a 10. Sarebbe buona norma, nelle condizioni, evitare di esprimere un'uguaglianza:''
MOV AX, 000Ah
inizio_ciclo:
INC AX
CMP AX, 000Ah
JB inizio_ciclo ; salta se minore (invece di salta se non uguale)
''In questo modo abbiamo risolto il problema del ciclo infinito. Tuttavia, a causa del fatto che la sequenza viene eseguita almeno una volta, in genere si evita il ciclo a controllo in coda e si utilizza invece quello a controllo in testa.''
 
'''Il ciclo a controllo in testa (while)'''
 
Una struttura iterativa a controllo in testa si può descrivere, ad alto livello, così:
mentre condizione
istruzioni
fine ciclo
''Equivale alla while (condizione) { sequenza } del C. in assembly:''
inizio_ciclo:
JNcondizione fine_ciclo
sequenza
JMP inizio_ciclo
fine_ciclo
''esempio:''
inizio_ciclo:
CMP AX,0Ah ;confronta AX con 10d
JNE fine_ciclo ;salta se diverso
INC AX ;incrementa AX
JMP inizio_ciclo
fine_ciclo
''La differenza tra questa struttura e quella a controllo in coda sta nel fatto che se la condizione è inizialmente verificata, la sequenza di istruzioni non viene eseguita nemmeno una volta.''
 
'''Il ciclo a contatore (for)'''
 
Il ciclo a contatore ha una struttura di questo tipo:
CONTATORE = 0
mentre CONTATORE < N
sequenza
incrementa CONTATORE
fine ciclo
''Possiamo utilizzare un ciclo a contatore se vogliamo ripetere un blocco di istruzioni per un numero di volte noto a priori. i cicli in assembly sono in genere a decremento:''
CONTATORE = N
ripeti
sequenza
decrementa CONTATORE
finché CONTATORE n > 0
''Come contatore si usa di solito il registro CX (registro contatore, appunto), perché esiste un'istruzione che esegue le ultime due istruzioni automaticamente: l'istruzione LOOP: decrementa CX e, se CX non è 0, salta all'etichetta specificata.''
MOV CX, 0
inizio_ciclo:
CMP CX, N
JGE fine_ciclo
sequenza
JMP inizio_ciclo
fine_ciclo:
 
''Grazie all'istruzione LOOP diventa semplice scrivere un ciclo a contatore in assembly:''
MOV CX, <N> ; dove N è il numero di ripetizioni da eseguire
inizio_ciclo:
sequenza
LOOP inizio_ciclo
 
''Va sottolineato che nel primo esempio si ha un ciclo a controllo in testa, mentre nel secondo uno a controllo in coda, e che, sebbene il secondo sia più compatto e veloce da scrivere, possa generare degli errori, come già detto sopra, se non si sta attenti a come lo si usa, infatti in esso le istruzioni vengono eseguite almeno una volta, per cui se non si è sicuri che il numero di ripetizioni non possa mai essere zero, è meno rischioso usare il primo.''
 
==L'input/output tramite l'INT 21h del DOS==
L'assembly, specialmente nel mondo dei PC, non prevede funzioni di input/output già pronte. Il programmatore deve quindi creare le proprie routine o appoggiarsi a quelle create da terze parti. Negli ambienti DOS è sufficiente porre il codice del servizio richiesto in AX ed usare l'istruzione INT 21h per richiamare il relativo [[software interrupt]], una delle caratteristiche più peculiari delle CPU Intel x86. Tra le funzioni più comuni per l'input/output da tastiera:
* servizio 01h==> Acquisizione di un carattere da tastiera con eco sul video. Attende la pressione di un tasto e restituisce il codice ASCII del tasto premuto
* servizio 02h ==> Visualizzazione di un carattere a video. Stampa il carattere il cui codice ASCII è contenuto in DL
* servizio 07h ==> Acquisizione di un carattere da tastiera senza eco sul video. Come il servizio 01h, ma non visualizza il carattere sullo schermo
* servizio 09h ==> Visualizzazione di una stringa a video. Stampa la stringa a cui punta l'indirizzo di memoria contenuto in DX
* servizio 4Ch ==> Servizio di ritorno al sistema operativo. Consente di terminare il programma.
 
''Quindi, per acquisire un carattere (con eco sul video):''
MOV AH, 01h ; servizio 01h
INT 21h ; se AX=0001h, allora in AL va il codice ASCII del tasto premuto
''E volendo poi stamparlo:''
MOV DL,AL ; copio il codice ASCII del tasto letto il DL
MOV AH,02h ; servizio 02h
INT 21h ; se AX=0002h, allora stampa il carattere di codice ASCII in D
''Come si può vedere, sia le operazioni di acquisizione che di stampa fanno rifemento ai codici di carattere ASCII. Nel caso si voglia leggere in input una cifra numerica, per risalire al valore numerico basta sottrarre il valore 30h (48 in decimale) al suo codice ASCII. Infatti 30h in ASCII corrisponde al carattere "0", 31h (49 in decimale) all'"1" e così via...''
 
Nel caso in cui si voglia stampare una stringa:
stringa DB 13,10,"questa è una stringa","$" ;alloco una variabile da un byte che chiamo stringa e in cui ci salvo una sequenza di caratteri(una stringa appunto)
LEA DX,stringa ;copio l'indirizzo di memoria che punta alla stringa in DX
MOV AH,09h ; servizio 09h
INT 21h ; se AX=0009h, allora stampa la stringa a cui punta l'indirizzo di memoria contenuto in DX
 
== Assembly x86 ==
Assembly x86 è una famiglia di linguaggi [[Assembly]], usati per creare codici oggetto per i processori [[Intel]] [[X86]]. Come tutti i linguaggi assembly, sfrutta brevi parole per realizzare le istruzioni per la [[CPU]].
 
== Bibliografia ==
* {{cita libro
 
|titolo = Struttura e progetto dei calcolatori
|autore = [[David Andrew Patterson]]
|autore2 = [[John LeRoy Hennessy]]
|curatore = Alberto Borghese
|edizione = 5
|editore = Zanichelli
|città = Bologna
|anno = 2015
|ISBN = 978-88-08-35202-6
|cid = Patterson, Hennessy 2015
}}
* {{cita libro|autore=[[Andrew Stuart Tanenbaum]]|titolo=Architettura dei calcolatori. Un approccio strutturale|editore=Pearson Education|città=Milano|anno=2006|url=http://books.google.it/books?id=hK8lJ4BPOYcC|pp=491-528|capitolo=Livello del linguaggio assemblativo|isbn=978-88-7192-271-3|cid=adc}}
* {{Cita testo|titolo=Programmare in Assembler|url=https://archive.org/details/programmareinassembler|autore=Alain Pinaud|editore=Gruppo Editoriale Jackson|anno=1982|ISBN=88-7056-105-4}}
* {{cita libro|autore=Randall Hyde|titolo=The Art of Assembly Language|editore=No Starch Press|anno=2010|url=http://books.google.it/books?id=F5MhjlEnnO0C|isbn=978-1-59327-301-9|cid=taoal}}
* {{cita libro|lingua=en|autore=Randall Hyde|titolo=The Art of Assembly Language|editore=No Starch Press|anno=2010|url=http://books.google.it/books?id=F5MhjlEnnO0C|isbn=978-1-59327-301-9|cid=taoal}}
 
== Voci correlate ==
* [[Assembler]]
* [[Disassembler]]
* [[Linguaggio macchina]]
 
== Altri progetti ==
{{interprogetto|b|b_preposizionepreposizione=sull'sul}}
 
== Collegamenti esterni ==
* {{Collegamenti esterni}}
* [http://www.marcofb.net/main/guida_assembler.html Guida Linguaggio Assembly MIPS/SPIM Architetture R2000/R3000]
* {{FOLDOC|assembly language|assembly language}}
* [https://web.archive.org/web/20110617064333/http://blogs.academicclub.org/leonardo/category/assembly Imparare l'Assembly con Visual C++]
* {{lingue|en|it|fr|es|de|zh}}[http://www.drpaulcarter.com/pcasm/ PC Assembly Language], tutorial di Paul Carter sull'assembly [[x86]]
* [http://www.intel-assembler.it/ Intel x86 programming]
 
{{Controllo di autorità}}