La struttura delle istruzioni del linguaggio assembly contiene. Struttura dei comandi nella programmazione in linguaggio assembly a livello. Formato dei dati e struttura dei comandi del linguaggio assembly

Comandi in linguaggio assembly (lezione)

PIANO DELLE LEZIONI

1. Principali gruppi di operazioni.

Pentium.

1. Principali gruppi di operazioni

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

operazioni di spedizione,

operazioni aritmetiche,

operazioni logiche,

operazioni su turni,

operazioni di confronto e test,

operazioni sui bit,

Operazioni di gestione del programma;

Operazioni di controllo del processore.

2. Mnemocode dei comandi del processore Pentium

Quando si descrivono i comandi, vengono solitamente utilizzate le loro designazioni mnemoniche (codici mnemonici), che servono a specificare il comando durante la programmazione in linguaggio Assembly. Per diverse versioni dell'Assembler, i codici mnemonici di alcuni comandi potrebbero differire. Ad esempio, per un comando che richiama 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 sono uguali o differiscono leggermente, poiché sono abbreviazioni delle corrispondenti parole inglesi che definiscono l'operazione da eseguire. Consideriamo i mnemonici dei comandi adottati per i processori Pentium.

Inoltra comandi. Il comando principale di questo gruppo è il comandoMOV , che prevede il trasferimento di dati tra due registri o tra un registro e una cella di memoria. Alcuni microprocessori implementano un trasferimento tra due celle di memoria, nonché un trasferimento di gruppo del contenuto di più registri dalla memoria. Ad esempio, i microprocessori della famiglia 68 Motorolaxxx eseguire il comandoMOSSA , che prevede il trasferimento da una cella di memoria all'altra, e il comandoMOVEM , che scrive in memoria o carica dalla memoria il contenuto di un dato insieme di registri (fino a 16 registri). SquadraXCHG effettua uno scambio reciproco del contenuto di due registri del processore oppure di un registro e di una cella di memoria.

Comandi di input IN e uscita FUORI attuare il trasferimento dei dati dal registro del processore a un dispositivo esterno o la ricezione dei dati da un dispositivo esterno al 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 ai dispositivi esterni. In questo caso, l'input e l'output dei dati nel sistema viene eseguito utilizzando il comandoMOV , che specifica l'indirizzo del dispositivo di interfaccia richiesto. Pertanto, un dispositivo esterno viene indirizzato come cella di memoria e nello spazio degli indirizzi viene allocata una sezione specifica in cui si trovano gli indirizzi dei dispositivi di interfaccia (porte) collegati al sistema.

Comandi per operazioni aritmetiche. I comandi principali di questo gruppo sono addizione, sottrazione, moltiplicazione e divisione, che hanno una serie di opzioni. Comandi di addizione AGGIUNGERE e sottrazione SUB eseguire le operazioni appropriate conCpossedere due registri, un registro e una posizione di memoria, oppure utilizzare un operando immediato. Squadre ANNO DOMINI C , SB B eseguire addizioni e sottrazioni, tenendo conto del valore dell'attributoC, impostato durante la formazione del trasferimento nel processo di esecuzione dell'operazione precedente. Con l'aiuto di questi comandi viene implementata l'aggiunta sequenziale di operandi, il cui numero di cifre supera la capacità del processore. Squadra NEG cambia il segno dell'operando, convertendolo in complemento a due.

Le operazioni di moltiplicazione e divisione possono essere eseguite su numeri con segno (comandiIO MUL, IO DIV ) o senza segno (commands MUL, DIV ). Il risultato dell'operazione si trova nel registro. Quando si moltiplica (comandiMUL , IMUL ) produce un risultato a due cifre, che utilizza due registri per adattarsi. Durante la divisione (comandiDIV , IDIV ) come dividendo viene utilizzato un operando a due cifre, inserito in due registri e, di conseguenza, il quoziente e il resto vengono scritti in due registri.

Comandi logici . Quasi tutti i microprocessori eseguono operazioni logiche AND, OR, OR esclusivo, che vengono eseguite sui bit dell'operando con lo stesso nome utilizzando i comandi E, O, X O . Le operazioni vengono eseguite sul contenuto di due registri, un registro e una posizione di memoria, oppure utilizzando un operando immediato. Squadra NON Inverte il valore di ciascun bit dell'operando.

