Come configurare smartphone e PC. Portale informativo
  • casa
  • OS
  • I componenti principali del linguaggio assembly e la struttura dei comandi. Caratteristiche generali del sistema di comando del linguaggio Assembler per IBM-PC (insieme di comandi di base, metodi di base di indirizzamento degli operandi)

I componenti principali del linguaggio assembly e la struttura dei comandi. Caratteristiche generali del sistema di comando del linguaggio Assembler per IBM-PC (insieme di comandi di base, metodi di base di indirizzamento degli operandi)

I comandi possono essere distinti in base al loro scopo (tra parentesi sono riportati esempi di codici mnemonici di operazioni per comandi assembler di un PC come IBM PC):

l eseguire operazioni aritmetiche (ADD e ADC - addizione e addizione con storno, SUB e SBB - sottrazione e sottrazione con prestito, MUL e IMUL - moltiplicazioni senza segno e con segno, DIV e IDIV - divisioni senza segno e con segno, CMP - confronti ecc.) ;

l eseguire operazioni logiche (OR, AND, NOT, XOR, TEST, ecc.);

l trasferimento dati (MOV - invia, XCHG - scambia, IN - entra nel microprocessore, OUT - uscita dal microprocessore, ecc.);

l trasferimento del controllo (rami di programma: JMP - ramo incondizionato, CALL - chiamata di procedura, RET - ritorno dalla procedura, J * - ramo condizionale, LOOP - controllo di loop, ecc.);

l elaborazione di stringhe di caratteri (MOVS - trasferimenti, CMPS - confronti, LODS - download, SCAS - scansioni. Questi comandi vengono solitamente utilizzati con il prefisso (modificatore di ripetizione) ​​REP;

l interruzioni del programma (INT - interruzioni software, INTO - interruzione condizionale in caso di overflow, IRET - ritorno dall'interruzione);

l controllo a microprocessore (ST * e CL * - impostazione e cancellazione flag, HLT - arresto, WAIT - attesa, NOP - inattività, ecc.).

Un elenco completo dei comandi assembler può essere trovato nei lavori.

Comandi di trasferimento dati

l MOV dst, src - trasferimento dati (move - trasferimento da src a dst).

Trasferisce: un byte (se src e dst sono in formato byte) o una parola (se src e dst sono in formato word) tra registri o tra registro e memoria, e scrive anche un valore immediato in un registro o in una memoria.

Gli operandi dst e src devono essere nello stesso formato di byte o parola.

Src può essere di tipo: r (registro) - registro, m (memoria) - memoria, i (impedenza) - valore immediato. Dst può essere di tipo r, m. Non è possibile utilizzare i seguenti operandi nello stesso comando: rsegm insieme a i; due operandi di tipo me due operandi di tipo rsegm). L'operando i può anche essere una semplice espressione:

mov AX, (152 + 101B) / 15

L'espressione viene valutata solo durante la traduzione. Non cambia bandiere.

l PUSH src - spingendo una parola nello stack (push - spingere attraverso; push sullo stack da src). Spinge il contenuto di src in cima allo stack: qualsiasi registro a 16 bit (compresi quelli di segmento) o due locazioni di memoria contenenti una parola a 16 bit. Le bandiere non cambiano;

l POP dst - estrae una parola dallo stack (pop - pop; legge dallo stack in dst). Estrae una parola dalla parte superiore dello stack e la inserisce in dst - qualsiasi registro a 16 bit (incluso il segmento) o due posizioni di memoria. Le bandiere non cambiano.

Introduzione.

La lingua in cui è scritto il programma originale si chiama Ingresso lingua, e la lingua in cui è tradotto per l'esecuzione dal processore-rom è fine settimana linguaggio. Il processo di conversione di una lingua di input in una lingua di output è chiamato trasmissione. Poiché i processori sono in grado di eseguire programmi in un linguaggio macchina di codici binari, che non viene utilizzato per la programmazione, è necessaria la traduzione di tutti i programmi sorgente. Conosciuto due strade traduzioni: compilazione e interpretazione.

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

In interpretazioni ogni riga del testo del programma sorgente viene analizzata (interpretata) e viene immediatamente eseguito il comando in essa specificato. L'attuazione di questo metodo è affidata a programma interprete. L'interpretazione richiede molto tempo. Per aumentare la sua efficienza, invece di elaborare ogni riga, l'interprete prima converte tutto squadra 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 sono:

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

) si usa il mnemonico

Sottrazione (

moltiplicazione (

Divisioni (

e così via.I nomi simbolici sono usati anche per indirizzare le celle di memoria. Per programmare in linguaggio assembly, invece di codici binari e indirizzi, è necessario conoscere solo i nomi simbolici, che l'assemblatore traduce in codici binari;

ogni affermazione corrisponde un comando macchina(codice), ovvero esiste una corrispondenza biunivoca tra istruzioni macchina e operatori in un programma in linguaggio assembly;

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

) non ha questa capacità. Si noti che i linguaggi per la programmazione del sistema (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 è un linguaggio universale. Ogni specifico gruppo di microprocessori ha il proprio assemblatore. Le lingue di alto livello non hanno 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 ricevuto ampio uso 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 in carte di credito, telefoni cellulari, driver di dispositivo, ecc.;

● alcune procedure richiedono l'accesso completo all'hardware, 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 che operano in tempo reale.

Nella maggior parte dei programmi, solo una piccola percentuale del codice totale è responsabile di una grande percentuale 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 un assembler che uno dei linguaggi di alto livello.

Il formato dell'operatore in linguaggio assembly.

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

Campo etichetta.

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

● eseguire un salto condizionato o incondizionato al comando;

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

Tali dichiarazioni sono etichettate. Per designare un nome, vengono utilizzate lettere (maiuscole) dell'alfabeto inglese e numeri. Il nome deve essere preceduto da una lettera e da un separatore di due punti alla fine. Un'etichetta con i due punti può essere scritta su una riga separata e un codice operativo può essere scritto sulla riga successiva nella colonna 2, il che semplifica il lavoro del compilatore. L'assenza dei due punti non consente di distinguere un'etichetta da un codice operativo se si trovano su righe separate.

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

Non dovrebbero esserci nomi identici nel campo dell'etichetta, poiché l'etichetta è associata agli indirizzi di comando. Se durante l'esecuzione del programma non è necessario richiamare un comando o dei dati dalla memoria, il campo dell'etichetta rimane vuoto.

Campo codice operazione.

Questo campo contiene il codice mnemonico del comando o pseudo-comando (vedi sotto). Il codice mnemonico dei comandi è scelto dai progettisti del linguaggio. In linguaggio assembly

mnemonico selezionato per caricare il registro dalla memoria

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

). Nei linguaggi assembly

un nome può essere utilizzato rispettivamente per entrambe le operazioni

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

Il mnemonico del registro dipende anche dalla versione assembler (Tabella 5.2.1).

Campo degli operandi.

Ulteriori informazioni necessarie per completare l'operazione si trovano qui. Nel campo degli operandi per le istruzioni di salto, viene indicato l'indirizzo in cui si desidera saltare, nonché indirizzi e registri, che sono operandi per un'istruzione macchina. Ad esempio, forniremo operandi che possono essere utilizzati per processori a 8 bit.

● dati numerici,

presentato in vari sistemi di numerazione. Per designare il sistema numerico utilizzato, la costante è seguita da una delle lettere latine: B,

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

non devi scriverlo). Se la prima cifra di un 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 delle informazioni) nella forma delle lettere A, B, C,

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

nel sistema binario);

● identificatori,

per registrare coppie di aeromobili,

Le prime lettere B,

H; per una coppia di accumulatori e un registro dei segni -

; per il contatore di comando -

; per il puntatore dello stack -

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

(se la condizione è soddisfatta) e salti incondizionati. Ad esempio, l'operando M1 nel comando

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

● espressioni,

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

Definire una parola) e successivamente ha introdotto un'alternativa.

che era nella lingua per i processori fin dall'inizio

Nella versione in lingua

usato da

Definire una costante).

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

