Programma in linguaggio assembly. Caratteristiche generali del sistema di comando del linguaggio Assembler per PC IBM (insieme base di comandi, modalità fondamentali di indirizzamento degli operandi). La struttura del programma in linguaggio Assembler. Comandi in linguaggio assembly

informazioni generali sul linguaggio assembly

Il linguaggio assembly simbolico consente di eliminare in gran parte le carenze della programmazione in linguaggio macchina.

Il suo vantaggio principale è che nel linguaggio assembly tutti gli elementi del programma sono rappresentati in forma simbolica. La trasformazione dei nomi simbolici dei comandi nei loro codici binari è responsabilità di programma speciale- assembler, che libera il programmatore dal lavoro faticoso ed elimina gli inevitabili errori.

I nomi simbolici introdotti durante la programmazione in linguaggio assembly, di regola, riflettono la semantica del programma e l'abbreviazione dei comandi è la loro funzione principale. Ad esempio: PARAM - parametro, TABLE - tabella, MASK - maschera, ADD - addizione, SUB - sottrazione, ecc. n. Tali nomi sono facilmente ricordabili dal programmatore.

Per programmare in linguaggio assembly è necessario disporre di strumenti più complessi che per programmare in linguaggio macchina: occorrono sistemi informatici basati su microcomputer o PC dotati di un set periferiche(tastiera alfanumerica, display a caratteri, floppy disk e stampante), nonché sistemi residenti o di programmazione incrociata per le tipologie di microprocessori richieste. Il linguaggio assembly consente di scrivere ed eseguire il debug in modo efficiente di programmi molto più complessi rispetto al linguaggio macchina (fino a 1 - 4 KB).

I linguaggi assembly sono orientati alla macchina, cioè dipendenti dal linguaggio macchina e dalla struttura del microprocessore corrispondente, poiché assegnano un nome simbolico specifico a ciascuna istruzione del microprocessore.

I linguaggi assembly forniscono un aumento significativo della produttività dei programmatori rispetto ai linguaggi macchina e allo stesso tempo mantengono la capacità di utilizzare tutte le risorse hardware del microprocessore accessibili dal software. Ciò consente ai programmatori esperti di scrivere programmi che vengono eseguiti in più di poco tempo e occupando meno memoria rispetto ai programmi scritti in un linguaggio di alto livello.

A questo proposito, quasi tutti i programmi di controllo dei dispositivi I/O (driver) sono scritti in linguaggio assembly, nonostante la presenza di una gamma abbastanza ampia di linguaggi di alto livello.

Utilizzando il linguaggio assembly, il programmatore può impostare i seguenti parametri:

mnemonico (nome simbolico) di ogni comando del linguaggio macchina del microprocessore;

formato standard per le righe di un programma descritto in assembler;

formato per specificare vari modi opzioni di indirizzamento e comando;

formato per specificare costanti di carattere e costanti di tipo intero in vari sistemi numerici;

pseudo-comandi che controllano il processo di assemblaggio (traduzione) del programma.

Nel linguaggio assembly il programma viene scritto riga per riga, ovvero per ogni istruzione viene assegnata una riga.

Per i microcomputer costruiti sulla base dei tipi più comuni di microprocessori, possono esserci diverse varianti del linguaggio assembly, tuttavia, di solito c'è una distribuzione pratica: questo è il cosiddetto linguaggio assembly standard

La programmazione a livello delle istruzioni macchina è il livello minimo al quale è possibile la programmazione. Il sistema di istruzioni della macchina deve essere sufficiente per implementare le azioni richieste impartendo istruzioni all'hardware del computer.

Ogni istruzione macchina è composta da due parti:

operativo: determinare "cosa fare";

· operando - definizione degli oggetti di elaborazione, "cosa fare con".

L'istruzione macchina del microprocessore, scritta in linguaggio assembly, è una riga singola con la seguente forma sintattica:

etichetta comando/direttiva operando(i) ;commenti

In questo caso, un campo obbligatorio in una riga è un comando o una direttiva.

L'etichetta, il comando/direttiva e gli operandi (se presenti) sono separati da almeno uno spazio o un carattere di tabulazione.

Se è necessario continuare un comando o una direttiva nella riga successiva, viene utilizzato il carattere barra rovesciata: \.

Per impostazione predefinita, il linguaggio assembly non distingue tra lettere maiuscole e minuscole nei comandi o nelle direttive.

Indirizzamento diretto: L'indirizzo effettivo è determinato direttamente dal campo offset dell'istruzione macchina, che può avere dimensioni di 8, 16 o 32 bit.

mov eax, somma; eax = somma

L'assembler sostituisce sum con l'indirizzo corrispondente memorizzato nel segmento dati (per impostazione predefinita, indirizzato dal registro ds) e inserisce il valore memorizzato nell'indirizzo sum nel registro eax.

indirizzamento indiretto a sua volta ha le seguenti tipologie:

Indirizzamento di base indiretto (registro);

Indirizzamento di base indiretto (registro) con offset;

· indirizzamento indicizzato indiretto;

· indirizzamento indiretto dell'indice di base.

Indirizzamento di base indiretto (registro). Con questo indirizzamento, l'indirizzo effettivo dell'operando può trovarsi in uno qualsiasi dei registri di uso generale, ad eccezione di sp / esp e bp / ebp (questi sono registri specifici per lavorare con un segmento dello stack). Sintatticamente in un'istruzione questa modalità di indirizzamento viene espressa racchiudendo il nome del registro tra parentesi quadre.

mov eax, ; eax = *esi; *valore esi all'indirizzo esi

Introduzione.

Viene chiamata la lingua in cui è scritto il programma originale ingresso lingua e la lingua in cui viene tradotto per l'esecuzione da parte del responsabile del trattamento - fine settimana lingua. Viene chiamato il processo di conversione di una lingua di input in una lingua di output trasmissione. Poiché i processori sono in grado di eseguire programmi in linguaggio macchina binario, che non viene utilizzato per la programmazione, è necessaria la traduzione di tutti i programmi sorgente. conosciuto due strade traduzioni: compilazione e interpretazione.

A compilazione il programma sorgente viene prima tradotto completamente in un programma equivalente nella lingua di destinazione, chiamato oggetto programma e poi eseguito. Questo processo viene eseguito utilizzando uno speciale programmi, chiamato compilatore. Viene chiamato un compilatore per il quale il linguaggio di input è una rappresentazione simbolica del linguaggio macchina (di output) dei codici binari assemblatore.

A interpretazioni ogni riga di testo del programma sorgente viene analizzata (interpretata) e il comando in essa specificato viene immediatamente eseguito. L'implementazione di questo metodo spetta a programma interprete. L'interpretazione richiede molto tempo. Per aumentare la propria efficienza, invece di elaborare ogni riga, l'interprete le converte preliminarmente tutte comando stringhe in caratteri (

). La sequenza di simboli generata viene utilizzata per eseguire le funzioni assegnate al programma originale.

Il linguaggio assembly discusso di seguito viene implementato utilizzando la compilazione.

Caratteristiche della lingua.

Le caratteristiche principali dell'assemblatore:

● invece dei codici binari, il linguaggio utilizza nomi simbolici - mnemonici. Ad esempio, per il comando di addizione (

) viene utilizzato il mnemonico

