Esercizi sul linguaggio Assembly 8086

Esercizi sul linguaggio Assembly 8086 : indice argomenti

Introduzione

L’Assembly 8086 è un linguaggio di basso livello utilizzato per la programmazione di computer che utilizzano l’architettura x86. Questo linguaggio è molto vicino alla lingua dell’hardware del computer e pertanto molto potente e flessibile. Tuttavia, il linguaggio Assembly è molto complesso e richiede una buona conoscenza dell’architettura hardware del computer.

Architettura del processore x86

Prima di iniziare a scrivere del codice Assembly 8086, è importante avere una buona conoscenza dell’architettura del processore x86. Il processore x86 è composto da un’unità di elaborazione centrale (CPU) e da una serie di registri, che sono piccole aree di memoria all’interno del processore utilizzate per l’archiviazione temporanea dei dati.

Il processore x86 utilizza anche una serie di bus di sistema per il trasferimento di dati tra la CPU, la memoria e i dispositivi di input/output (I/O). È importante avere una buona comprensione di questi bus di sistema prima di iniziare a scrivere del codice Assembly.

Istruzioni Assembly x86

Il codice Assembly 8086 è composto da una serie di istruzioni Assembly, che sono simili alle istruzioni in linguaggio macchina utilizzate dal processore x86. Ogni istruzione Assembly è costituita da un’operazione e uno o più operandi.

Ad esempio, l’istruzione Assembly MOV AX, BX copia il contenuto del registro BX nel registro AX. L’operazione in questo caso è “MOV”, mentre gli operandi sono “AX” e “BX”.

È importante notare che le istruzioni Assembly sono molto specifiche per l’architettura hardware del processore. Quindi, mentre le istruzioni Assembly possono sembrare simili tra diverse architetture di processori, le differenze sottostanti possono essere significative.

Registri del processore 8086

Il processore x86 utilizza una serie di registri interni per l’archiviazione temporanea dei dati. Questi registri sono essenziali per l’esecuzione del codice Assembly e sono utilizzati frequentemente nelle istruzioni Assembly.

I registri del processore possono essere divisi in diverse categorie:

  • Registri generali: questi registri sono utilizzati per l’archiviazione di dati temporanei durante l’esecuzione del codice Assembly. Ci sono 8 registri generali a 16 bit (AX, BX, CX, DX, BP, SP, SI e DI) e 8 registri generali a 8 bit (AL, AH, BL, BH, CL, CH, DL e DH).
  • Registri di segmento: questi registri sono utilizzati per l’archiviazione di informazioni relative alla memoria. Ci sono 4 registri di segmento (CS, DS, SS e ES).
  • Registri di controllo: questi registri sono utilizzati per il controllo del funzionamento del processore. Ci sono 4 registri di controllo (CR0, CR2, CR3 e CR4).
  • Registri di stato: questi registri sono utilizzati per indicare lo stato del processore. Ci sono 6 registri di stato (FLAGS, CF, PF, AF, ZF, SF e OF).

Esempio di codice linguaggio Assembly 8086

Di seguito è riportato un esempio di codice Assembly 8086 per la stampa della stringa “Hello, World!” sulla console:

    .model small
    .stack 100h

    .data
    hello_msg db 'Hello, World!', 0ah, 0dh, '$'

    .code
    main proc
        mov ah, 09h
        lea dx, hello_msg
        int 21h

        mov ah, 4ch
        int 21h
    main endp
    end main


  • .model small: specifica il modello di memoria da utilizzare per il programma.
  • .stack 100h: specifica la dimensione dello stack per il programma.
  • .data: la sezione dei dati del programma, in cui vengono definiti i dati statici.
  • hello_msg db 'Hello, World!', 0ah, 0dh, '$': definisce una stringa di caratteri con il testo “Hello, World!” seguito da un carattere di nuova riga (0ah), un carattere di ritorno a capo (0dh) e un carattere di terminazione ('$').
  • .code: la sezione del codice del programma, in cui viene definito il codice Assembly.
  • main proc: definisce la procedura principale del programma.
  • mov ah, 09h: carica il valore 09h nel registro ah, che corrisponde alla funzione di stampa del testo.
  • lea dx, hello_msg: carica l’indirizzo della stringa hello_msg nel registro dx.
  • int 21h: esegue la funzione di stampa del testo utilizzando il valore nel registro ah e l’indirizzo della stringa nel registro dx.
  • mov ah, 4ch: carica il valore 4ch nel registro ah, che corrisponde alla funzione di uscita dal programma.
  • int 21h: esegue la funzione di uscita dal programma utilizzando il valore nel registro ah.
  • main endp: indica la fine della procedura principale.
  • end main: indica la fine del programma.

Questo codice utilizza le istruzioni Assembly per caricare il messaggio “Hello, World!” nella memoria del computer e quindi utilizza le funzioni del sistema operativo per stamparlo sulla console.

Esercizi sul linguaggio Assembly 8086

Esempio 1: Somma di due numeri

    .model small
    .stack 100h

    .data
    num1 dw 1234h
    num2 dw 5678h
    result dw ?

    .code
    main proc
        mov ax, num1
        add ax, num2
        mov result, ax

        mov ah, 09h
        lea dx, result
        int 21h

        mov ah, 4ch
        int 21h
    main endp
    end main