II registri di diversa lunghezza hanno nomi diversi: ЕАХ - per inserire operandi a 32 bit (tipo

); АХ - per 16 bit (tipo

e AH - per 8 bit (tipo

● per processori

i suffissi vengono aggiunti a ciascun codice operativo: suffisso

Per tipo

; suffisso ".B" per il tipo

per operandi di diversa lunghezza si utilizzano opcode differenti, ad esempio per caricare un byte, mezza parola (

) e le parole nel registro a 64 bit, vengono utilizzati gli opcode

rispettivamente.

Campo dei commenti.

Questo campo fornisce spiegazioni sulle azioni del programma. I commenti non influiscono sul funzionamento del programma e sono destinati agli esseri umani. Potrebbero essere necessari per modificare il programma, che senza tali commenti potrebbe essere completamente incomprensibile anche a programmatori esperti. Un commento inizia con un simbolo e viene utilizzato per spiegare e documentare i programmi. Il carattere iniziale di un commento può essere:

● punto e virgola (;) nelle lingue per i processori aziendali

● punto esclamativo (!) Nelle lingue per

Ogni singola riga di commento è preceduta da un carattere di inizio.

Pseudo-comandi (direttive).

In linguaggio assembly, ci sono due tipi principali di comandi:

di base istruzioni che sono l'equivalente del codice macchina del processore. Questi comandi eseguono tutte le elaborazioni previste dal programma;

pseudo comandi, o direttive, progettato per servire il processo di traduzione di un programma nel linguaggio delle combinazioni di codici. Ad esempio, nella tabella. 5.2.2 vengono forniti alcuni pseudo-comandi dal campionatore ac

per la famiglia

.

In fase di 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 viene incontrata. Questo approccio aumenta le dimensioni del programma;

● formare questa sequenza in una procedura (subroutine) e richiamarla se necessario. Questo output ha i suoi svantaggi: ogni volta si deve eseguire un comando di chiamata di procedura speciale e un comando di ritorno, che, con una sequenza breve e di uso frequente, può ridurre notevolmente la velocità del programma.

Il modo più semplice ed efficiente per ripetere più volte una catena di comandi è usare macro, che può essere pensato come uno pseudo-comando progettato per ritrasmettere un gruppo di comandi che si incontrano frequentemente in un programma.

Una macro, o macro, è caratterizzata da tre aspetti: macrodefinizione, macroinversione e macroespansione.

Definizione macro

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

La definizione di macro ha la seguente struttura:

Elenco delle espressioni; Definizione macro

Si possono distinguere tre parti nella struttura di cui sopra di una macrodefinizione:

● titolo

una macro che include un nome

Pseudo-comando

e un insieme di parametri;

● contrassegnato da punti corpo macro;

● squadra

finali

macro.

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

Per ricomporre il gruppo di comandi selezionato, utilizzare l'indirizzo composto dal nome

macro e un elenco di parametri con altri valori.

Quando l'assemblatore incontra una definizione di macro durante la compilazione, la memorizza nella tabella di definizione della macro. Nelle successive apparizioni in programma del nome (

) della macro, l'assemblatore lo sostituisce con il corpo della macro.

Viene chiamato l'uso di un nome di macro come codice operativo macrocircolazione(mediante una chiamata di macro), e la sua sostituzione con il corpo della macro è espansione macro.

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

L'espansione della macro si verifica durante il processo di assemblaggio, non durante l'esecuzione del programma. Il modo di manipolare le stringhe di caratteri è responsabilità di fondi macro.

Il processo di assemblaggio viene eseguito in due passaggi:

● al primo passaggio, tutte le definizioni di macro vengono salvate e le chiamate di macro vengono espanse. In questo caso, il programma originale viene letto e convertito in un programma in cui vengono rimosse tutte le definizioni di macro e ogni chiamata di macro viene sostituita dal corpo della macro;

● nel secondo passaggio il programma risultante viene elaborato senza macro.

Macro parametrizzate.

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

● con effettivo parametri che si collocano nel campo degli operandi di macrochiamata;

● con formale parametri. Nel processo di espansione della macro, ogni parametro formale che appare nel corpo della macro viene sostituito dal parametro effettivo corrispondente.

utilizzando macro con parametri.

Il programma 1 mostra due sequenze di comandi simili, differendo 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 effettivo (P,

) e P2 è sostituito dal secondo parametro attuale (

) dal programma n. 1. Nella macrozona

il programma 2 è contrassegnato: P,

Il primo parametro effettivo,

Secondo parametro attuale.

Programma 1

Programma 2

MOV EBX, Q MOV EAX, Pl

MOV Q, EAX MOV EBX, P2

MOV P, EBX MOV P2, EAX

Capacità estese.

Consideriamo alcune funzionalità avanzate del linguaggio

Se la macro che contiene il comando di diramazione condizionale e l'etichetta a cui viene eseguito il ramo viene chiamata due o più volte, l'etichetta verrà duplicata (il problema delle etichette duplicate), il che causerà un errore. Pertanto, ad ogni chiamata, viene assegnata (dal programmatore) un'etichetta separata come parametro. in 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. Tener conto di

SE WORDSIZE GT 16 M2 MACRO

La macro M2 può essere definita in entrambe le parti dell'istruzione

Tuttavia, la definizione dipende dal processore su cui è assemblato il programma: 16 bit o 32 bit. Se M1 non viene chiamato, la macro M2 non verrà definita affatto.

Un'altra caratteristica avanzata è che le macro possono chiamare altre macro, incluso se stesse - ricorsivo chiamata. In quest'ultimo caso, per non ottenere un ciclo infinito, la macro deve passare a se stessa un parametro, che cambia ad ogni espansione, e anche dai un'occhiata questo parametro e termina la ricorsione quando il parametro raggiunge un certo valore.

Sull'uso delle macro in assembler.

Quando si utilizzano le macro, l'assemblatore deve essere in grado di eseguire due funzioni: preservare le macro-definizioni e estendere le chiamate macro.

Conservazione delle macro.

Tutti i nomi delle macro sono memorizzati in una tabella. Ogni nome è accompagnato da un puntatore alla macro corrispondente in modo che possa essere chiamato se necessario. Alcuni assemblatori hanno una tabella separata per i nomi delle macro, mentre altri hanno una tabella generale in cui, insieme ai nomi delle macro, si trovano tutte le istruzioni e le direttive 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 ad un'altra tabella di definizioni macro, dove verrà memorizzato il corpo della macro;

● elenco formale parametri.

Quindi il corpo della macro viene letto e salvato nella tabella delle definizioni delle macro, che è solo una stringa di simboli. I parametri formali trovati nel corpo del ciclo sono contrassegnati da un simbolo speciale.

Rappresentazione interna di una macro

dall'esempio sopra per il programma 2 (p. 244) appare come:

MOV EAX, MOV EBX, MOV MOV &

dove un punto e virgola viene utilizzato come carattere di ritorno a capo e l'e commerciale & viene utilizzato come carattere di parametro formale.

Espansione delle chiamate macro.

Ogni volta che viene rilevata una macro durante l'assemblaggio, viene memorizzata nella tabella delle macro. Quando viene chiamata la macro, l'assemblatore interrompe temporaneamente la lettura dell'input dal dispositivo di input e inizia a leggere il corpo della macro salvata. I parametri formali estratti dal corpo della macro vengono sostituiti con i parametri effettivi e forniti dalla chiamata. L'ampersant & davanti ai parametri permette all'as-sampler di riconoscerli.

Nonostante il fatto che ci siano molte versioni di assembler, i processi di assemblaggio hanno caratteristiche comuni e sono simili in molti modi. Il lavoro dell'assemblatore a due passaggi è discusso di seguito.

Assemblatore a due passaggi.

Il programma è composto da una serie di operatori. 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 di cui sopra fino alla traduzione dell'intero programma.

Tuttavia, questo approccio non è efficace. Un esempio è il cosiddetto problema collegamenti previsionali. Se la prima istruzione è un salto all'istruzione P situata 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. Ogni lettura completa del programma originale è chiamata corridoio. Ti mostriamo come risolvere il problema del collegamento in avanti utilizzando due passaggi:

segue il primo passaggio raccogliere e salvare tutte le definizioni dei simboli (incluse le etichette) nella tabella e, al secondo passaggio, leggere e assemblare ciascun operatore. Questo metodo è relativamente semplice, ma il secondo passaggio attraverso il programma originale richiede ulteriore tempo dedicato alle operazioni di I/O;

● al primo passaggio, trasformare programma in una forma intermedia e salvarlo nella tabella, ed eseguire il secondo passaggio non secondo il programma originale, ma secondo la tabella. Questo metodo di assemblaggio consente di risparmiare tempo, poiché non viene eseguito alcun I/O al secondo passaggio.

Primo passaggio.

Obiettivo primo passaggio- costruire una tabella dei simboli. Come notato sopra, un altro obiettivo del primo passaggio è preservare tutte le macro ed espandere le chiamate man mano che vengono visualizzate. Di conseguenza, sia la definizione del simbolo che l'espansione della macro avvengono in un unico passaggio. Il simbolo può essere sia etichetta, o significato, a cui viene assegnato un nome specifico utilizzando la direttiva:

; Valore - dimensione del buffer

Assegnando valori ai nomi simbolici nel campo etichetta istruzione, l'assemblatore imposta essenzialmente gli indirizzi che ogni istruzione avrà durante l'esecuzione del programma. Per questo, l'assemblatore durante il processo di assemblaggio salva comando indirizzo contatore(

) come variabile speciale. All'inizio del primo passaggio, il valore della variabile speciale è impostato su 0 e aumenta dopo ogni comando elaborato della lunghezza di questo comando. Ad esempio, nella tabella. 5.2.3 mostra un frammento del programma che indica la lunghezza dei comandi e i valori del contatore. Al primo passaggio si formano le tabelle nomi simbolici, direttive e codici operativi, e se necessario letterale tavolo. Un letterale è una costante per la quale l'assemblatore riserverà automaticamente memoria. Immediatamente, notiamo che i processori moderni contengono istruzioni con indirizzi immediati, quindi i loro acsembler non supportano i letterali.

