INT 3

Prerušiť hovor 3 (#BP, bod prerušenia)

8086

int 3

CD ib

INT imm8

Prerušiť hovor imm8

8086

int 13

DO

Zavolajte prerušenie 4 (#OF, pretečenie), ak EFLAGS.OF=1

8086

do

Popis:

Tím INT 3 je určený na generovanie prerušenia 3 a je identický s inštrukciou INT n v popise operácie s tým rozdielom, že číslo prerušenia tu nie je priamo prítomné v operačnom kóde, ale je implicitne nastavené na 3.

Toto prerušenie je určené na použitie debuggerom, ktorý umiestni špeciálnu jednobajtovú inštrukciu INT 3(kód CCh) namiesto prvého bajtu príkazov alebo namiesto jednobajtových príkazov.

Existuje druhý spôsob, ako zavolať toto prerušenie pomocou dvojbajtového kódu INT 3 (kód CD03h). Avšak túto metódu nepoužíva sa v praxi, všetky assemblery x86 štandardne interpretujú mnemotechnické pomôcky INT 3 ako jednobajtový príkaz s kódom CCh (to však nevylučuje možnosť manuálneho programovania dvojbajtového kódu). Okrem veľkosti kódu je rozdielne aj spracovanie jedno- a dvojbajtových príkazov. INT 3. Prerušenie generované jednobajtovou inštrukciou v režime EV86 (CR4.VME = 1) nie je presmerované mapou presmerovania prerušenia (ako je popísané pre Režim 2 , Režim 3 , Režim 5) a vždy ho spracuje obslužný program chráneného režimu cez deskriptor v tabuľke IDT. Okrem toho v režime V86 sa pre toto prerušenie nevykonávajú žiadne kontroly poľa IOPL, a preto sa pri EFLAGS.IOPL nedá vygenerovať chyba všeobecnej ochrany #GP< 3, то есть однобайтная команда не является IOPL-чувствительной .

Prevádzka:

Algoritmus tu prezentovaný popisuje nielen správanie procesora pri vykonávaní inštrukcie INT 3 externé prerušenie alebo generovanie výnimky.

POTOM CHOĎTE REŽIM REÁLNEJ ADRESY;

AK (EFLAGS.VM = 1 A EFLAGS.IOPL< 3 AND

(CR4.VME = 0 ALEBO CR4.VME = 1 A IRB[n] = 1)

) (* IRB[n] je bit zodpovedajúci prerušeniu n v mape presmerovania prerušenia *)

#GP(0); (Softvérové ​​prerušenie INT n v režime: (1) V86 na EFLAGS.IOPL< 3, (2) EV86 Режим 2 *)

ELSE (* Chránený režim alebo režim V86/EV86 *)

AK (EFLAGS.VM = 1 AND CR4.VME = 1 AND

(INT n) A IRB[n] = 0)

ELSE GOTO CHRÁNENÝ REŽIM; (* Hardvérové ​​prerušenia, výnimky; softvérové ​​prerušenia INT n v režime: (1) Chránený režim, (2) V86 s EFLAGS.IOPL = 3, (3) EV86 Režim 1 alebo Režim 4 *)

REŽIM REÁLNEJ ADRESY:

IF ((číslo prerušenia * 4) + 3 mimo segmentu pri prístupe k tabuľke vektorov prerušení IVT) THEN #GP; FI;

IF (žiadne miesto v zásobníku pre 6 bajtov) THEN #SS; FI;

EFLAGS.IF = 0; (* Resetovať príznak prerušenia *)

EFLAGS.TF = 0; (* Resetovať príznak pasce *)

EFLAGS.AC = 0; (* Resetovať príznak režimu kontroly zarovnania *)

CS = IVT[Číslo prerušenia * 4].selektor;

EIP = IVT[Číslo prerušenia * 4].offset AND 0x0000FFFFh;

(* Pokračovanie v režime skutočného adresovania... *)

EV86-MODE: (* CR0.PE = 1, EFLAGS.VM = 1, CR4.VME = 1, režim EV86 - softvérové ​​prerušenie INT n, s IRB[n] = 0 - režim 3 alebo režim 5 *)

IF (zásobník úloh V86 nemá miesto pre 6 bajtov) THEN #SS(0); FI;

tempFLAGS = VLAJKY;

tempFLAGS.NT = 0;

THEN EFLAGS.IF = 0; (* Resetovať príznak povolenia prerušenia *)

tempFLAGS.IF = EFLAGS.VIF;

EFLAGS.VIF = 0; (* Resetovať príznak virtuálneho prerušenia *)

EFLAGS.TF = 0; (* Resetovať príznak pasce *)

Push(tempFLAGS);

(* Na zásobník nie sú vložené žiadne chybové kódy *)

CS = IVT_V86[Číslo prerušenia * 4].selektor; (* Tabuľka vektorov prerušení IVT_V86 sa nachádza na začiatku adresného priestoru úloh V86 *)

EIP = IVT_V86[číslo prerušenia * 4].offset AND 0x0000FFFFh; (* horných 16 bitov registra EIP je nastavených na nulu *)

(* Pokračovanie v režime EV86 ... *)

CHRÁNENÝ REŽIM: (* CR0.PE = 1, hardvérové ​​prerušenia, výnimky; softvérové ​​prerušenie INT n v režime: (1) chránený režim, (2) V86 s EFLAGS.IOPL = 3, (3) EV86 režim 1 alebo režim 4 *)

IF ((číslo prerušenia * 8) + 7 nespadá do tabuľky IDT) THEN #GP(číslo prerušenia * 8 + 2 + EXT); FI;

(* Ďalej v parametroch chybového kódu výraz +2 znamená nastavenie bitu IDT chybového kódu a výraz +EXT znamená nastavenie bitu EXT chybového kódu v súlade s tým, či prerušenie, ktoré spôsobilo chybu, bolo softvérové EXT = 0 alebo externé EXT = 1 *)

Bajt AR deskriptora musí špecifikovať bránu prerušenia, bránu trapu alebo bránu úlohy, inak #GP(číslo prerušenia * 8 + 2 + EXT);

IF (softvérové ​​prerušenie alebo výnimka) (* t. j. jeden z prípadov INT n, INT 3, INT01, BOUND alebo INTO *)

IF (CPL > Gateway DPL)

#GP(číslo prerušenia * 8 + 2); (* CR0.PE = 1, brána DPL< CPL, программное прерывание *)

Brána musí byť prítomná inak #NP(číslo prerušenia * 8 + 2 + EXT);

IF (brána úloh)

POTOM CHOĎTE ÚLOHA-BRÁNA;

ÍSŤ DO PASCA-ALEBO-INT-BRÁNA; (* CR0.PE = 1, prerušenie alebo pasca *)

TRAP-OR-INT-GATE: (* Chránený režim alebo režim V86/EV86, brána pasce alebo prerušenia *)

Kontrola nového selektora CS špecifikovaného v deskriptore brány a jeho zodpovedajúceho deskriptora z LDT alebo GDT:

Selektor musí byť iný ako null, inak #GP(EXT);

Index selektora musí spadať do tabuľky deskriptorov, inak #GP(selektor + EXT);

Vybraný deskriptor musí byť deskriptorom segmentu kódu, inak #GP(selektor + EXT);

Segment musí byť prítomný (P = 1), inak #NP(selektor + EXT);

IF (Nekonzistentný segment kódu) AND (DPL segmentu kódu< CPL)

AK EFLAGS.VM = 0

POTOM CHOĎTE INT-TO-INTER-PRIV; (* CR0.PE = 1, EFLAGS.VM = 0, prerušenie alebo záchytná brána, nezhodný segment kódu, segment kódu DPL< CPL *)

ELSE(*EFLAGS.VM=1*)

IF (DPL nového segmentu kódu ≠ 0) THEN #GP(selektor segmentu kódu + EXT); FI;

ÍSŤ DO INT-FROM-V86-MODE;(* CR0.PE = 1, EFLAGS.VM = 1, prerušenie alebo záchytná brána, kódový segment DPL = 0, CPL = 3 *)

ELSE (* CR0.PE = 1, prerušenie alebo záchytná brána, zhodný segment kódu alebo nezhodný segment kódu s DPL = CPL *)

AK EFLAGS.VM = 1 THEN #GP(Výber segmentu kódu + EXT); FI;

IF ((vyjednaný segment kódu) ALEBO (segment kódu DPL = CPL))

POTOM CHOĎTE INT-TO-INTRA-PRIV; (* CR0.PE = 1, prerušenie alebo záchytná brána, segment kódu DPL ≤ CPL pre zhodný segment, segment kódu DPL = CPL pre nekonzistentný segment *)

ELSE #GP(Výber segmentu kódu + EXT); (* DPL > CPL pre zhodný segment alebo DPL ≠ CPL pre nezhodný segment *)

INT-TO-INTER-PRIV: (* Chránený režim, prerušenie alebo záchytná brána, nezhodný segment kódu, segment kódu DPL< CPL *)

IF (aktuálny 32-bitový TSS)

TSSstackAddress = (nový segment kódu DPL * 8) + 4

IF ((TSSstackAddress + 5) > TSS limit) (* (TSSstackAddress + 7) >

NewSS = [Základný TSS + TSSstackAddress + 4]; (*načítať 2 bajty*)

(* Načítané sú 4 bajty *)

ELSE (* Aktuálny 16-bitový TSS *)

TSSstackAddress = (nový segment kódu DPL * 4) + 2

IF ((TSSstackAddress + 3) > TSS limit) (* (TSSstackAddress + 4) > Limit TSS - pre niektoré modely procesorov *)

THEN #TS(aktuálny volič TSS + EXT);

NewESP = [Základný TSS + TSSstackAddress]; (*načítať 2 bajty*)

NewSS = [Základný TSS + TSSstackAddress + 2]; (*načítať 2 bajty*)

RPL selektora sa musí rovnať DPL nového segmentu kódu, inak #TS(selektor SS + EXT);

DPL segmentu zásobníka sa musí rovnať DPL nového segmentu kódu, inak #TS(selektor SS + EXT);

IF (32-bitová brána)

POTOM V novom zásobníku musí byť miesto pre 20 bajtov (24 bajtov, ak je tam kód chyby), inak #SS(EXT)

ELSE Nový zásobník musí mať miesto pre 10 bajtov (12 bajtov, ak je tam kód chyby), inak #SS(EXT)

SS:ESP = TSS(NewSS:NewESP); (* Stiahnite si nové hodnoty SS a eSP z TSS *)

IF (32-bitová brána)

POTOM

ELSE CS:IP = Brána(SELECTOR:OFFSET);

Nahrajte deskriptor SS do skrytej časti registra SS;

IF (32-bitová brána)

Push(Dlhý ukazovateľ na starý zásobník - SS:ESP);

Push(Dlhý ukazovateľ na návratový bod - CS:EIP); (*3 slová doplnené po 4*)

Push (kód chyby);

Push(Dlhý ukazovateľ na starý zásobník - SS:SP); (*2 slová*)

Push(Dlhý ukazovateľ na návratový bod - CS:IP); (*2 slová*)

Push (kód chyby);

CPL = DPL nového kódového segmentu;

IF (Interrupt Gateway) THEN EFLAGS.IF = 0 FI; (* Resetovať príznak prerušenia *)

EFLAGS.RF = 0;

(* Pokračovať v spustení v chránenom režime s vysokou úrovňou privilégií... *)

INT-FROM-V86-MODE: (* režim V86/EV86, prerušenie alebo záchytná brána, DPL = 0, CPL = 3 *)

(* Aktuálny TSS je vždy 32-bitový v režime V86 *)

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

THEN #TS(aktuálny volič TSS + EXT);

NewSS = [Základný TSS + 8]; (*načítať 2 bajty*)

NewESP = [Základný TSS + 4]; (* Načítané sú 4 bajty *)

Kontrola selektora nového segmentu zásobníka NewsSS a jeho zodpovedajúceho deskriptora z LDT alebo GDT:

Selektor musí byť iný ako null, inak #TS(EXT);

Index selektora musí spadať do tabuľky deskriptorov, inak #TS(selektor SS + EXT);

RPL selektora musí byť nula, inak #TS(selektor SS + EXT);

DPL segmentu zásobníka musí byť nula, inak #TS(selektor SS + EXT);

Deskriptor musí byť vo formáte zapisovateľného deskriptora dátového segmentu (W = 1), inak #TS(selektor SS + EXT);

Segment musí byť prítomný (P = 1), inak #SS(selektor SS + EXT);

IF (32-bitová brána)

Nový zásobník musí mať miesto pre 36 bajtov (40 bajtov, ak je tam kód chyby), inak #SS(EXT)

Ukazovateľ novej inštrukcie musí spadať do nového segmentu kódu, inak #GP(EXT); (* ukazovateľ inštrukcie je určený hodnotou poľa OFFSET z deskriptora brány *)

TempEflags = EFLAGS;

EFLAGS.VM = 0; (* Procesor opustí režim V86, aby spracoval prerušenie v chránenom režime *)

IF (brána prerušenia)

THEN EFLAGS.IF = 0;

CPL=0; (* Prepnúť na úroveň privilégií nula *)

SS:ESP = TSS(NewSS:NewESP); (* Načítajte hodnoty SS0 a ESP0 z TSS *)

Push(GS);

Push(FS); (*rozšíri sa na dve slová*)

Push(DS); (*rozšíri sa na dve slová*)

Push(ES); (*rozšíri sa na dve slová*)

GS = 0; (* Registre segmentov sú vynulované. Následné použitie nulových voličov v chránenom režime nie je povolené *)

Push(TempSS); (*rozšíri sa na dve slová*)

Push(TempEflags);

Push(CS); (*rozšíri sa na dve slová*)

Push (kód chyby); (* Ak sú prítomné, 4 bajty *)

CS:EIP = Brána(SELECTOR:POSUN); (* Selektor zaťaženia: posun od 32-bitovej rukoväte brány *)

ELSE (*16-bitová brána*)

Nový zásobník musí mať miesto pre 18 bajtov (20 bajtov, ak je tam kód chyby), inak #SS(EXT)

(* ukladanie 16-bitových hodnôt registra do zásobníka je podobné ako pri 32-bitovej bráne *)

(* Návrat z prerušenia s inštrukciou IRET späť do režimu V86 zo 16-bitového segmentu nebude možný, pretože príznak VM sa neuloží do zásobníka a pri návrate sa neobnoví z obrazu EFLAGS *)

(* Pokračovať v spustení v chránenom režime s nulovou úrovňou privilégií... *)

INT-TO-INTRA-PRIV: (* CR0.PE = 1, DPL = CPL alebo zhodný segment s DPL ≤ CPL *)

IF (32-bitová brána)

POTOM V novom zásobníku musí byť miesto pre 12 bajtov (16 bajtov, ak je tam kód chyby), inak #SS(EXT)

ELSE Nový zásobník musí mať miesto pre 6 bajtov (8 bajtov, ak je tam kód chyby), inak #SS(EXT)

Ukazovateľ novej inštrukcie musí spadať do nového segmentu kódu, inak #GP(EXT);

IF (32-bitová brána)

Push (Dlhý ukazovateľ na návratový bod); (*3 slová doplnené po 4*)

CS:EIP = Brána(SELECTOR:POSUN); (* Selektor zaťaženia: posun od 32-bitovej rukoväte brány *)

Push (kód chyby); (* Ak sú prítomné, 4 bajty *)

Push (Dlhý ukazovateľ na návratový bod); (*2 slová*)

CS:IP = Brána(SELECTOR:POSUN); (* Selektor zaťaženia: posun od 16-bitového deskriptora brány *)

Push (kód chyby); (* Ak sú prítomné, 2 bajty *)

Nahrajte deskriptor CS do skrytej časti registra CS;

IF (Interrupt Gateway) THEN EFLAGS.IF = 0; FI;

(* Pokračovať v spustení v chránenom režime bez zmeny úrovne privilégií... *)

TASK-GATE: (* CR0.PE = 1, brána úlohy *)

Kontrola selektora TSS z rukoväte brány úloh:

Selektor musí špecifikovať GDT (TI bit = 0), inak #GP(selektor TSS + EXT);

Index selektora musí spadať do tabuľky GDT, inak #GP(selektor TSS + EXT);

Kontrola zodpovedajúceho deskriptora TSS pre vybraný selektor:

Deskriptor TSS musí mať voľný typ TSS (TYPE.B = 0), inak #GP(selektor TSS + EXT);

Musí byť prítomný TSS (P = 1), inak #NP(selektor TSS + EXT);

SWITCH-TASKS (s prílohou) k TSS; (* tu "S vnorením" znamená skutočnosť, že keď je kontext inicializovaný Nová úloha nastaví sa príznak EFLAGS.NT = 1 a selektor TSS prerušenej (starej) úlohy sa skopíruje do poľa LINK jej segmentu TSS - pozri Adresovanie a multitasking: Podpora multitaskingu *)

IF (Prerušenie je špeciálna situácia s kódom chyby)

V zásobníku musí byť miesto pre chybový kód, inak #SS(EXT);

push (kód chyby);

Ukazovateľ inštrukcie EIP musí spadať do segmentu CS, inak #GP(EXT);

(* Načítanie nového kontextu úlohy prichádza s ďalšími kontrolami, ako je popísané v časti Adresovanie a multitasking: Podpora multitaskingu *)

(* Pokračovanie v kontexte novej úlohy... *)

Výnimky chráneného režimu:

INT 3, ale aj pri vygenerovaní akéhokoľvek externého prerušenia alebo výnimky. Trocha EXT v kóde chyby externého prerušenia).

  • deskriptor vektor(index) prerušenia nie je v tabuľke deskriptorov prerušení (IDT);
  • rukoväť zodpovedajúcu spracovávanej vektor(index) prerušenia, nie je rukoväťou brány pasce, brány prerušenia alebo brány úloh;
  • dôjde k softvérovému prerušeniu alebo softvérovej výnimke (to znamená jeden z prípadov: INT n , INT 3 , INT01, BOUND alebo INTO) a aktuálna úroveň privilégií(CPL) úloh viac úroveň privilégií(DPL) deskriptor brány z tabuľky IDT −
  • segmentový selektor v príslušnom spracovaní vektor(index) rukoväte prerušenia k bráne pasce, bráne prerušenia alebo bráne úlohy je nulový volič;
  • selektorový index segmentového deskriptora záchytnej brány alebo deskriptora prerušovacej brány nespadá do limitov zodpovedajúcej tabuľky deskriptorov;
  • Index selektora TSS z deskriptora brány úlohy zodpovedajúceho prerušeniu je mimo hraníc globálna tabuľka deskriptorov(GDT);
  • deskriptor nový segment kódu nie je deskriptorom segmentu kódu;
  • (DPL) nový dohodnutý kódový segment je väčší aktuálna úroveň privilégií(CPL) úlohy -
  • zvládnuť úroveň privilégií(DPL) nového segmentu nesprávneho kódu sa nerovná aktuálna úroveň privilégií(CPL) úlohy -
  • selektor TSS z deskriptora úlohy-brány zodpovedajúceho prerušeniu ukazuje na lokálna tabuľka deskriptorov(LDT);
  • rukoväť TSS novej úlohy je označená ako zaneprázdnený- TYP.B ≠ 1.
  • adresu, kde sa má načítať nová hodnota ukazovateľ zásobníka(SS:eSP), mimo segmentu TSS ;
  • selektor nového segmentu zásobníka je nulový selektor;
  • index selektora nového segmentu zásobníka nespadá do zodpovedajúcej tabuľky deskriptorov;
  • požadovaná úroveň privilégií(RPL) selektor nového segmentu zásobníka nie je rovný (DPL) nového segmentu kódu -
  • zvládnuť úroveň privilégií(DPL) nového segmentu zásobníka sa nerovná zvládnuť úroveň privilégií(DPL) nového segmentu kódu -
  • nový segment zásobníka nie je segmentom údajov, do ktorého je možné zapisovať -
  • zodpovedajúca rukoväť prerušenia k bráne pasce , bráne prerušenia , bráne úlohy alebo rukoväti TSS je označená ako neprítomný(bit P deskriptora je jasný);
  • nový segment kódu nie je prítomný ( bit P deskriptor segmentu sa vynuluje).
  • pri zápise do zásobníka (vrátane do nového zásobníka, ak došlo k prepnutiu zásobníka) hodnôt spiatočné adresy, ukazovateľ zásobníka, vlajky alebo chybový kód, segment zásobníka je mimo hraníc;
  • nový segment zásobníka nie je prítomný (bit P deskriptora segmentu je jasný).

Špeciálne situácie reálneho režimu adresovania:

Tu uvedený zoznam výnimiek charakterizuje správanie procesora nielen pri vykonávaní inštrukcie INT 3, ale aj pri vygenerovaní akéhokoľvek externého prerušenia alebo výnimky.

Špeciálne situácie režimu V86:

Tu uvedený zoznam výnimiek charakterizuje správanie procesora nielen pri vykonávaní inštrukcie INT 3, ale aj pri vygenerovaní akéhokoľvek externého prerušenia alebo výnimky. Trocha EXT v chybovom kóde sa používa na označenie udalosti mimo prerušeného programu (

MASM, TASM a WASM assemblery sa navzájom líšia. Vytváranie jednoduchých programov pre nich však nemá prakticky žiadne rozdiely, s výnimkou samotného zostavovania a prepojenia.

Takže náš prvý program pre MASM, TASM a WASM, ktorý vystupuje anglický list"A" na aktuálnej pozícii kurzora, teda vľavo hornom rohu obrazovka:

Model tiny .code ORG 100h začiatok: MOV AH,2 MOV DL,41h INT 21h INT 20h KONIEC začiatok textový editor- napríklad v NOTEBOOKU (Poznámkovom bloku) z WINDOWS (ale nie vo Worde a nie v inej "vychytávke"). Odporúčam však „pokročilý“ textový editor so zvýrazňovaním syntaxe ako napríklad PSPad (pozri časť ). Potom tento súbor s príponou .asm uložíme napríklad do priečinka MYPROG. Pomenujeme súbor atest. Takže máme: C:\MYPROG\atest.asm.

POZNÁMKA
Všimnite si, že v prvom príkaze sme napísali 2 namiesto 02h. MASM, TASM a WASM, podobne ako Emu8086, takéto „slobody“ umožňujú. Aj keď môžete napísať 02h - nedôjde k žiadnej chybe.

Vysvetlivky k programu:

.model maličký- 1. riadok. Direktíva .model definuje model pamäte pre konkrétny typ súboru. V našom prípade ide o súbor COM, takže si vyberieme malý model, ktorý kombinuje segmenty kódu, údajov a zásobníka. Malý model je určený na vytváranie súborov COM.

.kód- 2. riadok. Táto smernica spúšťa segment kódu.

ORG 100 hod- 3. riadok. Tento príkaz nastaví počítadlo programu na 100h, pretože pri načítavaní súboru COM do pamäte DOS pridelí prvých 256 bajtov pre dátový blok PSP ( desiatkové číslo 256 sa rovná šestnástkovej sústave 100h). Kód programu sa nachádza až za týmto blokom. Všetky programy, ktoré sa kompilujú do súborov COM, musia začínať touto direktívou.

štart: MOV AH, 02h- 4. riadok. Návestie štart je umiestnené pred prvým príkazom v programe a použije sa v direktíve END na označenie príkazu, ktorým program začína. Inštrukcia MOV umiestni hodnotu druhého operandu do prvého operandu. To znamená, že hodnota 02h je umiestnená v registri AH. Načo to je? 02h je funkcia DOS, ktorá vytlačí znak na obrazovku. Píšeme program pre DOS, takže používame jeho príkazy operačný systém(OS). A túto funkciu (alebo skôr jej číslo) zapíšeme do registra AH, pretože prerušenie 21h používa práve tento register.

MOV DL, 41h- 5. riadok. Kód znaku "A" sa zadá do registra DL. ASCII znakový kód pre "A" je číslo 41h.

INT 21h- 6. riadok. Ide o samotné prerušenie 21h - príkaz, ktorý volá systémovú funkciu DOS špecifikovanú v registri AH (v našom príklade ide o funkciu 02h). Príkaz INT 21h je hlavným prostriedkom interakcie medzi programami a OS.

INT 20h- 7. riadok. Toto je prerušenie, ktoré hovorí operačnému systému, aby ukončil program a preniesol riadenie do konzolovej aplikácie. V prípade, že je program už skompilovaný a spustený z OS, príkaz INT 20h nás vráti späť do OS (napríklad do DOSu).

KONIEC začiatok- 8. riadok. Direktíva END ukončí program a zároveň udáva, na akom návestí má začať jeho vykonávanie.

Čo je to assembler

Assembler je nízkoúrovňový programovací jazyk. Každý procesor má svoj vlastný assembler. Programovaním v assembleri priamo pracujete s hardvérom počítača. Zdrojový text jazyka symbolických inštrukcií pozostáva z inštrukcií (mnemotechniky), ktoré sa po kompilácii prevedú na kódy inštrukcií procesora.

Vývoj programov v assembleri je veľmi náročná vec. Na oplátku za strávený čas získate efektívny program. Assembler programy sa píšu vtedy, keď je dôležitý každý cyklus procesora. V assembleri dávate konkrétne príkazy procesoru a žiadne zbytočné odpadky. To zaisťuje vysokú rýchlosť vykonávania vášho programu.

Pre správne používanie assembleru je potrebné poznať programový model mikroprocesorového systému. Z pohľadu programátora sa mikroprocesorový systém skladá z:

  1. mikroprocesor
  2. Pamäť
  3. I/O zariadenia.

Programovací model je dobre opísaný v literatúre.

Syntax zostavy

Všeobecný formát programového riadku v assembleri

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

Pole štítku. Označenie môže pozostávať zo symbolov a podčiarkovníkov. Štítky sa používajú pri operáciách podmienených a nepodmienených skokov.

Pole operátora. Toto pole obsahuje mnemotechnický príkaz. Napríklad mnemotechnická pomôcka mov

Operandové pole. Operandy môžu byť prítomné iba vtedy, ak je prítomný operátor (pole operátora). Môžu existovať žiadne operandy alebo ich môže byť niekoľko. Operandy môžu byť dáta, na ktorých potrebujete vykonať nejakú akciu (odoslať, pridať atď.).

Pole komentára. Komentár je potrebný pre slovný sprievod programu. Všetko za symbolom ; považovaný za komentár.

Prvý program v assembleri

Tento článok používa assembler pre procesor i80x86 a používa nasledujúci softvér:

  • TASM - Borland Turbo Assembler - Kompilátor
  • TLINK - Borland Turbo Linker - editor odkazov (linker)

Aby som bol konkrétny, Tasm 2.0.

Tradične náš prvý program vypíše reťazec "Ahoj svet!" na obrazovku.

súbor sample.asm

Model malý; Pamäťový model.zásobník 100h ; Nastavenie veľkosti zásobníka.data ; Začiatok segmentu údajov programu HelloMsg DB "Hello World!",13,10,"$" .code ; Začiatok segmentu kódu mov ax,@DATA ; Presunúť adresu dátového segmentu do registra AX mov ds,ax ; Nastavte register DS na dátový segment mov ah,09h ; Funkcia DOS na vytlačenie reťazca na obrazovku mov dx,offset HelloMsg ; Nastavte posun na začiatok reťazca int 21h ; Výstupná struna mov ax,4C00h ; Funkcia ukončenia programu DOS int 21h ; Ukončenie programu koniec

Ako vidíte, program je rozdelený na segmenty: segment údajov, segment kódu a existuje aj segment zásobníka.

Zvážme všetko v poriadku.

Direktíva .model small špecifikuje model pamäte. Malý model je 1 segment pre kód, 1 segment pre dáta a zásobník t.j. údaje a zásobník sú v rovnakom segmente. Existujú aj iné modely pamäte, napríklad: malé, stredné, kompaktné. V závislosti od zvoleného modelu pamäte sa segmenty vášho programu môžu prekrývať alebo môžu mať v pamäti samostatné segmenty.

Direktíva .stack 100h nastavuje veľkosť zásobníka. Zásobník je potrebný na uloženie niektorých informácií s ich následnou obnovou. Najmä zásobník sa používa na prerušenia. V tomto prípade je obsah registra FLAGS, registra CS a registra IP uložený v zásobníku. Potom nasleduje spustenie programu prerušenia a potom sa obnovia hodnoty týchto registrov.

  • Register FLAGS obsahuje znaky, ktoré sú generované po vykonaní inštrukcie procesorom.
  • Register CS (Code Segment) obsahuje adresu segmentu kódu.
  • Register IP (Instruction Pointer) - ukazovateľ inštrukcie. Obsahuje adresu inštrukcie, ktorá sa má vykonať ako ďalšia (Adresa vzhľadom na segment kódu CS).

Viac Detailný popis presahuje rámec jednoduchého článku.

Direktíva .data definuje začiatok segmentu údajov vášho programu. Segment údajov definuje "premenné" t.j. existuje rezervácia pamäte pre potrebné údaje. Za .data je riadok
HelloMsg DB "Ahoj svet!",13,10,"$"

HelloMsg je symbolický názov, ktorý sa zhoduje so začiatkom reťazca "Ahoj svet!" (bez úvodzoviek). To znamená, že toto je adresa prvého znaku nášho reťazca vzhľadom na segment údajov. Direktíva DB (Define Byte) definuje bajt po byte dostupnú pamäťovú oblasť. 13,10 - znakové kódy Nový riadok a Carriage return a znak $ je potrebný na správne fungovanie funkcie DOS 09h. Takže náš reťazec bude zaberať 15 bajtov v pamäti.

Direktíva .code definuje začiatok segmentu kódu (CS - Code Segment) programu. Ďalej sú riadky programu obsahujúce mnemotechnické pomôcky príkazov.

Poďme sa rozprávať o príkaze mov.

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

Príkaz mov je príkaz na presun. Odošle obsah zdroja do cieľa. Prevody môžu byť register-register, register-pamäť, pamäť-register, ale nedochádza k prenosu pamäť-pamäť, t.j. všetko ide cez registre procesora.

Ak chcete pracovať s údajmi, musíte si nastaviť register segmentov údajov. Nastavenie spočíva v tom, že do registra DS (Data Segment) zapíšeme adresu dátového segmentu @DATA. Do tohto registra nie je možné priamo zapísať adresu - to je architektúra, preto používame register AX. V AX napíšeme adresu segmentu kódu

a následne obsah registra AX odošleme do registra DS.

Potom bude register DS obsahovať adresu začiatku segmentu údajov. Adresa DS:0000h bude obsahovať znak H. Predpokladám, že viete o segmentoch a posunoch.

Adresa sa skladá z dvoch častí.<Сегмент>:<Смещение>kde Segment je 2 bajty a offset je 2 bajty. Ukazuje sa, že 4 bajty pre prístup k akejkoľvek pamäťovej bunke.

mov ah,09h
mov dx,offset HelloMsg
medzi 21 hod

Tu zapíšeme do registra AH číslo 09h - číslo funkcie 21. prerušenia, ktoré zobrazuje riadok na obrazovke.

V ďalšom riadku napíšeme do registra DX adresu (rozpaky) na začiatok nášho riadku.

Ďalej voláme prerušenie 21h – ide o prerušenie pre funkcie DOSu. Prerušenie – keď je bežiaci program prerušený a prerušujúci program sa začne vykonávať. Číslo prerušenia určuje adresu podprogramu DOS, ktorý vytlačí na obrazovku reťazec znakov.

Pravdepodobne vás napadne otázka: Prečo zapisujeme do registra AH číslo funkcie 09h? A prečo sa offset na riadok zapisuje do DX registra?
Odpoveď je jednoduchá: pre každú funkciu sú definované špecifické registre, ktoré obsahujú vstupné dáta pre túto funkciu. Ktoré registre sú potrebné pre konkrétne funkcie, môžete vidieť v pomocníkovi „e.

movax, 4C00h
medzi 21 hod

mov ax,4C00h - odoslanie čísla funkcie do registra AX. Funkcia 4C00h - výstup z programu.

int 21h - vykonať prerušenie (skutočne ukončenie)

koniec - koniec programu.

Po direktíve end kompilátor všetko ignoruje, takže si tam môžete napísať čo chcete :)

Ak ste dočítali až do konca, ste hrdina!

Maiko G.V. Assembler pre IBM PC: - M.: "Business-Inform", "Sirin" 1999 - 212 s.