Sottrazioni (

moltiplicazione (

Divisioni (

ecc. I nomi simbolici vengono utilizzati anche per indirizzare le celle di memoria. Per programmare in linguaggio assembly, invece che codici e indirizzi binari, è necessario conoscere solo i nomi simbolici che l'assembler traduce in codici binari;

ogni affermazione corrisponde un comando della macchina(codice), cioè esiste una corrispondenza biunivoca tra le istruzioni della macchina e gli operatori in un programma in linguaggio assembly;

● la lingua fornisce l'accesso a tutti gli oggetti e squadre. I linguaggi di alto livello non hanno questa capacità. Ad esempio, il linguaggio assembly consente di controllare un bit di registro flag e un linguaggio di alto livello (ad esempio,

) non ha questa capacità. Si noti che i linguaggi per la programmazione dei sistemi (ad esempio C) occupano spesso una posizione intermedia. In termini di accessibilità sono più vicini al linguaggio assembly, ma hanno la sintassi di un linguaggio di alto livello;

● linguaggio assembly non è una lingua universale. Ogni gruppo specifico di microprocessori ha il proprio assemblatore. I linguaggi di alto livello non presentano questo svantaggio.

A differenza dei linguaggi di alto livello, la scrittura e il debug di un programma in linguaggio assembly richiedono molto tempo. Nonostante ciò, il linguaggio assembly è diventato ampio utilizzo a causa delle seguenti circostanze:

● Un programma scritto in linguaggio assembly è molto più piccolo e molto più veloce di un programma scritto in un linguaggio di alto livello. Per alcune applicazioni questi indicatori svolgono un ruolo primario, ad esempio molti programmi di sistema (compresi i compilatori), programmi di carte di credito, telefono cellulare, driver di dispositivo, ecc.;

● alcune procedure richiedono accesso completo all'hardware, cosa che di solito non è possibile in un linguaggio di alto livello. Questo caso include gli interrupt e i gestori degli interrupt nei sistemi operativi, nonché i controller dei dispositivi nei sistemi embedded in tempo reale.

Nella maggior parte dei programmi, solo una piccola percentuale del codice totale è responsabile di gran parte del tempo di esecuzione del programma. In genere, l'1% del programma è responsabile del 50% del tempo di esecuzione e il 10% del programma è responsabile del 90% del tempo di esecuzione. Pertanto, per scrivere un programma specifico in condizioni reali, vengono utilizzati sia l'assembler che uno dei linguaggi di alto livello.

Formato operatore in linguaggio assembly.

Un programma in linguaggio assembly è un elenco di comandi (istruzioni, frasi), ciascuno dei quali occupa una riga separata e contiene quattro campi: un campo etichetta, un campo operazione, un campo operando e un campo commento. Ogni campo ha una colonna separata.

Campo etichetta.

Al campo etichetta è assegnata la colonna 1. Un'etichetta è un nome simbolico, o identificatore, indirizzi memoria. E' necessario per poter:

● effettuare una transizione condizionale o incondizionata al comando;

● ottenere l'accesso al luogo in cui sono archiviati i dati.

Tali affermazioni sono etichettate. Per designare il nome vengono utilizzate lettere Xia (maiuscole) dell'alfabeto inglese e numeri. Il nome deve iniziare con una lettera e terminare con i due punti. L'etichetta dei due punti può essere scritta su una riga separata e il codice operativo può essere scritto sulla riga successiva nella colonna 2, il che semplifica il lavoro del compilatore. L'assenza dei due punti rende impossibile distinguere tra un'etichetta e un codice operativo se si trovano su righe separate.

In alcune versioni del linguaggio assembly, i due punti vengono posizionati solo dopo le etichette delle istruzioni, non dopo le etichette dei dati, e la lunghezza dell'etichetta può essere limitata a 6 o 8 caratteri.

Il campo etichetta non deve contenere gli stessi nomi, poiché l'etichetta è associata agli indirizzi dei comandi. Se durante l'esecuzione del programma non è necessario richiamare un comando o dati dalla memoria, il campo etichetta rimane vuoto.

Campo codice transazione.

Questo campo contiene il comando mnemonico o pseudo-comando (vedi sotto). Il codice mnemonico del comando viene scelto dai progettisti del linguaggio. Nel linguaggio assembly

mnemonico selezionato per caricare il registro dalla memoria

), e per memorizzare il contenuto del registro in memoria - il mnemonico

). Nei linguaggi assembly

è possibile utilizzare lo stesso nome rispettivamente per entrambe le operazioni

Se la scelta dei nomi mnemonici può essere arbitraria, allora la necessità di utilizzare due istruzioni macchina è dovuta all'architettura del processore

I mnemonici dei registri dipendono anche dalla versione dell'assembler (Tabella 5.2.1).

Campo dell'operando.

Qui si trova Informazioni aggiuntive necessari per eseguire l'operazione. Nel campo degli operandi per le istruzioni di salto viene indicato l'indirizzo in cui si desidera saltare, nonché gli indirizzi e i registri che sono operandi per l'istruzione macchina. Ad esempio, ecco gli operandi che possono essere utilizzati per i processori a 8 bit

● dati numerici,

presentati in diversi sistemi numerici. Per indicare il sistema numerico utilizzato, una costante è seguita da uno di Lettere latine: IN,

Di conseguenza, i sistemi numerici binari, ottali, esadecimali e decimali (

potrebbe non essere registrato). Se la prima cifra del numero esadecimale è A, B, C,

Quindi viene aggiunto uno 0 (zero) insignificante davanti;

● codici dei registri interni del microprocessore e delle celle di memoria

M (fonti o destinatari di informazioni) sotto forma di lettere A, B, C,

M o i loro indirizzi in qualsiasi sistema numerico (ad esempio, 10V - indirizzo di registro

nel sistema binario);

● identificatori,

per le coppie di aeromobili registrati,

Le prime lettere B

H; per una coppia di accumulatori e registri di funzioni -

; per il contatore del programma -

; per il puntatore dello stack -

● etichette che indicano gli indirizzi degli operandi o le istruzioni successive in modo condizionale

(quando la condizione è soddisfatta) e transizioni incondizionate. Ad esempio, l'operando M1 nel comando

indica la necessità di una transizione incondizionata al comando, il cui indirizzo nel campo dell'etichetta è contrassegnato con l'identificatore M1;

● espressioni,

che sono costruiti collegando i dati discussi sopra utilizzando operatori aritmetici e logici. Tieni presente che il modo in cui lo spazio dati viene riservato dipende dalla versione della lingua. Sviluppatori di linguaggio assembly per

Definire parola), e successivamente introdotto Opzione alternativa.

che fin dall'inizio era nel linguaggio dei processori

Nella versione linguistica

usato

definire una costante).

I processori elaborano operandi di diversa lunghezza. Per definirlo, gli sviluppatori assemblatori hanno preso diverse decisioni, ad esempio:

II registri di diversa lunghezza hanno nomi diversi: EAX - per posizionare operandi a 32 bit (tipo

); AX - per 16 bit (tipo

e AN - per 8 bit (tipo

● per i processori

i suffissi vengono aggiunti a ciascun codice operativo: suffisso

Per tipo

; suffisso ".B" per il tipo

per operandi di diversa lunghezza vengono utilizzati codici operativi diversi, ad esempio per caricare un byte, una mezza parola (

) e le parole nel registro a 64 bit utilizzano codici operativi

rispettivamente.

Campo commenti.

Questo campo fornisce spiegazioni sulle azioni del programma. I commenti non influenzano il funzionamento del programma e sono destinati a una persona. Potrebbero essere necessari per modificare un programma che, senza tali commenti, potrebbe risultare del tutto incomprensibile anche ai programmatori esperti. Un commento inizia con un carattere e viene utilizzato per spiegare e documentare i programmi. Il carattere iniziale di un commento può essere:

● punto e virgola (;) nelle lingue destinate ai responsabili del trattamento dell'azienda

Punto esclamativo(!) nelle lingue per

Ogni riga separata riservata a un commento è preceduta da un carattere iniziale.

Pseudo comandi (direttive).

Nel linguaggio assembly si possono distinguere due tipi principali di comandi:

di base istruzioni equivalenti al codice macchina del processore. Questi comandi eseguono tutte le elaborazioni previste dal programma;

pseudo-comandi O direttive, progettato per servire il processo di traduzione del programma nel linguaggio delle combinazioni di codici. Ad esempio, nella tabella. 5.2.2 mostra alcuni pseudo-comandi dell'assembler

per la famiglia

.

Durante la programmazione ci sono situazioni in cui, secondo l'algoritmo, la stessa catena di comandi deve essere ripetuta più volte. Per uscire da questa situazione puoi:

● scrivere la sequenza di comandi desiderata ogni volta che si verifica. Questo approccio porta ad un aumento del volume del programma;

● organizzare questa sequenza in una procedura (subroutine) e richiamarla se necessario. Tale uscita ha i suoi svantaggi: ogni volta è necessario eseguire un'istruzione di chiamata di procedura speciale e un'istruzione di ritorno che, con una sequenza breve e utilizzata frequentemente, possono ridurre notevolmente la velocità del programma.

Il più semplice e metodo efficaceè usare la ripetizione ripetuta di una catena di comandi macro, che può essere pensato come uno pseudo-comando progettato per ritradurre un gruppo di comandi incontrati frequentemente in un programma.

Una macro, o istruzione macro, è caratterizzata da tre aspetti: definizione macro, inversione macro ed espansione macro.

definizione macro

Questa è una designazione per una sequenza ripetuta ripetutamente di comandi di programma, utilizzata come riferimento nel testo del programma.

Una macro ha la seguente struttura:

Elenco delle espressioni; definizione macro

Ci sono tre parti nella struttura della definizione macro di cui sopra:

● intestazione

macro contenente il nome

Pseudo-comando

e una serie di parametri;

● punteggiato corpo macro;

● squadra

la laurea

definizioni macro.

Un set di parametri macro contiene un elenco di tutti i parametri forniti nel campo dell'operando per il gruppo di istruzioni selezionato. Se questi parametri vengono forniti in precedenza nel programma, possono essere omessi nell'intestazione della definizione della macro.

Per ricomporre il gruppo di istruzioni selezionato viene utilizzata una chiamata, composta dal nome

elenco macro e parametri con altri valori.

Quando l'assemblatore incontra una definizione di macro durante la compilazione, la memorizza nella tabella delle definizioni di macro. Con successive apparizioni nel programma del nome (

) di una macro, l'assembler lo sostituisce con il corpo della macro.

Viene chiamato l'utilizzo di un nome macro come codice operativo macro-inversione(chiamata macro) e la sua sostituzione con il corpo della macro - espansione macro.

Se il programma viene rappresentato come una sequenza di caratteri (lettere, numeri, spazi, punteggiatura e ritorni a capo per passare a una nuova riga), l'espansione della macro consiste nel sostituire alcune stringhe di questa sequenza con altre stringhe.

L'espansione delle macro avviene durante il processo di assemblaggio, non durante l'esecuzione del programma. A cui sono assegnati i modi per manipolare stringhe di caratteri strumenti macro.

Viene eseguito il processo di assemblaggio in due passaggi:

● Al primo passaggio, tutte le definizioni delle macro vengono mantenute e le chiamate delle macro vengono espanse. In questo caso, il programma sorgente viene letto e convertito in un programma in cui tutte le definizioni di macro vengono rimosse e ogni chiamata di macro viene sostituita da un corpo di macro;

● Il secondo passaggio elabora il programma ricevuto senza macro.

Macro con parametri.

Per lavorare con sequenze ripetute di comandi, i cui parametri possono assumere valori diversi, vengono fornite le definizioni delle macro:

● con effettivo parametri che vengono inseriti nel campo dell'operando della chiamata macro;

● con formale parametri. Durante l'espansione della macro, ogni parametro formale che appare nel corpo della macro viene sostituito dal corrispondente parametro effettivo.

utilizzando macro con parametri.

Il programma 1 mostra due sequenze simili di comandi, che differiscono per il fatto che la prima scambia P e

E il secondo

Il programma 2 include una macro con due parametri formali P1 e P2. Durante l'espansione della macro, ogni carattere P1 all'interno del corpo della macro viene sostituito dal primo parametro attuale (P,

), e il simbolo P2 viene sostituito dal secondo parametro attuale (

) dal programma n. 1. In una chiamata macro

il programma 2 è contrassegnato: P,

Il primo parametro effettivo,

Il secondo parametro effettivo.

Programma 1

Programma 2

MOV EBX,Q MOV EAX,Pl

MOV Q,EAX MOV EBX,P2

MOV P,EBX MOV P2,EAX

Funzionalità estese.

Considera alcune funzionalità avanzate del linguaggio

Se una macro contenente un'istruzione di salto condizionale e un'etichetta a cui saltare viene chiamata due o più volte, l'etichetta verrà duplicata (problema di duplicazione dell'etichetta), causando un errore. Pertanto ad ogni chiamata viene assegnata (dal programmatore) un'etichetta separata come parametro. Nella lingua

l'etichetta è dichiarata locale (

) e grazie alle funzionalità avanzate, l'assemblatore genera automaticamente un'etichetta diversa ogni volta che la macro viene espansa.

consente di definire macro all'interno di altre macro. Questa funzionalità avanzata è molto utile se combinata con il collegamento condizionale del programma. Prendere in considerazione

SE PAROLE GT 16 M2 MACRO

La macro M2 può essere definita in entrambe le parti della dichiarazione

Tuttavia, la definizione dipende dal fatto che il programma venga assemblato su un processore a 16 o 32 bit. Se M1 non viene chiamata, la macro M2 non verrà affatto definita.

Un'altra funzionalità avanzata è che le macro possono chiamare altre macro, incluse se stesse: ricorsivo chiamata. In quest’ultimo caso, per evitare un loop infinito, la macro deve passarsi un parametro, che cambia ad ogni espansione, e anche controllo questo parametro e termina la ricorsione quando il parametro raggiunge un determinato valore.

Sull'uso delle macro in assembler.

Quando si utilizzano le macro, l'assemblatore deve essere in grado di svolgere due funzioni: salvare le definizioni delle macro E espandere le chiamate macro.

Salvataggio delle definizioni delle macro.

Tutti i nomi delle macro vengono memorizzati in una tabella. Ogni nome è accompagnato da un puntatore alla macro corrispondente in modo da poterla richiamare in caso di necessità. Alcuni assemblatori hanno una tabella separata per i nomi delle macro, altri hanno una tabella comune in cui, insieme ai nomi delle macro, ci sono tutti i comandi e le direttive della macchina.

Quando si incontra una macro durante l'assemblaggio creato:

nuovo elemento della tabella con il nome della macro, il numero di parametri e un puntatore a un'altra tabella di definizione della macro in cui verrà memorizzato il corpo della macro;

● elenco formale parametri.

Il corpo della macro, che è semplicemente una stringa di caratteri, viene quindi letto e memorizzato nella tabella di definizione della macro. I parametri formali che si verificano nel corpo del ciclo sono contrassegnati carattere speciale.

Rappresentazione interna di una macro

dall'esempio precedente per il programma 2 (p. 244) è:

MOV EAX, MOV EBX, MOV MOV e

dove il punto e virgola viene utilizzato come carattere di ritorno a capo e la e commerciale & viene utilizzata come carattere di parametro formale.

Estensione di chiamata macro.

Ogni volta che viene incontrata una definizione di macro durante l'assemblaggio, viene memorizzata nella tabella delle macro. Quando viene richiamata una macro, l'assembler sospende temporaneamente la lettura dei dati di input dal dispositivo di input e inizia a leggere il corpo della macro salvata. I parametri formali estratti dal corpo della macro vengono sostituiti dai parametri effettivi e forniti dalla chiamata. Una e commerciale & davanti ai parametri consente all'assemblatore di riconoscerli.

Sebbene esistano molte versioni di assembler, i processi di assemblaggio hanno caratteristiche comuni e sono simili sotto molti aspetti. Di seguito viene considerato il lavoro di un assemblatore a due passaggi.

Assemblatore a due passaggi.

Il programma è composto da una serie di istruzioni. Pertanto, sembrerebbe che durante l'assemblaggio sia possibile utilizzare la seguente sequenza di azioni:

● tradurlo in linguaggio macchina;

● trasferire il codice macchina ricevuto in un file e la parte corrispondente dell'elenco in un altro file;

● ripetere le procedure sopra descritte fino alla trasmissione dell'intero programma.

Tuttavia, questo approccio non è efficiente. Un esempio è il cosiddetto problema collegamento principale. Se la prima istruzione è un salto all'istruzione P alla fine del programma, l'assemblatore non può tradurla. Deve prima determinare l'indirizzo dell'operatore P, e per questo è necessario leggere l'intero programma. Viene richiamata ogni lettura completa del programma originale passaggio. Mostriamo come possiamo risolvere il problema del riferimento diretto utilizzando due passaggi:

al primo passaggio raccogliere e memorizzare tutte le definizioni dei simboli (comprese le etichette) nella tabella e, al secondo passaggio, leggere e assemblare ciascun operatore. Questo metodo è relativamente semplice, ma il secondo passaggio del programma originale richiede tempo I/O aggiuntivo;

● al primo passaggio, convertire programma in una forma intermedia e lo salva in una tabella, e il secondo passaggio viene eseguito non secondo il programma originale, ma secondo la tabella. Questo metodo di assemblaggio consente di risparmiare tempo poiché non vengono eseguite operazioni di I/O nel secondo passaggio.

Primo passaggio.