Tabella dei nomi simbolici

contiene un elemento per ogni nome (tabella 5.2.4). Ogni elemento della tabella dei nomi simbolici 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 riallocazione della memoria (che mostrano se il valore di un simbolo cambia se il programma viene caricato in un indirizzo diverso da quello previsto dall'assemblatore);

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

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

Tabella direttiva.

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

Tabella codici operazione.

Per ogni opcode, la tabella fornisce colonne separate: designazione dell'opcode, operando 1, operando 2, valore esadecimale dell'opcode, lunghezza del comando e tipo di comando (Tabella 5.2.5). I codici operazione sono suddivisi in gruppi a seconda del numero e del tipo di operandi. Il tipo di comando determina il numero del gruppo e specifica la procedura che viene chiamata per elaborare tutti i comandi in questo gruppo.

Secondo passaggio.

Obiettivo del secondo passaggio- creazione di un programma oggetto ed eventuale stampa del protocollo assembly; l'output delle informazioni necessarie al linker per collegare le procedure che sono state 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. Operatore originale e derivato da esso in output di sistema esadecimale oggetto il codice può essere stampato o memorizzato per la stampa successiva. Dopo aver azzerato il contatore dell'indirizzo di comando, viene richiamata l'istruzione successiva.

Il programma originale può contenere errori, ad esempio:

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

● l'opcode è rappresentato da un nome non valido (a causa di un errore di battitura), non è fornito con un numero sufficiente di operandi o ha troppi operandi;

● non c'è nessun operatore

Alcuni assemblatori possono prendere un carattere indefinito e sostituirlo. Tuttavia, nella maggior parte dei casi, quando rileva 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 1.4 Mnemonici dell'assemblatore. Struttura e formati dei comandi. Tipi di indirizzamento. Set di comandi del microprocessore

Piano:

1 Linguaggio dell'Assemblea. Concetti basilari

2 Simboli del linguaggio assembly

3 Tipi di istruzioni assembler

4 Direttive dell'Assemblea

5 Set di istruzioni del processore

1 iolinguaggio assembly. Concetti basilari

linguaggio assemblyè una rappresentazione simbolica del linguaggio macchina. Tutti i processi in una macchina al livello hardware più basso sono guidati solo da comandi in linguaggio macchina (istruzioni). Quindi, è chiaro che, nonostante il nome generico, il linguaggio assembly è diverso per ogni tipo di computer.

Un programma in linguaggio assembly è una raccolta di blocchi di memoria chiamati segmenti di memoria. Un programma può essere costituito da uno o più di questi segmenti di blocco. Ogni segmento contiene una serie di frasi linguistiche, ognuna delle quali occupa una riga separata di codice di programma.

Le frasi assembly sono di quattro tipi:

1) comandi o istruzioni, che sono analoghi simbolici delle istruzioni macchina. Nel processo di traduzione, le istruzioni assembler vengono convertite nei corrispondenti comandi del set di istruzioni del microprocessore;

2) macro -le frasi del testo del programma, formate in un certo modo, sono sostituite durante la trasmissione da altre frasi;

3) direttive,che sono istruzioni al traduttore assembler per eseguire alcune azioni. Le direttive non hanno analoghi nella rappresentazione delle macchine;

4) righe di commento contenente qualsiasi simbolo, comprese le lettere dell'alfabeto russo. I commenti vengono ignorati dal traduttore.

­ La struttura di un programma assembly. Sintassi dell'assemblatore.

Le frasi che compongono il programma possono essere un costrutto sintattico corrispondente a un comando, macro, direttiva o commento. Affinché il traduttore assembler li riconosca, devono essere formati secondo determinate regole sintattiche. Il modo migliore per farlo è usare una descrizione formale della sintassi del linguaggio come le regole grammaticali. I modi più comuni per descrivere un linguaggio di programmazione come questo - diagrammi di sintassi e forme estese di Backus-Naur. Più conveniente per l'uso pratico diagrammi di sintassi. Ad esempio, la sintassi delle frasi assembler può essere descritta utilizzando i diagrammi di sintassi mostrati nelle seguenti figure 10, 11, 12.

Figura 10 - Formato frase di montaggio


­ Figura 11 - Formato delle direttive

­ Figura 12 - Formato comandi e macro

In queste cifre:

­ nome dell'etichetta- un identificatore, il cui valore è l'indirizzo del primo byte di quella frase del testo sorgente del programma, che esso designa;

­ nome -identificatore che distingue questa direttiva da altre direttive con lo stesso nome. A seguito dell'elaborazione di una specifica direttiva da parte dell'assemblatore, a tale nome possono essere attribuite determinate caratteristiche;

­ codice operativo (COP) e direttiva - sono designazioni mnemoniche della corrispondente istruzione macchina, comando macro o direttiva traduttore;

­ operandi -parti di un comando, una macro o una direttiva assembler che designano gli oggetti da manipolare. Gli operandi assembler sono descritti da espressioni con costanti numeriche e di testo, etichette e identificatori di variabili utilizzando segni di operazione e alcune parole riservate.

I diagrammi di sintassi aiutano trova e poi vai dall'input del diagramma (a sinistra) al suo output (a destra). Se esiste un tale percorso, allora la frase o la costruzione è sintatticamente corretta. Se non esiste tale percorso, il compilatore non accetterà questa costruzione.

­ 2 simboli linguaggio assembly

I caratteri consentiti durante la scrittura del testo del programma sono:

1) tutte le lettere latine: A-Z,a-z... In questo caso le lettere maiuscole e minuscole sono considerate equivalenti;

2) numeri da 0 prima 9 ;

3) segni ? , @ , $ , _ , & ;

4) separatori , . () < > { } + / * % ! " " ? = # ^ .

Le frasi assembler sono formate da gettoni, che sono sequenze sintatticamente inseparabili di caratteri validi della lingua che sono significativi per il traduttore.

lessemi sono:

