Utasítások
From WIKi
A feladatsor tele van hibákkal, használata nem ajánlott.
Első csoport . . . Utasítások . . . Eljárások . . . Megírandó programok . . . Mit ír ki a program??
Mire szolgál és hogyan működik az XLAT utasítás?
Egy byte lefordítása egy másik bytra egy max 255 byte hosszú úgynevezett fordítási táblázat alapján. A táblázat kezdőcíme EBX-ben van (vagy BX-ben, ha egy 16 bites kódban helyezkedik el az utasítás), és AL tartalmát felülírja a táblázat AL edik elemével ( ~MOV([EBX+AL],AL))
Hogyan férhetünk hozzá a flag regiszer tartalmához?
A LAHF (Load AH from Flag) utasítással a AH regiszterbe töltődik a FLAG regiszter alsó bájtja, vagy PUSHF ill. PUSFD utasítással a teljes FLAG ill. EFlag a verembe kerül és onnan kiolvashatjuk.
Mely utasítások írnak a verembe?
A PUSH utasítás különböző változatainak az a fő tevékenysége, hogy a verembe írjon valamit. Ezek: PUSH, PUSHW, PUSHD, PUSHA, PUSHAD, PUSHF, PUSHFD
Ezen túlmenően írnak még a verembe azok az utasítások is, melyek ideiglenesen félbeszakítják egy programkód működését. Ilyen a szubrutinhívás (CALL) és a megszakítás (INT) esete. Ezen utasítások az EIP (ill. IP) regiszter tartalmát helyezik el a veremben annak érdekében, hogy az ideiglenes tevékenység befejezése után a program ugyanott folytatódhasson, ahol azt félbeszakítottuk. (Az INT utasítás a visszatérési címen kívül verembe helyezi még a Flag regiszter tartalmát (F vagy EF), és a CS szegmensregisztert is. Ez utóbbit (CS) az ú.n. távoli eljárások meghívása során a CALL utasítás is kiírja a verembe.)
Mely utasítások olvasnak a veremből?
A POP utasítás különböző változatainak az a fő tevékenysége, hogy a adatot vegyenek ki a veremből. Ezek: POP, POPW, POPD, POPA, POPAD, POPF, POPFD.
Ezen túlmenően a veremből olvassák ki a program folytatásához szükséges információt (IP vagy EIP ill. CS és F vagy EF) a szubrutinból való visszatérésnél a RET utasítás, továbbá a megszakításokból történő visszatérésnél az IRET utasítás.
A FLAG regiszter mely bitjeit tudjuk közvetlenül, egyetlen utasítással módosítani?
Ezek a bitek a
- CF – carry
- DF – direction
- FI – interrupt enable
Mindegyiküket lehet 0-ra (CLear) vagy 1-re (Set) állítani, illetve a carry flaget lehet negálni (CoMplement) is.
A Flageket közvetlenül módosító utasítások:
CLC, STC, CMC, CLD, STD, CLI,
STI
Milyen módozatai vannak a feltétel nélküli JMP utasításnak?
- Direct ugrások (tipikusan egy cimke segítségével adjuk meg az
ugrás célpontját) Az utasítás és a cél közötti viszonytó függően az
alábbi esetek lehetségesek:
- jmp disp8
Előjeles bájt távolságon belüli (-128 .. +127) ugrás. Az ilyen ugrás gépi kódja a legrövidebb, hiszen csak 1 bájtnyi információt kell elhelyezni benne az ugrás célpontjára vonatkozóan. - jmp disp32 ; vagy 16 bites kódban: jmp disp16
szegmensen belüli ugrás - jmp adrs48 ; vagy 16 bites kódban: jmp adrs32
közvetlen, szegmensen kívüli, szegmens+offset cím, szegmens mindig 16 bitet igényel, az offszet viszont a kód-mérettől függően 16 vagy 32 bites lehet.
(Windows és LINUX alatt inkább csak elvi jelentőségű lehetőség. Ezek az operációs rendszerek nem bontják szegmensekra a memóriát, így nem tudunk az ezen rendszerek alatt működő programokban távoli címeket deklarálni.)
- jmp disp8
- Indirect ugrások. Az operandus nem magát az ugrás célpontját
határozza meg, hanem arról ad információt, honnan kell kiolvasni a
címet.
- 16 bites kódban:
- jmp reg16
regiszter-közvetett, szegmensen belüli. A regiszterből lesz kiolvasva a az IP regiszer új értéke (az ugrás célpontja). - jmp mem16
közvetett, szegmensen belüli vagy másképpen közeli ugrás, A megadott memóricímről lesz kiolvasva a az IP regiszer új értéke (az ugrás célpontja). - jmp mem32
közvetett, szegmensen kívüli, A megadott memóriacímről lesz kiolvasva a az IP és a CS regiszerek új értéke (az ugrás célpontja).
- jmp reg16
- 32 bites kódban (Windows, Linux):
- jmp reg32
regiszter-közvetett, szegmensen belüli. A regiszterből lesz kiolvasva a az EIP regiszer új értéke (az ugrás célpontja). - jmp mem32
közvetett, szegmensen belüli vagy másképpen közeli ugrás, A megadott memóricímről lesz kiolvasva a az EIP regiszer új értéke (az ugrás célpontja). - jmp mem48
közvetett, szegmensen kívüli, A megadott memóriacímről lesz kiolvasva a az EIP és a CS regiszerek új értéke (az ugrás célpontja). (itt is érvényes a fentebbi megjegyzés, ezt az elvi lehetőséget aligha fogjuk kihasználni.)
- jmp reg32
- 16 bites kódban:
Mely feltételes ugrásokat használhatjuk előjeles mennyiségek összehasonlítása után
Az összehasonlításra használt CMP(cél,forrás) utasítás a cél-forrás kivonásnak megfelelően állítja az állapotjelzőket. Az összehasonlítást követő feltételes ugró utasítások ezeket az állapotjelzőket vizsgálják meg. Ha a CMP utasítás operandusai előjeles egészek voltak, akkor a számol lözötti hagyományos relációkat az alábbi feltételes ugrásokkal vizsgálhatjuk:
- JG cimke
ugrik, ha cél>forrás (OF==SF és ZF==0) - JL cimke
ugrik, ha cél<forrás (OF!=SF) - JE cimke
ugrik, ha cél==forrás (ZF==1) - JGE cimke
ugrik, ha cél>=forrás (OF==SF) - JLE cimke
ugrik, ha cél<=forrás (OF!=SF vagy ZF==1) - JNE cimke
ugrik, ha cél!=forrás (ZF==0) - JNG cimke
ugyanaz, mint JLE cimke - JNL cimke
ugyanaz, mint JGE cimke - JNGE cimke
ugyanaz, mint JL cimke - JNLE cimke
ugyanaz, mint J cimke
Az utasítások mnemonikjában a különböző betűk az alábbi angol szavakra utalnak:
- G Greater ~ nagyobb
- L Less ~ kisebb
- E Equal ~ egyenlő
- N Not ~ nem
Az ugrás helyének egy előjeles bájtnyi távolságon belül (-128 .. +127) kell lennie.
Mely felt. ugrásokat használhatjuk előjel nélküli mennyiségek összehasonlítása után
Az összehasonlításra használt CMP(cél,forrás) utasítás a cél-forrás kivonásnak megfelelően állítja az állapotjelzőket. Az összehasonlítást követő feltételes ugró utasítások ezeket az állapotjelzőket vizsgálják meg. Ha a CMP utasítás operandusai előjel nélküli természetes számok voltak, akkor a számol lözötti hagyományos relációkat az alábbi feltételes ugrásokkal vizsgálhatjuk:
- JA cimke
ugrik, ha cél>forrás (CF==0 és ZF==0) - JB cimke
ugrik, ha cél<forrás (CF==1) - JE cimke
ugrik, ha cél==forrás (ZF==1) - JAE cimke
ugrik, ha cél>=forrás (CF==0) - JBE cimke
ugrik, ha cél<=forrás (CF==1 vagy ZF==1) - JNE cimke
ugrik, ha cél!=forrás (ZF==0) - JNA cimke
ugyanaz, mint JBE cimke - JNB cimke
ugyanaz, mint JAE cimke - JNAE cimke
ugyanaz, mint JB cimke - JNBE cimke
ugyanaz, mint JA cimke
Az utasítások mnemonikjában a különböző betűk az alábbi angol szavakra utalnak:
- A Above ~ fölötte/nagyobb
- B Below ~ alatta/kisebb
- E Equal ~ egyenlő
- N Not ~ nem
Az ugrás helyének egy előjeles bájtnyi távolságon belül (-128 .. +127) kell lennie.
Mely ugró utasítások vizsgálják közvetlenül az egyes állapotjelzőket?
- JC cimke
ugrik, ha CF==1 - JNC cimke
ugrik, ha CF==0 - JP cimke
ugrik, ha PF==1 - JPE cimke
ugrik, ha páros (Even); ugyanaz, mint JP cimke - JNP cimke
ugrik, ha PF==0 - JPO cimke
ugrik, ha páratlan (Odd); ugyanaz, mint JNP cimke - JZ cimke
ugrik, ha ZF==1 - JNZ cimke
ugrik, ha ZF==0 - JS cimke
ugrik, ha SF==1 - JNS cimke
ugrik, ha SF==0 - JO cimke
ugrik, ha OF==1 - JNO cimke
ugrik, ha OF==0
Az ugrás helyének egy előjeles bájtnyi távolságon belül (-128 .. +127) kell lennie.
Ismertesse a CALL és RET utasításokat!
CALL – szubrutin hívása
- közeli hívás: EIP értéke a verembe kerül, majd felülíródik a szubrutin címével
- távoli hívás: CS és EIP értéke a verembe kerül, majd felülíródnak a szubrutin szegmens és offset címével. (Windows, Linux alatt gyakorlatilag nem használunk távoli eljárásokat.)
Az eljárás meg lehet adva
- direkt
- CALL eljárás_név
ill. - CALL közeli_cím
- CALL távoli_cím
- CALL eljárás_név
- vagy indirekt módon
- CALL(reg32)
- CALL(mem32)
esetleg távoli eljárás esetén - CALL(mem48)
RET [(num_kif)] – szubrutinból való visszatérés a hívást követő utasításra
- visszatérés közeli hívásból: EIP értéke felülíródik a veremből
- visszatérés távoli hívásból: EIP majd CS értéke felülíródik a veremből
- Ha szerepel (num_kif), akkor megnöveli a veremmutató értékét, és ezzel eltünteti a veremből az eljárás argumentumait (~ ADD(num_kif,ESP)).
Ismertesse az INT és IRET utasításokat
- INT(bájt_konstans);
- INT;// Majdnem ugyanaz, mint: INT(3);
- INTO;// Majdnem ugyanaz, mint: IF(@O) THEN INT(4) ENDIF;
Az INT utasítás (és változatai) segítségével a programkódból lehet aktiváni a megszakítás kezelő rutinokat. Attól eltekintve, hogy ezen esetekben a programozó akarata indítja el a folyamatot, míg a külső megszakításoknál egy a külvilágból érkező jel, a két művelet azonos módon zajlik le. Mivel a megszakítás kezelők mindig csak ideiglenesen szakítják meg a program működését, biztosítani kell annak lehetőségét, hogy a későbbiek során a program úgy folytatódhasson, mintha nem is történt volna megszakítás. A probléma mentes visszatérés érdekében a megszakításnak el kell mentenie legalább a soron következő utasítás pontos címét. A 80x86-os processzorcsalád ezen túlmenően menti még a Flag regiszter tartalmát is. (Védett módban még további információkat is elment.)
INT(konst);
//PUSHF;CLT;IF(külső_megsz.) then CLI endif; PUSH(CS);PUSH(IP);
//CLT ~ törli a trap flaget; (Valójában nincs ilyen urasítás.)
- FONTOS: (Ha megszakítás kezelőt szeretnénk írni.) A flageken és az utasítás mutatón kívül minden mást a megszakítás kezelő rutinnak kell elmentenie (és helyreállítania), ha használni szeretné. Ezért az ilyen rutinok gyakran kezdődnek egy PUSHA utasítással.
Az operandus nélküli INT utasítás a nyomkövetés segítését szolgálja. Annyiban különbözik az "INT(3)" utasítástól, hogy mindössze egyetlen bájtot foglal el a gépi kódja. Ezzel segítik, hogy a nyomkövető programok egyszerűen tudjanak töréspontot elhelyezni a programban.
A 0-s sorszámú megszakítás az osztási hibához tartózó
eltérülés kezelője.
Az 1-es sorszámút a Trap flag 1 értéke aktiválja minden egyes
utasítást követően.
A 2-es az ú.n. nem maskolható külső megszakításhoz (NMI)
tartozik.
A 4-es számú megszakítás az INTO utasításhoz kötődik.
Amennyiben az utasítás végrehajtása idején az overflow flag értéke 1,
akkor kerül meghívásra ez a megszakítás kezelő. Ha OF értéke nulla,
akkor a progarm egyszerűen folytatódik az INTO utáni utasítás
végrehajtásával.
Némelyik operációs rendszer is formális megszakításokon keresztül nyújt
elérési lehetőséget a szolgáltatásai fele.
- DOS alatt pl. nevezetes a $21-es megszakítás, melyet DOS funkció hívásnak neveznek.
- Linux alatt az INT($80) uatasítással érhetjük el az operációs rendszer szolgáltatásait, pl. a program befejezésének kérését.
- A Windows más utat választott erre a célra. Ezért Windows alatt kerüljük az INT utasítás használatát.
IRET;
Ez az utasítás a megszakítás kezelőből történő visszatérést szolgálja.
Lényegében kiolvassa a veremből mindazon információkat, melyeket a
megszakítás hívás helyezett el. Utolsó lépésben helyreállítja az
utasítás mutató (EIP) értékét, és ezzel megtaremti a
lehetőséget, hogy a program működése ott folytatódjon, ahol a
megszakítás miatt félbeszakadt.
Ismertesse az aritmetnikai utasításokat!
Összeadás, kivonás
- ADD (forrás,cél);// cél=cél+forrás 8,16,32 bit
- ADC (forrás,cél);// cél=cél+forrás+CF (Segítségével a processzor által közvetlenül nem támogatott, nagyméretű -sok biten tárolt- számok összeadása is megoldható.)
- SUB (forrás,cél);// cél=cél-forrás
- SBB (forrás,cél);// cél=cél-forrás-CF (Segítségével a processzor által közvetlenül nem támogatott, nagyméretű -sok biten tárolt- számok kivonása is megoldható.)
- NEG (cél);// cél=0-cél
Fenti utasítások az összes állapotjelzőt (CF, PF, AF, ZF, SF és OF) értelemszerűen állítják.
- INC (cél);// ~ADD(1,cél)
- DEC (cél);// ~SUB(1,cél)
Fenti két utasítás -az eltérő gépi kódon kívül- annyiban más, mint a megfelelő összeadó/kivonó utasítás, hogy változatlanul hagyják a CF bitet. A többi állapotjelzőt viszont ugyanúgy módosítják, mint a helyettesítő kód.
- CMP(cél,forrás);// ~MOV(cél,TMP);SUB(forrás,TMP); (Annyiban tér el a SUB(forrás, cél) utasítástól, hogy nem tárolja a kivonás eredményét, csak az állapotjelzőket módosítja.
Szorzás
- INTMUL(forrás,cél);// cél=cél*forás
- INTMUL(konstans,forrás,cél);// cél=konstans*forrás (Itt a forrás csak memória operandus, vagy regiszter lehet.)
Fenti két utasításnál
-
- a céloperandus csak 16 vagy 32 bites általános célú regiszter lehet.
- a szorzandók előjeles egészként lesznek értelmezve
- MUL(szorzó);// szorzó méretétől függően:
- AX=AL*szorzó
- (DX:AX)=AX*szorzó
- (EDX:EAX)=EAX*szorzó
A MUL utasításnál a szorzandók előjel nélküli (természetes) számok.
- IMUL(szorzó);// Hasonlóan működik, mint a MUL utasítás, csak előjeles számként értelmezi a szorzandókat.
A szorzó utasítások határozatlan értéket helyeznek el a PF, AF, ZF és SF jelzőbitekben. CF=OF pedig azt jelzi, hogy az eredménynek a szorzandókkal megegyező számú alacsony helyiértékű bitje a helyes eredményt tartalmazza-e: (0-igen, 1-nem).
Osztás
- DIV(osztó);// Az osztó méretétől függően:
- AX/osztó==>AL ill. AX%osztó==>AH
- (DX:AX)/osztó==>AX ill. (DX:AX)%osztó==>DX
- (EDX:EAX)/osztó==>EAX ill. (EDX:EAX)%osztó==>EDX
A DIV utasításnál az osztandó és az osztó előjel nélküli (természetes) számok.
- IDIV(osztó);// Hasonlóan működik, mint a DIV utasítás, csak előjeles számként értelmezi az osztandót és az osztót.
Az osztások minden állapotjelzőt határozatlan értékre módosítanak.
Amennyiben a hányados nem ábrázplható az osztónak megfelelő méretű regiszterben, akkor az utasítás aktiválja a 0 sorszámú kivételt.
Ismertesse a veremkezelő utasításokat!
- PUSH(forrás); //forrás:16/32bit mem/reg
- PUSHW(forrás); //forrás:16bit mem/reg/konstans
- PUSHD(forrás); //forrás:32bit mem/reg/konstans
- POP(cél); //cél:16/32bit mem/reg
- POPW(cél); //cél:16bit mem/reg
- POPD(cél); //cél:32bit mem/reg
- PUSHA; // PUSH([AX-DX,SP,BP,SI,DI])
- POPA; // PUSH([AX-DX,SP,BP,SI,DI])visszafele
- PUSHAD,POPAD 32 bites reg
- PUSHF //FLAG a verembe; POPF //a veremből
A verem teteje pozíciót a memóriábam az ESP regiszter jelöli ki.
A PUSH utasítás előbb csökkenti a veremmutató (ESP) értékét az operandus méretének megfelelően, majd az új verem teteje címre kimásolja az utasítás operandusát.
A POP utasítás -pont fordított sorrendben- előbb kimásolja a verem teteje címen található adatot az operandusba, majd növeli a veremmutató (ESP) értékét az operandus méretének megfelelően.
Bár elvileg 16 és 32 bites operandusokkal is működnek ezek az utasítások, törekedjünk arra, hogy mindig 32 bites mennyiségeket helyezzünk el a veremben.
Ismertesse a logikai utasításokat!
- NOT(cél);// cél bitenkénti complementálása
- AND(forrás,cél);// bitenkénti és művelet
- OR(forrás,cél);// bitenkénti vagy művelet
- XOR(forrás,cél);// bitenkénti kizáró vagy művelet
- TEST(forrás,cél);// bitenkénti és művelet, az eredmény tárolása nélkül (a többi utasításnál a cél operandus tartalmazza az eredményt)
A NOT utasítás nem változtatja meg az állapotjelzőket.
A többi utasítást követően értelemszerű információt olvashatunk ki a PF, ZF és SF jelzőbitekből.
Ismertesse a forgató utasításokat!
- ROR(számláló,cél);
- ROL(számláló,cél);
Ezen utasítások jobbra (ROR) ill. balra (ROL) forgatják az operandusban lévő biteket. A szélen kilépő bit egyrészről beforog az operandus másik végén, másrészről pedig kimásolódik a CF jelzőbitbe. A számláló (vagy egy konstans, vagy a CL regiszter) határozza meg, hogy mennyivel mozdul el egy-egy bit az eredeti helyéhez képest.
- RCR(számláló,cél);
- RCL(számláló,cél);
Ezen utasítások annyiban térnek el az egyszerű forgatásoktól, hogy a CF-el kiegészített cél operandust forgatják el, azaz a CF eredeti tartalma bekerül a cél operandusba.
A forgató utasítások a CF mellett még az OF értékét változtatják meg:
- számláló==0 esetén nem (mégsem) változik meg az OF tartalma
- számláló==1 esetén
- OF=1, ha a forgatás hatására megváltozik a céloperandus legmagasabb helyiértékű bitje (azaz az előjele), és
- OF=0, ha a legmagasabb helyiértékű bit nem változik meg
- számláló>1 esetén OF határozatlan értékre változik
Ismertesse a léptető utasításokat!
- SHL(számláló,cél);
- SHR(számláló,cél);
A számláló (vagy egy konstans, vagy a CL regiszter) által meghatározott számú bittel eltolja a cél operandus bitjeit balra (SHL) ill. jobbra (SHR). Az utoljára kilépő bitet a CF-be helyezi. A másik oldalon 0 bitek lépnek be az operandusba.
A balra tolás megfelel a 2 hatványaival történő szorzásnak, míg a jobbra tolás az előjel nélküli számok 2 hatványaival történő osztásának feleltethető meg.
- SAL(számláló,cél);// Csak a nevében különbözik az SHL utasítástól, egyébként teljesen ugyanúgy működik (mivel azonos a gépi kódja is).
- SAR(számláló,cél);// Arithmetikai azaz az előjel megőrzésével történő eltolás. A magas helyiértékre nem automatikus 0-k lépnek be, mint az SHR utasításnál, hanem az eredetileg ott lévő érték marad az új érték is. Ez az utasítás az előjeles számok 2 ahtványaival történő osztásával hozható kapcsolatba. (Ha az osztás nem egész eredményt ad, akkor az SAR mindig a -végtelen felé kerekít.
Az eltoló utasítások az OF értékét is megváltoztatják:
- számláló==0 esetén nem (mégsem) változik meg az OF tartalma
- számláló==1 esetén
- OF=1, ha az eltolás hatására megváltozik a céloperandus legmagasabb helyiértékű bitje (azaz az előjele), és
- OF=0, ha a legmagasabb helyiértékű bit nem változik meg
- számláló>1 esetén OF határozatlan értékre változik
Értelemszerű információt olvashatunk ki a PF. ZF és SF jelzőbitekből is.
Első csoport . . . Utasítások . . . Eljárások . . . Megírandó programok . . . Mit ír ki a program??
A feladatsor tele van hibákkal, használata nem ajánlott.
