You are on page 1of 135

Forrás: http://www.doksi.

hu

Bevezetés

Ahhoz, hogy megértsük mit jelent az assembly nyelvű programozás, vissza kell
kanyarodnunk a legelsô számítógépekhez. Ezen gépek processzorai a bináris
számrendszer két számjegyének a 0 - nak és az 1 - nek megfelelô
feszültségszinteket voltak képesek értelmezni, és az így kapott gépi kódú
?
utasítást végrehajtani. Bármennyit is fejlôdött a számítástechnika azóta, a mai
processzorok többsége is csak a digitális jeleket képesek értelmezni.

A legelsô számítógépeket ennek megfelelôen kétállású kapcsolókkal


programozták. A kapcsolók aktuális helyzete reprezentált egy nullákból és
egyesekbôl álló bitmintát, amelyet a processzor a bitmintának megfelelô
feszültségszintek alapján értelmezett és végrehajtott. Ez volt a gépi kódú
programozás. Az elsô mikroprocesszorok megjelenésével, megjelentek az
úgynevezett kit-ek, amely egy áramköri panel volt. A panel tartalmazta a
processzort ( pl.: Intel 8080, 8 bites ), a processzor működéséhez
nélkülözhetetlen áramköri elemeket, valamint egy hexadecimális
billentyűzetet. Itt tehát a billentyűzet szolgálta azt a célt amit a hôskorszakban
a kétállású kapcsolók, azaz a billentyűzet segítségével lehetett bevinni a
processzor utasításainak gépi kódjait, amelyeket aztán végrehajtott a
processzor.

A gépi kódú programozásról elmondhatjuk tehát, hogy az teljes mértékben


lefedi az illetô processzor utasításkészletét, azaz se többet se kevesebbet nem
lehet vele megvalósítani, mint az utasításkészlet. A processzor utasításkészlete
egyébként a processzor mikroprogram tárjában található, mikroprogram
formájában. Ezen mikroprogram segítségével értelmezi és hajtja végre a
processzor a gépi kódú utasításokat.

Mint láthatjuk, a gépi kódú programozás esik legközelebb a számítógép


hardverjéhez. Közkeletű nyelven szólva ez a “legalacsonyabb szintű” nyelv.
Az is nyilvánvaló, hogy a programozásnak nem ez a legkényelmesebb módja.

Ezért a fejlôdés során minden gépi kódnak egy rövid - többnyire 3 vagy 4
betűs - szimbólumsorozatot feleltettek meg. Ezeket a gépi kódú utasításokat
reprezentáló karaktersorozatokat mnemonikoknak nevezzük. Ezekután a
processzor programozása úgy történt, hogy - egy szövegszerkesztô segítségé-
vel - a gépi kódok helyett a nekik megfelelô mnemonikokat írtuk le. Ez a gépi
nyelvű programozás máskeppen szólva az assembly nyelvű programozás.


Ezzel kapcsolatban három lényeges dolgot kell megállapítanunk. Az elsô az
az, hogy az assembly nyelv továbra is lefedi az illetô processzornak az utasítás
készletét.
Forrás: http://www.doksi.hu

Bevezetés
A második az az, hogy - mivel a processzor továbbra is csak a gépi kódot
képes értelmezni - kell egy szoftver eszköz, amely az assembly kódot a vele
egyenértékű gépi kóddá alakítja. Ezt az eszközt assemblernek hívják.

Harmadik megállapításunk pedig az, hogy - mivel az utasításkód is ugyan-


olyan bináris adat mint az utasítás valamely operandusa - a programunkban el
kell különítenünk egy adat illetve egy kód területet.

Késôbb szót ejtünk arról, hogy konkrétan melyik lesz az az assembler amit
használni fogunk és arról is, hogy hogyan történik az adat illetve a kód terület
elkülönítése.

Az elôszóban említettem, hogy manapság is létjogosultsága van az assembly


programozásnak bizonyos területeken, de nem kell az egész feladatot
assembly-ben megoldani. Ez úgy lehetséges, hogy mind a PASCAL, mind a C
nyelv képes az assembly-val történô egyittműködésre. Ebben a jegyzetben a C
- assembly kapcsolatot tárgyalom majd.

Bodlaki Tamás

Az assembly nyelvű programozás alapjai

Távoktatási jegyzet

10
Forrás: http://www.doksi.hu

Hiba! Nincs ilyen stílusú szöveg a dokumentumban.

Impresszumoldal

3
Forrás: http://www.doksi.hu

Elôszó

Elôszó

Az elsô kérdés amire választ keresünk az az, hogy miért hasznos az assembly
nyelvű ( gépi nyelvű ) programozás alapjaival megismerkednünk, amikor olyan
hatékony magasszintű programnyelvek állnak a rendelkezésünkre, mint a
PASCAL vagy a C ill. a C++ nyelv.

A választ ma már fôleg a sebességviszonyok alakulása mentén kell keresnünk.


Az alkalmazások egy jó részénél valóban nem számít mondjuk egy 10 ms - os
idôintervallum. Egy munkaügyi információs rendszernél nem okoz tragédiát,
ha egy lekérdezés eredménye 10 ms - mal késôb jelenik meg a képernyôn.

Ugyanez a késés egy tárolt programvezérlésű telefonközpont működésénél már


jelentôs, hiszen ahhoz hogy egy elôfizetô úgy érezze, hogy - miután felemelte
a kézibeszélôt - azonnal tárcsahangot kap, pontosan 10 ms-os letapogatási idô
szükséges.

Bármilyen hatékony is egy magasszintű nyelv, a belôle készült tárgykód


többnyire nem lesz olyan tömör, mint a problémát lefedô gépi nyelvű program,
hiszen a magasszintű nyelvek fordítói általában redundanciát tartalmazó
tárgykódot készítenek, és nem használják ki a processzor teljes
utasításkészletét.

A válasz tehát úgy hangzik, hogy ott ahol nagyon kényesek a sebesség ill.
idôzítési viszonyok, ott továbbra is létjogosultsága van a gépi nyelvű
programozásnak.

Manapság azonban nem a teljes programot kell gépi nyelven elkészíteni,


hiszen az elôbb említett két nyelv lehetôvé teszi az assembly kapcsolatot.
Ennek a lehetôségét ebben e jegyzetben is megvizsgáljuk. Meg kell említeni
még, hogy egy hardware eszköz teljes kapacitását (sebesség, intelligencia stb.)
is általában assembly nyelven tudjuk a leghatékonyabban kiaknázni.

10
Forrás: http://www.doksi.hu

Hiba! Nincs ilyen stílusú szöveg a dokumentumban.


A jegyzet fô célja az assembly nyelvű programozás alapjainak bemutatása,
gazdag példaprogram anyag segítségével. Mivel tehát nem egy konkrét
processzor utasításkészletének bemutatása a fôcél, így elégségesnek bizonyult
az i8086 - os processzor utasításkészletének használata.

A jegyzet írása során feltételeztem, hogy az Olvasó legalább egy magasszintű


nyelvet ismer ( jó, ha ez a C nyelv ), illetve tisztában van a bináris és a
hexadecimális számrendszer használatával.

Az egyes fejezetek a következôképpen tagozódnak :

Minden fejezet elején egy rövid összefoglaló található, amely tömören közli,
hogy mit fog tartalmazni a fejezet. Ezt az összefoglaló részt a bekeretezett ∑
jelzi. Ezután következik a fejezet anyaga. A példaprogramok ezzel a
betűtípussal készültek, és keret veszi körül ôket.

Minden fejezetet ellenôrzô kérdések és feladatok zárnak, melyeket érdemes


megoldani már csak az alkotómunka kedvéért is !

A jegyzetben a következô témákat érintjük :

Jelen elôszót egy bevezetés követi, amely definiálja a gépi kód, gépi nyelv
fogalmakat, ill. elhelyezi az assembly nyelvet a programozási nyelvek között.

Az 1. fejezet az i8086-os processzor memóriakezelésérôl ill. regisztereirôl


szól. Itt teszünk említést a programozáshoz nélkülözhetetlen software eszkö-
zökrôl is. A 2. fejezet leírja az alapvetô direktívákat ill. adattípus definíciókat
egy egyszerű példaprogram kapcsán. Itt tárgyalunk néhány egyszerű DOS
szolgáltatást is.

A 3. fejezet az alapvetô aritmetikai utasításokat ismerteti. A 4. fejezet a logi-


kai utasítások leírását tartalmazza. Az 5. fejezetben a feltételnélküli ill. felté-
teles ugró utasításokat tárgyaljuk, míg a 6. fejezetben a ciklus szervezést. A 7.
fejezet tartalmazza az i8086 - os processzor memóri címzési módjainak leírá-
sát.

A 8. fejezet a léptetô, rotáló és a flagekkel kapcsolatos utasításokat ismerteti.


A 9. fejezetben a szubrutinok szervezésérôl és használatáról lesz szó. Itt
tárgyaljuk röviden a makró használatot is. A 10. fejezet a stringutasításokat
ismerteti valamint példákat közöl DOS, BIOS szolgáltatások használatára.

A 11. fejezet a C nyelv és az assembly nyelv kapcsolatát mutatja be inline mó-


don, valamint önálló modulok formájában. A 12. fejezet megemlít néhány kü-
lönbséget az i8086 - os processzor és a fejletteb processzorok utasításai között.

5
Forrás: http://www.doksi.hu

Elôszó

A jegyzetben használt magyarázó ábrák, és jelentésük :

∑ : Fejezet elei összefoglaló


! : Fontos megállapítás
? : Kérdés vagy probléma jelzése
 : Egy téma részletes vizsgálata

: Egy problémára megoldása

Az ábrákat keret veszi körül.

Mindegyik fejezetben tárgyalt anyag a 2x45 perces gyakorlat során átvehetô a


hallgatókkal. Az ennél rövidebb fejezetek a gyakorlás lehetôségét biztosítják.
A féléves oktatás 15 hetes, a jegyzet 12 fejezetre oszlik. A fennmaradó 3 hét-
ben lehetôség van a gyakorlásra és a számonkérésre !

Pécs, 1997. június 18. A Szerzô

10
Forrás: http://www.doksi.hu

1. Az i8086 memór iakezelése és r egiszter ei


A fejezetben olyan mélységig lesz szó a processzor memória kezelésérôl,
amely a programozáshoz elengedhetetlenül szükséges. Azt nézzük meg, hogy
hogyan lehet 16 bites regiszterekkel 20 bites címet elôállítani. A fejezet
második része a processzor regisztereit tárgyalja, megemlítve a processzor
működésében illetve programozásában betöltött szerepüket. Szó lesz még az
assembly nyelvű programfejlesztés során alkalmazott software eszközökrôl.

1.1 M emór iakezelés

A 8086 - os processzor minden 80x86-os processzor ôse. Regiszterei 16


bitesek, címsíne viszont 20 bites. Ennélfogva a címezhetô memória 1 MB.
Felmerül a kérdés, hogy hogyan lehet 16 bites regiszterekkel 20 bites címet
?
elôállítani ?

Nyilván egy regiszterrel sehogyan. A címképzésre két regisztert alkalmaznak.


Az egyik regiszter tartalmazza a 20 bites cím úgynevezett szegmens részét, a
másik az offset részt. Ezáltal tehát a címet két 16 bites összetevôre osztottuk
fel. Ez azt is jelenti, hogy ha egyszer rögzítettük a szegmensregiszter tartalmát,
akkor ehhez képest 64 KB memóriát tudunk címezni az offsetet tartalmazó
regiszter segítségével. Ezekután a fizikai cím úgy adódik, hogy a
szegmensregiszter tartalmát 16-tal szorozzuk, ami 4 helyiértékkel történô balra
léptetést jelent a kettes számrendszerben. Az így kapott - immár 20 bites -
értékhez hozzáadjuk az offsetcímet. Mivel a címeket leggyakrabban
hexadecimális számrendszerben ábrázoljuk, ezért az elôbb elmondottak
alapján a 16-tal való szorzás itt 1 helyiértékkel történô balra léptetést jelent, és
az így kapott mennyiséghez kell hozzáadni az offsetet. Az általános képlet
tehát :

Fizikai cím = SZEGMENS* 16 + OFFSET

Legyen például a szegmenscím 0040h, az offset 0002h. Ekkor a cím így irható
fel : 0040:0002. Ebben az esetben a szegmenscímet 16-tal szorozva 0400h
értéket kapunk. Ehhez hozzáadva a 0002h értéket 0402h fizikai cím adódik. A
h betű a hexa számrendszert jelöli. Ugyanez a fizikai cím áll elô a 0030:0102
alakból ami azt jelenti, hogy a szegmensek átlapolhatják egymást. Ezt a
jelenséget egy programon belül a szegmensregiszterek használatával védhetjük
ki.
Forrás: http://www.doksi.hu

1. Az i8086 memór iakezelése és r egiszter ei


A visszalakítás során az IBM ajánlást szokás követni. Legyen a fizikai cím
12345h. Ilyenkor a cím elsô jegyét leválasztjuk és kiegészítjük három 0-val :

12345h = 1000:2345

1.2 Az i8086-os r egiszter ei

A regiszterek egy része ugyanolyan célra használható mint általában a közpon-


ti memória, de mivel a processzoron belül helyezkednek el, ezért lényegesen
gyorsabbak. A másik részük nélkülözhetetlen szerepet játszik a processzor
működésében és programozásában. Az i8086-os regiszterei a következôk:

AH AX AL
BH BX BL
CH CX CL
DH DX DL
SI
DI
BP
SP
IP
F
CS
DS
ES
SS

A regisztereket egyelôre vázlatosan ismertetem. Részletes ismertetésükre az


adott funkciónál illetve feladatnál kerül sor. Ezért ha most valami érthetetlen-
nek tűnik az késôbb remélhetôleg világossá válik.

Az AX regiszter :

Régebbi processzoroknál az akkumulátor regiszter nevet kapta kitüntetett


szerepe miatt. Az i8086-nál ez a kitüntetett szerep csak részben maradt meg,
mint azt a késôbbiekben látni fogjuk például a szorzásnál vagy az osztásnál.

12
Forrás: http://www.doksi.hu

1.2 Az i8086-os regiszterei


Az AX regiszter ugyan 16 bites, de külön névvel lehet hivatkozni az alsó ill.
felsô 8 bitjére. Az alsó byte-ra AL, a felsô byte-ra AH néven hivatkozhatunk.
Ennek a lehetôségnek az egyik oka nyilván a karakter műveletekben
keresendô, hiszen egy karaktert 1 byte-on ábrázolunk.

A BX regiszter :

Kitüntetett szerepe lesz a memória címzésnél. A DS tartalmazza majd a válto-


zó szegmenscímét, BX pedig az offset címét. Az AX-hez hasonlóan felezhetô.

A CX regiszter :

A ciklus számláló szerepét tölti be, úgynevezett LOOP ciklus esetén. A két
elôzô regiszterhez hasonlóan felezhetô. Emellett általános célú regiszter is.

A DX regiszter :

Periféria műveleteknél a periféria címét írjuk ebbe a regiszterbe. Egyes arit-


metikai műveleteknél kiemelt szerepe van, például a szorzásnál és az osztás-
nál. Ezenkívül használható általános célokra is. Az utolsó felezhetô regiszter.

Az SI ( Source Index ) regiszter :

A BX-hez hasonlóan memóriacímzéshez használható. Általában a


forrásobjektum címét tartalmazza. Az SI mindig az adatszegmens regiszter-hez
( DS ) címzi a memóriát. Általános célokra is használható.

A DI ( Destination Index ) regiszter :

Hasonló az SI regiszter szerepéhez, de általában a célobjektum címét


tartalmazza. Szintén a DS - hez képest címzi a memóriát. Szintén használható
általános célokra is.

A BP ( Basis Pointer ) regiszter :

Amellett, hogy általános célú regiszter, kitüntetett szerepe van a verem (stack)
címzésénél. Ilyenkor az SS regiszterhez képest címzi a stack-et. A stack
aktuális elemének az offset címét tartalmazza.

13
Forrás: http://www.doksi.hu

1. Az i8086 memór iakezelése és r egiszter ei

Az SP ( Stack Pointer ) regiszter :

A stack “ tetejének” címzésére szolgál, azaz a stack aljától számított utolsó


betöltött hely offset címét tartalmazza. Direkt módon tilos a megváltoztatása,
egy esetet kivéve, de errôl majd késôbb.

Az I P ( Instruction Pointer ) regiszter :

A következô végrehajtandó utasítás offset címét tartalmazza. Direkt módon


nem írható és nem olvasható !

Az F ( Flag ) regiszter :

A flag regiszter a feltételbiteket ( flageket ) tartalmazza a következô kiosztás-


ban :

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

X X X X O D I T S Z X A X P X C

A flagek nevei és ér telmezésük a következô :

0. Átvitel ( CARRY ) : Értéke 1 ha valamely művelet ered-


ménye túllépi az ábrázolási tarto-
mányt. Például ha két 8 bites mennyi-
ség összeadásánál fellép a 9. bit.

1. X : Kihasználatlan.

2. Párosság ( PARITY ) : Értéke egy, ha valamely művelet e-


redményében az 1. bitek száma páros.

3. X : Kihasználatlan.

4. Közbülsô átvitel : Ha a 3. ill. a 4. bit között átvitel


(AUXILARY CARRY) keletkezik, akkor 1 az értéke.

5. X : Kihasználatlan.

14
Forrás: http://www.doksi.hu

1.2 Az i8086-os regiszterei

6. Nulla (ZERO) : Ha valamely művelet ereménye 0, ak-


kor 1 az értéke, ellemkezô esetben 0.

7. Elôjel (SIGN) : Ha valamely művelet ereménye nega-


tív, akkor 1 az értéke, ellenkezô eset-
ben 0.

8. Nyomkövetés (TRACE) : Debuggereknél használatos lépésen-


kénti programvégrehajtásnál. A mi
esetünkben nem lesz rá szükség.

9. Megszakítás (INTERRUPT) : Ha 1 az értéke, akkor engedé-


lyezzük az interruptot, ha 0.
akkor letiltjuk.

10. Irány (DIRECTION) : Ha 1 az értéke, akkor a string-


műveletek a csökkenô indexek
mentén hajtódnak végre, ha 0
akkor a növekvô indexek men-
tén hajtódnak végre.

11. Túlcsordulás (OVERFLOW) : Értéke 1, ha valamely művelet


során túlcsordulás lép fel.

12. X : Kihasználatlan.

13. X : Kihasználatlan.

14. X : Kihasználatlan.

15. X : Kihasználatlan.

Természetesen a flagek működése most még áttekinthetetlennek tűnhet, de a


konkrét utasításoknál egyértelművé válik majd a helyzet.

A CS ( Code Segment ) regiszter :

A soron következô utasítás szegmenscímét tartalmazza. Direkt módon nem


írható és olvasható. Kezdeti értékét a DOS állítja be, a program betöltésekor.

15
Forrás: http://www.doksi.hu

1. Az i8086 memór iakezelése és r egiszter ei


Mint látható az utasítás teljes címe a CS:IP regiszterpárban van olymódon,
hogy CS-ben van a szegmenscím, IP-ben van az offset cím.

A DS ( Data Segment ) regiszter :

A program adatszegmensének kezdôcímét tartalmazza. Kötelezôen nekünk


kell beállítani a programunk elején. Minden változónk offset címe ettôl a
tartalomtól számítódik, relatív módon. Igy a program elsô változójának offset
címe : 0. A regisztert konstans értékkel tilos feltölteni, csak regiszterbôl
adhatunk át értéket !

Az ES (Extra Segment ) regiszter :

Egy extra adatszegmens kezdôcímét tartalmazza. Ez egy 64 KB méretű me-


mória terület. A mi esetünkben string műveleteknél használjuk, de használható
file bufferként és egyéb célokra is.

Az SS ( Stack Segment ) regiszter :

A stack szegmens kezdôcímét tartalmazza. A stack tetejének teljes címe tehát


az SS:SP regiszterpárban található. Mivel a stack-et a BP regiszterrel címezzük
relatív módon, így az elem teljes címe az SS:BP regiszterben található. A stack
egyébként nem véletlenül kapta a verem elnevezést, hiszen amit legutoljára
írunk bele azt olvassuk ki legelôször. Ez a L I FO ( Last In First Out ) típusú
adatszerkezet.

SP 92
elem3
94
elem2
96
elem1
98
elem0 100

Ez a stack például ami az ábrán látható 100 byte méretű. Elôszôr az elem0-t,
majd az elem1-et, elem2-ôt és végül az elem3-at írtuk bele. Ekkor az SP
regiszter értéke 92 lesz. A legelsô olvasás elem3-at fogja kiolvasni, így az SP
új értéke 94 lesz. A stack többek között nélkülözhetetlen a késôb tárgyalandó
szubrutin hívás megvalósításánál.

16
Forrás: http://www.doksi.hu

1.3 Az alkalmazott software eszközök


1.3 Az alkalmazott softwar e eszközök

Nem célom az alkalmazott eszközök részletes bemutatása, hiszen


! midegyiknek van helpje. Csak annyira ismertetem a programokat most
és a késôbbiekben, amennyire az nélkülözhetetlen a
programfejlesztéshez !

Korábban volt róla szó, hogy szükségünk lesz egy olyan eszközre, amely az
assembly nyelvű programunkat gépi kóddá fordítja le. Ennek a programnak
általában assembler a neve. A jegyzetben szereplô összes programot a
BORLAND C++ 3.1 programrendszer assemblerével fordítottam le. Ennek a
programnak a neve : TASM .EXE (Turbo Assembler). A TASM programnév
nélkül elindítva kiírja a képernyôre a rövid helpjét ami tartalmazza a
kapcsolóit. Mi fôleg a /zi kapcsolókat fogjuk használni a nyomkövetés
használatához. A TASM alapértelmezés szerint .ASM kiterjesztésű állományt
vár bemenetként.

Szükségünk lesz egy olyan programra is ami a gépi kódú programból (.OBJ)
futattható állományt szerkeszt (.EXE). Jelen rendszerben ez a TL I NK .EXE
(Turbo Linker) nevű program. Leggyakrabban a /v kapcsolóját fogjuk
használni, lehetôvé téve a hibakeresést.

Programnév nélkül elindítva szintén rövid helpet ír ki saját magáról. A TLINK


alapértelmezés szerint .OBJ kiterjesztésű állományt vár bemenetként.

Ez a két program nélkülözhetetlen az assembly nyelvű programfejlesztéshez !

A TD.EXE ( Turbo Debugger ) nem nélkülözhetetlen ugyan, de rendkívül


hasznos akkor, amikor a programunk nem működik kívánalmaink szerint, és
hibát akarunk keresni ( és találni ) benne. A TD alapértelmezés szerint .EXE
állományt vár a bemenetén. Elindulása után megjeleníti a forrásszöveget a
képernyôn. Ezután a programot lépésenként is végre lehet hajtani úgy, hogy
közben különbôzô változók értékeit figyeljük.

A késôbbiek folyamán hasznos lehet a TL I B.EXE ( Turbo Librarian ). Ennek


segítségével saját könyvtárat szerkeszthetünk ( .LIB ) meglévô object
moduljainkból.

Nyilván szükségünk van egy szövegszerkesztôre is. Ez lehet bármelyik ASCII


szövegszerkesztô, például a Norton Commander editora.

Ellenôr zô kér dések és feladatok

17
Forrás: http://www.doksi.hu

1. Az i8086 memór iakezelése és r egiszter ei

01. Mi a gépi kódú programozás, az assembly nyelvű programozás és mi az


assembler ?

02. Hogyan írható fel a 25642 hexadecimális számrendszerben ?

03. Hogyan írható fel a 642 bináris számrendszerben ?

04. Hogyan írható fel az F6E3 decimális számrendszerben ?

05. Hogyan írható fel az F6E3 bináris számrendszerben ?

06. Hogyan írható fel a 0000011011100011 decimális számrendszerben ?

07. Hogyan írható fel a 0000011011100011 hexadecimális számrendszer-


ben ?

08. Hogyan állítja elô az i8086-os a 20 bites címet ?

09. Melyek az i8086 regiszterei, és mi a szerepük ?

10. Melyek az i8086 jelzôbitjei, és mi a szerepük ?

11. Honnan kapta a stack a LIFO elnevezést ?

18
Forrás: http://www.doksi.hu

2. Egyszer űsített dir ektívák, fôbb adattípusok, alapvetô


DOS szolgáltatások

Σ
Ebben a fejezetben elôször is különbséget teszünk utasítás és direktíva között,
majd egy egyszerű assembly programocska kapcsán megismerkedünk az
assembly program felépítésével és az egyszerűsített direktívákkal. Szó lesz az
alkalmazható memóriamodellekrôl, az adatdefinícióról, illetve az alapvetô
DOS szolgáltatások hívásáról, valamint az általunk használt alapvetô adat-
típusok definiálásáról.

2.1 A HEL L O.ASM ismer tetése

Az egyszerű programocska a HELLO.ASM nevet viseli, és egy üzenetet ír ki


a képernyôre. A program a következôképpen néz ki :

1. sz. példaprogram :

;
; Egyszerű assembly példaprogram
;
.MODEL small
.STACK 100h
.DATA
;
uzenet db 'Hajrá Ferencváros',13,10,'$'
;
.CODE
mov ax, @data ; A DS regiszter feltöltése
mov ds,ax ; Az adatszegmens kezdôcímével
;
mov ah,9 ; Az üzenet kiiratása
mov dx,OFFSET uzenet
int 21h
;
mov ah,4ch ; Visszatérés a DOS-hoz
int 21h
END
Forrás: http://www.doksi.hu

2.1 A HEL L O.ASM ismertetése


Mielôtt rátérnénk a program működésének ismertetésére nézzük meg,

! hogy mi a különbség az utasítás és direktíva között. Az utasításból


tényleges gépi kód keletkezik, amit a processzor végrehajt, míg a
direktíva egy vezérlô infor-
máció a fordító számára, ami nem hajtódik végre !

Ezután nézzük a programot !



Az elsô három sor a ‘ ;’ karakterrel kezdôdik, ami programon belüli
megjegyzést, magyarázó szöveget jelent. Az elsô direktívánk a .MODEL
direktíva, amely segítségével megadhatjuk, hogy milyen memória modellben
akarunk dolgozni.

Az érvényes memóriamodellek egyébként a következôk :

- tiny : Az adat és a kód ugyanazon a 64 KB-os memó-


riaterületen (szegmensben) helyezkedik el.

- small : Az adat és a kód külön külön 64 KB szegmensben


helyezkedik el.

- medium : A kód lehet nagyobb mint 64 KB, de az adat nem.

- compact : Az adat lehet nagyobb mint 64 KB, de a kód nem.

- large : Mind az adat, mind a kód lehet nagyobb mint 64


KB, de egyetlen adattömb mérete sem lehet
nagyobb mint 64 KB.

- huge : Ugyanaz mint a large, de egy adattömb mérete


lehet nagyobb mint 64 KB.

