LA CAMPANA

C'è chi ha letto questa notizia prima di te.
Iscriviti per ricevere gli ultimi articoli.
E-mail
Nome
Cognome
Come vuoi leggere La Campana?
Niente spam

Comandi dell'Assemblatore (Lezione)

PROGRAMMA DELLE LEZIONI

1. I principali gruppi di operazioni.

Pentium.

1. Gruppi di operazioni di base

I microprocessori eseguono una serie di istruzioni che implementano i seguenti gruppi di operazioni di base:

Operazioni di spedizione,

Operazioni aritmetiche,

operazioni logiche,

Operazioni di spostamento,

Operazioni di confronto e test,

Operazioni sui bit,

Operazioni di controllo del programma;

Operazioni di controllo del processore.

2. Mnemocodici dei comandi del processore Pentium

Quando si descrivono i comandi, vengono solitamente utilizzate le loro designazioni mnemoniche (codici mnemonici), che servono per impostare il comando durante la programmazione in linguaggio assembly... Per diverse versioni di Assembler, i codici mnemonici di alcuni comandi potrebbero differire. Ad esempio, per un comando per chiamare una subroutine, viene utilizzato il codice mnemonicoCHIAMATA o JSR ("Salta a Sottoprogramma"). Tuttavia, i codici mnemonici della maggior parte dei comandi per i principali tipi di microprocessori coincidono o differiscono leggermente, poiché sono abbreviazioni delle corrispondenti parole inglesi che determinano l'operazione da eseguire. Considera i codici mnemonici dei comandi adottati per i processori Pentium.

Comandi di inoltro. La squadra principale di questo gruppo è la squadraMOV , che fornisce il trasferimento di dati tra due registri o tra un registro e una cella di memoria. Alcuni microprocessori implementano il trasferimento tra due celle di memoria, nonché il trasferimento di massa del contenuto di più registri dalla memoria. Ad esempio, i microprocessori della famiglia 68 xxx di Motorola eseguire il comandoSPOSTARE , fornendo il trasferimento da una cella di memoria all'altra, e il comandoMUOVERSI , che scrive in memoria o carica dalla memoria il contenuto di un dato insieme di registri (fino a 16 registri). ComandoXCHG effettua lo scambio reciproco del contenuto di due registri del processore o di un registro e di una cella di memoria.

Comandi di input IN e ritiro FUORI trasferire dati dal registro del processore a un dispositivo esterno o ricevere dati da un dispositivo esterno a un registro. Questi comandi specificano il numero del dispositivo di interfaccia (porta I/O) attraverso il quale vengono trasferiti i dati. Si noti che molti microprocessori non dispongono di comandi speciali per l'accesso a dispositivi esterni. In questo caso, l'input e l'output dei dati nel sistema viene eseguito utilizzando il comandoMOV , in cui è impostato l'indirizzo del dispositivo di interfaccia richiesto. Pertanto, il dispositivo esterno viene indirizzato come una cella di memoria e una certa sezione viene allocata nello spazio degli indirizzi, in cui si trovano gli indirizzi dei dispositivi di interfaccia (porte) collegati al sistema.

Comandi aritmetici. I comandi principali di questo gruppo sono i comandi di addizione, sottrazione, moltiplicazione e divisione, che hanno una serie di opzioni. Comandi di addizione INSERISCI e sottrazione SUB eseguire le operazioni appropriate conCossessionato da due registri, un registro e una posizione di memoria, o dall'usare un operando immediato. Comandi ANNO DOMINI C , SB B l'addizione e la sottrazione vengono eseguite tenendo conto del valore dell'attributoC, che viene impostato quando viene formato il trasferimento durante l'esecuzione dell'operazione precedente. Con l'aiuto di queste istruzioni, viene realizzata l'aggiunta sequenziale di operandi, il cui numero di bit supera la capacità di bit del processore. Comando NEG cambia il segno dell'operando, traducendolo in un codice complementare.

Le operazioni di moltiplicazione e divisione possono essere eseguite su numeri con segno (comandiio MUL, io DIV ) o senza segno (comandi MUL, DIV Uno degli operandi è sempre allocato in un registro, il secondo può trovarsi in un registro, in una posizione di memoria o in un operando diretto. Il risultato dell'operazione si trova nel registro. Quando si moltiplica (comandiMUL , IMUL ), il risultato è un risultato a due cifre, per il quale vengono utilizzati due registri. Quando si divide (comandiDIV , IDIV ) come dividendo si utilizza l'operando a doppia cifra, che si trova in due registri, e di conseguenza, il quoziente e il resto sono scritti in due registri.

Comandi operazioni logiche ... Quasi tutti i microprocessori eseguono operazioni logiche AND, OR, OR esclusivo, che vengono eseguite sugli stessi bit degli operandi tramite comandi E, OPPURE, X O ... Le operazioni vengono eseguite sul contenuto di due registri, un registro e una locazione di memoria, oppure utilizzando un operando immediato. Comando NON inverte il valore di ogni bit dell'operando.

Comandi Shift... I microprocessori effettuano spostamenti aritmetici, logici e ciclici degli operandi indirizzati di uno o più bit. L'operando spostato può trovarsi in un registro o in una posizione di memoria e il numero di bit di scorrimento viene specificato utilizzando l'operando immediato contenuto nell'istruzione o determinato dal contenuto del registro specificato. La funzione di trasferimento è solitamente coinvolta nell'implementazione del turno.Cnel registro di stato (SR o EFLAGGE), in cui si trova l'ultimo bit dell'operando, che viene rimosso dal registro o dalla cella di memoria.

Confronta e testa i team ... Il confronto degli operandi viene solitamente eseguito utilizzando il comandoCMP , che sottrae operandi impostando i valori caratteristici N, Z, V, C nel registro di stato in base al risultato. In questo caso, il risultato della sottrazione non viene salvato e i valori degli operandi non vengono modificati. L'analisi successiva dei valori delle caratteristiche ottenuti consente di determinare il valore relativo (>,<, =) операндов со знаком или без знака. Использование различных способов адресации позволяет производит сравнение содержимого двух регистров, регистра и ячейки памяти, непосредственно заданного операнда с содержимым регистра или ячейки памяти.

Alcuni microprocessori eseguono un comando di test TST , che è una variante a operando singolo del comando di confronto. Quando questo comando viene eseguito, i segni sono impostati N, Z secondo il segno ed il valore (uguale o non uguale a zero) dell'operando indirizzato.

Comandi per operazioni sui bit ... Questi comandi impostano il valore della caratteristicaCnel registro di stato in base al valore del bit testatobn nell'operando indirizzato. In alcuni microprocessori, in base al risultato del test del bit, viene impostato il segnoZ... Numero bit di provanè impostato o dal contenuto del registro specificato nel comando o da un operando immediato.

I comandi di questo gruppo implementano diverse opzioni per modificare il bit testato. BT mantiene invariato il valore di questo bit. B T S dopo il test imposta il valore bn= 1, e il comando B T C - significato bn= 0 comando B T C inverte il valore del bit bn dopo averlo testato.

Operazioni di controllo del programma. Un gran numero di comandi vengono utilizzati per controllare il programma, tra cui:

- comandi di trasferimento di controllo incondizionato;

- comandi di salto condizionato;

- squadre per l'organizzazione di cicli di programmi;

- comandi di interruzione;

- comandi per modificare le funzioni.

Il trasferimento incondizionato del controllo viene eseguito dal comandoJMP che carica nel contatore del programmaPCnuovo contenuto, che è l'indirizzo del prossimo comando da eseguire. Questo indirizzo è specificato direttamente nel comandoJMP (indirizzamento diretto), o calcolato come somma del contenuto correntePCe l'offset del comando, che è un numero con segno (indirizzamento relativo). PerchéPCcontiene l'indirizzo del prossimo comando di programma, l'ultimo metodo imposta l'indirizzo di salto, spostato dall'indirizzo successivo di un numero specificato di byte. Con un offset positivo, il passaggio ai successivi comandi del programma, con un offset negativo - ai precedenti.

Una chiamata di subroutine viene effettuata anche mediante trasferimento incondizionato del controllo mediante il comandoCHIAMATA (o JSR ). Tuttavia, in questo caso, prima di caricare inPC nuovo contenuto che imposta l'indirizzo del primo comando del sottoprogramma, è necessario salvare il suo valore corrente (l'indirizzo del comando successivo) per garantire un ritorno al programma principale (o al sottoprogramma precedente quando si annidano i sottoprogrammi) dopo l'esecuzione del sottoprogramma. I comandi di diramazione condizionale (rami di programma) vengono caricati inPCnuovo contenuto se sono soddisfatte determinate condizioni, che di solito sono impostate in base al valore corrente dei vari segni nel registro di stato. Se la condizione non è soddisfatta, viene eseguito il successivo comando di programma.

