Contacte

Introducere în limba de asamblare. Situații speciale ale modului V86

Masma de asamblare, tasmă și vierme diferă unul în celălalt. Cu toate acestea, crearea unor programe simple pentru ele practic nu are diferențe, cu excepția adunării și la aspectul însuși.

Deci, primul nostru program de masă, tasmă și WASM, care afișează litera engleză "A" în poziția cursorului curent, adică în stânga colțul superior Ecran:

Model mic. Cod ORG 100H Start: MOV Ah, 2 Mov DL, 41H INT 21H INT 20H Start Acest text poate fi tastat în orice simplă editor de text - De exemplu, în Notepad din Windows (dar nu în cuvânt și nu într-un alt "complicat"). Cu toate acestea, recomand editorul de text "avansat" cu o iluminare de sintaxă, de exemplu, PSPAD (vezi secțiunea). Apoi salvați acest fișier cu extensie.asm, de exemplu, în dosarul Myprog. Să numim cel mai atent fișier. Deci, avem: C: \\ Myprog \\ atest.asm.

NOTĂ
Vă rugăm să rețineți că în prima echipă am înregistrat 2 în loc de 02h. Masma, Tasmul și Wasmul, ca și Emu8086, admit o asemenea "libertate". Deși puteți scrie 02h - nu vor exista erori.

Explicarea programului:

.Model mic - prima linie. Directive.Model Definește un model de memorie pentru un anumit tip de fișier. În cazul nostru, acesta este un fișier cu extensie COM, astfel încât să selectăm modelul mic, în care segmentele codului, datelor și stivei sunt combinate. Modelul mic este conceput pentru a crea fișiere de tip SOM.

.cod. - a doua linie. Prezenta directivă începe segmentul de cod.

Org 100h. - String 3. Această comandă stabilește valoarea contorului de software în 100 ore, deoarece la încărcarea fișierului som în memorie, DOS selectează primele 256 octeți la blocul de date PSP pentru primii 256 de octeți (numărul zecimal 256 egal cu hexazecimal 100h). Codul programului este situat numai după acest bloc. Toate programele care sunt compilate în fișiere COM trebuie să înceapă cu prezenta directivă.

start: mov ah, 02h - Line a 4-a. Start eticheta este situată în fața primei comenzi din program și va fi utilizată în directiva de sfârșit pentru a specifica ce comandă începe programul. Instrucțiunea MOV plasează valoarea celui de-al doilea operand în primul operand. Adică, valoarea de 02h este plasată în registrul en. Pentru ce se face? 02h este o funcție dosova care afișează un simbol pe ecran. Scriem un program pentru DOS, așa că folosim comenzile acestui lucru sistem de operare (OS). Și scriem această caracteristică (sau mai degrabă numărul său), este în registrul EN, deoarece întreruperea 21h utilizează acest registru special.

MOV DL, 41H - Linia a 5-a. Codul de simbol "A" este introdus în registrul DL. Codul "A" în conformitate cu standardul ASCII este numărul 41h.

Int 21h. - Linia a 6-a. Aceasta este cea mai mare întrerupere de 21h - o comandă care determină funcția sistemului DOS specificată în registrul EN (în exemplul nostru este o funcție de 02h). Comanda INT 21H este principalul mijloc de interacțiune a programelor de la OS.

Int 20h. - Linia a 7-a. Această întrerupere care raportează sistemul de operare cu privire la ieșirea din program și transferul de management aplicație de consolă. În cazul în care programul este deja compilat și derulat de la OS, comanda INT 20H ne va reveni la OS (de exemplu, în DOS).

Începeți sfârșitul. - linia a 8-a. Directiva finală completează programul, indicând în același timp ce etichetă ar trebui executată.

Int 3.