A .M ODEL small kifejezés tehát azt jelenti, hogy mi a small modellt fogjuk
használni. Ez a jegyzetben található összes mintapéldára igaz.

A .STACK 100h jelenti azt, hogy a programunk által használt stack méretét
100h azaz 256 byte-ban határozzuk meg. A stack-et változók tárolására,
paraméterátadásra ill. szubrutinhívásra használja - többek között - a program.

19
Forrás: http://www.doksi.hu

2. Egyszerűsített direktívák, fôbb adattípusok, alapvetô DOS szolgáltatások


Ezután történik meg az adat illetve a kód terület (adatszegmens,

!
kódszegmens) szétválasztása. A .DATA direktíva jelenti az adatterület
kezdetét. Ezután a direktíva után definiálhatjuk adatainkat. Hiába egyezik
meg valamely adat a processzor valamelyik utasításának kódjával, akkor
sem kerül végrehajtásra, mert az adatszegmensben foglal helyet. A fordító
mindent adatnak értelmez, egészen a .CODE direktíváig. Amit ezután írunk az
vagy direktíva, vagy címke, vagy utasítás de semmiképpen sem adat.

Az utolsó direktíva az END ami a mindenkori forrásszöveg végét jelzi.


Az END direktíva után opcionálisan megadható egy címke, melynek
segítségével meghatározhatjuk azt, hogy mely utasítástól kezdve induljon a
programunk a betöltôdés után. Erre késôbb lesz szükségünk.

Ezekután tekintsük át programunk működését !

Az adatszegmensben definiáltunk egy uzenet nevű, db típusú változót. A db


típus a data byte rövidítése, és 8 bites adattípust jelent. A C nyelvben a char
típusnak felelne meg. A mi esetünkben egy karaktervektort (karakterlánc,
string) definiáltunk inicializálás segítségével. Az adatdefiniálásról késôbb
bôvebben lesz szó. Az üzenet utolsó három byte-ja a 13,10,’ $’ kombináció.
Ebbôl a 13 az újsor, a 10 a kocsi vissza (kurzor a sor elejére) kódja és arra
szolgálnak, hogy a kiiratás után a kurzort a következô sor kezdô poziciójára
vezéreljék. A ‘ $’ jel a string kiíró DOS szolgáltatás számára jelzi a string
végét.

A .CODE direktíva utáni művelet az adatszegmensregiszter inicializálása. A


@data szimbólum tartalmazza az adatszegmensünk kezdetének szegmens-
címét. Ezt a címet a mov utasítással írjuk be az ax regiszterbe. Az elsô dolog
amit tudnunk kell, hogy szegmensregiszterbe tilos közvetlenül konstans értéket
írni, csak egy másik regiszterbôl tölthetünk fel szegmensregisztert. A mov
utasításról még lesz szó a továbbiakban.

A mov utasítás az értékadó utasításhoz hasonlítható leginkább. Az elsô


operendusa a cél operandus, a második a for r ás. A céloperandus felveszi a
forrásoperandus értékét. Ennek értelmében az adatszegmens kezdôcímének
szegmens része az ax regiszterbe íródik és onnan a ds regiszterbe kerül.

! Ezt a műveletet minden egyes program elején el kell végeznünk, különben a


változóink kezdôcímét ( offset cím ) nem tudja mihez viszonyítani a fordító !

Most következik az üzenet kiiratása. Ezt a 9. számú DOS szolgáltatás segít-


ségével fogjuk elvégezni. A szolgáltatás úgy működik, hogy a sorszámát az ah
regiszterbe kell írni, a kiiratandó string kezdô címét (offset címét) a dx regisz-
terben kell elhelyezni az OFFSET operátor segítségével. Ezután az int 21h
utasítással hívjuk meg az ah regiszterben található sorszám alapján a kívánt
DOS szolgáltatást. Ez a DOS szolgáltatás tehát egy karakterláncot ír ki a

20
Forrás: http://www.doksi.hu

2.2 További DOS szolgáltatások ismertetése


képernyôre. A karakterlánc kiirása a ‘ $’ jel hatására fejezôdik be. Ha valamely
string végérôl lehagynánk a ‘ $’ jelet, akkor a 9. számú DOS szolgáltatás addig
folytatja a kiirást amíg valahol a memóriában nem talál egy ‘ $’ jelnek
megfelelô kódot. Ez nem kívánt jelenségek elôfordulásához vezet !

Az üzenet kiiratása után egy dolgunk maradt : visszadni a vezérlést a DOS-


nak, egész konkrétan a COMAND.COM-nak. Ezt a 4ch sorszámú DOS szol-
gáltatás végzi el. A 4c után írt h betű jelentiazt, hogy a konstans hexadecimális
számrendszerben értendô. A DOS szolgáltatás sorszámát most is az ah regisz-
terbe írjuk és magát a szolgáltatást az int 21h utasítással hívjuk meg.

!
A DOS-hoz való visszatérést mindig el kell végezni. Ennek elhagyása
ki-számíthatatlan hibajelenségeket eredményez !

Programunk forrásszövegét az END direktíva zárja.

2.2 További DOS szolgáltatások ismer tetése

A már megismert 9. illetve 4ch sorszámú DOS szolgáltatásokon kívül még két
szolgáltatást fogunk gyakran használni. Ezek az 1. illetve a 2. sorszámú DOS
szolgáltatások.

Az 1. sorszámú DOS szolgáltatás egy karakter beolvasására alkalmas. Az 1-et


az ah regiszterbe kell írni, a szolgáltatást az int 21h utasítással kell meghívni.
Ennek hatására programunk egy karakter billentyűzésére vár, majd ha ez
megtörténik, akkor a billentyűzött karakter ASCII kódja az al regiszterbe
kerül.

Például : mov ah,1


int 21h ; Egy billentyű leütésére vár a program
mov cl,al ; Az al-ben található karakterkódot
; beírjuk a cl regiszterbe.

A 2. sorszámú DOS szolgáltatás pedig egy karakter - képernyôre történô -


kiiratására alkalmas. A 2-ôt az ah regiszterbe, míg a kiiratni kívánt karakter
kódját a dl regiszterbe kell írni. A kód helyett írhatjuk magát a karktert is ‘ ’
jelek közé zárva. Ezt a DOS szolgáltatást is az int 21h utasítással hívjuk meg.

Például : mov ah,2


mov dl,65 ; A mov dl,’ A’ is tökéletesen megfelel !
int 21h

21
Forrás: http://www.doksi.hu

2. Egyszerűsített direktívák, fôbb adattípusok, alapvetô DOS szolgáltatások


Ennek hatására a képernyôn - az aktuális kurzorpozicióban - egy A betű jelenik
meg.

Egy késôbbi példaprogramban ismertetem még a 2ah szolgáltatást. Ez a szol-


gáltatás az aktuális dátumot állítja elô. Működése a következô : a 2ah - t itt is
az ah regiszterbe kell írni, majd az int 21h utasítással hívjuk meg a szol-
gáltatást. Hatására a dátum a következôképpen áll rendelkezésünkre: cx re-
giszterben az év 4 számjegyen, dh regiszterben a hónap 2 számjegyen, dl re-
giszterben a nap 2 számjegyen és az al regiszterben a hét hányadik napja 1
számjegyen. A 0 a Vasárnapot jelenti, az 1 a Hétfôt stb.

2.3 Alapvetô adattípusok és definiálásuk

Egy adattípussal már találkoztunk és db-nek hívtuk. Az assembly több adat-


típust ismer, de mi a db-n kívül a dw adattípussal foglalkozunk még. A dw a
data wor d rövidítése és 16 bites adattípust jelent. A C nyelv int típusa áll hoz-
zá a legközelebb.

Az adatdefiniálásra a .DATA direktíva után kerül sor a követlkezô általános


forma alapján :

<címke> <típus> [<mennyiség>] [<inicializálás>]

A <címke> jelenti az adatunk nevét. Betűvel kell kezdôdnie, számjegy és az


‘ _’ ( aláhúzás) karakter szerepelhet benne. Az elsô 32 karaktert különbözteti
meg az assembler. Mivel a címkét adatdefiníció követi, igy tilos a ‘ :’
használata a cimke után. Más esetekben ez kötelezô ( lásd késôbb ). A
<cimke> használata kötelezô !

A <típus> jelenti az adatunk típusát, ami a mi esetünkben db vagy dw lehet.


Használata szintén kötelezô !

Példa az eddig elmondottakra :

.DATA
karakter db ; karakter nevű 1 byte-os változó
index dw ; index nevű 2 byte-os változó
...

Abban az esetben, ha nem egyszerű változóra van szükségünk, hanem vektor-


ra, vagy mátrixra akkor a mennyiséget is meg kell adnunk, vagy inicializálásal

22
Forrás: http://www.doksi.hu

Ellenôr zô kér dések és feladatok


kell közölnünk az assemblyvel hogy nem egyszerű változóról van szó !
Inicializálni természetesen egyszerű változót is lehet.

Például :

kar db ‘ A’ ; kar nevű 1 byte-os változó, kezdeti értéke


; ‘ A’
szoveg db 20 dup(32) ; szoveg nevű 20 byte-os változó, mind-
; egyik byte kezdeti értéke a szóköz
szoveg1 db 10 dup(?) ; szoveg1 nevű 10 elemű karakter típusú
; vektor, kezdeti érték határozatlan
vektor dw 9 dup(0) ; vektor nevű 9 elemű integer változó, mind-
; egyik elem értéke 0
matrix dw 1, 2, 3 ; matrix nevű 3x3 - as integer típusú
dw 4, 5, 6 ; mátrix, inizializálva
dw 7, 8, 9

A dup operátor láthatóan arra alkalmas, hogy az elôtte álló számú adott típusú
adategységnek ( byte vagy word ) a zárójelek közötti kezdôértéket adja. Ha a
kezdôérték közömbös számunkra, akkor a ‘ ?’ karaktert használjuk.

Attól, hogy a matr ix nevű változó 3 sorban illetve 3 oszlopban lett iniciali-
zálva, attól még ugyanúgy sorfolytonosan tárolódnak az elemei, mintha azt
írtuk volna, hogy : matr ix dw 1,2,3,4,5,6,7,8,9. !
Azt, hogy vektorként vagy mátrixként fogjuk kezelni, azt majd az indexelés
módja fogja eldönteni !

Bármely - az adatszegmensben deiniált - egyszerű változóra a ‘ [‘ ’ ]’ záró-


jelpár segítségével hivatkozhatunk a kód szegmensben.

Példa : mov ax,[ertek1] ; Ha ertek1 3 volt akkor az ax értéke is 3 lesz

Amennyiben konstans értéket akarunk használni, úgy a következôket kell tud-


nunk : a konstans után írt ‘ b’ azt jelenti, hogy bináris konstansról van szó, a ‘ h’
hexadecimális, az ‘ o’ pedig oktális konstanst jelöl. Amennyiben a konstans
értéket nem követi betűjel, úgy decimális konstansról van szó. Hexadecimális
konstans esetén elôfordul, hogy a konstans betűvel kezdôdik. Ilyenkor egy ‘ 0’
karaktert kell eléje tenni, különben a fordító címkehivatkozásnak tekinti !

Példák konstansdefiníciókra : hexconst db 0aeh


binconst db 00011001b

Ellenôr zô kér dések és feladatok

23
Forrás: http://www.doksi.hu

2. Egyszerűsített direktívák, fôbb adattípusok, alapvetô DOS szolgáltatások

01. Mi a különbség az utasítás és a direktíva között ?

02. Miért szükséges az adat ill. a kódszegmens megkülönböztetése egy


programon belül ?

03. Mi a szerepe a .MODEL direktívának ?

04. Hogyan adhatjuk meg egy programon belül az általunk használni kívánt
stack terület méretét ?

05. Miért kötelezô az adatszegmens regiszter inicializálása ?

06. Mire használjuk az OFFSET operátort ?

07. Általában hogyan tudunk elérni egy DOS szolgáltatást, konkrétan mi-
lyen DOS szolgáltatásokat ismer ?

08. Mi az adatdefiníció általános alakja ? ( Rövid magyarázattal ! )

09. Mi a különbség a db és a dw adattípus között ?

10. Hogyan definiálhatunk vektorokat, mátrixokat ?

11. Készítsen egy olyan programot amely beolvas egy karaktert a


klaviatúráról, majd visszaírja azt a képernyôre !

12. Készítsen egy olyan programot amely kiír egy üzenetet a képernyôre,
majd egy soremelést ír ki, utána pedig még egy üzenetet ír ki a
képernyôre !

24
Forrás: http://www.doksi.hu

3. Ar itmetikai utasítások

Ebben a fejezetben komoly lépéseket teszünk annak érdekében, hogy az elôzô

Σ
fejezetben látott példa programnál bonyolultabb programokat is tudjunk írni.
Eôször a MOV értékadó utasítással, majd a fôbb aritmetikai utasításokkal is-
merkedünk meg. Ezt követôen konverziós illetve egyéb utasítások tárgyalása
következik.

3.1 Az i8086-os pr ocesszor általános utasítás for mátuma

Mielôtt rátérnénk a konkrét uatsítások tárgyalására, vizsgáljuk meg a


processzor utasítás formátumát általában:

[<címke>] <utasítás | dir ektíva > [<oper andusok>] [<; megj egyzés>]

Mint látható, az utasítás formátum négy részbôl áll, ebbôl egy kötelezô, három
pedig opcionális. A részek leírása a következô :

[<címke>] : Hasonló az adatdefiníciónál megismert cím-


kéhez de itt a ‘ :’ karakter követi. A ‘ :’ ka-
raktert kell használni egy címke után, ha az
önállóan szerepel egy sorban, vagy utasítás
követi.

<utasítás | direktíva > : Azok az utasítások amiket nemsokára rész-


letezünk, vagy a már megismert direk-
tívák valamelyike. Ez a kötelezô rész !

[<operandusok>] : Az operandusok mindig utasításokhoz tar-


toznak. Számuk lehet 0, 1, vagy több. Az
operandus lehet regiszter, memóriaváltozó,
indexkifejezés vagy konstans.

[<;megjegyzés>] : Magyarázó szöveg az utasítás sor végén.

Példa :

mov cx,10
Forrás: http://www.doksi.hu

3.2 A MOV utasítás


beolvas: mov ah,1 ; Itt kezdôdik a beolvasás
int 21h
...

3.2 A M OV utasítás

Szintaxis : MOV <op1>,<op2>

A mov utasítás értékadásra szolgál. Az <op1> felveszi <op2> értékét, <op2>


értéke változatlan marad. Az utasítás működését az <op1> = <op2> formával
lehet a legrövidebben leírni, ahol az ‘ =‘ karakter jelentése az, hogy “ legyen
egyenlô” . <op1> -et általában cél- , míg <op2>-ôt forrás operandusnak
nevezik. A forrásoperandus lehet : általános célú regiszter, memóriacím,
konstans, indexkifejezés. A céloperandus általános célú regiszter illetve
memóriacím lehet.

A mov utasítással kapcsolatban tilos a következôket megtenni !

-
-
A kódszegmens regiszternek ( CS ) értéket adni.
Szegmensregiszterbôl szegmensregiszterbe írni.
!
- Konstans értéket szegmensregiszterbe írni.
- Különbözô típusú operandusokat használni.

Ezeken kívül nem fordulhat elô az az eset, hogy mindkét operandus memória
változó !

Példák hibás mov utasításokra :

mov ax,bl ; Különböznek az operandus típusok !

mov [szam1],[szam2] ; Mindkét operandus memória változó !

mov ds,@data ; Szegmensregiszterbe nem írhatunk konstanst !

3.3 Az ADD és ADC utasítások

Szintaxis : ADD <op1>,<op2> , ADC <op1>,<op2>

25
Forrás: http://www.doksi.hu

3. Aritmetikai utasítások
Az add utasítás a két operandusának összeadására szolgál. Hasonlóan a mov
utasításhoz itt is <op1> a cél- és <op2> a forrás operandus. Megfelel az
<op1> = <op1> + <op2> műveletnek. A két operandus típusa meg kell
egyezzen, valamint itt is érvényes az a megkötés, hogy nem lehet egyszerre
mindkét operandus memóriaváltozó. Konstans érték csak a forrás operandus
lehet. Az utasítás a következô flageket érinti :

- CF = 1 ha átvitel keletkezett. ( Például két 8 bites


mennyiség összege már nem ábrázolható
8 biten, hanem megjelenik a 9. bit ).

- PF = 1 ha az eredmény alsó byte-jában az 1.


bitek száma páros.

- AF = 1 ha az eredmény 3. és a 4. számú bitje


között átvitel keletkezett. ( A bitek szá-
mozása 0 - tól indul ! ).

- ZF = 1 ha az összeadás eredménye 0.

- SF = 1 ha az eredmény negatív.

- OF = 1 ha túlcsordulás lép fel.

Ezek után nézzük meg, hogy mikor kell használnunk az adc utasítást ! Abban
az esetben ha 32 bites mennyiségeket akarunk összeadni elôfordulhat, hogy az
alsó 16 bit összeadásakor átvitel keletkezik. Ekkor a CF értéke 1 lesz. Világos,
hogy a felsô 16 bit összeadásánál ezt a bitet is figyelembe kell venni, tehát a
sima add utasítást nem használhatjuk. Ilyenkor az adc használatára kerül sor !
Az adc utasítás az <op1> = <op1> + <op2> + [CF] műveletnek felel meg. Az
utasítás ugyanazokat a flageket érinti mint az add.

Példák : mov al,10


mov bl,100
add al,bl ; al értéke 110 lesz
;
mov cx, 100
mov bx, 200
mov dx, 100
mov ax, 200
add ax,bx ; ax értéke 400 lesz
adc dx,cx ; dx értéke 200 lesz
; a dx:ax regiszterpárban keletkezett az eredmény

26
Forrás: http://www.doksi.hu

3.4 A SUB és SBB utasítások


3.4 A SUB és SBB utasítások

Szintaxis : SUB <op1>,<op2> , SBB <op1>,<op2>

A sub utasítás a két operandusának kivonására szolgál. Megfelel az <op1> =


<op1> - <op2> műveletnek. Ugyanazok a megkötések érvényesek a két
operandusra mint az add utasitás esetén, és ugyanazokat a flageket érinti a sub
mint az add. Itt is szembekerülünk azzal a problémával, hogy a kivonás
eredménye nem ábrázolható az adott tartományon, mert alulcsordulás
keletkezik.

Ez akkor fordulhat elô, ha nagyobb a kivonandó, mint a kisebbítendô. Ilyenkor


a CF értéke 1 lesz. 32 bites mennyiségek kivonása esetén tehát a felsô 16 bit
kivonásánál CF értékét is figyelembe kell venni. Ezt végzi az sbb utasítás :
<op1> = <op1> - <op2> - [CF]

Példák : mov al,10


mov bl,100
sub bl,al ; bl értéke 90 lesz
;
mov cx, 100
mov bx, 100
mov dx, 200
mov ax, 200

sub ax,bx ; ax értéke 100 lesz


sbb dx,cx ; dx értéke 100 lesz

; a dx:ax regiszterpárban keletkezett az eredmény

3.5 A CM P utasítás

Szintaxis : CMP <op1>,<op2>

A cmp utasítás ugyanúgy működik mint a sub, azzal a nagy különbséggel,


hogy <op1> értékét nem írja felül a kivonás eredményével, hanem csak a
flageket állítja be úgy mintha kivonás történt volna. Feltételes ugró utasítások
elôtt kiválóan használható feltétel vizsgálat céljára. Az <op1> és <op2> típusa
meg kell egyezzen, konstans csak <op2> lehet. Nem lehet egyszerre mindkét
operandus memória változó.

Példa : mov ah,1

27
Forrás: http://www.doksi.hu

3. Aritmetikai utasítások
int 21h
cmp al,13 ; <ENTER> - t billentyűztünk ?

3.6 Az I NC utasítás

Szintaxis : INC <op>

Az inc utasítás eggyel növeli operandusának értékét. Az elôzô utasításokkal


ellentétben a CF -et nem érinti, így az átvitel tényét nem tudjuk lekérdezni.
Amennyiben ez gondot jelent, úgy az add <op>,1 utasítást kell használni !

Példa : mov al,9


inc al ; al értéke 10 lesz

3.7 A DEC utasítás

Szintaxis : DEC <op>

Az dec utasítás eggyel csökkenti operandusának értékét. Az elôzô utasítások-


kal ellentétben a CF -et nem érinti, így az átvitel tényét nem tudjuk lekérdezni.
Amennyiben ez gondot jelent, úgy a sub <op>,1 utasítást kell használni !

Példa : mov al,11


dec al ; al értéke 10 lesz

3.8 A NEG utasítás

Szintaxis : NEG <op>

A neg utasítás az operandusának a kettes komplemensét állítja elô, azaz -1 -


gyel való szorzást hajt végre az operanduson. A művelet a CF,PF,AF,ZF,SF és
az OF flageket érinti.

Példa : mov al,10


neg al ; al értéke -10 lesz

3.9 A CBW és CWD utasítások

28
Forrás: http://www.doksi.hu

3.10 A MUL és IMUL utasítások


Szintaxis : CWB , CWD

Ez a két utasítás nagyon hasznos szerepet játszik az aritmetikai műveleteknél.


A cbw utasítás az al regiszterben lévô elôjeles byte-ot elôjeles szóvá
konvertálja és az ax regiszterbe helyezi, míg a cwd utasítás az ax regiszterben
lévô elôjeles szót elôjeles duplaszóvá konvertálja és a dx:ax regiszterpárba
helyezi. A most tárgyalásra kerülô szorzásnál és osztásnál jelentôs szerepet
kaphat ez a két utasítás !

Példa : mov al,10 ; al = 10


neg al ; al = -10
cbw ; ax = -10
;
mov ax,100 ; ax = 100
neg ax ; ax = -100
cwd ; dx:ax = -100

3.10 A M UL és I M UL utasítások

Szintaxis : MUL <op> , IMUL <op>

A mul utasítás elôjelnélküli mennyiségek szorzására szolgál, és két esetet


képes kezelni : egyrészt 8 bitet szoroz 8 bittel, másrészt 16 bitet 16 bittel. Az
elsô esetben az egyik operandus szigorúan az al regiszterben kell, hogy
elhelyezkedjen, a másik operandus valamelyik 8 bites általános célú
regiszterben, vagy memóriaváltozóban foglal helyet. Az eredmény az ax
regiszterben keletkezik a szorzás elvégzése után.

Példa : mov al,25


mov bl,4
mul bl ; az ax értéke 100 lesz

A másik esetben az egyik operandus az ax regiszterben kell, hogy helyet


foglaljon, a másik pedig valamely 16 bites általános célú regiszterben, vagy
memóriaváltozóban foglal helyet. Az eredmény a dx:ax regiszterpárban
keletkezik. Az alsó szó az ax, a felsô a dx regiszterben lesz elérhetô.

Az OF értéke 1 lesz, ha a szorzás után az eredmény felsô fele 0-tól eltérô,


egyébként törlôdik. A CF az OF-fel megegyezôen változik, a többi flag értéke
nem meghatározott.

29
Forrás: http://www.doksi.hu

3. Aritmetikai utasítások
Az imul utasítás két elôjeles mennyiséget szoroz össze. A műveleti szélesség
itt is kétféle lehet, mint a mul-nál, az operandusok elhelyezkedése is
tökéletesen megegyezik az elôzôekben leírtakkal.

3.11 A DI V és I DI V utasítások

Szintaxis : DIV <op> , IDIV <op>

A div utasítás elôjelnélküli mennyiségek osztására szolgál, és szintén két esetet


képes kezelni : egyrészt 16 bitet oszt 8 bittel, másrészt 32 bitet 16 bittel. Az
elsô esetben az osztandó szigorúan az ax regiszterben kell, hogy
elhelyezkedjen, az osztó valamelyik 8 bites általános célú regiszterben, vagy
memóriaváltozóban foglal helyet. Az osztás elvégzése után az eredmény az al
regiszterben keletkezik, a maradék pedig az ah-ban.

Példa : mov ax,41


mov bl,20
div bl ; az al értéke 2 az ah értéke 1 lesz.

A másik esetben az osztandó a dx:ax regiszterpárban kell, hogy helyet


foglaljon, a másik pedig valamely 16 bites általános célú regiszterben, vagy

memóriaváltozóban foglal helyet. Az eredmény az ax regiszterben keletkezik,


a maradék a dx regiszterben lesz elérhetô.

Egyik flag értéke sem meghatározott. Amennyiben az eredmény nem fér el a


célregiszterben ( al vagy ax ) vagy az osztó 0, úgy a 0. megszakítás lép életbe
ami a 0-val való osztást kezeli.

Az idiv utasítás teljesen megegyezôen működik a div-vel, csakhogy itt az


osztandó is és az osztó is elôjeles mennyiség.

Abban az esetben ha két 16 bites elôjeles mennyiséget akarunk elosztani,


átalakításhoz kell folyamodnunk, mert ilyen alakot az idiv nem ismer. Ebben
az esetben az osztandót beírjuk az ax regiszterbe, majd a cwd utasítást
alkalmazzuk. Ennek hatására a dx:ax regiszterpárban foglal helyet az osz-
tandónk, így semmi akadálya az osztásnak. Két 8 bites mennyiség esetén
hasonlóan járunk el csak nem a cwd, hanem a cbw utasítást használjuk !

Példa : ; bx - ben -200 van


; cx - ben 100 van
mov ax,bx
cwd ; a dx:ax-ben lesz a -200

30
Forrás: http://www.doksi.hu

3.12 Az XCHG utasítás


div cx ; ax-ben -2 lesz, dx-ben 0

3.12 Az XCHG utasítás

Szintaxis : XCHG <op1>,<op2>

Az xchg utasítás felcseréli két operandusának az értékét. A két operandus nem


lehet egyszerre memóriaváltozó, és típusuk megegyezô kell legyen. Az utasítás
nem érinti a flageket.

Példa : mov al,1


mov ah,0 ; így az ax-ben 1 van
xchg al,ah ; al és ah megcserélôdik, az ax-ben 256 lesz.

3.13 Az OFFSET oper átor

Szintaxis : OFFSET <memóriaváltozó>

Bár nem utasítás, de elég gyakran kell majd használnunk. Az offset operátor az
utána álló memória változó kezdôcímét állítja elô. A kezdôcím alatt a
szegmens kezdethez ( ds regiszter tartalma) képesti offset címet kell érteni.

Példa : mov dx,OFFSET szoveg ; dx-be kerül a szoveg kezdôcíme

Ellenôr zô kér dések és feladatok

01. Ismertesse az i8086-os általános utasításformátumát, és annak elemeit !

02. Hogyan működik a MOV utasítás, milyen megkötések vonatkoznak rá ?

03. Adja össze a dx:ax illetve a cx:bx regiszterpárok tartalmát !

04. Vonja ki a dx:ax regiszterpár tartalmából a cx:bx regiszterpár tartalmát!

31
Forrás: http://www.doksi.hu

3. Aritmetikai utasítások
05. Mi az azonosság illetve a különbség a SUB és a CMP utasítás
működését tekintve ?