Scopo del primo passaggio- costruire una tabella dei simboli. Come notato in precedenza, un altro obiettivo del primo passaggio è salvare tutte le definizioni delle macro ed espandere le chiamate man mano che appaiono. Pertanto, sia la definizione del carattere che l'espansione della macro avvengono nello stesso passaggio. Il simbolo può essere uno dei due etichetta, O Senso, a cui viene assegnato un nome specifico utilizzando la direttiva -you:

;Valore: dimensione del buffer

Dando un significato ai nomi simbolici nel campo etichetta dell'istruzione, l'assemblatore imposta in sostanza gli indirizzi che ogni istruzione avrà durante l'esecuzione del programma. Per fare ciò, l'assemblatore salva durante il processo di assemblaggio contatore dell'indirizzo dell'istruzione(

) come variabile speciale. All'inizio del primo passaggio, il valore della variabile speciale viene impostato su 0 e incrementato dopo ogni comando elaborato della lunghezza di quel comando. Ad esempio, nella tabella. 5.2.3 mostra un frammento del programma che indica la lunghezza dei comandi e i valori dei contatori. Le tabelle vengono generate durante il primo passaggio nomi di simboli, direttive E codici operativi, e se necessario letterale tavolo. Un valore letterale è una costante per la quale l'assemblatore riserva automaticamente memoria. Notiamo subito che i processori moderni contengono istruzioni con indirizzi diretti, quindi i loro assemblatori non supportano i letterali.

Tabella dei simboli

contiene un elemento per ciascun nome (Tabella 5.2.4). Ogni elemento della tabella dei simboli contiene il nome stesso (o un puntatore ad esso), il suo valore numerico e talvolta alcune informazioni aggiuntive, che possono includere:

● la lunghezza del campo dati associato al simbolo;

