Componentele de bază ale limbajului de asamblare și structura de instrucție. Formatul datelor și structura comenzilor limbajului de asamblare. La disciplina „Programare sistem”

Introducere.

Se numește limba în care este scris programul sursă Intrare limba și limba în care este tradus pentru executare de către procesor este în zilele libere limbă. Procesul de conversie a limbajului de intrare în limbaj de ieșire este numit difuzat. Deoarece procesoarele sunt capabile să execute programe în limbaj mașină binar, care nu este folosit pentru programare, este necesară traducerea tuturor programelor sursă. Cunoscut doua feluri emisiuni: compilare și interpretare.

La compilare programul sursă este mai întâi tradus complet într-un program echivalent în limbajul de ieșire, numit obiect program și apoi executat. Acest proces este implementat cu ajutorul unui program special programe, numit compilator. Un compilator pentru care limbajul de intrare este o formă simbolică de reprezentare a limbajului mașină (de ieșire) al codurilor binare se numește asamblator.

La interpretări Fiecare linie de text din programul sursă este analizată (interpretată) și comanda specificată în acesta este imediat executată. Implementarea acestei metode îi este încredințată program de interpret. Interpretarea durează mult. Pentru a-și crește eficiența, în loc să proceseze fiecare linie, interpretul le convertește mai întâi pe toate echipășiruri în caractere (

). Secvența generată de simboluri este utilizată pentru a îndeplini funcțiile atribuite programului original.

Limbajul de asamblare discutat mai jos este implementat folosind compilare.

Caracteristicile limbii.

Principalele caracteristici ale asamblatorului:

● în loc de coduri binare, limba folosește nume simbolice - mnemonice. De exemplu, pentru comanda de adăugare (

) sunt folosite mnemonice

Scăderi (

inmultire (

Diviziuni (

etc. Numele simbolice sunt, de asemenea, folosite pentru adresa celulelor de memorie. Pentru a programa în limbaj de asamblare, în loc de coduri și adrese binare, trebuie să cunoașteți doar nume simbolice pe care asamblatorul le traduce în coduri binare;

fiecare afirmatie corespunde o comandă de mașină(cod), adică există o corespondență unu-la-unu între comenzile mașinii și operatori într-un program în limbaj de asamblare;

● limba oferă acces la toate obiectele si echipe. Limbile de nivel înalt nu au această abilitate. De exemplu, limbajul de asamblare vă permite să verificați biți din registrul steagului și limbajul de nivel înalt (de exemplu,

) nu are această capacitate. Rețineți că limbajele de programare a sistemelor (de exemplu, C) ocupă adesea o poziție intermediară. În ceea ce privește accesibilitatea, acestea sunt mai apropiate de limbajul de asamblare, dar au sintaxa unui limbaj de nivel înalt;

● limbaj de asamblare nu este un limbaj universal. Fiecare grup specific de microprocesoare are propriul său asamblator. Limbile de nivel înalt nu au acest dezavantaj.

Spre deosebire de limbajele de nivel înalt, scrierea și depanarea unui program în limbaj de asamblare necesită mult timp. În ciuda acestui fapt, limbajul de asamblare a primit utilizare largă datorita urmatoarelor circumstante:

● un program scris în limbaj de asamblare este semnificativ mai mic ca dimensiune și rulează mult mai rapid decât un program scris într-un limbaj de nivel înalt. Pentru unele aplicații, acești indicatori joacă un rol principal, de exemplu, mulți programe de sistem(inclusiv compilatoare), programe pe cărți de credit, celulare, drivere de dispozitiv etc.;

● unele proceduri necesită acces complet la hardware, ceea ce este de obicei imposibil de realizat într-un limbaj de nivel înalt. Acest caz include întreruperi și gestionare de întreruperi în sistemele de operare, precum și controlere de dispozitiv în sistemele încorporate în timp real.

În majoritatea programelor, doar un mic procent din codul total este responsabil pentru un procent mare din timpul de execuție al programului. De obicei, 1% din program este responsabil pentru 50% din timpul de execuție, iar 10% din program este responsabil pentru 90% din timpul de execuție. Prin urmare, pentru a scrie un program specific în condiții reale, se utilizează atât asamblatorul, cât și unul dintre limbajele de nivel înalt.

Format operator în limbaj de asamblare.

Un program în limbaj de asamblare este o listă de comenzi (instrucțiuni, propoziții), fiecare dintre acestea ocupând o linie separată și conține patru câmpuri: un câmp de etichetă, un câmp de operare, un câmp de operand și un câmp de comentariu. Fiecare câmp are o coloană separată.

Câmp de etichetă.

Coloana 1 este alocată pentru câmpul etichetă. Eticheta este un nume simbolic sau un identificator, adrese memorie. Este necesar pentru a putea:

● face o trecere condiționată sau necondiționată la comandă;

● obțineți acces la locația în care sunt stocate datele.

Astfel de declarații sunt prevăzute cu o etichetă. Pentru a indica un nume, sunt folosite litere (majuscule) din alfabetul englez și numere. Numele trebuie să aibă o literă la început și un separator de două puncte la sfârșit. Eticheta două puncte poate fi scrisă pe o linie separată, iar opcode-ul poate fi scris pe următoarea linie din coloana 2, ceea ce simplifică munca compilatorului. Absența două puncte nu permite distingerea unei etichete de un cod de operație dacă acestea sunt situate pe linii separate.

În unele versiuni ale limbajului de asamblare, două puncte sunt plasate numai după etichetele de instrucțiuni, nu după etichetele de date, iar lungimea etichetei poate fi limitată la 6 sau 8 caractere.

Nu ar trebui să existe nume identice în câmpul de etichetă, deoarece eticheta este asociată cu adrese de comandă. Dacă în timpul execuției programului nu este nevoie să apelați o comandă sau date din memorie, atunci câmpul de etichetă rămâne gol.

Câmpul pentru codul operațiunii.

Acest câmp conține codul mnemonic pentru o comandă sau pseudo-comandă (vezi mai jos). Codul mnemonic al comenzii este ales de dezvoltatorii limbajului. În limbaj de asamblare

mnemonic este selectat pentru a încărca un registru din memorie

), și pentru a salva conținutul registrului în memorie - un mnemonic

). În limbaje de asamblare

pentru ambele operațiuni puteți folosi, respectiv, același nume

Dacă alegerea numelor mnemonice poate fi arbitrară, atunci necesitatea de a utiliza două instrucțiuni de mașină este determinată de arhitectura procesorului

Mnemotecnia registrelor depinde și de versiunea de asamblare (Tabelul 5.2.1).

Câmp operand.

Aici se află Informații suplimentare, necesare efectuarii operatiei. În câmpul operand pentru comenzile de săritură este indicată adresa la care trebuie efectuată săritura, precum și adresele și registrele care sunt operanzi pentru comanda mașinii. Ca exemplu, oferim operanzi care pot fi utilizați pentru procesoare pe 8 biți

● date numerice,

prezentate în diferite sisteme numerice. Pentru a indica sistemul numeric folosit, constanta este urmată de una dintre literele latine: B,

În consecință, sistemele de numere binar, octal, hexazecimal, zecimal (

Nu trebuie să-l scrieți). Dacă prima cifră a unui număr hexazecimal este A, B, C,

Apoi se adaugă un 0 (zero) nesemnificativ în față;

● coduri ale registrelor interne ale microprocesorului și celulelor de memorie

M (surse sau receptori de informații) sub forma literelor A, B, C,

M sau adresele acestora în orice sistem de numere (de exemplu, 10B - adresa de înregistrare

în sistem binar);

● identificatori,

pentru perechi de aeronave de înregistrare,

Primele litere sunt B,

N; pentru o pereche de acumulator și registru de caracteristici -

; pentru contorul de programe -

;pentru indicatorul stivei -

● etichete care indică adresele operanzilor sau instrucțiunile următoare din condițional

(dacă este îndeplinită condiția) și tranziții necondiționate. De exemplu, operandul M1 din comandă

înseamnă necesitatea unei tranziții necondiționate la comandă, a cărei adresă în câmpul de etichetă este marcată cu identificatorul M1;

● expresii,

care sunt construite prin legarea datelor discutate mai sus folosind operatori aritmetici și logici. Rețineți că metoda de rezervare a spațiului de date depinde de versiunea limbii. Dezvoltatori de limbaj de asamblare pentru

Definiți cuvântul) și introdus ulterior Opțiune alternativă.

care a fost în limbajul pentru procesoare încă de la început

În versiune lingvistică

folosit

Definiți o constantă).

Procesoarele procesează operanzi de diferite lungimi. Pentru a-l defini, dezvoltatorii de asamblare au luat diferite decizii, de exemplu:

