Linguaggio assembly

Un linguaggio di assemblaggio è un linguaggio di programmazione che può essere usato per dire direttamente al computer cosa fare. Un linguaggio assembly è quasi esattamente come il codice macchina che un computer può capire, tranne per il fatto che usa le parole al posto dei numeri. Un computer non può capire direttamente un programma di assemblaggio. Tuttavia, può facilmente cambiare il programma in codice macchina sostituendo le parole del programma con i numeri che rappresentano. Un programma che lo fa si chiama assemblatore.

I programmi scritti in linguaggio assembly sono di solito costituiti da istruzioni, che sono piccoli compiti che il computer esegue quando esegue il programma. Sono chiamate istruzioni perché il programmatore le usa per istruire il computer su cosa fare. La parte del computer che segue le istruzioni è il processore.

Il linguaggio di assemblaggio di un computer è un linguaggio di basso livello, il che significa che può essere utilizzato solo per eseguire i semplici compiti che un computer può comprendere direttamente. Per eseguire compiti più complessi, si deve dire al computer ciascuno dei semplici compiti che fanno parte del compito complesso. Per esempio, un computer non capisce come stampare una frase sul suo schermo. Invece, un programma scritto in montaggio deve dirgli come fare tutti i piccoli passi che sono coinvolti nella stampa della frase.

Un tale programma di assemblaggio sarebbe composto da molte, molte istruzioni, che insieme fanno qualcosa che sembra molto semplice e basilare per un umano. Questo rende difficile per gli umani leggere un programma di assemblaggio. Al contrario, un linguaggio di programmazione di alto livello può avere una singola istruzione come PRINT "Hello, world!" che dirà al computer di eseguire tutti i piccoli compiti per voi.

Sviluppo del linguaggio di assemblaggio

Quando gli informatici hanno costruito le prime macchine programmabili, le hanno programmate direttamente in codice macchina, che è una serie di numeri che insegnano al computer cosa fare. Il linguaggio delle macchine di scrittura era molto difficile da fare e richiedeva molto tempo, così alla fine è stato realizzato il linguaggio di assemblaggio. Il linguaggio assembly è più facile da leggere per un umano e può essere scritto più velocemente, ma è ancora molto più difficile da usare per un umano rispetto ad un linguaggio di programmazione di alto livello che cerca di imitare il linguaggio umano.

Programmazione in codice macchina

Per programmare in codice macchina, il programmatore deve conoscere l'aspetto di ogni istruzione in binario (o esadecimale). Anche se è facile per un computer capire rapidamente il significato del codice macchina, è difficile per un programmatore. Ogni istruzione può avere diverse forme, che per la gente assomigliano tutte ad un mucchio di numeri. Ogni errore che qualcuno commette mentre scrive codice macchina sarà notato solo quando il computer fa la cosa sbagliata. Capire l'errore è difficile perché la maggior parte delle persone non può dire cosa significhi il codice macchina guardandolo. Un esempio di come appare il codice macchina:

05 2A 00

Questo codice macchina esadecimale dice ad un processore x86 di aggiungere 42 all'accumulatore. È molto difficile per una persona leggerlo e capirlo anche se conosce il codice macchina.

Utilizzo del linguaggio di montaggio

Con il linguaggio di assemblaggio, ogni istruzione può essere scritta come una parola breve, chiamata mnemonica, seguita da altre cose come numeri o altre brevi parole. Il mnemonico è usato in modo che il programmatore non debba ricordare i numeri esatti in codice macchina necessari per dire al computer di fare qualcosa. Esempi di mnemonica nel linguaggio assembly includono add, che aggiunge dati, e mov, che sposta i dati da un luogo all'altro. Poiché "mnemonica" è una parola non comune, il tipo di istruzione della frase o solo l'istruzione è a volte usata al suo posto, spesso in modo errato. Le parole e i numeri dopo la prima parola danno maggiori informazioni su cosa fare. Per esempio, le cose che seguono un'aggiunta possono essere ciò che due cose da aggiungere insieme e le cose che seguono mov dicono cosa spostare e dove metterlo.