Apel întrerupe 3 (#bp, punct de oprire)

8086

int 3.

CD ib.

Int. imm8.

Provocarea întreruperilor imm8.

8086

int 13.

În

Apel întrerupe 4 (#, depășire) dacă eflags.h \u003d 1

8086

În

Descriere:

Echipă Int 3. Se intenționează să genereze întreruperea 3 și să descrie operația identică cu comanda INT N, cu excepția faptului că numărul de întreruperi aici nu este prezent direct în codul de operare, dar implicit stabilit egal cu 3.

Această întrerupere este destinată utilizării de către debugger, care pune o comandă specială cu un singur ton. Int 3. (Codul CCCH) în locul primei octeți de comandă sau în loc de comenzi unice.

Există oa doua modalitate de a apela această întrerupere folosind un cod de două byte Int 3 (cod CD03H). dar aceasta metoda În practică, nu se aplică, toate asambloarele X86 sunt implicite de mnemonicele implicite Int 3. Ca o comandă cu un singur ton cu codul CCC (dar acest lucru nu exclude posibilitatea programării manuale a unui byte). În plus față de mărimea codului, procesul de procesare a comenzilor unice și de două octeți este diferit. Int 3.. Întreruperea generată de o comandă unică în modul EV86 (CR4.VME \u003d 1) nu este expusă la redirecționarea cardului de redirecționare a întreruperii (așa cum este descris pentru modul 2, modul 3, modul 5) și este întotdeauna procesat de manipulatorul de moduri protejate prin descriptorul din tabelul IDT. În plus, în modul V86, verificările câmpului IOPL nu sunt verificate pentru această întrerupere și, în consecință, eroarea nu poate fi generată de eroare de eroare atunci când eflags.iopl< 3, то есть однобайтная команда не является IOPL-чувствительной .

Operațiune:

Algoritmul prezentat aici descrie nu numai comportamentul procesorului atunci când execută comanda Int 3. Întreruperea externă sau generarea unei situații speciale.

Apoi a ajuns. Modul real-adresa;

Dacă (eflags.vm \u003d 1 și eflags.iopl< 3 AND

(CR4.VME \u003d 0 sau CR4.VME \u003d 1 și IRB [N] \u003d 1)

) (* IRB [N] biți, care corespunde întreruperii n în harta redirecționării întreruperilor *)

#GP (0); (Interrupător de software INT N în modul: (1) V86 la Eflags.iopl< 3, (2) EV86 Режим 2 *)

Altfel. (* Modul protejat sau modul V86 / EV86 *)

Dacă (eflags.vm \u003d 1 și cr4.vme \u003d 1 și

(Int n) și IRB [N] \u003d 0)

Altfel goto. Mod protejat.; (* Interrupturi hardware, situații speciale; Int n Interruperi de software: (1) Mod protejat, (2) V86 cu EFLAGS.IOPL \u003d 3, (3) Modul EV86 1 sau 4 *)

Real-Adres-mod:

Dacă ((numărul de întrerupere * 4) + 3 depășește segmentul atunci când accesează tabelul vectorilor de întrerupere a IVT), apoi #GP; ;

Dacă (nu există loc pentru 6 octeți în stack), atunci #ss; ;

Eflags.if \u003d 0; (* Resetați steagul întreruperilor *)

Eflags.tf \u003d 0; (* Capcane de pavilion *)

Eflags.ac \u003d 0; (* Resetați steagul modului de control al alinierii *)

CS \u003d IVT [numărul de întrerupere * 4] .Selector;

EIP \u003d IVT [Număr de întrerupere * 4]. FFFFset și 0x0000fffh;

(* Continuarea muncii în abordarea reală ... *)

EV86-MODE: (* CR0.PE \u003d 1, EFLAGS.VM \u003d 1, CR4.VME \u003d 1, Modul EV86 este o întrerupere a programului INT N, cu IRB [N] \u003d 0 - modul 3 sau modul 5 *)

Dacă (în stiva de sarcini V86 nu există spațiu pentru 6 octeți), atunci #ss (0); ;

tempflags \u003d steaguri;

tempflags.nt \u003d 0;

Apoi eflags.if \u003d 0; (* Resetați pavilionul permisiunii întreruperii *)

tempflags.if \u003d eflags.vif;

Eflags.vif \u003d 0; (* Resetarea pavilionului virtual de întreruperi *)

Eflags.tf \u003d 0; (* Capcane de pavilion *)

Împingere (tempflags);

(* Codurile de eroare nu sunt introduse pe stivă *)

CS \u003d IVT_V86 [Numărul de întrerupere * 4] .Selectorul; (* Tabelul vectorilor de întrerupere IVT_V86 este situat la începutul spațiului de adrese al sarcinii V86 *)

EIP \u003d IVT_V86 [Număr de întrerupere * 4] .offset și 0x0000fffh; (* Registrul EIP vechi de 16 biți sunt resetate *)

(* Lucrări continue în EV86 ... *)

MOD PROTEJAT: (* CR0.PE \u003d 1, întreruperile hardware, situații speciale; int n software întrerupe în modul: (1) mod protejat, (2) v86 cu eflags.iopl \u003d 3, (3) Modul EV86 1 sau modul 4 *)

Dacă ((numărul de întrerupere * 8) + 7 nu se încadrează în interiorul IDT) TAN #GP (număr de întrerupere * 8 + 2 + ext); ;

(* În continuare, în parametrii codului de eroare, termenul +2 înseamnă setarea codului de eroare al codului de eroare și termenii + ext - mijloace setarea codului de eroare ext în conformitate cu dacă eroarea a provocat programul de întrerupere ext \u003d 0 sau extern exterior \u003d 1 *)

AR descriptorii octeți trebuie să seteze gateway-ul de întrerupere, o gateway de capcană sau o gateway de sarcină, altfel #GP (număr de întrerupere * 8 + 2 + ext);

Dacă (întreruperea software-ului sau situația specială) (* Acestea. Unul dintre cazurile INT N, INT 3, INT01, legat sau în *)

Dacă (CPL\u003e DPL Gateway)

#GP (numărul de întrerupere * 8 + 2); (* CR0.PE \u003d 1, DPL Gateway< CPL, программное прерывание *)

Poarta trebuie să fie prezentă, altfel #np (număr de întrerupere * 8 + 2 + ext);

Dacă (sarcini de gateway)

Apoi a ajuns. Task-poarta.;

Mergi la. Trap-or-in-poarta; (* Cr0.pe \u003d 1, interput sau capcana gateway *)

Capcana sau-int-poarta: (* Modul protejat sau modul V86 / EV86, capcana sau gateway-ul de întrerupere *)

Verificarea noului selector CS specificat în descriptorul gateway-ului și descriptorul corespunzător de la LDT sau GDT:

Selectorul nu trebuie să fie zero, altfel, #GP (ext);

Indicele selectorului trebuie să cadă în tabelul descriptorilor, altfel #gp (selector + ext);

Mânerul selectat trebuie să fie un cod descriptor al segmentului, altfel #gp (selector + ext);

Segmentul trebuie să fie prezent (p \u003d 1), altfel #np (selector + ext);

Dacă (segmentul de cod necoordonat) și (segmentul de cod DPL< CPL)

Dacă eflags.vm \u003d 0

Apoi a ajuns. Int-to-inter-priveste; (* CR0.PE \u003d 1, EFLAGS.VM \u003d 0, întreruperea sau capcana, segmentul de cod inconsecvent, segmentul de cod DPL< CPL *)

Altceva (* eflags.vm \u003d 1 *)

Dacă (DPL al noului segment de cod ≠ 0), apoi #GP (sector de cod de selector + EXT); ;

Mergi la. In-de-v86-mod;(* CR0.PE \u003d 1, EFLAGS.VM \u003d 1, gateway-ul de întrerupere sau capcane, segmentul de cod DPL \u003d 0, CPL \u003d 3 *)

Altfel. (* CR0.PE \u003d 1, Gateway de întrerupere sau capcană, segment coerențial de cod sau segment de cod inconsistent cu DPL \u003d CPL *)

Dacă eflags.vm \u003d 1, atunci #GP (selector de cod de cod + ext); ;

Dacă ((corespunzător corespunzătoare) sau (segmentul de cod DPL \u003d CPL))

Apoi a ajuns. Int-to-intra-priveste; (* CR0.PE \u003d 1, Gateway de întrerupere sau capcană, segmentul de cod DPL ≤ CPL pentru un segment consecvent, segmentul de cod DPL \u003d CPL pentru segment inconsistent *)

Altceva #gp (selector de cod de cod + ext); (* DPL\u003e CPL pentru un segment consecvent sau DPL ≠ CPL pentru segment inconsistent *)

Int-to-Inter-Privare: (* Mod protejat, interput sau capcane, segment de cod inconsecvent, segment de cod DPL< CPL *)

Dacă (curent TSS 32-Bit)

TSSSTACKADDRESS \u003d (segmentul de cod nou DPL * 8) + 4

Dacă ((tssStackaddress + 5)\u003e limită TSS) (* (TSSSTACKADDRESS + 7)\u003e

Newss \u003d [TSS + TSSSTACKADDRESS + 4]; (* 2 bytes încărcate *)

(* 4 octeți încărcați *)

Altfel. (* Curent TSS 16-bit *)

TSSSTACKADDRESS \u003d (segmentul de cod nou DPL * 4) + 2

Dacă ((tssStackaddress + 3)\u003e limită TSS) (* (TSSSTACKADDRESS + 4)\u003e TSS Limita - pentru unele modele de procesoare *)

Apoi #ts (selector al actualului TS + EXT);

Newesp \u003d [Baza TSS + TSSSTACKADRESS]; (* 2 bytes încărcate *)

Newss \u003d [TSS + TSSSTACKADDRESS + 2 bază]; (* 2 bytes încărcate *)

Selectorul RPL trebuie să fie egal cu DPL al noului segment de cod, altfel #s (selector SS + EXT);

DPL a segmentului de stivă trebuie să fie egal cu DPL al noului segment de cod, altfel #s (Selectare SS + EXT);

Dacă (gateway-ul pe 32 de biți)

Apoi, noua stivă ar trebui să aibă loc pentru 20 de octeți (24 octeți, dacă există un cod de eroare), altfel #ss (ext)

Altfel noua stivă trebuie să aibă loc pentru 10 octeți (12 octeți, dacă există un cod de eroare), altfel #ss (ext)

SS: ESP \u003d TSS (Newss: Newessp); (* Descărcați noi valori SS și ESP de la TSS *)

Dacă (gateway-ul pe 32 de biți)

Atunci.

Altceva CS: IP \u003d Poarta (selector: offset);

Descărcați descriptorul SS în partea ascunsă a registrului SS;

Dacă (gateway-ul pe 32 de biți)

Împingeți (indicatorul lung la vechea stack - SS: ESP);

Împingeți (indicatorul lung la punctul de retur - CS: EIP); (* 3 cuvinte sunt completate la 4 *)

Împingere (cod de eroare);

Împingeți (indicatorul lung la vechea stack - SS: SP); (* 2 cuvinte *)

Apăsați (indicatorul lung la punctul de retur - CS: IP); (* 2 cuvinte *)

Împingere (cod de eroare);

CPL \u003d DPL a noului segment de cod;

Dacă (întrerupeți gateway), atunci eflags.if \u003d 0 fi; (* Resetați steagul de întrerupere *)

Eflags.rf \u003d 0;

(* Continuarea lucrărilor în modul protejat la un nivel cu privilegii mari ... *)

In-de-v86-mod: (* V86 / EV86, întreruperea sau capcana, DPL \u003d 0, CPL \u003d 3 *)

(* TSS curent este întotdeauna pe 32 de biți în modul V86 *)

Dacă (limita TSS< 9) (* Limita TSS< 11 - для некоторых моделей процессоров *)

Apoi #ts (selector al actualului TS + EXT);

Newss \u003d [Base TSS + 8]; (* 2 bytes încărcate *)

Newesp \u003d [Base TSS + 4]; (* 4 octeți încărcați *)

Verificați selectorul noului segment de stivă al Descriptorului Newss și al LDT sau GDT:

Selectorul nu trebuie să fie zero, altfel #ts (ext);

Indicele selectorului trebuie să cadă în tabelul descriptorului, altfel #s (selectorul SS + EXT);

Selectorul RPL ar trebui să fie zero, altfel #s (selector SS + EXT);

DPL a segmentului de stivă trebuie să fie zero, în caz contrar #s (selectorul SS + EXT);

Descriptorul trebuie să aibă un format descriptor descriptor de date permis pentru înregistrare (W \u003d 1), altfel #s (selector SS + EXT);

Segmentul trebuie să fie prezent (p \u003d 1), altfel #ss (selectorul SS + EXT);

Dacă (gateway-ul pe 32 de biți)

Noul stivă ar trebui să aibă loc pentru 36 de octeți (40 octeți, dacă există un cod de eroare), altfel #ss (ext)

Noul indicator al instrucțiunii ar trebui să se încadreze în noul segment de cod, altfel #GP (ext); (* Pointerul de instrucțiuni este determinat de valoarea câmpului offset din descriptorul gateway-ului *)

Tempesflags \u003d Eflags;

Eflags.vm \u003d 0; (* Procesorul iese din modul V86 pentru a procesa întreruperea în modul protejat *)

Dacă (interput gateway)

Apoi eflags.if \u003d 0;

Cpl \u003d 0; (* Comutați la nivelul privilegiului zero *)

SS: ESP \u003d TSS (Newss: Newessp); (* Descărcați valorile SS0 și ESP0 de la TSS *)

Împingere (gs);

Împingere (fs); (* Se extinde la două cuvinte *)

Împingere (DS); (* Se extinde la două cuvinte *)

Împingeți (ES); (* Se extinde la două cuvinte *)

Gs \u003d 0; (* Registrele segmentului sunt resetate. Este inacceptabilă pentru utilizarea ulterioară a selectorilor zero în modul Secure *)

Împingere (temps); (* Se extinde la două cuvinte *)

Împingeți (temperaturi);

Împingere (CS); (* Se extinde la două cuvinte *)

Împingere (cod de eroare); (* Dacă este prezent, 4 octeți *)

CS: EIP \u003d Poarta (selector: offset); (* Descărcați selectorul: Offset de la Descriptorul Gateway 32 de 32 de biți *)

Altceva (* gateway 16 biti *)

Noul stack trebuie să aibă loc pentru 18 octeți (20 octeți, dacă există un cod de eroare), altfel #ss (ext)

(* Salvarea într-un stack de registre pe 16 biți apare similar cu un gateway de 32 de biți *)

(* Returnul de la întreruperea cu comanda Iret Înapoi la modul V86 din segmentul pe 16 biți nu va fi posibil, deoarece steagul VM nu va fi salvat în stack și nu va fi recuperat din imaginea EFLAGS la returnarea * )

(* Continuarea lucrărilor în modul protejat la nivelul zero a privilegiilor ... *)

Int-to-intra-prived: (* CR0.PE \u003d 1, DPL \u003d CPL sau segment consecvent cu DPL ≤ CPL *)

Dacă (gateway-ul pe 32 de biți)

Apoi, noua stivă ar trebui să aibă loc pentru 12 octeți (16 octeți, dacă există un cod de eroare), altfel #ss (ext)

Altfel noul stivă ar trebui să aibă loc pentru 6 octeți (8 octeți, dacă există un cod de eroare), altfel #ss (ext)

Noul indicator al instrucțiunii ar trebui să se încadreze în noul segment de cod, altfel #GP (ext);

Dacă (gateway-ul pe 32 de biți)

Împingeți (indicatorul lung la punctul de retur); (* 3 cuvinte sunt completate la 4 *)

CS: EIP \u003d Poarta (selector: offset); (* Descărcați selectorul: Offset de la Descriptorul Gateway 32 de 32 de biți *)

Împingere (cod de eroare); (* Dacă este prezent, 4 octeți *)

Împingeți (indicatorul lung la punctul de retur); (* 2 cuvinte *)

CS: IP \u003d Poarta (selector: offset); (* Descărcați selectorul: Offset de la descriptorul gateway-ului pe 16 biți *)

Împingere (cod de eroare); (* Dacă este prezent, 2 octeți *)

Descărcați descriptorul CS în partea ascunsă a registrului CS;

Dacă (interput gateway), atunci eflags.if \u003d 0; ;

(* Continuarea lucrărilor în modul protejat fără a schimba nivelul privilegiului ... *)

Task-poarta: (* CR0.PE \u003d 1, gateway-ul de sarcini *)

Verificați selectorul TSS din gateway-ul Task Descriere:

Selectorul trebuie să seteze GDT (biți ti \u003d 0), altfel #gp (selector TSS + EXT);

Indicele selectorului trebuie să cadă în tabelul GDT, altfel #gp (selector TSS + EXT);

Verificarea descriptorului TSS corespunzător corespunzător selectorului selectat:

Descriptorul TSS trebuie să aibă un tip de TSS gratuit (Type.B \u003d 0), altfel #gp (selector TSS + EXT);

TSS trebuie să fie prezentă (p \u003d 1), altfel #np (selector TSS + EXT);

Sarcini de comutare (cu atașament) în TSS; (* Aici "cu atașamentul" înseamnă faptul că atunci când inițializând contextul unei noi sarcini va fi setat de steagul EFLAGS.NT \u003d 1, iar sarcina Selector TSS (Vechi) va fi copiată în segmentul TSS (vechi) Segment - A se vedea adresarea și multitasking-ul: înseamnă suport multisascia *)

Dacă (întrerupe este o situație specială cu cod de eroare)

Stack-ul trebuie să fie un loc pentru codul de eroare, altfel #ss (ext);

Împingere (cod de eroare);

Pointerul de instrucțiuni EIP ar trebui să cadă în segmentul CS, altfel #gp (ext);

(* Încărcarea contextului unei noi sarcini este însoțită de controale suplimentare, așa cum este descris în secțiunea Adresarea și multitasking: mijloace de suport multisadality *)

(* Continuarea muncii în contextul unei noi sarcini ... *)

Situații speciale de regim protejat:

Int 3.Dar și la primirea oricărei întreruperi externe sau a unei generații de o situație specială. Pic Ext. În codul de eroare al întreruperii externe).

  • descriptor vector (Index) de întreruperi nu se află în tabelul descriptorilor de întrerupere (IDT);
  • descriptor vector (Index) al întreruperii, nu este un descriptor de gateway capcană, un gateway de întrerupere sau un gateway de sarcină;
  • există o întrerupere a software-ului sau o situație specială software (adică unul dintre cazurile: INT N, Int 3, Int01, legat sau în) și în același timp nivelul actual de privilegiu (CPL) mai mult nivele de privilegiu(DPL) descriptor de gateway Din tabelul IDT -
  • selector de segment în prelucrarea corespunzătoare vector (Index) de a întrerupe descriptorul de gateway capcane, gateway-ul de întrerupere sau gateway-ul de sarcini este un selector zero;
  • selectarea segmentului segmentului al gateway-ului capcanei sau descriptorul de gateway de întrerupere nu se încadrează în tabelul corespunzător al descriptorilor;
  • indicele selectorului TSS din întreruperea corespunzătoare a descriptorului gateway-ului de sarcini nu se încadrează în interiorul global Descriptor Tabel (GDT);
  • descriptor Noul segment de cod nu este un descriptor de segmente de cod;
  • (DPL) segment coordonat nou coordonat privilege de nivel curent (CPL) sarcini -
  • nivelul de privilegii Descriptor (DPL) a noului segment de cod inconsistent nu este egal nivelul actual de privilegiu (CPL) sarcini -
  • selector TSS din întreruperea corespunzătoare a descriptorului gateway-ului de sarcini indică descriptorii de tabele locale (LDT);
  • descriptorul TSS al noii sarcini este marcat ca ocupat- Type.B ≠ 1.
  • adresa pe care trebuie citită noua valoare stivă pointer. (SS: ESP), depășește segmentul TSS;
  • selecția noului segment de stivă este un selector zero;
  • indicele selector al noului segment de stivă nu se încadrează în tabelul corespunzător al descriptorilor;
  • nivelul solicitat de privilegii (Rpl) selecția noului segment de stivă nu este egală (DPL) segment de cod nou -
  • nivelul de privilegii Descriptor (DPL) a noului segment de stivă nu este egal nivelul de privilegii Descriptor (DPL) segment de cod nou -
  • noul segment de stivă nu este un segment de date disponibil pentru înregistrare -
  • întreruperea corespunzătoare descriptorului de gateway, gateway-ul de întrerupere, gateway-ul de sarcină sau descriptorul TSS este marcat ca neînsoţit (Descriptorul bitului P este resetat);
  • noul segment de cod nu este prezent (bit P. Descriptorul segmentului este resetat).
  • când scrieți la stivă (inclusiv într-un nou stivă, dacă valorile de comutare) adrese de întoarcere, stivă pointer., steaguri sau codul de eroare este potrivit pentru marginea admisibilă a segmentului de stivă;
  • noul segment de stivă nu este prezent (descriptorul segmentului B Bit P este resetat).

Situații speciale de regim real:

Lista situațiilor speciale prezentate aici caracterizează comportamentul procesorului nu numai atunci când execută comanda Int 3.Dar și la primirea oricărei întreruperi externe sau a unei generații de o situație specială.

Situații speciale ale modului V86:

Lista situațiilor speciale prezentate aici caracterizează comportamentul procesorului nu numai atunci când execută comanda Int 3.Dar și la primirea oricărei întreruperi externe sau a unei generații de o situație specială. Pic Ext. În codul de eroare, acesta este utilizat pentru a indica externă cu privire la programul de evenimente întrerupte (

Toate funcțiile DOS sunt numite prin întreruperea 21h (în notația zecimală 33). Prima versiune a DOS conține 42 de funcții. În cea de-a doua, sunt adăugate 33 de funcții, care sunt stocate în toate versiunile ulterioare. Alegerea unei funcții specifice se efectuează prin înregistrarea numărului corespunzător în registrul AH.

Funcția 02: Ieșire Simbol unic pe ecran

Pentru a scoate un caracter pe ecranul PC utilizat

21h Funcția de întrerupere 02:

mOV DL,<код выводимого символа>

Simbolul de ieșire este evidențiat în poziția cursorului (indiferent de ce este înregistrat), după care cursorul se deplasează într-o poziție spre dreapta. Dacă cursorul a fost la capătul șirului de ecran, atunci se deplasează la începutul liniei următoare și dacă cursorul a fost la sfârșitul ultimei linii a ecranului, conținutul ecranului schimbă o linie în sus și goală Șirul apare în partea de jos și cursorul este instalat.

Simbolurile cu coduri 7, 8, 9, 10 (0AH) și 13 (0HDH) sunt efectuate într-un mod special. Simbolul cu codul 7 (clopotul, apelul) de pe ecran nu este evidențiat (și cursorul nu se schimbă) și cauzează semnal sonor. Simbolul cu codul 8 (backspase, pas înapoi) returnează cursorul la o poziție spre stânga, cu excepția cazului în care a fost în linia stângă a șirului. Simbolul cu codul 9 (fila, fila) deplasează cursorul spre dreapta până la cea mai apropiată poziție 8. Simbolul cu codul 10 (hrana de linie, traducerea liniei) deplasează cursorul la șirul liniei următoare, lăsând-o în același coloană. Simbolul cu codul 13 (Carrige Returne, întoarcerea transportului) stabilește cursorul la începutul liniei curente; Concluzie la un rând de caractere cu coduri 13 și 10 înseamnă traducerea unui cursor la începutul liniei următoare.

Funcția 9: afișați un șir pe ecranul afișajului

Pentru a afișa șirul (secvențe de simboluri), puteți utiliza, desigur, funcția 02, dar se poate face într-o singură recepție folosind o funcție de întrerupere de 21h 09:

DS: DX: \u003d Adresa rândului de pornire

Înainte de a se referi la această funcție, numărul segmentului de memorie trebuie plasat în registrul DS, în care este localizată linia de ieșire și în registrul DX - rândul de compensare în interiorul acestui segment. În același timp, la sfârșitul liniei ar trebui să existe un simbol $ (cod 24h), care servește ca un semn al sfârșitului liniei și nu este afișat.

Deși această caracteristică ar putea fi mult mai convenabil pentru funcții Ieșire preluată pe ecran (funcția 2 și 6), are dezavantajul că un simbol complet obișnuit este folosit ca limitator de șir. Aceasta este o altă compatibilitate a produselor laterale cu CP / M.

Sistemul avansat de operare DOS funcționează ca limitator de coarde Utilizați CHR $ (0). Acest lucru este conform cu acordurile adoptate în sistemul de operare Unix și limba de programare SI.

Nu există nici un fel de funcții DOS care afișează numere. O astfel de operațiune, dacă este necesar, trebuie pusă în aplicare pe baza funcțiilor considerate.

Funcția 4CH: Finalizarea programului

După finalizarea tuturor acțiunilor sale, programul este obligat să returneze gestionarea sistemului de operare, astfel încât utilizatorul să poată continua să lucreze pe PC. O astfel de restituire este implementată de funcția de întrerupere de 21h, care este plasată la sfârșitul programului:

mOV AL,<код завершения>

Fiecare program, în general, este obligat să raporteze, cu succes sau nu și-a finalizat activitatea. Faptul este că orice program este apelat de la un alt program (de exemplu, din sistemul de operare) și, uneori, numit programul pentru a continua în mod corespunzător să lucreze, trebuie să știți dacă programul numit a îndeplinit sau a lucrat cu un eroare. Astfel de informații sunt transmise ca codul de finalizare a programului (un număr întreg), care ar trebui să fie zero dacă programul a funcționat corect și non-zero (care este specificat în mod specific în fiecare caz) altfel. (Puteți afla codul de completare al programului care se numește utilizând funcția de întrerupere 4DH 21h.) Acest cod va fi necesar sau nu, programul trebuie să-l dau în continuare.

Ce este asamblatorul

Asamblerul este un limbaj de programare la nivel scăzut. Pentru fiecare procesor, există un asamblator. Programarea pe asamblare Lucrați direct cu instrumentul de calculator. Textul sursă din limba de asamblare este alcătuit din comenzi (mnemonice), care, după compilare, sunt convertite în codurile de comandă a procesorului.

Dezvoltarea programelor pe asamblare este un lucru foarte greu. În loc de timpul petrecut timp, primiți un program eficient. Programele de asamblare sunt scrise când fiecare ciclu de procesor este important. La asamblare, oferiți comenzi specifice procesorului și orice gunoi suplimentar. Acest lucru este realizat printr-o viteză mare a programului dvs.

Pentru a utiliza competent asamblerul, trebuie să cunoașteți modelul de software microprocesor. Din punctul de vedere al programatorului, sistemul de microprocesor constă în:

  1. Microprocesor
  2. Memorie
  3. Dispozitive I / O.

Modelul software este bine descris în literatură.

Sintaxa de asamblare

Formatul general al șirului de program pe asamblare

<Метка>: <Оператор> <Операнды> ; <Комментарий>

Etichete. Eticheta poate consta din caractere și semne de adeziune. Etichetele sunt utilizate în operațiuni de tranziție condiționate și necondiționate.

Câmpul operatorului. Acest câmp conține o echipă mnemonică. De exemplu, Mnemonica mov.

Operand Field. Operand pot fi prezente numai dacă operatorul este prezent (câmp de operator). Operand-urile nu pot fi, și poate mai multe. Operand pot fi date pe care trebuie să le îndepliniți unele acțiuni (înainte, pliați etc.).

Câmp de comentarii. Comentariul este necesar pentru suportul verbal al programului. Tot ce se află în spatele simbolului ; Este considerat un comentariu.

Primul program din limba de asamblare

Acest articol va utiliza un asamblator pentru procesorul I80x86 și se utilizează următorul software:

  • Tasm - Borland Turbo Assembler - Compilator
  • TLINK - BORLAND TURBO LINKER - Editor de comunicații (linker)

Pentru a fi concret, tasm 2.0.

Prin tradiție, primul nostru program va retrage șirul "Bună ziua!" pe ecran.

Eșantion de fișiere.asm.

Model mic; Memorie Model.Stack 100h; Setarea dimensiunii stivei.Data; Începutul segmentului de date al programului Hellomsg DB "Bună ziua World!", 13.10, "$". Codul; Începutul segmentului de cod MOV, @ date; Trimitem adresa segmentului de date la registrul AX MOV DS, AX; Instalarea înregistrării DS la segmentul de date MOV AH; Funcția de ieșire a rândului DOS pe ecranul MOV DX, OFFSET Hellomsg; Specificăm compensarea la începutul liniei INT 21H; Afișim șirul MOV AX, 4C00H; Funcția DOS ieșire din programul INT 21H; Ieșiți de la capăt

După cum ați observat că programul este împărțit în segmente: segmentul de date, segmentul de cod și există un alt segment de stivă.

Luați în considerare totul în ordine.

Directive.Model Specifică modelul de memorie. Modelul mic este 1 segment pentru cod, 1 segment pentru date și stivă, de exemplu Datele și stiva sunt în același segment. Există și alte modele de memorie, de exemplu: mic, mediu, compact. În funcție de modelul de memorie pe care l-ați ales, segmentele programului dvs. se pot suprapune sau pot avea segmente separate în memorie.

Directive.Stack 100h stabilește dimensiunea stack-ului. Stack-ul este necesar pentru a salva informații cu recuperarea ulterioară. În special, stiva este utilizată în timpul întreruperilor. În acest caz, conținutul Registrului Steagurilor Steaguri, registrul CS și registrul IP sunt stivuite. Apoi, există un program de întrerupere și apoi este restabilit de valorile acestor registre.

  • Steagurile Steaguri Înregistrează semne care se formează după executarea comenzii procesorului.
  • CS Înregistrare (segment de cod) conține adresa segmentului de cod.
  • Înregistrarea IP (indicatorul de instrucțiuni) este un indicator de comandă. Conține adresa comenzii care trebuie completată în continuare (adresa relativă la segmentul codului CS).

Mai mult descriere detaliata Intră în cadrul unui articol simplu.

Directiva.Data determină începerea segmentului de date al programului dvs. Segmentul de date definește "variabilele" adică " Există o redundanță de memorie în conformitate cu datele necesare. Dupa.Data merge String.
Hellomsg DB "Bună ziua!", 13.10, "$"

Aici Hellomsg este un nume simbolic care se potrivește cu începutul liniei "Hello World!" (fără ghilimele). Adică, aceasta este adresa primului simbol al șirului nostru față de segmentul de date. Directiva DB (definirea octetului) definește zona de memorie disponibilă în bypass. 13.10 - Coduri de simboluri Linie nouă Și întoarcerea căruciorului, iar simbolul $ este necesar pentru funcționarea corectă a funcției DOS 09H. Deci, șirul nostru va ocupa în memoria a 15 octeți.

Directivă. Codul determină începerea segmentului de cod (segmentul CS - cod) al programului. Apoi, rândurile programului care conține mnemonicele echipelor.

Îți voi spune despre echipa mov.

mov.<приёмник>, <источник>

MOV Command - Trimite comanda. Ea transmite conținutul sursei în receptor. Transferul poate fi un registru de registru, înregistrare, registru de memorie, dar nu există memorie de memorie de transfer. Totul trece prin registrele procesorului.

Pentru a lucra cu datele, trebuie să configurați înregistrarea segmentului de date. Setarea este că înregistram adresa segmentului de date @Data în registrul DS (segmentul de date). Înregistrați direct adresa din acest registru nu este posibilă - aceasta este arhitectura, așa că folosim registrul AX. În topor, scriem o adresă de segment de cod

Și apoi trimitem conținutul înregistrării AX la Registrul DS.

După aceasta, registrul DS va conține adresa segmentului de date. Adresa DS: 0000H va conține simbolul H. Presupun că știți despre segmente și compensări.

Adresa este formată din două componente<Сегмент>:<Смещение>În cazul în care segmentul este 2 octeți și offset - 2 octeți. Se pare că 4 octeți pentru a accesa orice locație de memorie.

mov ah, 09h
MOV DX, OFFSET Hellomsg
Int 21h.

Aici suntem în registrul ah, scrieți numărul 09h - numărul celei 21 de funcții de întrerupere, care afișează un șir pe ecran.

În linia următoare, scriem adresa (jena) la începutul liniei noastre în Registrul DX.

Apoi, numim întreruperea 21h este întreruperea funcțiilor DOS. Întrerupeți - când programul executat este întrerupt și începe programul de întrerupere. Prin numărul de întrerupere, se determină adresa subrutinei DOS, care afișează șirul de caractere pe ecran.

Veți avea probabil o întrebare: De ce scriem numărul funcției 09h în registrul ah? Și de ce este compensarea la șirul scris în registrul DX?
Răspunsul este simplu: Pentru fiecare funcție, sunt definite registrele specifice care conțin date de intrare pentru această funcție. Vedeți ce registre sunt necesare funcții specifice pe care le puteți în ajutor "E.

mOV AX, 4C00H
Int 21h.

mOV AX, 4C00H - trimitem un număr de funcție în registrul AX. Funcție 4C00H - Ieșiți la program.

iNT 21H - Efectuați o întrerupere (de fapt ieși)

sfârșitul este sfârșitul programului.

După directiva de sfârșit, compilatorul ignoră totul, astfel încât să puteți scrie totul, orice :)

Dacă citiți până la sfârșit, atunci sunteți un erou!

MAIKO G.V. Asambl pentru IBM PC: - M.: "Business informează", "Sirin" 1999 - 212 p.



Ți-a plăcut articolul? Împărtășește-l