06. Mi a különbség az add al,1 és az inc al utasítások között ?

07. Mi a különbség a sub bl,1 és az dec bl utasítások között ?

08. Hogy lehet a -25 - öt elôjeles duplaszóvá konvertálni ?

09. Végezze el a következô szorzásokat : 30* 20, 300* 200, 3000* 2000,
30000* 20000 !

10. Végezze el a következô szorzásokat : -30* 20, -300* 200, -3000* 2000,
-30000* 20000 !

11. Végezze el a következô osztásokat : 16/9, 160/60, 1600/700,


16000/1500, 160000/9, 1600000/13400 !

12. Végezze el a következô osztásokat : -16/9, -160/60, -1600/700,


-16000/1500, -160000/9, -1600000/13400 !

13. Az ax regiszter tartalma 2. Alakítsa át 512-vé úgy, hogy nem


alkalmazhatja sem a mov sem az add, sem a mul utasításokat !

14. Melyik általunk ismert DOS szolgáltatásnál kell használni az OFFSET


operátort ?

32
Forrás: http://www.doksi.hu

4. L ogikai utasítások

Σ
Ebben a fejezetben a logikai utasításokat mutatom be. Feltételezem, hogy a
tárgyalandó logikai utasítások igazságtáblájával tisztában van az olvasó !

4.1 Az AND és a TEST utasítások

Szintaxis : AND <op1>,<op2> , TEST <op1>,<op2>

Az and utasítás bitenkénti ÉS műveletet végez a két operandusa között, és


ennek a műveletnek az eredményét az elsô operandusban tárolja. A működése
tehát a következôképpen írható le : <op1> = <op1> ÉS <op2>. Az utasítás a
PF, ZF és SF flageket érinti. Itt is érvényesek a szokásos megkötések : az
operandusok típusai meg kell, hogy egyezzenek, valamint nem lehet két
memóriaváltozón elvégezni az ÉS műveletet !

A test utasítás működése teljesen hasonló az and működéséhez. A különbség

! abban van, hogy test nem rombolja le az <op1> értékét az eredménnyel,


hanem csak a flageket állítja be az ÉS műveletnek megfelelôen.

Az and utasítás több mindenre használható. Elôször is bármely bitminta


bármely bitjét 0-ba tudjuk “ kényszeríteni” , ha a bitmintát egy olyan bitmintával
hozzuk ÉS kapcsolatba, amelynek a megfelelô pozicióján 0 áll, a többi
pozición pedig 1.

Példa :

mov al,00110011b ; a 4. bitet 0-ba akarom állítani, a bitek


; sorszámozása 0-tól indul !
and al,11101111b ; az eredmény 00100011 lesz.

Az and utasítás másik hasznos alkalmazása a “ maszkolás” nevet viseli. Ez azt


jelenti, hogy egy ismeretlen értékű bit vagy bitcsoport értékét meg tudjuk
határozni olymódon, hogy a kérdéses poziciókon 1-gyel, a többi pozición 0-val
végzünk ÉS műveletet. A maszkolás eredményétôl függôen tudjuk tovább
folyatni a programunkat. A maszkolást a 2. sz példaprogram mutatja be. Egy 8
Forrás: http://www.doksi.hu

4.2 Az OR utasítás
bites minta 3. 4. ill. 5. számú bitjének az értékét kell megállapítanunk. Mivel
három bitrôl van szó, ez az érték elvileg lehet 111, 110, 101, 011, 100, 010,
001 és 000. Nyilván mindegyik érték különbözô információt hordoz.

2. sz. példaprogram :

.MODEL small
.STACK 100h
.DATA
;
minta db 00101010b
info db 28h ; 00101000b ( erre vadászunk ! )
;
.CODE
mov ax, @data
mov ds,ax
;
mov ax,0
mov al,[minta] ; A gyakorlatban valamilyen
; periféria küldi.
and al,00111000b ; Itt történt meg a maszkolás !
cmp al,[info]
;
; Az összehasonlítás eredményétôl függô
; program sorok
;
mov ah,4ch
int 21h
END

Az and utasítás még arra is alkalmas, hogy egy regiszterrôl a leggyorsabb


módon eldöntsük, hogy tartalma 0.

Példa : and ax,ax ; Ha 0 volt az ax-ben akkor ZF értéke 1 lesz.

4.2 Az OR utasítás

Szintaxis : OR <op1>,<op2>

33
Forrás: http://www.doksi.hu

4. Logikai utasítások

Az or utasítás bitenkénti VAGY műveletet végez a két operandusa között, és


ennek a műveletnek az eredményét az elsô operandusban tárolja. A működése
tehát a következôképpen írható le : <op1> = <op1> VAGY <op2>. Az utasítás
szintén a PF, ZF és SF flageket érinti. Itt is érvényesek a szokásos megkötések
: az operandusok típusai meg kell, hogy egyezzenek, valamint nem lehet két
memóriaváltozón elvégezni a VAGY műveletet !

Az or utasítás segítségével bármely bitminta bármely bitjét 1-be tudjuk


“ kényszeríteni” , ha a bitmintát egy olyan bitmintával hozzuk VAGY
kapcsolatba, amelynek a megfelelô pozicióján 1 áll, a többi pozición pedig 0.

Példa : mov al,00100011b ; a 4. bitet 1-be akarom állítani, a bitek


; sorszámozása 0-tól indul !
or al,00010000b ; az eredmény 00110011 lesz.

4.3 Az XOR utasítás

Szintaxis : XOR <op1>,<op2>

Az xor utasítás bitenkénti KIZÁRÓ VAGY műveletet végez a két operandusa


között, és ennek a műveletnek az eredményét az elsô operandusban tárolja. A
működése tehát a következôképpen írható le : <op1> = <op1> KIZÁRÓ
VAGY <op2>. Az utasítás ugyancsak a PF, ZF és SF flageket érinti. Itt is
érvényesek a szokásos megkötések : az operandusok típusai meg kell, hogy
egyezzenek, valamint nem lehet két memóriaváltozón elvégezni a KIZÁRÓ
VAGY műveletet !

Az xor utasítás segítségével bármely bitminta bármely bitjét az ellenkezô


értékébe tudjuk “ kényszeríteni” , ha a bitmintát egy olyan bitmintával hoz-
zuk KIZÁRÓ VAGY kapcsolatba, amelynek a megfelelô pozicióján 1 áll, a
többi pozición pedig 0. Ezt a műveletet bit komplementálásnak hívjuk.

Példa : mov al,00110011b ; a 4. bitet akarom komplementálni


; sorszámozása 0-tól indul !
;
xor al,00010000b ; az eredmény 00100011 lesz.

Az xor utasítás másik alkalmazása : egy regiszter kinullázásának ez a leg-


gyorsabb módja.

34
Forrás: http://www.doksi.hu

4.4 A NOT utasítás

Példa : xor ax,ax ; ax-ben 0 lesz

4.4 A NOT utasítás

Szintaxis : NOT <op>

A not utasítás az operandusának az egyes komplemensét állítja elô, azaz


mindegyik bitjének értékét az ellenkezôjére változtatja. Egyik flagre sincs
hatással.

Ellenôr zô kér dések és feladatok

01. Mi a különbség az and és a test utasítások között ?

02. Mire használható az and utasítás ?

03. Milyen eljárással állapíthatjuk meg egy bitminta adott bitcsoportjának


az értékét ?

04. Állítsa 0 értékűre az alábbi byte 2. és 3. bitjeit. A sorszámozás 0-tól


indul : 00101101b !

05. A dl regiszterben egy ismeretlen bitminta található. Melyik bitmintával


kell maszkolni a dl tartalmát ahhoz, hogy megállapítsuk a 4., 5., 6.
bitek értékét ?

06. Hogyan működik az or utasítás, milyen megkötések érvényesek az


operandusaira ?

07. Állítsa 1 értékűre az alábbi byte 3. és 4. bitjeit. A sorszámozás 0-tól


indul : 00100101b ! Milyen bitmintát kell használnunk ?

08. Hogyan működik az xor utasítás, milyen megkötések érvényesek az


operandusaira ?

09. Komplementálja az alábbi byte 4. bitjét. A sorszámozás 0-tól indul :


00100101b !

10. Mire használhatjuk a not utasítást ?

35
Forrás: http://www.doksi.hu

4. Logikai utasítások

36
Forrás: http://www.doksi.hu

5. Feltételnélküli és feltételes ugr ó utasítások

Eljutottunk arra a fokra, hogy egyszerű adatokon adatmozgatást, aritmetikai és

Σ logikai műveleteket tudunk végrehajtani. Ez az állapot csak program


szekvenciák elôállítását teszi lehetôvé, vagyis utasítások egymásutánjának a
végrehajtását.

Ahhoz, hogy egy feltétel szerint el tudjunk ágazni két vagy több irányba - azaz
szelekciót tudjunk végrehajtani - , meg kell ismerkednünk a feltételnélküli és
feltételes ugró utasításokkal. Ebben a fejezetben a feltételnélküli és feltételes
ugróutasításokat tárgyaljuk.

5.1 Feltételnélküli ugr ó utasítás : j mp

Szintaxis : JMP <cimke>

Az j mp utasítás az ôt követô cimkére adja át a vezérlést, tehát a programunk


nem a következô utasításon, hanem a címkéhez tartozó utasításon folytatódik.
Magas szintű nyelveken a j mp megfelel a sokak által szidott goto utasításnak.
Mint látni fogjuk néhány esetben elkerülhetetlen a használata.

Amennyiben a cimke az ugrás helyétôl egy elôjeles byte-nyi távolságra van

! ( -127 ill. +128 byte ), ebben az esetben a j mp utasítás relatív cimzést használ.
Ez azt jelenti, hogy az ugrás távolsága elôjelesen hozzáadódik az IP regiszter
tartalmához, ezáltal megvalósul a vezérlésátadás.

Abban az esetben ha az ugrás helye távolabb van mint amit egy elôjeles byte-
on ábrázolni tudunk, abszolút cimzéssel hajtódik végre a j mp. Ez pedig azt
jelenti, hogy a cimkéhez tartozó offset cím kerül az IP regiszterbe, azaz símán
felülíródik az IP regiszter tartalma. A címkéhez tartozó offset cím a
szimbólumtábla alapján érhetô el.

Amennyiben a programozó biztosan tudja, hogy az ugrás távolsága belül esik a


-127 ill. +128 byte-os határon úgy a shor t operátort alkamazva, direkt módon
elôírhatja a relatív címzéssel végrehajtott ugrást.

Példa : jmp short cimke1 ; a program cimke1-en folytatódik


Forrás: http://www.doksi.hu

5.2 Feltételes ugró utasítások


; a jmp végrehajtása relatív cimzéssel
; történik

5.2 Feltételes ugr ó utasítások

A feltételes ugró utasítások használata rendkívül megnöveli programunk


intelligenciáját, hiszen segítségükkel feltételtôl függô elágazásokat ( szelek-
ciókat ) tudunk megvalósítani. A feltételes ugró utasításoknak három csoportja
van. Mindhárom csoport relatív címzést használ, vagyis a feltételes ugró
utasításokkal -127 vagy +128 byte-ot tudunk ugrani. A - elôjel az ugrás
szempontjából a visszafelé, a + elôjel az elôre irányt jelenti. A viszonyítási
alap mindig az a hely ahol az ugrási parancsot kiadtuk ( az ugrás helye ).
Amennyiben nagyobb távolságra akarunk ugratni, akkor természetesen
gondoskodnunk kell a megoldásról. Ezt a késôbbiek során tárgyalom.

5.2.1 Elôjel nélküli mennyiségekkel kapcsolatos utasítások

Az ugró utasítások használata elôt természetesen szükség van egy össze-


hasonlító műveletre. Ez a mi esetünkben a cmp utasítás lesz. Abban az
esetben, ha a következô összehasonlítást végezzük el :

cmp op1,op2 ; op1 és op2 elôjelnélküli mennyiségek

akkor a következô feltételes ugró utasításokat használhatjuk :

ja cimke ; ugrás ha op1 > op2


jb cimke ; ugrás ha op1 < op2
je cimke ; ugrás ha op1 = op2
jae cimke ; ugrás ha op1 >= op2
jbe cimke ; ugrás ha op1 <= op2

Érvényes ennek az öt esetnek a tagadása is :

jna cimke ; ugrás ha op1 <= op2


jnb cimke ; ugrás ha op1 >= op2
jne cimke ; ugrás ha op1 != op2
jnae cimke ; ugrás ha op1 < op2
jnbe cimke ; ugrás ha op1 > op2

37
Forrás: http://www.doksi.hu

5. Feltételnélküli és feltételes ugró utasítások

Látható, hogy a rendelkezésre álló alakok rendundanciát tartalmaznak. A


program környezetétôl függôen viszont, az egyik alak jobban kiemelheti a
lényeget, mint a vele megegyezô működésű másik.

Példa : cmp al,20 ; al-ben 30 van


ja ide ; a program az ide cimkén folytatódik

5.2.2 Elôjeles mennyiségekkel kapcsolatos utasítások

Abban az esetben, ha a következô összehasonlítást végezzük el :

cmp op1,op2 ; op1 és op2 elôjeles mennyiségek

akkor a következô feltételes ugró utasításokat használhatjuk :

jg cimke ; ugrás ha op1 > op2


jl cimke ; ugrás ha op1 < op2
je cimke ; ugrás ha op1 = op2
jge cimke ; ugrás ha op1 >= op2
jle cimke ; ugrás ha op1 <= op2

Érvényes ennek az öt esetnek a tagadása is :

jng cimke ; ugrás ha op1 <= op2


jnl cimke ; ugrás ha op1 >= op2
jne cimke ; ugrás ha op1 != op2
jnge cimke ; ugrás ha op1 < op2
jnle cimke ; ugrás ha op1 > op2

A rendelkezésre álló alakok itt is rendundanciát tartalmaznak.

Példa : cmp al,20 ; al-ben 30 van


jg ide ; a program az ide cimkén folytatódik

5.2.3 Flagek értékétôl függô utasítások

Ezek az utasítások a következôk :

38
Forrás: http://www.doksi.hu

5.2 Feltételes ugró utasítások


jc cimke ; ugrás, ha CF = 1
js cimke ; ugrás, ha SF = 1
jo cimke ; ugrás, ha OF = 1
jz cimke ; ugrás, ha ZF = 1
jp cimke ; ugrás, ha PF = 1
jpe cimke ; ugrás, ha PF = 1
jpo cimke ; ugrás, ha PF = 0

Ahogy az elôzôekben láttuk, mindegyik utasításnak érvényes a tagadása is :

jnc cimke ; ugrás, ha CF = 0


jns cimke ; ugrás, ha SF = 0

jno cimke ; ugrás, ha OF = 0


jnz cimke ; ugrás, ha ZF = 0
jnp cimke ; ugrás, ha PF = 0
jnpe cimke ; ugrás, ha PF = 0
jnpo cimke ; ugrás, ha PF = 1

A redundanciára vontakozó megállapítás a PF-re nézve ugyancsak érvényes !

Példa : mov ah,1


int 21h ; egy karaktert olvasunk az al regiszterbe
cmp al,13 ; ENTER volt ?
jz sor1 ; ha igen akkor a sor1 cimkén folytatódjon
; a program
...

sor1: ; itt jönnek a sor1 cimkéhez tartozó utasítá-


; sok

A fejezet elején említettem, hogy elôfordulhat az az eset amikor a -127 ill.


+128 byte távolságnál nagyobbat kell ugranunk. Ebbôl probléma származik,
ugyanis a feltételes ugó utasításokkal csak ez a távolság kezelhetô. Ez a
probléma a jmp utasítás használatával oldható meg :
!
Példa : cmp ax,40 ; ax-ben 50 van
ja cimke ; a cimke-re kell ugratnunk

; az ugrás helye és célja közötti távolság 200 byte

cimke: ; itt jönnek a cimke-hez tartozó uta-


; sítások

39
Forrás: http://www.doksi.hu

5. Feltételnélküli és feltételes ugró utasítások


Mivel 200 byte-ot nem tudunk a j a utasítással átugrani, ezért a
következô megoldást alkalmazzuk :

Példa : cmp ax,40 ; ax-ben 50 van


jbe tovabb ; ez nem teljesül
jmp cimke ; ez hajtódik végre
tovabb: ; itt jönnek a tovabb-hoz tartozó uta-
; sítások

cimke: ; itt jönnek a cimke-hez tartozó uta-


; sítások

Nézzük meg a feltételes ugróutasítások használatát egy rövid programon !


Beolvasunk két karaktert, összehasonlítjuk ôket, majd kiirjuk az össze-
hasonlítás eredményét :

3. sz. példaprogram :

.MODEL small
.STACK 100h
.DATA
c1 db ?
c2 db ?
nagy12 db ' 1 > 2 ','$'
kis12 db ' 1 < 2 ','$'
egy12 db ' 1 = 2 ','$'
sorem db 0dh,0ah,'$'
.CODE
mov ax,@data
mov ds,ax
mov ah,1
int 21h
mov [c1],al ; Elsô karakter C1-ben
int 21h
mov [c2],al ; Második karakter C2-ben
;
cmp [c1],al ; Elsô összehasonlítva másodikkal
je egyen ; Ha egyenlôk, akkor ugrás EGYEN-re
jb k1_2 ; Ha elsô < második, akkor ugrás
; K1_2-re

mov dx,OFFSET nagy12 ; Egyébként elsô > második


jmp kiir
egyen: mov dx,OFFSET egy12

40
Forrás: http://www.doksi.hu

Ellenôrzô kérdések és feladatok


jmp kiir
k1_2: mov dx,OFFSET kis12
kiir:
mov ah,9 ; DOS print string funkcio
int 21h
mov ah,2 ; Egyik karakter kiiratása
mov dl,[c1]
int 21h
mov dl,20h ; Szóköz kiiratása
int 21h
mov dl,[c2] ; Másik karakter kiiratása
int 21h
mov ah,9 ; Soremelés kiiratása
mov dx,OFFSET sorem
int 21h
mov ah,1
int 21h ; Várakozás egy billentyűre
mov ah,4ch ; DOS programbefejezes funkcio
int 21h
END

Ellenôr zô kér dések és feladatok

01. Mire szolgál a jmp utasítás, milyen működési módjai vannak ?

02. Mire szolgálnak a feltételes ugró utasítások, mely három típusba


sorolhatóak ?

03. Hogyan tudjuk megvalósítani a -127 ill. +128 byte intervallumon


kivülesô távolságú ugrásokat ?

04. Irjon programot amely annyival bôvíti a 3. sz. példaprogramot, hogy a


két beolvasott karaktert a nagyságuk szerinti sorrendben írja vissza a
képernyôre. Például : beolvasva : b,a - kiírva : a,b.

05. Irjon programot amely három karaktert olvas be. Elsô lépésben döntse
el, hogy a három karakter közül melyik a legnagyobb. Második
lépésben rakja ABC sorrendbe a három karaktert, és így irassa ki ôket a
képernyôre !

41
Forrás: http://www.doksi.hu

5. Feltételnélküli és feltételes ugró utasítások


06. Tegye intelligensebbé a 05. sz feladatban szereplô programot. A
kiiratás után kérdezze meg a program, hogy akarunk-e még karakter
hármasokat beolvasni. Ha a válasz igenlô ( ‘ i’ vagy ‘ I’ ), akkor adja
vissza a vezérlést a beolvasásra. Ezt egész addig ismételje, amíg a
kérdésre az ‘ n’ vagy ‘ N’ billentyűk valamelyikét nyomjuk le !

07. Irjon programot, amely beolvas egy számjegynek megfelelô karaktert,


és átalakítja számmá ! Például az ‘ 1’ -bôl 1-et csinál ! ( Az ‘ 1’ ASCII
kódja 49 ).

08. Irjon programot, amely beolvas egy kétjegyű számnak megfelelô két
karaktert, és átalakítja számmá ! Például az ‘ 1’ ‘ 2’ -bôl 12-ôt csinál !

09. Irjon programot, amely beolvas három darab kétjegyű számnak


megfelelô karaktersorozatot. A karaktersorozatot alakítsa át kétjegyű
számokká, és döntse el hogy a számok alapján szerkeszthetô-e
háromszög.

10. Tegye intelligensebbé a 09. sz feladatban szereplô programot ! A


program jelezze, ha nem számjegynek megfelelô karaktert
billentyűztünk és kérje be újra a karaktert !

11. Irjon programot amely egy négyjegyű szám számjegyeit olvassa be,
majd elvégzi a számmá alakítást ! Ezután bontsa le megint
számjegyekre, és fordított sorrendben írja ki a számjegyeket a kép-
ernyôre.

42
Forrás: http://www.doksi.hu

6. Ciklusszer vezô utasítások

Σ
A feltételnélküli és feltételes ugró utasítások ismertetése után a ciklusszervezô
utasításokkal ismerkedünk meg. A ciklusszervezô utasítások a harmadik
alapvetô programstruktúra - az iteráció - megvalósítására szolgálnak.
Segítségükkel tehát egy programrészlet végrehajtását többször is megismétel-
hetjük. Ebben a fejezetben mutatom be a Turbo Debugger ( TD.EXE )
használatát is.

6.1 A loop utasítás

Szintaxis : LOOP <cimke>

Jelenlegi tudásunk alapján a következôképpen szervezhetnénk ciklust :

Példa : mov cx,10


cikl: .
. ; itt jönnek a ciklusmag utasításai
.
dec cx
jnz cikl

A loop utasítás a dec cx, j nz cikl utasításokat valósitja meg ebben az esetben :

Példa : mov cx,10


cikl:
.
.
.
loop cikl

A loop utasításról elmondhatjuk tehát, hogy a cx tartalmát eggyel csökkenti,


majd - ha cx tartalma nem egyenlô nullával - az utána írt címre adja a
vezérlést. Amennyiben cx tartalma nullával egyenlô, úgy a loop utasítást
követô utasításon folytatódik a program.

A loop utasítás csakis és kizárólag a cx regiszterrel működik együtt ! A loop

!
utasítás egy elôjeles byte-on ábrázolja az ugrás hosszúságát, tehát -127 byte-
nál többet nem lehet visszafelé ugratni ! Ennél hosszabb ciklusok tehát nem
Forrás: http://www.doksi.hu

6.2 A loope és a loopne utasítások


szervezhetôk a loop utasítással. A loop utasítás abban a tekintetben nem
egyezik meg a dec cx, j nz cimke utasításpárral, hogy egyetlen flaget sem
befolyásol, míg a dec utasítás igen !

Látható, hogy a loop utasítással csökkenô ciklusváltozójú ciklust tudunk csak


megvalósítani. Növekményes ciklus megvalósítását kizárólag hagyományos
eszközökkel érhetjük el, külön utasítás nem áll rendelkezésre !

Példa : mov dx,0


eleje: .
. ; A ciklus utasításai
.
inc dx
cmp dx,10 ; Dx =10 - re a ciklus befejezi működését
jnz eleje

A loop utasításnak igen hasznos módosulatai állnak rendelkezésre, amelyek


feltételes ciklusszervezést tesznek lehetôvé.

6.2 A loope és a loopne utasítások

Szintaxis : LOOPE <cimke> , LOOPNE <cimke>

Mindkét utasítás a cx regiszterrel működik együtt. A loope addig működteti a


ciklust amíg cx tartalma pozitív és a ZF = 1. A loopne addig működteti a
ciklust amíg cx tartalma pozitív és a ZF = 0. A loop utasításnál ismertetett
megkötések itt is érvényesek ! A loope helyett loopz a loopne helyett loopnz
is írható !

Példa : ; Beolvasó ciklus 20 karakterre, vagy az ENTER billentyű


; megnyomására

mov cx,20
mov ah,1
;
beo_cikl: int 21h ; karakter az al-ben
mov [kar],al ; karakter a kar nevű változóban
cmp al,13 ; összehasonlítás az ENTER kódjával
loopne beo_cikl ; ha cx tartalma pozitív és nem e-
; gyenlô 13-mal, ( cx > 0 és ZF = 0 )
; akkor folytatás a beo_cikl címkén.
... ; a program folytatása

43
Forrás: http://www.doksi.hu

6. Ciklusszervezô utasítások

Létezik még egy feltételes ugró utasítás aminek az ismertetése mégis ide
kivánkozik. Ez a j cxz utasítás. Szintaktikája a következô : jcxz <cimke>.
Abban az esetben ha a cikluba való belépés elôtt cx tartalma nulla és ezt az
utasítást leírjuk, akkor a cimkére adódik a vezérlés. A j cxz segítségével tehát
átugorhatunk egy olyan ciklust, amelynek ciklusváltozója - azaz a cx regiszter
- nulla.

Esetleg felmerülhet a kérdés, hogy miért probléma ha a cx tartalma nulla ?


 Magasszintű programnyelvek esetén ilyenkor a for ciklus egyszer sem fut le.
Mint oly sok mindenben, az assembly ebben is eltér a magasszintű nyelvektôl.
Ha a cx regiszter tartalma nulla, abban az esetben a ciklus egyszer
mindenképpen lefut, hiszen a loop utasítás csak a ciklus végén teszteli a cx
regisztert. A tesztelés elôtt azonban a loop levon egyet a cx tartalmából, tehát
annak értéke -1 lesz. A -1 hexadecimálisan ábrázolva : 0FFFFh, vagyis mind a
16 bit értéke 1. A ciklus tehát ahelyett, hogy egyszer sem fut le, 65535-ször
futna le, ha nem védenénk ki ezt az esetet a j cxz használatával !

6.3 A Tur bo Debugger használata

A Turbo Debugger használatát egy példaprogram segítségével mutatom be.


Elöljárójában annyit, hogyha használni akarjuk a debuggert, akkor ahhoz a
következô kapcsolók szükségesek a fordításnál és a linkelésnél :

Legyen a programunk neve proba.asm !

Fordítás : tasm /zi proba[.asm]


Linkelés : tlink /v proba[.obj]
Debugger : td proba[.exe]

A [] zárójelpárban szereplô karakterek opcionálisak.

A debugger (“ rovartalanító” ) arra alkalmas, hogy akár lépésenként is tudjuk


futtatni a programunkat ha ez szükséges, illetve regiszterek és/vagy memória-
változók értékeinek alakulását kisérjük figyelemmel. Ezenkívül sok lehetôség
áll rendelkezésre. Megfigyelhetjük a stack illetve a flagek állapotát külön -
külön illetve együtt a CPU panelen is. A debugger legfelsô sorában egy
legördülô menüsor található, ennek segítségével választhatunk a különféle
opciók között. Most nézzünk meg pár funkciót részletesen a következô
példaprogram segítségével : Bekérünk egy számjegynek megfelelô karaktert,
majd számmá alakítjuk ( levonunk belôle 48-at, azaz a ‘ 0’ ASCII kódját ).

44
Forrás: http://www.doksi.hu

6.3 A Turbo Debugger használata