1) identificatori - sequenze di caratteri validi utilizzati per denotare oggetti del programma come codici operativi, nomi di variabili e nomi di etichette. La regola per scrivere gli identificatori è la seguente: un identificatore può essere composto da uno o più caratteri;

2) stringhe di caratteri - sequenze di caratteri racchiuse tra virgolette singole o doppie;

3) numeri interi di uno dei seguenti sistemi di numerazione : binario, decimale, esadecimale. L'identificazione dei numeri durante la loro scrittura nei programmi in linguaggio assembly viene eseguita secondo determinate regole:

4) i numeri decimali non richiedono simboli aggiuntivi per la loro identificazione, ad esempio 25 o 139. Per l'identificazione nel codice sorgente del programma numeri binariè necessario dopo aver registrato gli zeri e gli uno che li compongono, mettere il latino “ B”, Ad esempio 10010101 B.

5) i numeri esadecimali hanno più convenzioni quando vengono scritti:

In primo luogo, sono costituiti da numeri 0...9 , lettere minuscole e maiuscole dell'alfabeto latino un,B, C,D,e,F o UN,B,C,D,E,F.

In secondo luogo, il traduttore può avere difficoltà a riconoscere i numeri esadecimali perché possono essere costituiti solo da cifre 0 ... 9 (ad esempio 190845) o iniziare con una lettera dell'alfabeto latino (ad esempio, ef15). Per "spiegare" al traduttore che un dato token non è un numero decimale o un identificatore, il programmatore deve selezionare un numero esadecimale in un modo speciale. Per fare ciò, alla fine della sequenza di cifre esadecimali che compongono un numero esadecimale, scrivi la lettera latina “ h”. Questo è un prerequisito. Se un numero esadecimale inizia con una lettera, davanti ad esso viene scritto uno zero iniziale: 0 ef15 h.

Quasi ogni frase contiene una descrizione dell'oggetto su cui o con l'aiuto del quale viene eseguita un'azione. Questi oggetti sono chiamati operandi... Si possono definire così: operandi- si tratta di oggetti (alcuni valori, registri o celle di memoria) su cui agiscono istruzioni o direttive, oppure sono oggetti che definiscono o chiariscono l'azione di istruzioni o direttive.

È possibile effettuare la seguente classificazione degli operandi:

­ operandi costanti o immediati;

­ indirizzo operandi;

­ operandi mobili;

contatore di indirizzi;

­ registro operando;

­ operandi base e indice;

­ operandi strutturali;

record.

Gli operandi sono componenti elementari da cui è formata una parte di un'istruzione macchina, che denota gli oggetti su cui viene eseguita un'operazione. In un caso più generale, gli operandi possono essere inclusi come parti costitutive in formazioni più complesse, dette espressioni.

espressioni sono combinazioni di operandi e operatori, trattati nel loro insieme. Il risultato della valutazione di un'espressione può essere un indirizzo di una cella di memoria o un valore costante (assoluto).

­ 3 Tipi di istruzioni assembler

Elenchiamo le possibili tipologie operatori assembler e regole sintattiche per la formazione di espressioni assembler:

­ operatori aritmetici;

­ operatori di turno;

­ operatori di confronto;

­ operatori logici;

­ operatore indice;

­ operatore di sovrascrittura del tipo;

­ operatore di ridefinizione del segmento;

­ operatore di denominazione del tipo di struttura;

­ operatore per ottenere la componente di segmento dell'indirizzo di espressione;

­ operatore per ottenere l'offset di un'espressione.

1 Direttive per gli assemblatori

­ Le direttive dell'assemblatore sono:

1) Direttive di segmentazione. Nel corso della discussione precedente, abbiamo scoperto tutte le regole di base per scrivere comandi e operandi in un programma assembler. Resta aperta la questione di come formulare correttamente la sequenza dei comandi in modo che il traduttore li possa elaborare e il microprocessore li possa eseguire.

Considerando l'architettura del microprocessore, abbiamo appreso che ha sei registri di segmento, attraverso i quali può funzionare contemporaneamente:

­ con un segmento di codice;

­ con un segmento di pila;

­ con un segmento di dati;

­ con tre segmenti di dati aggiuntivi.

Fisicamente, un segmento è un'area di memoria occupata da istruzioni e (o) dati, i cui indirizzi sono calcolati rispetto al valore nel registro di segmento corrispondente. La descrizione sintattica di un segmento in assieme è la costruzione mostrata in Figura 13:


­ Figura 13 - Descrizione sintattica di un segmento in assembler

È importante notare che la funzionalità di un segmento è in qualche modo più ampia rispetto alla semplice suddivisione di un programma in blocchi di codice, dati e stack. La segmentazione fa parte di un meccanismo più generale relativo a il concetto di programmazione modulare. Presuppone l'unificazione del design dei moduli oggetto creati dal compilatore, inclusi quelli di diversi linguaggi di programmazione. Ciò consente di combinare programmi scritti in lingue diverse. Gli operandi nella direttiva SEGMENT hanno lo scopo di implementare varie varianti di tale associazione.

2) Direttive per la gestione delle quotazioni. Le direttive di controllo degli elenchi sono suddivise nei seguenti gruppi:

­ direttive generali per il controllo degli elenchi;

­ direttive per l'output nell'elenco dei file inclusi;

­ direttive per l'output di blocchi di assemblaggio condizionali;

­ direttive per elencare le macro;

­ direttive per l'output delle informazioni sui riferimenti incrociati all'elenco;

­ direttive per modificare il formato dell'elenco.

2 Set di istruzioni del processore

Il set di istruzioni del processore è mostrato nella Figura 14.

Consideriamo i principali gruppi di squadre.

­ Figura 14 - Classificazione delle istruzioni dell'assemblatore

Le squadre sono:

1 Comandi di trasferimento dati. Questi comandi occupano un posto molto importante nel set di istruzioni di qualsiasi processore. Svolgono le seguenti funzioni essenziali:

­ memorizzare in memoria il contenuto dei registri interni del processore;

­ copiare il contenuto da un'area di memoria a un'altra;

­ scrittura su dispositivi I/O e lettura da dispositivi I/O.

Su alcuni processori, tutte queste funzioni vengono eseguite da un singolo comando. MOV (per i trasferimenti di byte - MOVB ) ma con diversi metodi di indirizzamento degli operandi.

Su altri processori oltre al comando MOV ci sono molti altri comandi per eseguire le funzioni elencate. Inoltre, i comandi di trasferimento dati includono comandi di scambio di informazioni (la loro designazione si basa sulla parola Scambio ). Lo scambio di informazioni tra registri interni, tra due metà di un registro ( SCAMBIO ) o tra un registro e una locazione di memoria.

2 Comandi aritmetici. Le istruzioni aritmetiche trattano i codici operando come codici numerici binari o binari-decimali. Questi comandi possono essere suddivisi in cinque gruppi principali:

­ comandi per operazioni a punto fisso (addizione, sottrazione, moltiplicazione, divisione);

­ comandi in virgola mobile (addizione, sottrazione, moltiplicazione, divisione);

­ comandi di pulizia;

­ comandi di incremento e decremento;

­ comando di confronto

3 I comandi di operazioni a punto fisso funzionano con codici nei registri del processore o in memoria come con i normali codici binari. Le istruzioni in virgola mobile (punto) utilizzano il formato di rappresentazione dei numeri con ordine e mantissa (di solito questi numeri occupano due locazioni di memoria consecutive). Nei moderni potenti processori, l'insieme di istruzioni in virgola mobile non è limitato a sole quattro operazioni aritmetiche, ma contiene molte altre istruzioni più complesse, ad esempio il calcolo di funzioni trigonometriche, funzioni logaritmiche e funzioni complesse necessarie per l'elaborazione del suono e immagini.

4 Le istruzioni di cancellazione sono progettate per scrivere un codice zero in un registro o in una cella di memoria. Questi comandi possono essere sovrascritti con comandi di trasferimento zero, ma i comandi di cancellazione speciali sono generalmente più veloci dei comandi di trasferimento.

5 Comandi per incremento (aumento di uno) e decremento