● bit di rimappatura della memoria (che indicano se il valore di un simbolo cambia se il programma viene caricato ad un indirizzo diverso da quello previsto dall'assemblatore);

● informazioni sulla possibilità di accesso al simbolo dall'esterno della procedura.

I nomi simbolici sono etichette. Possono essere specificati utilizzando gli operatori (ad esempio,

Tabella delle direttive.

Questa tabella elenca tutte le direttive, o pseudo-comandi, che si verificano durante l'assemblaggio di un programma.

Tabella dei codici operazione.

Per ciascun codice operativo, la tabella ha colonne separate: designazione del codice operativo, operando 1, operando 2, valore esadecimale del codice operativo, lunghezza dell'istruzione e tipo di istruzione (Tabella 5.2.5). I codici operazione sono divisi in gruppi a seconda del numero e del tipo di operandi. Il tipo di comando determina il numero del gruppo e specifica la procedura richiamata per elaborare tutti i comandi in quel gruppo.

Secondo passaggio.

Scopo del secondo passaggio- creare un programma oggetto e stampare, se necessario, un protocollo assembly; informazioni di output necessarie al linker per collegare procedure assemblate in momenti diversi in un unico file eseguibile.

Nel secondo passaggio (come nel primo), le righe contenenti le istruzioni vengono lette ed elaborate una dopo l'altra. L'operatore originale e l'output da esso derivato in formato esadecimale oggetto il codice può essere stampato o memorizzato nel buffer per la stampa successiva. Dopo aver reimpostato il contatore dell'indirizzo del comando, viene richiamato il comando successiva affermazione.

Il programma originale può contenere errori, ad esempio:

il simbolo dato non è definito o definito più di una volta;

● L'opcode è rappresentato da un nome non valido (a causa di un errore di battitura), non è dotato di sufficienti operandi o ha troppi operandi;

● nessun operatore

Alcuni assemblatori potrebbero rilevare un simbolo non definito e sostituirlo. Tuttavia, nella maggior parte dei casi, quando viene rilevata un'istruzione con un errore, l'assemblatore visualizza un messaggio di errore sullo schermo e tenta di continuare il processo di assemblaggio.

Articoli dedicati al linguaggio assembly.

Argomento 2.5 Nozioni di base sulla programmazione del processore

All'aumentare della lunghezza del programma diventa più difficile ricordare i codici delle varie operazioni. I mnemonici forniscono un aiuto in questo senso.

Viene chiamato il linguaggio di codifica delle istruzioni simboliche assemblatore.

linguaggio assemblyè un linguaggio in cui ogni istruzione corrisponde esattamente ad un'istruzione macchina.

Assemblea chiamata conversione di un programma dal linguaggio assembly, cioè preparazione di un programma in linguaggio macchina sostituendo nomi simbolici di operazioni con codici macchina e indirizzi simbolici con numeri assoluti o relativi, nonché includendo programmi di libreria e generando sequenze di istruzioni simboliche specificando parametri specifici nelle microistruzioni. Questo programma solitamente inserito nella ROM o inserito nella RAM da un supporto esterno.

Il linguaggio assembly ha diverse caratteristiche che lo distinguono dai linguaggi di alto livello:

1. Questa è una corrispondenza biunivoca tra le istruzioni in linguaggio assembly e le istruzioni macchina.

2. Il programmatore in linguaggio assembly ha accesso a tutti gli oggetti e comandi presenti sulla macchina di destinazione.

La comprensione delle basi della programmazione nei linguaggi orientati alla macchina è utile per:



Migliore comprensione dell'architettura dei PC e migliore utilizzo dei computer;

Sviluppare strutture più razionali di algoritmi per programmi per la risoluzione di problemi applicati;

La possibilità di visualizzare e correggere programmi eseguibili con estensione .exe e .com, compilati da qualsiasi linguaggio di alto livello, in caso di perdita dei programmi sorgente (richiamando questi programmi nel debugger del programma DEBUG e decompilando la loro visualizzazione in linguaggio assembly );

Compilazione di programmi per risolvere i compiti più critici (un programma compilato in un linguaggio orientato alla macchina è solitamente più efficiente - più breve e più veloce del 30-60% rispetto ai programmi ottenuti come risultato della traduzione da linguaggi di alto livello)

Per l'implementazione delle procedure incluse nel programma principale come frammenti separati nel caso in cui non possano essere implementate né nel linguaggio di alto livello utilizzato né utilizzando le procedure di servizio del sistema operativo.

Un programma in linguaggio assembly può essere eseguito solo su computer della stessa famiglia, mentre un programma scritto in un linguaggio di alto livello può potenzialmente essere eseguito su macchine diverse.

L'alfabeto del linguaggio assembly è composto da caratteri ASCII.

I numeri sono solo numeri interi. Distinguere:

Numeri binari che terminano con la lettera B;

Numeri decimali che terminano con D;

Numeri esadecimali che terminano con la lettera N.

RAM, registri, rappresentazione dei dati

Per una certa serie di parlamentari viene utilizzato un linguaggio di programmazione individuale: il linguaggio assembly.

Il linguaggio assembly occupa una posizione intermedia tra i codici macchina e i linguaggi di alto livello. La programmazione in questo linguaggio è più semplice. Un programma in linguaggio assembly utilizza le capacità di una particolare macchina (più precisamente, MP) in modo più razionale di un programma in linguaggio di alto livello (che è più facile per un programmatore che per un assemblatore). Considereremo i principi di base della programmazione in linguaggi orientati alla macchina utilizzando come esempio il linguaggio assembly per MP KR580VM80. Per la programmazione nel linguaggio viene utilizzata una tecnica generale. Tecniche specifiche per la registrazione dei programmi sono legate all'architettura e alle caratteristiche del sistema di comando dell'MP di destinazione.

Modello software sistema a microprocessore basato su MP KR580VM80

Il modello di programma dell'MPS secondo la Figura 1

Memoria delle porte MP

S Z AC P C

Immagine 1

Dal punto di vista del programmatore, il KR580VM80 MP dispone dei seguenti registri accessibili dal programma.

UN– Registro accumulatore a 8 bit. È il registro principale di MP. Qualsiasi operazione eseguita nell'ALU comporta l'inserimento nell'accumulatore di uno degli operandi da elaborare. Il risultato dell'operazione nell'ALU viene solitamente memorizzato anche in A.

B, C, D, E, H, L– Registri di uso generale a 8 bit (RON). Memoria interiore deputato. Progettato per memorizzare le informazioni elaborate, nonché i risultati dell'operazione. Quando si elaborano parole a 16 bit dai registri, si formano coppie BC, DE, HL e il doppio registro è chiamato la prima lettera: B, D, H. Nella coppia di registri, il primo registro è il più alto. I registri H, L, utilizzati sia per memorizzare dati che per memorizzare indirizzi a 16 bit di celle RAM, hanno una proprietà speciale.

Florida– registro flag (registro delle caratteristiche) Un registro a 8 bit che memorizza cinque caratteristiche del risultato dell'esecuzione di operazioni aritmetiche e logiche nell'MP. Formato FL secondo l'immagine

Bit C (CY - riporto) - riporto, impostato a 1 se si è verificato un riporto dall'ordine più alto del byte durante l'esecuzione di operazioni aritmetiche.

Bit P (parità) - parità, è impostato su 1 se il numero di unità nei bit del risultato è pari.

Il bit AC è un riporto aggiuntivo, progettato per memorizzare il valore del riporto dal tetrado inferiore del risultato.

Bit Z (zero): impostato su 1 se il risultato dell'operazione è 0.

Il bit S (segno) è impostato su 1 se il risultato è negativo e su 0 se il risultato è positivo.

SP-- lo stack pointer, un registro a 16 bit, è progettato per memorizzare l'indirizzo della posizione di memoria in cui è stato scritto l'ultimo byte inserito nello stack.

RS– program counter (contatore di programma), registro a 16 bit, progettato per memorizzare l'indirizzo della successiva istruzione eseguibile. Il contenuto del contatore del programma viene automaticamente incrementato di 1 immediatamente dopo il recupero del byte di istruzione successivo.

Nell'area di memoria iniziale si trova l'indirizzo 0000H - 07FF programma di controllo e programmi dimostrativi. Questa è l'area ROM.

0800 - 0AFF - area indirizzi per la registrazione dei programmi in studio. (RAM).

0В00 - 0ВВ0 - area indirizzi per la registrazione dei dati. (RAM).

0BB0 è l'indirizzo iniziale dello stack. (RAM).

Lo stack è un'area RAM appositamente organizzata progettata per l'archiviazione temporanea di dati o indirizzi. L'ultimo numero messo nello stack è il primo numero estratto dallo stack. Il puntatore dello stack memorizza l'indirizzo dell'ultima posizione dello stack in cui sono archiviate le informazioni. Quando viene richiamata una subroutine, l'indirizzo di ritorno al programma principale viene automaticamente memorizzato nello stack. Di norma, all'inizio di ciascuna subroutine, il contenuto di tutti i registri coinvolti nella sua esecuzione viene memorizzato nello stack e alla fine della subroutine viene ripristinato dallo stack.

Formato dei dati e struttura dei comandi del linguaggio assembly

La memoria MP KR580VM80 è un array di parole da 8 bit chiamate byte. Ogni byte ha il proprio indirizzo a 16 bit che ne determina la posizione nella sequenza delle celle di memoria. L'MP può indirizzare 65536 byte di memoria, che possono contenere sia ROM che RAM.

Formato dei dati

I dati vengono archiviati in memoria come parole da 8 bit:

D7 D6 D5 D4 D3 D2 D1 D0

Il bit meno significativo è il bit 0, il bit più significativo è il bit 7.

Il comando è caratterizzato dal formato, cioè dal numero di bit ad esso assegnati, che sono divisi byte per byte in determinati campi funzionali.

Formato del comando

I comandi MP KR580VM80 hanno il formato a uno, due o tre byte. Le istruzioni multibyte devono essere posizionate nei PL vicini. Il formato del comando dipende dalle specifiche dell'operazione eseguita.

Il primo byte del comando contiene l'opcode scritto in forma mnemonica.

Definisce il formato del comando e le azioni che devono essere eseguite dall'MP sui dati durante la sua esecuzione, nonché il metodo di indirizzamento e può contenere anche informazioni sulla posizione dei dati.

Il secondo e il terzo byte possono contenere dati su cui operare o indirizzi che indicano la posizione dei dati. I dati su cui vengono eseguite le operazioni sono chiamati operandi.

Formato del comando a byte singolo secondo la Figura 2

Figura 4

Nelle istruzioni in linguaggio assembly, il codice operativo ha una forma abbreviata di scrittura delle parole inglesi: una notazione mnemonica. La mnemonica (dal greco mnemonico - l'arte della memorizzazione) rende più facile ricordare i comandi in base al loro scopo funzionale.

Prima dell'esecuzione, il programma sorgente viene tradotto utilizzando un programma di traduzione, chiamato assembler, nel linguaggio delle combinazioni di codici - linguaggio macchina, in questa forma viene inserito nella memoria dell'MP e quindi utilizzato durante l'esecuzione del comando.


Metodi di indirizzamento

Tutti i codici degli operandi (input e output) devono trovarsi da qualche parte. Possono trovarsi nei registri interni dell'MP (i più convenienti e opzione veloce). Possono trovarsi nella memoria di sistema (l'opzione più comune). Infine, possono trovarsi in dispositivi I/O (il caso più raro). La posizione degli operandi è determinata dal codice istruzione. Esistere metodi diversi, con il quale il codice istruzione può determinare dove prendere l'operando di input e dove inserire l'operando di output. Questi metodi sono chiamati metodi di indirizzamento.

Per MP KR580VM80 sono previste le seguenti modalità di indirizzamento:

Immediato;

Registrati;

indiretto;

Pila.

Immediato l'indirizzamento presuppone che l'operando (input) sia in memoria immediatamente dopo il codice dell'istruzione. L'operando è solitamente una costante che deve essere inviata da qualche parte, aggiunta a qualcosa, ecc. i dati sono contenuti nel secondo o nel secondo e terzo byte del comando, con il byte di dati basso nel secondo byte di comando e il byte di dati alto nel terzo byte di comando.

Dritto L'indirizzamento (noto anche come assoluto) presuppone che l'operando (input o output) si trovi in ​​memoria all'indirizzo il cui codice si trova all'interno del programma immediatamente dopo il codice dell'istruzione. Utilizzato nei comandi a tre byte.

Registrati l'indirizzamento presuppone che l'operando (ingresso o uscita) sia nel registro MP interno. Utilizzato nei comandi a byte singolo

Indiretto l'indirizzamento (implicito) presuppone che il registro interno dell'MP non sia l'operando stesso, ma il suo indirizzo in memoria.

Pila l'indirizzamento presuppone che il comando non contenga un indirizzo. Indirizzamento alle celle di memoria tramite il contenuto del registro SP a 16 bit (stack pointer).

Sistema di comando

Il sistema di comando dell'MP è un elenco completo di azioni elementari che l'MP è in grado di eseguire. L'MP controllato da questi comandi esegue azioni semplici, come operazioni aritmetiche e logiche elementari, trasferimento di dati, confronto di due valori, ecc. Il numero di comandi dell'MP KR580VM80 è 78 (incluse le modifiche 244).

Esistono i seguenti gruppi di comandi:

Trasmissione dati;

Aritmetica;

Rompicapo;

Comandi di salto;

Comandi per input-output, controllo e lavoro con lo stack.


Simboli e abbreviazioni utilizzati nella descrizione dei comandi e nella scrittura dei programmi

Simbolo Riduzione
INDIRIZZO Indirizzo a 16 bit
DATI Dati a 8 bit
DATI 16 Dati a 16 bit
PORTA Indirizzo I/O a 8 bit (dispositivi I/O)
BYTE2 Secondo byte di comando
BYTE 3 Terzo byte di comando
R, R1, R2 Uno dei registri: A, B, C, D, E, H, L
RP Una delle coppie di registri: B - imposta una coppia di aerei; D - imposta una coppia di DE; H - specifica una coppia di HL
RH Primo registro della coppia
RL Secondo registro della coppia
Λ Moltiplicazione booleana
V Addizione booleana
Modulo due addizione
M Cella di memoria il cui indirizzo specifica il contenuto della coppia di registri HL, ovvero M = (HL)

1. Architettura del PC................................................................5

    1.1. Registri.

    1.1.1 Registri di carattere generale.

1.1.2. registri di segmento

1.1.3 Registro delle bandiere

1.2. Organizzazione della memoria.

1.3. Rappresentazione dei dati.

1.3.1 Tipi di dati

1.3.2 Rappresentazione di caratteri e stringhe

2. Dichiarazioni programmatiche dell’Assemblea ………………

    1. Comandi in linguaggio assembly

2.2. Modalità di indirizzamento e formati delle istruzioni macchina

3. Pseudo-operatori …………………..

3.1 Direttive sulla definizione dei dati

3.2 Struttura del programma di assemblaggio

3.2.1 Segmenti di programma. assumere direttiva

3.2.3 Direttiva sulla segmentazione semplificata

4. Assemblare e collegare il programma ………….

5. Comandi di trasferimento dati…………….

    5.1 Comandi generali

    5.2 Comandi in pila

5.3 Comandi I/O

5.4 Comandi di inoltro indirizzi

5.5 Comandi di trasferimento flag

6. Comandi aritmetici ………………….

    6.1 Operazioni aritmetiche su interi binari

6.1.1 Addizione e sottrazione

6.1.2 Comandi per incrementare e decrementare il ricevitore di uno

6.2 Moltiplicazione e divisione

6.3 Cambio di segno

7. Operazioni logiche ………………….

8. Turni e turni ciclici …………………

9. Operazioni sulle stringhe ……………………………………….

10. Logica e organizzazione dei programmi …………………

10.1 Salti incondizionati

10.2 Salti condizionati

10.4 Procedure in linguaggio assembly

10.5 Interrompe INT

10.6 Software di sistema

10.6.1.1 Lettura della tastiera.

10.6.1.2 Visualizzazione dei caratteri sullo schermo

10.6.1.3 Fine dei programmi.

10.6.2.1 Selezione delle modalità di visualizzazione

11. Memoria del disco …………………..

11.2 Tabella di allocazione dei file

11.3 I/O del disco

11.3.1 Scrittura di un file su disco

11.3.1.1 Dati ASCIIZ

11.3.1.2 Numero del file

11.3.1.3 Creazione di un file su disco

11.3.2 Lettura di un file su disco

introduzione

Il linguaggio assembly è una rappresentazione simbolica del linguaggio macchina. Tutti i processi in un personal computer (PC) al livello hardware più basso sono guidati solo da comandi (istruzioni) in linguaggio macchina. È impossibile risolvere realmente i problemi legati all'hardware (o anche, soprattutto, legati all'hardware, come ad esempio migliorare la velocità di un programma), senza conoscere l'assemblatore.

L'assemblatore è una forma conveniente di comandi direttamente per i componenti del PC e richiede la conoscenza delle proprietà e delle capacità del circuito integrato contenente questi componenti, vale a dire il microprocessore del PC. Pertanto, il linguaggio assembly è direttamente correlato all'organizzazione interna del PC. E non è un caso che quasi tutti i compilatori di linguaggi di alto livello supportino l'accesso al livello di programmazione assembler.

Un elemento della preparazione di un programmatore professionista è necessariamente lo studio dell'assemblatore. Questo perché la programmazione in linguaggio assembly richiede la conoscenza dell'architettura del PC, che consente di creare programmi più efficienti in altri linguaggi e combinarli con programmi in linguaggio assembly.

Il manuale tratta la programmazione in linguaggio assembly per computer basati su microprocessori Intel.

Questo tutorial è rivolto a tutti coloro che sono interessati all'architettura del processore e alle basi della programmazione in linguaggio Assembly, innanzitutto agli sviluppatori di un prodotto software.

    Architettura del computer.

L'architettura del computer è una rappresentazione astratta di un computer che riflette la sua organizzazione strutturale, circuitale e logica.

Tutti i computer moderni hanno alcune proprietà architettoniche comuni e individuali. Le proprietà individuali sono inerenti solo a uno specifico modello di computer.

Il concetto di architettura del computer comprende:

    schema a blocchi di un computer;

    mezzi e modalità di accesso agli elementi dello schema a blocchi di un computer;

    l'insieme e la disponibilità dei registri;

    organizzazione e modalità di indirizzamento;

    modalità di presentazione e formato dei dati informatici;

    una serie di istruzioni per la macchina del computer;

    formati di istruzioni macchina;

    gestione delle interruzioni.

Gli elementi principali dell'hardware del computer: unità di sistema, tastiera, dispositivi di visualizzazione, unità disco, dispositivi di stampa (stampante) e vari mezzi di comunicazione. Unità di sistemaè costituito da scheda madre, alimentatore e slot di espansione per schede opzionali. La scheda madre contiene il microprocessore, la memoria di sola lettura (ROM), RAM(RAM) e coprocessore.

      Registri.

All'interno del microprocessore le informazioni sono contenute in un gruppo di 32 registri (16 utente, 16 sistema), più o meno a disposizione del programmatore. Poiché il manuale è dedicato alla programmazione del microprocessore 8088-i486, è logico iniziare questo argomento discutendo i registri interni del microprocessore a disposizione dell'utente.

I registri utente vengono utilizzati dal programmatore per scrivere programmi. Questi registri includono:

    otto registri a 32 bit (registri per uso generale) EAX/AX/AH/AL, EBX/BX/BH/BL, ECX/CX/CH/CL, EDX/DX/DLH/DL, EBP/BP, ESI/SI, EDI/DI, ESP/SP;

    sei registri di segmenti a 16 bit: CS,DS, SS, ES, FS,GS;

    registri di stato e di controllo: registro flag EFLAGS/FLAGS e registro puntatore comando EIP/IP.

Parti di un registro a 32 bit vengono visualizzate tramite una barra. Il prefisso E (Extended) denota l'uso di un registro a 32 bit. Per lavorare con i byte, vengono utilizzati i registri con i prefissi L (basso) e H (alto), ad esempio AL, CH, che denota i byte bassi e alti delle parti a 16 bit dei registri.

        Registri generali.

EAX/AX/AH/AL(registro accumulatore) - batteria. Utilizzato nelle moltiplicazioni e divisioni, nelle operazioni di I/O e in alcune operazioni sulle stringhe.

EBX/BX/BH/BL - registro di base(registro base), spesso utilizzato quando si indirizzano i dati in memoria.

ECX/CX/CH/CL - contatore(registro di conteggio), utilizzato come contatore del numero di ripetizioni del loop.

EDX/DX/DH/DL- registro dati(registro dati), utilizzato per memorizzare dati intermedi. Alcuni comandi lo richiedono.

Tutti i registri di questo gruppo consentono di accedere alle loro parti "inferiori". Solo le parti inferiori a 16 e 8 bit di questi registri possono essere utilizzate per l'autoindirizzamento. I 16 bit superiori di questi registri non sono disponibili come oggetti indipendenti.

Per supportare i comandi di elaborazione stringhe che consentono l'elaborazione sequenziale di stringhe di elementi con lunghezza di 32, 16 o 8 bit, vengono utilizzati:

ESI/SI (registro indice sorgente) - indice fonte. Contiene l'indirizzo dell'elemento sorgente corrente.

EDI/DI (registro indice della distanza) - indice ricevitore(destinatario). Contiene l'indirizzo corrente nella stringa di destinazione.

L'architettura del microprocessore a livello hardware e software supporta la struttura dei dati: lo stack. Per lavorare con lo stack, ci sono comandi speciali e registri speciali. Va notato che lo stack viene riempito verso indirizzi più piccoli.

ESP/SP (registro del puntatore dello stack) - Registrati puntatore pila. Contiene un puntatore alla parte superiore dello stack nel segmento dello stack corrente.

EBP/BP (registro del puntatore base) – registro del puntatore base dello stack. Progettato per organizzare l'accesso casuale ai dati all'interno dello stack.

1.1.2. registri di segmento

Il modello software del microprocessore ne ha sei registri di segmento: CS, SS, DS, ES, GS, FS. La loro esistenza è dovuta alle specificità dell'organizzazione e dell'utilizzo della RAM da parte dei microprocessori Intel. L'hardware del microprocessore supporta l'organizzazione strutturale del programma composto da segmenti. Per specificare i segmenti disponibili in questo momento registri di segmento. Il microprocessore supporta i seguenti tipi di segmenti:

    segmento di codice. Contiene i comandi del programma Per accedere a questo segmento, utilizzare il registro CS (registro del segmento di codice) - registro del codice del segmento. Contiene l'indirizzo del segmento di istruzione macchina a cui ha accesso il microprocessore.

    segmento di dati. Contiene i dati elaborati dal programma. Per accedere a questo segmento viene utilizzato il registro DS (registro del segmento dati) - registro dei dati del segmento, che memorizza l'indirizzo del segmento di dati del programma corrente.

    Segmento di pila. Questo segmento è una regione di memoria chiamata stack. Il microprocessore organizza lo stack secondo il principio: il primo "è arrivato", il primo "è rimasto". Per accedere allo stack viene utilizzato il registro SS (registro dei segmenti dello stack) - registro del segmento dello stack A contenente l'indirizzo del segmento dello stack.

    Segmento dati aggiuntivo. I dati da elaborare possono trovarsi in tre segmenti dati aggiuntivi. Per impostazione predefinita, si presuppone che i dati si trovino nel segmento dati. Quando si utilizzano segmenti di dati aggiuntivi, i relativi indirizzi devono essere specificati esplicitamente utilizzando speciali prefissi di ridefinizione dei segmenti nel comando. Gli indirizzi dei segmenti dati aggiuntivi devono essere contenuti nei registri ES, GS, FS (registri dei segmenti dati di estensione).

        Registri di controllo e di stato

Il microprocessore contiene diversi registri che contengono informazioni sullo stato sia del microprocessore stesso che del programma le cui istruzioni sono attualmente caricate nella pipeline. Questo:

Registro del puntatore di comando EIP/IP;

    Registro flag EFLAGS/FLAGS.

Utilizzando questi registri è possibile ottenere informazioni sui risultati dell'esecuzione del comando e influenzare lo stato del microprocessore stesso.

EIP/IP (registro puntatore istruzione) - puntatore comandi. Il registro EIP/IP è largo 32 o 16 bit e contiene l'offset della successiva istruzione da eseguire rispetto al contenuto del registro del segmento CS nel segmento dell'istruzione corrente. Questo registro non è direttamente accessibile, ma viene modificato tramite istruzioni di salto.

EFLAGS/FLAGS (registro delle bandiere) - Registrati bandiere. Profondità di bit 32/16 bit. I singoli bit di questo registro hanno uno scopo funzionale specifico e sono chiamati flag. Un flag è un bit impostato su 1 ("flag impostato") se viene soddisfatta una condizione e su 0 ("flag cancellato") altrimenti. La parte inferiore di questo registro è completamente analoga al registro FLAGS dell'i8086.

1.1.3 Registro delle bandiere

Il registro flag è a 32 bit e ha il nome EFLAGS (Fig. 1). I singoli bit del registro hanno uno scopo funzionale specifico e sono chiamati flag. A ciascuno di essi viene assegnato un nome specifico (ZF, CF, ecc.). I 16 bit inferiori di EFLAGS rappresentano il registro FLAGS a 16 bit utilizzato durante l'esecuzione di programmi scritti per il microprocessore i086 e i286.

Fig.1 Registro delle bandiere

Alcuni flag sono chiamati flag di condizione; cambiano automaticamente quando i comandi vengono eseguiti e fissano alcune proprietà del loro risultato (ad esempio, se è uguale a zero). Altre bandiere sono chiamate bandiere di stato; cambiano rispetto al programma e influenzano l'ulteriore comportamento del processore (ad esempio bloccano gli interrupt).

Flag di condizione:

CF (porta bandiera) - portare bandiera. Prende il valore 1 se, sommando interi, appariva un'unità di riporto che non "si adattava" alla griglia di bit, o se, sottraendo numeri senza segno, la prima era inferiore alla seconda. Nei comandi di spostamento, il bit che è fuori rete viene inserito nel CF. CF fissa anche le caratteristiche dell'istruzione di moltiplicazione.

OF (flag di overflow) bandiera di trabocco. Viene impostato su 1 se, sommando o sottraendo numeri interi con un segno, il risultato è stato ottenuto, modulo superiore al valore consentito (la mantissa è traboccata e si è "arrampicata" nel bit del segno).

ZF (bandiera zero) bandiera zero. Impostato su 1 se il risultato del comando è 0.

SF (bandiera di segnale) - bandiera cartello. Impostato a 1 se l'operazione sui numeri con segno dà come risultato un risultato negativo.

PF (bandiera di parità) - bandiera parità. È uguale a 1 se il risultato del comando successivo contiene un numero pari di unità binarie. Di solito viene preso in considerazione solo durante le operazioni di I/O.

AF (bandiera di trasporto ausiliario) - flag di trasporto aggiuntivo. Corregge le funzionalità di esecuzione di operazioni su numeri decimali binari.

Flag di stato:

DF (bandiera di direzione) bandiera di direzione. Imposta la direzione della scansione delle linee nei comandi stringa: con DF=0, le linee vengono scansionate "in avanti" (dall'inizio alla fine), con DF=1 - nella direzione opposta.

IOPL (livello di privilegio di input/output) - Livello di privilegio I/O. Utilizzato nella modalità protetta del microprocessore per controllare l'accesso ai comandi I/O, a seconda del privilegio dell'attività.

NT (attività nidificata) flag di nidificazione delle attività. Utilizzato nella modalità protetta del microprocessore per registrare il fatto che un'attività è annidata all'interno di un'altra.

Indicatore di sistema:

SE (flag di interruzione) - flag di interruzione. Con IF=0 il processore smette di rispondere agli interrupt che gli arrivano, con IF=1 il blocco degli interrupt viene rimosso.

TF (flag trappola) bandiera di traccia. Con TF=1, dopo aver eseguito ciascuna istruzione, il processore effettua un'interruzione (con il numero 1), che può essere utilizzata durante il debug di un programma per tracciarlo.

RF (flag di ripresa) riprendere la bandiera. Utilizzato quando si gestiscono gli interrupt dai registri di debug.

VM (modalità 8086 virtuale) - bandiera virtuale 8086. 1 - il processore funziona in modalità virtuale 8086. 0 - il processore funziona in modalità reale o protetta.

AC (controllo allineamento) - flag di controllo dell'allineamento. Progettato per abilitare il controllo dell'allineamento durante l'accesso alla memoria.

      Organizzazione della memoria.

Viene chiamata la memoria fisica a cui ha accesso il microprocessore memoria di lavoro ( o memoria ad accesso casuale RAM). La RAM è una catena di byte che hanno il proprio indirizzo univoco (il suo numero), chiamato fisico. L'intervallo di indirizzi fisici è compreso tra 0 e 4 GB. Il meccanismo di gestione della memoria è interamente basato sull'hardware.

Il microprocessore supporta diversi modelli di utilizzo della RAM nell'hardware:

    modello segmentato. In questo modello, la memoria del programma è divisa in aree di memoria contigue (segmenti) e il programma stesso può accedere solo ai dati che si trovano in questi segmenti;

    modello di pagina. In questo caso la RAM viene considerata come un insieme di blocchi di dimensione fissa pari a 4 KB. L’applicazione principale di questo modello è legata all’organizzazione memoria virtuale, che consente ai programmi di utilizzare più spazio di memoria rispetto alla quantità di memoria fisica. Per un microprocessore Pentium la dimensione della memoria virtuale possibile può arrivare fino a 4 TB.

L'utilizzo e l'implementazione di questi modelli dipende dalla modalità operativa del microprocessore:

    Modalità indirizzo reale (modalità reale). La modalità è simile al funzionamento del processore i8086. Necessario per il funzionamento dei programmi progettati per i primi modelli di processore.

    Modalità protetta. La modalità protetta consente il multitasking elaborazione delle informazioni, protezione della memoria utilizzando un meccanismo di privilegi a quattro livelli e il relativo paging.

    Modalità 8086 virtuale. In questa modalità diventa possibile eseguire diversi programmi per i8086. In questo caso, i programmi in modalità reale possono funzionare.

La segmentazione è un meccanismo di indirizzamento che garantisce l'esistenza di diversi spazi di indirizzi indipendenti. Un segmento è un blocco di memoria indipendente, supportato dall'hardware.

Ogni programma nel caso generale può consistere di un numero qualsiasi di segmenti, ma ha accesso diretto ai tre principali: codice, dati e stack - e da uno a tre segmenti di dati aggiuntivi. Il sistema operativo colloca i segmenti di programma nella RAM in determinati indirizzi fisici, quindi inserisce i valori di questi indirizzi nei registri appropriati. All'interno di un segmento, il programma accede agli indirizzi relativi all'inizio del segmento in modo lineare, cioè iniziando dall'indirizzo 0 e terminando con un indirizzo uguale alla dimensione del segmento. Indirizzo relativo o pregiudizio, che il microprocessore utilizza per accedere ai dati all'interno di un segmento viene chiamato efficace.

Formazione di un indirizzo fisico in modalità reale

In modalità reale, l'intervallo di indirizzi fisici è compreso tra 0 e 1 MB. La dimensione massima del segmento è 64 KB. Quando si fa riferimento a uno specifico indirizzo fisico La RAM è determinata dall'indirizzo dell'inizio del segmento e dall'offset all'interno del segmento. L'indirizzo iniziale del segmento viene preso dal registro del segmento corrispondente. In questo caso il registro del segmento contiene solo i 16 bit superiori dell'indirizzo fisico dell'inizio del segmento. I quattro bit inferiori mancanti dell'indirizzo a 20 bit si ottengono spostando il valore del registro del segmento a sinistra di 4 bit. L'operazione di spostamento viene eseguita nell'hardware. Il valore risultante a 20 bit è l'indirizzo fisico effettivo corrispondente all'inizio del segmento. Questo è indirizzo fisicoè specificato come una coppia "segmento:offset", dove "segmento" sono i primi 16 bit dell'indirizzo iniziale del segmento di memoria a cui appartiene la cella e "offset" è l'indirizzo a 16 bit di questa cella, contato da l'inizio di questo segmento di memoria (il valore 16*segmento +offset fornisce l'indirizzo assoluto della cella). Se ad esempio nel registro CS è memorizzato il valore 1234h, allora la coppia di indirizzi 1234h:507h definisce un indirizzo assoluto pari a 16*1234h+507h =12340h+507h = 12847h. Tale coppia è scritta come una doppia parola e (come per i numeri) nella forma "invertita": la prima parola contiene l'offset e la seconda - il segmento, ciascuna di queste parole a sua volta è rappresentata nella forma "invertita" modulo. Ad esempio, la coppia 1234h:5678h verrebbe scritta così:| 78| 56| 34| 12|.

Questo meccanismo di formazione di un indirizzo fisico consente di rendere il software rilocabile, cioè non dipendente da specifici indirizzi di download nella RAM.

La programmazione a livello delle istruzioni macchina è il livello minimo al quale è possibile la programmazione. Il sistema di istruzioni della macchina deve essere sufficiente per implementare le azioni richieste impartendo istruzioni all'hardware del computer.

Ogni istruzione macchina è composta da due parti:

  • sala operatoria - determinare "cosa fare";
  • operando: definizione degli oggetti di elaborazione, "cosa fare con".

L'istruzione macchina del microprocessore, scritta in linguaggio assembly, è una riga singola con la seguente forma sintattica:

comando/direttiva etichetta operando(i) ;commenti

In questo caso, un campo obbligatorio in una riga è un comando o una direttiva.

L'etichetta, il comando/direttiva e gli operandi (se presenti) sono separati da almeno uno spazio o un carattere di tabulazione.

Se è necessario continuare un comando o una direttiva nella riga successiva, viene utilizzato il carattere barra rovesciata: \.

Per impostazione predefinita, il linguaggio assembly non distingue tra lettere maiuscole e minuscole nei comandi o nelle direttive.

Righe di codice di esempio:

Conta DB 1 ;Nome, direttiva, un operando
movimento eax,0 ;Comando, due operandi
cbw; Squadra

Tag

Etichetta in linguaggio assembly può contenere i seguenti caratteri:

  • tutte le lettere dell'alfabeto latino;
  • numeri da 0 a 9;
  • caratteri speciali: _, @, $, ?.

È possibile utilizzare un punto come primo carattere di un'etichetta, ma alcuni compilatori scoraggiano questo carattere. I nomi riservati del linguaggio assembly (direttive, operatori, nomi di comandi) non possono essere utilizzati come etichette.

Il primo carattere nell'etichetta deve essere una lettera o un carattere speciale (non un numero). Lunghezza massima etichette - 31 caratteri. Tutte le etichette scritte su una riga che non contiene una direttiva assembler devono terminare con i due punti: .

Squadre

Squadra dice al traduttore quale azione dovrebbe eseguire il microprocessore. In un segmento di dati, un comando (o una direttiva) definisce un campo, un'area di lavoro o una costante. In un segmento di codice, un'istruzione definisce un'azione, come uno spostamento (mov) o un'addizione (add).

direttive

L'assemblatore ha una serie di operatori che consentono di controllare il processo di assemblaggio e generazione di un elenco. Questi operatori vengono chiamati direttive . Agiscono solo nel processo di assemblaggio del programma e, a differenza delle istruzioni, non generano codici macchina.

operandi

Operando – un oggetto su cui viene eseguito un comando macchina o un operatore del linguaggio di programmazione.
Un'istruzione può avere uno o due operandi oppure nessun operando. Il numero di operandi è implicitamente specificato dal codice istruzione.
Esempi:

  • Nessun operando ret ;Return
  • Un operando inc ecx ;Incrementa ecx
  • Due operandi aggiungono eax,12 ;Aggiungi 12 a eax

L'etichetta, il comando (direttiva) e l'operando non devono iniziare in una posizione particolare nella stringa. Si consiglia comunque di scriverli in colonna per una maggiore leggibilità del programma.

Gli operandi possono essere

  • identificatori;
  • stringhe di caratteri racchiuse tra virgolette singole o doppie;
  • numeri interi in formato binario, ottale, decimale o esadecimale.
Identificatori

Identificatori – sequenze di caratteri validi utilizzati per designare oggetti del programma come codici operativi, nomi di variabili e nomi di etichette.

Regole per la scrittura degli identificatori.

  • L'identificatore può essere uno o più caratteri.
  • Come caratteri, puoi utilizzare lettere dell'alfabeto latino, numeri e alcuni caratteri speciali: _, ?, $, @.
  • Un identificatore non può iniziare con un carattere numerico.
  • L'ID può contenere fino a 255 caratteri.
  • Il traduttore accetta i primi 32 caratteri dell'identificatore e ignora il resto.
Commenti

I commenti sono separati dalla riga dell'eseguibile da un carattere; . In questo caso tutto ciò che viene scritto dopo il punto e virgola e fino alla fine della riga è un commento. L'uso dei commenti in un programma ne migliora la chiarezza, soprattutto quando lo scopo di una serie di istruzioni non è chiaro. Il commento può contenere qualsiasi carattere stampabile, compresi gli spazi. Il commento può occupare l'intera riga o seguire il comando sulla stessa riga.

Struttura del programma di assemblaggio

Un programma scritto in linguaggio assembly può essere composto da più parti, chiamate moduli . Ogni modulo può definire uno o più segmenti di dati, stack e codice. Qualsiasi programma completo in linguaggio assembly deve includere un modulo principale, o principale, da cui inizia la sua esecuzione. Un modulo può contenere codice, dati e segmenti di stack dichiarati con le direttive appropriate. Prima di dichiarare i segmenti, è necessario specificare il modello di memoria utilizzando la direttiva .MODEL.

Un esempio di un programma "che non fa nulla" in linguaggio assembly:

686P
.MODELLO PIATTO, STDCALL
.DATI
.CODICE
INIZIO:

RET
FINE INIZIO

Questo programma contiene solo un'istruzione del microprocessore. Questo comando è RET. Garantisce la corretta conclusione del programma. In generale, questo comando viene utilizzato per uscire da una procedura.
Il resto del programma è legato al funzionamento del traduttore.
.686P - Sono consentiti i comandi in modalità protetta Pentium 6 (Pentium II). Questa direttiva seleziona il set di istruzioni assembler supportato specificando il modello del processore. La lettera P alla fine della direttiva indica al traduttore che il processore funziona in modalità protetta.
.MODEL FLAT, stdcall è un modello di memoria flat. Questo modello di memoria viene utilizzato in sala operatoria Sistema Windows. stdcall
.DATA è un segmento di programma contenente dati.
.CODE è un blocco di programma contenente codice.
START è un'etichetta. Nell'assemblatore, le etichette svolgono un ruolo importante, cosa che non si può dire dei moderni linguaggi di alto livello.
END START - la fine del programma e un messaggio al traduttore che il programma deve essere avviato dall'etichetta START .
Ogni modulo deve contenere una direttiva END che segna la fine codice sorgente programmi. Tutte le righe che seguono la direttiva END vengono ignorate. L'omissione della direttiva END genera un errore.
L'etichetta dopo la direttiva END indica al compilatore il nome del modulo principale da cui inizia l'esecuzione del programma. Se il programma contiene un modulo, l'etichetta dopo la direttiva END può essere omessa.




Superiore