Registrele II de lungimi diferite au nume diferite: EAX - pentru plasarea operanzilor pe 32 de biți (tip

); AX - pentru 16 biți (tip

și AN - pentru 8 biți (tip

● pentru procesoare

La fiecare cod de operare se adaugă sufixe: sufix

Pentru tip

; sufixul „.B” pentru tip

diferite opcode sunt utilizate pentru operanzi de diferite lungimi, de exemplu, pentru a încărca un octet, jumătate de cuvânt (

) și cuvinte într-un registru de 64 de biți folosind opcodes

respectiv.

Câmp de comentarii.

Acest câmp oferă explicații despre acțiunile programului. Comentariile nu afectează funcționarea programului și sunt destinate oamenilor. Ele pot fi necesare pentru a modifica un program, care fără astfel de comentarii poate fi complet de neînțeles chiar și pentru programatorii experimentați. Un comentariu începe cu un simbol și este folosit pentru a explica și documenta programe. Caracterul de început al unui comentariu poate fi:

● punct și virgulă (;) în limbile pentru procesoarele companiei

Semn de exclamare(!) în limbi pentru

Fiecare linie de comentariu separată este precedată de un caracter principal.

Pseudo-comenzi (directive).

În limbajul de asamblare există două tipuri principale de comenzi:

de bază instrucțiuni care sunt echivalentul codului mașinii procesorului. Aceste comenzi efectuează toate procesările prevăzute de program;

pseudo-comenzi sau directive, conceput pentru a deservi procesul de traducere a unui program într-un limbaj de combinare de coduri. Ca exemplu în tabel. 5.2.2 prezintă câteva pseudo-comenzi de la asamblator

pentru familie

.

La programare, sunt situații în care, conform algoritmului, același lanț de comenzi trebuie repetat de mai multe ori. Pentru a ieși din această situație puteți:

● scrieți secvența necesară de comenzi ori de câte ori apare. Această abordare duce la o creștere a volumului programului;

● aranjați această secvență într-o procedură (subrutină) și apelați-o dacă este necesar. Această ieșire are dezavantajele sale: de fiecare dată trebuie să executați o comandă de apel de procedură specială și o comandă de returnare, care, dacă secvența este scurtă și utilizată frecvent, poate reduce foarte mult viteza programului.

Cel mai simplu și metoda eficienta repetarea repetată a unui lanț de comenzi constă în folosirea macro, care poate fi reprezentată ca o pseudo-comandă concepută pentru a retraduce un grup de comenzi des întâlnite într-un program.

O macrocomandă sau macrocomandă se caracterizează prin trei aspecte: macrodefiniție, macroinversie și macroextensie.

Definiție macro

Aceasta este o desemnare pentru o secvență repetată în mod repetat de comenzi de program, folosită pentru referințe în textul programului.

Definiția macro are următoarea structură:

Lista de expresii; Definiție macro

În structura dată de macro-definiție, se pot distinge trei părți:

● titlu

macro, inclusiv numele

Pseudo-comandă

și un set de parametri;

● marcate cu puncte corp macro;

● echipa

absolvire

definiții macro.

Setul de parametri de definiție macro conține o listă cu toți parametrii dați în câmpul operand pentru grupul de instrucțiuni selectat. Dacă acești parametri au fost indicați mai devreme în program, atunci nu trebuie să fie indicați în antetul definiției macro.

Pentru a reasambla grupul selectat de comenzi, se folosește un apel constând din nume

comenzi macro și listă de parametri cu alte valori.

Când asamblatorul întâlnește o definiție de macro în timpul procesului de compilare, o stochează în tabelul de definiții de macro. La aparițiile ulterioare în programul numelui (

) a unei macrocomenzi, asamblatorul o înlocuiește cu corpul macro-ului.

Utilizarea unui nume de macrocomandă ca opcode este apelată macro-inversare(apel macro) și înlocuirea acestuia cu corpul macro-ului - extinderea macro.

Dacă un program este reprezentat ca o secvență de caractere (litere, numere, spații, semne de punctuație și întoarceri de cărucior pentru a trece la o nouă linie), atunci extinderea macro constă în înlocuirea unor lanțuri din această secvență cu alte lanțuri.

Extinderea macro-ului are loc în timpul procesului de asamblare, nu în timpul execuției programului. Le sunt atribuite metode de manipulare a șirurilor de caractere macro înseamnă.

Procesul de asamblare este efectuat in doua treceri:

● La prima trecere, toate definițiile macro sunt păstrate, iar apelurile macro sunt extinse. În acest caz, programul original este citit și convertit într-un program în care toate definițiile macro sunt eliminate și fiecare apel de macro este înlocuit cu corpul macro-ului;

● a doua trecere procesează programul rezultat fără macro-uri.

Macro-uri cu parametri.

Pentru a lucra cu secvențe repetate de comenzi, ai căror parametri pot lua valori diferite, sunt furnizate definiții macro:

● cu real parametrii care sunt plasați în câmpul operand al apelului macro;

● cu formal parametrii. În timpul extinderii macro, fiecare parametru formal care apare în corpul macro-ului este înlocuit cu parametrul real corespunzător.

folosind macro-uri cu parametri.

Programul 1 conține două secvențe similare de comenzi, care diferă prin faptul că prima schimbă P și

Iar al doilea

Programul 2 include o macro cu doi parametri formali P1 și P2. În timpul extinderii macro, fiecare caracter P1 din corpul macro este înlocuit cu primul parametru real (P,

), iar simbolul P2 este înlocuit cu al doilea parametru real (

) din programul nr. 1. În apelul macro

programul 2 este marcat: P,

Primul parametru real,

Al doilea parametru real.

Programul 1

Programul 2

MOV EBX,Q MOV EAX,Pl

MOV Q,EAX MOV EBX,P2

MOV P,EBX MOV P2,EAX

Capabilitati extinse.

Să ne uităm la câteva caracteristici avansate ale limbii

Dacă o macrocomandă care conține o comandă de salt condiționat și o etichetă la care trebuie sărită este apelată de două sau de mai multe ori, eticheta va fi duplicată (problema cu eticheta duplicată), ceea ce va cauza o eroare. Prin urmare, fiecare apel atribuie o etichetă separată ca parametru (de către programator). În limbaj

eticheta este declarată locală (

) și datorită capabilităților avansate, asamblatorul generează automat o etichetă diferită de fiecare dată când macro-ul este extins.

vă permite să definiți macrocomenzi în interiorul altor macrocomenzi. Această caracteristică avansată este foarte utilă în combinație cu legarea condiționată a unui program. Sa luam in considerare

IF WORDSIZE GT 16 M2 MACRO

Macro-ul M2 poate fi definit în ambele părți ale declarației

Cu toate acestea, definiția depinde de procesorul pe care este asamblat programul: 16 biți sau 32 de biți. Dacă M1 nu este apelat, atunci macro M2 nu va fi definită deloc.

O altă caracteristică avansată este că macrocomenzile pot apela alte macrocomenzi, inclusiv ele însele - recursiv apel. În acest din urmă caz, pentru a evita o buclă fără sfârșit, macro-ul trebuie să-și transmită un parametru care se modifică cu fiecare extindere și, de asemenea, Verifica acest parametru și încheie recursiunea când parametrul atinge o anumită valoare.

Despre utilizarea mijloacelor macro în asamblare.

Când utilizați macrocomenzi, asamblatorul trebuie să poată îndeplini două funcții: salvați definițiile macroȘi extinde provocările macro.

Salvarea definițiilor macro.

Toate numele macrocomenzilor sunt stocate într-un tabel. Fiecare nume este însoțit de un indicator către macrocomanda corespunzătoare, astfel încât să poată fi apelat dacă este necesar. Unii asamblatori au un tabel separat pentru numele macro-urilor, alții au un tabel general în care, împreună cu numele macro-urilor, se află toate instrucțiunile și directivele mașinii.

Când întâlniți o macrocomandă în timpul asamblarii este creat:

nou element de masă cu numele macro-ului, numărul de parametri și un pointer către un alt tabel de definire a macrocomenzii în care va fi stocat corpul macro-ului;

● listă formal parametrii.

Corpul macrocomenzii, care este pur și simplu un șir de caractere, este apoi citit și stocat în tabelul de definire a macrocomenzii. Parametrii formali care apar în corpul buclei sunt marcați caracter special.

Reprezentarea internă a unei macrocomenzi

din exemplul de mai sus pentru programul 2 (p. 244) este:

MOV EAX, MOV EBX, MOV MOV &

unde punctul și virgulă este folosit ca caracter de returnare a căruciorului, iar ampersand & este folosit ca caracter parametru formal.

Extinderea apelurilor macro.

Ori de câte ori o definiție macro este întâlnită în timpul asamblarii, aceasta este stocată în tabelul macro. Când este apelată o macrocomandă, asamblatorul oprește temporar citirea datelor de intrare de pe dispozitivul de intrare și începe să citească corpul macro-ului stocat. Parametrii formali extrași din corpul macro sunt înlocuiți cu parametri reali și furnizați de apel. Parametrii ampersand & before permit asamblatorului să-i recunoască.

În ciuda faptului că există multe versiuni de asamblare, procesele de asamblare au caracteristici comune și sunt similare în multe privințe. Funcționarea unui asamblator cu două treceri este discutată mai jos.

Asamblator cu două treceri.

Un program constă dintr-un număr de declarații. Prin urmare, s-ar părea că la asamblare, puteți utiliza următoarea secvență de acțiuni:

● traducerea acestuia în limbajul mașinii;

● transferați codul mașinii rezultat într-un fișier, iar partea corespunzătoare a listei într-un alt fișier;

● repetați procedurile enumerate până când întregul program este tradus.

Cu toate acestea, această abordare nu este eficientă. Un exemplu este așa-numita problemă link direct. Dacă prima instrucțiune este un salt la instrucțiunea P, situată la sfârșitul programului, atunci asamblatorul nu o poate traduce. Mai întâi trebuie să determine adresa operatorului P, iar pentru a face acest lucru trebuie să citească întregul program. Fiecare citire completă a programului sursă este apelată trecere. Să arătăm cum puteți rezolva problema link-ului anticipat folosind două treceri:

la prima trecere ar trebui colectareași stocați toate definițiile simbolurilor (inclusiv etichetele) în tabel, iar la a doua trecere, citiți și asamblați fiecare operator. Această metodă este relativ simplă, dar o a doua trecere prin programul original necesită timp suplimentar petrecut cu operațiunile I/O;

● la prima trecere ar trebui convertit programul într-o formă intermediară și salvați-l într-un tabel și efectuați a doua trecere nu conform programului original, ci conform tabelului. Această metodă de asamblare economisește timp, deoarece a doua trecere nu efectuează operațiuni I/O.

Prima trecere.

Gol din prima pasă- construiți un tabel de simboluri. După cum sa menționat mai sus, un alt obiectiv al primei treceri este păstrarea tuturor definițiilor macro și extinderea apelurilor pe măsură ce apar. În consecință, atât definirea simbolului, cât și extinderea macro au loc într-o singură trecere. Simbolul poate fi oricare eticheta, sau sens, căruia i se atribuie un nume specific folosind directiva -you:

;Valoare - dimensiunea tamponului

Atribuind semnificații numelor simbolice în câmpul de etichetă a comenzii, asamblatorul specifică în esență adresele pe care fiecare comandă le va avea în timpul execuției programului. În acest scop, asamblatorul stochează în timpul procesului de asamblare contor de adrese de instrucțiuni(

) ca o variabilă specială. La începutul primei treceri, valoarea variabilei speciale este setată la 0 și crește după fiecare comandă procesată de lungimea acelei comenzi. Ca exemplu în tabel. 5.2.3 prezintă un fragment de program care indică lungimea comenzilor și valorile contorului. La prima trecere, sunt generate tabele nume simbolice, directiveȘi coduri de operare, iar dacă este necesar literal masa. Un literal este o constantă pentru care asamblatorul își rezervă automat memorie. Să remarcăm imediat că procesoarele moderne conțin instrucțiuni cu adrese imediate, astfel încât asamblatorii lor nu acceptă literale.

Tabel cu nume de simbol

conține câte un element pentru fiecare nume (Tabelul 5.2.4). Fiecare element al tabelului de nume simbolice conține numele în sine (sau un indicator către acesta), valoarea sa numerică și, uneori, câteva informații suplimentare, care pot include:

● lungimea câmpului de date asociat simbolului;

● biți de realocare a memoriei (care indică dacă valoarea unui simbol se modifică dacă programul este încărcat la o adresă diferită de cea prevăzută de asamblator);

● informații despre dacă simbolul poate fi accesat din afara procedurii.

Numele simbolice sunt etichete. Ele pot fi specificate folosind operatori (de exemplu,

Tabel directiv.

Acest tabel listează toate directivele, sau pseudo-comenzile, care sunt întâlnite la asamblarea unui program.

Tabelul de coduri de operare.

Pentru fiecare cod de operare, tabelul are coloane separate: denumirea codului de operare, operandul 1, operandul 2, valoarea hexazecimală a codului de operare, lungimea comenzii și tipul comenzii (Tabelul 5.2.5). Codurile de operare sunt împărțite în grupuri în funcție de numărul și tipul operanzilor. Tipul de comandă determină numărul grupului și specifică procedura care este apelată pentru a procesa toate comenzile din acel grup.

A doua trecere.

Golul celei de-a doua pasi- realizarea unui program obiect si tiparirea, daca este cazul, a protocolului de asamblare; informațiile de ieșire necesare pentru linker pentru a lega procedurile care au fost asamblate la momente diferite într-un singur fișier executabil.

În a doua trecere (ca și în prima), rândurile care conțin declarațiile sunt citite și procesate unul câte unul. Operatorul original și operatorul de ieșire derivat din acesta în hexazecimal obiect Codul poate fi tipărit sau plasat într-un buffer pentru imprimare ulterioară. După resetarea contorului de adrese de comandă, comanda este apelată următoarea declarație.

Programul sursă poate conține erori, de exemplu:

simbolul dat nu este definit sau este definit de mai multe ori;

● opcode-ul este reprezentat de un nume nevalid (din cauza unei greșeli de scriere), nu are destui operanzi sau are prea mulți operanzi;

● fără operator

Unii asamblatori pot detecta un simbol nedefinit și îl pot înlocui. Cu toate acestea, în majoritatea cazurilor, când întâlnește o declarație de eroare, asamblatorul afișează un mesaj de eroare pe ecran și încearcă să continue procesul de asamblare.

Articole dedicate limbajului de asamblare.

UNIVERSITATEA NAȚIONALĂ DIN UZBEKISTAN NUMITĂ DUPĂ MIRZO ULUGBEK

FACULTATEA DE TEHNOLOGIA CALCULATORULUI

Pe subiect: Analiza semantică a unui fișier EXE.

Efectuat:

Tașkent 2003.

Prefaţă.

Limbajul de asamblare și structura de comandă.

Structura fișierului EXE (parsare semantică).

Structura fișierului COM.

Principiul de acțiune și răspândire a virusului.

Dezasamblator.

Programe.

Prefaţă

Profesia de programator este uimitoare și unică. În zilele noastre, este imposibil să ne imaginăm știința și viața fără cea mai recentă tehnologie. Tot ceea ce ține de activitatea umană nu se poate face fără tehnologia calculatoarelor. Și acest lucru contribuie la dezvoltarea și perfecțiunea sa ridicată. Deși dezvoltarea computerelor personale a început nu cu mult timp în urmă, în acest timp s-au făcut pași colosali în produsele software și aceste produse vor fi utilizate pe scară largă pentru o lungă perioadă de timp. Domeniul cunoștințelor legate de computer a cunoscut o explozie, la fel ca și tehnologia corespunzătoare. Dacă nu ținem cont de latura comercială, atunci putem spune că nu există străini în acest domeniu de activitate profesională. Mulți oameni dezvoltă programe nu pentru profit sau venituri, ci din propria voință, din pasiune. Desigur, acest lucru nu ar trebui să afecteze calitatea programului, iar în această afacere, ca să spunem așa, există concurență și cerere pentru execuție de calitate, muncă stabilă și îndeplinirea tuturor cerințelor moderne. Aici este de remarcat și apariția microprocesoarelor în anii 60, care au venit să înlocuiască un număr mare de seturi de lămpi. Există unele tipuri de microprocesoare care sunt foarte diferite unele de altele. Aceste microprocesoare diferă unele de altele prin adâncimea de biți și comenzile de sistem încorporate. Cele mai comune sunt: ​​Intel, IBM, Celeron, AMD etc. Toate aceste procesoare sunt legate de arhitectura avansată a procesoarelor Intel. Răspândirea microcalculatoarelor a determinat o reconsiderare a atitudinilor față de limbajul de asamblare din două motive principale. În primul rând, programele scrise în limbaj de asamblare necesită mult mai puțină memorie și timp de execuție. În al doilea rând, cunoașterea limbajului de asamblare și a codului de mașină rezultat oferă o înțelegere a arhitecturii mașinii, care este puțin probabil să fie furnizată atunci când se lucrează într-un limbaj de nivel înalt. Deși majoritatea profesioniștilor de software se dezvoltă în limbaje de nivel înalt precum Pascal, C sau Delphi, care este mai ușor atunci când scrieți programe, cel mai puternic și eficient software scris integral sau parțial în limbaj de asamblare. Limbile de nivel înalt au fost concepute pentru a evita special caracteristici tehnice calculatoare specifice. Iar limbajul de asamblare, la rândul său, este conceput pentru specificul specific al procesorului. Prin urmare, pentru a scrie un program în limbaj de asamblare pentru un anumit computer, trebuie să cunoașteți arhitectura acestuia. În aceste zile, vederea principală produs software este un fișier EXE. Luand in considerare laturi pozitive Aceasta înseamnă că autorul programului poate avea încredere în integritatea acestuia. Dar de multe ori acest lucru este departe de a fi cazul. Există și un dezasamblator. Folosind un dezasamblator, puteți afla întreruperi și coduri de program. Nu va fi dificil pentru o persoană bine versată în asamblare să refacă întregul program după gustul său. Poate că aici apare cea mai insolubilă problemă - virusul. De ce scriu oamenii un virus? Unii pun această întrebare cu surprindere, alții cu furie, dar cu toate acestea continuă să existe oameni care sunt interesați de această sarcină nu din punctul de vedere al producerii vreunui rău, ci ca interes pentru programarea sistemului. Virușii sunt scrisi de diverse motive. Unora le plac apelurile de sistem, alții își îmbunătățesc cunoștințele despre asamblare. Voi încerca să explic toate acestea în mine munca de curs. De asemenea, spune nu numai despre structura fișierului EXE, ci și despre limbajul de asamblare.

^ Limbajul de asamblare.

Este interesant de urmărit, de la apariția primelor calculatoare și până în zilele noastre, transformarea ideilor programatorilor despre limbajul de asamblare.

Pe vremuri, asamblarea era un limbaj fără de care nu puteai face un computer să facă nimic util. Treptat, situația s-a schimbat. Au apărut mijloace mai convenabile de a comunica cu un computer. Dar, spre deosebire de alte limbi, asamblatorul nu a murit; în plus, nu a putut face acest lucru în principiu. De ce? În căutarea unui răspuns, să încercăm să înțelegem ce este limbajul de asamblare în general.

Pe scurt, limbajul de asamblare este o reprezentare simbolică a limbajului mașină. Toate procesele dintr-o mașină la cel mai scăzut nivel hardware sunt conduse numai de comenzi (instrucțiuni) în limbajul mașinii. Din aceasta rezultă clar că, în ciuda numelui comun, limbajul de asamblare este diferit pentru fiecare tip de computer. Se aplică și acest lucru aspect programe scrise în limbaj de asamblare și idei pe care acest limbaj este o reflectare.

Este imposibil să rezolvi cu adevărat probleme legate de hardware (sau chiar, mai mult, dependente de hardware, precum creșterea vitezei unui program), fără cunoștințe de asamblare.

Un programator sau orice alt utilizator poate folosi orice instrumente de nivel înalt, chiar și programe pentru construirea de lumi virtuale și poate nici măcar nu bănuiește că de fapt computerul nu execută comenzile limbajului în care este scris programul său, ci reprezentarea lor transformată. sub forma unor secvențe plictisitoare și plictisitoare de comenzi dintr-un limbaj complet diferit - limbajul mașinii. Acum să ne imaginăm că un astfel de utilizator are o problemă non-standard sau ceva pur și simplu nu funcționează. De exemplu, programul său trebuie să funcționeze cu un dispozitiv neobișnuit sau să efectueze alte acțiuni care necesită cunoașterea principiilor de funcționare a hardware-ului computerului. Oricât de inteligent este programatorul, indiferent cât de bun ar fi limbajul în care și-a scris minunatul program, nu se poate lipsi de cunoștințe de asamblare. Și nu este o coincidență faptul că aproape toate compilatoarele de limbaj de nivel înalt conțin mijloace de conectare a modulelor lor cu module de asamblare sau de a sprijini accesul la nivelul de asamblare de programare.

Desigur, vremea generaliştilor informatici a trecut deja. După cum se spune, nu poți îmbrățișa imensitatea. Dar există ceva în comun, un fel de fundație pe care se construiește orice educație serioasă în domeniul informaticii. Aceasta este cunoștințele despre principiile funcționării computerului, arhitectura și limbajul de asamblare ca o reflectare și întruchipare a acestor cunoștințe.

Un computer modern tipic (i486 sau bazat pe Pentium) este format din următoarele componente (Figura 1).

Orez. 1. Computer și periferice

Orez. 2. Diagrama bloc calculator personal

Din figură (Figura 1) se poate observa că computerul este alcătuit din mai multe dispozitive fizice, fiecare dintre ele conectat la o unitate, numită unitate de sistem. Dacă gândim logic, este clar că joacă rolul unui fel de dispozitiv de coordonare. Să ne uităm în interiorul unității de sistem (nu este nevoie să încercați să intrați în interiorul monitorului - nu este nimic interesant acolo și, în plus, este periculos): deschideți carcasa și vedeți câteva plăci, blocuri, fire de conectare. Pentru a înțelege scopul lor funcțional, să ne uităm la diagrama bloc a unui computer tipic (Fig. 2). Nu pretinde acuratețe absolută și este destinat doar să arate scopul, interconectarea și compoziția tipică a elementelor unui computer personal modern.

Să discutăm diagrama din fig. 2 într-un stil oarecum neconvențional.
Este obișnuit ca o persoană, atunci când întâlnește ceva nou, să caute niște asociații care o pot ajuta să înțeleagă necunoscutul. Ce asocieri evocă computerul? De exemplu, asociez adesea un computer cu persoana însăși. De ce?

Când o persoană a creat un computer, undeva în adâncul său a crezut că creează ceva asemănător cu el însuși. Computerul are organe pentru primirea informațiilor din lumea exterioară - o tastatură, un mouse și unități de disc magnetice. În fig. 2 aceste organe sunt situate în dreapta magistralelor de sistem. Computerul are organe care „digeră” informațiile primite - acestea sunt CPUși RAM. Și, în sfârșit, computerul are organe de vorbire care produc rezultatele prelucrării. Acestea sunt și câteva dintre dispozitivele din dreapta.

Calculatoare moderne, desigur, este departe de a fi uman. Ele pot fi comparate cu creaturile care interacționează cu lumea exterioară la nivelul unui set mare, dar limitat de reflexe necondiționate.
Acest set de reflexe formează un sistem de comenzi de mașină. Indiferent cât de înalt este nivelul de comunicare cu un computer, în cele din urmă se reduce la o secvență plictisitoare și monotonă de comenzi ale mașinii.
Fiecare comandă a mașinii este un fel de stimul pentru a excita unul sau altul reflex necondiționat. Reacția la acest stimul este întotdeauna neechivocă și „cablată” în blocul de microcomandă sub forma unui microprogram. Acest microprogram implementează acțiuni pentru implementarea unei comenzi de mașină, dar la nivelul semnalelor furnizate anumitor logică computer, controlând astfel diverse subsisteme ale computerului. Acesta este așa-numitul principiu al controlului microprogramelor.

Continuând analogia cu o persoană, observăm: pentru ca un computer să mănânce corect, au fost inventate multe sisteme de operare, compilatoare pentru sute de limbaje de programare etc.. Dar toate sunt, de fapt, doar un platou pe care alimentele (programele) se livrează după anumite reguli.stomacul (calculatorul). Doar stomacul computerului iubește dieta, mâncarea monotonă - dă-i informații structurate, sub formă de secvențe strict organizate de zerouri și unu, ale căror combinații alcătuiesc limbajul mașinii.

Astfel, deși în exterior este un poliglot, computerul înțelege o singură limbă - limba instrucțiunilor mașinii. Desigur, pentru a comunica și a lucra cu un computer, nu este necesar să cunoașteți acest limbaj, dar aproape orice programator profesionist se confruntă mai devreme sau mai târziu cu nevoia de a-l studia. Din fericire, programatorul nu trebuie să încerce să înțeleagă semnificația diferitelor combinații de numere binare, deoarece în anii 50, programatorii au început să folosească un analog simbolic al limbajului mașină pentru programare, care a fost numit limbaj de asamblare. Acest limbaj reflectă cu acuratețe toate caracteristicile limbajului mașinii. De aceea, spre deosebire de limbajele de nivel înalt, limbajul de asamblare este diferit pentru fiecare tip de computer.

Din toate cele de mai sus, putem concluziona că, deoarece limbajul de asamblare este „nativ” pentru un computer, cel mai eficient program poate fi scris doar în el (cu condiția să fie scris de un programator calificat). Există un mic „dar” aici: acesta este un proces foarte intensiv în muncă, care necesită multă atenție și experiență practică. Prin urmare, în realitate, ei scriu în principal programe în asamblare care ar trebui să le ofere munca eficienta cu hardware. Uneori, secțiunile de program care sunt critice în ceea ce privește timpul de execuție sau consumul de memorie sunt scrise în asamblator. Ulterior, acestea sunt formalizate sub formă de subrutine și combinate cu cod într-un limbaj de nivel înalt.

Este logic să începeți să învățați limbajul de asamblare al oricărui computer numai după ce ați aflat ce parte a computerului este lăsată vizibilă și accesibilă pentru programare în acest limbaj. Acesta este așa-numitul model de program de calculator, parte din care este modelul de program cu microprocesor, care conține 32 de registre, într-o măsură sau alta, disponibile pentru utilizare de către programator.

Aceste registre pot fi împărțite în două grupuri mari:

^ 16 registre de utilizatori;

16 registre de sistem.

Programele în limbaj de asamblare folosesc registrele foarte intens. Majoritatea registrelor au un scop funcțional specific.

După cum sugerează și numele, registrele de utilizatori sunt numite registre de utilizatori, deoarece programatorul le poate folosi atunci când își scrie programele. Aceste registre includ (Fig. 3):

Opt registre pe 32 de biți care pot fi folosite de programatori pentru a stoca date și adrese (numite și registre de uz general (GPR)):

șase registre de segmente: cs, ds, ss, es, fs, gs;

registre de stare și control:

Steaguri înregistrează steaguri/steaguri;

Registrul indicatorului de comandă eip/ip.

Orez. 3. Registre de utilizator ale microprocesoarelor i486 și Pentium

De ce multe dintre aceste registre sunt afișate cu bare oblice? Nu, acestea nu sunt registre diferite - sunt părți ale unui registru mare de 32 de biți. Ele pot fi folosite în program ca obiecte separate. Acest lucru a fost făcut pentru a asigura funcționalitatea programelor scrise pentru modelele mai tinere pe 16 biți de microprocesoare Intel, începând cu i8086. Microprocesoarele i486 și Pentium au în mare parte registre pe 32 de biți. Numărul lor, cu excepția registrelor de segmente, este același cu cel al i8086, dar dimensiunea este mai mare, ceea ce se reflectă în denumirile lor - au
prefixul e (Extins).

^ Registre de uz general
Toate registrele din acest grup vă permit să accesați părțile lor „inferioare” (vezi Fig. 3). Privind această figură, rețineți că numai părțile inferioare de 16 și 8 biți ale acestor registre pot fi utilizate pentru auto-adresare. Cei 16 biți superiori ai acestor registre nu sunt disponibili ca obiecte independente. Acest lucru a fost făcut, așa cum am menționat mai sus, pentru compatibilitatea cu modelele mai tinere pe 16 biți de microprocesoare Intel.

Să enumerăm registrele care aparțin grupului de registre de uz general. Deoarece aceste registre sunt localizate fizic în microprocesor în interiorul unei unități aritmetice și logică (ALU), ele sunt numite și registre ALU:

eax/ax/ah/al (Registrul acumulatorului) - baterie.
Folosit pentru stocarea datelor intermediare. Unele comenzi necesită utilizarea acestui registru;

ebx/bx/bh/bl (Registrul de bază) - registrul de bază.
Folosit pentru a stoca adresa de bază a unui obiect în memorie;

ecx/cx/ch/cl (Registrul de contorizare) - registru de contor.
Folosit în echipe care efectuează unele acțiuni repetitive. Utilizarea sa este adesea implicită și ascunsă în algoritmul comenzii corespunzătoare.
De exemplu, comanda pentru organizarea unei bucle, pe lângă transferul controlului către o comandă situată la o anumită adresă, analizează și scade valoarea registrului ecx/cx cu una;

edx/dx/dh/dl (Registrul de date) - registrul de date.
La fel ca registrul eax/ax/ah/al, acesta stochează date intermediare. În unele comenzi utilizarea sa este obligatorie; Pentru unele comenzi acest lucru se întâmplă implicit.

Următoarele două registre sunt utilizate pentru a suporta așa-numitele operații în lanț, adică operațiuni care procesează secvenţial lanțuri de elemente, fiecare dintre acestea putând avea o lungime de 32, 16 sau 8 biți:

esi/si (Registrul Indexului Sursei) - indexul sursei.
Acest registru în operațiuni înlănțuite conține adresa curentă a elementului din lanțul sursă;

edi/di (Registrul Destination Index) - indexul receptorului (destinatarului).
Acest registru în operațiunile înlănțuite conține adresa curentă în lanțul de destinație.

În arhitectura microprocesorului, o structură de date, cum ar fi o stivă, este suportată la nivel hardware și software. Pentru a lucra cu stiva, există comenzi speciale în sistemul de instrucțiuni al microprocesorului, iar în modelul software al microprocesorului există registre speciale pentru aceasta:

esp/sp (Stack Pointer register) - registru stack pointer.
Conține un indicator către partea de sus a stivei din segmentul de stivă curent.

ebp/bp (registru indicator de bază) - registru indicator de bază de cadru de stivă.
Proiectat pentru a organiza accesul aleatoriu la date din interiorul stivei.

O stivă este o zonă de program pentru stocarea temporară a datelor arbitrare. Desigur, datele pot fi stocate și într-un segment de date, dar în acest caz, pentru fiecare dată stocată temporar, trebuie creată o celulă de memorie separată denumită, care crește dimensiunea programului și numărul de nume utilizate. Comoditatea stivei constă în faptul că zona sa este reutilizabilă, iar stocarea datelor pe stivă și preluarea lor de acolo se face folosind comenzile eficiente push și pop fără a specifica niciun nume.
Stiva este folosită în mod tradițional, de exemplu, pentru a salva conținutul registrelor utilizate de un program înainte de a apela o subrutină, care, la rândul său, va folosi registrele procesorului „în propriile scopuri”. Conținutul original al registrelor este scos din stivă după ce subrutinele revin. O altă tehnică comună este de a trece parametrii necesari unei subrutine prin intermediul stivei. Subrutina, știind în ce ordine sunt așezați parametrii pe stivă, îi poate lua de acolo și îi poate folosi în timpul execuției sale. Trăsătură distinctivă Stiva este o ordine unică în care datele conținute în ea sunt preluate: în orice moment, doar elementul de sus este disponibil pe stivă, adică. elementul împins cel mai recent pe stivă. Scoaterea elementului de sus din stivă face ca următorul element să fie disponibil. Elementele stivei sunt situate în zona de memorie alocată stivei, începând de la partea de jos a stivei (adică de la adresa sa maximă) la adrese care descresc secvențial. Adresa elementului de sus, accesibil este stocată în registrul de pointer al stivei SP. Ca orice altă zonă a memoriei programului, stiva trebuie să facă parte dintr-un anumit segment sau să formeze un segment separat. În ambele cazuri, adresa de segment a acestui segment este plasată în registrul stivă de segmente SS. Astfel, perechea de registre SS:SP descrie adresa unei celule de stivă accesibilă: SS stochează adresa de segment a stivei, iar SP stochează offset-ul ultimelor date stocate pe stivă (Fig. 4, a). Rețineți că, în starea inițială, indicatorul de stivă SP indică o celulă care se află sub partea de jos a stivei și nu este inclusă în aceasta.

Fig 4. Organizarea stivei: a - starea inițială, b - după încărcarea unui element (în acest exemplu, conținutul registrului AX), c - după încărcarea celui de-al doilea element (conținutul registrului DS), d - după descărcarea unuia element, e - după descărcarea a două elemente și revenirea la starea lor inițială.

Încărcarea în stivă se realizează printr-o comandă specială pentru lucrul cu stiva (împingere). Această instrucțiune mai întâi decrește conținutul indicatorului stivei cu 2 și apoi plasează operandul la adresa din SP. Dacă, de exemplu, dorim să stocăm temporar conținutul registrului AX pe stivă, ar trebui să rulăm comanda

Stiva intră în starea prezentată în Fig. 1.10, b. Se poate observa că pointerul stivei este deplasat în sus cu doi octeți (spre adrese inferioare) și operandul specificat în comanda push este scris la această adresă. Următoarea comandă de încărcare a stivei este de ex.

va pune stiva în starea prezentată în Fig. 1.10, c. Stiva va stoca acum două elemente și doar cel de sus, indicat de indicatorul de stivă SP, va fi accesibil. Dacă după ceva timp trebuie să restabilim conținutul original al registrelor stocate pe stivă, trebuie să executăm comenzile pop (push) pentru a descărca din stivă:

pop DS
pop AX

Cât de mare ar trebui să fie stiva? Depinde de cât de intens este folosit în program. Dacă, de exemplu, intenționați să stocați o matrice de 10.000 de octeți pe stivă, atunci stiva trebuie să aibă cel puțin această dimensiune. Trebuie avut în vedere că, în unele cazuri, stiva este utilizată automat de către sistem, în special atunci când se execută comanda int 21h de întrerupere. Cu această comandă, procesorul împinge mai întâi adresa de retur în stivă, iar apoi DOS împinge conținutul registrelor și alte informații legate de programul întrerupt în stivă. Prin urmare, chiar dacă un program nu folosește deloc o stivă, acesta trebuie să fie în continuare prezent în program și să aibă o dimensiune de cel puțin câteva zeci de cuvinte. În primul nostru exemplu, am alocat 128 de cuvinte stivei, ceea ce este cu siguranță suficient.

^ Structura unui program de asamblare

Un program în limbaj de asamblare este o colecție de blocuri de memorie numite segmente de memorie. Un program poate consta din unul sau mai multe astfel de segmente de bloc. Fiecare segment conține o colecție de propoziții de limbă, fiecare dintre acestea ocupând o linie separată de cod de program.

Există patru tipuri de instrucțiuni de asamblare:

comenzi sau instrucțiuni care sunt analogi simbolici ai comenzilor mașinii. În timpul procesului de traducere, instrucțiunile de asamblare sunt convertite în comenzile corespunzătoare ale setului de instrucțiuni ale microprocesorului;

macrocomenzi - propoziții de text de program formate într-un anumit mod, înlocuite în timpul difuzării cu alte propoziții;

directive, care sunt instrucțiuni către traducătorul de asamblare pentru a efectua anumite acțiuni. Directivele nu au corespondente în reprezentarea mașinii;

linii de comentarii care conțin orice caractere, inclusiv litere din alfabetul rus. Comentariile sunt ignorate de traducător.

^ Sintaxa de asamblare

Propozițiile care alcătuiesc un program pot fi un construct sintactic corespunzător unei comenzi, macro, directivă sau comentariu. Pentru ca traducătorul asamblator să le recunoască, ele trebuie să fie formate după anumite reguli sintactice. Pentru a face acest lucru, cel mai bine este să folosiți o descriere formală a sintaxei limbii, cum ar fi regulile gramaticale. Cele mai comune moduri de a descrie un limbaj de programare în acest fel sunt diagramele de sintaxă și formele extinse Backus-Naur. Pentru uz practic diagramele de sintaxă sunt mai convenabile. De exemplu, sintaxa instrucțiunilor limbajului de asamblare poate fi descrisă folosind diagramele de sintaxă prezentate în figurile următoare.

Orez. 5. Format de propoziție de asamblare

Orez. 6. Formatul directivei

Orez. 7. Formatul comenzilor și al macrocomenzilor

In aceste imagini:

label name - un identificator a cărui valoare este adresa primului octet al propoziției din codul sursă al programului pe care îl desemnează;

nume - un identificator care distinge această directivă de alte directive cu același nume. Ca rezultat al procesării de către asamblator a unei anumite directive, anumite caracteristici pot fi atribuite acelui nume;

un cod de operare (OPC) și o directivă sunt simboluri mnemonice pentru instrucțiunea de mașină corespunzătoare, instrucțiunea macro sau directiva translator;

operanzii sunt părți ale unei directive de comandă, macro sau asamblare care desemnează obiectele asupra cărora sunt efectuate acțiuni. Operanzii limbajului de asamblare sunt descriși prin expresii cu constante numerice și text, etichete și identificatori de variabile folosind semne de operator și unele cuvinte rezervate.

^ Cum se utilizează diagramele de sintaxă? Este foarte simplu: tot ce trebuie să faceți este să găsiți și apoi să urmați calea de la intrarea diagramei (în stânga) la ieșirea acesteia (în dreapta). Dacă o astfel de cale există, atunci propoziția sau construcția este corectă din punct de vedere sintactic. Dacă nu există o astfel de cale, atunci compilatorul nu va accepta această construcție. Când lucrați cu diagrame de sintaxă, acordați atenție direcției de parcurgere indicată de săgeți, deoarece printre căi pot exista unele care pot fi urmate de la dreapta la stânga. În esență, diagramele de sintaxă reflectă logica funcționării traducătorului atunci când parsează propozițiile de intrare ale programului.

Caracterele acceptabile atunci când scrieți textul programului sunt:

Toate scrisori: A-Z, a-z. În acest caz, literele mari și mici sunt considerate echivalente;

Numerele de la 0 la 9;

Semne ?, @, $, _, &;

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

Propozițiile în limbajul de asamblare sunt formate din lexeme, care sunt secvențe inseparabile sintactic de simboluri de limbaj valide care au sens pentru traducător.

Lexemele sunt:

identificatorii sunt secvențe de caractere valide folosite pentru a desemna obiecte de program, cum ar fi coduri de operare, nume de variabile și nume de etichete. Regula de scriere a identificatorilor este următoarea: un identificator poate consta din unul sau mai multe caractere. Ca simboluri puteți folosi litere din alfabetul latin, numere și unele caractere speciale - _, ?, $, @. Un identificator nu poate începe cu un caracter cifră. Lungimea identificatorului poate fi de până la 255 de caractere, deși traducătorul acceptă doar primele 32 și ignoră restul. Puteți ajusta lungimea identificatorilor posibili folosind opțiunea Linie de comanda mv. În plus, este posibil să instruiți traducătorul să facă distincția între litere mari și mici sau să ignore diferența dintre acestea (ceea ce se face în mod implicit).

^Comenzile asamblatorului.

Comenzile asamblatorului dezvăluie capacitatea de a vă transfera cerințele pe computer, un mecanism de transfer al controlului într-un program (cicluri și tranziții) pentru comparații logice și organizarea programului. Cu toate acestea, sarcinile programabile sunt rareori atât de simple. Majoritatea programelor conțin o serie de bucle în care se repetă mai multe comenzi până la atingerea unei anumite cerințe și diverse verificări care determină care dintre mai multe acțiuni ar trebui efectuată. Unele instrucțiuni pot transfera controlul prin modificarea secvenței normale de pași prin modificarea directă a valorii offset-ului din indicatorul de instrucțiuni. După cum am menționat mai devreme, există diferite comenzi pentru diferite procesoare, dar ne vom uita la o serie de comenzi pentru procesoarele 80186, 80286 și 80386.

Pentru a descrie starea steagurilor după executarea unei anumite comenzi, vom folosi o selecție dintr-un tabel care reflectă structura registrului de steaguri eflags:

Rândul de jos al acestui tabel arată valorile steagurilor după executarea comenzii. Se folosesc următoarele notații:

1 - după executarea comenzii, steag-ul este setat (egal cu 1);

0 - după executarea comenzii, steag-ul este resetat (egal cu 0);

r - valoarea steagului depinde de rezultatul comenzii;

După executarea comenzii, flag-ul nu este definit;

spațiu - după ce comanda este executată, steag-ul nu se schimbă;

Următoarea notație este utilizată pentru a reprezenta operanzi în diagramele de sintaxă:

r8, r16, r32 - un operand într-unul din registrele de dimensiune octet, cuvânt sau cuvânt dublu;

m8, m16, m32, m48 - dimensiunea operandului de memorie octet, cuvânt, cuvânt dublu sau 48 de biți;

i8, i16, i32 - dimensiunea operandului imediat octet, cuvânt sau cuvânt dublu;

a8, a16, a32 - adresa relativă (offset) în segmentul de cod.

Comenzi (în ordine alfabetică):

*Aceste comenzi sunt descrise în detaliu.

ADĂUGA
(Plus)

Plus

^ Diagrama comenzii:

adăugați destinație, sursă

Scop: adăugarea a doi operanzi sursă și destinație de dimensiune octet, cuvânt sau cuvânt dublu.

Algoritm de lucru:

adăugați operanzii sursă și destinație;

scrieți rezultatul adunării la receptor;

pune steaguri.

Starea steagurilor după executarea comenzii:

Aplicație:
Comanda add este folosită pentru a adăuga doi operanzi întregi. Rezultatul adunării este plasat la adresa primului operand. Dacă rezultatul adunării depășește limitele operandului receptor (se produce un depășire), atunci această situație ar trebui luată în considerare prin analiza steagului cf și posibila utilizare ulterioară a comenzii adc. De exemplu, să adăugăm valorile în registrul ax și în zona de memorie ch. Când adăugați, luați în considerare posibilitatea de depășire.

Registru plus registru sau memorie:

|000000dw|modregr/rm|

Registrul AX (AL) plus valoarea imediată:

|0000010w|--date--|date dacă w=1|

Registrul sau memoria plus valoarea imediată:

|100000sw|mod000r/m|--data--|date dacă BW=01|

APEL
(APEL)

Apelarea unei proceduri sau sarcini

^ Diagrama comenzii:

Scop:

transferarea controlului la o procedură apropiată sau îndepărtată cu stocarea adresei punctului de retur pe stivă;

comutarea sarcinilor.

Algoritm de lucru:
determinat de tipul de operand:

Near label - conținutul indicatorului de comandă eip/ip este împins pe stivă și noua valoare a adresei corespunzătoare etichetei este încărcată în același registru;

Far label - conținutul indicatorului de comandă eip/ip și cs este împins pe stivă. Apoi, noile valori de adresă corespunzătoare etichetei îndepărtate sunt încărcate în aceleași registre;

R16, 32 sau m16, 32 - definiți un registru sau o celulă de memorie care conține decalaje în segmentul de instrucțiuni curent căruia i se transferă controlul. Când controlul este transferat, conținutul indicatorului de comandă eip/ip este împins pe stivă;

Pointer de memorie - definește o locație de memorie care conține un pointer de 4 sau 6 octeți către procedura apelată. Structura unui astfel de indicator este de 2+2 sau 2+4 octeți. Interpretarea unui astfel de indicator depinde de modul de funcționare al microprocesorului:

^ Starea steagurilor după executarea comenzii (cu excepția comutării sarcinilor):

executarea comenzii nu afectează steagurile

Atunci când o sarcină este schimbată, valorile flag sunt modificate în funcție de informațiile despre registrul eflags din segmentul de stare TSS al sarcinii la care se trece.
Aplicație:
Comanda de apel vă permite să organizați un transfer flexibil și cu mai multe variante de control la o subrutină, păstrând în același timp adresa punctului de întoarcere.

Cod obiect (patru formate):

Adresare directă într-un segment:

|11101000|disp-low|diep-high|

Adresare indirectă într-un segment:

|11111111|mod010r/m|

Adresare indirectă între segmente:

|11111111|mod011r/m|

Adresare directă între segmente:

|10011010|offset-low|offset-high|seg-low|seg-high|

CMP
(Compară operanzi)

Comparație de operanzi

^ Diagrama comenzii:

cmp operand1,operand2

Scop: compararea a doi operanzi.

Algoritm de lucru:

efectuați scăderea (operand1-operand2);

în funcție de rezultat, setați steaguri, nu schimbați operand1 și operand2 (adică nu vă amintiți rezultatul).

Aplicație:
Această comandă folosit pentru a compara doi operanzi prin scădere fără a modifica operanzii. Pe baza rezultatelor comenzii, sunt setate steaguri. Comanda cmp este utilizată cu comenzile de salt condiționat și comanda setcc setcc.

Cod obiect (trei formate):

Registru sau memorie cu registru:

|001110dw|modregr/m|

Valoare imediată cu registrul AX (AL):

|0011110w|--date--|date dacă w=1|

Valoare imediată cu registru sau memorie:

|100000sw|mod111r/m|--data--|date dacă sw=0|

DEC
(Decrementează operandul cu 1)

Scăderea unui operand cu unu

^ Diagrama comenzii:

operand dec

Scop: Scădeți valoarea unui operand din memorie sau registru cu 1.

Algoritm de lucru:
comanda scade 1 din operand. Starea steagurilor după executarea comenzii:

Aplicație:
Instrucțiunea dec este folosită pentru a decrementa valoarea unui octet, cuvânt, cuvânt dublu din memorie sau registru cu unul. Cu toate acestea, rețineți că comanda nu afectează indicatorul cf.

Înregistrare: |01001reg|

^ Registrul sau memorie: |1111111w|mod001r/m|

DIV
(DIVIDE nesemnat)

Diviziune nesemnată

Schema echipei:

div divider

Scop: Efectuați o operație de împărțire între două valori binare fără semn.

^ Algoritm de operare:
Comanda necesită doi operanzi - dividendul și divizorul. Dividendele este specificat implicit și mărimea lui depinde de mărimea divizorului, care este specificată în comanda:

dacă divizorul are dimensiunea unui octet, atunci dividendul trebuie să fie situat în registrul ax. După operație, coeficientul se pune în al și restul în ah;

dacă divizorul este un cuvânt de mărime, atunci dividendul trebuie să fie situat în perechea de registre dx:ax, cu partea de ordin inferioară a dividendului situată în ax. După operație, coeficientul se pune în ax și restul în dx;

dacă divizorul este un cuvânt dublu ca mărime, atunci dividendul trebuie să fie situat în perechea de registre edx:eax, cu partea de ordin scăzut a dividendului situată în eax. După operație, coeficientul este plasat în eax și restul în edx.

^ Starea steagurilor după executarea comenzii:

Aplicație:
Comanda efectuează o împărțire întregă a operanzilor, producând rezultatul împărțirii ca cât și restul divizării. La efectuarea unei operații de împărțire poate apărea o excepție: 0 - eroare de divizare. Această situație apare într-unul din două cazuri: divizorul este 0 sau câtul este prea mare pentru a se încadra în registrul eax/ax/al.

Cod obiect:

|1111011w|mod110r/m|

INT
(Întrerupe)

Apelarea rutinei serviciului de întrerupere

^ Diagrama comenzii:

int număr_întrerupere

Scop: apelați rutina serviciului de întrerupere cu numărul de întrerupere specificat de operandul de comandă.

^ Algoritm de operare:

împinge steaguri registrul eflags/steaguri și adresa de retur în stivă. La scrierea unei adrese de retur, se scrie mai întâi conținutul registrului de segment cs, apoi conținutul pointerului de comandă eip/ip;

resetați steaguri if și tf la zero;

transferați controlul către programul de serviciu de întrerupere cu numărul specificat. Mecanismul de transfer al controlului depinde de modul de funcționare al microprocesorului.

^ Starea steagurilor după executarea comenzii:

Aplicație:
După cum puteți vedea din sintaxă, există două forme ale acestei comenzi:

int 3 - are propriul cod de operare individual 0cch și ocupă un octet. Această împrejurare face foarte convenabil pentru utilizare în diverse programe de depanare software setarea punctelor de întrerupere prin înlocuirea primului octet al oricărei comenzi. Microprocesorul, întâmpinând o comandă cu codul de operare 0cch în succesiunea comenzilor, apelează programul de procesare a întreruperii cu vectorul numărul 3, care servește la comunicarea cu depanatorul software.

A doua formă a comenzii ocupă doi octeți, are un cod operațional de 0cdh și vă permite să inițiați un apel către o rutină de serviciu de întrerupere cu un număr vectorial în intervalul 0–255. Caracteristicile transferului de control, după cum s-a menționat, depind de modul de funcționare al microprocesorului.

Cod obiect (două formate):

Înregistrare: |01000reg|

^ Registrul sau memorie: |1111111w|mod000r/m|

J.C.C.
JCXZ/JECXZ
(Săriți dacă starea)

(Săriți dacă CX=Zero/Săriți dacă ECX=Zero)

Sari dacă condiția este îndeplinită

Salt dacă CX/ECX este zero

^ Diagrama comenzii:

eticheta jcc
eticheta jcxz
eticheta jecxz

Scop: tranziție în cadrul segmentului de comandă curent în funcție de anumite condiții.

^ Algoritm de comandă (cu excepția jcxz/jecxz):
Verificarea stării steagurilor în funcție de opcode (reflectă condiția verificată):

dacă condiția testată este adevărată, atunci mergeți la celula indicată de operand;

dacă condiția verificată este falsă, atunci transferați controlul la următoarea comandă.

Algoritm pentru comanda jcxz/jecxz:
Verificarea condiției ca conținutul registrului ecx/cx să fie egal cu zero:

dacă se verifică starea

Structura comenzilor in limbaj de asamblare Programarea la nivelul comenzilor masinii este nivelul minim la care este posibila programarea pe calculator. Sistemul de comandă al mașinii trebuie să fie suficient pentru a implementa acțiunile necesare prin emiterea de instrucțiuni către echipamentul mașinii. Fiecare instrucțiune de mașină constă din două părți: una operațională, care determină „ce trebuie să faci” și un operand, care determină obiectele de procesare, adică „ce să faci”. O instrucțiune de mașină cu microprocesor, scrisă în limbaj de asamblare, este o singură linie care are următoarea formă: etichetă comanda/operanzii directivă; comentarii Eticheta, comanda/directiva și operandul sunt separate de cel puțin un spațiu sau un caracter tabulator. Operanzii comenzii sunt separați prin virgule.

Structura de comandă a limbajului de asamblare O comandă de asamblare îi spune traducătorului ce acțiune ar trebui să efectueze microprocesorul. Directivele de asamblare sunt parametri specificați în textul programului care afectează procesul de asamblare sau proprietățile fișierului de ieșire. Operandul precizează valoarea inițială a datelor (în segmentul de date) sau elementele asupra cărora se execută acțiunea de comandă (în segmentul de cod). O instrucțiune poate avea unul sau doi operanzi sau niciun operanzi. Numărul de operanzi este implicit specificat de codul instrucțiunii. Dacă o comandă sau o directivă trebuie continuată pe linia următoare, se folosește caracterul backslash: "" . În mod implicit, asamblatorul nu face distincție între litere mari și mici atunci când scrie comenzi și directive. Exemple de directive și comenzi Count db 1 ; Nume, directivă, un operand mov eax, 0 ; Comandă, doi operanzi

Identificatorii sunt secvențe de caractere valide folosite pentru a desemna numele variabilelor și numele etichetelor. Identificatorul poate consta din unul sau mai multe dintre următoarele caractere: toate literele alfabetului latin; numere de la 0 la 9; caractere speciale: _, @, $, ? . Un punct poate fi folosit ca prim caracter al etichetei. Numele rezervate de asamblare (directive, operatori, nume de comenzi) nu pot fi folosite ca identificatori. Primul caracter al identificatorului trebuie să fie o literă sau un caracter special. Lungime maxima Identificatorul are 255 de caractere, dar traducătorul le acceptă pe primele 32 și le ignoră pe restul. Toate etichetele care sunt scrise pe o linie care nu conține o directivă de asamblare trebuie să se termine cu două puncte „:”. Eticheta, comanda (directiva) și operandul nu trebuie să înceapă de la o anumită poziție din linie. Se recomandă să le scrieți într-o coloană pentru o mai mare lizibilitate a programului.

Etichete Toate etichetele care sunt scrise pe o linie care nu conține o directivă de asamblare trebuie să se termine cu două puncte „:”. Eticheta, comanda (directiva) și operandul nu trebuie să înceapă de la o anumită poziție din linie. Se recomandă să le scrieți într-o coloană pentru o mai mare lizibilitate a programului.

Comentarii Utilizarea comentariilor într-un program îmbunătățește claritatea acestuia, mai ales acolo unde scopul unui set de comenzi este neclar. Comentariile încep pe orice linie din modulul sursă cu punct și virgulă (;). Toate caracterele din dreapta lui "; " până la sfârșitul rândului sunt un comentariu. Un comentariu poate conține orice caracter imprimabil, inclusiv spațiu. Un comentariu se poate întinde pe întreaga linie sau poate urma o comandă pe aceeași linie.

Structura programului în limbaj de asamblare Un program scris în limbaj de asamblare poate consta din mai multe părți numite module, fiecare dintre acestea putând defini unul sau mai multe segmente de date, stivă și cod. Orice program complet în limbaj de asamblare trebuie să includă un modul principal, sau principal, de la care începe execuția lui. Modulul poate conține segmente de program, date și segmente de stivă declarate folosind directive adecvate.

Modele de memorie Înainte de a declara segmente, trebuie să specificați modelul de memorie folosind o directivă. MODEL MODEL memory_model, calling_convention, OS_type, stack_parameter Modele de memorie de bază ale limbajului de asamblare: Model de memorie Adresarea codului Adresarea datelor sistem de operare Intercalarea codului și a datelor MINUS APROAPE DE MS-DOS Acceptabil MIC LÂNGĂ MS-DOS, Windows Nu MEDIUM FAR NEAR MS-DOS, Windows Nu COMPACT NEAR FAR MS-DOS, Windows Nu LARGE FAR MS-DOS, Windows Nu HUGE FAR MS-DOS, Windows Nu NEAR Windows 2000, Windows XP, Windows acceptabil FLAT NEAR NT,

Modele de memorie Modelul mic funcționează numai în aplicațiile MS-DOS pe 16 biți. În acest model, toate datele și codul sunt situate pe un segment fizic. Dimensiunea fișierului de program în acest caz nu depășește 64 KB. Modelul mic acceptă un segment de cod și un segment de date. Datele și codul sunt adresate cât mai aproape atunci când utilizați acest model. Modelul mediu acceptă mai multe segmente de cod și un segment de date, toate referințele din segmentele de cod considerate în mod implicit departe și referințele dintr-un segment de date considerate aproape. Modelul compact acceptă mai multe segmente de date care utilizează adresarea datelor departe (departe) și un segment de cod care utilizează adresarea aproape (near). Modelul mare acceptă mai multe segmente de cod și mai multe segmente de date. În mod implicit, toate referințele la cod și date sunt considerate departe. Modelul uriaș este aproape echivalent cu modelul cu memorie mare.

Modele de memorie Modelul plat presupune o configurație de program nesegmentată și este utilizat numai în sistemele de operare pe 32 de biți. Acest model este similar cu modelul mic prin faptul că datele și codul sunt situate într-un singur segment, dar este pe 32 de biți. Pentru a dezvolta un program pentru modelul plat înainte de directivă. model flat ar trebui să plaseze una dintre directivele: . 386, . 486, . 586 sau. 686. Alegerea directivei de selecție a procesorului determină setul de instrucțiuni disponibile la scrierea programelor. Litera p după directiva de selecție a procesorului înseamnă modul de funcționare protejat. Adresarea datelor și a codului este aproape, toate adresele și indicatorii fiind pe 32 de biți.

Modele de memorie. MODEL modificator memory_model, calling_convention, OS_type, stack_parameter Parametrul modificator este utilizat pentru a defini tipurile de segmente și poate lua următoarele valori: use 16 (segmentele modelului selectat sunt folosite ca pe 16 biți) use 32 (segmentele modelului selectat sunt utilizate ca pe 32 de biți). Parametrul calling_convention este folosit pentru a determina metoda de transmitere a parametrilor la apelarea unei proceduri din alte limbi, inclusiv limbaje de nivel înalt (C++, Pascal). Parametrul poate lua următoarele valori: C, BASIC, FORTRAN, PASCAL, SYSCALL, STDCALL.

Modele de memorie. MODEL modificator memory_model, calling_convention, OS_type, stack_parameter Parametrul OS_type este OS_DOS în mod implicit și activat acest moment aceasta este singura valoare acceptată pentru acest parametru. Parametrul stack_parameter este setat la: NEARSTACK (registrul SS este egal cu DS, zonele de date și stiva sunt situate în același segment fizic) FARSTACK (registrul SS nu este egal cu DS, zonele de date și stiva sunt situate în segmente fizice diferite). Valoarea implicită este NEARSTACK.

Un exemplu de program care nu face nimic. 686 P. MODEL PLAT, STDCALL. DATE. COD START: RET END START RET - comandă microprocesor. Se asigură că programul se încheie corect. Restul programului se referă la funcționarea traducătorului. . 686 P - Comenzile în mod protejat Pentium 6 (Pentium II) sunt permise. Această directivă selectează setul acceptat de instrucțiuni pentru asamblare, indicând modelul procesorului. . MODEL FLAT, stdcall - model cu memorie plată. Acest model de memorie este utilizat în sistemul de operare Windows. stdcall - convenția de apelare a procedurii utilizată.

Un exemplu de program care nu face nimic. 686 P. MODEL PLAT, STDCALL. DATE. COD START: RET END START. DATE este un segment de program care conține date. Acest program nu folosește stiva, deci segmentul. STACK lipsește. . CODE este un segment de program care conține cod. START - etichetă. END START - sfârșitul programului și un mesaj către compilator că execuția programului ar trebui să înceapă cu eticheta START. Fiecare program trebuie să conțină o directivă END pentru a marca sfârșitul cod sursa programe. Toate liniile care urmează directivei END sunt ignorate.Eticheta specificată după directiva END spune traducătorului numele modulului principal de la care începe execuția programului. Dacă programul conține un singur modul, eticheta de după directiva END poate fi omisă.

Traducători în limbaj de asamblare Traducător - program sau mijloace tehnice, care convertește un program reprezentat într-unul dintre limbajele de programare într-un program în limba țintă, numit cod obiect. Pe lângă suportul mnemonicii de instrucțiuni ale mașinii, fiecare traducător are propriul său set de directive și instrumente macro, adesea incompatibile cu orice altceva. Principalele tipuri de traducători de limbaj de asamblare: MASM (Microsoft Assembler), TASM (Borland Turbo Assembler), FASM (Flat Assembler) - un asamblator multi-pass distribuit gratuit, scris de Tomasz Gryshtar (polonez), NASM (Netwide Assembler) - un asamblator gratuit. asamblator pentru arhitectura Intel x 86, a fost creat de Simon Tatham împreună cu Julian Hall și este în prezent dezvoltat de o echipă mică de dezvoltatori de la Source. Forja. net.

Src="https://present5.com/presentation/-29367016_63610977/image-15.jpg" alt="Traducerea unui program în Microsoft Visual Studio 2005 1) Creați un proiect selectând Fișier->Nou- >Meniul proiect Și"> Трансляция программы в 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="Traducerea programului în Microsoft Visual Studio 2005 2) În arborele proiectului (View->Solution Explorer) adăuga"> Трансляция программы в Microsoft Visual Studio 2005 2) В дереве проекта (View->Solution Explorer) добавить файл, в котором будет содержаться текст программы: Source. Files->Add->New. Item.!}

Traducerea programului în Microsoft Visual Studio 2005 3) Selectați tipul de fișier Cod C++, dar specificați numele cu extensia. asm:

Traducerea programului în Microsoft Visual Studio 2005 5) Setați parametrii compilatorului. Faceți clic dreapta pe meniul Custom Build Rules din fișierul de proiect...

Traduceți programul în Microsoft Visual Studio 2005 și selectați Microsoft Macro Assembler în fereastra care apare.

Traducerea programului în Microsoft Visual Studio 2005 Verificați cu butonul din dreapta în fișierul salut. arborele de proiect asm din meniul Proprietăți și instalați General->Tool: Microsoft Macro Assembler.

Src="https://present5.com/presentation/-29367016_63610977/image-22.jpg" alt="Traducerea programului în Microsoft Visual Studio 2005 6) Compilați fișierul selectând Build->Build hello. prj."> Трансляция программы в Microsoft Visual Studio 2005 6) Откомпилировать файл, выбрав Build->Build hello. prj. 7) Запустить программу, нажав F 5 или выбрав меню Debug->Start Debugging.!}

Programarea în sistemul de operare Windows Programarea în sistemul de operare Windows se bazează pe utilizarea funcțiilor API (Interfața programului de aplicație, adică interfața aplicației software). Numărul lor ajunge la 2000. Programul Windows constă în mare parte din astfel de apeluri. Toate interacțiunile cu dispozitive externe iar resursele sistemului de operare apare, de regulă, prin astfel de funcții. sala de operatie sistem Windows utilizează un model de memorie plată. Adresa oricărei celule de memorie va fi determinată de conținutul unui registru de 32 de biți. Există 3 tipuri de structuri de program pentru Windows: dialog (fereastra principală este dialog), structură consolă sau fără ferestre, structură clasică (fereastră, cadru).

