Casa / Servizi online / Caratteristiche generali del sistema di comando del linguaggio Assembler per IBM-PC (set base di comandi, modalità base di indirizzamento operandi). La struttura del programma in linguaggio Assembler. Comandi in linguaggio assembly Comandi in linguaggio assembly

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

Lavoro del corso

Soggetto "Programmazione del sistema"

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

opzione 2

UNIVERSITÀ STATALE DELLA SIBERIA ORIENTALE

TECNOLOGIA E GESTIONE

____________________________________________________________________

COLLEGIO TECNOLOGICO

ESERCIZIO

per la tesina

Disciplina:
Argomento: Problem solving per le procedure
Artista(i): Glavinskaya Arina Alexandrovna
Responsabile: Sesegma Viktorovna Dambaeva
Breve riassunto del lavoro: lo studio delle subroutine su linguaggio assembly,
risoluzione di problemi tramite subroutine
1. Parte teorica: Informazioni di base sul linguaggio assembly (set
comandi, ecc.), Organizzazione dei sottoprogrammi, Modalità di passaggio dei parametri
nei sottoprogrammi
2. Parte pratica: Sviluppa due subroutine, una delle quali converte qualsiasi lettera in maiuscolo (anche per le lettere russe) e l'altra converte la lettera in minuscolo.
converte una determinata lettera in maiuscolo e l'altro converte la lettera in minuscolo.
converte una lettera in minuscolo.
Tempistiche del progetto secondo il programma:
1. Parte teorica - 30% a settimana 7.
2. Parte pratica - 70% entro 11 settimane.
3. Protezione - 100% entro 14 settimane.
Requisiti di progettazione:
1. La liquidazione e la nota esplicativa del progetto di corso devono essere presentate in
copie elettroniche e cartacee.
2. Il volume della relazione deve essere di almeno 20 pagine dattiloscritte, esclusi gli allegati.
3. L'RPP è redatto in conformità con GOST 7.32-91 e firmato dal capo.

Responsabile del lavoro __________________

Esecutore __________________

Data di emissione " 26 " settembre 2017 G.


Introduzione. 2

1.1 Informazioni di base sul linguaggio assembly. 3

1.1.1 Set di comandi. quattro

1.2 Organizzazione di subroutine in linguaggio assembly. quattro

1.3 Metodi per passare parametri nelle subroutine. 6

1.3.1 Passare i parametri attraverso i registri.. 6

1.3.2 Passaggio di parametri attraverso lo stack. 7

2 SEZIONE PRATICA.. 9

2.1 Dichiarazione del problema. 9

2.2 Descrizione della soluzione del problema. 9

2.3 Testare il programma.. 7

Conclusione. otto

Riferimenti.. 9


introduzione

È risaputo che programmare in linguaggio Assembly è difficile. Come sai, ora ci sono molte lingue diverse alto livello , che ti consentono di dedicare molto meno sforzo durante la 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, che di solito controllano vari dispositivi computer (tali programmi sono chiamati driver). Questi programmi di sistema usano istruzioni macchina speciali che non hanno bisogno di essere usate in ordinario (o, come si dice, applicato) programmi. Questi comandi sono impossibili o molto difficili da specificare in un linguaggio di alto livello.