(decrementi di uno) sono anche molto convenienti. In linea di principio possono essere sostituiti dall'addizione con uno o sottrae uno, ma incremento e decremento sono più veloci dell'addizione e della sottrazione. Queste istruzioni richiedono un operando di ingresso, che è anche un operando di uscita.

6 L'istruzione di confronto confronta due operandi di ingresso. Infatti calcola la differenza tra questi due operandi, ma non forma un operando di uscita, ma cambia solo i bit nel registro di stato del processore in base al risultato di questa sottrazione. L'istruzione successiva che segue l'istruzione di confronto (di solito un'istruzione di salto) analizzerà i bit nel registro di stato del processore ed eseguirà azioni in base ai loro valori. Alcuni processori forniscono istruzioni per il collegamento a margherita di due sequenze di operandi in memoria.

7 Comandi logici. Le istruzioni logiche eseguono operazioni logiche (a bit) sugli operandi, ovvero considerano i codici operando non come un singolo numero, ma come un insieme di bit separati. Ecco come differiscono dai comandi aritmetici. I comandi logici eseguono le seguenti operazioni di base:

­ AND logico, OR logico, addizione modulo 2 (OR esclusivo);

­ spostamenti logici, aritmetici e ciclici;

­ controllo di bit e operandi;

­ impostazione e cancellazione dei bit (flag) del registro di stato del processore ( PSW).