Comandi di spostamento. I microprocessori eseguono spostamenti aritmetici, logici e ciclici degli operandi indirizzati di uno o più bit. L'operando da spostare può trovarsi in un registro o in una posizione di memoria e il numero di bit di spostamento viene specificato utilizzando l'operando immediato contenuto nell'istruzione o determinato dal contenuto del registro specificato. Il segno di trasferimento è solitamente coinvolto nell'attuazione dello spostamentoCnel registro di stato (SR O EFLAG), che contiene l'ultimo bit dell'operando estratto dal registro o dalla posizione di memoria.

Comandi di confronto e test . Il confronto degli operandi viene solitamente eseguito con il comandoCMP , che esegue la sottrazione di operandi con l'impostazione dei valori delle caratteristiche 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 cambiano. La successiva analisi dei valori caratteristici ottenuti consente di determinare il valore relativo (>,<, =) операндов со знаком или без знака. Использование различных способов адресации позволяет производит сравнение содержимого двух регистров, регистра и ячейки памяти, непосредственно заданного операнда с содержимым регистра или ячейки памяти.

Alcuni microprocessori eseguono un comando di test TST , che è una variante a operando singolo dell'istruzione di confronto. Quando viene eseguito questo comando, i segni vengono impostati N,Z in base al segno e al valore (uguale o diverso da zero) dell'operando indirizzato.

Istruzioni per l'uso dei bit . Questi comandi impostano il valore dell'attributoCnel registro di stato in base al valore del bit in fase di testmiliardo nell'operando indirizzato. In alcuni microprocessori, in base al risultato del test, viene impostato un segnoZ. Numero di bit di provaNviene impostato 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.Command B T S dopo aver testato imposta il valore miliardo=1 e il comando B T C - Senso miliardo=0.Comando B T C inverte il valore del bit bn dopo averlo testato.

Operazioni di gestione del programma. Per controllare il programma vengono utilizzati numerosi comandi, tra cui:

- comandi di trasferimento del controllo incondizionato;

- comandi di salto condizionato;

- comandi per organizzare i cicli del programma;

- comandi di interruzione;

- comandi di modifica delle funzionalità.

Il trasferimento incondizionato del controllo viene eseguito dal comandoJMP , che viene caricato nel contatore del programmacomputernuovo contenuto che è l'indirizzo del prossimo comando da eseguire. Questo indirizzo può essere specificato direttamente nel comandoJMP (indirizzo diretto), o calcolato come somma del contenuto correntecomputere l'offset specificato nel comando, che è un numero con segno (indirizzamento relativo). Perchécomputercontiene l'indirizzo del comando successivo del programma, quindi l'ultimo metodo imposta l'indirizzo della transizione, sfalsato rispetto all'indirizzo successivo di un dato numero di byte. Se l'offset è positivo viene eseguito il passaggio ai comandi successivi del programma, se l'offset è negativo, a quelli precedenti.

La subroutine viene anche chiamata tramite trasferimento incondizionato del controllo utilizzando il comandoCHIAMATA (O JSR ). Tuttavia, in questo caso, prima di caricare incomputer nuovo contenuto che specifica l'indirizzo della prima istruzione del sottoprogramma, è necessario salvarne il valore corrente (l'indirizzo dell'istruzione successiva) per garantire un ritorno al programma principale dopo l'esecuzione del sottoprogramma (o al subroutine precedente quando si annidano subroutine). Vengono caricate le istruzioni di salto condizionato (rami di programma).computernuovo contenuto se vengono soddisfatte determinate condizioni, che solitamente vengono impostate in base al valore corrente di vari attributi nel registro di stato. Se la condizione non è soddisfatta, viene eseguito il comando successivo del programma.