Il secondo ambito di applicazione di Assembler è legato 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 a programmi di natura computazionale, in cui una sezione molto piccola (circa il 3-5%) del programma (il ciclo 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 diverse. Di solito, la parte principale del programma è scritta in un linguaggio di programmazione di alto livello (Fortran, Pascal, C, ecc.) e le sezioni del programma in cui il tempo è critico sono scritte in Assembler. In questo caso, la velocità dell'intero programma può aumentare in modo significativo. Questo è spesso l'unico modo per fare in modo che un programma produca risultati in un ragionevole lasso di tempo.

Questo tesinaè quello di acquisire abilità pratiche nella programmazione in linguaggio assembly.

Compiti di lavoro:

1. Studiare le informazioni di base sul linguaggio Assembler (la struttura ei componenti del programma in Assembler, il formato dei comandi, l'organizzazione delle subroutine, ecc.);

2. Studiare i tipi di operazioni bit, il formato e la logica dei comandi logici assembler;

3. Risolvere un singolo problema per l'utilizzo di subroutine in Assembler;

4.. Formulare una conclusione sul lavoro svolto.

1 SEZIONE TEORICA

Nozioni di base sul linguaggio assembly

Assemblatore - linguaggio di programmazione basso livello, che è un formato per scrivere le istruzioni della macchina che è conveniente per la percezione umana.

I comandi in linguaggio assembly corrispondono uno a uno ai comandi del processore e, di fatto, rappresentano una comoda forma simbolica di notazione (codice mnemonico) dei comandi e dei loro argomenti. Il linguaggio assembly fornisce anche astrazioni di programmazione di base: collegamento di parti di un programma e dati tramite etichette con nomi simbolici e direttive.

Le direttive di assemblaggio consentono di includere blocchi di dati (descritti esplicitamente o letti da un file) nel programma; ripetere un certo frammento un determinato numero di volte; compilare il frammento secondo la condizione; impostare l'indirizzo di esecuzione del frammento, modificare i valori dell'etichetta durante la compilazione; utilizzare definizioni di macro con parametri, ecc.

Vantaggi e svantaggi

La quantità minima di codice ridondante (l'uso di meno comandi e accessi alla memoria). Di conseguenza, maggiore velocità e taglia più piccola programmi;

grandi quantità di codice, un gran numero di piccole attività aggiuntive;

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

· la difficoltà di implementare paradigmi di programmazione e altre convenzioni un po' complesse, la complessità dello sviluppo congiunto;

Meno librerie disponibili, la loro scarsa compatibilità;

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

massimo "fitting" per la piattaforma desiderata (utilizzo di apposite istruzioni, caratteristiche tecniche"ghiandola");

· non portabilità su altre piattaforme (ad eccezione di quelle binarie compatibili).

Oltre alle istruzioni, il programma può contenere direttive: comandi che non vengono tradotti direttamente in istruzioni macchina, ma controllano il funzionamento del compilatore. Il loro set e la loro sintassi variano notevolmente 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, possiamo distinguere:

Definizione dei dati (costanti e variabili);

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

impostare la modalità 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

Le tipiche istruzioni in linguaggio assembly sono:

Comandi di trasferimento dati (mov, ecc.)

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

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

Comandi per la gestione dell'esecuzione del programma (jmp, loop, ret, ecc.)

Comandi di chiamata di interruzione (a volte indicati come comandi di controllo): int

Comandi I/O alle porte (in, out)

Microcontrollori e microcomputer sono inoltre caratterizzati da comandi che eseguono controlli e transizioni per condizione, ad esempio:

· jne - salta se non uguale;

· jge - salta se maggiore o uguale a .

Informazione Generale sul linguaggio assembly

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

Il suo vantaggio principale è che in linguaggio assembly tutti gli elementi del programma sono rappresentati in forma simbolica. Converti i nomi dei comandi simbolici nei loro file codici binari sono assegnati a programma speciale- assembler, che libera il programmatore dal lavoro laborioso ed elimina gli inevitabili errori.

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

Per programmare in linguaggio assembly è necessario disporre di un file complex Strumenti rispetto a quando si programma in linguaggio macchina: sono necessari sistemi informatici basati su microcomputer o PC con un set periferiche(tastiera alfanumerica, display a caratteri, lettore floppy e stampante), nonché sistemi residenti o di programmazione incrociata per i tipi di microprocessori richiesti. Il linguaggio assembly consente di scrivere ed eseguire il debug in modo efficiente di programmi molto più complessi rispetto al linguaggio macchina (fino a 1 - 4 KB).

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

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

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

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

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

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

formato da specificare vari modi opzioni di indirizzamento e comando;

formato per specificare costanti carattere e costanti di tipo intero in vari sistemi resa dei conti;

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

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

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

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

Ogni istruzione della macchina è composta da due parti:

operativo - determinare "cosa fare";

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

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

label comando/direttiva operando(i) ;commenti

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

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

Se un comando o una direttiva deve continuare sulla riga successiva, viene utilizzato il carattere barra rovesciata: \.

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

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

mov eax, somma ; eax = somma

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

indirizzamento indiretto a sua volta ha i seguenti tipi:

Indirizzamento di base indiretto (registro);

Indirizzamento di base indiretto (registro) con offset;

· indirizzamento indiretto dell'indice;

· indirizzamento indiretto dell'indice di base.

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

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

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, in cui è necessario associare una raccolta di dati di tipi diversi 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 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.

Per definizione struttura è un tipo di dati costituito da un numero fisso di elementi di tipi diversi.

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

    Chiedere modello di struttura .

    In sostanza, 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 prevede l'inizializzazione di una variabile specifica con una struttura predefinita (utilizzando un modello).

    Organizzare accedere ai membri della struttura .

È molto importante che tu capisca fin dall'inizio qual è la differenza tra descrizione strutture nel programma e il suo definizione.

descrivere struttura in 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 il loro valore predefinito.

Definire struttura significa istruire il traduttore ad allocare memoria e ad assegnare un nome simbolico a questa 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 FINISCE

Qui è una sequenza di direttive di descrizione dei dati db, dw, dd, dq e dt.

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

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

Posizione template nel programma può essere arbitrario, ma, seguendo la logica del traduttore one-pass, deve trovarsi 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.

Prendi in considerazione l'idea di lavorare con le strutture utilizzando 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'input, concorderemo sul fatto che tutti i campi sono 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'ausilio del template nel programma, è necessario definire una variabile con il tipo di tale struttura. Per questo viene utilizzata la seguente sintassi:

[nome variabile] nome_struttura

    nome variabile- identificatore di variabile del tipo strutturale dato.

    La specifica di un nome di variabile è facoltativa. Se non viene specificato, verrà semplicemente allocata un'area di memoria con la dimensione della somma delle lunghezze di tutti gli 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 data vengono inizializzati con i valori del modello, se presenti.

    È 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 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 per impostazione predefinita), è sufficiente scrivere parentesi angolari.

    Per esempio: lavoratore vincitore.

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

Metodi di struttura

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

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

    indirizzo_espressione- un identificatore di variabile di qualche 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 dall'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, estrarre in ascia valori di 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, perché a causa del principio della memorizzazione dei dati "low byte 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 all age sotr1

ed è possibile così:

Ulteriore lavoro con una matrice 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 type. Il valore di questo attributo è la dimensione in byte occupata dai campi di questa struttura. È possibile estrarre questo valore utilizzando l'operatore genere.

Una volta che la dimensione di un'istanza di struttura è diventata nota, 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 impiegato sul campo nome quinto dipendente:

mas_sotr lavoratore 10 dup()

mov bx,offset mas_sotr

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

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

Mi sembra che il mestiere di un 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 questo riesce, allora la soddisfazione morale non è da meno, e forse di più, che da una meravigliosa cena 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 alla volontà della “padrona di casa” di utilizzare nel modo più efficiente possibile l'area di lavoro del tavolo (RAM) durante la preparazione dei cibi o per la collocazione dei prodotti (programma dati ).

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

    1.1. Registri.

    1.1.1 Registri di uso generale.

1.1.2. registri di segmento

1.1.3 Registro delle bandiere

1.2. Organizzazione della memoria.

1.3. Rappresentazione dei dati.

1.3.1 Tipi di dati

1.3.2 Rappresentazione di caratteri e stringhe

2. Dichiarazioni sul programma dell'assemblea ……………………………………

    1. Comandi in linguaggio assembly

2.2. Modalità di indirizzamento e formati di istruzione macchina

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

3.1 Direttive per la definizione dei dati

3.2 Struttura del programma di assemblaggio

3.2.1 Segmenti di programma. assumere direttive

3.2.3 Direttiva sulla segmentazione semplificata

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

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

    5.1 Comandi generali

    5.2 Sovrapponi i comandi

5.3 Comandi I/O

5.4 Comandi di inoltro indirizzo

5.5 Comandi di Trasferimento Bandiera

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

    6.1 Operazioni aritmetiche su interi binari

6.1.1 Addizione e sottrazione

6.1.2 Comandi per incrementare e decrementare il ricevitore di uno

6.2 Moltiplicazione e divisione

6.3 Cambio di segno

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

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

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

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

10.1 Salti incondizionati

10.2 Salti condizionati

10.4 Procedure in linguaggio assembly

10.5 Interruzioni INT

10.6 Software di sistema

10.6.1.1 Lettura della tastiera.

10.6.1.2 Visualizzazione dei caratteri sullo schermo

10.6.1.3 Terminare i programmi.

10.6.2.1 Selezione delle modalità di visualizzazione

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

11.2 Tabella di allocazione dei file

11.3 I/O su disco

11.3.1 Scrivere un file su disco

11.3.1.1 Dati ASCIIZ

11.3.1.2 Numero fascicolo

11.3.1.3 Creazione di un file su disco

11.3.2 Leggere un file su disco

introduzione

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

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

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

Il manuale si occupa della programmazione in linguaggio assembly per computer basati su microprocessori Intel.

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

    Architettura PC.

L'architettura del computer è una rappresentazione astratta di un computer che ne riflette la struttura, i circuiti e l'organizzazione logica.

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

Il concetto di architettura del computer include:

    diagramma a blocchi di un computer;

    mezzi e modalità di accesso agli elementi diagramma a blocchi COMPUTER;

    set e disponibilità dei registri;

    organizzazione e modalità di indirizzamento;

    metodo di presentazione e formato dei dati informatici;

    una serie di istruzioni per la macchina del computer;

    formati di istruzioni per macchine;

    gestione degli interrupt.

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

      Registri.

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

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

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

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

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

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

        Registri generali.

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

EBX/BX/BH/BL - registro di base(registro di base), spesso utilizzato per indirizzare i dati in memoria.

ECX/CX/CH/CL - contatore(count register), utilizzato come contatore per il numero di ripetizioni del loop.

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

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

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

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

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

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

ESP/SP (registro del puntatore dello stack) - Registrati puntatore pila. Contiene un puntatore all'inizio dello stack nel segmento dello stack corrente.

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

1.1.2. registri di segmento

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

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

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

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

    Segmento di dati aggiuntivo. I dati da elaborare possono trovarsi in tre segmenti di dati aggiuntivi. Per impostazione predefinita, si presume che i dati si trovino nel segmento di dati. Quando si utilizzano segmenti di dati aggiuntivi, i loro indirizzi devono essere specificati in modo esplicito utilizzando speciali prefissi di ridefinizione del segmento nel comando. Gli indirizzi di ulteriori segmenti di dati devono essere contenuti nei registri ES, GS, FS (extenSIon data segment registers).

        Registri di controllo e di stato

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

registro del puntatore di comando EIP/IP;

    Registro delle bandiere EFLAGS/FLAGS.

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

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

EFLAGS/FLAGS (registro delle bandiere) - Registrati bandiere. Profondità di bit 32/16 bit. I singoli bit di questo registro hanno uno scopo funzionale specifico e sono chiamati flag. Un flag è un bit impostato a 1 ("flag is set") se una condizione è soddisfatta e 0 ("flag is clear") altrimenti. La parte inferiore di questo registro è del tutto analoga al registro FLAGS per l'i8086.

1.1.3 Registro delle bandiere

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

Fig.1 Registro delle bandiere

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

Flag di condizione:

CF (porta bandiera) - portare bandiera. Assume il valore 1 se, durante l'aggiunta di numeri interi, è apparsa un'unità di riporto che non si "adattava" alla griglia di bit o se, durante la sottrazione di numeri senza segno, il primo di essi era inferiore al secondo. Nei comandi di scorrimento, il bit off-grid viene inserito nella CF. CF corregge anche le caratteristiche dell'istruzione di moltiplicazione.

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

ZF (bandiera zero) bandiera zero. Impostare a 1 se il risultato del comando è 0.

SF (Bandiera del segno) - bandiera cartello. Impostare a 1 se l'operazione sui numeri con segno ha esito negativo.

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

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

Flag di stato:

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

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

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

Bandiera di sistema:

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

TF (bandiera trappola) traccia bandiera. Con TF=1, dopo aver eseguito ciascuna istruzione, il processore esegue un interrupt (con numero 1), che può essere utilizzato durante il debug di un programma per tracciarlo.

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

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

AC (Controllo allineamento) - indicatore di controllo dell'allineamento. Progettato per consentire il controllo dell'allineamento durante l'accesso alla memoria.

      Organizzazione della memoria.

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

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

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

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

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

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

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

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

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

Ogni programma nel caso generale può essere costituito da un numero qualsiasi di segmenti, ma ha accesso diretto ai tre principali: codice, dati e stack e da uno a tre segmenti di dati aggiuntivi. Sistema operativo posiziona segmenti di programma nella RAM in determinati indirizzi fisici, dopodiché inserisce i valori di questi indirizzi nei registri corrispondenti. All'interno di un segmento, il programma accede agli indirizzi relativi all'inizio del segmento in modo lineare, ovvero partendo dall'indirizzo 0 e terminando con un indirizzo pari alla dimensione del segmento. Indirizzo relativo o pregiudizio, utilizzato dal microprocessore per accedere ai dati all'interno di un segmento efficace.

Formazione di un indirizzo fisico in modalità reale

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

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

Struttura delle istruzioni in linguaggio assembly La programmazione a livello di istruzioni macchina è il livello minimo al quale è possibile programmare 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: label istruzione/direttiva operando/i ; commenti L'etichetta, il comando/direttiva e l'operando sono separati da almeno uno spazio o un carattere di tabulazione. Gli operandi dell'istruzione 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 assemblaggio sono parametri specificati nel testo del programma che influenzano il processo di assemblaggio o le proprietà del file di output. L'operando specifica il valore iniziale dei dati (nel segmento di dati) o gli elementi su cui deve agire l'istruzione (nel segmento di codice). Un'istruzione può avere uno o due operandi o nessun operando. Il numero di operandi è implicitamente specificato dal codice dell'istruzione. Se il comando o la direttiva devono continuare sulla 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'identificativo può essere costituito da uno o più dei seguenti caratteri: tutte le lettere dell'alfabeto latino; numeri da 0 a 9; caratteri speciali: _, @, $, ? . Un punto può essere utilizzato come primo carattere dell'etichetta. I nomi di assembler riservati (direttive, operatori, nomi di comando) non possono essere utilizzati come identificatori. Il primo carattere dell'identificatore deve essere una lettera o un carattere speciale. La lunghezza massima dell'identificatore è di 255 caratteri, ma il traduttore accetta i primi 32 caratteri e ignora il resto. 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, specialmente quando lo scopo di un insieme 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 "; ' alla fine della riga ci sono commenti. Il commento può contenere qualsiasi carattere stampabile, incluso lo "spazio". Il commento può estendersi sull'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ù segmenti di dati, stack e codice. Qualsiasi programma in linguaggio assembly completo 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 opportune direttive.

Modelli di memoria Prima di dichiarare i segmenti, è necessario specificare il modello di memoria utilizzando una direttiva. MODIFICATORE MODELLO modello_di_memoria, convenzione_di_chiamata, tipo_di_sistema operativo, parametro_di_stack Modelli di memoria in linguaggio assembly di base: Modello di memoria Indirizzamento del codice Indirizzamento dei dati Sistema operativo Interleaving di codice e dati TINY VICINO MS-DOS Valido PICCOLO VICINO MS-DOS, Windows No MEDIUM FAR VICINO MS-DOS, Windows No COMPATTO VICINO LONTANO MS-DOS, Windows No GRANDE LONTANO MS-DOS, Windows No ENORME LONTANO MS-DOS, Windows No VICINO Windows 2000, Windows XP, Windows Valid FLAT VICINO NT,

Modelli di memoria Il modello tiny funziona solo nelle applicazioni MS-DOS a 16 bit. In questo modello, tutti i dati e il codice risiedono in un segmento fisico. La dimensione del file del 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 di dati, con tutti i collegamenti nei segmenti di codice considerati lontani (lontano) per impostazione predefinita e i collegamenti nel segmento di dati sono considerati vicini (vicini). 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 grande supporta più segmenti di codice e più segmenti di dati. Per impostazione predefinita, tutti i riferimenti al codice e ai dati sono considerati far. Il modello enorme è quasi equivalente al modello di memoria grande.

Modelli di memoria Il modello flat presuppone una configurazione di programma non segmentata e viene utilizzato solo su sistemi operativi a 32 bit. Questo modello è simile al modello minuscolo in quanto i dati e il codice risiedono nello stesso segmento a 32 bit. Sviluppare un programma per il modello piatto prima della direttiva. model flat dovrebbe porre una delle direttive: . 386, . 486, . 586 o. 686. La scelta della direttiva di selezione del processore determina l'insieme dei 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 codice è vicino, con tutti gli indirizzi e i puntatori a 32 bit.

modelli di memoria MODEL modifier memory_model, calling_convention, OS_type, stack_parameter Il parametro modifier 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 i linguaggi di alto livello (C++, Pascal). Il parametro può assumere i seguenti valori: C, BASIC, FORTRAN, PASCAL, SYSCALL, STDCALL.

modelli di memoria MODEL modifier 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, le regioni di dati e stack si trovano nello stesso segmento fisico) FARSTACK (il registro SS non è uguale a DS, le regioni di dati e stack si trovano in segmenti fisici diversi). L'impostazione predefinita è NEARSTACK.

Un esempio di un programma "non fare nulla". 686 P. MODELLO FLAT, STDCALL. DATI. CODE START: RET END START RET - comando a microprocessore. Assicura la corretta chiusura del programma. Il resto del programma è legato al funzionamento del traduttore. . 686 P - I comandi in modalità protetta Pentium 6 (Pentium II) sono consentiti. Questa direttiva seleziona il set di istruzioni assembler supportato specificando il modello di processore. . MODEL FLAT, stdcall - modello di memoria flat. Questo modello di memoria viene utilizzato nel sistema operativo Windows. stdcall è la procedura che chiama la convenzione da usare.

Un esempio di un programma "non fare nulla". 686 P. MODELLO FLAT, STDCALL. DATI. CODICE START: RET END START . DATA - segmento di programma contenente dati. Questo programma non usa lo stack, quindi segment. Manca la pila. . CODE - 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 del codice sorgente del programma. 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 mezzi tecnici A che converte un programma in uno dei linguaggi di programmazione in un programma nella lingua di destinazione, chiamato codice oggetto. Oltre a supportare la mnemonica delle istruzioni della macchina, ogni traduttore ha il proprio insieme di direttive e macro, spesso incompatibili con qualsiasi altra cosa. I principali tipi di traduttori in linguaggio assembly sono: MASM (Microsoft Assembler), TASM (Borland Turbo Assembler), FASM (Flat Assembler) - un assemblatore multi-pass distribuito liberamente scritto da Tomasz Gryshtar (polacco), NASM (Netwide Assembler) - un assemblatore gratuito per l'architettura Intel x 86 è stato creato da Simon Tatham con Julian Hall ed è attualmente sviluppato da un piccolo team di sviluppo presso Source. Fucina. rete.

Src="https://present5.com/presentation/-29367016_63610977/image-15.jpg" alt="(!LANG:Program translation 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="(!LANG:Program translation in Microsoft Visual Studio 2005 2) Nell'albero del progetto (Visualizza->Solution Explorer) 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. Seleziona sul pulsante a destra nel menu del file di progetto Regole di creazione personalizzate...

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

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

Src="https://present5.com/presentation/-29367016_63610977/image-22.jpg" alt="(!LANG:Program translation in Microsoft Visual Studio 2005 6) Compila 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, ovvero interfaccia 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 si verificano, di regola, attraverso tali funzioni. sala operatoria Sistema Windows utilizza un modello di memoria piatta. 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), console o struttura senza finestre, struttura classica (finestra, frame).

Chiamata Caratteristiche di Windows API Nel file della guida, qualsiasi funzione API è rappresentata come tipo nome_funzione (FA 1, FA 2, FA 3) Tipo – valore restituito tipo; FAX – elenco di argomenti formali nel loro ordine, ad esempio int Messaggio. Box (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Questa funzione visualizza una finestra con un messaggio e uno o più pulsanti di uscita. Significato dei parametri: h. Wnd - handle per la 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, puoi specificare il numero di pulsanti di uscita.

Chiamata delle funzioni API di Windows int Message. Box (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); 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. Box (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Quando si utilizza MASM, è necessario aggiungere @N N alla fine del nome, il numero di byte occupati dagli argomenti passati nello stack. Per le funzioni API Win 32, questo numero può essere definito come il numero di argomenti n volte 4 (byte in ogni argomento): N=4*n. Per chiamare una funzione, viene utilizzata 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à inserito per primo nello stack. genere. La chiamata della funzione specificata sarà simile a questa: CALL Message. scatola. [e-mail protetta]

Chiamata delle funzioni API di Windows int Message. Box (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Il risultato dell'esecuzione di qualsiasi funzione API è in genere un numero intero, che viene restituito nel registro EAX. La direttiva OFFSET è un "segment offset" 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 FLAT, STDCALL. STACK 4096. DATA MB_OK EQU 0 STR 1 DB "Il mio primo programma", 0 STR 2 DB "Ciao a tutti!", 0 HW DD ? Messaggio ESTERNO. scatola. [e-mail protetta]: VICINO. CODICE INIZIO: PUSH MB_OK PUSH OFFSET STR 1 PUSH OFFSET STR 2 PUSH HW CALL Messaggio. scatola. [e-mail protetta] RITORNO FINE INIZIO

La direttiva INVOKE Il traduttore di lingua MASM consente anche di 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 disporre di una descrizione del prototipo della funzione utilizzando la direttiva PROTO nella forma: Messaggio. scatola. A PROTO: DWORD, : DWORD