Ezután a számot egy integer alsó byte-jának tekintve, megfordítjuk az integer
alsó és felsô byte-ját, például az 1-bôl 256 lesz.

4. sz. példaprogram :

.MODEL small
.STACK 100h
.DATA
szam DW 0
.CODE
mov ax,@data
mov ds,ax ; DS regiszter inicializálása
;
;
xor ax,ax ; AX regiszter nullázása
mov ah,1
int 21h ; Egy karakter bekérése
;
xor ah,ah ; AH regiszter nullázása
sub al,48 ; Numerikus értékké alakítás
;
xchg ah,al ; Az integer (AX) megfordítása
;
mov [szam],ax

mov ah,4ch ; Visszatérés a DOS-hoz


int 21h
END

Tételezzük fel, hogy programunk neve int_swap.asm. Ebben az esetben a


következô lépéseket kell végrehajtani :

For dítás : tasm /zi int_swap


L inkelés : tlink /v int_swap
Debugger : td int_swap

Természetesen az int_swap kiterjesztése lépésenként rendre : .asm, .obj, .exe!

Miután a td-t elindítottuk kék háttéren sárga betűkkel megjelenik a progra-


munk forrásszövege. A képernyô legfelsô sorában egy menüsor látható, a kék
hátterű program ablak alatt pedig egy szürke hátterű “ watch” ablak, ahol majd
a kijelölt változoink értékét követhejük figyelemmel. A képernyô baloldalán,
közvetlenül a .CODE direktíva után egy balramutató nyíl jelzi, hogy a
debugger a programunk elejére állt.

45
Forrás: http://www.doksi.hu

6. Ciklusszervezô utasítások
Mielôtt elindítanánk a programunkat, jelöljük ki megfigyelésre a szam
változót illetve az ax, al, ah regisztereket. Ezt úgy tehetjük meg, hogy a
programunkban a kurzort - az egér, vagy a billentyűzet segítségével - ráállítjuk
a kívánt változó vagy regiszter nevére és lenyomjuk a <CTRL> <W>
billentyűkombinációt. Ezen művelet hatására a képernyô alján rendre
megjelennek a kijelölt regiszterek illetve a szam változó nevei, valamint az
éppen aktuális értékük.

Ha most az <F8> billentyű segítségével lépésenként futtajuk a programunkat,


akkor a következôket figyelhetjük meg :

- Egy <F8> lenyomása egy sorral viszi lejjebb a balramutató nyilat.

- Az int 21h utasításhoz érve a debugger átadja nekünk a vezérlést, abból


a célból, hogy billentyűzhessünk egy karaktert. Ennek megtétele után a
billentyűzött karakter ASCII kódja az al regiszterbe kerül.

- Most látható, hogy miért kell 48-at kivonni az al regiszter tartalmából.


Ha az 1-et billentyűztük, akkor az al-be 49 kerül, ha ebbôl 48-at
kivonunk , akkor kapjuk meg az 1-et.

- Az xchg ah,al utasítás végrehajtása után látszik, hogy az integer -


vagyis az ax regiszter tartalma - valóban “ megfordult” , hiszen az ax
regiszter tartalma 256 lett.

- Utolsó elôtti lépésként kiírjuk ezt azt értéket a szam változóba, majd
visszadjuk a vezérlést a DOS-nak.

Amennyiben újra szeretnénk futtatni a programot, akkor a <CTRL > <F2>


billentyű kombináció lenyomásával állíthatjuk az IP regisztert a programunk
elejére. A szövegkurzor a <CTRL > <O> lenyomására áll a programszöveg
elejére.

Természetesen a szövegkurzor program elejére történô állítása nem helyettesíti

! az IP regiszter inicializálását !

Amennyiben egy lépésben szeretnénk lefuttatni a programot úgy az <F9>


billentyűt nyomjuk le !

Lehetôség van arra is, hogy a programnak egy részét egy lépésben, míg a
fennmaradó részt lépésenként futtassuk. Állítsuk a szövegkurzort a mov
[szam],ax utasításra és nyomjuk le az <F4> billentyűt. Ennek hatására egy
lépésben történik meg a karakter bekérése, a 48 kivonása az al regiszterbôl
valamint az ah és al megcserélése, majd a program végrehajtása megáll az
általunk kijelölt utasításon és innét lépésenként hajthatjuk végre. Ez a

46
Forrás: http://www.doksi.hu

Ellenôrzô kérdések és feladatok


lehetôség különösen akkor jó, ha a programunk egy részét már “ belôttük” , és
nem akarjuk lépésenként futtatni.

A Turbo Debugger ilyen szintű ismerete már elégséges ahhoz, hogy


programjainkat javítani tudjuk. További ismeretek a debugger help menüjében
állnak rendelkezésre.

A fejezetet egy további példaprogrammal zárjuk. Egy olyan programot írunk,


amely maximum 70 karaktert olvas be, de ha az <ENTER> billentyűt
lenyomjuk, akkor vége van a beolvasásnak. Beolvasás közben meg kell
számolni, hogy hány darab számjegyet billentyűztünk, és ezt a mennyiséget ki
kell iratni az szj változóba !

5. sz. példaprogram :

.MODEL small
.STACK 100h
.DATA
;
szj dw 0
;
.CODE
mov ax,@data
mov ds,ax
;
mov cx,70
xor ax,ax
mov dx,0 ; DX-ben számoljuk a számjegyeket
mov ah,1
;
beolv: int 21h
cmp al,'0'
jb nem ; Ha kisebb mint '0', akkor nem számjegy
cmp al,'9'
ja nem ; Ha nagyobb mint '9', akkor sem számjegy
;
inc dx ; Ha egyik sem tejesül akkor számjegy volt !
nem: cmp al,13 ; ENTER-re vizsgálunk
loopne beolv
;
mov [szj],dx
;
mov ah,4ch
int 21h
END

Ellenôr zô kér dések és feladatok

47
Forrás: http://www.doksi.hu

6. Ciklusszervezô utasítások

01. Mire használjuk a loop utasítást, melyik regiszterrel működik együtt ?

02. Meddig működik a ciklus loope és meddig loopne esetén ?

03. Hogyan írna meg egy 128 byte-nál hosszabb ciklust ?

04. Miért okoz problémát, ha a cx regiszter 0 kezdô értékével akarunk


belépni egy loop ciklusba ?

05. Módosítsa úgy a 4. sz. példaprogramot, hogy jelezze azt, ha nem


számjegyet billentyűztünk ?

06. Irjon programot amely hasonló az 5. sz. példaprogramhoz, csak nem a


számjegyek, hanem a magánhangzók számát állapítja meg ! Magán-
hangzók alatt csak az ‘ a’ , ‘ e’ , ‘ i’ , ‘ o’ , ‘ u’ értendô !

07. Irjon programot amely nem az <ENTER>, hanem az <Esc> billentyűre


fejezi be a karakterek beolvasását, és a karakterek száma nincs
korlátozva. Meg kell állapítani, hogy hány sort és hány mondatot
gépeltünk be. Mondatzáró karakterek : ‘ .’ , ‘ !’ , ‘ ?’ . Az <Esc> billentyű
ASCII kódja : 27 (1bh).

48
Forrás: http://www.doksi.hu

7. M emór ia címzési módok

Σ
Az elôzô fejezet alapján rendelkezésre állnak a vezérlésátadó uatsítások is. Az
igazán hatékony programok elkészítését többek között azonban az gátolja,
hogy csak egyszerű változókat tudunk kezelni az eddig tanultak alapján. A
most következô fejezetben megismerkedünk az i8086-os processzor memória
címzési módjaival, amelyek a következôk : közvetlen operandusú, direkt,
indirekt, indexelt. Ezután képesek leszünk összetet adatokkal ( vektorok,
mátrixok ) dolgozni.

7.1 K özvetlen oper andusú címzés

A közvetlen operandusú címzést már használtuk. A nevét onnan kapta, hogy a


forrásoperandus kódja része lesz az utasítás gépi kódjának.

Példa : mov ax,7

7.2 Dir ekt címzés

A direkt címzést is használtuk már. Az elnevezés onnan ered, hogy a forrás-


operandusra közvetlenül a nevével hivatkozunk.

Példa : mov ax,[adat] ; az adat egy dw típusú változó

Látható, hogy ezzel a két címzési móddal nem tudnánk kezelni egy vektort,
ugyanis egyik móddal sem tudunk indexelni. Az az eljárás pedig, hogy a vek-
tor mindegyik elemét egyszerű változóként kezeljük, gyakorlatilag megvaló-
síthatatlan. A következô két címzési mód teszi lehetôvé az összetett adatszer-
kezetek kezelését.

7.3 I ndir ekt címzés

Mint a neve is mutatja, az operandusra nem az értékével és nem is a nevével


fogunk hivatkozni ! Ebben az esetben az operandusra a címével hivatkozunk,
Forrás: http://www.doksi.hu

7.3 Indirekt címzés


amelyet egy regiszterben fogunk eltárolni. Ez a regiszter aztán tetszés szerint
növelhetô illetve csökkenthetô, tehát a következô vagy az elôzô elem címét
tudjuk elôállítani, azaz képesek vagyunk indexelni !

Címregiszterként csak a bx, si, di regiszterek használhatók !


!
Példa : ; indirekt hivatkozás egyszerű változóra

mov bx, OFFSET adat1 ; bx-ben lesz az adat1 címe


.
. ; utasítások
.
mov ax,[bx] ; ax-be kerül a bx által muta-
; tott címen lévô adat, tehát az
; adat1 változó tartalma.

Példa : ; indirekt hivatkozás összetett változóra

.DATA
adat2 db ‘ 12345’
.
. ; további adatdefiníciók
.
.CODE
.
. ; utasítások
.
mov si,OFFSET adat2
.
. ; utasítások
.
mov ah,2
mov cx,5
kiir: mov dl,[si] ; kiiratjuk az adat2 karakter-
int 21h ; vektor öt elemét.
inc si
loop kiir

Abban az esetben, ha az indirekt hivatkozást tartalmazó kifejezés másik tagja


regiszter, tehát egyértelműen kijelöli a műveleti szélességet, akkor nincs
semmi tennivalónk. Abban az esetben viszont, ha a másik operandus például !
egy konstans, akkor nekünk kell kijelölni a műveleti szélességet. Arról ugyanis
nem készül nyilvántartás, hogy a címregiszterben lévô címen milyen típusú

49
Forrás: http://www.doksi.hu

7. Memória címzési módok


adat található. A műveleti szélességet a BYTE PTR és a WORD PTR
operátorokkal jelölhetjük ki.

Példa: mov [bx],1 ; az 1 8 biten is kiirható, de 16 biten


; is. Nekünk kell tehát eldönteni,
; hogy hány bites legyen a műveleti
; szélesség !
mov BYTE PTR [bx],1 ; kiirás 8 biten
mov WORD PTR [bx],1 ; kiirás 16 biten

7.4 I ndexelt címzés

Az indexelt címzésben két regiszter is részt vehet a cím kiszámításban, az


egyiket bázis-, a másikat indexregiszternek hívjuk. Mátrixok kezelésére ez a
címzés alkalmasabb mint az elôbbi. Az indexelt címzés általános képlete a
következô :

Telj es cím = [bázisr egiszter + indexr egiszter + eltolás ]

Az egyes elnevezések a következôket jelentik és az alábbi értékeket vehetik fel


:

bázisregiszter : Ezzel a regiszterrel mondjuk meg, hogy az


adat-, vagy a stack szegmenshez képest
kívánunk e címezni. Amennyiben bx az
értéke akkor elôbbi, amennyiben bp az
értéke, akkor utóbbi.

indexregiszter : A bázis regiszterhez viszonyított másik


címösszetevôt tartalmazza. Értéke az si
regiszter illetve a di regiszter lehet.

eltolás : A teljes cím konstans része. Értéke egy


memór iacím, vagy egy konstans lehet. A
következôkben mindegyikre látunk majd
példát !

Az eddigi ismereteinket felhasználva a képletünk a következôképpen alakul :

BX SI

50
Forrás: http://www.doksi.hu

7.4 Indexelt címzés

Telj es cím = vagy + vagy + Eltolás

BP DI

A képletet kifejtve 16 konkrét memóriacímzési módot tudunk elôállítani :

01. [eltolás] (direkt címzés) 05. [bx + si]


02. [bx] (indirekt címzés) 06. [bx + di]
03. [si] (indirekt címzés) 07. [bp + si]
04. [di] (indirekt címzés) 08. [bp + di]

09. [bx + eltolás] 13. [bx + si + eltolás]


10. [bp + eltolás] 14. [bx + di + eltolás]
11. [si + eltolás] 15. [bp + si + eltolás]
12. [di + eltolás] 16. [bp + di + eltolás]

Abban az esetben, ha az eltolás memóriacím, a [bx + si + eltolás] alak a


következôképpen is írható : eltolás[bx][si]. Az írásmód nem változtatja meg a
címzés működését. A két regiszter tartalma összeadódik, ehhez hozzáadódik az
eltolás és így jön létre a teljes cím !

Példa : mov ax,[matrix + bx +si] ; ax-be kerül a matrix aktuális


; eleme.
mov ax,matrix[bx][si] ; ugyanazt a műveletet hajtja
; végre, mint az elôzô utasítás

Az i8086-os assemblyben nem létezik pointeraritmetika, mint a C nyelvben. Itt


nekünk kell arra ügyelnünk, hogy a címzésben szereplô regisztereket, helyesen
inkrementáljuk vagy dekrementáljuk. Nyilvánvaló, hogy db változótípus esetén
az indexregisztert elég eggyel növelni, hogy a következô elem címét
!
megkapjuk, de dw típusnál kettôt kell az index regiszterhez hozzáadni, mivel
az integer változó hossza két byte !

A most következô példaprogramban beolvasunk egy maximum 40 hosszú kis-


betűs karaktersorozatot, átalakítjuk nagybetűssé és kiiratjuk.

6. sz. példaprogram :

.MODEL small
.STACK 100h
.DATA

51
Forrás: http://www.doksi.hu

7. Memória címzési módok


kars db 40 dup(?)
nagy db 41 dup(?)
sorem db 0dh,0ah,'$'
;
.CODE
mov ax,@data
mov ds,ax
;
mov si,0
mov cx,40
;
beo: mov ah,1 ; Itt kezdôdik a beolvasó ciklus
int 21h
mov kars[si],al
inc si ; Csak eggyel kell növelni az
; indexregisztert
cmp al,0dh
loopne beo
;

mov cx,si
mov si,0
;
konv: ; Itt kezdôdik az átalakítás
mov al,kars[si]
cmp al,'a'
jb n_kis
cmp al,'z'
ja nkis
sub al,20h ; A kisbetű és a nagybetű ASCII
; kódja között 20h a különbség
nkis: mov nagy[si],al
inc si
loop konv

mov nagy[si],'$' ; A kiiratás miatt kell !


xor ax,ax
mov ah,9
mov dx,OFFSET nagy
int 21h
mov dx,OFFSET sorem
int 21h
;
mov ah,4ch
int 21h
END

52
Forrás: http://www.doksi.hu

7.4 Indexelt címzés


A következô példaprogramban két 10 elemű integer vektort adunk össze.
Figyeljük meg, hogy itt már nem elég az indexregiszter eggyel való növelése,
hiszen az integer változó hossza 2 byte ! A példaprogram eredményét egyelôre
a Turbo Debugger ( továbbiakban TD ) segítségével tudjuk megtekinteni.

7. sz. példaprogram :

.MODEL small
.STACK 100h
.DATA
;
v1 dw 1,2,3,4,5,6,7,8,9,10
v2 dw 1,2,3,4,5,6,7,8,9,10
v3 dw 10 dup(0)
;
.CODE
mov ax,@data
mov ds,ax
;
mov si,0
mov cx,10
;

ad:
mov ax,v1[si]
add ax,v2[si]
mov v3[si],ax
inc si ; Az SI indexregisztert kettôvel
inc si ; kell növelni !
loop ad
;
mov ah,4ch
int 21h
END

A következô példaprogramban egy C típusú ( bináris nulla lezárású ) string


hosszát fogjuk megállapítani. A hossz változóban lévô értéket a TD segít-
ségével nézzük meg !

8 sz. példaprogram :

53
Forrás: http://www.doksi.hu

7. Memória címzési módok


.MODEL small
.STACK 100h
.DATA
;
szoveg db 'FRADI',0
hossz dw 0
;
.CODE
mov ax,@data
mov ds,ax
;
mov bx,0
kezd:
mov al,szoveg[bx]
cmp al,0
jz bef
inc bx ; BX tartalmazza a hosszat
jmp kezd
bef:
mov [hossz],bx
;
mov ah,4ch
int 21h
END prg

Most egy stringet fogunk átmásolni egy másik stringbe. Az eredménystringet


kiiratjuk.

9 sz. példaprogram :

.MODEL small
.STACK 100h
.DATA
innen db 'Lisztes berúgta elsô Bundesliga gólját !',0
ide db 80 dup(?)
hossz dw 0
.CODE
mov ax,@data
mov ds,ax
;
mov si,0
hossza: ; Másolandó string hosszának megállapítása
mov al,innen[si]
inc si ; SI-ben lesz a hossza
cmp al,0

54
Forrás: http://www.doksi.hu

7.4 Indexelt címzés


jnz hossza
mov [hossz],si ; Látszólag felesleges
; de célszerű kimenteni !
mov cx,[hossz]
mov bx,0
;
masol:
mov al,innen[bx]
mov ide[bx],al
inc bx
loop masol
mov ide[bx],'$' ; A kiiratás miatt kell a ‘ $’
xor ax,ax
mov ah,9
mov dx,OFFSET ide
int 21h ; Itt iratjuk ki a másolatot
;
mov ah,4ch
int 21h
END

Egy 3x3-as karaktermátrix kiiratása következik. Ehhez a mátrixot indexelnünk


kell ami azt jelenti, hogy elô kell állítanunk tetszôleges elemének a címét. Ezt
a műveletet a következô képlet segítségével tudjuk elvégezni :

Elem címe = Mátrix kezdôcíme + Sorindex* Oszlopméret + Oszlopindex

A képlet természetesen feltételezi a pointeraritmetikát. Mivel az i8086-nál ez


nem áll rendelkezésre, ezért integer mátrix esetében a képlet 2. és 3. tagját
nekünk kell megszorozni kettôvel !

10 sz. példaprogram :

.MODEL small
.STACK 100h
.DATA
;
matrix DB '1','2','3'
DB '4','5','6'
DB '7','8','9'
elemsz DW 3
sorem DB 0dh,0ah,'$'
;

55
Forrás: http://www.doksi.hu

7. Memória címzési módok


.CODE
mov ax,@data
mov ds,ax
;
mov cx,0 ; Sorindex
cikl1:
mov di,0 ; Oszlopindex
kiir :
mov al,cl
mul BYTE PTR [elemsz] ; Sorindex* Oszlopméret
mov bx,ax
mov si,di ; Oszlopindex
mov ah,2
mov dl,matrix[bx][si] ; A mátrix eleme
int 21h
mov dl,20h ; Egy szóköz kiiratása
int 21h
inc di
cmp di,[elemsz]
jnz kiir
;
mov ah,9
mov dx,offset sorem ; Soremelés kiiratása
int 21h
inc cx
cmp cx,[elemsz]
jnz cikl1
;
mov ah,9
mov dx,OFFSET sorem
int 21h

mov ah,1 ; Várunk egy billentyü lenyomására


int 21h
;
mov ah,4ch
int 21h
END

Ellenôr zô kér dések és feladatok

01. Milyen memória címzési módokat ismer az i8086-os processzor ?

56
Forrás: http://www.doksi.hu

Ellenôrzô kérdések és feladatok


02. Mi az indexelt címzés alapképlete, milyen regisztereket használhatunk
és mi ezeknek a regisztereknek a szerepe ?

03. Mi célt szolgálnak a BYTE PTR és a WORD PTR operátorok ?

04. Hogyan tudjuk “ kivédeni” azt, hogy az i8086 assembly-ben nem létezik
pointeraritmetika ?

05. Hogyan számítjuk ki egy mátrix tetszôleges elemének a címét ?

06. Irjon programot, amely beolvas egy maximum 40 hosszú karakter-


sorozatot és eltárolja egy vektorban. Másolja át egy másik vektorba, de
fordított sorrendben. Irassa ki az eredményvektort !

07. Irjon programot amely bekér két egyenlô hosszú stringet. ( Maximum
40 karakter hosszút ). Állapítsa meg, hogy melyik string a nagyobb
illetve egyenlôek-e ! A megállapítást irassa is ki a stringekkel együtt !
( Az egyik string akkor nagyobb mint a másik, ha az adott pozición
nagyobb ASCII kódú karakter áll mint a másikban ).

08. Bôvítse úgy a 07. számú programot, hogy alkalmas legyen két string
viszonyának megállapítására akkor is, ha azok nem egyenlô hosszúak.

09. Irjon programot, amely összefűz két C típusú stringet olymódon, hogy
az elsôt bemásolja egy célstringbe, majd utána fűzi a másodikat. Az
eredmény irassa ki !

10. Irjon programot, amely összefűz két C típusú stringet olymódon, hogy
az elsô string egy karakterét bemásolja egy célstringbe, majd utána a
második string egy karakterét. Elôszö a két string lehet egyenlô hosszú,
majd próbálja meg különbözô hosszú stringekkel megoldani a feladatot!
Az eredményt irassa ki !

11. Vonjon ki egymásból két 10 elemű integer tömböt. Az eredményt a


TD-vel tekintse meg !

12. Képezze két 10 elemű integer vektor skaláris szorzatát. A szorzat ered-
ményét a TD-vel tekintse meg !

13. A 10. sz. példaprogram alapján indexeljen egy 5x5-ös integer mátrixot.
Az aktuális elemet írja az ax regiszterbe és a TD-vel tekintse meg !

57
Forrás: http://www.doksi.hu

8. L éptetô és flagekkel kapcsolatos utasítások


A fejezetben szó lesz a balra illetve jobbra történô bitléptetésrôl, illetve
rotációról egy adott byte-on, vagy szón belül. Megtárgyaljuk ezek különbözô
válfajait, úgymint aritmetikai léptetés illetve rotáció a CF-en keresztül. A
fejezetet a flagekkel kapcsolatos utasítások ismertetése zárja.

8.1 Az SHL és SAL utasítások

Szintaxis : SHL <op1>,<op2> , SAL <op1>,<op2>

Az shl utasítás annyival lépteti balra az <op1> bitjeit a CF-en keresztül,


amennyivel az <op2>-ben meghatároztuk. A balra léptetett alacsony
helyiértékű bitek helyébe nullát ír. Az <op1> lehet regiszter, vagy
memóriaváltozó. Az <op2> lehet egy konstans, vagy a cl regiszter. Az sal
(aritmetikai léptetés balra) utasítás működése teljesen megegyezik az shl
utasítás működésével. Az érintett flagek a következôk : CF, PF, ZF, SF, OF.

Az i8086 assembly esetében a konstans csak 1 lehet. Amennyiben egyszerre


több bittel akarunk balra léptetni, akkor ezt a számot a cl regiszterbe kell
elôszôr írnunk és aztán alkalmazhatjuk az shl utasítást. Mind az shl, mind az
!
sal utasítás 2 hatványaival való szorzást hajt végre.

Példa : mov al,11001101b

CF Eredeti bitminta (al)

0 1 1 0 0 1 1 0 1

shl al,1 ; hatására így alakul az al tartalma

CF Balra léptetettt bitminta (al)

1 1 0 0 1 1 0 1 0

; Egyszerre több bittel léptetünk balra


Forrás: http://www.doksi.hu

8. L éptetô és flagekkel kapcsolatos utasítások


mov al,11001100b
mov cl,4
shl al,cl

8.2 Az SHR és SAR utasítások

Szintaxis : SHR <op1>,<op2> , SAR <op1>,<op2>

Az shr utasítás annyival lépteti jobbra az <op1> bitjeit a CF-en keresztül,


amennyivel az <op2>-ben meghatároztuk. A jobbra léptetett magas helyi-
értékű bitek helyébe nullát ír. Az <op1> lehet regiszter, vagy memóriaváltozó.
Az <op2> lehet egy konstans, vagy a cl regiszter. Az sar ( aritmetikai léptetés
jobbra ) utasítás működése nem egyezik meg az shr utasítás működésével. A
különbség az, hogy az sar nem nullát ír a legmagasabb helyiértékre, hanem a
léptetés utáni legmagasabb helyiértékű bit értékét ( 6. számú ), visszaírja a 7.
számú bit pozíciójába. Ezzel gyakorlatilag az eredeti bináris szám elôjelét ôrzi
meg az sar utasítás.

Az érintett flagek a következôk : CF, PF, ZF, SF, OF.

Az shl utasításnál tárgyalt <op2>-re vonatkozó megkötések itt is


érvényesek. Az shr utasítás 2 hatványaival való elôjel nélküli, míg az
sar utasítás 2 hatványaival való elôjeles osztást hajt végre.
!
Példa : mov al,11001101b

Eredeti bitminta (al) CF

1 1 0 0 1 1 0 1 0

shr al,1 ; hatására így alakul az al tartalma

SHR-rel jobbra léptetett bitminta (al) CF

0 1 1 0 0 1 1 0 1

; ha az eredeti bitmintát az sar utasítással léptetjük:


sar al,1

SAR-rel jobbra léptetett bitminta (al) CF

1 1 1 0 0 1 1 0 1

58
Forrás: http://www.doksi.hu

8.3 A ROL és RCL utasítások

; Egyszerre több bittel léptetünk jobbra

mov al,11001100b
mov cl,4
shr al,cl

8.3 A ROL és RCL utasítások

Szintaxis : ROL <op1>,<op2> , RCL <op1>,<op2>

A r ol és r cl utasítások balra történô rotációt valósítanak meg. A rotáció


hasonlít a léptetéshez ( shiftelés ), azzal a különbséggel, hogy a legalsó bit
pozicióba nem nulla íródik, hanem a kiléptetett legfelsô bit inzertálódik be. Az
<op1>-re illetve <op2>-re ugyanazok a megkötések igazak, mint a léptetô
utasítások esetén. Az r cl utasítás a CF-en keresztül végzi a rotációt, azaz a
kiléptetett legfelsô bitet a CF-be írja, és a CF értékét inzertálja a legalsó bit
pozicióba.

Az utasítások a CF és az OF flageket érintik.

Példa : mov al,11001101b

CF Eredeti bitminta (al)

0 1 1 0 0 1 1 0 1

rol al,1 ; hatására így alakul az al tartalma

ROL-lal balra léptetettt bitminta (al)

1 0 0 1 1 0 1 1

; ha az eredeti bitmintát az rcl-lel rotáljuk


rcl al,1

CF RCL-lal balra léptetettt bitminta (al)

59
Forrás: http://www.doksi.hu

8. L éptetô és flagekkel kapcsolatos utasítások


1 1 0 0 1 1 0 1 0

; Egyszerre több bittel rotálunk balra

mov al,11001100b
mov cl,4
;
shl al,cl

8.4 A ROR és RCR utasítások