Le istruzioni logiche consentono di calcolare le funzioni logiche di base da due operandi di ingresso, bit per bit. Inoltre, l'operazione AND viene utilizzata per cancellare forzatamente i bit specificati (un codice maschera viene utilizzato come uno degli operandi, in cui i bit da cancellare sono impostati a zero). L'operazione OR viene utilizzata per impostare forzatamente i bit specificati (come uno degli operandi, viene utilizzato il codice maschera, in cui i bit che richiedono l'impostazione a uno sono uguali a uno). L'operazione "OR esclusivo" viene utilizzata per invertire i bit specificati (come uno degli operandi viene utilizzato un codice maschera, in cui i bit da invertire sono impostati su uno). Le istruzioni richiedono due operandi di ingresso e formano un operando di uscita.

8 I comandi Shift consentono di spostare bit per bit il codice dell'operando a destra (verso i bit di ordine inferiore) oa sinistra (verso i bit di ordine superiore). Il tipo di spostamento (logico, aritmetico o ciclico) determina quale sarà il nuovo valore del bit più significativo (in caso di spostamento a destra) o meno significativo (in caso di spostamento a sinistra) e determina anche se il valore precedente del bit più significativo (quando si sposta a sinistra) verrà salvato da qualche parte o il bit meno significativo (quando si sposta a destra). Gli spostamenti ciclici consentono di spostare i bit di un operando in modo circolare (in senso orario se spostati a destra o in senso antiorario se spostati a sinistra). In questo caso, la bandierina di trasporto può essere inclusa o meno nell'anello del cambio. Il bit del flag di riporto (se utilizzato) memorizza il valore del bit più significativo quando ciclato a sinistra e il bit meno significativo quando ciclato a destra. Di conseguenza, il valore del bit di flag di riporto verrà sovrascritto nel bit meno significativo quando si cicla a sinistra e nel bit più significativo quando ci si sposta a destra.

9 Comandi di transizioni. Le istruzioni di salto sono progettate per organizzare tutti i tipi di loop, rami, chiamate di subroutine, ecc., ovvero interrompono il flusso sequenziale del programma. Questi comandi scrivono un nuovo valore nel registro del contatore dei comandi e quindi fanno sì che il processore passi non al comando successivo nell'ordine, ma a qualsiasi altro comando nella memoria del programma. Alcuni comandi di transizione forniscono un ulteriore ritorno al punto da cui è stata effettuata la transizione, altri non lo prevedono. Se viene fornito il ritorno, i parametri correnti del processore vengono salvati nello stack. Se non viene fornito alcun ritorno, i parametri del processore correnti non vengono salvati.

I comandi di transizione senza backtracking sono divisi in due gruppi:

­ comandi di salto incondizionato;

­ comandi di salto condizionato.

Questi comandi usano le parole Ramo e salto.

Le istruzioni di salto incondizionato provocano un salto a un nuovo indirizzo indipendentemente da qualsiasi cosa. Possono causare un salto di una quantità specificata di offset (in avanti o indietro) oa un indirizzo di memoria specificato. Il valore di offset o il nuovo valore di indirizzo viene specificato come operando di ingresso.

Le istruzioni di salto condizionale non provocano sempre un salto, ma solo quando vengono soddisfatte le condizioni specificate. Queste condizioni sono solitamente i valori dei flag nel registro di stato del processore ( PSW ). Cioè, la condizione di transizione è il risultato dell'operazione precedente che modifica i valori dei flag. Possono esserci in totale da 4 a 16 di tali condizioni di salto Diversi esempi di comandi di salto condizionato:

­ transizione se uguale a zero;

­ transizione se non uguale a zero;

­ saltare se c'è troppo pieno;

­ saltare se non c'è troppo pieno;

­ transizione se maggiore di zero;

­ salta se minore o uguale a zero.

Se la condizione di transizione è soddisfatta, il nuovo valore viene caricato nel registro dei comandi. Se la condizione di salto non è soddisfatta, il contatore delle istruzioni viene semplicemente incrementato e il processore seleziona ed esegue l'istruzione successiva nell'ordine.

Il comando di confronto (CMP) che precede il comando di salto condizionato (o anche più comandi di salto condizionato) viene utilizzato specificamente per verificare le condizioni di salto. Ma i flag possono essere impostati da qualsiasi altro comando, ad esempio un comando di trasferimento dati, qualsiasi comando aritmetico o logico. Nota che gli stessi comandi di salto non cambiano i flag, il che ti consente solo di inserire diversi comandi di salto uno dopo l'altro.

I comandi di interruzione occupano un posto speciale tra i comandi di salto indietro. Queste istruzioni richiedono un numero di interrupt (indirizzo vettoriale) come operando di ingresso.

Produzione:

Il linguaggio assembly è una rappresentazione simbolica di un linguaggio macchina. Il linguaggio assembly per ogni tipo di computer è diverso. Un programma in linguaggio assembly è una raccolta di blocchi di memoria chiamati segmenti di memoria. Ogni segmento contiene una serie di frasi linguistiche, ognuna delle quali occupa una riga separata di codice di programma. Le frasi assembly sono di quattro tipi: comandi o istruzioni, macro, direttive, righe di commento.

Tutte le lettere latine sono caratteri validi durante la scrittura del testo del programma: A-Z,a-z... In questo caso le lettere maiuscole e minuscole sono considerate equivalenti; figure da 0 prima 9 ; segni ? , @ , $ , _ , & ; separatori , . () < > { } + / * % ! " " ? = # ^ .

Si applicano i seguenti tipi di istruzioni assembler e regole di sintassi per la formazione di espressioni assembler. operatori aritmetici, operatori di spostamento, operatori di confronto, operatori logici, operatore indice, operatore di sostituzione del tipo, operatore di sostituzione del segmento, operatore di denominazione del tipo di struttura, operatore per ottenere il componente del segmento di un indirizzo di espressione, operatore per ottenere l'offset di un'espressione.

Il sistema di comando è diviso in 8 gruppi principali.

­ Domande di controllo:

1 Che cos'è il linguaggio assembly?

2 Quali simboli possono essere utilizzati per scrivere comandi in linguaggio assembly?

3 Cosa sono le etichette e il loro scopo?

4 Spiegare la struttura dei comandi assembler.

5 Elenca 4 tipi di frasi assembler.

Struttura delle istruzioni in linguaggio assembly La programmazione a livello di istruzione macchina è il livello minimo al quale è possibile la programmazione del computer. Il set di istruzioni della macchina deve essere sufficiente per eseguire le azioni richieste impartendo istruzioni all'hardware della macchina. Ogni istruzione macchina è composta da due parti: una operativa che definisce "cosa fare" e un operando che definisce gli oggetti di elaborazione, ovvero cosa fare. Un'istruzione macchina a microprocessore scritta in linguaggio assembly è una singola riga della forma seguente: etichetta istruzione / operando/i direttiva; commenti L'etichetta, il comando/la direttiva e l'operando sono separati da almeno uno spazio o un carattere di tabulazione. Gli operandi dei comandi sono separati da virgole.

Struttura dell'istruzione in linguaggio assembly Un'istruzione in linguaggio assembly indica al traduttore quale azione deve eseguire il microprocessore. Le direttive Assembler sono parametri specificati nel testo del programma che influiscono sul processo di assemblaggio o sulle proprietà del file di output. L'operando definisce il valore iniziale dei dati (nel segmento di dati) o gli elementi su cui agire con il comando (nel segmento di codice). Un'istruzione può avere uno o due operandi o nessun operando. Il numero di operandi è implicitamente specificato dal codice del comando. Se è necessario continuare un comando o una direttiva sulla riga successiva, viene utilizzato il carattere barra rovesciata: "". Per impostazione predefinita, l'Assembler non distingue tra lettere maiuscole e minuscole nella scrittura di comandi e direttive. Esempi di direttiva e comando Conteggio db 1; Nome, direttiva, un operando mov eax, 0; Comando, due operandi

Gli identificatori sono sequenze di caratteri validi utilizzati per indicare nomi di variabili e nomi di etichette. L'identificatore può essere costituito da uno o più dei seguenti caratteri: tutte le lettere dell'alfabeto latino; numeri da 0 a 9; caratteri speciali: _, @, $,? ... Un punto può essere utilizzato come primo carattere dell'etichetta. I nomi di assembler riservati (direttive, operatori, nomi di comandi) non possono essere utilizzati come identificatori. Il primo carattere dell'identificatore deve essere una lettera o un carattere speciale. La lunghezza massima dell'identificatore è di 255 caratteri, ma il traduttore accetta i primi 32 caratteri, ignorando il resto. Tutte le etichette scritte in una riga che non contiene una direttiva assembler devono terminare con i due punti ":". Etichetta, comando (direttiva) e operando non devono iniziare in una posizione particolare nella stringa. Si consiglia di annotarli in una colonna per una migliore leggibilità del programma.

Etichette Tutte le etichette scritte in una riga che non contiene una direttiva assembler devono terminare con i due punti ":". Etichetta, comando (direttiva) e operando non devono iniziare in una posizione particolare nella stringa. Si consiglia di annotarli in una colonna per una migliore leggibilità del programma.

Commenti L'utilizzo dei commenti in un programma migliora la chiarezza, soprattutto quando l'intento del set di istruzioni non è chiaro. I commenti iniziano su qualsiasi riga del modulo sorgente con un punto e virgola (;). Tutti i caratteri a destra di “; "Alla fine della linea sono un commento. Il commento può contenere qualsiasi carattere stampabile, compreso lo spazio. Un commento può occupare l'intera riga o seguire un comando sulla stessa riga.

La struttura di un programma in linguaggio assembly Un programma scritto in linguaggio assembly può essere costituito da più parti, chiamate moduli, in ciascuna delle quali è possibile definire uno o più dati, stack e segmenti di codice. Qualsiasi programma completo in linguaggio assembly deve includere un modulo principale, o principale, dal quale inizia la sua esecuzione. Un modulo può contenere segmenti di programma, segmenti di dati e uno stack, dichiarato utilizzando le direttive appropriate.

Modelli di memoria Prima di dichiarare i segmenti, è necessario specificare il modello di memoria utilizzando una direttiva. Modificatore MODEL memory_model, call_convention, OS_type, stack_parameter Modelli di memoria di base del linguaggio assembly: Modello di memoria Indirizzamento del codice Indirizzamento dei dati Sistema operativo Interlacciamento del codice e dei dati TINY NEAR MS-DOS Consentito SMALL NEAR MS-DOS, Windows No MEDIUM FAR NEAR MS-DOS, Windows No COMPACT NEAR FAR MS-DOS, Windows No LARGE LONTANO MS-DOS, Windows No ENORME LONTANO MS-DOS, Windows No NEAR Windows 2000, Windows XP, Windows Consentito FLAT NEAR NT,

Modelli di memoria Il modello minuscolo funziona solo nelle applicazioni MS-DOS a 16 bit. In questo modello, tutti i dati e il codice si trovano in un segmento fisico. In questo caso, la dimensione del file di programma non supera i 64 KB. Il modello piccolo supporta un segmento di codice e un segmento di dati. I dati e il codice vengono indirizzati il ​​più vicino possibile quando si utilizza questo modello. Il modello medio supporta più segmenti di codice e un segmento di dati, con tutti i collegamenti nei segmenti di codice considerati lontani per impostazione predefinita e i collegamenti in un segmento di dati come vicini. Il modello compatto supporta più segmenti di dati utilizzando l'indirizzamento dei dati lontani e un segmento di dati vicino. Il modello grande supporta più segmenti di codice e più segmenti di dati. Per impostazione predefinita, tutti i riferimenti di codice e dati sono considerati lontani. Il modello enorme è quasi equivalente al modello con memoria grande.

Modelli di memoria Il modello piatto presuppone una configurazione del programma non segmentata e viene utilizzato solo su sistemi operativi a 32 bit. Questo modello è simile al modello minuscolo in quanto i dati e il codice sono contenuti in un singolo segmento a 32 bit. Sviluppare un programma per il modello piatto prima della direttiva. modello piatto una delle direttive dovrebbe essere collocata:. 386,. 486,. 586 o. 686. La scelta della direttiva di selezione del processore determina l'insieme delle istruzioni disponibili durante la scrittura dei programmi. La lettera p dopo la direttiva di selezione del processore indica una modalità di funzionamento protetta. L'indirizzamento di dati e codice è vicino, con tutti gli indirizzi e i puntatori a 32 bit.

Modelli di memoria. MODEL modificatore memory_model, call_convention, OS_type, stack_parameter Il parametro modificatore viene utilizzato per definire i tipi di segmenti e può assumere i seguenti valori: use 16 (segmenti del modello selezionato sono usati come 16 bit) use 32 (segmenti del modello selezionato sono usati come 32 bit). Il parametro call_convention viene utilizzato per determinare come vengono passati i parametri quando si chiama una procedura da altri linguaggi, inclusi i linguaggi di alto livello (C++, Pascal). Il parametro può assumere i seguenti valori: C, BASIC, FORTRAN, PASCAL, SYSCALL, STDCALL.

Modelli di memoria. Modificatore MODEL memory_model, call_ convention, OS_type, stack_parameter OS_type è l'OS_DOS predefinito ed è attualmente l'unico valore supportato per questo parametro. Stack_parameter è impostato su: NEARSTACK (il registro SS è DS, i dati e le aree dello stack si trovano nello stesso segmento fisico) FARSTACK (il registro SS non è uguale a DS, i dati e le aree dello stack si trovano in segmenti fisici diversi). L'impostazione predefinita è NEARSTACK.

Un esempio di un programma "non fare nulla". 686 P. MODELLO PIATTO, STDCALL. DATI. CODICE START: RET END START RET - comando a microprocessore. Garantisce la corretta conclusione del programma. Il resto del programma è legato al lavoro del traduttore. ... 686 P - Comandi in modalità protetta Pentium 6 (Pentium II) consentiti. Questa direttiva seleziona il set di istruzioni assembler supportato specificando il modello del processore. ... MODELLO FLAT, stdcall è un modello di memoria flat. Questo modello di memoria viene utilizzato nel sistema operativo Windows. stdcall è la convenzione di chiamata della procedura utilizzata.

Un esempio di un programma "non fare nulla". 686 P. MODELLO PIATTO, STDCALL. DATI. CODICE INIZIO: RET FINE START. DATA è un segmento di programma contenente dati. Questo programma non usa lo stack, quindi il file. STACK è mancante. ... CODE - un segmento del programma contenente il codice. START è un'etichetta. END START - la fine del programma e un messaggio al compilatore che il programma deve essere avviato dall'etichetta START. Ogni programma deve contenere una direttiva END per contrassegnare la fine del codice sorgente del programma. Tutte le righe che seguono la direttiva END vengono ignorate L'etichetta specificata dopo la direttiva END comunica al traduttore il nome del modulo principale da cui parte il programma. Se il programma contiene un modulo, l'etichetta dopo la direttiva END può essere omessa.

Traduttori di linguaggio assembly Un traduttore è un programma o un mezzo tecnico che converte un programma in uno dei linguaggi di programmazione in un programma nella lingua di destinazione, chiamato codice oggetto. Oltre a supportare i mnemonici delle istruzioni macchina, ogni traduttore ha il proprio set di direttive e strumenti macro, che spesso sono incompatibili con qualsiasi cosa. I principali tipi di traduttori di linguaggio assembly: MASM (Microsoft Assembler), TASM (Borland Turbo Assembler), FASM (Flat Assembler) - un assemblatore multi-pass gratuito scritto da Tomasz Grishtar (polacco), NASM (Netwide Assembler) - un assemblatore gratuito per l'architettura Intel x 86, è stato creato da Simon Tatham in collaborazione con Julian Hall ed è attualmente sviluppato da un piccolo team di sviluppo su Source. Fucina. netto.

Src = "https://present5.com/presentation/-29367016_63610977/image-15.jpg" alt = "(! LANG: trasmissione del programma a Microsoft Visual Studio 2005 1) Creare un progetto scegliendo File-> Nuovo-> Progetto e"> Трансляция программы в Microsoft Visual Studio 2005 1) Создать проект, выбрав меню File->New->Project и указав имя проекта (hello. prj) и тип проекта: Win 32 Project. В дополнительных опциях мастера проекта указать “Empty Project”.!}