Apel Funcții Windows API În fișierul de ajutor, orice funcție API este prezentată ca tip nume_funcție (FA 1, FA 2, FA 3) Tip – tip valoare returnată; FAx – o listă de argumente formale în ordinea în care apar. De exemplu, int Mesaj. Casetă(HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Legendă, UINT u. Tip); Această funcție afișează o fereastră cu un mesaj și un buton de ieșire (sau butoane). Sensul parametrilor: h. Wnd este un descriptor al ferestrei în care va apărea fereastra de mesaj, lp. Text - text care va apărea în fereastră, lp. Legendă - text în titlul ferestrei, u. Tip - tip de fereastră; în special, puteți determina numărul de butoane de ieșire.

Apelarea funcțiilor Windows API int Message. Casetă(HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Legendă, UINT u. Tip); Aproape toți parametrii funcției API sunt de fapt numere întregi de 32 de biți: HWND este un număr întreg de 32 de biți, LPCTSTR este un pointer de 32 de biți către un șir, UINT este un număr întreg de 32 de biți. Sufixul „A” este adesea adăugat la numele funcției pentru a trece la versiuni mai noi ale funcției.

Apelarea funcțiilor Windows API int Message. Casetă(HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Legendă, UINT u. Tip); Când utilizați MASM, trebuie să adăugați @N N la sfârșitul numelui - numărul de octeți pe care argumentele transmise îi ocupă pe stivă. Pentru funcțiile API Win 32, acest număr poate fi definit ca numărul de argumente n înmulțit cu 4 (octeți în fiecare argument): N=4*n. Pentru a apela o funcție, utilizați instrucțiunea CALL asamblatorului. În acest caz, toate argumentele funcției îi sunt transmise prin intermediul stivei (comanda PUSH). Direcția de transmitere a argumentelor: STÂNGA LA DREAPTA - DE JOS SUS. Argumentul u va fi împins mai întâi în stivă. Tip. Apelul către funcția specificată va arăta astfel: CALL Message. Cutie. A@16