Szintaxis : ROR <op1>,<op2> , RCR <op1>,<op2>

A r or és r cr utasítások jobbra történô rotációt valósítanak meg. A jobbra


történô rotáció úgy valósul meg, hogy a legfelsô bit pozicióba a kiléptetett
legalsó bit inzertálódik be. Az <op1>-re illetve <op2>-re ugyanazok a
megkötések igazak, mint a léptetô utasítások esetén. Az r cr utasítás a CF-en
keresztül végzi a rotációt, azaz a kiléptetett legalsó bitet a CF-be írja, és a CF
értékét inzertálja a legfelsô bit pozicióba.

Az utasítások szintén a CF és az OF flageket érintik.

Példa : mov al,11001101b

Eredeti bitminta (al) CF

1 1 0 0 1 1 0 1 0

ror al,1 ; hatására így alakul az al tartalma

ROR-ral jobbra léptetett bitminta (al)

1 1 1 0 0 1 1 0

; ha az eredeti bitmintát az rcr-lel rotáljuk:


rcr al,1

60
Forrás: http://www.doksi.hu

8.5 Flagekkel kapcsolatos utasítások

RCR-rel jobbra léptetett bitminta (al) CF

0 1 1 0 0 1 1 0 1

; Egyszerre több bittel rotálunk balra

mov al,11001100b
mov cl,4
;
shl al,cl

8.5 Flagekkel kapcsolatos utasítások

Mint a nevükbôl is kiderül, ezek az utasítások bizonyos flagek értékének meg-


változtatására szolgálnak. Ezek a flagek konkrétan : CF, DF, IF. Az utasítások
és hatásaik a következôk :

CLC CF = 0
CMC CF = NOT CF
STC CF = 1
CLD DF = 0
STD DF = 1
CLI IF = 0
STI IF = 1

A cld és std utasításokat az i8086-os string műveleteinél fogjuk használni, a


cli és sti utasítások pedig interrupt kezelésnél használatosak.

A most következô példaprogramban két 8 bites kódszó Hamming távolságát


számítjuk ki. Hamming távolság alatt értjük azon bitpoziciók számát,
amelyeken a kódszavak bitértékei különböznek.

11. sz. példaprogram :

.MODEL small
.STACK 100h
.DATA
kod1 db 00001101b
kod2 db 00101000b
ht dw 0

61
Forrás: http://www.doksi.hu

8. L éptetô és flagekkel kapcsolatos utasítások


.CODE
mov ax, @data
mov ds,ax
;
xor ax,ax
mov al,[kod1]
;
xor al,[kod2] ; Megállapítjuk, hogy hol különböz-
; nek a bitértékek !
clc ; Megszámoljuk, hány db 1-es bitünk
mov cx,8
;
leptet: shl al,1
jnc nem1
inc [ht]
nem1: loop leptet
mov ah,4ch
int 21h
END

A másik példaprogramban szimuláljuk a soros protokolt. Bekérünk egy


karaktert és kiiratjuk a bitjeit. Az adatátvitel egy start bittel kezdôdik, melynek
értéke 0. Ezután következik a 8 adatbit, majd a páros paritásbit. Az adatátvitelt
egy 1-es értékű stopbit zárja.

12. sz. példaprogram :

.MODEL small
.STACK 100h
.DATA
be db 'Kérem a karaktert : ','$'
kar db ?
prot db 'A soros protokoll : ','$'
sorem db 0dh,0ah,'$'
.CODE
mov ax,@data
mov ds,ax
;
mov ah,9
mov dx,OFFSET be
int 21h
mov ah,1 ; A karakter beolvasása
int 21h
mov [kar],al
;

62
Forrás: http://www.doksi.hu

8.5 Flagekkel kapcsolatos utasítások


mov ah,9
mov dx,OFFSET sorem
int 21h
mov ah,9
mov dx,OFFSET prot
int 21h
;
mov ah,2 ; START bit kiiratása
mov dl,'0'
int 21h
;
mov cx,8
mov bl,0
adatbitek:
shl [kar],1
jc egyes ; Ha 1. volt a bit
mov ah,2
mov dl,'0'
int 21h
jmp cv
egyes: mov ah,2
mov dl,'1'
int 21h
inc bl
cv: loop adatbitek
;
;
test bl,1 ; PARITAS bit kiiratása
jnz ptl ; Ha a legalsó bit nem 0 akkor
; páratlan
mov ah,2
mov dl,'0'
int 21h
jmp stopbit
ptl:
mov ah,2
mov dl,'1'
int 21h
;
stopbit: ; STOP bit kiiratása
mov ah,2
mov dl,'1'
int 21h
;
mov ah,9
mov dx,OFFSET sorem
int 21h
;
mov ah,4ch
int 21h

63
Forrás: http://www.doksi.hu

8. L éptetô és flagekkel kapcsolatos utasítások


END

Ellenôr zô kér dések és feladatok

01. Milyen megkötések érvényesek az shl illetve sal utasítások két


operandusára ?

02. Mi a különbség az shr és az sar utasítások működése között ?

03. Mi a különbség a léptetés és a rotáció között ?

04. Mi a különbség a rol és rcl valamint a ror és rcr utasítások között ?

05. Szorozza meg +8-cal a 00010100b bitmintát. Elôször lépésenként


hatjsa végre a műveletet ( egyesével léptetve ) !

06. Ossza el a -16-ot +8-cal ! A -16 binárisan : 11110000b.

07. Ossza el +8-cal lépésenként a következô bitmintát : 01110000b !

08. Irjon programot amely a következô bitminta 5. bitjét komplementálja,


de nem használhatja az xor utasítást. Az 5. bitet be kell “ csempészni” a
CF-be, ott komplementálni kell, majd vissza kell vinni a helyére ! A
bitminta a következô : 10100110b. A bitek sorszámozása 0.-tól indul !

64
Forrás: http://www.doksi.hu

9. Szubr utinok szer vezése

Σ
Ebben a fejezetben megismerkedünk a szubrutinok szervezésével és használa-
tával. A szubrutinok önálló alprogramok, amelyekre meghatározott hívási
mechanizmus segítségével adhatjuk rá a vezérlést. A hívó programba való
visszatérés is meghatározott mechanizmus szerint történik. Rokon fogalom a
C-ben a függvény fogalma.

9.1 A szubr utin for mai szer vezése és hívása

Szubrutint a következô formában tudunk megvalósítani :

sub_név PROC
.
.
.
utasítások
.
.
.
ret
sub_név ENDP

A szubrutin - fôprogramhoz képesti - elhelyezése szokás kérdése, van aki a


fôprogram elé, van aki mögé írja a szubrutinjait. Ebben a jegyzetben a
szubrutinok a fôprogram mögött helyezkednek el. Az END direktíva most is a
program legutolsó sora lesz !

Az általános definíció szerint a sub_név a szubrutin nevét jelenti, melyet a


PROC direktíva követ. Ezután a szubrutin “ testét” képezô utasítások
következnek, majd a r et utasítás. Ezen utasítás hatására tér vissza a szubrutin
az ôt hívó programba. A szubrutint a sub_név megismételt leírása, valamint az
ENDP direktíva zárja. Mivel mi a small modellt használjuk ezért a szubrutin-
hívás mindig közeli lesz, vagyis a hívás során nem lépünk ki a 64 K-s kód
szegmensbôl. Ezt a tényt az assembler a .MODEL direktíva után írt small
kulcsszó alapján regisztrálja.
Forrás: http://www.doksi.hu

9.2 A szubrutinhívás és visszatérés működése


Van arra mód, hogy elôírjuk a hívás típusát : a PROC direktíva után a NEAR
vagy a FAR direktívával megszabhatjuk ezt. Ennek megfelelôen a r et helyett a
r etn vagy a r etf utasítást kell elhelyezni a szubrutin végén.

A hívóprogramban a következô módon hívhatjuk meg a szubrutinunkat :

call sub_név

A call utasítás hatására a vézérlés átadódik a sub_név nevű szubrutinra, majd a


szubrutin végén található r et utasítás hatására a vezérlés visszaadódik a
hívóprogramra. A hívóprogram a call utasítást követô utasításon folytatódik. A
következô fejezet részletezi a szubrutinhívás működését.

9.2 A szubr utinhívás és visszatér és működése

A formai áttekintés után következzenek a lényegi dolgok. Amikor egy call


utasításhoz érkezik a programunk, akkor nyilván meg kell szakítani a szekven-
ciális végrehajtást és egy adott nevű szubrutinra kell átadni a vezérlést. Az
assembler által készített ún. szimbólumtábla segítségével a szubrutin nevéhez
egy fizikai cím rendelôdik, amely cím a call utasítás végrehajtásakor beíródik
az IP regiszterbe. Ezzel megtörtént ugyan a vezérlésátadás, de a probléma ott
van, hogy a r et utasítás “ nem tudja” , hogy hova kell visszaadni a vezérlést.
Ezért még mielôtt a szimbólumtáblában lévô fizikai címre átadnánk a
vezérlést, el kell menteni a call utasítást követô utasítás címét annak
érdekében, hogy a szubrutinbeli r et utasítás vissza tudja adni a vezérlést a hívó
programnak. Most már csak az a kérdés, hogy hova mentsük ezt az ún.
visszatérési címet ?
?
Kézenfekvô a stack-be történô mentés. Ekkor ugyanis a r et utasítás hatására
egyszerűen csak beíródik a stack tetejérôl a visszatérési cím az IP regiszterbe,
és máris megtörtént a visszatérés.

Öszefoglalva megállapíthatjuk tehát, hogy szubrutinhívásnál két lényeges


dolog történik. Elôször a call utasítást követô utasítás címe - visszatérési cím -
beíródik a stackbe. Ezután a call utasítást követô szimbólumhoz tartozó fizikai
cím beíródik az IP regiszterbe. Ezzel megtörtént a vezérlésátadás a szubrutin-
ra. A vezérlés visszadása a hívóprogramra pedig úgy történik, hogy a r et
utasítás hatására a stack tetején tárolt visszatérési cím beíródik az IP regiszter-
be. Ez a mechanizmus természetesen feltételezi azt, hogy a szubrutin ne rontsa
el a stack-et, tehát az esetleges stack használat után állítsa vissza a stack
eredeti állapotát.

65
Forrás: http://www.doksi.hu

9. Szubrutinok szervezése

Most láthatjuk, hogy mennyire kézenfekvô a stack használata szubrutin hívás-


kor. Abban az esetben ugyanis, amikor egy szubrutinból meghívunk egy másik
szubrutint - tehát két visszatérési címet kell tárolnunk - másféle adatszerkezet
nem is jöhetne szóba a visszatérési címek kezelésére. A másodjára meghívott
szubrutinban a r et utasítás hatására ugyanis azt a visszatérési címet kell
beolvasni az IP-be, amelyet késôbb mentettünk el.

9.3 Par améter át - és visszaadás kér dése

Elvileg természetesen léteznek olyan szubrutinok, amelyeknek sem bemenô


paraméterük nincs és értéket sem adnak vissza. Általában azonban azért
alkalmazunk szubrutint, hogy bizonyos adatokon bizonyos művelete(ke)t
hajtsunk végre. Gyakran elôfordul az az eset is, hogy a szubrutin valamilyen
értéket ad vissza, valamely művelet eredményeként. Mindenképpen jogos tehát
a kérdés:

? Milyen módon adhatunk át paramétereket egy szubrutinnak ?

A paraméterátadás öt módját különböztetem meg és a késôbbiekben mind-


egyikre látunk példát.

1. Paraméter értékének átadása regiszteren keresztül.


2. Paraméter címének átadása regiszteren keresztül.
3. Paraméter értékének átadása stacken keresztül.
4. Paraméter címének átadása stacken keresztül.
5. Globális változó használata.

A paraméter ér tékének átadása regiszteren keresztül talán nem igényel


különösebb magyarázatot, az aktuális paramétereket a megfelelô regiszterekbe
írjuk majd meghívjuk a kívánt szubrutint.

Példa : mov ax,[adat1]


mov bx,[adat2]
call szubrut1 ; A szubrut1 nevű szubrutin az AX-ben ta-
; lálja az elsô, míg BX-ben a második para-
; méterét.

66
Forrás: http://www.doksi.hu

9.3 Paraméter át - és visszaadás kérdése


A paraméter címének regiszteren keresztül történô átadására akkor van
szükség, amikor a paraméter értékét a szubrutinban felül akarjuk írni. Ehhez -
amint azt a C nyelvben is láttuk - a paraméter címének átadására van szükség.

Példa : mov ax,OFFSET adat1


mov bx,OFFSET adat2
;
call szubrut2 ; A szubrut2 nevű szubrutin az AX-ben ta-
; lálja az elsô, míg BX-ben a második para-
; méterének a címét

Joggal kérdezhetné valaki, hogy ha regisztereken keresztül is tudunk “ közle-


kedni” egy szubrutinnal, akkor miért kell a stacket használni paraméter-
átadásra ? A válasz egyszerű :

1. Egy nagyobb és fôleg bonyolultabb programnál nem pazarolha-


tunk regisztereket pusztán paraméterátadásra. Ilyenkor egyértel-
műen a stacken keresztül történik a paraméterátadás !

2. Mint azt a késôbbiekben látni fogjuk, nem mindig választhatunk


regiszteren keresztüli vagy stacken keresztüli paraméterátadás
között ! A C nyelv és az assembly nyelv közötti kapcsolat során
a paraméterátadás a stacken keresztül valósul meg - függvény-
hívás esetén.

Ahhoz, hogy a stackbe írni illetve onnan olvasni tudjunk, két utasítást kell
megismernünk, de elôbb nézzük meg a globális változó használatát. A C
nyelven globális változó alatt a main() elôtt definiált változót értjük, ami az
egész forrásprogramra nézve látható. A mi esetünkben az adatszegmensben
definiált változó látható az egész programra nézve, tehát minden további
nélkül használhatjuk egy szubrutinban.

Természetesen ennek a megoldásnak az alkalmazása csak a legvégsô esetben


ajánlható ! !
9.3.1 A PUSH és a POP utasítások

Szintaxis : PUSH <op> , POP <op>

A push utasítás a stackbe ír 2 byte-ot és az SP regiszter értékét kettôvel


csökkenti, a pop utasítás pedig kettôvel növeli az SP regiszter tartalmát és a
stackbôl kiolvas 2 byte-ot. Az <op> lehet 16 bites regiszter, vagy 16 bites

67
Forrás: http://www.doksi.hu

9. Szubrutinok szervezése
memóriaváltozó. Az utasítások a flageket nem érintik. A következô kis
példaprogramot érdemes TD alatt lefuttatni úgy, hogy közben a VIEW
menübôl a CPU panelt választjuk, és ott a jobb alsó sarokban figyeljük a stack
helyzetének alakulását.

13. sz. példaprogram :

.MODEL small
.STACK 100h
.DATA
adat dw 0
;
.CODE
mov ax, @data
mov ds,ax
;

mov ax,1
mov bx,2
mov [adat],3
;
push ax
push bx
push [adat]
;
mov ax,0 ; Kinullázzuk ôket, hogy ellenôrizni
mov bx,0 ; tudjuk a kiolvasás helyességét.
mov adat],0
;
pop [adat]
pop bx
pop ax
;
mov ah,4ch
int 21h
END

Ezekután nézzünk meg egy példát stacken keresztüli paraméterátadásra :

A fôpr ogr am :
.
.
.
push ax ; Az ax-ben lévô paraméter a stackbe kerül
call szubrut5 ; Meghívjuk a szubrutint

68
Forrás: http://www.doksi.hu

9.3 Paraméter át - és visszaadás kérdése


add sp,2 ; Helyreállítjuk a stacket, errôl majd késôbb !
.
.
.

A stack a következôképpen néz ki a szubr utin hívás után :

96
OFFSET R. A. 98
AX 100

Az R. A. rövidítés a Return Adress ( Visszatérési Cím ) kifejezésbôl ered. Mint


tudjuk a szubrutinhívásnál ez a cím mindenképpen a stackben tárolódik. Az SP
regiszter értéke 96, a stack tetejére mutat. Az egyszerűbb kezelhetôség
érdekében decimális számokat alkalmazunk.

Megtörtént a vezérlésátadás a szubr ut5 szubrutinra amely - mivel a stackbôl


fogja “ kihalászni” a paraméterét - használni fogja a BP regisztert. Ezért elôbb
a BP regisztert el kell menteni a stackbe. Ezáltal az SP regiszter értéke 94 lesz.
Az eredeti paraméter tehát relatíve 4 egységgel nagyobb címen helyezkedik el,
mint az SP aktuális értéke. Ezt a tényt használja ki a szubrutin.

A szubr utin :

szubrut5 PROC
push bp ; BP-t a stackbe mentjük
mov bp,sp ; Most BP értéke is 94
.
.
.
mov bx,[bp+4] ; Indexelt címzéssel érjük el a paraméterün-
; ket, amely most a BX-be került.
.
.
.
pop bp ; Hatására a stack teteje a BP regiszterbe író-
; dik és az SP értéke 96 lesz.
ret ; Hatására a stack tetejérôl az R. A. az IP
;regiszterbe íródik, és megtörténik a

69
Forrás: http://www.doksi.hu

9. Szubrutinok szervezése
;vezérlés visszaadása a hívóprogramra. Az
;SP értéke 98 lesz.
szubrut5 ENDP

Látható, hogy a hívóprogramba úgy térünk vissza, hogy az SP regiszter


tartalma nem felel meg annak a tartalomnak amellyel meghívtuk a szubrut5
szubrutint. Ezért a stacket úgymond helyre kell állítani. Ezzel kapcsolatban
kétféle konvenció alakult ki :

- A Pascal konvenció szerint a hívott pr ogr am állítja vissza a


stacket. Jelen esetben a ret 2 utasítással tehettük volna ezt meg.

- A C konvenció szerint a hívott pr ogr am állítja helyre a stacket.


Ezért található a fôprogramban a call szubrut5 utasítás után az
add sp,2 utasítás !

Roppant fontos kérdés a - szubrutin által lerombolt - regiszterek mentése.


Itt szintén két szokás alakult ki. Az egyik szerint a hívó program
elôzetesen elmenti a kérdéses regisztereket és hívás után visszamenti !
ôket. A másik szerint a szubrutin menti el és vissza a regisztereket.
Akármelyiket is használjuk, gondosan dokumentáljuk a szubrutinunkat.
Amellett, hogy feltüntetjük a paramétereit, funkcióját és lehetséges visszaadott
értékét, feltét-len tüntessük fel az általa lerombolt regisztereket is !

A szubrutin által visszadott érték háromféleképpen kerülhet vissza a hívó -


programba :

1. Visszaadott érték regiszterben. C nyelv és assembly kapcsolat


esetén ez a regiszter egyértelműen az AX regiszter !
2. Visszadott érték memória változóban. Ez rendszerint úgy műkö-
dik, hogy a memóriaváltozó címét kapja meg bemenô paraméte-
rül a szubrutin, és erre a címre írja az értéket.
3. Globális változón keresztül.

A most következô példaprogramban egy olyan hasznos szubrutinnal ismerke-


dünk meg, amely egy integert stringgé konvertál, majd kiirja a képernyôre. A
konvertálás olyan elven történik, hogy az integer tízzel való osztásának
maradéka adja a legalacsonyabb helyiértékű számjegyet. Amennyiben ehhez
48-at adok, akkor máris karakterré konvertáltam. Ehhez az eljáráshoz, a
konvertálási célterület végének a címét kell átadni, hiszen ide kerül a legala-
csonyabb helyiértékű számjegy. Ezért jelöljük meg egy LABEL BYTE
címkével a célterület vége utáni byte-ot, hogy ebbôl a címbôl egyet levonva
átadhassuk a terület végének a címét. A szubrutint neve cnts. Három
paraméterét regiszterekben kapja meg : magát az integert az AX, az elôbb

70
Forrás: http://www.doksi.hu

9.3 Paraméter át - és visszaadás kérdése


említett címet a BX, a kiirási szélességet a CX regiszter tartalmazza. A kiiró
szubrutin neve pedig prst. Paraméterét a BX regiszterben kapja meg : ez a
kiirandó string kezdôcíme.

14. sz. példaprogram :

.MODEL small
.STACK 100h
.DATA
szam DW 334
ide DB 5 DUP (20h)
vege LABEL BYTE
DB 0dh,0ah,'$'
;
.CODE
mov ax,@data
mov ds,ax
;
mov ax,[szam] ; Paraméterátadás regiszteren mov bx,OFFSET
vege - 1 ; keresztül
mov cx,5
call cnts
;
mov bx, OFFSET ide
call prst
;

mov ah,4ch
int 21h

; Itt jon a CNTS fuggveny


;
; AX : Konvertálandó szám
; DS:BX : A string végére mutató pointer, ahol
; elhelyezzük a számot
; CX : A konvertálás szélessége
;

cnts PROC

mov si,10 ; 10 az osztó

cnvlp:
sub dx,dx
div si ; Maradék a DX-ben
add dl,'0' ; Most konvertáltuk karakterré
mov [bx],dl ; Kiirjuk az aktuális címre
dec bx

71
Forrás: http://www.doksi.hu

9. Szubrutinok szervezése
and ax,ax ; Ha 0 az AX tartalma, akkor vége
jz szokoz
loop cnvlp

szokoz:

ret

cnts ENDP

; Itt jön a PRST függvény


;
; DS:BX : A stringre mutató pointer
;

prst PROC

push ax
push dx
;
mov ah,9
mov dx,bx
int 21h
;
pop dx
pop ax
ret

prst ENDP

END

Gyakorlottabb programozókban lehet, hogy már felmerült a kérdés : ezentúl


? minden elkészült szubrutint forrásszinten tartalmaznia kell az aktuális prog-
ramnak ? A választ a következôkben adom meg .

9.4 K ész szubr utinok szer kesztése, saj át könyvtár ak létr ehozása.

72
Forrás: http://www.doksi.hu

9.4 Kész szubrutinok szerkesztése, saját könyvtárak létrehozása.


Természetesen nem szükséges minden szubrutint forrásszinten
beinzertálni a fôprogramba. Az egyszer elkészített és “ belôtt” szubrutint
vagy szubrutinokat lefordítva objekt modullá, hozzá linkelhetjük a
fôprogramunk objekt modul-jához. Ehhez azonban a következôket kell
megtennünk :

1. A fôprogramban a hivatkozott szubrutint elôször az EXTRN és a


PROC direktívák segítségével, externként kell deklarálni. Ez
mondja meg a fôprogramnak, hogy itt hívjuk meg a szubrutint,
de annak megvalósítása nem itt található. Ez az eljárás a C
nyelvben megfelel az EXTERN kulcsszó használatának.

2. A szubrutint tartalmazó modulban a szubrutint a PUBLIC


direktíva segítségével kell deklarálni jelezvén a linkernek, hogy
ezt a modult más modulok is használhatják, elérhetik.

Példa : Fôprogramot tartalmazó modul

.MODEL small
.STACK 100h
.DATA
; Adatdefiníciók
.CODE
EXTRN cnts:PROC
kezd:
;
; Utasítások
;
END kezd

Szubrutint tartalmazó modul

PUBLIC cnts
cnts PROC
;
; Utasítások
;
cnts ENDP

Legyen ezután a fôprogram neve fo_prog.asm, a szubrutint tartalmazó modulé


al_prog.asm. A fordítás illetve linkelés menete a következô :

1. tasm fo_prg[. asm]

73
Forrás: http://www.doksi.hu

9. Szubrutinok szervezése

Hatására létrejön a fo_prg.obj.

2. tasm al_prg[.asm]

Hatására létrejön az al_prg.obj.

3. tlink fo_prg[.obj], al_prg[.obj]

Hatására létrejön a fo_prg.exe.

Van egy még kényelmesebb módja a szubrutin használatnak, ez pedig a saját


könyvtár létrehozása. Tételezzük fel, hogy a cnts és a prst szubrutinjainkat
ellátuk a szükséges PUBLIC direktívával, és kimentettük ôket az f_cnts.asm
illetve az f_prst.asm állományokba. Ezekután a következôket kell tennünk :

1. tasm f_cnts[.asm]

Hatására létrejön a f_cnts.obj.

2. tasm f_prst[.asm]

Hatására létrejön az f_prst.obj.

3. tlib bt.lib +f_cnts[.obj] +f_prst[.obj], bt.lst

Hatására létrejön a bt.lib könyvtár és a bt.lst lista állomány, ami


a könytárban lévô modulok neveit tartalmazza.

A könyvtár egy olyan állomány, amely objekt modulokat tartalmaz, megfelelô


formátumban. A TLIB.EXE a Borland C++ 3.1-hez adott könyvtárkészítô
program és BIN alkönyvtárban található.

Ezt a könytárat hozzálinkelhetjük - és a példaprogramok készítése során hozzá


is linkeltem - a fôprogramunk objekt moduljához. Az EXTRN és PUBLIC
direktívák használata itt is kötelezô ! A linkelést a következôképpen kell
végrehajtani :

tlink fo_prg[.obj] , , , bt[.lib]

A [] zárójelek között szereplô karakterek opcionálisak !

74
Forrás: http://www.doksi.hu

9.4 Kész szubrutinok szerkesztése, saját könyvtárak létrehozása.


Van egy olyan módja is a szubrutin használatnak, amikor a szubrutinjainkat
egy szöveges állományba gyűjtjük, és a fôprogramban az INCLUDE direk-
tívával beinzertáljuk. Meglehetôsen növeli a méretet.

Ezekután nézzük meg az integer alsó és felsô byte-ját megcserélô program


különbôzô verzióit. Lesz olyan verzió, ahol a szubrutinok forrásszövege része
a fôprogramnak, és lesz olyan is ahol a szubrutin modulokat a bt.lib
könyvtárból linkeltem a fôprogramhoz. A most következô példaprogramban a
két szubrutin forrásszöveg szinten része a programnak. A paraméterátadás
regisztereken keresztül történik.

15. sz. példaprogram :

; Paraméterátadás regiszteren keresztül


;
.MODEL small
.STACK 100h
.DATA

szam DW 1
ide DB 5 DUP (20h)
vege LABEL BYTE ; Itt jelöljük meg az
DB 0dh,0ah,'$' ; IDE utáni byte-ot.
;
.CODE
prgstart:
mov ax,@data
mov ds,ax
;
xor ax,ax
mov ax,[szam]
mov BYTE PTR[szam],ah ; Ez a két sor a csere
mov BYTE PTR[szam+1],al
;
mov ax,[szam] ; Átadjuk a számot

mov bx,OFFSET vege - 1 ; Itt adjuk át a kon-


; vertálási terület
; végének a címét

mov cx,5 ; Átadjuk a kiiratási


; szélességet

call cnts ; Meghívjuk a konver-


; táló szubrutint
mov bx, OFFSET ide ; Átadjuk a konvertá-
; lási terület kezdô-
; címét
call prst ; Meghívjuk a kiiró

75
Forrás: http://www.doksi.hu