I comandi di gestione dei tratti forniscono la scrittura: la lettura del contenuto del registro di stato, che memorizza i tratti, nonché la modifica dei valori dei singoli tratti. Ad esempio, i processori Pentium implementano i comandi LAHF E SAHF , che caricano il byte basso, che contiene i segni, dal registro di stato EFLAG al byte basso del registro EAX e byte basso di riempimento EFLAG dal registro EAX.. Comandi CLC, STC impostare i valori del flag di trasferimento CF=0, CF=1 e del comando CMC fa sì che il valore di questa funzione venga invertito. Poiché i tratti determinano il flusso di esecuzione del programma durante i salti condizionali, le istruzioni di modifica dei tratti vengono solitamente utilizzate per controllare il programma.

Comandi di controllo del processore . Questo gruppo include comandi di arresto, nessuna operazione e una serie di comandi che determinano la modalità di funzionamento del processore o dei suoi singoli blocchi. SquadraHLT termina l'esecuzione del programma e pone il processore in uno stato di halt, l'uscita dal quale avviene alla ricezione di segnali di interruzione o riavvio ( Ripristina). Squadra NO Un'istruzione (“vuota”), che non comporta l'esecuzione di alcuna operazione, viene utilizzata per implementare ritardi del programma o colmare le lacune che si formano nel programma.

Squadre speciali CLI, STI disabilitare e abilitare il servizio di richieste di interruzione. Nei processori Pentium a questo scopo viene utilizzato un bit di controllo (flag).SE nel registro EFLAG.

Molti microprocessori moderni emettono un comando di identificazione che consente all'utente o ad altri dispositivi di ottenere informazioni sul tipo di processore utilizzato in un determinato sistema. Nei processori Pentuimo questo è lo scopo del comando ID CPU , durante il quale i dati necessari relativi al responsabile del trattamento vengono inseriti nei 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 specificati di dati elaborati, l'insieme dei comandi eseguibili può essere notevolmente ampliato.

Alcuni processori eseguono operazioni aritmetiche BCD o eseguono istruzioni speciali di correzione dei risultati durante l'elaborazione di tali numeri. Molti processori ad alte prestazioni includono FPU - blocco elaborazione numeri C "virgola mobile".

In un certo numero di processori moderni, viene implementata l'elaborazione di gruppo di diversi numeri interi o numeri. C “virgola mobile” con un unico comando secondo il principio SIMD (“Istruzione singola – Dati multipli ”) - “Un comando – Molti dati”. L'esecuzione simultanea di operazioni su più operandi aumenta significativamente le prestazioni del processore quando si lavora con dati video e audio. Tali operazioni sono ampiamente utilizzate nell'elaborazione delle immagini, nell'elaborazione dei segnali audio e in altre applicazioni. Per eseguire queste operazioni, nei processori vengono introdotti blocchi speciali che implementano i corrispondenti set di istruzioni, che in vari tipi di processori ( Pentium, Atlon) ha preso il nomeMMX (“ Milti-Estensione multimediale ”) – Estensione multimediale,SSE(“Estensione SIMD in streaming”) – SIMD in streaming - estensione, “3 DEstensione- Espansione 3D.

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

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

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

Gli identificatori sono sequenze di caratteri validi utilizzati per designare 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: _, @, $, ? . È possibile utilizzare un punto come primo carattere dell'etichetta. I nomi 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. Lunghezza massima identificatore 255 caratteri, ma il traduttore accetta i primi 32, il resto viene ignorato. Tutte le etichette scritte su una riga che non contiene una direttiva assembler devono terminare con i due punti ":". L'etichetta, il comando (direttiva) e l'operando non devono iniziare in una posizione particolare nella stringa. Si consiglia di scriverli in colonna per una maggiore leggibilità del programma.

Etichette Tutte le etichette scritte su una riga che non contiene una direttiva assembler devono terminare con i due punti ":". L'etichetta, il comando (direttiva) e l'operando non devono iniziare in una posizione particolare nella stringa. Si consiglia di scriverli in colonna per una maggiore leggibilità del programma.

Commenti L'uso dei commenti in un programma ne migliora la chiarezza, soprattutto quando lo scopo di una serie di istruzioni non è chiaro. I commenti iniziano su qualsiasi riga di un modulo sorgente con un punto e virgola (;). Tutti i caratteri a destra di "; ' fino alla fine della riga ci sono i commenti. Il commento può contenere qualsiasi carattere stampabile, compreso lo "spazio". Il commento può occupare l'intera riga o seguire il comando sulla stessa riga.

