INT 3

3. hívás megszakítása (#BP, töréspont)

8086

int 3

CD ib

INT imm8

Hívás megszakítása imm8

8086

int 13

BA

A 4. megszakítás hívása (#OF, túlcsordulás), ha EFLAGS.OF=1

8086

-ba

Leírás:

Csapat INT 3 a 3. megszakítást hivatott generálni, és megegyezik a művelet leírásában szereplő INT n utasítással, azzal a különbséggel, hogy a megszakítási szám itt nincs közvetlenül a műveleti kódban, hanem implicit módon 3-ra van állítva.

Ezt a megszakítást egy speciális egybájtos utasítást elhelyező hibakereső használja INT 3(CCh kód) a parancsok első bájtja helyett vagy az egybájtos parancsok helyett.

Van egy másik módja ennek a megszakításnak az INT 3 (CD03h kód) kétbájtos kód használatával. azonban ez a módszer a gyakorlatban nem használják, alapból minden x86 assembler értelmezi a mnemonikát INT 3 egybájtos parancsként a CCh kóddal (de ez nem zárja ki a kétbájtos kód kézi programozásának lehetőségét). A kód méretén túl az egy- és kétbájtos parancsok feldolgozása is eltérő. INT 3. Az EV86 módban (CR4.VME = 1) egybájtos utasítás által generált megszakítást nem irányítja át a megszakítás átirányítási térkép (ahogyan a 2. módban, 3. módban, 5. módban leírtuk), és mindig a védett mód kezelője kezeli. egy leíró az IDT táblázatban. Ezenkívül V86 módban nem történik IOPL mezőellenőrzés ehhez a megszakításhoz, és ennek megfelelően #GP általános védelmi hiba nem generálható, amikor az EFLAGS.IOPL< 3, то есть однобайтная команда не является IOPL-чувствительной .

Művelet:

Az itt bemutatott algoritmus nem csak a processzor viselkedését írja le utasítás végrehajtása során INT 3 külső megszakítás vagy kivételgenerálás.

AKKOR GOTO VALÓS CÍM MÓD;

IF (EFLAGS.VM = 1 ÉS EFLAGS.IOPL< 3 AND

(CR4.VME = 0 VAGY CR4.VME = 1 ÉS IRB[n] = 1)

) (* IRB[n] az n megszakításnak megfelelő bit a megszakítás átirányítási leképezésben *)

#GP(0); (Szoftvermegszakítás INT n módban: (1) V86 az EFLAGS.IOPL-nél< 3, (2) EV86 Режим 2 *)

MÁS (* Védett mód vagy V86/EV86 mód *)

HA (EFLAGS.VM = 1 ÉS CR4.VME = 1 ÉS

(INT n) ÉS IRB[n] = 0)

ELSE GOTO VÉDETT MÓD; (* Hardveres megszakítások, kivételek; szoftver megszakítja az INT n-t módban: (1) Védett mód, (2) V86 EFLAGS.IOPL = 3 értékkel, (3) EV86 Mode 1 vagy Mode 4 *)

VALÓS CÍM MÓD:

IF ((Megszakítás száma * 4) + 3 szegmensen kívül az IVT megszakítási vektortáblázat elérésekor) THEN #GP; FI;

IF (Nincs hely a veremben 6 bájt számára) THEN #SS; FI;

FLAGOK.IF = 0; (* Reset Interrupt flag *)

FLAGOK.TF = 0; (* Csapdajelző visszaállítása *)

EFLAGS.AC = 0; (* Igazításvezérlő mód jelzőjének visszaállítása *)

CS = IVT[megszakítási szám * 4].választó;

EIP = IVT[megszakítási szám * 4].eltolás ÉS 0x0000FFFFh;

(* Folytatás valós címzési módban... *)

EV86-MODE: (* CR0.PE = 1, EFLAGS.VM = 1, CR4.VME = 1, EV86 mód – INT n szoftvermegszakítás, IRB[n] = 0 esetén – 3. mód vagy 5. mód *)

IF (A V86-os feladatveremben nincs hely 6 bájt számára) THEN #SS(0); FI;

tempFLAGS = FLAGS;

tempFLAGS.NT = 0;

AKKOR ZÁSZLÓK.HA = 0; (* Reset Interrupt enable flag *)

tempFLAGS.IF = EFLAGS.VIF;

EFLAGS.VIF = 0; (* Virtuális megszakításjelző visszaállítása *)

FLAGOK.TF = 0; (* Csapdajelző visszaállítása *)

Push(tempFLAGS);

(* Nincs hibakód a veremre *)

CS = IVT_V86[megszakítási szám * 4].választó; (* Az IVT_V86 megszakítási vektor tábla a V86 feladat címterének elején található *)

EIP = IVT_V86[Megszakítás száma * 4].eltolás ÉS 0x0000FFFFh; (* az EIP regiszter felső 16 bitje nullára van állítva *)

(* Folytatás EV86 módban... *)

VÉDETT MÓD: (* CR0.PE = 1, hardveres megszakítások, kivételek; szoftver megszakítja az INT n-t módban: (1) Védett mód, (2) V86 EFLAGS.IOPL = 3 értékkel, (3) EV86 Mode 1 vagy Mode 4 *)

IF ((Megszakítás száma * 8) + 7 nem esik az IDT táblába) THEN #GP(megszakítás száma * 8 + 2 + EXT); FI;

(* A továbbiakban a hibakód paramétereiben a +2 kifejezés a hibakód IDT bitjének beállítását, az +EXT kifejezés pedig a hibakód EXT bitjének beállítását jelenti aszerint, hogy a hibát okozó megszakítás szoftveres EXT volt-e = 0 vagy külső EXT = 1 * )

A leíró AR bájtjának meg kell adnia a megszakítási kaput, a trap kaput vagy a feladat kaput, ellenkező esetben #GP(megszakítási szám * 8 + 2 + EXT);

IF (szoftver megszakítás vagy kivétel) (* azaz az INT n, INT 3, INT01, BOUND vagy INTO esetek egyike *)

IF (CPL > Gateway DPL)

#GP(megszakítási szám * 8 + 2); (* CR0.PE = 1, átjáró DPL< CPL, программное прерывание *)

Ellenkező esetben az átjárónak jelen kell lennie #NP(megszakítási szám * 8 + 2 + EXT);

IF (Task Gateway)

AKKOR GOTO FELADAT-KAPU;

MENJ CSAPDA-VAGY-INT-GATE; (* CR0.PE = 1, megszakítás vagy csapdakapu *)

CSAPVA VAGY INT-GATE: (* Védett mód vagy V86/EV86 mód, csapda vagy megszakítás átjáró *)

Az átjáróleíróban megadott új CS-szelektor és a hozzá tartozó leíró ellenőrzése az LDT-ből vagy a GDT-ből:

A választónak nem nullának kell lennie, ellenkező esetben #GP(EXT);

A kiválasztó indexnek a leíró táblán belül kell lennie, ellenkező esetben #GP(selector + EXT);

A kiválasztott leírónak kódszegmens leírónak kell lennie, különben #GP(selector + EXT);

A szegmensnek jelen kell lennie (P = 1), ellenkező esetben #NP(választó + EXT);

IF (a kódszegmens inkonzisztens) ÉS (a kódszegmens DPL-je).< CPL)

IF EFLAGS.VM = 0

AKKOR GOTO INT-TO-INTER-PRIV; (* CR0.PE = 1, EFLAGS.VM = 0, megszakítás vagy csapdakapu, nem illő kódszegmens, kódszegmens DPL< CPL *)

ELSE(*EFLAGS.VM=1*)

IF (új kódszegmens DPL-je ≠ 0) THEN #GP(Kódszegmens választó + EXT); FI;

MENJ INT-FROM-V86-MODE;(* CR0.PE = 1, EFLAGS.VM = 1, megszakítás vagy csapdakapu, kódszegmens DPL = 0, CPL = 3 *)

MÁS (* CR0.PE = 1, megszakítás vagy csapdakapu, egyező kódszegmens vagy nem illő kódszegmens DPL = CPL esetén *)

IF EFLAGS.VM = 1 THEN #GP(kódszegmensválasztó + EXT); FI;

IF ((kódszegmens egyeztetve) VAGY (kódszegmens DPL = CPL))

AKKOR GOTO INT-TO-INTRA-PRIV; (* CR0.PE = 1, megszakítás vagy csapdakapu, kódszegmens DPL ≤ CPL az egyező szegmenshez, kódszegmens DPL = CPL az inkonzisztens szegmenshez *)

ELSE #GP(kódszegmensválasztó + EXT); (* DPL > CPL egyező szegmens esetén vagy DPL ≠ CPL nem egyező szegmens esetén *)

INT-TO-INTER-PRIV: (* Védett mód, megszakítás vagy csapdakapu, nem illő kódszegmens, kódszegmens DPL< CPL *)

IF (jelenlegi 32 bites TSS)

TSSstackAddress = (új kódszegmens DPL * 8) + 4

IF ((TSSstackAddress + 5) > TSS-korlát) (* (TSSstackAddress + 7) >

NewSS = [Base TSS + TSSstackAddress + 4]; (*2 bájt betöltése*)

(* 4 bájt van betöltve *)

MÁS (* Jelenlegi TSS 16 bit *)

TSSstackAddress = (új kódszegmens DPL * 4) + 2

IF ((TSSstackAddress + 3) > TSS-korlát) (* (TSSstackAddress + 4) > TSS-korlát – egyes processzormodelleknél *)

THEN #TS(aktuális TSS választó + EXT);

NewESP = [Base TSS + TSSstackAddress]; (*2 bájt betöltése*)

NewSS = [Base TSS + TSSstackAddress + 2]; (*2 bájt betöltése*)

A választó RPL-jének meg kell egyeznie az új kódszegmens DPL-jével, különben #TS(SS szelektor + EXT);

A verem szegmens DPL-jének meg kell egyeznie az új kódszegmens DPL-jével, különben #TS(SS szelektor + EXT);

IF (32 bites átjáró)

AKKOR az új veremnek 20 bájtnak kell lennie (hibakód esetén 24 bájtnak), különben #SS(EXT)

ELSE Az új veremben 10 bájtnak kell helyet biztosítania (12 bájt, ha hibakód van), különben #SS(EXT)

SS:ESP = TSS(NewSS:NewESP); (* Új SS és eSP értékek letöltése a TSS-ből *)

IF (32 bites átjáró)

AKKOR

ELSE CS:IP = Kapu(SELECTOR:OFFSET);

Töltse be az SS-leírót az SS-regiszter rejtett részébe;

IF (32 bites átjáró)

Push(Hosszú mutató a régi veremre - SS:ESP);

Push(hosszú mutató a visszatérési ponthoz - CS:EIP); (*3 szó 4-re kitöltve*)

Push(hibakód);

Push(Hosszú mutató a régi veremre - SS:SP); (*2 szó*)

Push(hosszú mutató a visszatérési ponthoz - CS:IP); (*2 szó*)

Push(hibakód);

CPL = az új kódszegmens DPL-je;

IF (megszakítási átjáró) THEN EFLAGS.IF = 0 FI; (* Reset Interrupt flag *)

EFLAGS.RF = 0;

(* Folytassa a futást védett módban magas jogosultsági szinten... *)

INT-FROM-V86-MODE: (* V86/EV86 mód, megszakítás vagy csapdakapu, DPL = 0, CPL = 3 *)

(* A jelenlegi TSS mindig 32 bites V86 módban *)

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

THEN #TS(aktuális TSS választó + EXT);

NewSS = [Base TSS + 8]; (*2 bájt betöltése*)

NewESP = [Base TSS + 4]; (* 4 bájt van betöltve *)

Az új NewSS veremszegmens választójának és a megfelelő leírójának ellenőrzése az LDT-ből vagy a GDT-ből:

A választónak nem nullának kell lennie, ellenkező esetben #TS(EXT);

A kiválasztó indexnek a leíró táblán belül kell lennie, ellenkező esetben #TS(SS szelektor + EXT);

A választó RPL értékének nullának kell lennie, ellenkező esetben #TS(SS választó + EXT);

A veremszegmens DPL-jének nullának kell lennie, ellenkező esetben #TS(SS választó + EXT);

A leírónak írható adatszegmens-leíró formátumában kell lennie (W = 1), ellenkező esetben #TS(SS szelektor + EXT);

A szegmensnek jelen kell lennie (P = 1), ellenkező esetben #SS(SS választó + EXT);

IF (32 bites átjáró)

Az új veremben 36 bájtnak kell helyet biztosítania (hibakód esetén 40 bájt), különben #SS(EXT)

Az új utasításmutatónak az új kódszegmensen belül kell lennie, ellenkező esetben #GP(EXT); (* az utasításmutatót az átjáróleíró OFFSET mezőjének értéke határozza meg *)

TempEflags = EFLAGS;

EFLAGS.VM = 0; (* A processzor kilép a V86 módból, hogy védett módban kezelje a megszakításokat *)

IF (megszakítási átjáró)

AKKOR ZÁSZLÓK.HA = 0;

CPL=0; (* Váltás nulla jogosultsági szintre *)

SS:ESP = TSS(NewSS:NewESP); (* SS0 és ESP0 értékek betöltése a TSS-ből *)

Push(GS);

Push(FS); (*két szóra bővül*)

Push(DS); (*két szóra bővül*)

Push(ES); (*két szóra bővül*)

GS = 0; (* A szegmensregiszterek nullázva vannak. A nullszelektorok utólagos használata védett módban nem megengedett *)

Push(TempSS); (*két szóra bővül*)

Push(TempEflags);

Push(CS); (*két szóra bővül*)

Push(hibakód); (* Ha van, 4 bájt *)

CS:EIP = Kapu(SELECTOR:OFFSET); (* Terhelésválasztó: eltolás a 32 bites átjáró fogantyújától *)

ELSE (*16 bites átjáró*)

Az új veremben 18 bájtnak kell helyet biztosítania (hibakód esetén 20 bájt), különben #SS(EXT)

(* a 16 bites regiszterértékek veremben való mentése hasonló a 32 bites átjáróhoz *)

(* A megszakításból IRET utasítással visszatérés V86 módba 16 bites szegmensről nem lehetséges, mivel a VM jelző nem kerül mentésre a verembe, és nem kerül visszaállításra az EFLAGS képből visszatéréskor *)

(* Folytassa a futást védett módban nulla jogosultsági szinttel... *)

INT-TO-INTRA-PRIV: (* CR0.PE = 1, DPL = CPL vagy illesztett szegmens DPL-vel ≤ CPL *)

IF (32 bites átjáró)

AKKOR az új veremben 12 bájtnak kell helyet biztosítania (16 bájt, ha hibakód van), különben #SS(EXT)

ELSE Az új veremben 6 bájtnak kell helyet biztosítania (hibakód esetén 8 bájt), különben #SS(EXT)

Az új utasításmutatónak az új kódszegmensen belül kell lennie, ellenkező esetben #GP(EXT);

IF (32 bites átjáró)

Push (hosszú mutató a visszatérési ponthoz); (*3 szó 4-re kitöltve*)

CS:EIP = Kapu(SELECTOR:OFFSET); (* Terhelésválasztó: eltolás a 32 bites átjáró fogantyújától *)

Push(hibakód); (* Ha van, 4 bájt *)

Push (hosszú mutató a visszatérési ponthoz); (*2 szó*)

CS:IP = Kapu(SELECTOR:OFFSET); (* Terhelésválasztó: eltolás a 16 bites átjáróleírótól *)

Push(hibakód); (* Ha van, 2 bájt *)

Töltse be a CS leírót a CS regiszter rejtett részébe;

IF (megszakítási átjáró) THEN EFLAGS.IF = 0; FI;

(* Folytassa a futást védett módban a jogosultsági szint megváltoztatása nélkül... *)

FELADAT-KAPU: (* CR0.PE = 1, feladatkapu *)

A TSS-választó ellenőrzése a feladatátjáró fogantyújáról:

A választónak meg kell adnia a GDT-t (TI bit = 0), különben #GP(TSS választó + EXT);

A kiválasztó indexnek a GDT táblán belül kell lennie, ellenkező esetben #GP(TSS szelektor + EXT);

A kiválasztott választóhoz tartozó megfelelő TSS-leíró ellenőrzése:

A TSS-leírónak szabad TSS-típussal kell rendelkeznie (TYPE.B = 0), ellenkező esetben #GP(TSS-szelektor + EXT);

A TSS-nek jelen kell lennie (P = 1), különben #NP(TSS választó + EXT);

VÁLTÁS-FELADATOK (melléklettel) a TSS-re; (* itt a "beágyazással" azt a tényt jelenti, hogy amikor a kontextus inicializálva van új feladat jelző EFLAGS.NT = 1 lesz beállítva, és a megszakított (régi) feladat TSS választója be lesz másolva a TSS szegmensének LINK mezőjébe – lásd Címzés és többfeladatos munkavégzés: Többfeladatos támogatás *)

IF (A megszakítás egy speciális helyzet hibakóddal)

A veremben helynek kell maradnia a hibakód számára, ellenkező esetben #SS(EXT);

push(hibakód);

Az EIP utasításmutatónak a CS szegmensen belül kell lennie, különben #GP(EXT);

(* Az új feladatkörnyezet betöltése további ellenőrzésekkel jár a Címzés és többfeladatos munkavégzés: többfeladatos támogatások című részben leírtak szerint *)

(* Folytatás az új feladat kapcsán... *)

A védett mód kivételei:

INT 3, hanem bármilyen külső megszakítás vagy kivétel generálásakor is. Bit EXT a külső megszakítási hibakódban).

  • leíró vektor a megszakítás (index) nem a megszakításleíró táblán (IDT) belül van;
  • a feldolgozás alatt állónak megfelelő fogantyú vektor(index) egy megszakítás, nem fogantyú a trap kapuhoz, megszakítási kapuhoz vagy feladatkapuhoz;
  • szoftvermegszakítás vagy szoftverkivétel történik (azaz az esetek egyike: INT n , INT 3 , INT01, BOUND vagy INTO), és jelenlegi jogosultsági szintje(CPL) feladatokat privilégium szint(DPL) átjáró leíró IDT táblázatból −
  • szegmensválasztó a megfelelő feldolgozásban vektor A csapdakapu, megszakítási kapu vagy feladatkapu megszakítási fogantyújának (index) nullszelektor;
  • a csapdakapu-leíró szegmensválasztójának vagy a megszakítási kapuleírónak az indexe nem esik a megfelelő leíró tábla korlátai közé;
  • A megszakításnak megfelelő feladatkapu-leíróból származó TSS-választó index túllép a határokon globális leíró táblázat(GDT);
  • leíró az új kódszegmens nem kódszegmens leíró;
  • (DPL) új egyeztetett kódszegmens nagyobb jelenlegi jogosultsági szintje(CPL) feladatok -
  • kezelni jogosultsági szintet Az új nem egyező kódszegmens (DPL) értéke nem egyenlő jelenlegi jogosultsági szintje(CPL) feladatok -
  • a TSS-választó a megszakításnak megfelelő feladatkapu-leíróból arra mutat helyi leíró táblázat(LDT);
  • az új feladat TSS-leírója a következővel van megjelölve elfoglalt- B TÍPUS ≠ 1.
  • az a cím, ahol az új értéket be kell olvasni veremmutató(SS:eSP), TSS szegmensen kívül ;
  • az új veremszegmens választója egy nullszelektor;
  • az új veremszegmens kiválasztó indexe nem esik a megfelelő leíró táblába;
  • kért jogosultsági szint(RPL) új verem szegmens választója nem egyenlő (DPL) egy új kódszegmenshez -
  • kezelni jogosultsági szintet(DPL) az új verem szegmens nem egyenlő kezelni jogosultsági szintet(DPL) egy új kódszegmenshez -
  • az új verem szegmens nem írható adatszegmens -
  • a megfelelő megszakítási fogantyú a csapókapuhoz , megszakítási kapuhoz , feladatkapuhoz vagy TSS fogantyúhoz van jelölve távollévő(a leíró P bitje egyértelmű);
  • nincs új kódszegmens ( bit P szegmensleíró visszaállítva).
  • amikor az értékeket a verembe írjuk (beleértve az új verembe is, ha veremváltás történt). visszaküldési címek, veremmutató, zászlókat vagy hibakód, a verem szegmens határon kívül van;
  • az új veremszegmens nincs jelen (a szegmensleíró P bitje tiszta).

A valódi címzési mód speciális helyzetei:

Az itt bemutatott kivételek listája nem csak utasítás végrehajtása során jellemzi a processzor viselkedését INT 3, hanem bármilyen külső megszakítás vagy kivétel generálásakor is.

A V86 mód különleges helyzetei:

Az itt bemutatott kivételek listája nem csak utasítás végrehajtása során jellemzi a processzor viselkedését INT 3, hanem bármilyen külső megszakítás vagy kivétel generálásakor is. Bit EXT a hibakódban a megszakított programon kívüli esemény jelzésére szolgál (

A MASM, TASM és WASM szerelők különböznek egymástól. A számukra egyszerű programok létrehozása azonban gyakorlatilag nincs különbség, kivéve magát az összeállítást és az összekapcsolást.

Tehát az első programunk a MASM, TASM és WASM számára, amely kimenet angol levél"A" a kurzor aktuális pozíciójában, azaz a bal oldalon felső sarok képernyő:

Modell apró .kód ORG 100h start: MOV AH,2 MOV DL,41h INT 21h INT 20h END start szöveg szerkesztő- például egy JEGYZETKÖZBEN (NotePad) a WINDOWS-ból (de nem Word-ben és nem egy másik "fantasztikus"-ban). Javasolok azonban egy "haladó" szövegszerkesztőt szintaktikai kiemeléssel, mint például a PSPad (lásd a részt). Ezután ezt a fájlt .asm kiterjesztéssel mentjük például a MYPROG mappába. Nevezzük el a fájlt atestnek. Így kaptuk: C:\MYPROG\atest.asm.

JEGYZET
Vegye figyelembe, hogy az első parancsban 2-t írtunk a 02h helyett. A MASM, a TASM és a WASM az Emu8086-hoz hasonlóan megengedi az ilyen "szabadságokat". Bár írhat 02h - nem lesz hiba.

Magyarázatok a programhoz:

.modell apró- 1. sor. A .model direktíva egy adott fájltípus memóriamodelljét határozza meg. Esetünkben ez egy COM fájl, ezért a pici modellt választjuk, amely kódot, adatot és veremszegmenseket kombinál. Az apró modellt COM-fájlok létrehozására tervezték.

.kód- 2. sor. Ez a direktíva elindít egy kódszegmenst.

ORG 100h- 3. sor. Ez a parancs 100h-ra állítja a programszámlálót, mivel a COM fájl memóriába való betöltésekor a DOS lefoglalja az első 256 bájtot a PSP adatblokk számára ( decimális szám 256 egyenlő hexadecimális 100 órával). A programkód csak e mondat után található. Minden COM-fájlba fordító programnak ezzel az irányelvvel kell kezdődnie.

kezdés: MOV AH, 02h- 4. sor. A start címke a program első parancsa elé kerül, és az END direktívában lesz használva annak jelzésére, hogy a program melyik paranccsal indul. A MOV utasítás a második operandus értékét az első operandusba helyezi. Azaz a 02h érték az AH regiszterbe kerül. Mire való? A 02h egy DOS-funkció, amely egy karaktert nyomtat a képernyőre. Programot írunk DOS-ra, ezért ennek parancsait használjuk operációs rendszer(OS). És ezt a függvényt (vagy inkább a számát) beírjuk az AH regiszterbe, mert a 21h megszakítás ezt a regisztert használja.

MOV DL, 41 óra- 5. sor. Az "A" karakterkód bekerül a DL regiszterbe. Az "A" ASCII karakterkódja a 41h szám.

INT 21 óra- 6. sor. Ez a 21h megszakítás – egy parancs, amely meghívja az AH regiszterben megadott DOS rendszerfüggvényt (példánkban ez a 02h függvény). Az INT 21h parancs a programok és az operációs rendszer közötti interakció fő eszköze.

INT 20 óra- 7. sor. Ez egy megszakítás, amely arra utasítja az operációs rendszert, hogy lépjen ki a programból, és adja át a vezérlést a konzolalkalmazásnak. Abban az esetben, ha a program már le lett fordítva és futott az operációs rendszerről, az INT 20h parancs visszaküld minket az operációs rendszerbe (például DOS-ba).

VÉGE start- 8. sor. Az END direktíva leállítja a programot, egyúttal jelzi, hogy melyik címkén kell megkezdenie a végrehajtást.

Mi az összeszerelő

Az Assembler egy alacsony szintű programozási nyelv. Minden processzornak saját összeszerelője van. Az assemblerben történő programozással közvetlenül a számítógép hardverével dolgozik. Az Assembly nyelvű forrásszöveg utasításokból (mnemonikákból) áll, amelyeket a fordítás után processzor utasításkódokká alakítanak át.

A programok fejlesztése assemblerben nagyon nehéz dolog. Az eltöltött idő fejében egy hatékony programot kap. Az Assembler programok akkor íródnak, amikor a processzor minden ciklusa fontos. Az assemblerben konkrét parancsokat adsz a processzornak, és nincs felesleges szemét. Ez biztosítja a program végrehajtásának nagy sebességét.

Az assembler helyes használatához ismernie kell a mikroprocesszoros rendszer programmodelljét. A programozó szempontjából a mikroprocesszoros rendszer a következőkből áll:

  1. mikroprocesszor
  2. memória
  3. I/O eszközök.

A programozási modellt a szakirodalom jól leírja.

Assembly Syntax

A programsor általános formátuma az assemblerben

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

Címke mező. A címke szimbólumokból és aláhúzásjelekből állhat. A címkéket feltételes és feltétel nélküli ugrási műveletekben használják.

Kezelői mező. Ez a mező tartalmazza a parancsmnemonikát. Például mnemonikus mov

Operandus mező. Az operandusok csak akkor lehetnek jelen, ha az Operátor (operátor mező) jelen van. Lehet, hogy nincsenek operandusok, vagy lehet több is. Az operandusok olyan adatok lehetnek, amelyeken valamilyen műveletet kell végrehajtania (küldeni, hozzáadni stb.).

Megjegyzés mező. A kommentár a műsor szóbeli kíséretéhez szükséges. Minden a szimbólum mögött ; megjegyzésnek tekintette.

Az első assembly nyelvű program

Ez a cikk az assembler programot használja az i80x86 processzorhoz, és a következő szoftvereket használja:

  • TASM - Borland Turbo Assembler - Fordító
  • TLINK - Borland Turbo Linker - linkszerkesztő (linker)

Pontosabban: Tasm 2.0.

A hagyományoknak megfelelően első programunk a "Hello world!" a képernyőre.

sample.asm fájl

Modell kicsi ; Memóriamodell.stack 100h ; A verem méretének beállítása.data ; A program adatszegmensének kezdete HelloMsg DB "Hello World!",13,10,"$" .code ; A kódszegmens eleje mov ax,@DATA ; Az adatszegmens címének áthelyezése az AX regiszterbe mov ds,ax ; DS regiszter beállítása adatszegmensre mov ah,09h ; DOS-függvény karakterlánc nyomtatásához a képernyőre mov dx,offset HelloMsg ; Állítsa az eltolást a karakterlánc elejére int 21h ; Kimeneti karakterlánc mov ax,4C00h ; DOS program kilépési funkció int 21h ; Kilépés a program végéből

Amint látható, a program szegmensekre van felosztva: adatszegmensre, kódszegmensre, és van veremszegmens is.

Vegyünk mindent sorjában.

A .model small direktíva határozza meg a memóriamodellt. A kis modell 1 szegmens a kódhoz, 1 szegmens az adatokhoz és a veremhez, azaz. adatok és verem ugyanabban a szegmensben vannak. Vannak más memóriamodellek is, például: pici, közepes, kompakt. A választott memóriamodelltől függően a program szegmensei átfedhetik egymást, vagy különálló szegmenseket tartalmazhatnak a memóriában.

A .stack 100h direktíva beállítja a verem méretét. A verem szükséges bizonyos információk mentéséhez a későbbi helyreállítás során. A verem különösen a megszakításokra szolgál. Ebben az esetben a FLAGS regiszter, a CS regiszter és az IP regiszter tartalma a veremben tárolódik. Ezután következik a megszakító program végrehajtása, majd ezeknek a regisztereknek az értékei visszaállnak.

  • A FLAGS regiszter olyan jeleket tartalmaz, amelyeket a processzor egy utasítás végrehajtása után generál.
  • A CS (Code Segment) regiszter tartalmazza a kódszegmens címét.
  • Regisztráljon IP (Instruction Pointer) - utasításmutató. A következőképpen végrehajtandó utasítás címét tartalmazza (Cím a CS kódszegmenshez viszonyítva).

Több Részletes leírás túlmutat egy egyszerű cikken.

A .data direktíva határozza meg a program adatszegmensének elejét. Az adatszegmens "változókat" határoz meg, azaz. memóriafoglalás van a szükséges adatokhoz. A .data után van egy sor
HelloMsg DB "Hello World!",13,10,"$"

Itt a HelloMsg a szimbolikus név, amely megegyezik a "Hello World!" karakterlánc elejével. (idézőjelek nélkül). Vagyis ez a karakterláncunk első karakterének címe az adatszegmenshez képest. A DB (Define Byte) direktíva bájtonként határozza meg a rendelkezésre álló memóriaterületet. 13,10 - karakterkódok Új sorés Carriage return, és a $ karakter szükséges a DOS 09h függvény megfelelő működéséhez. Tehát a karakterláncunk 15 bájtot foglal el a memóriában.

A .code direktíva határozza meg a program kódszegmensének (CS - Code Segment) kezdetét. Ezután következnek a program parancsmnemonikat tartalmazó sorai.

Beszéljünk a mov parancsról.

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

A mov parancs egy mozgatás parancs. A forrás tartalmát elküldi a célállomásra. Az átvitelek lehetnek regiszter-regiszter, regiszter-memória, memória-regiszter, de nincs memória-memória átvitel, i.e. minden a processzor regiszterein megy keresztül.

Az adatokkal való munkavégzéshez be kell állítani egy adatszegmens regisztert. A beállítás az, hogy a @DATA adatszegmens címét írjuk a DS (Data Segment) regiszterbe. Ebbe a regiszterbe nem lehet közvetlenül beírni a címet – ez az architektúra, ezért az AX regisztert használjuk. Az AX-ben a kódszegmens címét írjuk

majd az AX regiszter tartalmát elküldjük a DS regiszterbe.

Ezt követően a DS regiszter tartalmazza az adatszegmens kezdetének címét. A DS:0000h cím a H karaktert fogja tartalmazni. Feltételezem, hogy ismeri a szegmenseket és az eltolásokat.

A cím két részből áll.<Сегмент>:<Смещение>ahol a szegmens 2 bájt és az eltolás 2 bájt. Kiderült, hogy 4 bájt bármely memóriacellához való hozzáféréshez.

mov ah, 09h
mov dx,offset HelloMsg
int 21h

Itt írjuk be az AH regiszterbe a 09h számot - a 21. megszakítás függvényének számát, amely a vonalat jeleníti meg a képernyőn.

A következő sorba írjuk be a DX regiszterbe sorunk elejére a címet (szégyen).

Ezután a 21h megszakítást hívjuk – ez a DOS-funkciók megszakítása. Megszakítás - amikor egy futó program megszakad, és a megszakító program végrehajtása megkezdődik. A megszakítási szám határozza meg a DOS szubrutin címét, amely karaktersorozatot nyomtat a képernyőre.

Valószínűleg felmerül a kérdés: Miért írjuk be a 09h függvényszámot az AH regiszterbe? És miért van a vonal eltolása a DX regiszterbe írva?
A válasz egyszerű: minden funkcióhoz meghatározott regiszterek vannak meghatározva, amelyek a funkció bemeneti adatait tartalmazzák. A súgóban megtekintheti, hogy mely regiszterekre van szükség bizonyos funkciókhoz: "e.

movax,4C00h
int 21h

mov ax,4C00h - küldje el a függvény számát az AX regiszterbe. 4C00h funkció - kilépés a programból.

int 21h - megszakítás végrehajtása (valójában kilépés)

vége - a program vége.

Az end direktíva után a fordító mindent figyelmen kívül hagy, így oda írhatsz amit akarsz :)

Ha a végéig elolvastad, akkor hős vagy!

Maiko G.V. IBM PC összeszerelő: - M.: "Business-Inform", "Sirin" 1999 - 212 p.