Apelarea funcțiilor Windows API int Message. Casetă(HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Legendă, UINT u. Tip); Rezultatul executării oricărei funcții API este de obicei un număr întreg care este returnat în registrul EAX. Directiva OFFSET reprezintă un „decalaj într-un segment” sau, tradus în termeni de limbaj de nivel înalt, un „indicator” la începutul unei linii. Directiva EQU, ca #define în SI, definește o constantă. Directiva EXTERN îi spune traducătorului că funcția sau identificatorul este extern acestui modul.

Exemplu de program „Salut tuturor!” . 686 P. MODEL PLAT, STDCALL. STACK 4096. DATE MB_OK EQU 0 STR 1 DB „Primul meu program”, 0 STR 2 DB „Salut tuturor!”, 0 HW DD ? Mesaj EXTERN. Cutie. A@16: APROAPE. COD START: PUSH MB_OK PUSH OFFSET STR 1 PUSH OFFSET STR 2 PUSH HW CALL Mesaj. Cutie. A@16 RET END START

Directiva INVOKE Translatorul limbajului MASM vă permite, de asemenea, să simplificați apelurile de funcții folosind un instrument macro - directiva INVOKE: funcția INVOKE, parametrul1, parametrul2, ... Nu este nevoie să adăugați @16 la apelul de funcție; parametrii se scriu exact în ordinea în care sunt dați în descrierea funcției. Prin mijloace macro ale translatorului, parametrii sunt plasați pe stivă. Pentru a utiliza directiva INVOKE, trebuie să aveți o descriere a prototipului funcției folosind directiva PROTO sub forma: Mesaj. Cutie. A PROTO: DWORD, : DWORD Dacă un program folosește multe funcții API Win 32, este recomandabil să folosiți directiva include C: masm 32includeuser 32. inc