Questo codice somma due numeri a 16 bit e stampa il risultato sulla console. Il primo numero è memorizzato nella variabile num1 e il secondo numero è memorizzato nella variabile num2. Il risultato della somma viene memorizzato nella variabile result.

  • .model small: specifica il modello di memoria da utilizzare per il programma.
  • .stack 100h: specifica la dimensione dello stack per il programma.
  • .data: la sezione dei dati del programma, in cui vengono definiti i dati statici.
  • num1 dw 1234h: definisce una variabile num1 di tipo word (16 bit) e la inizializza con il valore 1234h.
  • num2 dw 5678h: definisce una variabile num2 di tipo word (16 bit) e la inizializza con il valore 5678h.
  • result dw ?: definisce una variabile result di tipo word (16 bit) senza inizializzarla.
  • .code: la sezione del codice del programma, in cui viene definito il codice Assembly.
  • main proc: definisce la procedura principale del programma.
  • mov ax, num1: carica il valore della variabile num1 nel registro ax.
  • add ax, num2: aggiunge il valore della variabile num2 al registro ax.
  • mov result, ax: copia il valore del registro ax nella variabile result.
  • mov ah, 09h: carica il valore 09h nel registro ah, che corrisponde alla funzione di stampa del testo.
  • lea dx, result: carica l’indirizzo della variabile result nel registro dx.
  • int 21h: esegue la funzione di stampa del testo utilizzando il valore nel registro ah e l’indirizzo della variabile nel registro dx.
  • mov ah, 4ch: carica il valore 4ch nel registro ah, che corrisponde alla funzione di uscita dal programma.
  • int 21h: esegue la funzione di uscita dal programma utilizzando il valore nel registro ah.
  • main endp: indica la fine della procedura principale.
  • end main: indica la fine del programma.

Esempio 2: Calcolo del fattoriale

    .model small
    .stack 100h

    .data
    num dw 5
    fact dw 1

    .code
    main proc
        mov cx, num
    loop_start:
        mul cx
        loop loop_start

        mov fact, ax

        mov ah, 09h
        lea dx, fact
        int 21h

        mov ah, 4ch
        int 21h
    main endp
    end main


Questo codice calcola il fattoriale di un numero utilizzando un loop. Il numero di cui calcolare il fattoriale è memorizzato nella variabile num. Il risultato del fattoriale viene memorizzato nella variabile fact.

Esempio 3: Stampa dei numeri da 1 a 10

    .model small
    .stack 100h

    .code
    main proc
        mov cx, 10
        mov ax, 1
    loop_start:
        mov ah, 09h
        mov dx, ax
        add dx, 30h
        int 21h

        inc ax
        loop loop_start

        mov ah, 4ch
        int 21h
    main endp
    end main


Questo codice stampa i numeri da 1 a 10 sulla console. Il loop utilizza la variabile cx per contare fino a 10 e la variabile ax per tenere traccia del numero corrente da stampare.

Esempio 4: Calcolo del massimo comun divisore

    .model small
    .stack 100h

    .data
    num1 dw 45
    num2 dw 30
    gcd dw ?

    .code
    main proc
    loop_start:
        mov ax, num1
        mov bx, num2
        xor dx, dx
        div bx
        cmp dx, 0
        jne loop_start

        mov gcd, bx

        mov ah, 09h
        lea dx, gcd
        int 21h

        mov ah, 4ch
        int 21h
    main endp
    end main


Questo codice calcola il massimo comun divisore di due numeri utilizzando l’algoritmo di Euclide. I due numeri sono memorizzati nelle variabili num1 e num2. Il risultato del massimo comun divisore viene memorizzato nella variabile gcd.

Esempio 5: Stampa di una stringa inversa

    .model small
    .stack 100h

    .data
    str db 'Hello, World!', 0ah, 0dh, '$'

    .code
    main proc
        lea si, str
        lea di, str

        mov cx, 0
    loop_start:
        mov al, [si]
        cmp al, '$'
        je loop_end

        inc si
        inc cx
        jmp loop_start

    loop_end:
        mov bx, cx
        dec si

    reverse_loop:
        mov dl, [si]
        mov [di], dl

        inc di
        dec si
        dec bx
        cmp bx, 0
        jne reverse_loop

        mov ah, 09h
        lea dx, str
        int 21h

        mov ah, 4ch
        int 21h
    main endp
    end main


Questo codice stampa una stringa al contrario sulla console. La stringa è memorizzata nella variabile str. Il codice utilizza un loop per determinare la lunghezza della stringa e quindi un altro loop per stampare la stringa al contrario.

Esempio 6: Calcolo della somma degli elementi di un array

    .model small
    .stack 100h

    .data
    arr dw 1, 2, 3, 4, 5
    arr_len dw 5
    sum dw 0

    .code
    main proc
        mov cx, arr_len
        mov si, offset arr
    loop_start:
        mov ax, [si]
        add sum, ax

        add si, 2
        loop loop_start

        mov ah, 09h
        lea dx, sum
        int 21h

        mov ah, 4ch
        int 21h
    main endp
    end main


Questo codice calcola la somma degli elementi di un array di numeri. Gli elementi dell’array sono memorizzati nella variabile arr e la lunghezza dell’array è memorizzata nella variabile arr_len. Il risultato della somma viene memorizzato nella variabile sum.

Piattaforma per programmare su macchine virtuali

Estensione per VSCode

Lezioni sul linguaggio C

Conclusioni

In questa lezione abbiamo fornito una panoramica del linguaggio Assembly 8086 e fornito un esempio di codice. L’Assembly 8086 è un linguaggio molto potente e flessibile, ma richiede una buona conoscenza dell’architettura hardware del computer. Questo linguaggio è spesso utilizzato per la programmazione di driver di dispositivi e altri software a basso livello.

Pubblicato da Carlo Contardi

Carlo Contardi, docente di informatica e sviluppatore Full Stack, condivide la sua passione per la programmazione e l’informatica attraverso il suo blog Space Coding. Offre preziosi consigli e soluzioni pratiche a chi vuole imparare a programmare o migliorare le proprie abilità. 🚀👨‍💻

Translate »