Ad esempio, il codice macchina nella sezione precedente (05 2A 00) può essere scritto nel montaggio come:

 aggiungere l'ascia,42

Il linguaggio di assemblaggio consente inoltre ai programmatori di scrivere i dati reali che il programma utilizza in modo più semplice. La maggior parte dei linguaggi di assemblaggio hanno il supporto per la creazione di numeri e testi in modo semplice. Nel codice macchina, ogni diverso tipo di numero, come positivo, negativo o decimale, dovrebbe essere convertito manualmente in binario e il testo dovrebbe essere definito una lettera alla volta, come numeri.

Il linguaggio assembly fornisce quella che viene chiamata astrazione del codice macchina. Quando si usa l'assembly, i programmatori non hanno bisogno di conoscere i dettagli di ciò che i numeri significano per il computer, l'assemblatore lo capisce invece. Il linguaggio assembly in realtà permette ancora al programmatore di usare tutte le caratteristiche del processore che potrebbe usare con il codice macchina. In questo senso, il linguaggio assembly ha una caratteristica molto buona e rara: ha la stessa capacità di esprimere le cose come la cosa che sta estraendo (codice macchina), ma è molto più facile da usare. Per questo motivo il codice macchina non viene quasi mai usato come linguaggio di programmazione.

Smontaggio e Debugging

Quando i programmi sono finiti, sono già stati trasformati in codice macchina in modo che il processore possa effettivamente eseguirli. A volte, tuttavia, se il programma presenta un bug (errore), i programmatori vorranno essere in grado di dire cosa sta facendo ogni parte del codice macchina. I disassemblatori sono programmi che aiutano i programmatori a farlo trasformando il codice macchina del programma di nuovo in linguaggio assembly, che è molto più facile da capire. I disassemblatori, che trasformano il codice macchina in linguaggio assembly, fanno l'opposto degli assemblatori, che trasformano il linguaggio assembly in codice macchina.

Organizzazione informatica

Una comprensione di come i computer sono organizzati, di come sembrano funzionare a un livello molto basso, è necessaria per capire come funziona un programma di linguaggio assembly. Al livello più semplicistico, i computer hanno tre parti principali:

  1. memoria principale o RAM che contiene dati e istruzioni,
  2. un processore, che elabora i dati eseguendo le istruzioni, e
  3. ingresso e uscita (a volte abbreviati in I/O), che permettono al computer di comunicare con il mondo esterno e di memorizzare i dati al di fuori della memoria principale in modo da poterli recuperare in seguito.

Memoria principale

Nella maggior parte dei computer, la memoria è suddivisa in byte. Ogni byte contiene 8 bit. Ogni byte in memoria ha anche un indirizzo che è un numero che dice dove si trova il byte in memoria. Il primo byte in memoria ha un indirizzo di 0, il successivo ha un indirizzo di 1, e così via. Dividere la memoria in byte la rende indirizzabile perché ogni byte ottiene un indirizzo univoco. Gli indirizzi delle memorie di byte non possono essere usati per riferirsi ad un singolo bit di un byte. Un byte è il più piccolo pezzo di memoria che può essere indirizzato.

Anche se un indirizzo si riferisce ad un particolare byte in memoria, i processori consentono di utilizzare più byte di memoria in fila. L'uso più comune di questa funzione è quello di utilizzare 2 o 4 byte di fila per rappresentare un numero, di solito un numero intero. I singoli byte sono talvolta utilizzati anche per rappresentare gli interi, ma poiché sono lunghi solo 8 bit, possono contenere solo 28 o 256 diversi valori possibili. L'uso di 2 o 4 byte in una riga aumenta il numero dei diversi valori possibili rispettivamente a 216, 65536 o 232, 4294967296.