I comandi di gestione delle funzionalità forniscono la scrittura: la lettura del contenuto del registro di stato, che memorizza le funzionalità, nonché la modifica dei valori delle singole funzionalità. Ad esempio, nei processori Pentium, i comandi sono implementati LAHF e SAHF che caricano il byte basso contenente i segni dal registro di stato EFLAG al byte basso del registro EAX e riempiendo il byte basso EFLAGGE dal registro E AX.. Squadre CLC, STC eseguire l'impostazione dei valori dell'attributo di trasferimento CF = 0, CF = 1 e il comando CMC provoca l'inversione del valore di questo attributo. Poiché le funzionalità determinano il corso dell'esecuzione del programma durante i salti condizionali, i comandi per modificare le funzionalità vengono solitamente utilizzati per controllare il programma.

Comandi CPU ... Questo gruppo include i comandi di arresto, nessuna operazione e una serie di comandi che determinano la modalità operativa del processore o dei suoi singoli blocchi. ComandoHLT termina l'esecuzione del programma e mette il processore in uno stato di halt, la cui uscita si verifica quando viene ricevuto un segnale di interruzione o riavvio ( Ripristina). Comando NO (comando "Vuoto"), che non provoca l'esecuzione di alcuna operazione, viene utilizzato per implementare ritardi del programma o colmare le lacune formate nel programma.

Comandi speciali CLI, STI disabilitare e abilitare il servizio di richieste di interrupt. Nei processori Pentium il bit di controllo (flag) viene utilizzato per questoSE nel registro EFLAGGE.

Molti microprocessori moderni eseguono un comando di identificazione che consente a un utente oa un altro dispositivo di ottenere informazioni sul tipo di processore utilizzato in un dato sistema. Nei processori Pentuim il comando è usato per questo ID CPU , quando eseguito, i dati necessari sul processore vanno ai registri EAX,EBX,ECX,EDX e può quindi essere letto dall'utente o dal sistema operativo.

A seconda delle modalità operative implementate dal processore e dei tipi di dati elaborati specificati, l'insieme dei comandi eseguibili può essere notevolmente ampliato.

Alcuni processori eseguono operazioni aritmetiche con numeri decimali binari o eseguono comandi speciali per correggere il risultato durante l'elaborazione di tali numeri. Molti processori ad alte prestazioni includono FPU - unità di elaborazione del numero C Virgola mobile.

Un certo numero di processori moderni implementano l'elaborazione di gruppo di diversi numeri interi o numeri C Virgola mobile con un solo comando secondo il principio SIMD ("Istruzione singola - Dati multipli ”) -“Un comando - Molti dati”. L'esecuzione simultanea di operazioni su più operandi migliora significativamente le prestazioni del processore quando si lavora con dati video e audio. Tali operazioni sono ampiamente utilizzate per l'elaborazione di immagini, segnali audio e altre applicazioni. Per eseguire queste operazioni, nei processori sono stati introdotti blocchi speciali che implementano i corrispondenti insiemi di istruzioni, che in vari tipi di processori ( Pentium, Athlon) sono stati nominatiMMX (“ Milti- Estensione multimediale ”) - Estensione multimediale,SSE("Estensione Streaming SIMD") - Streaming SIMD - estensione, “3 DEstensione- Espansione 3D.

Una caratteristica dei processori dell'azienda Intel , a partire dal modello 80286, viene fornito il controllo prioritario durante l'accesso alla memoria, che è garantito quando il processore funziona in modalità indirizzo virtuale protetto - " Modalità protetta "(Modalità protetta). Per implementare questa modalità vengono utilizzati appositi gruppi di comandi, che servono ad organizzare la protezione della memoria secondo l'algoritmo di accesso prioritario adottato.

UNIVERSITÀ NAZIONALE DELL'UZBEKISTAN CHE DÀ IL NOME A MIRZO ULUGBEK

FACOLTÀ DI INFORMATICA

Sull'argomento: analisi semantica di un file EXE.

Completato:

Taskent 2003.

Prefazione.

Linguaggio assembly e struttura dei comandi.

Struttura del file EXE (analisi semantica).

Struttura del file COM.

Il principio di funzionamento e diffusione del virus.

Disassemblatore.

Programmi.

Prefazione