9. Szubrutinok szervezése
; szubrutint
mov ah,4ch ; Visszaadjuk a vezér-
int 21h ; lést a DOS-nak.
;

; Itt jön a CNTS függvény


;
; AX : Konvertálandó szám
; DS:BX : A string végére mutató pointer, ahol ;
elhelyezzük a számot
; CX : A konvertálás szélessége
;
cnts PROC

mov si,10
cnvlp: sub dx,dx
div si
add dl,'0' ; Most konvertáltuk karakterré
mov [bx],dl
dec bx
and ax,ax
jz szokoz
loop cnvlp
szokoz:
ret

cnts ENDP

; Itt jön a PRST függvény


;
; DS:BX : A stringre mutató pointer
;
prst PROC

push ax
push dx
;
mov ah,9
mov dx,bx
int 21h
pop dx
pop ax
ret

prst ENDP

END prgstart

76
Forrás: http://www.doksi.hu

9.4 Kész szubrutinok szerkesztése, saját könyvtárak létrehozása.


A következô példaprogram egyrészt az INCLUDE direktíva használatát mu-
tatja be. Az INC_DEF.ASM fileban különbözô konstansokhoz rendeltünk
szimbólumokat. Másrészt itt találkozunk elôször azzal a megoldással, hogy a
program nem tartalmazza azon szubrutinoknak a forrásszövegét, amelyekre
hivatkozik. A 9.4 alatt leírtak szerint elkészítettem a bt.lib állományt, és ezt
linkeltem a fôprogram objekt moduljához. Az END direktíva használata is új
elemmel bôvül : a program indításakor a mögé írt címkére adódik a vezérlés.
Jelen esetben ez a prgstart címke.

16. sz. példaprogram:

Nézzük elôször az INC_DEF.ASM állomány tartalmát :

;
; INC_DEF.ASM : Include fileként használható assembly
; program
;
CR EQU 0dh ; Újsor
CHARIN EQU 1 ; Egy karakter bekérése
CHAROUT EQU 2 ; Egy karakter kiírása
STROUT EQU 9 ; String kiírása
RETDOS EQU 4ch ; visszatérés a DOS-hoz

Ezután nézzük a programot :

; Hivatkozott szubrutinok a BT.LIB - ben.


.MODEL small
.STACK 100h
.DATA
INCLUDE INC_DEF.ASM
szam DW 1
ide DB 5 DUP (20h)
vege LABEL BYTE
DB 0dh,0ah,'$'
;
.CODE
EXTRN cnts:PROC ; A szubrutinok deklarálása
EXTRN prst:PROC ; extern-ként
prgstart:
mov ax,@data
mov ds,ax
;
xor ax,ax
mov ax,[szam]

77
Forrás: http://www.doksi.hu

9. Szubrutinok szervezése
mov BYTE PTR[szam],ah ; Ez a két sor a csere
mov BYTE PTR[szam+1],al
;
mov ax,[szam]
mov bx,OFFSET vege - 1
mov cx,5
call cnts
mov bx, OFFSET ide
call prst
mov ah,RETDOS ; Az INC_DEF.ASM-bôl

int 21h

END prgstart

A következô példaprogramban az integer megfordítását is szubrutinként


implementáljuk. Az átadási módszer : változó címe regiszterben.

17. sz. példaprogram:

; Megvalósitás függvénnyel
;
; Paraméterátadás : Változó címe a BX regiszterben
.MODEL small
.STACK 100h
.DATA
szam DW 1
ide DB 5 DUP (20h)
vege LABEL BYTE
DB 0dh,0ah,'$'
;
.CODE
EXTRN cnts:PROC
EXTRN prst:PROC
prgstart:
mov ax,@data
mov ds,ax
;
mov bx,OFFSET szam ; BX-ben átadjuk a megfor-
; dítani kívánt integer
; címét
call fordit ; Meghívjuk a szubrutint
mov ax,[szam]
mov bx,OFFSET vege - 1
mov cx,5
call cnts
mov bx, OFFSET ide
call prst
mov ah,4ch
int 21h

78
Forrás: http://www.doksi.hu

9.4 Kész szubrutinok szerkesztése, saját könyvtárak létrehozása.


;
; Itt jön a FORDIT megvalósítása
;
; BX : Megforditandó szám címe
;
fordit PROC
;
mov ax,[bx] ; AX-be töltjük a BX-ben
; lévô címen található
; adatot
mov BYTE PTR [bx],ah ; Ez a két sor a csere
mov BYTE PTR [bx+1],al
ret
fordit ENDP
END

A következô példaprogramban megváltozik a paraméterátadás módja. A vál-


tozó címét nem egy regiszteren keresztül, hanem a stacken keresztül adjuk át.

18. sz. példaprogram:

; Paraméterátadás : Változó címe a STACK-ben


.MODEL small
.STACK 100h
.DATA
;
szam DW 1
ide DB 5 DUP (20h)
vege LABEL BYTE
DB 0dh,0ah,'$'
;
.CODE
EXTRN cnts:PROC
EXTRN prst:PROC
prgstart:
mov ax,@data
mov ds,ax
;
mov ax,OFFSET szam
;
push ax ; Itt adjuk át a változó címét !
call fordit
add sp,2 ; Helyre állítjuk a STACK-et !
;
mov ax,[szam]
mov bx,OFFSET vege - 1
mov cx,5
call cnts
mov bx, OFFSET ide

79
Forrás: http://www.doksi.hu

9. Szubrutinok szervezése
call prst
mov ah,4ch
int 21h
;
; Itt jön a fordit megvalósítása
;
; Megfordítandó szám címe a STACK-ben
;
fordit PROC
push bp
mov bp,sp
mov bx,[bp+4] ; BP+0 = bp értéke
; BP+2 = visszatérési cím
; BP+4 = paraméter címe
; BX-ben a szám címe van !

mov ax,[bx] ; AX-ben a szám van, az indirekció miatt

mov BYTE PTR [bx],ah ; Ez a két sor a csere


mov BYTE PTR [bx+1],al

pop bp
ret
fordit ENDP
END

Végül következzék egy elrettentô példa a globális változó használatára.

19. sz. példaprogram :

; Paraméterátadás : globális változó használata


.MODEL small
.STACK 100h
.DATA
;
szam DW 1
ide DB 5 DUP (20h)
vege LABEL BYTE
DB 0dh,0ah,'$'
;
.CODE
EXTRN cnts:PROC
EXTRN prst:PROC
;
prgstart:
mov ax,@data
mov ds,ax
;

80
Forrás: http://www.doksi.hu

9.5 Makró alkalmazás


call fordit ; Semmilyen paraméterátadás nincs
;
mov ax,[szam]
mov bx,OFFSET vege - 1
mov cx,5
call cnts
mov bx, OFFSET ide
call prst
;
mov ah,4ch
int 21h

;
; Itt jön a fordit megvalósítása
;
;
fordit PROC
;
mov ax,[szam] ; AX-ben a szám van
;
mov BYTE PTR [szam],ah ; Ez a két sor a csere
mov BYTE PTR [szam+1],al
;
ret
;
fordit ENDP

END

9.5 M akr ó alkalmazás

A makró használatra csak egy nagyon rövid példát mutatok be jelezvén, hogy
ilyen lehetôség is rendelkezésünkre áll. A makró definíciója a következô :

név MACRO formális paraméterlista


.
.
.
utasítások
.
.
.
ENDM

81
Forrás: http://www.doksi.hu

9. Szubrutinok szervezése

A makróra egyszerűen a nevével hivatkozunk.

Példa : dosint MACRO intszam


;
mov ah,intszam
int 21h
;
ENDM
.
.
.

Hívása : dosint 4ch ; visszatérés a DOS-hoz

A makró és a szubrutin annyiban hasonlítanak egymásra, hogy mindegyiket


csak egyszer kell megírni és többször lehet hivatkozni rájuk. Ezzel a
hasonlóság be is fejezôdött ! Amíg a szubrutint vezérlésátadással tudjuk hasz-
nálni, addig a makrónak - a fordítás során - a forrásszövege másolódik be a
hivatkozás helyére.

Világos, hogy a szubrutin csökkenti a program méretét, de a vezérlés átadás

! miatt növeli annak végrehajtási idejét. A makró viszont csökkenti a


végrehajtási idôt, mert nem kell vezérlésátadással foglalkozni, de növeli a
program méretét. A feladattól függôen kompromisszumot kell kötni a két
alkalmazás között !

A most következô példaprogram két karakter összehasonlítását végzi. A DOS


hívásokat makró alkalmazással oldja meg.

20. sz. példaprogram :

.MODEL small
.STACK 100h
; Itt jön a makró definíció !
;
dosint MACRO intnum
mov ah,intnum
int 21h
ENDM
.DATA
nagy12 db '1 > 2','$'
nagy21 db '1 < 2','$'
egy12 db '1 = 2','$'
sorem db 0dh,0ah,'$'

82
Forrás: http://www.doksi.hu

Ellenôrzô kérdések és feladatok


.CODE
mov ax,@data
mov ds,ax
;
dosint 1 ; A makró meghivása egy karakter
; beolvasására
mov cl,al
dosint 1 ; A másik karakter beolvasása
mov bl,al
;
mov al,cl
cmp al,bl
je egyen
js n2_1
;
mov dx,OFFSET nagy12
jmp kiir
egyen:
mov dx,OFFSET egy12
jmp kiir
n2_1:
mov dx,OFFSET nagy21
kiir:
mov ah,9
int 21h
;
mov ah,2
mov dl,cl
int 21h
mov dl,20h
int 21h
mov dl,bl
int 21h
mov ah,9
mov dx,OFFSET sorem
int 21h
dosint 4ch ; Viszatérés a DOS-hoj funkció
END

Ellenôr zô kér dések és feladatok

01. Mit nevezünk szubrutinnak, miért elônyös a használata ?

02. Milyen formában kell megírni egy szubrutint, és mely utasítással kell
hivatkozni rá ?

83
Forrás: http://www.doksi.hu

9. Szubrutinok szervezése
03. Miért nem elég szubrutinhíváskor csak a vezérlésátadást megvalósítani?

04. Mi játszódik le egy szubrutin meghívásakor illetve a szubrutinba való


visszatéréskor ?

05. Milyen paraméterátadási módokat ismer. Vezesse le a stack kezelést két


paraméter stacken keresztüli átadása esetén. Adja meg az elsô
paraméter indirekt címét valamint a másodikét is. ( A [bp+...] alakra
gondolok ).

06. Irjon programot, amely az 56. oldalon található 07. sz. feladatot
szubrutin alkamazásával oldja meg. A két string címét regisztereken
keresztül adja át a szubrutinnak !

07. Olja meg a 06. sz. feladatot úgy, hogy a két string címét a stacken
keresztül adja át !

08. Bôvítse úgy a 07. számú programot, hogy alkalmas legyen két string
viszonyának megállapítására akkor is, ha azok nem egyenlô hosszúak.

09. Irjon programot, amely az 56. oldalon található 09. sz. feladatot
szubrutin alkamazásával oldja meg. A két string címét elôször regisz-
tereken, majd a stacken keresztül adja át a szubrutinnak !

10. Irjon programot, amely az 56. oldalon található 10. sz. feladatot
szubrutin alkamazásával oldja meg. A két string címét elôször regisz-
tereken, majd a stacken keresztül adja át a szubrutinnak !

11. Irja meg a string másoló programot szubrutinnal. A paraméterátadás


módja szabadon választott !

12. Képezze két 10 elemű integer vektor skaláris szorzatát. A szorzat ered-
ményét a most ne a TD-vel tekintse meg, hanem irassa ki a képernyôre!
A feladatot szubrutin alkalmazásával oldja meg, a paraméterátadás
módját Önre bízom !

13. Irja meg a string hosszát meghatározó programot szubrutinnal. A


paraméterátadás módja szabadon választott ! A stirng összehasonlító,
stringmásoló és stringhossz meghatározó rutinokból készítsen - a tanult
módon - egy SAJAT.LIB nevű könyvtárat !

84
Forrás: http://www.doksi.hu

10. Str ing utasítások, DOS és BI OS szolgáltatások


Ebben fejezetben elôször az i8086-os stringutasításait mutatom be, amelyek
csak a nevükben stringutasítások hiszen integer változókon is működnek. Az
utasítások közül az elsô három adatmozgató, a következô kettô pedig
összehasonlító. Ezután a stringműveleteknél használható prefixek működését
nézzük meg. A stringműveletek után példaprogramok következnek a DOS dá-
tumelôállító, illetve a BIOS színkezelô szolgáltatásaira

10.1 A L ODS utasítás

Szintaxis : LODS <cím> , LODSB , LODSW

A lods utasítás egy vagy két byte-ot tölt be a memóriából az al vagy az ax


regiszterbe. Az aktuális memóriacím a DS:SI regiszterpárban kell, hogy
rendelkezésre álljon. További fontos momentum, hogy a lods a DF értékétôl
függôen eggyel vagy kettôvel növeli vagy csökkenti az SI regiszter értékét.
Amennyiben DF = 0 akkor növeli - a string művelet a növekvô indexek
mentén hajtódik végre -, amennyiben DF = 1 úgy csökkenti. Az utasítás egyet-
len flaget sem állít. A lods utasítást háromféleképpen alkalmazhatjuk :

1. lods <cím>

Itt a <cím> csak a változótípus ( db vagy dw ) megállapítására


szolgál, hiszen a DS:SI regiszterpár már tartalmazza a címet.

2. lodsb

Egy byte betöltése a DS:SI-ben lévô címrôl az al regiszterbe. Az


SI regisztert eggyel növeli vagy csökkenti DF értékétôl függôen.

3. lodsw

K ét byte betöltése a DS:SI-ben lévô címrôl az ax regiszterbe. Az


SI regisztert kettôvel növeli vagy csökkenti DF értékétôl füg-
gôen.
Forrás: http://www.doksi.hu

10. Str ing utasítások, DOS és BI OS szolgáltatások

A lods utasítás alkalmazására a késôbbiekben láthatunk példaprogramot !

10.2 A STOS utasítás

Szintaxis : STOS <cím> , STOSB , STOSW

A stos utasítás egy vagy két byte-ot ír ki az al vagy az ax regiszterbôl az


ES:DI regiszterpárban megadott címre. A DF értékétôl függôen eggyel vagy
kettôvel növeli vagy csökkenti a DI regiszter értékét. Az utasítás szintén nem
állít egyetlen flaget sem. A stos utasítást is háromféleképpen alkalmazhatjuk :

1. stos es:<cím>

Itt az es:<cím> csak a változótípus (db vagy dw) megállapítására


szolgál, hiszen az ES:DI regiszterpár már tartalmazza a címet.

2. stosb

Egy byte kiírása az ES:DI-ben lévô címre az al regiszterbôl. A


DI regisztert eggyel növeli vagy csökkenti DF értékétôl függôen.

3. stosw

K ét byte kiírása az ES:DI-ben lévô címre az ax regiszterbôl. A


DI regisztert kettôvel növeli vagy csökkenti DF értékétôl füg-
gôen.

A következô példaprogramban a lods és a stos utasítások használatát mutatom


be egy stringmásoló program keretén belül. Mindkét utasításna az 1. számú
alakját - vagyis a cím operandusos alakot - használjuk.

Mielôtt áttekintenénk a programot elôször nézzük meg, mit jelent a $ szimbó-


lum. Egy jelentését már ismerjük : string lezáró karakterként használtuk a-
posztrófok között. Itt a $ jel azonban aposztrófok nélkül áll és az elhelyezke-
dés számláló szerepét tölti be, vagyis annak a memóriacímnek az értékét tar-
talmazza, ahol áll. Ezért tudjuk a programunk 6. sorában az innen nevű string
hosszának meghatározására használni.A másik megemlítendô a SEG operátor.
Ez az operátor az utána írt memóriaváltozó szegmenscímét állítja elô !

21. sz. példaprogram:

84
Forrás: http://www.doksi.hu

10.2 A STOS utasítás

.MODEL small
.STACK 100h
.DATA
innen db 'Ezt a szöveget másoljuk !',0
SLEN EQU ($-innen) ; Az EQU az egyenlôség direktíva
ide db SLEN DUP(?)
db 0dh,0ah,'$'
;
.CODE
mov ax,@data
mov ds,ax
;
mov ax,SEG innen
mov ds,ax ; A forrás string címe a DS:SI-ben
mov si,OFFSET innen
;
mov ax,SEG ide
mov es,ax ; A cél string címe az ES:DI-ben
mov di,OFFSET ide
;
mov cx,SLEN
masol:
lods [innen]
stos es:[ide]
loop masol
;
xor ax,ax
mov ah,9
mov dx,OFFSET ide
int 21h
;
mov ah,4ch
int 21h
END

A következô példaprogram ugyanezt a műveletet hajtja végre, csak a lods és a


stos 2. számú alakjával ( lodsb, stosb ).

22. sz. példaprogram:

.MODEL small
.STACK 100h
.DATA
innen db 'Ezt a szöveget másoljuk !',0
SLEN EQU ($-innen)
ide db SLEN DUP(?)

85
Forrás: http://www.doksi.hu

10. Str ing utasítások, DOS és BI OS szolgáltatások


db 0dh,0ah,'$'
;
.CODE
mov ax,@data
mov ds,ax
;
mov ax,SEG innen
mov ds,ax ; A forrás string címe a DS:SI-ben
mov si,OFFSET innen
;
mov ax,SEG ide
mov es,ax ; A cél string címe az ES:DI-ben
mov di,OFFSET ide

cld ; Növekvô indexek irányában


;
masol:
lodsb
stosb
cmp al,0
jnz masol
;
xor ax,ax
mov ah,9
mov dx,OFFSET ide
int 21h
;
mov ah,4ch
int 21h
END

A következô példaprogram csökkenô indexek mentén hajt végre másolást.


A string vége vizsgálatot most nem a nullával való összehasonlítással oldottam
meg, hanem az SLEN értékét CX-be írva loop ciklust szerveztem.

23. sz. példaprogram:

.MODEL small
.STACK 100h
.DATA
;
innen db 'Ezt a szöveget másoljuk !',0
SLEN EQU ($-innen)
ide db SLEN DUP(?)
db 0dh,0ah,'$'
;
.CODE

86
Forrás: http://www.doksi.hu

10.2 A STOS utasítás


mov ax,@data
mov ds,ax
;
mov ax,SEG innen
mov ds,ax ; A forrás string címe a DS:SI-ben
mov si,OFFSET innen + SLEN - 1
;
mov ax,SEG ide
mov es,ax ; A cél string címe az ES:DI-ben
mov di,OFFSET ide + SLEN - 1
;
std ; Csökkenô indexek irányában
;
mov cx,SLEN
masol:
lodsb
stosb
loop masol
;
xor ax,ax
mov ah,9
mov dx,OFFSET ide
int 21h
;
mov ah,4ch
int 21h
END

A következô két példaprogram integer vektor másolását mutatja be. Az elsô a


címoperandusos, a második az operandusnélküli alakot használja.

24. sz. példaprogram:

.MODEL small
.STACK 100h
.DATA
;
innen dw 1,2,3,4,5
SLEN EQU ($-innen)/2 ; Az integer hossza miatt
ide dw SLEN DUP(?)
;
.CODE
mov ax,@data
mov ds,ax
;

87
Forrás: http://www.doksi.hu

10. Str ing utasítások, DOS és BI OS szolgáltatások


mov ax,SEG innen
mov ds,ax ; A forrás string címe a DS:SI-ben
mov si,OFFSET innen
;
mov ax,SEG ide
mov es,ax ; A cél string címe az ES:DI-ben
mov di,OFFSET ide
;
mov cx,SLEN
cld
masol:
lods [innen]
stos es:[ide]
loop masol
;
mov ah,4ch
int 21h
END

25. sz. példaprogram:

.MODEL small
.STACK 100h
.DATA
innen dw 1,2,3,4,5
SLEN EQU ($-innen)/2
ide dw SLEN DUP(?)
;
.CODE
mov ax,@data
mov ds,ax
;
mov ax,SEG innen
mov ds,ax ; A forrás string címe a DS:SI-ben
mov si,OFFSET innen
;
mov ax,SEG ide
mov es,ax ; A cél string címe az ES:DI-ben
mov di,OFFSET ide
;
mov cx,SLEN
cld
masol:
lodsw

88
Forrás: http://www.doksi.hu

10.3 A MOVS utasítás


stosw
loop masol
;
mov ah,4ch
int 21h
END

10.3 A M OVS utasítás

Szintaxis : MOVS <cím> , MOVSB , MOVSW

A movs utasítás tulajdonképpen a lods és a stos utasítások összevonása. Egy


vagy két byte-ot olvas az al vagy ax regiszterbe a DS:SI címrôl, majd a DF
értékétôl függôen növeli vagy csökkenti SI regiszter értékét. Ezután az al vagy
ax regiszterbôl ( ahova az olvasás történt ) kiírja a tartalmat az ES:DI-ben lévô
címre és a DI értékét is a megfelelô módon változtatja. Tulajdonképpen egy
byte-ot vagy egy szót másol ! Közbensô regisztert nem használ, egyetlen flag
értékét sem állítja. Szintén háromféleképpen használható :

1. movs es:<cél címe>, <forrás címe>

A címek szintén csak a változótípus (db vagy dw) megállapí-


tására szolgálnak.

2. movsb

Egy byte olvasása a DS:SI-ben lévô címrôl az al regiszterbe. Az


al tartalmának kiírása az ES:DI-ben lévô címre. AZ SI, DI
regiszterek a DF-tôl függôen eggyel nônek vagy csökkennek.

3. movsw

K ét byte olvasása a DS:SI-ben lévô címrôl az ax regiszterbe. Az


ax tartalmának kiírása az ES:DI-ben lévô címre. AZ SI, DI
regiszterek a DF-tôl függôen kettôvel nônek vagy csökkennek.

26. sz. példaprogram:

.MODEL small
.STACK 100h

89
Forrás: http://www.doksi.hu

10. Str ing utasítások, DOS és BI OS szolgáltatások


.DATA
;
innen db 'Ezt a szöveget másoljuk !',0
SLEN EQU ($-innen)
ide db SLEN DUP(?)
db 0dh,0ah,'$'
;
.CODE
mov ax,@data
mov ds,ax
;
mov ax,SEG innen
mov ds,ax ; A forrás string címe a DS:SI-ben
mov si,OFFSET innen
;
mov ax,SEG ide
mov es,ax ; A cél string címe az ES:DI-ben
mov di,OFFSET ide
;
mov cx,SLEN ; A forrás string hossza CX-ben
cld ; A D flaget nullázzuk, igy a növekvô
; indexek felé mozog a másolás
;
masol:
;
movsb ; A MOVSB egyik regiszterben sem
; helyezi el a byte-ot, igy a hosszát
; ismernünk kell !
loop masol
;

xor ax,ax

mov ah,9
mov dx,OFFSET ide
int 21h
;
mov ah,4ch
int 21h
end

10.4 A SCAS utasítás

Szintaxis : SCASB , SCASW

90
Forrás: http://www.doksi.hu

10.5 A CMPS utasítás

A scas utasítás az ES:DI-ben lévô címen tárolt byte vagy szó értékét hasonlítja
össze az al vagy az ax regiszter tartalmával. Az összehasonlítás kivonás
formájában történik meg, de az eredményt nem ôrzi meg a művelet, hanem
csak a flageket változtatja az eredménynek megfelelôen. Ezek a flagek a
következôk : CF, PF, AF, ZF, SF, OF. A művelet után a DI regisztert a
megfelelô módon változtatja az utasítás. Amennyiben byte-os összehasonlítást
akarunk végezni úgy a scasb alakot, amennyiben szavas összehasonlítást, úgy
a scasw alakot használjuk.

10.5 A CM PS utasítás

Szintaxis : CMPSB , CMPSW

A cmps utasítás a DS:SI-ben lévô címen lévô byte vagy szó értékét hasonlítja
össze az ES:SI-ben tárolt címen lévô byte vagy szó tartalmával. Az érintett
flagek a következôk : CF, PF, AF, ZF, SF, OF. A művelet után az SI és a DI
regisztereket a megfelelô módon változtatja az utasítás. Amennyiben byte-os
összehasonlítást akarunk végezni úgy a cmpsb alakot, amennyiben szavas
összehasonlítást, úgy a cmpsw alakot használjuk.

Az összes stringutasításra érvényes szabály tehát az, hogy az SI és a DI


! regisz-terek tartalma az adott művelet elvégzése után mindig a
következô fel-dolgozandó elemre mutat !

Mielôtt példaprogramokat mutatnék az elôzô két utasításra, tekintsük át a


string utasításokkal kapcsolatos prefixeket !

10.6 Str ing utasítás pr efixek : REP, REPE, REPNE

A string utasítás prefixek az utasítások ismétlését idézik elô. Csakis és kizáró-


lag string utasításokhoz használhatók !

A r ep addig ismétli a string utasítást, amíg a CX regiszter tartalma el nem éri a


nullát.

91
Forrás: http://www.doksi.hu

10. Str ing utasítások, DOS és BI OS szolgáltatások

A r epe ( repz ) addig ismétli a string utasítást, amíg a CX regiszter tartalma el


nem éri a nullát és ZF értéke 1. Ennélfogva csak a scas és cmps utasításokkal
együtt alkalmazható !

A r epne ( repnz ) addig ismétli a string utasítást, amíg a CX regiszter tartalma


el nem éri a nullát és ZF értéke 0. Szintén csak a scas és cmps utasításokkal
együtt alkalmazható !

Ezek után következzenek a példaprogramok ! A következô példaprogram még


mindig a stringmásolást hajtja végre, de most már prefix használattal. A
másolást TD alatt lehet ellenôrizni, ugyanis a programok a kiiratást nem
tartalmazzák !

27. sz. példaprogram:

.MODEL small
.STACK 100h
.DATA
innen db 'Ezt a szöveget másoljuk !',0
SLEN EQU ($-innen)
ide db SLEN DUP(?)
db 0dh,0ah,'$'
.CODE
mov ax,@data
mov ds,ax
;
mov ax,SEG innen
mov ds,ax ; A forrás string címe a DS:SI-ben
mov si,OFFSET innen
;
mov ax,SEG ide
mov es,ax ; A cél string címe az ES:DI-ben
mov di,OFFSET ide
;
mov cx,SLEN ; A forrás string hossza CX-ben
cld ; A D flaget nullázzuk, igy a növekvô
; indexek felé mozog a másolás
;
rep movsb ; A MOVSB egyik regiszterben sem he-
; lyezi el a byte-ot, igy a hosszát ; ismernünk
kell !
;

xor ax,ax
mov ah,9
mov dx,OFFSET ide
int 21h
;

92
Forrás: http://www.doksi.hu

10.6 String utasítás prefixek : REP, REPE, REPNE


mov ah,4ch
int 21h
END

A következô két példaprogram a movs két alakját és a rep prefixet használja.

28. sz. példaprogram:

.MODEL small
.STACK 100h
.DATA
innen dw 1,2,3,4,5
SLEN EQU ($-innen)/2
ide dw 5 DUP(0)
.CODE
mov ax,@data
mov ds,ax
;
mov ax,SEG innen
mov ds,ax ; A forrás string címe a DS:SI-ben
mov si,OFFSET innen
;
mov ax,SEG ide
mov es,ax ; A cél string címe az ES:DI-ben
mov di,OFFSET ide
;
mov cx,SLEN ; A forrás string hossza CX-ben
cld
;
rep movs es:[ide],[innen]
;
xor ax,ax
mov bx,0
mov cx,SLEN
mutat: ; A másolás ellenôrzése TD alatt
mov ax,ide[bx]
inc bx
inc bx
loop mutat
;
mov ah,4ch
int 21h
END

93
Forrás: http://www.doksi.hu

10. Str ing utasítások, DOS és BI OS szolgáltatások


29. sz. példaprogram:

.MODEL small
.STACK 100h
.DATA
innen dw 1,2,3,4,5
SLEN EQU ($-innen)/2
ide dw 5 DUP(0)
.CODE
mov ax,@data
mov ds,ax
;
mov ax,SEG innen
mov ds,ax
mov si,OFFSET innen
;
mov ax,SEG ide
mov es,ax
mov di,OFFSET ide
;
mov cx,SLEN
cld
;
rep movsw
;
xor ax,ax
mov bx,0
mov cx,SLEN
;
mutat:
mov ax,ide[bx]
inc bx
inc bx
loop mutat
;
mov ah,4ch
int 21h
END

A következô példaprogram a scas, az ezt követô pedig a cmps utasításra mutat


példát, prefixhasználattal együtt. A scas utasítást arra használjuk, hogy egy
stringben megkeressük az elsô szóközt és a di regiszterben tároljuk annak po-
zícióját. A cmps utasítással egy stringben keresünk egy adott karakter mintát.
A találati poziciókat a TD-vel lehet ellenôrizni ! A cmps utasítást bemutató

94
Forrás: http://www.doksi.hu

10.6 String utasítás prefixek : REP, REPE, REPNE


programban találunk egy új utasítást, ez pedig a lea utasítás. Az utána követ-
kezô operandus offszetjét állítja elô csakúgy mint az OFFSET operátor. Ez u-
tóbbit azonban tömb elemek offszetjének elôállítására nem használhatjuk, míg
a lea utasítást igen !

30. sz. példaprogram:

.MODEL small
.STACK 100h
.DATA
;
innen db 'Ebben a szövegbenkeressük az elsôszóközt!'
SLEN EQU ($-innen)
;
.CODE
mov ax,@data
mov ds,ax
;
mov ax,SEG innen
mov es,ax ; A string címe az ES:DI-ben
mov di,OFFSET innen
;
mov cx,SLEN ; A string hossza CX-ben
cld
mov al,20h ; A szóköz kódja
repne scasb ; Keresés 'nem egyenlô' - ig !
;
jne vege
dec di ; Itt volt az elsô szóköz !
;
vege:
mov ah,4ch
int 21h
END

31. sz. példaprogram:

.MODEL small
.STACK 100h
.DATA
;
minta db 'Ezaz'
ml EQU $ - minta
innen db '111122223333Ezaz4444'
SLEN EQU ($-innen)/ml
;

95
Forrás: http://www.doksi.hu

10. Str ing utasítások, DOS és BI OS szolgáltatások


.CODE
mov ax,@data
mov ds,ax
;
mov ax,SEG innen
mov ds,ax ; A keresô tábla szegmense a DS-ben
;
mov ax,SEG minta
mov es,ax ; A minta szegmense ES-ben

cld
;
mov dx,SLEN
mov bx,0
;
kov:
lea si,innen[bx] ; A tábla aktuális offszetje
; az SI-ben
lea di,minta ; A minta offszetje DI-ben
mov cx,ml ; A minta mérete CX-ben
repe cmpsb ; Keresés amíg a tábla elem =
; = minta elem !
;
je megvan
add bx,ml ; Ha nincs találat, akkor arrébb
; megyünk a minta hosszával
dec dx
jnz kov
mov si,ml
;
megvan:
sub si,ml ; Itt volt az egyezés !

;
mov ah,4ch
int 21h
END

10.7 DOS szolgáltatás hívását bemutató példapr ogr am

A kérdéses DOS szolgáltatás a dátum elôállító függvény lesz, sorszáma 2ah.


Ennek a szolgáltatásnak bemenô paramétere nincs. Kimenô paraméterei a
következôk :

96
Forrás: http://www.doksi.hu

10.7 DOS szolgáltatás hívását bemutató példaprogram


CX regiszter = Az évszám négy számjegyen
DH regiszter = A hónap két számjegyen
DL regiszter = A nap két számjegyen
AL regiszter = A hét hányadik napja 1 számjegyen

Az AL regiszterel kapcsolatban meg kell jegyezni, hogy a vasárnap a 0. a hétfô


az 1. stb. sorszámozęs van érvényben.

Ezekután a feladat az, hogy írassuk ki a dátumot magyar szokás szerint, de a


hónapot és a hét napját ne a sorszámával irassuk ki, hanem a nevével.

Például : 1997. június 11. szerda

32. sz. példaprogram :

.MODEL small
.STACK 100h
.DATA
;
ev DW ?
honap DB ?
nap DB ?
hnap DB ?
sev DB 4 DUP (20h)
sevv LABEL BYTE
DB '$'
snap DB 2 DUP (20h)
snv LABEL BYTE
DB '$'
spa DB ' '
;
holen DB 12
;
hok DB 'Január ','$'
DB 'Február ','$'
DB 'Március ','$'
DB 'Április ','$'
DB 'Május ','$'
DB 'Június ','$'
DB 'Július ','$'
DB 'Augusztus ','$'
DB 'Szeptember ','$'
DB 'Október ','$'
DB 'November ','$'
DB 'December ','$'
;

97
Forrás: http://www.doksi.hu

10. Str ing utasítások, DOS és BI OS szolgáltatások


naplen DB 11
;
napok DB 'Vasárnap ','$'
DB 'Hétfô ','$'
DB 'Kedd ','$'
DB 'Szerda ','$'
DB 'Csütörtök ','$'
DB 'Péntek ','$'
DB 'Szombat ','$'
sorem DB 0dh,0ah,'$'
;
.CODE
prgstart:
mov ax,@data
mov ds,ax
;
xor ax,ax

;
mov ah,2ah
int 21h ; Meghivtuk a dátum függvényt
;
mov [ev],cx ; Kimentjük a dátum alkotó részeit
mov [honap],dh
mov [nap],dl
mov [hnap],al
;
mov ax,[ev] ; Az évszám átalakítása kezdôdik !
mov bx,OFFSET sevv - 1
mov cx,4
call cnts
;
xor ax,ax ; A nap átalakítása kezdôdik !
mov al,[nap]
mov bx,OFFSET snv - 1
mov cx,2
call cnts
;
mov bx, OFFSET sev ; Az évszám kiírása
call prst
mov ah,2 ; Egy szóközt írunk ki utána
mov dl,[spa]
int 21h
;
xor ax,ax ; A hónap nevének szöveges kiírása
mov al,[honap] ; kezdôdik
dec al
mul holen
mov bx,OFFSET hok
add ax,bx

98
Forrás: http://www.doksi.hu

10.7 DOS szolgáltatás hívását bemutató példaprogram


mov dx,ax
mov ah,9
int 21h
;
mov bx, OFFSET snap ; A nap kiirása
call prst
mov ah,2 ; Egy szóközt írunk ki utána
mov dl,[spa]
int 21h
;
xor ax,ax ; A hét napjának szöveges kiirása
mov al,[hnap] ; kezdôdik
mul naplen
mov bx,OFFSET napok
add ax,bx
mov dx,ax
mov ah,9
int 21h
;
mov dx,OFFSET sorem
int 21h
mov ah,4ch
int 21h

;
cnts PROC
mov si,10
cnvlp:
sub dx,dx
div si
add dl,'0'
mov [bx],dl
dec bx
and ax,ax
jz szokoz
loop cnvlp
szokoz:
ret
cnts ENDP
;
;
prst PROC
push ax
push dx
mov ah,9
mov dx,bx
int 21h
pop dx
pop ax
ret
prst ENDP

99
Forrás: http://www.doksi.hu

10. Str ing utasítások, DOS és BI OS szolgáltatások


END prgstart

10.8 BI OS szolgáltatás hívását bemutató példapr ogr am

A következô program cilusban ír ki egyszerre egy karaktert szín attribútum-


mal. Az attribútumot ciklusban változtatja 0 - 255 ig. Ezt a 10h BIOS szolgál-
tatás 9-es funkciójával tudjuk végrehajtani ! Minden kiírás után egy billentyű
lenyomására vár a program.

33. sz. példaprogram:

.MODEL small
.STACK 100h
.DATA
.CODE

mov ax,@data
mov ds,ax
;

mov ah,9 ; BIOS funkció sorszáma -> AH


mov al,'A' ; Kiiratni kivánt karakter -> AL
mov bh,0 ; Aktív képernyô lap -> BH
mov cx,2 ; Hányszor írjuk ki -> CX
;
mov dx,0 ; Attribútum -> DL

kiir:
mov bl,dl ; Karakter attribútum
int 10h
push ax
mov ah,1 ; Várakozás billentyű lenyomásra
int 21h
pop ax
inc dx
cmp dx,255
jnz kiir
;
mov ah,4ch
int 21h
END

100
Forrás: http://www.doksi.hu

Ellenôrzô kérdések és feladatok

A DOS és a BIOS szolgáltatások bemutatásával meglehetôsen sok szakkönyv


foglalkozik. PC-n a Norton Guide nevű on-line help taglalja részletesen a
szolgáltatások paraméterezését, és funkcióját.

Ellenôr zô kér dések és feladatok

01. Hogyan működnek a lods, stos, movs utasítások ?

02. Milyen alakjaik léteznek ? Miért elônyôs a használatuk a hagyomá-


nyos adatmozgató utasítások használatához képest ?

03. Mire alkalmasak a scas és cmps uatsítások ?

04. Irjon programot, amely egy maximum 70 karakter hosszú szövegben


megszámolja a magánhangzók számát ! A megvalósíthoz stringutasítást
használjon !

05. Irjon programot, amely meghatározza egy C típusú string hosszát ! A


megvalósíthoz stringutasítást használjon !

06. Irjon programot amely a 10h BIOS szolgáltatás 02 funkcióját hívja.


Ennek segítségével tudjuk a képernyôn a kurzort pozicionálni. Az AH
regiszterbe kell írni a 2-ôt, a BH-ba a képernyô lapszámot ( 0 ), DH-ba
a sor, DL-be az oszlop számot. Ha a program működik, készítsen önálló
kurzorpozicionáló szubrutint, és adja hozzá a meglévô saját könyv-
tárához !

101
Forrás: http://www.doksi.hu

11. A C nyelv és az assembly nyelv kapcsolata

Σ
A kapcsolattartást a két nyelv között többek közt az indokolja, hogy manapság
- hála a C nyelv elterjedésének - egyre ritkább a nagyméretű, tisztán assembly
nyelven írt program. A fejlesztés általában úgy történik, hogy csak a nagy se-
bességigényű programrészeket “ hegyezik ki” assembly betétekkel, a többit
leginkább C - esetleg Pascal - nyelven írják meg. Ez a fejezet konkrétan az
inline kapcsolatot és a modul szerű kapcsolatot mutatja be.

11.1 I nline kapcsolat

Az inline kapcsolat onnan kapta a nevét, hogy az assembly forrásszöveg r észe


a C nyelvű forrásszövegnek, akár soronként is váltogathatják egymást. A C
programban elôforduló assembly sort az asm kulcszóval kezdjük.

Példa: .
.
.
int i;
.
.
.
i=0;
asm dec WORD PTR i;
i++;


Ha valaki egy kicsit is jártas az inline assembly használatában az azonnal rá-
jön, hogy i értéke 0 marad az utasítások végén, de azért nézzük meg részlete-
sebben az asm kulcsszóval kezdôdô sort.

1. Azontúl, hogy megállapítjuk hogy asm kulcsszóval kezdôdik, meg-


állapíthatjuk, hogy a ‘ ;’ karakterrel végzôdik. Ezenkívül az inline
assembly sor végzôdhet még ‘ új sor’ billentyűvel is. Ha több assembly
sort akarunk egymásután elhelyezni, akkor az “ asm“ után a ‘ { ‘ karak-
tert kell írni még ugyanabba a sorba, majd utána soronként az
utasításokat, végül a ‘ } ’ karakterrel kell zárni az assembly sorokat.
Forrás: http://www.doksi.hu

11.1 Inline kapcsolat