Struttura di un programma in linguaggio assembly Un programma in linguaggio assembly può essere composto da diverse parti, chiamate moduli, ciascuna delle quali può definire uno o più dati, stack e segmenti di codice. Qualsiasi programma completo in linguaggio assembly deve includere un modulo principale, o principale, da cui inizia la sua esecuzione. Un modulo può contenere programmi, dati e segmenti di stack dichiarati con le direttive appropriate.

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

Modelli di memoria Il modello piccolo funziona solo con applicazioni MS-DOS a 16 bit. In questo modello, tutti i dati e il codice risiedono in un segmento fisico. La dimensione del file di programma in questo caso non supera i 64 KB. Il modello piccolo supporta un segmento di codice e un segmento di dati. I dati e il codice quando si utilizza questo modello vengono indirizzati come vicino (vicino). Il modello medio supporta più segmenti di codice e un segmento dati, con tutti i collegamenti nei segmenti di codice considerati lontani (far) per impostazione predefinita e i collegamenti nel segmento dati sono considerati vicini (vicino). Il modello compatto supporta più segmenti di dati che utilizzano l'indirizzamento dei dati lontani (far) e un segmento di codice che utilizza l'indirizzamento dei dati vicini (near). Il modello di grandi dimensioni supporta più segmenti di codice e più segmenti di dati. Per impostazione predefinita, tutti i riferimenti al codice e ai dati sono considerati lontani. Il modello enorme è quasi equivalente al modello di memoria grande.

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

modelli di memoria. MODIFICATORE MODEL memory_model, calling_convention, OS_type, stack_parameter Il parametro modificatore viene utilizzato per definire i tipi di segmento e può assumere i seguenti valori: utilizzare 16 (i segmenti del modello selezionato vengono utilizzati come 16 bit) utilizzare 32 (i segmenti del modello selezionato vengono utilizzati come 32 bit). Il parametro calling_convention viene utilizzato per determinare come vengono passati i parametri quando si chiama una procedura da altri linguaggi, inclusi 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, calling_convention, OS_type, stack_parameter Il parametro OS_type è OS_DOS per impostazione predefinita ed è attualmente l'unico valore supportato per questo parametro. Il parametro stack_param è impostato su: NEARSTACK (il registro SS è uguale a DS, i dati e le regioni dello stack si trovano nello stesso segmento fisico) FARSTACK (il registro SS non è uguale a DS, i dati e le regioni 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 del microprocessore. Garantisce la corretta conclusione del programma. Il resto del programma è legato al funzionamento del traduttore. . 686 P - Sono consentiti i comandi in modalità protetta Pentium 6 (Pentium II). Questa direttiva seleziona il set di istruzioni assembler supportato specificando il modello del processore. . MODELLO FLAT, stdcall - modello di memoria flat. Questo modello di memoria viene utilizzato in sala operatoria Sistema Windows. stdcall è la convenzione di chiamata della procedura da utilizzare.

Un esempio di un programma "non fare nulla". 686 P. MODELLO PIATTO, STDCALL. DATI. CODICE INIZIO: RET FINE INIZIO . DATI - segmento di programma contenente dati. Questo programma non utilizza lo stack, quindi segmenta. Manca lo STACK. . CODICE - un segmento del programma contenente il codice. INIZIO - 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 che segna la fine codice sorgente programmi. Tutte le righe che seguono la direttiva END vengono ignorate.L'etichetta dopo la direttiva END indica al compilatore il nome del modulo principale da cui inizia l'esecuzione del programma. Se il programma contiene un modulo, l'etichetta dopo la direttiva END può essere omessa.

Traduttori in linguaggio assembly Un traduttore è un programma o hardware che converte un programma presentato 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 macro, spesso incompatibili con qualsiasi altra cosa. I principali tipi di traduttori del linguaggio assembly sono: MASM (Microsoft Assembler), TASM (Borland Turbo Assembler), FASM (Flat Assembler) - un assemblatore multi-pass distribuito gratuitamente scritto da Tomasz Gryshtar (polacco), NASM (Netwide Assembler) - un L'assemblatore libero per l'architettura Intel x 86 è stato creato da Simon Tatham con Julian Hall ed è attualmente in fase di sviluppo da un piccolo team di sviluppo presso Source. Fucina. netto.