La professione di programmazione è straordinaria e unica. Nel nostro tempo, la scienza e la vita non possono essere immaginate senza la tecnologia più recente. Tutto ciò che riguarda l'attività umana non è completo senza la tecnologia informatica. E questo contribuisce al suo alto sviluppo e perfezione. Sebbene lo sviluppo dei personal computer sia iniziato non molto tempo fa, durante questo periodo sono stati compiuti passi colossali nei prodotti software e questi prodotti saranno ampiamente utilizzati per molto tempo. Il campo della conoscenza relativa ai computer è esploso, così come la tecnologia correlata. Se non prendi in considerazione il lato commerciale, allora possiamo dire che non ci sono estranei in questo settore dell'attività professionale. Molte persone sono impegnate nello sviluppo di programmi non per motivi di profitto o guadagni, ma di loro spontanea volontà, per hobby. Naturalmente, ciò non dovrebbe influire sulla qualità del programma, e in questo business, per così dire, "business" c'è competizione e richiesta di prestazioni di qualità, lavoro stabile e soddisfare tutti i requisiti del nostro tempo. Vale anche la pena notare qui l'emergere dei microprocessori negli anni '60, che sono venuti a sostituire un gran numero di set di lampade. Esistono alcuni tipi di microprocessori molto diversi tra loro. Questi microprocessori differiscono l'uno dall'altro per dimensioni in bit e comandi di sistema incorporati. I più comuni sono: Intel, IBM, Celeron, AMD, ecc. Tutti questi processori sono correlati all'architettura avanzata dei processori Intel. La proliferazione dei microcomputer ha indotto un ripensamento del linguaggio assembly per due ragioni principali. Innanzitutto, i programmi scritti in linguaggio assembly richiedono molta meno memoria e tempo di esecuzione. In secondo luogo, la conoscenza del linguaggio assembly e del codice macchina risultante fornisce una comprensione dell'architettura della macchina, che è improbabile che venga fornita quando si lavora in un linguaggio di alto livello. Sebbene la maggior parte dei professionisti del software sviluppi in linguaggi di alto livello come Pascal, C o Delphi, che sono più facili da scrivere programmi, il software più potente ed efficiente è scritto interamente o in parte in linguaggio assembly. I linguaggi di alto livello sono stati progettati per evitare la tecnicità speciale di computer specifici. E il linguaggio assembly, a sua volta, è progettato per le specifiche specifiche del processore. Pertanto, per scrivere un programma in linguaggio assembly per un determinato computer, è necessario conoscerne l'architettura. In questi giorni, il prodotto software principale è il file EXE. Dati gli aspetti positivi di ciò, l'autore del programma può essere certo della sua integrità. Ma a volte spesso non è così. C'è anche un smontatore. Con l'aiuto di un disassemblatore, puoi scoprire interruzioni e codici di programma. Non sarà difficile per una persona esperta del linguaggio assembly rifare l'intero programma a proprio piacimento. Forse da qui deriva il problema più insolubile: il virus. Perché le persone scrivono un virus? Alcuni fanno questa domanda con sorpresa, altri con rabbia, ma tuttavia, ci sono ancora persone interessate a questo problema non dal punto di vista di causare danni, ma come interesse per la programmazione del sistema. I virus scrivono per vari motivi. Ad alcune persone piacciono le chiamate di sistema, ad altri piace migliorare la loro conoscenza dell'assemblatore. Cercherò di delineare tutto questo nella mia tesina. Dice anche non solo sulla struttura del file EXE, ma anche sul linguaggio assembly.

^ Linguaggio dell'Assemblea.

È interessante tracciare, dai tempi dei primi computer ai giorni nostri, le trasformazioni della comprensione del linguaggio assembly tra i programmatori.

Un tempo l'assemblatore era un linguaggio, senza la cui conoscenza era impossibile far fare a un computer qualcosa di utile. La situazione è gradualmente cambiata. Sono apparsi mezzi più convenienti per comunicare con un computer. Ma, a differenza di altri linguaggi, l'assemblatore non è morto, inoltre, non poteva farlo in linea di principio. Come mai? Alla ricerca di una risposta, cercheremo di capire che cos'è il linguaggio assembly in generale.

In breve, il linguaggio assembly è una rappresentazione simbolica di un linguaggio macchina. Tutti i processi nella 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 per ogni tipo di computer è diverso. Questo vale anche per l'aspetto dei programmi scritti in linguaggio assembly e le idee che questo linguaggio riflette.

È impossibile risolvere veramente problemi relativi all'hardware (o anche, inoltre, problemi dipendenti dall'hardware come il miglioramento delle prestazioni del programma) senza conoscere l'assemblatore.

Un programmatore o qualsiasi altro utente può utilizzare qualsiasi mezzo di alto livello, fino a programmi per costruire mondi virtuali, e può anche non sospettare che in realtà il computer non esegua i comandi del linguaggio in cui è scritto il suo programma, ma li trasformi rappresentazione sotto forma di sequenze noiose e noiose di comandi di un linguaggio completamente diverso - macchina. Ora immaginiamo che un tale utente abbia un problema non standard o semplicemente qualcosa è andato storto. Ad esempio, il suo programma deve funzionare con un dispositivo insolito o eseguire altre azioni che richiedono la conoscenza dei principi dell'hardware del computer. Non importa quanto sia intelligente il programmatore, non importa quanto sia bravo il linguaggio in cui ha scritto il suo meraviglioso programma, non può fare a meno della conoscenza dell'assemblatore. E non è un caso che quasi tutti i compilatori di linguaggi di alto livello contengano mezzi per collegare i propri moduli con moduli in assembler o supportino l'accesso al livello di programmazione assembler.

Certo, il tempo dei generalisti informatici è passato. Come si suol dire, non si può afferrare l'immensità. Ma c'è qualcosa in comune, una sorta di fondamento su cui si costruisce qualsiasi seria educazione informatica. Questa è la conoscenza dei principi di un computer, della sua architettura e del linguaggio assembly come riflesso e incarnazione di questa conoscenza.

Un tipico computer moderno (basato su i486 o Pentium) è costituito dai seguenti componenti (Figura 1).

Riso. 1. Computer e periferiche

Riso. 2. Schema a blocchi di un personal computer