Subiectul 2.5 Bazele programării procesoarelor

Pe măsură ce durata programului crește, devine din ce în ce mai dificil să vă amintiți codurile diferitelor operațiuni. Mnemonicii oferă o oarecare asistență în acest sens.

Se numește limbajul de codificare a comenzilor simbolice asamblator.

limbaj de asamblare este o limbă în care fiecare enunț corespunde exact unei comenzi de mașină.

Asamblare numită convertirea unui program din limbajul de asamblare, adică pregătirea unui program în limbajul mașinii prin înlocuirea denumirilor simbolice ale operațiilor cu coduri de mașină și adreselor simbolice cu numere absolute sau relative, precum și încorporarea programelor de bibliotecă și generarea de secvențe de instrucțiuni simbolice prin specificarea unor parametri specifici în micro-echipe. Acest program este de obicei localizat în ROM sau introdus în RAM de pe unele medii externe.

Limbajul de asamblare are mai multe caracteristici care îl deosebesc de limbajele de nivel înalt:

1. Aceasta este o corespondență unu-la-unu între instrucțiunile limbajului de asamblare și instrucțiunile mașinii.

2. Un programator în limbaj de asamblare are acces la toate obiectele și instrucțiunile prezente pe mașina țintă.

Înțelegerea elementelor de bază ale programării în limbaje orientate pe mașină este utilă pentru:



O mai bună înțelegere a arhitecturii PC-ului și o utilizare mai competentă a computerelor;

Dezvoltarea unor structuri mai raționale de algoritmi pentru programe de rezolvare a problemelor aplicate;

Posibilitatea de a vizualiza și corecta programe executabile cu extensia .exe și .com, compilate din orice limbaj de nivel înalt, în caz de pierdere a programelor sursă (prin apelarea programelor specificate în depanatorul programului DEBUG și decompilarea afișajului lor în asamblare limba);

Compilarea de programe pentru rezolvarea celor mai critice probleme (un program scris într-un limbaj orientat către mașină este de obicei mai eficient - mai scurt și mai rapid cu 30-60 la sută din programele obținute ca urmare a traducerii din limbi de nivel înalt)

Să implementeze procedurile incluse în programul principal sub formă de fragmente separate în cazul în care acestea nu pot fi implementate nici în limbajul de nivel înalt folosit, nici folosind procedurile de service OS.

Un program în limbaj de asamblare poate rula doar pe o singură familie de computere, în timp ce un program scris într-un limbaj de nivel înalt poate rula pe diferite mașini.

Alfabetul limbajului de asamblare este format din caractere ASCII.

Numerele sunt doar numere întregi. Sunt:

Numerele binare se termină cu litera B;