Src="https://present5.com/presentation/-29367016_63610977/image-15.jpg" alt="Traduzione del programma in Microsoft Visual Studio 2005 1) Crea un progetto selezionando File->Nuovo->Progetto menù 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="Traduzione del programma in Microsoft Visual Studio 2005 2) Nell'albero del progetto (Visualizza->Esplora soluzioni) aggiungi"> Трансляция программы в 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. Selezionare sul pulsante destro nel menu file di progetto Regole di creazione personalizzate...

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

Traduzione del programma in Microsoft Visual Studio 2005 Controllare con il tasto destro nel file ciao. asm dell'albero del progetto dal menu Proprietà e impostare Generale->Strumenti: Microsoft Macro Assembler.

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

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

Chiamata Funzionalità di Windows API Nel file della guida, qualsiasi funzione API è rappresentata come tipo nome_funzione (FA 1, FA 2, FA 3) Tipo – tipo di valore restituito; FAX è un elenco di argomenti formali nell'ordine in cui appaiono, ad esempio int Message. Casella (HWND h. Wnd, LPCTSTR lp. Testo, LPCTSTR lp. Didascalia, UINT u. Tipo); Questa funzione visualizza una finestra con un messaggio e uno o più pulsanti di uscita. Significato dei parametri: h. Wnd - handle della finestra in cui apparirà la finestra del messaggio, lp. Testo: il testo che apparirà nella finestra, lp. Didascalia: testo nel titolo della finestra, u. Tipo: tipo di finestra, in particolare è possibile specificare il numero di pulsanti di uscita.

Chiamata delle funzioni API di Windows int Message. Casella (HWND h. Wnd, LPCTSTR lp. Testo, LPCTSTR lp. Didascalia, UINT u. Tipo); Quasi tutti i parametri delle funzioni API sono in realtà numeri interi a 32 bit: HWND è un numero intero a 32 bit, LPCTSTR è un puntatore a stringa a 32 bit, UINT è un numero intero a 32 bit. Il suffisso "A" viene spesso aggiunto al nome delle funzioni per passare alle versioni più recenti delle funzioni.

Chiamata delle funzioni API di Windows int Message. Casella (HWND h. Wnd, LPCTSTR lp. Testo, LPCTSTR lp. Didascalia, UINT u. Tipo); 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 volte 4 (byte in ciascun argomento): N=4*n. Per chiamare una funzione si utilizza l'istruzione CALL dell'assembler. In questo caso tutti gli argomenti della funzione le vengono passati tramite lo stack (comando PUSH). Direzione di passaggio dell'argomento: DA SINISTRA A DESTRA - DAL BASSO IN ALTO. L'argomento u verrà messo per primo nello stack. tipo. La chiamata alla funzione specificata sarà simile a questa: Messaggio CALL. scatola. A@16

Chiamata delle funzioni API di Windows int Message. Casella (HWND h. Wnd, LPCTSTR lp. Testo, LPCTSTR lp. Didascalia, UINT u. Tipo); Il risultato dell'esecuzione di qualsiasi funzione API è solitamente un numero intero, che viene restituito nel registro EAX. La direttiva OFFSET è un "offset di segmento" o, in termini di linguaggio di alto livello, un "puntatore" all'inizio di una stringa. La direttiva EQU, come #define in C, definisce una costante. La direttiva EXTERN dice al compilatore che una funzione o un identificatore è esterno al modulo.

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. A@16: VICINO. CODICE AVVIO: PUSH MB_OK PUSH OFFSET STR 1 PUSH OFFSET STR 2 PUSH HW CALL Messaggio. scatola. A@16 RET FINE AVVIO