Dalla figura (Figura 1) si può notare che il computer è composto da più dispositivi fisici, ognuno dei quali è connesso ad un'unità, chiamata unità di sistema. Logicamente parlando, è chiaro che svolge il ruolo di una sorta di dispositivo di coordinamento. Diamo un'occhiata all'interno dell'unità di sistema (non è necessario provare a entrare nel monitor - non c'è nulla di interessante e inoltre è pericoloso): apriamo la custodia e vediamo alcune schede, blocchi, cavi di collegamento. Per comprendere il loro scopo funzionale, diamo un'occhiata allo schema a blocchi di un tipico computer (Fig. 2). Non pretende di essere un'accuratezza incondizionata ed ha il solo scopo di mostrare lo scopo, l'interconnessione e la composizione tipica degli elementi di un moderno personal computer.

Parliamo del circuito di fig. 2 in uno stile un po' anticonvenzionale.
È naturale per una persona, quando incontra qualcosa di nuovo, cercare alcune associazioni che possono aiutarlo a imparare l'ignoto. Quali associazioni causa un computer? Per me, ad esempio, il computer è spesso associato alla persona stessa. Come mai?

Una persona che creava un computer da qualche parte nelle profondità di se stesso pensava di creare qualcosa di simile a se stesso. Il computer ha organi per percepire le informazioni dal mondo esterno: è una tastiera, un mouse, unità a disco magnetico. Nella fig. 2 questi organi si trovano a destra dei bus di sistema. Il computer ha organi che "digeriscono" le informazioni ricevute: questi sono il processore centrale e la memoria ad accesso casuale. E infine, il computer ha organi del linguaggio che producono i risultati dell'elaborazione. Questi sono anche alcuni dei dispositivi sulla destra.

I computer moderni, ovviamente, sono tutt'altro che umani. Possono essere paragonati a creature che interagiscono con il mondo esterno a livello di un insieme ampio, ma limitato di riflessi incondizionati.
Questo insieme di riflessi forma un sistema di istruzioni macchina. A qualunque livello si comunichi con un computer, alla fine tutto si riduce a una sequenza noiosa e monotona di istruzioni della macchina.
Ogni comando della macchina è una specie di stimolo per l'eccitazione dell'uno o dell'altro riflesso incondizionato. La risposta a questo stimolo è sempre univoca ed è "cablata" nel blocco di microistruzioni sotto forma di microprogramma. Questo microprogramma implementa azioni per implementare un comando macchina, ma già a livello di segnali forniti a determinati circuiti logici del computer, controllando così vari sottosistemi del computer. Questo è il cosiddetto principio del controllo del microprogramma.

Continuando l'analogia con una persona, notiamo: affinché un computer possa mangiare bene, sono stati inventati molti sistemi operativi, compilatori per centinaia di linguaggi di programmazione, ecc.. Ma tutti sono, in realtà, solo un piatto su cui il cibo (programmi) viene consegnato secondo determinate regole stomaco (computer). Solo lo stomaco di un computer ama il cibo dietetico e monotono: forniscigli informazioni strutturate sotto forma di sequenze rigorosamente organizzate di zero e uno, le cui combinazioni costituiscono il linguaggio macchina.

Quindi, essendo esteriormente un poliglotta, il computer comprende solo una lingua: la lingua delle istruzioni della macchina. Certo, per comunicare e lavorare con un computer, non è necessario conoscere questo linguaggio, ma quasi tutti i programmatori professionisti prima o poi si trovano ad affrontare la necessità di impararlo. Fortunatamente, un programmatore non ha bisogno di cercare di comprendere il significato di varie combinazioni di numeri binari, poiché negli anni '50, i programmatori hanno iniziato a utilizzare per programmare un analogo simbolico di un linguaggio macchina, che chiamavano linguaggio assembly. Questo linguaggio riflette accuratamente tutte le caratteristiche del linguaggio macchina. Ecco perché, a differenza dei linguaggi di alto livello, il linguaggio assembly è diverso per ogni tipo di computer.

Da tutto quanto sopra, possiamo concludere che poiché il linguaggio assembly è "nativo" per un computer, il programma più efficiente può essere scritto solo in esso (a condizione che sia scritto da un programmatore qualificato). C'è un piccolo "ma" qui: questo è un processo molto laborioso che richiede molta attenzione ed esperienza pratica. Pertanto, in realtà, scrivono principalmente programmi in assembler che dovrebbero garantire un lavoro efficiente con l'hardware. A volte le parti del programma che sono critiche in termini di tempo di esecuzione o consumo di memoria sono scritte in linguaggio assembly. Successivamente, vengono formattati come subroutine e combinati con codice di linguaggio di alto livello.

Ha senso iniziare a imparare il linguaggio assembly di qualsiasi computer solo dopo aver scoperto quale parte del computer è rimasta visibile e accessibile per la programmazione in questo linguaggio. Questo è il cosiddetto modello software di un computer, una parte del quale è un modello software di un microprocessore, che contiene 32 registri, in un modo o nell'altro, disponibili per l'uso da parte di un programmatore.

Questi registri possono essere suddivisi in due grandi gruppi:

^ 16 registri utente;

16 registri di sistema.

Nei programmi in linguaggio assembly, i registri sono usati molto pesantemente. La maggior parte dei registri ha uno scopo funzionale specifico.

Come suggerisce il nome, i registri personalizzati sono chiamati registri personalizzati perché il programmatore può usarli quando scrive i propri programmi. Questi registri includono (Fig. 3):

Otto registri a 32 bit che possono essere utilizzati dai programmatori per memorizzare dati e indirizzi (chiamati anche registri di uso generale (RON)):

sei registri di segmento: cs, ds, ss, es, fs, gs;

stato e registri di controllo:

Flag register eflags/flag;

Il registro del puntatore del comando eip/ip.

Riso. 3. Registri utente dei microprocessori i486 e Pentium

Perché molti di questi registri sono mostrati con separatori obliqui? No, questi non sono registri diversi: sono parti di un unico grande registro a 32 bit. Possono essere usati come oggetti separati nel programma. Questo viene fatto per garantire l'operatività dei programmi scritti per modelli a 16 bit di fascia bassa di microprocessori Intel, a partire da i8086. I microprocessori i486 e Pentium hanno per lo più registri a 32 bit. Il loro numero, ad eccezione dei registri di segmento, è lo stesso dell'i8086, ma la dimensione è maggiore, il che si riflette nelle loro designazioni: hanno
il prefisso e (esteso).

^ Registri per scopi generici
Tutti i registri di questo gruppo consentono l'accesso alle loro parti "inferiori" (vedi Fig. 3). Osservando questa figura, si noti che 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. Questo viene fatto, come abbiamo notato sopra, per la compatibilità con i modelli a 16 bit inferiori dei microprocessori Intel.

Elenchiamo i registri appartenenti al gruppo dei registri di uso generale. Poiché questi registri si trovano fisicamente nel microprocessore all'interno dell'unità logica aritmetica (ALU), vengono anche chiamati registri ALU:

eax / ax / ah / al (Registro dell'accumulatore) - batteria.
Viene utilizzato per memorizzare dati intermedi. In alcuni comandi è richiesto l'uso di questo registro;

ebx / bx / bh / bl (Registro di base) - registro di base.
Viene utilizzato per memorizzare l'indirizzo di base di un oggetto in memoria;

ecx / cx / ch / cl (registro conteggio) - registro contatore.
Utilizzato nei comandi che eseguono alcune azioni ripetitive. Il suo utilizzo è spesso implicito e nascosto nell'algoritmo del comando corrispondente.
Ad esempio, il comando per l'organizzazione del loop, oltre a trasferire il controllo al comando che si trova ad un certo indirizzo, analizza e decrementa di uno il valore del registro ecx/cx;

edx / dx / dh / dl (registro dati) - registro dati.
Proprio come il registro eax / ax / ah / al, memorizza i dati intermedi. In alcuni comandi è richiesto il suo utilizzo; per alcuni comandi questo avviene implicitamente.

I seguenti due registri sono utilizzati per supportare le cosiddette operazioni di concatenamento, cioè operazioni che eseguono elaborazioni sequenziali di stringhe di elementi, ciascuna delle quali può essere lunga 32, 16 o 8 bit:

esi / si (registro dell'indice di origine) - indice di origine.
Questo registro nelle operazioni di concatenamento contiene l'indirizzo corrente dell'elemento nella catena sorgente;

edi / di (registro indice di destinazione) - indice del destinatario (destinatario).
Questo registro nelle operazioni di concatenamento contiene l'indirizzo corrente nella catena di destinazione.

In un'architettura a microprocessore, una struttura dati come uno stack è supportata a livello di firmware. Per lavorare con lo stack nel sistema di comando a microprocessore c'è squadre speciali, e nel modello software del microprocessore ci sono registri speciali per questo:

esp / sp (registro del puntatore dello stack) - registro del puntatore dello stack.
Contiene il puntatore alla parte superiore dello stack nel segmento dello stack corrente.

ebp / bp (Base Pointer register) - registro del puntatore della base dello stack frame.
Progettato per organizzare l'accesso casuale ai dati all'interno dello stack.

Uno stack è un'area di un programma per l'archiviazione temporanea di dati arbitrari. Ovviamente i dati possono essere memorizzati nel segmento dati, ma in questo caso, per ogni dato memorizzato per l'ora, deve essere creata una cella di memoria denominata separata, che aumenta le dimensioni del programma e il numero di nomi utilizzati. La comodità di uno stack è che il suo ambito è riutilizzabile e i dati vengono archiviati nello stack e recuperati da lì utilizzando gli efficienti comandi push e pop senza specificare alcun nome.
Lo stack viene tradizionalmente utilizzato, ad esempio, per memorizzare il contenuto dei registri utilizzati da un programma prima di chiamare una subroutine, che a sua volta utilizzerà i registri del processore "per i propri scopi". I contenuti originali dei registri vengono estratti dallo stack al ritorno dalla subroutine. Un'altra tecnica comune consiste nel passare i parametri necessari attraverso lo stack a una subroutine. La subroutine, conoscendo l'ordine in cui i parametri vengono inseriti nello stack, può prelevarli da lì e utilizzarli durante la sua esecuzione. Una caratteristica distintiva dello stack è una sorta di ordine di recupero dei dati che contiene: in qualsiasi momento, nello stack è disponibile solo l'elemento superiore, ad es. l'ultimo elemento spinto sulla pila. Scaricare l'elemento in cima alla pila rende disponibile l'elemento successivo. Gli elementi dello stack si trovano nell'area di memoria allocata per lo stack, a partire dal fondo dello stack (cioè dal suo indirizzo massimo) ad indirizzi successivamente decrescenti. L'indirizzo dell'elemento più accessibile è memorizzato nel registro del puntatore dello stack SP. Come qualsiasi altra area della memoria del programma, lo stack deve entrare in un segmento o formare un segmento separato. In ogni caso, l'indirizzo del segmento di questo segmento è posto nel registro del segmento dello stack SS. Pertanto, la coppia di registri SS: SP descrive l'indirizzo della cella dello stack disponibile: SS memorizza l'indirizzo del segmento dello stack e SP memorizza l'offset degli ultimi dati memorizzati nello stack (Fig. 4, a). Prestare attenzione al fatto che nello stato iniziale il puntatore dello stack SP punta a una cella che si trova sotto il fondo dello stack e non è incluso in esso.

Fig 4. Organizzazione dello stack: a - stato iniziale, b - dopo aver caricato un elemento (in questo esempio - il contenuto del registro AX), c - dopo aver caricato il secondo elemento (contenuto del registro DS), d - dopo aver scaricato uno elemento, e - dopo aver scaricato due articoli e tornare alle condizioni originali.

Il caricamento in pila avviene tramite un apposito comando di operazione pila push (push). Questo comando decrementa prima di 2 il contenuto del puntatore dello stack, quindi inserisce l'operando all'indirizzo in SP. Se, ad esempio, vogliamo salvare temporaneamente sullo stack il contenuto del registro AX, dovremmo eseguire il comando

Lo stack passa allo stato mostrato in Fig. 1.10, b. Si può vedere che il puntatore dello stack viene spostato di due byte verso l'alto (verso gli indirizzi inferiori) e l'operando specificato nel comando push viene scritto su questo indirizzo. Il seguente comando di caricamento nello stack, ad esempio,

metterà lo stack nello stato mostrato in Fig. 1.10, c. Lo stack ora memorizzerà due elementi e solo quello in alto, a cui punta il puntatore dello stack SP, sarà disponibile. Se, dopo qualche tempo, abbiamo bisogno di ripristinare il contenuto originale dei registri memorizzati nello stack, dobbiamo eseguire i comandi pop:

pop DS
pop AX

Quanto dovrebbe essere grande lo stack? Dipende da quanto viene usato pesantemente nel programma. Se, ad esempio, prevedi di archiviare un array di 10.000 byte nello stack, lo stack deve avere almeno questa dimensione. Si tenga presente che in alcuni casi lo stack viene utilizzato automaticamente dal sistema, in particolare quando viene eseguito il comando di interrupt int 21h. Con questo comando, il processore prima inserisce nello stack l'indirizzo di ritorno, quindi il DOS vi invia il contenuto dei registri e altre informazioni relative al programma interrotto. Pertanto, anche se il programma non utilizza affatto lo stack, esso deve comunque essere presente nel programma e avere una dimensione di almeno alcune decine di parole. Nel nostro primo esempio, mettiamo in pila 128 parole, il che è certamente sufficiente.

^ La struttura di un programma in linguaggio assembly

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 un insieme di frasi linguistiche, ognuna delle quali occupa una riga separata di codice di programma.

Le frasi assembly sono di quattro tipi:

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;

le macro sono frasi del testo del programma che si formano in un certo modo, che vengono sostituite da altre frasi durante la trasmissione;

direttive che istruiscono il traduttore assembler a eseguire determinate azioni. Le direttive non hanno analoghi nella rappresentazione delle macchine;

righe di commento contenenti qualsiasi carattere, comprese le lettere dell'alfabeto russo. I commenti vengono ignorati dal traduttore.

^ 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 sia in grado di riconoscerli, 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 in questo modo sono i diagrammi di sintassi e i moduli Backus-Naur estesi. Per uso pratico, i diagrammi di sintassi sono più convenienti. Ad esempio, la sintassi delle frasi assembly può essere descritta utilizzando i diagrammi di sintassi mostrati nelle figure seguenti.

Riso. 5. Formato della frase assembler

Riso. 6. Formato delle direttive

Riso. 7. Formato dei comandi e delle macro

In queste cifre:

nome etichetta è un identificatore, il cui valore è l'indirizzo del primo byte della frase del testo sorgente del programma che designa;

name è un 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;

un codice operazione (COP) e una direttiva sono designazioni mnemoniche della corrispondente istruzione macchina, macro o direttiva traduttore;

gli operandi sono parti di un'istruzione, 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.

^ Come usare i diagrammi di sintassi? È molto semplice: tutto quello che devi fare è trovare e poi passare 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. Quando si lavora con i diagrammi di sintassi, prestare attenzione alla direzione di attraversamento, indicata dalle frecce, poiché tra i percorsi potrebbero esserci quelli lungo i quali si può andare da destra a sinistra. In effetti, i diagrammi di sintassi riflettono la logica del traduttore durante l'analisi delle frasi di input del programma.

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

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

Numeri da 0 a 9;

Segni ?, @, $, _, &;

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

Le frasi assembler sono formate da token, che sono sequenze sintatticamente inseparabili di caratteri validi nella lingua che hanno senso per un traduttore.

I token sono:

gli identificatori sono sequenze di caratteri validi utilizzati per designare oggetti di 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. Come simboli, puoi usare lettere dell'alfabeto latino, numeri e alcuni caratteri speciali - _,?, $, @. L'identificatore non può iniziare con un carattere numerico. La lunghezza dell'identificatore può essere fino a 255 caratteri, sebbene il traduttore accetti solo i primi 32 e ignori il resto. Puoi regolare la lunghezza dei possibili identificatori usando l'opzione riga di comando mv. Inoltre, è possibile dire al traduttore di distinguere tra lettere maiuscole e minuscole o ignorare la loro differenza (cosa che viene eseguita per impostazione predefinita).

^ Comandi dell'assemblatore.

I comandi dell'assemblatore rivelano la capacità di trasferire i propri requisiti al computer, il meccanismo per trasferire il controllo nel programma (loop e salti) per i confronti logici e l'organizzazione del software. Tuttavia, le attività programmabili raramente sono così facili. La maggior parte dei programmi contiene una serie di cicli in cui vengono ripetute diverse istruzioni fino al raggiungimento di un determinato requisito e vari controlli per determinare quale delle diverse azioni eseguire. Alcuni comandi possono trasferire il controllo modificando la normale sequenza di passaggi modificando direttamente il valore di offset nel puntatore del comando. Come accennato in precedenza, esistono istruzioni diverse per processori diversi, ma prenderemo in considerazione alcune istruzioni per i processori 80186, 80286 e 80386.

Per descrivere lo stato dei flag dopo l'esecuzione di un determinato comando, utilizzeremo un esempio da una tabella che riflette la struttura del registro eflags:

La riga inferiore di questa tabella elenca i valori dei flag dopo l'esecuzione del comando. In questo caso, vengono utilizzate le seguenti designazioni:

1 - dopo aver eseguito il comando, viene impostato il flag (uguale a 1);

0 - dopo l'esecuzione del comando, il flag viene cancellato (uguale a 0);

r - il valore del flag dipende dal risultato del comando;

Dopo aver eseguito il comando, il flag non è definito;

spazio - dopo aver eseguito il comando, il flag non cambia;

Le seguenti convenzioni vengono utilizzate per rappresentare gli operandi nei diagrammi di sintassi:

r8, r16, r32 - un operando in uno dei registri in byte, parola o doppia parola;

m8, m16, m32, m48 - byte, parola, doppia parola o operando di memoria a 48 bit;

i8, i16, i32 - operando immediato a byte, parola o doppia parola;

a8, a16, a32 - indirizzo relativo (offset) nel segmento di codice.

Comandi (in ordine alfabetico):

* Questi comandi sono descritti in dettaglio.

INSERISCI
(ADdizione)

aggiunta

^ Schema di comando:

aggiungi destinazione, fonte

Scopo: aggiunta di due operandi sorgente e destinazione in byte, parola o doppia parola.

Algoritmo di lavoro:

aggiungere gli operandi di origine e di destinazione;

scrivere il risultato dell'aggiunta al destinatario;

impostare bandiere.

Lo stato dei flag dopo l'esecuzione del comando:

Applicazione:
Il comando add viene utilizzato per aggiungere due operandi interi. Il risultato dell'addizione è posto all'indirizzo del primo operando. Se il risultato dell'addizione è al di fuori dei limiti dell'operando del ricevitore (si verifica un overflow), allora questa situazione dovrebbe essere presa in considerazione analizzando il flag cf e il successivo possibile utilizzo del comando adc. Ad esempio, aggiungi i valori in ax e ch. L'aggiunta dovrebbe tenere conto della possibilità di overflow.

Registro più registro o memoria:

| 000000dw | modregr / rm |

Registro AX (AL) più valore immediato:

| 0000010w | --data-- | dati se w = 1 |

Registro o memoria più valore immediato:

| 100000sw | mod000r / m | --data-- | dati se BW = 01 |

CHIAMATA
(CHIAMATA)

Chiamare una procedura o un'attività

^ Schema di comando:

Scopo:

trasferimento del controllo a una procedura vicina o lontana con memorizzazione dell'indirizzo del punto di ritorno nello stack;

cambio di compiti.

Algoritmo di lavoro:
determinato dal tipo di operando:

Near label - il contenuto del puntatore del comando eip/ip viene inserito nello stack e il nuovo valore dell'indirizzo corrispondente all'etichetta viene caricato nello stesso registro;

Far label: il contenuto dei puntatori dei comandi eip/ip e cs viene inserito nello stack. Quindi i nuovi valori di indirizzo corrispondenti all'etichetta lontana vengono caricati negli stessi registri;

R16, 32 o m16, 32 - definiscono un registro o una posizione di memoria contenente gli offset nel segmento di istruzione corrente a cui viene trasferito il controllo. Quando il controllo viene trasferito, il contenuto del puntatore del comando eip/ip viene inserito nello stack;

Memory Pointer - Definisce una locazione di memoria contenente un puntatore di 4 o 6 byte alla procedura richiamata. La struttura di tale puntatore è 2 + 2 o 2 + 4 byte. L'interpretazione di tale puntatore dipende dalla modalità operativa del microprocessore:

^ Stato dei flag dopo l'esecuzione del comando (eccetto il cambio di attività):

l'esecuzione del comando non influisce sui flag

Quando un'attività viene commutata, i valori dei flag cambiano in base alle informazioni del registro eflags nel segmento di stato TSS dell'attività a cui passare.
Applicazione:
Il comando di chiamata consente di organizzare un trasferimento di controllo flessibile e multivariato ad un sottoprogramma mantenendo l'indirizzo del punto di ritorno.

Informazioni sul codice oggetto (quattro formati):

Indirizzamento diretto del segmento:

| 11101000 | disp-basso | diep-alto |

Indirizzamento indiretto in un segmento:

| 11111111 | mod010r / m |

Indirizzamento indiretto tra segmenti:

| 11111111 | mod011r / m |

Indirizzamento diretto tra i segmenti:

| 10011010 | offset-basso | offset-alto | seg-basso | seg-alto |

CMP
(operandi Confronta)

Confronto di operandi

^ Schema di comando:

cmp operando1, operando2

Scopo: confronto di due operandi.

Algoritmo di lavoro:

eseguire la sottrazione (operando1-operando2);

a seconda del risultato, impostare i flag, non modificare operando1 e operando2 (ovvero non memorizzare il risultato).

Applicazione:
Questo comando utilizzato per sottrarre due operandi senza modificare gli operandi. I flag vengono impostati in base ai risultati dell'esecuzione del comando. Il comando cmp viene utilizzato con i comandi del ramo condizionale e il comando byte per valore setcc.

Informazioni sul codice oggetto (tre formati):

Registro o memoria con registro:

| 001110dw | modregr / m |

Valore immediato con registro AX (AL):

| 0011110w | --data-- | dati se w = 1 |

Valore immediato con registro o memoria:

| 100000sw | mod111r / m | --data-- | dati se sw = 0 |

DEC
(Decremento operando di 1)

Diminuendo l'operando di uno

^ Schema di comando:

dec operando

Scopo: decrementare di 1 il valore di un operando in memoria o registro.

Algoritmo di lavoro:
il comando sottrae 1 dall'operando. Lo stato dei flag dopo l'esecuzione del comando:

Applicazione:
Il comando dec viene utilizzato per decrementare di uno il valore di un byte, parola, doppia parola in memoria o registro. Si noti, tuttavia, che il comando non influisce sul flag cf.

Registrati: | 01001reg |

^ Registro o memoria: | 1111111w | mod001r/m |

DIV
(Dividi senza segno)

Divisione senza segno

Schema di comando:

divisore div

Scopo: eseguire operazioni di divisione di due valori binari senza segno.

^ Algoritmo di lavoro:
Il comando richiede la specifica di due operandi: il dividendo e il divisore. Il dividendo è impostato implicitamente e la sua dimensione dipende dalla dimensione del divisore, che è specificata nel comando:

se il divisore è di dimensioni in byte, il dividendo deve trovarsi nel registro dell'ascia. Dopo l'operazione, il quoziente viene posto in al e il resto in ah;

se il divisore è una parola, allora il dividendo deve trovarsi in una coppia di registri dx: ax, e la parte meno significativa del dividendo è in ax. Dopo l'operazione, il quoziente è posto in ax e il resto è in dx;

se il divisore è una doppia parola, allora il dividendo deve trovarsi nella coppia di registri edx: eax, con la parte meno significativa del dividendo in eax. Dopo l'operazione, il quoziente viene messo in eax e il resto in edx.

^ Stato dei flag dopo l'esecuzione del comando:

Applicazione:
Il comando esegue la divisione intera degli operandi con l'output del risultato della divisione come quoziente e resto della divisione. Quando si esegue un'operazione di divisione, può verificarsi un'eccezione: 0 - errore di divisione. Questa situazione si verifica in uno dei due casi: il divisore è 0 o il quoziente è troppo grande per entrare nel registro eax / ax / al.

Informazioni sul codice oggetto:

| 1111011w | mod110r / m |

INT
(Interrompere)

Chiamare una routine di servizio di interruzione

^ Schema di comando:

int interrupt_number

Scopo: chiamare la routine del servizio di interrupt con il numero di interrupt specificato dall'operando dell'istruzione.

^ Algoritmo di lavoro:

spingere il registro eflags / flags e restituire l'indirizzo nello stack. Quando si scrive l'indirizzo di ritorno, viene scritto prima il contenuto del registro del segmento cs, quindi il contenuto del puntatore del comando eip/ip;

azzerare i flag if e tf;

trasferire il controllo al gestore di interrupt con il numero specificato. Il meccanismo di trasferimento del controllo dipende dalla modalità operativa del microprocessore.

^ Stato dei flag dopo l'esecuzione del comando:

Applicazione:
Come puoi vedere dalla sintassi, ci sono due forme di questo comando:

int 3 - ha il suo codice operativo individuale 0cch e occupa un byte. Questo fatto rende molto comodo l'uso in vari debugger software per impostare punti di interruzione sostituendo il primo byte di qualsiasi comando. Il microprocessore, incontrando un comando con codice operazione 0cch nella sequenza di comando, chiama il programma di elaborazione degli interrupt con il vettore numero 3, che serve per comunicare con debugger software.

La seconda forma del comando richiede due byte, ha un codice operativo 0cdh e consente di avviare una chiamata a una routine di servizio di interruzione con un numero di vettore nell'intervallo 0-255. Le caratteristiche del trasferimento del controllo, come notato, dipendono dalla modalità operativa del microprocessore.

Informazioni sul codice oggetto (due formati):

Registrati: | 01000reg |

^ Registro o memoria: | 1111111w | mod000r/m |

JCC
JCXZ / JECXZ
(Salta se condizione)

(Salta se CX = Zero / Salta se ECX = Zero)

Salta se la condizione è soddisfatta

Salta se CX / ECX è zero

^ Schema di comando:

etichetta jcc
etichetta jcxz
etichetta jecxz

Scopo: transizione all'interno del segmento corrente di comandi, a seconda di una determinata condizione.

^ Algoritmo dei comandi (eccetto jcxz / jecxz):
Verifica dello stato dei flag in base al codice dell'operazione (riflette la condizione verificata):

se la condizione verificata è vera, vai alla cella indicata dall'operando;

se la condizione selezionata è falsa, trasferire il controllo al comando successivo.

Algoritmo del comando jcxz / jecxz:
Verificando la condizione che il contenuto del registro ecx/cx sia uguale a zero:

se la condizione controllata

Strutture assemblatrici

Gli array che abbiamo considerato sopra sono una raccolta di elementi dello stesso tipo. Ma spesso nelle applicazioni diventa necessario considerare un certo insieme di dati. tipi diversi come un tipo unico.

Questo è molto importante, ad esempio, per i programmi database, dove è necessario associare ad un oggetto una raccolta di dati di tipo diverso.

Ad esempio, abbiamo esaminato il Listato 4 in precedenza, in cui abbiamo lavorato con un array di elementi a tre byte. Ciascun elemento, a sua volta, rappresentava due elementi di tipo diverso: un campo contatore di un byte e un campo di due byte che poteva contenere altre informazioni necessarie per l'archiviazione e l'elaborazione. Se il lettore ha familiarità con uno dei linguaggi di alto livello, allora sa che un tale oggetto viene solitamente descritto utilizzando un tipo di dati speciale - strutture.

Al fine di migliorare l'usabilità del linguaggio assembly, è stato introdotto anche questo tipo di dati.

A-priorità struttura è un tipo di dati costituito da un numero fisso di elementi di tipo diverso.

Per utilizzare le strutture in un programma, devi fare tre cose:

    Chiedere modello di struttura .

    Per definizione, ciò significa definire un nuovo tipo di dati, che può essere successivamente utilizzato per definire variabili di questo tipo.

    Definire istanza di struttura .

    Questa fase implica l'inizializzazione di una variabile specifica con una struttura predefinita (usando un modello).

    Organizzare accesso agli elementi della struttura .

È molto importante che tu capisca la differenza tra descrizione struttura nel programma e la sua definendo.

Descrivere la struttura nel programma significa solo indicare il suo schema o modello; nessuna memoria è allocata.

Questo modello può essere considerato solo come informazione per il traduttore sulla posizione dei campi e sui loro valori predefiniti.

Definire struttura significa indicare al traduttore di allocare memoria e assegnare un nome simbolico a quest'area di memoria.

È possibile descrivere la struttura in un programma solo una volta, ma è possibile definirla un numero qualsiasi di volte.

Descrizione del modello di struttura

La descrizione del modello di struttura ha la seguente sintassi:

nome_struttura STRUC

struct_name FINISCE

Qui è una sequenza di direttive che descrivono i dati db, dw, dd, dq e dt.

I loro operandi determinano la dimensione dei campi e, se necessario, i valori iniziali. Questi valori verranno probabilmente inizializzati nei campi corrispondenti durante la definizione della struttura.

Come abbiamo notato durante la descrizione del modello, non viene allocata memoria, poiché si tratta solo di informazioni per il traduttore.

Posizione Il template nel programma può essere arbitrario, ma, seguendo la logica del traduttore one-pass, deve trovarsi fino al punto in cui è definita la variabile con il tipo di questa struttura. Cioè, quando si descrive una variabile con il tipo di una struttura in un segmento di dati, il suo modello deve essere posizionato all'inizio del segmento di dati o prima di esso.

Consideriamo di lavorare con le strutture usando l'esempio della modellazione di un database di dipendenti di un determinato dipartimento.

Per semplicità, al fine di evitare i problemi di conversione delle informazioni durante l'immissione, converremo che tutti i campi sono simbolici.

Definiamo la struttura record di questo database con il seguente template:

Definire i dati con un tipo di struttura

Per utilizzare la struttura descritta utilizzando il modello nel programma, è necessario definire una variabile con il tipo di questa struttura. Per questo, viene utilizzata la seguente costruzione sintattica:

[nome variabile] nome_struttura

    nome variabile- identificatore di una variabile di questo tipo strutturale.

    Il nome della variabile è facoltativo. Se non lo specifichi, un'area di memoria della dimensione nella somma delle lunghezze di tutti elementi della struttura.

    lista di valori- un elenco racchiuso tra parentesi angolari valori iniziali elementi della struttura, separati da virgole.

    Anche il suo incarico è facoltativo.

    Se l'elenco è incompleto, tutti i campi della struttura per questa variabile vengono inizializzati con i valori del modello, se presenti.

    È possibile inizializzare i singoli campi, ma in questo caso i campi mancanti devono essere separati da virgole. I campi mancanti verranno inizializzati con i valori del modello di struttura. Se, quando si definisce una nuova variabile con il tipo di questa struttura, siamo d'accordo con tutti i valori del campo nel suo modello (ovvero, impostato di default), allora devi solo scrivere parentesi angolari.

    Per esempio: operaio vincitore.

Ad esempio, definiamo più variabili con il tipo della struttura sopra descritta.

Metodi per lavorare con la struttura

L'idea di introdurre un tipo strutturato in qualsiasi linguaggio di programmazione è combinare variabili di tipi diversi in un unico oggetto.

Il linguaggio deve avere un mezzo per accedere a queste variabili all'interno di un'istanza specifica della struttura. Per fare riferimento a un campo di una struttura in un comando, viene utilizzato un operatore speciale - simbolo ". " (punto)... Viene utilizzato nella seguente sintassi:

    espressione_indirizzo- l'identificativo di una variabile di qualche tipo strutturale o di un'espressione tra parentesi secondo le regole sintattiche sotto indicate (Fig. 1);

    nome_campo_struttura- il nome del campo dal modello di struttura.

    Questo, infatti, è anche un indirizzo, o meglio, l'offset del campo dall'inizio della struttura.

Quindi, l'operatore " . "(punto) valuta l'espressione

Riso. 5. La sintassi di un'espressione di indirizzo in un operatore di accesso al campo della struttura

Dimostriamo usando l'esempio della struttura che abbiamo definito lavoratore alcune tecniche per lavorare con le strutture.

Ad esempio, estrai in ascia i valori del campo con l'età. Poiché è improbabile che l'età di una persona abile sia superiore a 99 anni, dopo aver inserito il contenuto di questo campo di caratteri nel registro ascia sarà conveniente convertirlo in rappresentazione binaria con il comando aad.

Fai attenzione, poiché a causa del principio di archiviazione dei dati "Byte meno significativo indirizzo almeno significativo" la cifra dell'età più alta sarà inserita in al, e il più giovane - in ah.

Per regolare basta usare il comando xchg al, ah:

mov ax, parola ptr sotr1.age; in al age sotr1

oppure puoi fare così:

L'ulteriore lavoro con un array di strutture viene eseguito allo stesso modo di un array unidimensionale. Qui sorgono diverse domande:

Che dire delle dimensioni e di come organizzare l'indicizzazione degli elementi dell'array?

Analogamente ad altri identificatori definiti nel programma, il traduttore assegna all'attributo type il nome del tipo di struttura e il nome della variabile con il tipo di struttura. Il valore di questo attributo è la dimensione in byte occupata dai campi di questa struttura. Puoi recuperare questo valore usando l'operatore genere.

Dopo che la dimensione di un'istanza di struttura è diventata nota, non è difficile organizzare l'indicizzazione in una matrice di strutture.

Per esempio:

Come faccio a copiare un campo da una struttura al campo corrispondente di un'altra struttura? O come si copia l'intera struttura? Copiamo il campo nome terzo impiegato nel settore nome quinto dipendente:

mas_sotr lavoratore 10 dup ()

mov bx, offset mas_sotr

mov si, (tipo lavoratore) * 2; si = 77 * 2

mov di, (tipo lavoratore) * 4; si = 77 * 4

Mi sembra che il mestiere di programmatore, prima o poi, faccia sembrare una persona una brava casalinga. Lui, come lei, è costantemente alla ricerca di dove salvare qualcosa, tagliare e fare una cena meravigliosa con un minimo di prodotti. E se questo ha successo, allora la soddisfazione morale si ottiene non meno, e forse di più, che da una meravigliosa cena con una casalinga. Il grado di questa soddisfazione, mi sembra, dipende dal grado di amore per la tua professione.

D'altra parte, i successi nello sviluppo di software e hardware rilassano un po' il programmatore, e molto spesso si osserva una situazione simile al noto proverbio sulla mosca e l'elefante: per risolvere qualche piccolo problema, sono coinvolti mezzi pesanti, la cui efficacia, nel caso generale, è significativa solo quando si realizzano progetti relativamente grandi.

La presenza dei seguenti due tipi di dati nel linguaggio è probabilmente spiegata dal desiderio della "padrona di casa" di utilizzare l'area di lavoro del tavolo (RAM) nel modo più efficiente possibile durante la preparazione del cibo o per l'immissione dei prodotti (dati del programma ).

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 nella 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 per ogni tipo di computer è diverso.

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 un insieme 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 da altre frasi durante la trasmissione;

3) direttive,che sono istruzioni al traduttore assembler per eseguire determinate 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'assieme.

Le frasi che compongono il programma possono essere un costrutto sintattico corrispondente a un comando, macro, direttiva o commento. Affinché il traduttore assembler sia in grado di riconoscerli, 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 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, macro o direttiva traduttore;

­ operandi -parti di un comando, macro o 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 lingua 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 annotato 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:

Innanzitutto, 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 potrebbe avere difficoltà a riconoscere i numeri esadecimali a causa del fatto che 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”. esso condizione richiesta... 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 sono oggetti (alcuni valori, registri o celle di memoria) su cui agiscono istruzioni o direttive, oppure sono oggetti che definiscono o specificano 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 componenti in formazioni più complesse, chiamate 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 override 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 più meccanismo comune Associato 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 unione.

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

­ direttive generali di controllo degli elenchi;

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

­ direttive per l'output di blocchi di assembly 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 comandi.

­ 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 BCD. 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 di consueto. 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). In moderno potenti processori l'insieme di istruzioni in virgola mobile non si limita alle sole quattro operazioni aritmetiche, ma contiene molti altri comandi più complessi, ad esempio il calcolo di funzioni trigonometriche, funzioni logaritmiche e funzioni complesse necessarie per l'elaborazione di suoni 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 sostituiti 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 un 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 di spostamento 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 causano un salto a nuovo indirizzo non importa cosa. Possono causare una transizione a il valore specificato offset (avanti o indietro) o all'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 in modo specifico 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 un insieme 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; cifre 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.

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: Dambaeva Sesegma 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 una lettera in minuscola.
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 la settimana 14.
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 Assembler. 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 nella scrittura di 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.

In primo luogo, questi sono i cosiddetti programmi di sistema dipendenti dalla macchina, di solito controllano vari dispositivi computer (tali programmi sono chiamati driver). In questi programmi di sistema vengono utilizzate istruzioni speciali della macchina 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 si possono utilizzare i cosiddetti sistemi di programmazione multilingue, che consentono di scrivere parti del programma in lingue differenti... 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 far sì che il programma fornisca un risultato in un ragionevole lasso di tempo.

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 forma simbolica di notazione (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 frammento specifico il numero di volte specificato; 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 altre convenzioni alquanto complesse, la complessità dello sviluppo congiunto;

· Meno librerie disponibili, loro bassa compatibilità;

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

· Massima "adattabilità" per la piattaforma giusta(usando istruzioni speciali, caratteristiche tecniche"ghiandola");

· Intolleranza ad altre piattaforme (tranne compatibile binario).

Oltre alle istruzioni, un programma può contenere delle direttive: istruzioni 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);

· Gestire l'organizzazione del programma in memoria ei 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 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.

LA CAMPANA

C'è chi ha letto questa notizia prima di te.
Iscriviti per ricevere gli ultimi articoli.
E-mail
Nome
Cognome
Come vuoi leggere La Campana?
Niente spam