Quando un programma usa un byte o un numero di byte in una riga per rappresentare qualcosa come una lettera, un numero o qualsiasi altra cosa, quei byte sono chiamati oggetti perché fanno tutti parte della stessa cosa. Anche se gli oggetti sono tutti memorizzati in byte di memoria identici, sono trattati come se avessero un 'tipo', che dice come i byte dovrebbero essere intesi: o come un intero o un carattere o qualche altro tipo (come un valore non intero). Anche il codice macchina può essere pensato come un tipo che viene interpretato come istruzioni. La nozione di tipo è molto, molto importante perché definisce ciò che si può e non si può fare all'oggetto e come interpretare i byte dell'oggetto. Per esempio, non è valido per memorizzare un numero negativo in un oggetto con numero positivo e non è valido per memorizzare una frazione in un numero intero.

Un indirizzo che punta a (è l'indirizzo di) un oggetto a più byte è l'indirizzo del primo byte di quell'oggetto - il byte che ha l'indirizzo più basso. A parte questo, una cosa importante da notare è che non si può dire quale sia il tipo di oggetto - o anche la sua dimensione - in base al suo indirizzo. Infatti, non si può nemmeno dire che tipo di oggetto sia un oggetto guardandolo. Un programma di linguaggio assembly deve tenere traccia di quali indirizzi della memoria contengono quali oggetti e quanto sono grandi. Un programma che lo fa è sicuro del tipo, perché fa cose sicure solo agli oggetti che sono sicuri di fare sul loro tipo. Un programma che non lo fa probabilmente non funzionerà correttamente. Si noti che la maggior parte dei programmi non memorizza esplicitamente il tipo di oggetto, ma si limita ad accedere agli oggetti in modo coerente - lo stesso oggetto viene sempre trattato come se fosse dello stesso tipo.

Il processore

Il processore esegue (esegue) le istruzioni, che vengono memorizzate come codice macchina nella memoria principale. Oltre ad essere in grado di accedere alla memoria per la memorizzazione, la maggior parte dei processori dispone di alcuni piccoli, veloci e fissi spazi per contenere gli oggetti con cui si sta lavorando. Questi spazi sono chiamati registri. I processori di solito eseguono tre tipi di istruzioni, anche se alcune istruzioni possono essere una combinazione di questi tipi. Di seguito sono riportati alcuni esempi di ogni tipo nel linguaggio di assemblaggio x86.

Istruzioni che leggono o scrivono la memoria

La seguente istruzione del linguaggio di assemblaggio x86 legge (carica) un oggetto a 2 byte dal byte all'indirizzo 4096 (0x1000 in esadecimale) in un registro a 16 bit chiamato 'ax':

        mov ax, [1000h]

In questo linguaggio di montaggio, le parentesi quadre attorno ad un numero (o ad un nome di registro) indicano che il numero deve essere utilizzato come indirizzo dei dati che devono essere utilizzati. L'uso di un indirizzo per indicare i dati si chiama indirezione. In questo esempio successivo, senza le parentesi quadre, un altro registro, bx, ottiene in realtà il valore 20 caricato in esso.

        mov bx, 20

Poiché non è stata utilizzata alcuna indirezione, il valore effettivo è stato messo nel registro.

Se gli operandi (le cose che vengono dopo il mnemonico), appaiono in ordine inverso, un'istruzione che carica qualcosa dalla memoria invece lo scrive in memoria:

        mov [1000h], asse

Qui, la memoria all'indirizzo 1000h ottiene il valore di ax. Se questo esempio viene eseguito subito dopo il precedente, i 2 byte a 1000h e 1001h saranno un intero di 2 byte con il valore di 20.

Istruzioni che eseguono operazioni matematiche o logiche

Alcune istruzioni fanno cose come la sottrazione o operazioni logiche come non fare:

L'esempio di codice macchina precedente in questo articolo sarebbe questo nel linguaggio assembly:

        aggiungere l'ascia, 42

Qui si sommano 42 e ax e il risultato viene memorizzato nuovamente in ax. Nel montaggio x86 è anche possibile combinare un accesso alla memoria e un'operazione matematica come questa:

        aggiungere l'asse, [1000h]

Questa istruzione aggiunge il valore dei 2 byte interi memorizzati a 1000h all'asse e memorizza la risposta in asse.

        o ascia, bx

Questa istruzione calcola il o del contenuto dei registri ax e bx e memorizza il risultato in ax.

Istruzioni che decidono quale sarà la prossima istruzione

Di solito le istruzioni vengono eseguite nell'ordine in cui appaiono in memoria, che è l'ordine in cui vengono digitate nel codice di assemblaggio. Il processore le esegue solo una dopo l'altra. Tuttavia, affinché i processori possano fare cose complicate, devono eseguire istruzioni diverse in base a quali sono i dati che gli sono stati dati. La capacità dei processori di eseguire istruzioni diverse a seconda del risultato di qualcosa si chiama ramificazione. Le istruzioni che decidono quale deve essere la prossima istruzione sono chiamate istruzioni di diramazione.

In questo esempio, supponiamo che qualcuno voglia calcolare la quantità di vernice di cui avrà bisogno per dipingere un quadrato con una certa lunghezza di lato. Tuttavia, a causa dell'economia di scala, il negozio di vernici non venderà meno della quantità di vernice necessaria per dipingere un quadrato di 100 x 100.

Per capire la quantità di vernice che dovranno ottenere in base alla lunghezza del quadrato che vogliono dipingere, escogitano questa serie di passi:

  • sottrarre 100 dalla lunghezza del lato
  • se la risposta è inferiore a zero, impostare la lunghezza del lato a 100
  • moltiplicare la lunghezza del lato per se stesso

Tale algoritmo può essere espresso nel seguente codice dove l'asse è la lunghezza del lato.

        mov bx, ax     sub bx, 100    jge continua   mov ax, 100 continua: mul ax

Questo esempio introduce diverse novità, ma le prime due istruzioni sono familiari. Copiano il valore dell'asse in bx e poi sottraggono 100 da bx.

Una delle novità di questo esempio si chiama etichetta, un concetto che si trova nei linguaggi di assemblaggio in generale. Le etichette possono essere qualsiasi cosa il programmatore voglia (a meno che non sia il nome di un'istruzione, che confonderebbe l'assemblatore). In questo esempio, l'etichetta è "continua". Viene interpretata dall'assemblatore come l'indirizzo di un'istruzione. In questo caso, è l'indirizzo di mult ax.

Un altro nuovo concetto è quello delle bandiere. Sui processori x86, molte istruzioni impostano dei 'flag' nel processore che possono essere usati dalle istruzioni successive per decidere cosa fare. In questo caso, se bx era inferiore a 100, sub imposterà un flag che dice che il risultato era inferiore a zero.

L'istruzione successiva è jge che è l'abbreviazione di 'Salta se maggiore o uguale a'. Si tratta di un'istruzione di ramo. Se i flag nel processore specificano che il risultato è stato maggiore o uguale a zero, invece di andare semplicemente all'istruzione successiva il processore salterà all'istruzione all'etichetta continua, che è mul ax.

Questo esempio funziona bene, ma non è quello che la maggior parte dei programmatori scriverebbe. L'istruzione sottrarre imposta correttamente il flag, ma modifica anche il valore su cui opera, il che richiede che l'asse sia copiato in bx. La maggior parte dei linguaggi di assemblaggio consentono istruzioni di confronto che non modificano nessuno degli argomenti che vengono passati, ma impostano comunque i flag correttamente e l'assemblaggio x86 non fa eccezione.

        asse cmp, 100 jge continua   mov ax, 100 continua: mul ax

Ora, invece di sottrarre 100 dall'asse, vedere se quel numero è inferiore a zero, ed assegnarlo di nuovo all'asse, l'asse viene lasciato invariato. Le bandiere sono ancora impostate allo stesso modo, e il salto è ancora preso nelle stesse situazioni.

Ingresso e uscita

Mentre l'input e l'output sono una parte fondamentale del calcolo, non c'è un solo modo in cui vengono fatti nel linguaggio assembly. Questo perché il modo in cui l'I/O funziona dipende dall'impostazione del computer e dal sistema operativo in funzione, non solo dal tipo di processore che ha. Nella sezione di esempio l'esempio di Hello World usa le chiamate al sistema operativo MS-DOS e l'esempio dopo le chiamate al BIOS.

E' possibile effettuare I/O nel linguaggio di assemblaggio. In effetti, il linguaggio assembly può generalmente esprimere tutto ciò che un computer è in grado di fare. Tuttavia, anche se ci sono istruzioni da aggiungere e diramare nel linguaggio assembly che faranno sempre la stessa cosa, non ci sono istruzioni nel linguaggio assembly che fanno sempre I/O.

La cosa importante da notare è che il modo in cui funziona l'I/O non fa parte di alcun linguaggio di assemblaggio perché non fa parte di come funziona il processore.

Lingue di montaggio e portabilità

Anche se il linguaggio di assemblaggio non è gestito direttamente dal processore - il codice macchina lo è, ha ancora molto a che fare con esso. Ogni famiglia di processori supporta diverse caratteristiche, istruzioni, regole per ciò che le istruzioni possono fare e regole per quale combinazione di istruzioni sono consentite dove. Per questo motivo, diversi tipi di processori hanno ancora bisogno di diversi linguaggi di assemblaggio.

Poiché ogni versione del linguaggio di assemblaggio è legata a una famiglia di processori, manca di qualcosa chiamato portabilità. Qualcosa che ha la portabilità o che è portatile può essere facilmente trasferito da un tipo di computer ad un altro. Mentre altri tipi di linguaggi di programmazione sono portatili, il linguaggio assembly, in generale, non lo è.

Linguaggio di montaggio e lingue di alto livello

Sebbene il linguaggio di assemblaggio consenta un modo semplice di utilizzare tutte le caratteristiche del processore, non viene utilizzato per i moderni progetti software per diversi motivi:

  • Ci vuole molto impegno per esprimere un programma semplice in fase di assemblaggio.
  • Anche se non così incline agli errori come il codice della macchina, il linguaggio di assemblaggio offre ancora una protezione molto limitata contro gli errori. Quasi tutti i linguaggi di assemblaggio non fanno rispettare la sicurezza del tipo.
  • Il linguaggio di assemblaggio non promuove buone pratiche di programmazione come la modularità.
  • Mentre ogni singola istruzione del linguaggio di assemblaggio è facile da capire, è difficile dire quale fosse l'intento del programmatore che l'ha scritto. Infatti, il linguaggio di assemblaggio di un programma è così difficile da capire che le aziende non si preoccupano che la gente smonti (ottenendo il linguaggio di assemblaggio) i loro programmi.

Come risultato di questi inconvenienti, per la maggior parte dei progetti vengono invece utilizzati linguaggi di alto livello come il Pascal, il C e il C++. Essi permettono ai programmatori di esprimere le loro idee in modo più diretto, invece di doversi preoccupare di dire al processore cosa fare in ogni fase del progetto. Sono chiamati di alto livello perché le idee che il programmatore può esprimere nella stessa quantità di codice sono più complicate.

I programmatori che scrivono codice in linguaggi compilati di alto livello utilizzano un programma chiamato compilatore per trasformare il loro codice in linguaggio assembly. I compilatori sono molto più difficili da scrivere di quanto lo siano gli assemblatori. Inoltre, i linguaggi di alto livello non sempre permettono ai programmatori di usare tutte le caratteristiche del processore. Questo perché i linguaggi di alto livello sono progettati per supportare tutte le famiglie di processori. A differenza dei linguaggi di assemblaggio, che supportano solo un tipo di processore, i linguaggi di alto livello sono portatili.

Anche se i compilatori sono più complicati degli assemblatori, decenni di produzione e ricerca di compilatori li ha resi molto buoni. Ora, non c'è più molta ragione di usare il linguaggio assembly per la maggior parte dei progetti, perché i compilatori di solito riescono a capire come esprimere i programmi anche in linguaggio assembly o meglio dei programmatori.

Esempi di programmi

Un programma di Hello World scritto nell'assemblea x86:

adosseg .model small .stack 100h .data hello_message db 'Hello, World! .code '0dh,0ah,0ah,'$' .code main proc mov ax,@data mov ds,ax mov ah,9 mov dx,offset hello_message int 21h mov ax,4C00h int 21h endp principale endp principale endp principale

Una funzione che stampa un numero sullo schermo usando gli interrupt del BIOS scritti nel montaggio NASM x86. È possibile scrivere codice modulare in assembly, ma ci vuole uno sforzo in più. Si noti che tutto ciò che viene dopo un punto e virgola su una linea è un commento e viene ignorato dall'assemblatore. Mettere commenti nel codice del linguaggio assembly è molto importante perché i grandi programmi del linguaggio assembly sono così difficili da capire.

; stampa nulla (numero int, int base int); stampa:   premere bp      muoviti bp, sp         Spingere       ascia   Spingere       bx      Spingere       cx      Spingere        dx      Spingere       si      muoviti si, 0   muoviti asse, [bp + 4] ; numero         muoviti cx, [bp + 6]   ; base gloop:  inc     si             lunghezza della stringa        muoviti dx, 0          zero dx        div     cx             Dividere per base    cmp     dx, 10         è il 10?       jge     num     aggiungi       dx, '0          aggiungere zero a dx   jmp     anum num:      aggiungi       dx, ('A'- 10)        valore esadecimale, aggiungere 'A' a dx - 10. anum:   premere dx              Mettete dx sulla pila.         cmp     ascia, 0               Dobbiamo continuare?    jne     gloop   muoviti bx, 7h         per l'interruzione del ciclo:  pop        ascia          ottenere il suo valore         muoviti ah, 0eh        per l'interruzione int     10h            scrivere il carattere dicembre       si              Sbarazzarsi del carattere      jnz     tloop  pop     si      pop     dx      pop        cx      pop     bx      pop     ascia   pop     bp      ret     4

Domande e risposte

D: Che cos'è un linguaggio assembly?


R: Un linguaggio assembly è un linguaggio di programmazione che può essere usato per dire direttamente al computer cosa fare. È quasi identico al codice macchina che un computer è in grado di comprendere, tranne per il fatto che utilizza parole al posto dei numeri.

D: Come fa un computer a capire un programma assembly?


R: Un computer non può capire direttamente un programma di assemblaggio, ma può facilmente trasformare il programma in codice macchina, sostituendo le parole del programma con i numeri che rappresentano. Questo processo viene eseguito con un assemblatore.

D: Cosa sono le istruzioni in un linguaggio assembly?


R: Le istruzioni in un linguaggio assembly sono piccoli compiti che il computer esegue durante l'esecuzione del programma. Si chiamano istruzioni perché istruiscono il computer su cosa fare. La parte del computer responsabile di seguire queste istruzioni si chiama processore.

D: Che tipo di linguaggio di programmazione è l'assembly?


R: Il linguaggio assembly è un linguaggio di programmazione di basso livello, il che significa che può essere utilizzato solo per svolgere compiti semplici che un computer può comprendere direttamente. Per eseguire compiti più complessi, è necessario scomporre ogni compito nei suoi singoli componenti e fornire istruzioni per ogni componente separatamente.

D: In cosa differisce dai linguaggi di alto livello?


R: I linguaggi di alto livello possono avere singoli comandi, come PRINT "Hello, world!", che indicheranno al computer di eseguire automaticamente tutti i piccoli compiti, senza doverli specificare singolarmente come si dovrebbe fare con un programma assembly. Questo rende i linguaggi di alto livello più facili da leggere e comprendere per gli esseri umani, rispetto ai programmi di assemblaggio composti da molte istruzioni individuali.

D: Perché potrebbe essere difficile per l'uomo leggere un programma di assemblaggio?


R: Perché devono essere specificate molte istruzioni individuali per svolgere un compito complesso, come la stampa di qualcosa sullo schermo o l'esecuzione di calcoli su serie di dati - cose che sembrano molto basilari e semplici quando vengono espresse nel linguaggio umano naturale - quindi ci possono essere molte righe di codice che compongono un'istruzione, il che rende difficile per gli esseri umani, che non conoscono il funzionamento interno dei computer a un livello così basso, seguire e interpretare ciò che sta accadendo al loro interno.

AlegsaOnline.com - 2020 / 2023 - License CC3