2. Az a tény, hogy ‘ ;’ - re is végzôdhet a sor meggátol bennünket abban,
hogy a ‘ ;’ karaktert megjegyzésként használjuk, mint ahogy eddig tet-
tük. Inline assembly-t tartalmazó C programban csak a már ismert ka-
raktereket használhatjuk megjegyzésként ! ( /* ... * / illetve // ... ).

3. Mint látható szabadon hivatkozhatunk a C program valamennyi vál-


tozójára, sôt konstansára is. Ez a sor az i változó értékét eggyel csök-
kenti.

4. Mivel a dec nem határozza meg a műveleti szélességet, az inline


assembly pedig nem készít nyilvántartást arról, hogy az i milyen típusú
változó, ezért a műveleti szélességet, nekünk kellett elôírni. Termé-
szetesen, ahol regiszter jelöli ki a műveleti szélességet ott nincs ilyen
probléma.

Az inline assembly sor általános alakja tehát a következô :

asm [<címke>] < utasítás | dir ektíva > < oper andus ... > < ; | új sor >

Az inline assembly használatával kapcsolatosan még a következôkre kell


ügyelnünk :

1. Az inline assembly urgó utasítások csak C címkére vonatkozhatnak. Az


összes többi “ asm” utasítás viszont mindenre hivatkozhat, csak C cím-
kére nem.

Példa : asm jnz cimke1; asm jnz cimke2;


. .
. .
. .
cimke: asm cimke2 :

. .
. .
. .

jó nem j ó

2. A következô regiszterek tartalma változatlan kell, hogy maradjon inline


assembly használat után : BP, SP, CS, DS, SS. A többi regiszter
kezelése a programozóra van bízva.

101
Forrás: http://www.doksi.hu

11. A C nyelv és az assembly nyelv kapcsolata


3. Az inline assembly-t tartalmazó C programot a BCC.EXE “ egyenes”
fordítóval kell fordítani és linkelni. Vagy a BCC.EXE -B kapcsolóját
használjuk, vagy a programunk elején elhelyezzük a #pr agma inline
sort. A fordítás ilyenkor a hagyományos .C -> .OBJ -> .EXE sorrend
helyett úgy alakul, hogy a C programot elôször assemblyre fordítja le a
BCC úgy, hogy az assembly részekhez nem nyúl hozzá. Ezután a BCC
elindítja a TASM.EXE programot, ami az assembly programból objekt
programot készít, majd a TLINK.EXE programot indítja el ami létre-
hozza a futtatható programot.

A fordítás menete tehát a következô : .C -> .ASM -> .OBJ -> .EXE.
Amennyiben azt szeretnôk látni, hogy a C forrásprogramunknak milyen
assembly program felel meg, úgy használjuk a BCC -S kapcsolóját.

Példa : bcc -S prog.c

hatására létrejön a prog.asm állomány.

Az inline assembly használat hátrányaként megemlíthetjük, hogy csökkenti az


áttekinthetôséget és a hordozhatóságot !

A következô két példaprogram mindegyike string másolást valósít meg. Az


elsô a függvény paraméterek nevét használja.

34. sz. példaprogram:

#include <stdio.h>
#include <conio.h>
#include <string.h>
#pragma inline

void main()
{
void sm(char * , char * , int );
char st1[] = { "Ezt másoljuk !" } ;
char st2[] = { "xxxxxxxxxxxxxx" } ;
int l;

l = strlen(st1);

sm( st1,st2,l );

printf("\nSTRING1 = %s\n",st1) ;
printf("\nSTRING2 = %s\n",st2) ;

102
Forrás: http://www.doksi.hu

11.1 Inline kapcsolat


getch() ;
}

void sm(char * s1, char * s2, int len)


{
asm {
// A forrás string OFFSET-je SI-ben
mov si,s1
// A cél string OFFSET-je DI-ben
mov di,s2
// A forrás string hossza CX-ben
mov cx,len
}

masol:
asm {
mov al,[si]
mov [di],al
inc si
inc di
loop masol
}
}

A második példaprogram szintén stringmásolást hajt végre, de stack címzést


használ a paraméterek kezeléséhez. A “ vájtfülüeknek” biztosan feltűnik, hogy
hiányzik a BP regiszter elmentése a stack-be, és a mov bp, sp utasítás is. Ez
azért van így, mert a C automatikusan megcsinálja. Ha a programunkat a -S
kapcsolóval assemblyre fordítjuk, akkor ez világosan látszik a listán.

35. sz. példaprogram:

#include <stdio.h>
#include <conio.h>
#include <string.h>
#pragma inline

void main()
{
void sm(char * , char * , int );
char st1[25] = { "Ezt másoljuk !" } ;
char st2[] = { " " };
int l;

103
Forrás: http://www.doksi.hu

11. A C nyelv és az assembly nyelv kapcsolata

l = strlen(st1);

sm( st1,st2,l );

printf("\nSTRING1 = %s\n",st1) ;
printf("\nSTRING2 = %s\n",st2) ;
getch() ;
}

void sm(char * s1, char * s2, int len)


{
asm {
//A forrás string OFFSET-je SI-ben
mov si,[bp+4]
// A cél string OFFSET-je DI-ben
mov di,[bp+6]
// A forrás string hossza CX-ben
mov cx,[bp+8]
}

masol:
asm {
mov al,[si]
mov [di],al
inc si
inc di
loop masol
}
}

11.2 M odul kapcsolat

Ellentétben az inline kapcsolattal, modul kapcsolat esetén forrásnyelvi szinten


nincs közös része a C illetve az assembly nyelvű programnak.

Az elsô dolog amire ügyelni kell, hogy a C nyelvű modul is és az assembly

! nyelvű modul is ugyanazt a memória modellt kell, hogy használja. Esetünkben


ezt a BCC -ms kapcsolójával garantálhatjuk. Az általunk használt egyszerű-
sített szegmensdirektívák BCC kompatibilis szegmenseket generálnak, úgy-
hogy továbbra is használhatóak.

A második dolog az assembly modul használatának formai részével kapcso-


latos. Az assembly rutint a C forrásprogramban EXTERN-ként kell deklarálni.
Az assembly modulban a PUBLIC direktívát kell használni a szubrutin forrás-

104
Forrás: http://www.doksi.hu

11.2 Modul kapcsolat


szövege elôtt. A szubrutin neve az ‘ _’ ( aláhúzás ) karakterrel kell, hogy
kezdôdjön - utalva arra, hogy C nyelvű a hívóprogram !

A harmadik dolog amit meg kell vizsgálnunk, az a C nyelvű modul és

 az assembly nyelvű modul közti paraméterátadás. A C a paramétereit


mindig a stacken keresztül adja át mégpedig olyan sorrendben, hogy a
jobb szélsô para-métert helyezi el elôször a stackben, és utána a többit.
Enek az az eredménye, hogy az elsônek átadott paraméter ( a bal szélsô ) lesz
legközelebb a stack tetejéhez.

Példa : ...
EXTERN szubr2( int, int, int );
int a, b, c;
...
szubr2( a, b, c ); // Assembly nyelvű szubrutin
...

A stack állapota hívás után :

OFFSET R. A.
a
b
c

Mint eddig is az OFFSET R. A. a visszatérési cím ( Return Address ) offset


címe. Ha most a szubrutinban relatív stack címzéssel akarjuk elérni az elôbb
C-bôl átadott paramétereket, akkor ezt a következôképpen tehetjük meg :

Példa : PUBLIC _szubr2


_szubr2 PROC
push bp
mov bp, sp
mov ax,[bp+4] ; Az a paraméter AX-be kerül
mov bx,[bp+6] ; A b paraméter BX-be kerül
mov cx,[bp+8] ; A c paraméter CX-be kerül
.
. ; utasítások
.
_szubr2 ENDP
END

A szubrutin hívás után a stacket a hívó program állítja helyre ! Esetünkben


tehát ez azt jelenti, hogy a C hívási mechanizmus lesz az, amelyik elvégzi az
add sp,6 utasítást !

105
Forrás: http://www.doksi.hu

11. A C nyelv és az assembly nyelv kapcsolata


A negyedik dolog a regiszterek mentésének kérdése. Már az inline kapcsolat-
nál láttuk, hogy van öt regiszter, amelyeknek az értékét a C ugyanúgy akarja
visszakapni, amilyen tartalommal átadta az assemblynek. Ez a helyzet itt sem
változik. Ez az öt regiszter továbbra is a BP, SP, CS, DS, SS. A többi általános
célú regisztert szabadon használhatjuk.

Az ötödik egyben utolsó kérdés a szubrutin által visszaadott érték kérdése. A


mi esetünkben - mivel csak db és dw adattípust használunk - az AL vagy AX
regiszterben kell elhelyezni a visszatérési értéket !

A C illetve az assembly nyelvű forrásmodul fordítása és linkelése pusztán egy


sor begépelését igényli a részünkrôl :

Példa : Legyen egy prg1.c és egy prg2.asm nevű programunk. Ekkor a


következô sort kell begépelnünk :

bcc [-ms] prg1.c prg2.asm

A [] zárójelpárban szereplô kapcsoló opcionális. A C nyelvű


illetve az assembly nyelvű modulnak nem lehet azonos a neve !

Meg kell még válaszolnunk egy kérdést ! Mi van akkor, ha valaki az


objek-tum orientált programozás és az assembly nyelvű modul használat
örömeit akarja élvezni ? Ebben az esetben .CPP kiterjesztést kell ?
használnia, és ilyenkor a fordításnál a függvénynevek megváltoznak.
Ezért valamilyen módon közölnünk kell a fordítóval, hogy az assembly
rutinunk nevét hagyományos C konvenció szerint fordítsa, azaz ne változtassa
meg. Ez a konstrukció a következô :

Példa : A szubr3 egy assemblyben megvalósított rutin és .CPP függ-


vénybôl szeretnénk használni.

extern “ C” {
extern szubr3( int, int * , int);
}

A következô példaprogram a stringmásolást valósítja meg, de most önálló C és


assembly nyelvű modulok formájában.

36. sz. példaprogram:

Elôször a C nyelvű modul listája látható :

106
Forrás: http://www.doksi.hu

11.2 Modul kapcsolat

#include <stdio.h>
#include <conio.h>
#include <string.h>

// String másolás C fôprogram + önálló assembly modul

extern void sm(char * , char * , int );

void main()
{

char st1[25] = { "Ezt másoljuk !" } ;


char st2[25] = { "xxxxxxxxxxxxxx" } ;
int l;

l = strlen(st1);

sm( st1,st2,l );

printf("\nSTRING1 = %s\n",st1) ;
printf("\nSTRING2 = %s\n",st2) ;

getch() ;
}

Majd ezt követi az assembly nyelvű modul :

;
; String másolás szubrutinként megvalósítva
;
.MODEL small
.STACK 100h
.DATA
;
.CODE
PUBLIC _sm
_sm PROC
;
push bp
mov bp,sp
;
mov si,[bp+4] ; A forrás string OFFSET-je SI-ben

107
Forrás: http://www.doksi.hu

11. A C nyelv és az assembly nyelv kapcsolata


mov di,[bp+6] ; A cél string OFFSET-je DI-ben
mov cx,[bp+8] ; A forrás string hossza CX-ben
;
masol:
mov al,[si]
mov [di],al
inc si
inc di
loop masol
;
pop bp
ret
_sm ENDP
END

A következô példaprogram az értékvisszaadást szemlélteti egy C típusú string


hosszának meghatározása kapcsán.

37. sz. példaprogram:

#include <stdio.h>
#include <conio.h>

// Stringhossz meghatározás

void main()
{
extern int sh(char * );
char st1[25] = { "Mennyi lehet a hossza ?" } ;
int l;

l = sh(st1);

sh( st1 );

printf("\nSTRING1 = %s\n",st1) ;
printf("\nHOSSZ = %d\n",l) ;
getch() ;
}

108
Forrás: http://www.doksi.hu

11.2 Modul kapcsolat

;
; String hossza szubrutinként megvalósítva
;
.MODEL small
.STACK 100h
;.DATA
;
.CODE
PUBLIC _sh
_sh PROC
;
push bp
mov bp,sp
;
mov cx,0 ; Itt számoljuk a hosszat
mov si,[bp+4] ; A forrás string OFFSET-je SI-ben
;
hossz:
mov al,[si]
cmp al,0
je vege
inc si
inc cx
jmp hossz
;
vege:
pop bp
mov ax,cx
ret
_sh ENDP
END

A következô példaprogram a jól ismert integer alsó felsô byte megfordítást


mutatja be, de .CPP kiterjesztésű programból hívott assembly modul
segítségével.

38. sz. példaprogram:

109
Forrás: http://www.doksi.hu

11. A C nyelv és az assembly nyelv kapcsolata

#include <stdio.h>
#include <conio.h>

// Integer forditás

extern "C" {
extern void fordit(int * );
}

void main()
{
int i;

printf("\nKérem I értékét : ") ; scanf("%d",& i) ;


fordit( & i );

printf("\nI = %d\n",i) ; getch() ;


}

;
; Integer megforditását végzô assembly szubrutin
;
.MODEL small
.STACK 100h
.CODE
PUBLIC _fordit

fordit PROC
;
push bp ; A bázispointer elmentése a stackba
mov bp,sp
;
mov bx,[bp+4] ; A szám cime a BX - ben !
;
mov ax,[bx] ; Maga a szám az AX-ben !
mov BYTE PTR [bx],ah ; Ez a ket sor a csere
mov BYTE PTR [bx+1],al
;
pop bp
ret
fordit ENDP
END

110
Forrás: http://www.doksi.hu

Ellenôrzô kérdések és feladatok

Ellenôr zô kér dések és feladatok

01. Melyek a C - assembly kapcsolattartás módjai, és mi a különbség


köztük ?

02. Mi az inline kapcsolat lényege ?

03. Mi a modul kapcsolat formai és tartalmi lényege ?

04. Hogyan valósul meg a C paraméterátadási konvenció ?

05. Irjon programot amely összefűz két C típusú stringet. A két stringet C-
ben olvassuk be, magát az összefűzést pedig assemblyben végezzük el.
Oldja meg a feladatot elôször inline assemblyben, majd a modul
kapcsolat segítségével !

06. Irjon programot, amely egy 5x5-ös mátrixot helyben tükröz a fô-
átlójára ! A mátrixot C-ben lehet inicializálni, a tükrözést assemblyben
kell elvégezni. Oldja meg a feladatot elôször inline assemblyben, majd
a modul kapcsolat segítségével !

07. Tegye inteligensebbé a 06. feladat megoldását ! Irja át úgy a prog-


ramot, hogy ne csak 5x5-ös, hanem bármilyen mátrix tükrözésére
alkalmas legyen. Jelezzen hibát, ha a mátrix nem négyzetes !

08. Irjon programot amely eldönti egy 5x5-ös mátrixról, hogy szim-
metrikus-e ! Egy mátrix akkor szimmetrikus, ha aij = aj i minden i,j-re.
A mátrixot C-ben lehet inicializálni, a vizsgálatot assemblyben
kell elvégezni. Oldja meg a feladatot elôször inline assemblyben, majd
a modul kapcsolat segítségével !

09. Irjon egy egyszerűsített morze jeleket elôállító programot ! A program


bemenete egy karakter, amely csak számjegy lehet ! Ezt a karaktert C-
ben kell bekérni, majd át kell adni egy assembly rutinnak. Ez a rutin
elôször vizsgálja le, hogy valóban számjegy érkezett, majd írja ki a
képernyôre a számjegynek megfelelô morze kódot ! A program
kérdezzen rá, hogy akarunk-e még morzézni és ha igenlô a válasz ( i
vagy I ), akkor olvassa be a következô karaktert ! A C - assembly
kapcsolat módja szabadon választott !A számjegyeknek megfelelô
morze kódok a következôk :

1 = .---- 2 = ..--- 3=...-- 4=....- 5=.....


6 = -.... 7 = --... 8 = ---.. 9 = ----. 0 = -----

111
Forrás: http://www.doksi.hu

11. A C nyelv és az assembly nyelv kapcsolata


10. Irjon programot, amely visszafejti a bemenô adatként kapott ötelemű
morze kódból a neki megfelelô számjegyet ! A visszafejtést
assemblyben végezze el !

112
Forrás: http://www.doksi.hu

12. Néhány szó a fej lettebb pr ocesszor ok utasításair ól


Ebben fejezetben azokat a lényeges különbségeket mutatom be amelyek a
tanult i8086-os utasítások és ugyanezen utasítások fejlettebb processzorokon
történô megvalósításai között állnak fenn. Szó lesz továbbá a skálázott cím-
zésrôl is. A programok 386-os üzemmódban készültek ( az TASM assembler
ezen verziójának idejében még nem terjedt el a Pentium ) de az utasítások
ugyanígy szerepelnek a Pentium utasításkészletében is !

12.1 Regiszter készlet, új memór iacímzési mód

A 80386-os processzor és fejlettebb társai 32 bites regiszterekkel


rendelkeznek, csak a szegmensregiszterek maradtak meg 16 bitesnek. A 32
bites regiszterek megszokott nevei elé egy ‘ E’ betű kerül, tehát az AX
regiszterbôl EAX regiszter lesz. Természetesen az alsó 16 bitre ezután is lehet
AX néven hivatkozni, ennek alsó 8 bitjére AL, felsô 8 bitjére pedig AH
névvel. A felsô 16 bitre nem lehet külön nével hivatkozni, de megfelelô rotáló
utasítással az alsó 16 bit helyére lehet rotálni, majd a kívánt művelet elvégzése
után vissza lehet rotálni az eredeti helyére.

EAX

31 15 0
AH AL
AX

Ez a felosztás igaz az eddigi BX, CX, DX illetve új nevükön az EBX, ECX,


EDX regiszterekre is ! Azok a regiszterek emelyek eddig sem voltak felez-
hetôk, azok most sem lettek azok. Az alsó 16 bitre a régi névvel lehet
hivatkozni, például az ESI regiszter alsó 16 bitjének a neve továbbra is SI.

ESI

31 15 0
SI
Forrás: http://www.doksi.hu

12. Néhány szó a fejlettebb processzorok utasításairól

Ez a megállapítás igaz, az ESI, EDI, EBP, ESP, EIP és az EF regiszterekre.

A szegmensregiszterek tehát maradtak 16 bitesek, viszont belép két új szeg-


mensregiszter, az FS és a GS. Ezek az ES regiszterhez hasonlóan felhasználói
adatszegmens kijelölésére és kezelésére alkalmasak.

Az új memória címzési módot skálázott címzésnek hívják. Azt jelenti, hogy


bármely indexregiszter tartalmát eggyel, kettôvel, néggyel illetve nyolccal
lehet szorozni. Nyilván annak a változónak a típusa határozza meg a
szorzótényezôt, amit indexelünk. Látható tehát, hogy a fejletteb
processzoroknál elmozdulás történt - egy fokkal legalábbis - a
pointeraritmetika irányába. Fontos könnyítés még, hogy mindegyik általános
célú 32 bites regiszter lehet bázisregiszter és az ESP regisztert kivéve bár-
melyik lehet indexregiszter. Ha visszaemlékezünk, akkor az i8086-os
processzornál csak a BX illetve BP lehetett bázisregiszter és az SI illetve DI
lehetett indexregiszter. Ezek után a megkülönböztetési szabály a következô :

1. Egy regiszter használata esetén ez a regiszter a bázisregiszter.

2. Két regiszter használata esetén a baloldali lesz a bázisregiszter, a


jobboldali lesz az indexregiszter.

3. Skálázott címzés használata esetén a skálázott regiszter lesz az


indexregiszter, bárhol is áll.

A kérdés többek között azért sem közömbös, mert például az EBP regiszter
bázisregiszterként a stackszegmenst, indexregiszterként az adatszegmenst
címzi !

A következô példaprogram egy 3x3-as mátrix indexelését és kiiratását mutatja


be a skálázott címzés felhasználásával. A 80386-os üzemódot a .386 direktíva
használatával érjük el. Ha ezt a direktívát a .MODEL elé írnánk akkor 32 bites
szegmenseket kapnánk. A .MODEL után írva a hagyományos 16 bites szeg-
mensekkel dolgozunk. A program fordítása hagyományosan történik, a linke-
lésnél a /3 kapcsolót kell alkalmaznunk : tlink /3 filenév.obj

39. sz. példaprogram:

.MODEL small
.386 ; 16 bites szegmensek használata
.STACK 100h
.DATA

112
Forrás: http://www.doksi.hu

12.1 Regiszterkészlet, új memóriacímzési mód


matrix DW 1,2,3
DW 4,5,6
DW 7,8,9
selem DB 5 dup(20h)
selemv LABEL BYTE
DB '$'
elemsz DW 3
sorem DB 13,10,'$'
;
;
.CODE
EXTRN cnts:PROC
EXTRN prst:PROC
;
prgs:
mov ax,@data
mov ds,ax
;
mov cx,0
cikl1:
mov edi,0
kiir :
mov al,cl
mul BYTE PTR [elemsz]
movzx ebx,ax
shl bx,1 ; 2-vel való szorzás a DW miatt
; Kiiratás következik

mov ax,matrix[ebx][edi* 2]
mov bx,OFFSET selemv - 1

push cx ; El mentjük a ciklus változót


mov cx,3
call cnts
pop cx ; Visszahozzuk a ciklus változót

mov bx,OFFSET selem


call prst
inc di
cmp di,[elemsz]
jnz kiir
;
mov ah,9
mov dx,OFFSET sorem
int 21h
inc cx
cmp cx,[elemsz]
jnz cikl1
;
mov ah,9
mov dx,OFFSET sorem

113
Forrás: http://www.doksi.hu

12. Néhány szó a fejlettebb processzorok utasításairól


int 21h
;
mov ah,4ch
int 21h
END prgs

12.2 Új utasítások, új ver ziók

- A léptetô és rotáló utasításoknál megszűnt az a megkötés, hogy a


konstans értéke csak 1 lehet.

- A mov utasítás zéró és elôjel kiterjesztéssel rendelkezik : movzx és


movsx. Míg az i8086-os processzornál tilos volt 8 bites értéket 16 bites
regiszterbe írni, itt a movzx használatával ez lehetségessé válik. A
movzx alkalmazásával a 8 (16) bites érték a 16 (32) bites cél változó
alsó 8 (16) bitjére íródik, a felsô 8 (16) bit kinullázódik. A másik ki-
terjesztés elôjeles másolást engedélyez.

Példa : i8086-os processzor esetén a mov bx,dl használata tilos.


i80386-os processzor esetén a movzx bx,dl érvényes
művelet.

Példa : i8086-os processzor esetén egy elôjeles byte-ot, a


következôképpen lehetett egy 16 bites regiszterbe írni :

...
mov al,[byte]
cbw ; AX-be konvertáljuk elôjelesen
mov dx,ax
...

i80386-os processzor esetén ugyanez :

...
mov sx dx,[byte]

114
Forrás: http://www.doksi.hu

12.2 Új utasítások, új verziók


...

- A loop utasításnak megfelelô új utasítás a loopd. Ez az utasítás az ECX


regiszterrel működik együtt. A loope utasításnak a loopde a loopne
utasításnak a loopdne felel meg. Működésük logikája megegyezik.

- A meglévô stringutasításokhoz újak társulnak : a lods új alakja a lodsd,


a stos új alakja stosd, movs utasításé a movsd. Az öszehasonlító
utasítások új alakjai : scasd és cmpsd.

- Az újdonságok ismertetését az imul utasítás új verzióinak ismerteté-


sével fejezem be. Az imul utasításnak két sôt három operandusa is le-
het, az alábbiak szerint :

1. Lehetôség van közvetlen konstanssal való szorzásra

2. Bármely regiszter szorozható bármely regiszterrel, illetve


memóriaváltozóval.

3. A szorzás eredménye külön célregiszterben tárolható.


Ilyenkor a célregiszter az elsô operandus, a második az
egyik szorzótényezô, a harmadik pedig a másik szorzó-
tényezô. A harmadik operandus csak konstans lehet !

Nézzük meg a következô példaprogram segítségével az imul utasítás külön-


bôzô verzióinak működését. Az eredmények megtekintéséhez a TD-t
használjuk !

40. sz. példaprogram:

.MODEL small
.386 ; 16 bites szegmensek
.STACK 100h
.DATA
;
szorzo1 dw 2
szorzo2 dw 3
szorzat dw 0
;
.CODE

115
Forrás: http://www.doksi.hu

Függelék : A tanult utasítások összefoglalása


mov ax,@data
mov ds,ax
;
mov cx,[szorzo1]
imul cx,[szorzo2]
imul cx,2
; imul cx,[szorzo1],[szorzo2] Ezt nem fogadja el !
; imul [szorzo1],[szorzo2] Ezt meg nem hajtja vegre !
mov ax,[szorzo2]
imul dx,ax,2
imul cx,[szorzo1],3
shl cx,4
mov [szorzat],cx
;
mov ah,4ch
int 21h
END

Függelék : A tanult utasítások összefoglalása

Adatmozgató, ar itmetikai utasítások

Utasítás Működés leírása Érintett flagek

MOV op1, op2 op1 = op2 -


ADD op1,op2 op1 = op1 + op2 C,P,A,Z,S,O
ADC op1,op2 op1 = op1 +op2 + [CF] C,P,A,Z,S,O
SUB op1,op2 op1 = op1 - op2 C,P,A,Z,S,O
SBB op1,op2 op1 = op1 - op2 - [CF] C,P,A,Z,S,O
CMP op1,op2 op1 - op2 C,P,A,Z,S,O
INC op op = op + 1 P,A,Z,S,O
DEC op op = op - 1 P,A,Z,S,O
NEG op op = -op C,P,A,Z,S,O
CBW AX <- AL -
CWD DX:AX <- AX -
MUL op AX = AL* op C,O
IMUL op AX = AL* op (elôjeles) C,O

116
Forrás: http://www.doksi.hu

Logikai utasítások
DIV op AL = AX/op Határozatlan
IDIV op AL = AX/op (elôjeles) Határozatlan
XCHG op1, op2 op1 <--> op2 -

L ogikai utasítások

Utasítás Működés leírása Érintett flagek

AND op1,op2 op1 = op1 AND op2 ; bitenként C=0,P,Z,S,O=0


TEST op1,op2 op1 AND op2 ; bitenként C=0,P,Z,S,O=0
OR op1,op2 op1 = op1 OR op2 ; bitenként C=0,P,Z,S,O=0
XOR op1,op2 op1 = op2 XOR op2 ; bitenként C=0,P,Z,S,O=0
NOT op op = NOT op ; bitenként A,P,Z,S,O

Ugr ó utasítások

Feltételnélküli ugró utasítás

Utasítás Működés leírása Érintett flagek

JMP címke IP = IP + OFFSET címke -


vagy
IP = IP + Eltolás -

Feltételes ugró utasítások

Elôjelnélküli mennyiségekkel kapcsolatos ugró utasítások :

CMP op1,op2 ; op1 és op2 elôjelnélküli mennyiségek

Utasítás Működés leírása Érintett flagek

117
Forrás: http://www.doksi.hu

Függelék : A tanult utasítások összefoglalása


JA cimke ugrás ha op1 > op2 -
JB cimke ugrás ha op1 < op2 -
JE cimke ugrás ha op1 = op2 -
JAE cimke ugrás ha op1 >= op2 -
JBE cimke ugrás ha op1 <= op2 -
JNA cimke ugrás ha op1 <= op2 -
JNB cimke ugrás ha op1 >= op2 -
JNE cimke ugrás ha op1 != op2 -
JNAE cimke ugrás ha op1 < op2 -
JNBE cimke ugrás ha op1 > op2 -

Elôjeles mennyiségekkel kapcsolatos ugró utasítások

CMP op1,op2 ; op1 és op2 elôjeles mennyiségek

Utasítás Működés leírása Érintett flagek

JG cimke ugrás ha op1 > op2 -


JL cimke ugrás ha op1 < op2 -
JE cimke ugrás ha op1 = op2 -
JGE cimke ugrás ha op1 >= op2 -
JLE cimke ugrás ha op1 <= op2 -
JNG cimke ugrás ha op1 <= op2 -
JNL cimke ugrás ha op1 >= op2 -
JNE cimke ugrás ha op1 != op2 -
JNGE cimke ugrás ha op1 < op2 -
JNLE cimke ugrás ha op1 > op2 -

Flagek értékétôl függô ugró utasítások

Utasítás Működés leírása Érintett flagek

JC cimke ugrás, ha CF = 1 -
JS cimke ugrás, ha SF = 1 -
JO cimke ugrás, ha OF = 1 -
JZ cimke ugrás, ha ZF = 1 -
JP cimke ugrás, ha PF = 1 -
JPE cimke ugrás, ha PF = 1 -
JPO cimke ugrás, ha PF = 0 -
JNC cimke ugrás, ha CF = 0 -
JNS cimke ugrás, ha SF = 0 -
JNO cimke ugrás, ha OF = 0 -
JNZ cimke ugrás, ha ZF = 0 -
JNP cimke ugrás, ha PF = 0 -
JNPE cimke ugrás, ha PF = 0 -

118
Forrás: http://www.doksi.hu

Ciklus szervezô utasítások


JNPO cimke ugrás, ha PF = 1 -

Ciklus szer vezô utasítások

Utasítás Működés leírása Érintett flagek

LOOPcímke Ha CX > 0, akkor ugrás a címkére -

LOOPE címke Ha CX >0 és ZF = 1 akkor ugrás a -


(LOOPZ) címkére

LOOPNE címke Ha CX >0 és ZF = 0 akkor ugrás a -


(LOOPNZ) címkére

JCXZ címke Ha CX=0 akkor ugrás a címére -

L éptetô és r otáló utasítások

Utasítás Működés leírása Érintett flagek

SHL, SAL op1,op2 Bitléptetés balra op2-vel C,P,Z,S,O


SHR op1, op2 Bitléptetés jobbra op2-vel C,P,Z,S,O
SAR op1, op2 Aritmetikai bitléptetés jobbra op2-vel C,P,Z,S,O
ROL op1, op2 Bitrotáció balra op2-vel C,O
RCL op1,op2 Bitrotáció balra a CF-en keresztül C,O
ROR op1,op2 Bitrotáció jobbra op2-vel C,O
RCR op1,op2 Bitrotáció jobbra a CF-en keresztül C,O

Feltételbit ( flag ) műveletek

Utasítás Működés leírása Érintett flagek

CLC CF = 0 C=0
CMC CF = NOT CF C
STC CF = 1 C=1
CLD DF = 0 D=0
STD DF = 1 D=1
CLI IF = 0 I=0
STI IF = 1 I=1

119
Forrás: http://www.doksi.hu

Irodalomjegyzék
Szubr utin szer vezô uatsítások

Utasítás Működés leírása Érintett flagek

CALL címke Vezérlésátadás cimke nevű szubrutinra -


RET Visszatérés szubrutinból -

Ver em (stack) műveletek

Utasítás Működés leírása Érintett flagek

PUSH op Két byte írása a stack tetejére op-ból -


POP op Két byte olvasása a stack tetejérôl op-ba -

Str ingműveletek

Utasítás Működés leírása Érintett flagek

LODS Egy byte/szó olvasása [SI]-rôl AL/AX-be -


STOS Egy byte/szó írása [DI]-re AL/AX-ból -
MOVS Egy byte/szó olvasása [SI]-rôl és ki- -
írása [DI]-re
SCAS Az ES:DI-n lévô byte/szó értékét C,P,A,Z,S,O
hasonlítja össze AL/AX tartalmával
CMPS Az ES:DI-n lévô byte/szó értékét C,P,A,Z,S,O
hasonlítja össze a DS:SI-n tárolt
byte/szó tartalmával
REP Addig ismétlôdik az utasítás, amíg CX != 0 -
REPE Ismétlôdés amíg CX != 0 és ZF = 1 -
(REPZ)
REPNE Ismétlôdés amíg CX != 0 és ZF = 0 -
(REPNZ)

I r odalomj egyzék

A felhasznált irodalom a következô :

120
Forrás: http://www.doksi.hu

Stringműveletek
1. Dr. Gidófalvi Zoltán : Az IBM PC programozása assembly
nyelven.

Novotrade 1988

2. BORLAND Turbo Assembler User’ s Guide Version 1.0

Borland International 1988, 1989

3. Grochmann-Eicher : A 8086/88-as mikroprocesszor. Technika és


programozás.

Data Becker - Novotrade 1987

121
Forrás: http://www.doksi.hu

TARTAL OM JEGYZÉK

Elôszó ........................................................................................................................7

Bevezetés ....................................................................................................................... 8

1. Az i8086-os processzor memóriakezelése és regiszterei ......................................... 11


1.1 Memóriakezelés ................................................................................... 11
1.2 Az i8086-os regiszterei ........................................................................ 12
1.3 Az alkalmazott software eszközök ......................................................... 16
Ellenôrzô kérdések és feladatok ................................................................... 17

2. Egyszerûsített direktívák, fôbb adattípusok, alapvetô DOS szolgáltatások. .............18


2.1 A HELLO.ASM ismertetése ................................................................ 18
2.2 További DOS szolgáltatások ismertetése ................................................21
2.3 Alapvetô adattípusok és definiálásuk ......................................................21
Ellenôrzô kérdések és feladatok ....................................................................23

3. Aritmetikai utasítások ............................................................................................ 24


3.1 Az i8086-os processzor általános utasításformátuma ............................ 24
3.2 A MOV utasítás .................................................................................... 25
3.3 Az ADD és ADC utasítások ................................................................. 25
3.4 A SUB és SBB utasítások .................................................................... 26
3.5 A CMP utasítás .................................................................................... 27
3.6 Az INC utasítás .................................................................................... 27
3.7 A DEC utasítás ..................................................................................... 28
3.8 A NEG utasítás ...................................................................................... 28
3.9 A CBW és CWD utasítások .................................................................. 28
3.10 A MUL és IMUL utasítások ............................................................... 29
3.11 A DIV és IDIV utasítások ................................................................... 29
3.12 Az XCHG utasítás ................................................................................ 30
3.13 Az OFFSET operátor ........................................................................... 30
Ellenôrzô kérdések és feladatok .................................................................... 31

4. Logikai utasítások ................................................................................................... 32


4.1 Az AND és a TEST utasítások ............................................................. 32
4.2 Az OR utasítás ....................................................................................... 33
4.3 Az XOR utasítás ................................................................................... 34
4.4 A NOT utasítás........................................................................................ 34
Ellenôrzô kérdések és feladatok .................................................................. 35

5. Feltételnélküli és feltételes ugró utasítások ..............................................................36


5.1 Feltételnélküli ugró utasítás : jmp ......................................................... 36
5.2 Feltételes ugró utasítások ..................................................................... 37
5.2.1 Elôjel nélküli mennyiségekkel kapcsolatos utasítások ...... 37

3
Forrás: http://www.doksi.hu

5.2.2 Elôjeles mennyiségekkel kapcsolatos utasítások ............... 38


5.2.3 Flagek értékétôl függô utasítások ...................................... 38
Ellenôrzô kérdések és feladatok ................................................................... 41
6. Ciklusszervezô utasítások ....................................................................................... 42
6.1 A loop utasítás ....................................................................................... 42
6.2 A loope és a loopne utasítások .............................................................. 43
6.3 A Turbo Debugger használata ............................................................... 44
Ellenôrzô kérdések és feladatok ................................................................... 47

7. Memória címzési módok ....................................................................................... 48


7.1 Közvetlen operandusú címzés .............................................................. 48
7.2 Direkt címzés ........................................................................................ 48
7.3 Indirekt címzés ..................................................................................... 48
7.4 Indexelt címzés ...................................................................................... 50
Ellenôrzô kérdések és feladatok ................................................................... 56

8. Léptetô és flagekkel kapcsolatos utasítások .......................................................... 57


8.1 Az SHL, és SAL utasítások ................................................................... 57
8.2 Az SHR és SAR utasítások ................................................................... 58
8.3 A ROL és RCL utasítások ..................................................................... 59
8.4 A ROR és RCR utasítások ..................................................................... 60
8.5 Flagekkel kapcsolatos utasítások ............................................................ 61
Ellenôrzô kérdések és feladatok .................................................................... 63

9. Szubrutinok szervezése .......................................................................................... 64


9.1 A szubrutin formai szervezése és hívása ............................................... 64
9.2 A szubrutinhívás és visszatérés mûködése ............................................ 65
9.3 A paraméter át - és visszaadás kérdése ................................................. 66
9.3.1 A PUSH és a POP utasítások ........................................... 67
9.4 Kész szubrutinok szerkesztése, saját könyvtárak létrehozása ............... 72
9.5 Makró alkalmazás ................................................................................. 80
Ellenôrzô kérdések és feladatok ............................................................... 82

10. String utasítások, DOS és BIOS szolgáltatások ................................................... 83


10.1 A LODS utasítás .................................................................................. 83
10.2 A STOS utasítás .................................................................................... 84
10.3 A MOVS utasítás .................................................................................. 88
10.4 A SCAS utasítás ......................................................................................90
10.5 A CMPS utasítás .....................................................................................90
10.6 String utasítás prefixek : REP, REPE, REPNE .......................................91
10.7 DOS szolgáltatás hívását bemutató példaprogram ................................ 95
10.8 BIOS szolgáltatás hívását bemutató példaprogram ............................... 98
Ellenôrzô kérdések és feladatok .....................................................................99

11. A C nyelv és az assembly nyelv kapcsolata ........................................................ 100


11.1 Inline kapcsolat ................................................................................... 100

4
Forrás: http://www.doksi.hu

11.2 Modul kapcsolat .................................................................................. 104


Ellenôrzô kérdések és feladatok ................................................................... 110

12. Néhány szó a fejlettebb processzorok utasításairól ............................................. 111


12.1 Regiszterkészlet, új memória címzési mód .......................................... 111
12.2 Új utasítások, új verziók ....................................................................... 114

Függelék : A tanult utasítások összefoglalása ........................................................... 116


PÉL DAPROGRAM OK JEGYZÉK E

01. Üzenet kiiratása képernyôre ................................................................................... 18


02. Bit maszkolás ..................................................................................................... 33
03. Két karakter összehasonlítása ................................................................................ 40
04. Integer alsó és felsô byte-jának megfordítása ........................................................ 44
05. Számjegyek számlálása egy max. 70 hosszú karaktersorozatban .......................... 46
06. Kisbetûs karaktersorozat átalakítása nagybetûssé ................................................. 51
07. Két 10 elemû integer vektor összeadása ................................................................ 52
08. C típusú string hosszának megállapítása ............................................................... 53
09. C típusú string másolása ........................................................................................ 54
10. 3x3-as karaktermátrix indexelése és kiiratása ....................................................... 55
11. Hamming távolság kiszámítása ............................................................................. 61
12. Soros protokol szimulálása .................................................................................... 62
13. A PUSH és a POP utasítások mûködése ................................................................ 67
14. Integer kiiratása szubrutinnal ................................................................................. 70
15. Integer alsó és felsô byte-jának megfordítása, kiiratás szubrutinnal ..................... 74
16. Ugyanaz mint 15. , de a szubrutinok egy saját könyvtárban vannak ..................... 76
17. Ugyanaz mint 15. , de a megfordítást is szubrutin végzi ....................................... 77
18. Ugyanaz mint 17. , de a paraméterátadás a stacken keresztül történik .................. 78
19. Ugyanaz mint 17. , de globális változó használattal .............................................. 79
20. Egyszerû makró alkalmazás ................................................................................... 81
21. String másolás a LODS és a STOS utasítások címmel történô alkalmazásával .... 84
22. String másolás a LODSB és a STOSB utasítások alkalmazásával ........................ 85
23. Ugyanaz mint 22. , de csökkenô indexek mentén ...................................................86
24. Integer másolás a LODS és a STOS utasítások címmel történô alkalmazásával ... 87
25. Integer másolás a LODSW és a STOSW utasítások alkalmazásával .................... 88
26. String másolás a MOVSB utasítás alkalmazásával ............................................... 89
27. String másolás a REP prefix, és a MOVSB utasítás alkalmazásával .................... 91
28. Integer másolás a REP prefix és a MOVS címmel történô alkalmazásával .......... 92
29. Integer másolás a REP prefix és a MOVSW utasítás alkalmazásával ................... 93
30. Szóköz keresése szövegben a SCASB utasítás alkalmazásával ............................ 94
31. Szövegminta keresése szövegben a CMPSB utasítás alkalmazásával .................. 94
32. A DOS dátumelôállító ( 2ah ) függvénye mûködésének bemutatása .................... 96
33. A BIOS képernyôkezelô ( 10h ) szolgáltatása 09h funkciójának bemutatása ....... 98
34. Stringmásolás inline assembly betéttel, változónév használattal ......................... 102

5
Forrás: http://www.doksi.hu

35. Ugyanaz mint 34. , de a paraméterekre stack címzéssel hivatkozunk ................. 103
36. Stringmásolás megoldása C és assembly modul kapcsolat segítségével ............. 106
37. C típusú string hosszának meghatározása modul kapcsolat segítségével ............ 107
38. Integer alsó és felsô byte-jának megfordítása .CPP kiterjesztésû programból .... 109
39. 3x3-as mátrix indexelése skálázott címzéssel ...................................................... 112
40. Szorzás változatok az IMUL utasítás új alakjaival .............................................. 115

You might also like