Src = "https://present5.com/presentation/-29367016_63610977/image-16.jpg" alt = "(! LANG: trasmissione del programma a Microsoft Visual Studio 2005 2) Nella struttura del progetto (Visualizza-> Esplora soluzioni) Inserisci"> Трансляция программы в Microsoft Visual Studio 2005 2) В дереве проекта (View->Solution Explorer) добавить файл, в котором будет содержаться текст программы: Source. Files->Add->New. Item.!}

Traduzione del programma in Microsoft Visual Studio 2005 3) Selezionare il tipo di file Code C++, ma specificare il nome con l'estensione. asm:

Traduzione del programma in Microsoft Visual Studio 2005 5) Impostare le opzioni del compilatore. Fare clic con il pulsante destro del mouse sul menu Regole di compilazione personalizzate... nel file di progetto.

Traduzione del programma in Microsoft Visual Studio 2005 e selezionare Microsoft Macro Assembler nella finestra che appare.

Traduzione del programma in Microsoft Visual Studio 2005 Verifica facendo clic con il pulsante destro del mouse su Hello. asm della struttura del progetto del menu Proprietà e impostare Generale-> Strumento: Microsoft Macro Assembler.

Src = "https://present5.com/presentation/-29367016_63610977/image-22.jpg" alt = "(! LANG: trasmissione del programma a Microsoft Visual Studio 2005 6) Compila il file scegliendo Build-> Build hello. Prj."> Трансляция программы в Microsoft Visual Studio 2005 6) Откомпилировать файл, выбрав Build->Build hello. prj. 7) Запустить программу, нажав F 5 или выбрав меню Debug->Start Debugging.!}

Programmazione nel sistema operativo Windows La programmazione nel sistema operativo Windows si basa sull'utilizzo delle funzioni API (Application Program Interface). Il loro numero raggiunge il 2000. Il programma per Windows consiste in gran parte di tali chiamate. Tutte le interazioni con dispositivi esterni e risorse del sistema operativo avvengono, di regola, attraverso tali funzioni. Il sistema operativo Windows utilizza un modello di memoria flat. L'indirizzo di qualsiasi locazione di memoria sarà determinato dal contenuto di un registro a 32 bit. Esistono 3 tipi di strutture di programma per Windows: finestra di dialogo (finestra principale - finestra di dialogo), struttura console o senza finestre, struttura classica (finestra, wireframe).

Richiamo delle funzioni API di Windows Nel file della guida, qualsiasi funzione API è rappresentata come tipo nome_funzione (FA 1, FA 2, FA 3) Tipo - il tipo del valore restituito; ФАх - un elenco di argomenti formali nell'ordine in cui vengono visualizzati, ad esempio int Message. Casella (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Questa funzione visualizza una finestra con un messaggio e un pulsante (o pulsanti) di uscita. Significato dei parametri: h. Wnd - handle alla finestra in cui apparirà la finestra del messaggio, lp. Testo - il testo che apparirà nella finestra, lp. Didascalia - il testo nella didascalia della finestra, u. Tipo - il tipo della finestra, in particolare, è possibile definire il numero di pulsanti di uscita.