La direttiva INVOKE Il traduttore del linguaggio MASM rende anche possibile semplificare la chiamata di funzione utilizzando uno strumento macro: la direttiva INVOKE: funzione INVOKE, parametro1, parametro2, ... Non è necessario aggiungere @16 alla chiamata di funzione; i parametri sono scritti esattamente nell'ordine in cui sono riportati nella descrizione della funzione. le macro del traduttore inseriscono i parametri nello stack. per utilizzare la direttiva INVOKE è necessario avere una descrizione del prototipo della funzione utilizzando la direttiva PROTO nella forma: Messaggio. scatola. A PROTO: DWORD, : DWORD

Strutture in linguaggio assembly

Gli array che abbiamo considerato sopra sono una raccolta di elementi dello stesso tipo. Ma spesso nelle applicazioni è necessario considerare un determinato insieme di dati tipo diverso come un singolo tipo.

Ciò è molto rilevante, ad esempio, per i programmi di database, dove è necessario associare una raccolta di dati di diverso tipo a un oggetto.

Ad esempio, in precedenza abbiamo esaminato il Listato 4, che funzionava con un array di elementi a tre byte. Ogni elemento, a sua volta, era costituito da due elementi di tipo diverso: un campo contatore da un byte e un campo da due byte che poteva contenere ulteriori informazioni necessarie per l'archiviazione e l'elaborazione. Se il lettore ha familiarità con uno dei linguaggi di alto livello, allora sa che un oggetto del genere viene solitamente descritto utilizzando un tipo di dati speciale: strutture.

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

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

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

    Chiedere modello di struttura .

    In sostanza, ciò significa definire un nuovo tipo di dati, che potrà essere utilizzato successivamente per definire variabili di questo tipo.

    Definire istanza di struttura .

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

    Organizzare accedere ai membri della struttura .

È molto importante capire fin dall'inizio qual è la differenza tra descrizione strutture del programma e dei suoi definizione.

descrivere la struttura di un programma significa solo indicarne lo schema o il modello; la memoria non è allocata.

Questo modello può essere considerato solo come informazione per il traduttore sulla posizione dei campi e sul loro valore predefinito.

Definire struttura significa istruire il traduttore ad allocare memoria e assegnare un nome simbolico a quest'area di memoria.

È possibile descrivere la struttura nel programma solo una volta e definirla un numero qualsiasi di volte.

Descrizione del modello di struttura

La dichiarazione del modello di struttura ha la seguente sintassi:

nome_struttura STRUC

nome_struttura FINE

Qui è una sequenza di direttive per la descrizione dei dati db, dw, gg, dq E dt.

I loro operandi determinano la dimensione dei campi e facoltativamente i valori iniziali. Questi valori eventualmente inizializzeranno i campi corrispondenti quando la struttura sarà definita.

Come abbiamo già notato descrivendo il modello, non viene allocata memoria, poiché si tratta solo di informazioni per il traduttore.

Posizione template nel programma può essere arbitrario, ma, seguendo la logica del traduttore a passaggio singolo, deve essere posizionato prima del 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.

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

Per semplicità, per evitare i problemi di conversione delle informazioni durante l'input, concorderemo che tutti i campi siano simbolici.

Definiamo la struttura dei record di questo database con il seguente schema:

Definizione dei dati con un tipo di struttura

Per utilizzare la struttura descritta con l'aiuto del template nel programma, è necessario definire una variabile con il tipo di questa struttura. A questo scopo viene utilizzata la seguente sintassi:

[nome variabile] nome_struttura

    nome della variabile- identificatore variabile della tipologia strutturale data.

    Specificare un nome di variabile è facoltativo. Se non è specificato, un'area di memoria con la dimensione della somma delle lunghezze di tutti elementi della struttura.

    elenco di valori- un elenco separato da virgole dei valori iniziali degli elementi della struttura racchiusi tra parentesi angolari.

    Anche il suo compito è facoltativo.

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

    È consentito inizializzare singoli campi, ma in questo caso i campi mancanti devono essere separati da virgole. I campi mancanti verranno inizializzati con i valori del modello struct. Se, quando definiamo una nuova variabile con il tipo di questa struttura, siamo d'accordo con tutti i valori dei campi nel suo modello (cioè impostati per impostazione predefinita), allora devi solo scrivere parentesi angolari.

    Per esempio: lavoratore vincitore.