Numerele zecimale care se termină cu litera D;

Numerele hexazecimale se termină cu litera H.

RAM, registre, prezentarea datelor

Pentru o anumită serie de MP, se folosește un limbaj de programare individual - limbajul de asamblare.

Limbajul de asamblare ocupă o poziție intermediară între codurile de mașină și limbajele de nivel înalt. Programarea în acest limbaj este mai ușoară. Un program în limbaj de asamblare folosește mai eficient capacitățile unei anumite mașini (mai precis, un MP) decât un program într-un limbaj de nivel înalt (care este mai simplu pentru un programator decât pentru asamblator). Să ne uităm la principiile de bază ale programării în limbaje orientate spre mașină, folosind exemplul de limbaj de asamblare pentru MP KR580VM80. Se folosește o metodologie generală pentru a programa în limbaj. Tehnicile tehnice specifice pentru înregistrarea programelor sunt asociate cu caracteristicile arhitecturii și sistemului de comandă al MP țintă.

Model software sistem cu microprocesor bazat pe MP KR580VM80

Modelul software al MPS în conformitate cu figura 1

Porturi MP Memorie

S Z A.C. P C

Poza 1

Din punctul de vedere al programatorului, MP KR580VM80 are următoarele registre accesibile programului.

A– Registrul acumulator de 8 biți. Este registrul principal al parlamentarului. Orice operație efectuată într-o ALU implică plasarea unuia dintre operanzii care urmează să fie procesați în acumulator. Rezultatul unei operații în ALU este de obicei stocat în A.

B, C, D, E, H, L– registre de uz general pe 8 biți (GPR). Memoria interioară MP. Conceput pentru a stoca informațiile prelucrate, precum și rezultatele operațiunii. La procesarea cuvintelor de 16 biți, registrele formează perechi BC, DE, HL, iar registrul dublu se numește prima literă - B, D, H. Într-o pereche de registre, cel mai mare este primul registru. Registrele H și L au o proprietate specială, folosită atât pentru stocarea datelor, cât și pentru stocarea adreselor pe 16 biți ale celulelor RAM.

FL– registru de pavilion (registru de semne) registru de 8 biți în care sunt stocate cinci semne ale rezultatului efectuării operațiilor aritmetice și logice în MP. Format FL conform imaginii

Bit C (CY - carry) - carry, setat la 1 dacă a existat o carry din ordinea înaltă a octetului la efectuarea operațiilor aritmetice.

Bit P (paritate) – paritate, setat la 1 dacă numărul de biți ai rezultatului este par.

Cifra AC este un transport suplimentar, conceput pentru a stoca valoarea de transport din tetrada de ordin inferioară a rezultatului.

Bit Z (zero) – setat la 1 dacă rezultatul operației este 0.

Bit S (semn) – este setat la 1 dacă rezultatul este negativ și la 0 dacă rezultatul este pozitiv.

SP– stack pointer, un registru de 16 biți, conceput pentru a stoca adresa celulei de memorie unde a fost scris ultimul octet introdus pe stivă.

RS– contor de programe (contor de programe), un registru de 16 biți, conceput pentru a stoca adresa următoarei instrucțiuni de executat. Conținutul contorului programului este incrementat automat cu 1 imediat după preluarea următorului octet de instrucțiune.

În zona de memorie inițială a adresei 0000Н – 07FF există program de controlși programe demonstrative. Aceasta este zona ROM.

0800 – 0AFF - zona de adresă pentru înregistrarea programelor aflate în studiu. (RAM).

0В00 – 0ВВ0 - zonă de adresă pentru scrierea datelor. (RAM).

0ВВ0 – adresa de pornire a stivei. (RAM).

O stivă este o zonă special organizată de RAM destinată stocării temporare a datelor sau adreselor. Ultimul număr scris în stivă apare primul. Indicatorul de stivă stochează adresa ultimei celule de stivă în care sunt scrise informații. Când este apelată o subrutină, adresa de retur la programul principal este stocată automat pe stivă. De regulă, la începutul fiecărei subrutine, conținutul tuturor registrelor implicate în execuția acesteia este salvat pe stivă, iar la sfârșitul subrutinei acestea sunt restaurate din stivă.

Formatul datelor și structura de comandă a limbajului de asamblare

Memoria MP KR580VM80 este o matrice de cuvinte de 8 biți numite octeți.Fiecare octet are propria sa adresă de 16 biți, care determină poziția sa în secvența celulelor de memorie. MP-ul poate adresa 65536 de octeți de memorie, care pot fi conținute atât în ​​ROM, cât și în RAM.

Format de date

Datele sunt stocate în memorie ca cuvinte de 8 biți:

D7 D6 D5 D4 D3 D2 D1 D0

Bitul cel mai puțin semnificativ este bitul 0, cel mai semnificativ bit este bitul 7.

O comandă se caracterizează prin formatul său, adică numărul de biți alocați pentru ea, care sunt împărțiți octet cu octet în anumite câmpuri funcționale.

Format de comandă

Comenzile MP KR580VM80 au format de unul, doi sau trei octeți. Comenzile multibyte trebuie plasate în limbi adiacente. Formatul comenzii depinde de specificul operației efectuate.

Primul octet al comenzii conține codul operației, scris sub formă mnemonică.

Determină formatul comenzii și acțiunile care trebuie efectuate de către MP asupra datelor în timpul executării acestora, precum și metoda de adresare și poate conține, de asemenea, informații despre locația datelor.

Al doilea și al treilea octet pot conține date pentru care se efectuează operațiuni sau adrese care indică locația datelor. Datele asupra cărora sunt efectuate acțiunile se numesc operanzi.

Format de comandă pe un singur octet conform Figura 2

Figura 4

În comenzile limbajului de asamblare, codul de operare are o formă scurtă de scriere a cuvintelor în limba engleză - o notație mnemonică. Mnemotecnia (de la grecescul mnemonic - arta memorării) facilitează rememorarea comenzilor prin scopul lor funcțional.

Înainte de execuție, programul sursă este tradus folosind un program de traducere numit assembler în limbajul combinațiilor de cod - limbaj mașină, sub această formă este plasat în memoria MP-ului și este apoi folosit la executarea comenzii.


Metode de adresare

Toate codurile operanzilor (intrare și ieșire) trebuie să fie localizate undeva. Ele pot fi localizate în registrele interne ale MP (cele mai convenabile și varianta rapida). Ele pot fi amplasate în memorie de sistem(cea mai comună opțiune). În cele din urmă, acestea pot fi localizate în dispozitivele I/O (cel mai rar caz). Locația operanzilor este determinată de codul de instrucțiune. Exista metode diferite, cu care codul de instrucțiune poate determina unde să ia operandul de intrare și unde să plaseze operandul de ieșire. Aceste metode se numesc metode de adresare.

Pentru MP KR580VM80, există următoarele metode de adresare:

Direct;

Inregistreaza-te;

Indirect;

Stivuite.

Direct adresarea presupune că operandul (de intrare) este localizat în memorie imediat după codul de instrucțiune. Operandul este de obicei o constantă care trebuie trimisă undeva, adăugată la ceva etc. datele sunt conținute în al doilea sau al doilea și al treilea octet al comenzii, cu octetul mic de date situat în al doilea octet al comenzii, iar octetul înalt în al treilea octet de comandă.

Drept Adresarea (aka absolută) presupune că operandul (intrare sau ieșire) este localizat în memorie la adresa, al cărei cod este localizat în interiorul programului imediat după codul de instrucțiune. Folosit în comenzi de trei octeți.

Inregistreaza-te adresarea presupune că operandul (intrare sau ieșire) se află în registrul intern al MP. Folosit în comenzile pe un singur octet

Indirect Adresarea (implicita) presupune că registrul intern al MP conține nu operandul în sine, ci adresa sa în memorie.

Grămadă adresarea presupune că comanda nu conține o adresă. Adresarea celulelor de memorie folosind conținutul registrului SP de 16 biți (pointer de stivă).

Sistem de comandă

Sistemul de comandă MP este o listă completă de acțiuni elementare pe care MP este capabil să le efectueze. MP controlat de aceste comenzi efectuează acțiuni simple, cum ar fi operații aritmetice și logice elementare, transfer de date, compararea a două valori etc. Numărul de comenzi al MP KR580VM80 este de 78 (ținând cont de modificările 244).

Se disting următoarele grupuri de comenzi:

Transmitere de date;

Aritmetic;

Joc de inteligență;

Comenzi de salt;

Comenzi de intrare/ieșire, control și stiva.


Simboluri și abrevieri folosite la descrierea comenzilor și la compunerea programelor

Simbol Reducere
ADDR adresa pe 16 biți
DATE date pe 8 biți
DATE 16 date pe 16 biți
PORT Adresa dispozitivului I/O pe 8 biți
BYTE 2 Al doilea octet al comenzii
BYTE 3 Al treilea octet de comandă
R, R1, R2 Unul dintre registrele: A, B, C, D, E, H, L
R.P. Una dintre perechile de registre: B - precizează perechea BC; D - specifică o pereche DE; H – specifică perechea HL
RH Primul registru al perechii
R.L. Al doilea registru al perechii
Λ Înmulțirea logică
V Adăugarea logică
Adăugarea modulo doi
M O celulă de memorie a cărei adresă specifică conținutul perechii de registre HL, adică M = (HL)



Top