Chiamare le funzioni API di Windows int Message. Casella (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Quasi tutti i parametri delle funzioni API sono in realtà interi a 32 bit: HWND è un intero a 32 bit, LPCTSTR è un puntatore a una stringa a 32 bit, UINT è un intero a 32 bit. Il suffisso "A" viene spesso aggiunto al nome della funzione per passare a versioni più recenti della funzione.

Chiamare le funzioni API di Windows int Message. Casella (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Quando si utilizza MASM, è necessario aggiungere @N N alla fine del nome, il numero di byte che gli argomenti passati occupano nello stack. Per le funzioni API Win 32, questo numero può essere definito come il numero di argomenti n per 4 (byte in ogni argomento): N = 4 * n. Il comando CALL assembler viene utilizzato per chiamare la funzione. In questo caso, tutti gli argomenti della funzione vengono passati ad essa tramite lo stack (comando PUSH). Direzione di passaggio degli argomenti: DA SINISTRA A DESTRA - BASSO SU. Il primo argomento da inserire nello stack è u. Tipo. La chiamata alla funzione specificata sarà simile a questa: CALL Message. Scatola. [e-mail protetta]

Chiamare le funzioni API di Windows int Message. Casella (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Il risultato dell'esecuzione di qualsiasi funzione API è, di regola, un numero intero restituito nel registro EAX. La direttiva OFFSET è un "segmento offset" o, in termini di linguaggio di alto livello, un "puntatore" all'inizio di una riga. La direttiva EQU, come #define nel linguaggio C, definisce una costante. La direttiva EXTERN dice al traduttore che la funzione o l'identificatore è esterno al modulo dato.

Un esempio del programma "Ciao a tutti!" ... 686 P. MODELLO PIATTO, STDCALL. STACK 4096. DATA MB_OK EQU 0 STR 1 DB "Il mio primo programma", 0 STR 2 DB "Ciao a tutti!", 0 HW DD? Messaggio ESTERNO. Scatola. [e-mail protetta]: VICINO. CODICE START: PUSH MB_OK PUSH OFFSET STR 1 PUSH OFFSET STR 2 PUSH HW CALL Messaggio. Scatola. [e-mail protetta] RIT FINE AVVIO

La direttiva INVOKE Il traduttore di lingua MASM consente anche di semplificare la chiamata di funzioni utilizzando uno strumento macro - la direttiva INVOKE: funzione INVOKE, parametro1, parametro2, ... In questo caso, non è necessario aggiungere @ 16 alla chiamata di funzione; i parametri sono scritti esattamente nell'ordine in cui sono riportati nella descrizione della funzione. i parametri vengono inseriti nello stack tramite il traduttore. per utilizzare la direttiva INVOKE, è necessario disporre di una descrizione del prototipo della funzione utilizzando la direttiva PROTO nella forma: Messaggio. Scatola. A PROTO: DWORD,: DWORD Se un programma utilizza molte funzioni API Win 32, è consigliabile utilizzare la direttiva include C: masm 32includeuser 32. inc

Lavoro del corso

Nella disciplina "Programmazione di sistema"

Argomento numero 4: "Risoluzione dei problemi per le procedure"

opzione 2

UNIVERSITÀ STATO SIBERIANO ORIENTALE

TECNOLOGIA E CONTROLLO

____________________________________________________________________

COLLEGIO TECNOLOGICO

ESERCIZIO

per tesina

Disciplina:
Argomento: Risoluzione dei problemi per le procedure
Interpreti: Glavinskaya Arina Aleksandrovna
Responsabile: DambaevaSesegma Viktorovna
Il riassunto del lavoro: lo studio delle routine in linguaggio assembly,
risoluzione dei problemi utilizzando le subroutine
1. Parte teorica: Informazioni di base sul linguaggio Assembly (set
comandi, ecc.), Organizzazione dei sottoprogrammi, Metodi di passaggio dei parametri
nei sottoprogrammi
2. Parte pratica: sviluppa due subroutine, una delle quali converte una data lettera in maiuscolo (anche per le lettere russe) e l'altra converte la lettera in minuscolo.
converte una data lettera in maiuscolo e l'altro converte la lettera in minuscolo.
converte una lettera in minuscolo.
Scadenze del progetto nei tempi previsti:
1. Parte teorica - 30% entro 7 settimane.
2. Parte pratica - 70% entro 11 settimane.
3. Protezione: 100% entro 14 settimane.
Requisiti per la registrazione:
1. Il regolamento e la nota esplicativa del progetto del corso devono essere presentati in
elettroniche e cartacee.
2. Il volume della relazione deve essere di almeno 20 pagine dattiloscritte esclusi gli allegati.
3. RPZ è redatto in conformità con GOST 7.32-91 e firmato dal capo.

Responsabile del lavoro __________________

Appaltatore __________________

Data di emissione " 26 " settembre 2017 G.


Introduzione. 2

1.1 Informazioni di base sul linguaggio Assembly. 3

1.1.1 Insieme di comandi. 4

1.2 Organizzazione dei sottoprogrammi in linguaggio assembly. 4

1.3 Metodi di passaggio dei parametri nei sottoprogrammi. 6

1.3.1 Passaggio dei parametri attraverso i registri .. 6

1.3.2 Passaggio di parametri attraverso lo stack. 7

2 SEZIONE PRATICA .. 9

2.1 Dichiarazione del problema. nove

2.2 Descrizione della soluzione del problema. nove

2.3 Testare il programma .. 7

Conclusione. otto

Riferimenti .. 9


introduzione

È risaputo che è difficile programmare in Assembler. Come sai, ci sono molte lingue diverse ora. alto livello che ti permettono di spendere molto meno sforzo durante la scrittura dei programmi. Naturalmente, sorge la domanda quando un programmatore potrebbe aver bisogno di utilizzare Assembler durante la scrittura di programmi. Attualmente, ci sono due aree in cui l'uso del linguaggio assembly è giustificato, e spesso necessario.

Innanzitutto, questi sono i cosiddetti programmi di sistema dipendenti dalla macchina, di solito controllano vari dispositivi sul computer (tali programmi sono chiamati driver). Questi programmi di sistema utilizzano istruzioni macchina speciali che non devono essere utilizzate nell'ordinario (o, come si suol dire applicato) programmi. Questi comandi sono impossibili o molto difficili da definire in un linguaggio di alto livello.

La seconda area di applicazione dell'Assembler è relativa all'ottimizzazione dell'esecuzione del programma. Molto spesso, i programmi di traduzione (compilatori) da linguaggi di alto livello producono un programma in linguaggio macchina molto inefficiente. Questo di solito si applica ai programmi di natura computazionale, in cui una sezione molto piccola (circa il 3-5%) del programma (loop principale) viene eseguita per la maggior parte del tempo. Per risolvere questo problema possono essere utilizzati i cosiddetti sistemi di programmazione multilingue, che consentono di scrivere parti del programma in diverse lingue. Di solito, la parte principale del programma è scritta in un linguaggio di programmazione di alto livello (Fortran, Pascal, C, ecc.) e le sezioni critiche del programma sono scritte in Assembler. In questo caso, la velocità dell'intero programma può essere notevolmente aumentata. Questo è spesso l'unico modo per fare in modo che il programma produca un risultato in un lasso di tempo ragionevole.

Lo scopo di questo lavoro del corso è acquisire competenze pratiche nella programmazione in linguaggio assembly.

Compiti di lavoro:

1. Studiare le informazioni di base sul linguaggio Assembler (struttura e componenti del programma Assembler, formato dei comandi, organizzazione dei sottoprogrammi, ecc.);

2. Studiare i tipi di operazioni sui bit, il formato e la logica delle istruzioni logiche dell'Assembler;

3. Risolvere un problema individuale sull'uso dei sottoprogrammi in Assembler;

4 .. Formulare una conclusione sul lavoro svolto.

1 SEZIONE TEORICA

Comprensione del linguaggio assembly

Assembler è un linguaggio di programmazione di basso livello che è un formato leggibile dall'uomo per scrivere istruzioni macchina.

Le istruzioni in linguaggio assembly corrispondono uno a uno con le istruzioni del processore e, infatti, rappresentano una comoda notazione simbolica (codice mnemonico) dei comandi e dei loro argomenti. Inoltre, il linguaggio assembly fornisce astrazioni software di base: collegamento di parti del programma e dati tramite etichette con nomi simbolici e direttive.

Le direttive Assembler consentono di includere blocchi di dati (descritti esplicitamente o letti da un file) nel programma; ripetere un determinato frammento un numero specificato di volte; compilare un frammento in modo condizionale; impostare l'indirizzo di esecuzione del frammento, modificare i valori delle etichette durante il processo di compilazione; utilizzare macro con parametri, ecc.

Vantaggi e svantaggi

· La quantità minima di codice ridondante (utilizzando meno istruzioni e accessi alla memoria). Di conseguenza - maggiore velocità e minori dimensioni del programma;

· Grandi quantità di codice, un gran numero di piccoli compiti aggiuntivi;

· Scarsa leggibilità del codice, difficoltà di manutenzione (debug, aggiunta di funzionalità);

· La difficoltà di implementare paradigmi di programmazione e ogni altra convenzione più complessa, la complessità dello sviluppo congiunto;

· Meno librerie disponibili, loro bassa compatibilità;

· Accesso diretto all'hardware: porte input-output, registri speciali del processore;

· Massima "adattamento" alla piattaforma desiderata (utilizzo di istruzioni speciali, caratteristiche tecniche di "hardware");

· Intolleranza ad altre piattaforme (tranne compatibile binario).

Oltre alle istruzioni, un programma può contenere delle direttive: comandi che non si traducono direttamente in istruzioni macchina, ma controllano il funzionamento del compilatore. Il loro insieme e la loro sintassi variano in modo significativo e dipendono non dalla piattaforma hardware, ma dal compilatore utilizzato (dando origine a dialetti di linguaggi all'interno della stessa famiglia di architetture). Come insieme di direttive, si possono individuare:

· Definizione dei dati (costanti e variabili);

· Gestione dell'organizzazione del programma in memoria e dei parametri del file di output;

· Impostazione della modalità di funzionamento del compilatore;

· Tutti i tipi di astrazioni (cioè elementi di linguaggi di alto livello) - dalla progettazione di procedure e funzioni (per semplificare l'implementazione del paradigma di programmazione procedurale) a strutture e cicli condizionali (per il paradigma di programmazione strutturata);

· Macro.

Set di comandi

I comandi tipici del linguaggio assembly sono:

Comandi di trasferimento dati (mov, ecc.)

Comandi aritmetici (add, sub, imul, ecc.)

Operazioni logiche e bit a bit (or, and, xor, shr, ecc.)

· Comandi per controllare l'esecuzione del programma (jmp, loop, ret, ecc.)

Interruzione dei comandi di chiamata (a volte indicati come comandi di controllo): int

Comandi I/O alle porte (in, out)

Per microcontrollori e microcomputer sono caratteristici anche i comandi che eseguono il controllo e la transizione per condizione, ad esempio:

· Jne - sposta se non uguale;

· Jge - salta se maggiore o uguale.

Principali articoli correlati