Ad esempio, definiamo diverse variabili con il tipo di struttura sopra descritta.

Metodi di struttura

L'idea di introdurre un tipo strutturale in qualsiasi linguaggio di programmazione è quella di combinare variabili di tipo diverso in un unico oggetto.

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

    indirizzo_espressione- un identificatore di variabile di tipo strutturale o un'espressione tra parentesi secondo le regole sintattiche di seguito indicate (Fig. 1);

    nome_campo_struttura- nome del campo dal modello di struttura.

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

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

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

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

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

Fai attenzione, perché a causa del principio di archiviazione dei dati “byte basso all’indirizzo basso” verrà inserita la cifra più alta dell'età al, e il più giovane in Ah.

Per correggerlo basta usare il comando xchg al, ah:

mov ax,word ptr sotr1.age ;at al age sotr1

ed è possibile in questo modo:

Ulteriore lavoro con una serie di strutture viene eseguito allo stesso modo di una matrice unidimensionale. Qui sorgono diverse domande:

Come gestire le dimensioni e come organizzare l'indicizzazione degli elementi dell'array?

Come altri identificatori definiti nel programma, il traduttore assegna al nome del tipo di struttura e al nome della variabile con il tipo di struttura un attributo di tipo. Il valore di questo attributo è la dimensione in byte occupata dai campi di questa struttura. È possibile estrarre questo valore utilizzando l'operatore tipo.

Una volta nota la dimensione di un'istanza di struttura, organizzare l'indicizzazione in un array di strutture non è particolarmente difficile.

Per esempio:

Come copiare un campo da una struttura al campo corrispondente di un'altra struttura? O come copiare l'intera struttura? Copiamo il campo nome terzo dipendente sul campo 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 preparare una cena meravigliosa con un minimo di cibo. E se ciò riesce, la soddisfazione morale non è inferiore, e forse maggiore, di una cena meravigliosa dalla casalinga. Il grado di questa soddisfazione, mi sembra, dipende dal grado di amore per la propria professione.

D'altra parte, i progressi nello sviluppo di software e hardware rilassano in qualche modo il programmatore, e molto spesso si verifica una situazione simile al noto proverbio sulla mosca e l'elefante: per risolvere qualche piccolo problema, vengono utilizzati strumenti pesanti coinvolti, la cui efficacia, nel caso generale, è significativa solo quando si realizzano progetti relativamente grandi.

La presenza nel linguaggio delle seguenti due tipologie di dati è probabilmente dovuta al 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 il posizionamento dei prodotti (dati del programma ).

In base allo scopo, i comandi possono essere distinti (esempi di codici operativi mnemonici di comandi di un assemblatore di PC come PC IBM sono riportati tra parentesi):

eseguire operazioni aritmetiche (ADD e ADC - addizione e somma con riporto, 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 - invio, XCHG - scambio, IN - ingresso nel microprocessore, OUT - ritiro 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 del loop, ecc.);

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

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

l controllo tramite microprocessore (ST* e CL* - imposta e cancella flag, HLT - stop, WAIT - standby, NOP - inattivo, ecc.).

CON elenco completo i comandi assembler possono essere trovati nei lavori.

Comandi di trasferimento dati

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

Trasferimenti: 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 un valore immediato in un registro o memoria.

Gli operandi dst e src devono avere lo stesso formato: 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. Gli operandi non possono essere utilizzati in un comando: rsegm insieme a i; due operandi di tipo m e due operandi di tipo rsegm). L'operando i può anche essere una semplice espressione:

mov AX, (152 + 101B) / 15

La valutazione dell'espressione viene eseguita solo durante la traduzione. Le bandiere non cambiano.

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

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

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

Ogni istruzione macchina è composta da due parti:

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

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

comando/direttiva etichetta operando(i) ;commenti

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

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

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

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

Righe di codice di esempio:

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

Tag

Etichetta in linguaggio assembly può contenere i seguenti caratteri:

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

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

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

Squadre

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

direttive

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

operandi

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

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

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

Gli operandi possono essere

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

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

Regole per la scrittura degli identificatori.

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

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

Struttura del programma di assemblaggio

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

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

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

RET
FINE INIZIO

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




Superiore