Hardver alapismeretek programozóknak Szemelvények Utolsó szerkesztés: 2011. Ápr 19
Végh János (
[email protected])
Nyomtatva: 2011. június 1.
1
Hardver alapismeretek programozóknak
2/23
Tartalomjegyzék I.
Hardver
4
1. Próba 2. Bevezetés 2.1. A „kis ember” számítógép 2.2. A Neumann architektúra 2.3. A szoftveres felépítés . . . 2.4. A „kis ember” számítógép
4 . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
4 4 5 6 7
3. Architektúra 3.1. Memória . . . . . . . . . . . . . . . . . . . . . 3.1.1. Memóriatípusok . . . . . . . . . . . . 3.2. I/O . . . . . . . . . . . . . . . . . . . . . . . . 3.2.1. A CPU összekapcsolása a külvilággal 3.2.2. Az I/O eszközök kezelése . . . . . . . 3.3. Buszok . . . . . . . . . . . . . . . . . . . . . 3.4. CPU . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
8 8 9 9 11 12 12 15
. . . .
15 15 16 18 21
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
4. Verem 4.1. A verem tároló használata adat mozgató utasításokkal . 4.2. A verem tároló használata szubrutin hívására . . . . . . 4.3. A verem tároló használata szubrutinon belül . . . . . . 4.4. Paraméter átadás szubrutin hívás során . . . . . . . . .
II.
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
Szoftver
23
Ábrák jegyzéke 2.1. 2.2. 2.3. 2.4. 2.5. 2.6. 2.7. 3.2. 3.1. 3.3. 3.4. 3.5. 3.6. 3.7. 3.8.
Egy tipikus PC konfiguráció . . . . . . . . . . . . . . . . . Egy egyszeru ˝ mikroszámítógép szerkezete . . . . . . . . . Kis ember a számítógépben . . . . . . . . . . . . . . . . . . A Neumann-féle számítógép elvi architektúrája . . . . . . A Neumann és a Harvard architektúrák összehasonlítása Szoftveres összetev˝ok . . . . . . . . . . . . . . . . . . . . . Kis ember a számítógépben . . . . . . . . . . . . . . . . . . A ki/bemeneti címek leképezése . . . . . . . . . . . . . . . Általánosan használt memória típusok . . . . . . . . . . . Az I/O címek tere . . . . . . . . . . . . . . . . . . . . . . . Egy tipikus output port . . . . . . . . . . . . . . . . . . . . Egy írás/olvasást támogató output port . . . . . . . . . . Beviteli illeszt˝o egység . . . . . . . . . . . . . . . . . . . . . Kiviteli illeszt˝o egység . . . . . . . . . . . . . . . . . . . . . Memóriára leképezett és I/O térbeli eszközök kezelése . .
Tartalomjegyzék
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
4 5 5 6 6 8 8 10 10 11 11 12 12 12 13
Hardver alapismeretek programozóknak
3/23
3.9. Memóriára leképezett és I/O térbeli eszközök elérése . . . . . . 3.10.Kiszolgálás lekérdezéssel és megszakítással . . . . . . . . . . . 3.11.A számítógép buszrendszer blokkdiagramja . . . . . . . . . . . 4.1. A verem tároló használata adat mozgató utasításokkal . . . . . 4.2. A CALL és RET utasítások hatása az EIP és ERP regiszterekre 3.12.A Neumann-féle számítógép tényleges architektúrája . . . . . 4.3. Extra PUSH használatának hatása szubrutinban . . . . . . . . 4.4. Extra POP használatának hatása szubrutinban . . . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
13 13 13 17 18 19 20 20
2.1. Az LMC utasításkészlete . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2. Az LMC utasításkészlete . . . . . . . . . . . . . . . . . . . . . . . . . . .
6 9
Táblázatok jegyzéke
Listings lst/ExtraPOP.asm . . . . . . lst/nonworkingsub1.asm . . lst/nonworkingsub2.asm . . lst/passthroughstack.asm . lst/passthroughstack2.asm lst/ardemo.asm . . . . . . .
Táblázatok jegyzéke
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
19 21 22 22 23 23
Hardver alapismeretek programozóknak
I. rész
Hardver 1. Próba 2. A hardver-közeli programozás, madártávlatból Manapság szinte mindenütt ún. személyi számítógépekkel (Personal Computer, PC) dolgozunk, legyen bár iskolai, hivatali vagy otthoni felhasználó. Ez a számítógép valamilyen „fekete mágia” révén, használja a hozzá kapcsolt berendezéseket, az ún. perifériákat, lásd 2.1 ábra.
4/23 Ennek szellemében nem megyünk bele egyik területen sem a gyorsan változó részletekbe, és nagyon sok esetben használunk jelent˝os egyszerusítéseket. ˝ Az el˝oadási anyaghoz szervesen illeszkedik a laboratóriumi gyakorlat: az el˝oadás anyagát a speciálisan elkészített laboratóriumi gyakorlatokon tehetjük él˝ové. Els˝o megközelítésben a következ˝o összetev˝oket látjuk egy ilyen rendszerben: Hardver
• Utasítások végrehajtásával adatokat dolgoz fel
• Ki/bevitellel adatokat cserél a környezetével • Vezérli az adatok ki/bevitelét, tárolását, feldolgozását Szoftver
• Alapvet˝oen alkalmazói és rendszerprogramokat különböztetünk meg
• Utasítások határozzák meg, hogy a hardvernek mit és mikor kell elvégezni Adatok
c 2010 Wiley/Englander
• Tényeket és megfigyeléseket ábrázol
Kommunikáció • Er˝oforrásokat oszt meg különálló rendszerek között
2.1. ábra. Egy tipikus PC konfiguráció
2.1. A „kis ember” számítógép Ebben a jegyzetben megpróbálunk segítséget adni ahhoz, hogy megértsük: hogyan is muködik ˝ számítógépünk (a hardver és a szoftver), amit nap-mintnap használunk. Mivel alapfokú megértés a célunk, nem akarunk sem hardver tervezési ismereteket közvetíteni, sem szoftver algoritmusokat részletesen ismertetni. Célunk viszont az egész folyamat megértése és átlátása; megismerése azon fogalmaknak, amelyeknek részletei azután a különböz˝o területek specializált szakkönyveib˝ol tanuljuk meg.
2.1. A „kis ember” számítógép
A számítógép muködésének ˝ rejtelmeit kezdjük egy kicsit iskolás példán tanulmányozni. Van egy olyan „számítógépünk”, lásd 2.7 ábra, amelyikben egy kis ember hajt végre néhány egyszeru ˝ feladatot. Ez lesz a továbbiakban az LMC (Little Man Computer). A "kis ember" rendelkezésére áll egy kalkulátor, amelyik muveleteket ˝ tud végezni a megadott adatokkal, van egy számlálója, amit minden muvelet ˝ végeztével továbbítani tud. A bemen˝o adatokat egy
Hardver alapismeretek programozóknak bemeneti kosárkában kapja meg, az eredményeket egy kimeneti kosárkába rakja. A közbüls˝o adatokat a „postafiókokban” tárolja, amelyeket a 00 és 99 közötti számok azonosítanak; a tartalmuk pedig vagy egy utasítás vagy egy adat (mindenképpen háromjegyu ˝ szám) lehet. A program betöltésekor megtöltjük a postafiókokat, a „bejöv˝o adat” kosárkába odatesszük a feldolgozandó adatot, és: elkezd muködni ˝ a program. Nézzük, hogyan is csinálja.
5/23 vagy pedig annak címét; lásd 2.2 táblázat. Az így megadott utasítások a gépi kódok, amelyeknek a könnyebb kezelésére egy emlékeztet˝o szimbólumot használunk (nmemonik). Az ilyen szimbólumokat használó nyelv az assembly nyelv, amelyik egy-egy módú leképezést hajt végre a gépi kód és az assembly utasítás között. Az assembly nyelv CPU specifikus, tipikusan hardver vezérlésre használják.
LDA ADD,SUB STO
IN
T OU c Wiley 2005, Maxfield
2.2. ábra. Egy egyszeru ˝ mikroszámítógép szerkezete Nézzük meg el˝oször, hogy milyen típusú muveleteket ˝ kell emberkénknek végrehajtani. Szükség van arra, hogy a bemen˝o kosárkákból elvegye az adatokat (IN ), az eredményeket pedig oda tegye (OU T ). Szükség van az adatok el˝ovételére (LDA) és elrakására (ST O), valamint muveletvégz˝ ˝ o utasításokra: tudjon összeadni (ADD) és kivonni (SU B). Kés˝obb még hozzáveszünk ugró (BR) és elágaztató (BRZ, BRP ) utasításokat, valamint a számítógép megállítására való (ST OP ) utasítást is. Az utóbbit a kis ember csak kávészünetnek (COB) értelmezi. A postafiók tartalmát utasításként értelmezzük, a háromjegyu ˝ szám els˝o jegye adja meg a muvelet ˝ kódját (OP code), a másik két jegy pedig az operandust (amivel a muveletet ˝ végezzük),
2.2. A Neumann architektúra
2.3. ábra. Kis ember a számítógépben Mint látható, a ki/beviteli utasítások esetén az utasítás két utolsó jegye nem a postafiók számot adja meg; lásd még az I/O címtér és memória címtér megfogalmazását. A bejöv˝o adatot a kis ember a kosárkából a kalkulátorhoz viszi, és a kiszámított eredményt közvetlenül a kiviteli kosárkába teszi.
2.2. A Neumann architektúra A számítógépek gyakorlatilag egészen napjainking ható felépítési elvét Neumann János 1945-ös publikációja határozza meg (ez váltotta fel a korábbi „huzalozott” logikát). A f˝o alkotóelemek, lásd 2.4 ábra): Memória írható/olvasható, véletlen hozzáférésu ˝ tároló, az utasítások és adatok tárolására
Hardver alapismeretek programozóknak 2.1. táblázat. Az LMC utasításkészlete Utasítás típus Arithmetic Data movement Jump Branch on 0 Branch on + Input/output Input/output Machine control (Coffee break)
Érték 1XX 2XX 3XX 5XX 6XX 7XX 8XX 901 902 000
Muvelet ˝ ADD SUB STO LDA BR BRZ BRP IN OUT HALT COB
6/23 terület elkülönítése (az ún. Harvardarchitektúra, lásd 2.5 ábra). A Harvardarchitektúra fontos el˝onye, hogy az adatokhoz a programutasítás végrehajtásával egyidejuleg ˝ is hozzá lehet férni, mivel mindkét memóriarész saját busszal kapcsolódik a CPUhoz. Mikrokontrollerekben, mikroprocesszorokban szinte kizárólagos jelleggel használják. A konkrét megoldások természetesen különböznek. Néhány konkrét megoldás esetén napjaink egyik legelterjedtebb processzortípusa, az Intel 80x86 megoldásai szerepelnek példaként.
2.3. A szoftveres felépítés Vezérl˝ oegység az utasítások el˝ovételére a memóriából, dekódolásra, és a muveletek ˝ koordinálására Aritmetikai egység az aritmetikai mu˝ veletek végzésére Ki/bevitel kapcsolat az emberi operátorral
A számítógépet alkotó hardver elemeket olyan programok közvetítésével használjuk, amelyek alapvet˝oen kétféle irányban kommunikálnak. Az alkalmazói programok a felhasználóval állnak kapcsolatban, az ún rendszer programok egy része pedig a hardverrel foglalkozik. A szoftvereket alapvet˝oen a 2.6 ábra szerint kategorizáljuk, egyfajta hierachia szerint.
c 2006 http://www.tomchrane.com
c 2004 https://computing.llnl.gov
2.4. ábra. A Neumann-féle számítógép elvi architektúrája Szinte az egyetlen lényeges javítás ehhez képest a program és az adattároló
2.3. A szoftveres felépítés
2.5. ábra. A Neumann és a Harvard architektúrák összehasonlítása • Alkalmazások • Operációs rendszer
Hardver alapismeretek programozóknak
7/23
– API: application program interface
• gyakran kell szimulátort használni
– Fájl kezel˝o rendszer – Ki/bevitel – Kernel ∗ ∗ ∗ ∗
Memória kezelés Er˝oforrás ütemezés Program kommunikáció Biztonság
– Hálózati modul A következ˝okben alapvet˝oen a rendszerprogramozás alapjaival fogunk foglalkozni, azaz azt próbáljuk megérteni, hogy milyen hardver muködés ˝ áll az ismert folyamatok mögött, illetve milyen programozási módszerrel lehet meghatározott muködést ˝ elérni. Ez utóbbi a hardver alapos ismeretét, és az alkalmazói programoktól alapvet˝oen eltér˝o programozási tudást igényel. Ebben a kurzusban ilyen ismereteket fogunk szerezni. A rendszerprogramozás során • jó hardver (és egyéb rendszer) ismeretekre van szükség • nagyon hatékonyan (kis runtime overhead) kell programozni • kevés er˝oforrással gazdálkodhatunk, nincs hulladékgyujtés, ˝ stb • ha van is támogató könyvtár (runtime library), nagyon kicsi • általában „nyers” kezelést igényel, közvetlenül a hardvert kezel˝o regiszterekkel kell foglalkozni • sok gépi (assembly) kódú támogatást igényel, vagy ilyen nyelven írt rutinokat vagy ilyen betéteket • nagyon nehéz hibát keresni, inkább monitoring és logging használatos 2.4. A „kis ember” számítógép
Ebbe a témakörbe tartozik az operációs rendszer bizonyos részeinek kódolása, és az eszközmeghajtók írása is. El˝oször áttekintjük a szükséges hardver ismereteket, a programozó szemével.
2.4. A „kis ember” számítógép A számítógép muködésének ˝ rejtelmeit kezdjük egy kicsit iskolás példán tanulmányozni. Van egy olyan „számítógépünk”, lásd 2.7 ábra, amelyikben egy kis ember hajt végre néhány egyszeru ˝ feladatot. Ez lesz a továbbiakban az LMC (Little Man Computer). A "kis ember" rendelkezésére áll egy kalkulátor, amelyik muveleteket ˝ tud végezni a megadott adatokkal, van egy számlálója, amit minden muvelet ˝ végeztével továbbítani tud. A bemen˝o adatokat egy bemeneti kosárkában kapja meg, az eredményeket egy kimeneti kosárkába rakja. A közbüls˝o adatokat a „postafiókokban” tárolja, amelyeket a 00 és 99 közötti számok azonosítanak; a tartalmuk pedig vagy egy utasítás vagy egy adat (mindenképpen háromjegyu ˝ szám) lehet. A program betöltésekor megtöltjük a postafiókokat, a „bejöv˝o adat” kosárkába odatesszük a feldolgozandó adatot, és: elkezd muködni ˝ a program. Nézzük, hogyan is csinálja. Nézzük meg el˝oször, hogy milyen típusú muveleteket ˝ kell emberkénknek végrehajtani. Szükség van arra, hogy a bemen˝o kosárkákból elvegye az adatokat (IN ), az eredményeket pedig oda tegye (OU T ). Szükség van az adatok el˝ovételére (LDA) és elrakására (ST O), valamint muveletvégz˝ ˝ o utasításokra: tudjon összeadni (ADD) és kivonni (SU B). Kés˝obb még hozzáveszünk ugró (BR) és elágaztató (BRZ, BRP ) utasításokat, valamint a számítógép megállítására való (ST OP ) utasítást is. Az utóbbit a
Hardver alapismeretek programozóknak
8/23
LDA ADD,SUB STO
IN
T OU
2.7. ábra. Kis ember a számítógépben galmazását. A bejöv˝o adatot a kis ember a kosárkából a kalkulátorhoz viszi, és a kiszámított eredményt közvetlenül a kiviteli kosárkába teszi.
c 2010 Wiley/Englander
2.6. ábra. Szoftveres összetev˝ok kis ember csak kávészünetnek (COB) értelmezi. A postafiók tartalmát utasításként értelmezzük, a háromjegyu ˝ szám els˝o jegye adja meg a muvelet ˝ kódját (OP code), a másik két jegy pedig az operandust (amivel a muveletet ˝ végezzük), vagy pedig annak címét; lásd 2.2 táblázat. Az így megadott utasítások a gépi kódok, amelyeknek a könnyebb kezelésére egy emlékeztet˝o szimbólumot használunk (nmemonik). Az ilyen szimbólumokat használó nyelv az assembly nyelv, amelyik egy-egy módú leképezést hajt végre a gépi kód és az assembly utasítás között. Az assembly nyelv CPU specifikus, tipikusan hardver vezérlésre használják. Mint látható, a ki/beviteli utasítások esetén az utasítás két utolsó jegye nem a postafiók számot adja meg; lásd még az I/O címtér és memória címtér megfo3. Architektúra
3. Számítógép szerkezet a programozó szemével 3.1. Program- és (memória)
adattárolás
Egy tipikus 80x86 processzor legfeljebb 2n memóriahelyet tud megcímezni, ahol n a címbusz bitjeinek száma. A 80x86 processzorok 20, 24, 32 és 36 bites címbusszal rendelkeznek (és már jön a 64 bites). Természetesen az els˝o felmerül˝o kérdés "Mi is pontosan egy memóriahely?" A 80x86 bájtcímzésu ˝ memóriát támogat, tehát a memória alapegysége a bájt. A 20, 24, 32 illetve 36 címvonallal a 80x86 processorok egy megabájt, 16 megabájt, négy gigabájt illetve 64 gigabájt memóriát tudnak megcímezni. A memóriát bájtok lináris tömbjeként képzelhetjük el. Az els˝o bájt címe nulla, az utolsóé 2n − 1. Egy 20-bites címbusszal rendelkez˝o 8088 esetén a következ˝o pseudo-Pascal tömbdeklaráció jó közelítés arról, hogyan képzeljük el a memóriát:
Hardver alapismeretek programozóknak Memory: array [0..1048575] o f byte ;
Ahhoz, hogy a "Memory [125] := 0;" Pascal utasítás megfelel˝ojét végrehajtsa, a CPU nulla értéket tesz ki az adatbuszra, a 125 címet a címbuszra, majd írási utasítást ad ki a write vonalon (mivel a CPU most adatot ír a memóriába). 3.1.1. Memóriatípusok A mai számítógépek sokféle típusú tárolót használnak. A legtöbb programozó csak RAM és ROM memóriát ismer, mint írható és olvasható, illetve csak olvasható eszközt. Van azonban ezeknek altípusa is, s˝ot olyan hibrid eszköz is, amelyik csak speciális körülmények között írható, lásd 3.1 ábra. A különböz˝o memóriatípusokat csak programozhatóságuk szempontjából vizsgáljuk. 2.2. táblázat. Az LMC utasításkészlete Utasítás típus Arithmetic Data movement Jump Branch on 0 Branch on + Input/output Input/output Machine control (Coffee break)
Érték 1XX 2XX 3XX 5XX 6XX 7XX 8XX 901 902 000
Muvelet ˝ ADD SUB STO LDA BR BRZ BRP IN OUT HALT COB
A RAM (Random Access Memory) két f˝o típusa a statikus és a dinamikus RAM. Az utóbbihoz speciális vezérl˝ot használnak, amely periodikus frissítéssel tartja csak meg tartalmát. Költség és elérési id˝o alapján választanak közöttük. A ROM (Read Only Memory) esetén, a technológia miatt, az írási muvele˝ tet programozásnak vagy beégetésnek 3.2. I/O
9/23 nevezik. A beírást egy ilyen eszközzel kapcsolatban, csak korlátozott számban, és nehézkesen tudjuk megtenni, viszont az információt a memória a tápfeszültség eltávolítása után is megtartja. A felhasználó által beírható memóriát programozhatónak nevezik, van bel˝ole egyszer programozható (one-timeprogrammable, OTP) PROM és törölhet˝o és programozható (erasable-andprogrammable) EPROM típus. A hibrid memóriák a fenti két típus el˝onyeit kombinálják: úgy írhatók és olvashatók, mint a RAM, és ugyanúgy meg˝orzik tartalmukat tápfeszültség nélkül is, mint a ROM. Ilyen memória a flash, ami viszont nem bájt, hanem szektor (blokk) adategységeket kezel íráskor (olvasni bájtonként lehet). Eléggé bonyolultan kezelhet˝o íráskor el˝obb az egész blokkot törölni kell, majd az új tartalmat beírni.
3.2. A ki/beviteli alrendszer A ki/bemeneti eszközöknek is a memóriákhoz hasonlóan címe van, és a memóriához hasonló címzési mechanizmusa. A konkrét megvalósítástól függ˝oen, vagy a memória címtartományának egy részét eszközök címeként használjuk, vagy pedig külön címtartományt (és I/O címbuszt) használunk, lásd 3.2 ábra. Az els˝o esetben a processzor által kiadott címen egy memóriarekesz helyett egy eszköz jelentkezik, és az eszközöket a memóriák kezelésére is használatos utasításokkal érjük el. A második esetben külön utasítással kell elérni az eszköz címterét. Gyakran mindkét megoldás el˝ofordul egyazon architektúrában. A 80x86 családnak a memória elérésére szolgáló 20, 24 vagy 32-bites címvonalak mellett van egy 16-bites I/O címbusza is. Ez lehet˝ové teszi, hogy a
Hardver alapismeretek programozóknak
10/23
c 2006 http://physics.usask.ca
Masked
ROM PROM
EPROM
EEPROM
Flash
NVRAM
SRAM
DRAM
RAM
Hibrid
Memory
3.2. ábra. A ki/bemeneti címek leképezése
3.1. ábra. Általánosan használt memória típusok 80x86 CPUk két külön címteret használjanak: egyet a memória és egyet I/O muveletekhez. ˝ A vezérl˝obusz vonalai különböztetik meg a memória és I/O címeket. A vezérl˝ojelekt˝ol és a kisebb busztól eltekintve, az I/O címzés pontosan ugyanúgy muködik, ˝ mint a memóriacímzés. A memória és az I/O eszközök
3.2. I/O
közösen használják az adatbuszt és a címbusz kisebb helyértéku ˝ 16 bitjét. Három korlátozás vonatkozik a PC I/O alrendszerére: az els˝o, hogy 80x86 CPUknak külön utasítás szükséges az I/O eszközök elérésre; a második, hogy a PC tervez˝oi a "legjobb" helyeket saját céljaikra már felhasználták (lásd 3.3 ábra, a többi fejleszt˝ot kevésbé jól hozzáférhet˝o helyek használatára kényszerítve; a harmadik, hogy a 80x86 alapú rendszerek 65,536 (216 ) I/O címnél többet nem tudnak megcímezni. Amikor azt tekintjük, hogy egy tipikus videokártya nyolc megabájtnál több címezhet˝o helyet igényel, látjuk, hogy az I/O busz mérete valóban problémát jelent. Szerencsére a hardver tervez˝ok ugyanolyan könnyedén leképezhetik az I/O eszközöket a memóriacímtérbe, mint a I/O címtérbe. A megfelel˝o áramkörök felhasználásával az I/O eszközeik ugyanolyannak látszanak, mint a memória. Ilyen módon muködnek ˝ például a PC képerny˝oadapterei.
Hardver alapismeretek programozóknak
11/23
3.2.1. A CPU összekapcsolása a külvilággal A legtöbb be- és kiviteli eszköz a memóriához egészen hasonló módon kapcsolódik a CPU-hoz. Valóban, sok eszköz úgy jelenik meg a CPU számára, mintha az memória eszköz volna. Hogy egy adatot kiküldjön a külvilágba, a CPU egyszeruen ˝ beírja azt egy "memória" helyre és az adat valami varázslat révén megjelenik a számítógép egy küls˝o csatlakozóján. Hasonlóképpen, hogy egy eszközr˝ol adatot olvasson be, a CPU egyszeruen ˝ adatot visz át a "memóriából" a CPU-ba; ez a "memória" hely tartalmazza azt az értéket, amelyik egy küls˝o csatlakozó bizonyos érintkez˝oin található. Egy output port egy olyan eszköz, amelyik memóriacellának tunik, ˝ de kapcsolatban van a külvilággal (ne feledjük: ez olyan memóriacella, amelyik tartalmát a prifériás berendezés is megváltoztathatja! C-ben programozva, a volatile kulcsszóval érdemes megjelölni az ilyen memóriarészt). Egy tipikus I/O port egy latch regisztert használ flip-flop helyett a memóriacella megvalósítására. Amikor a CPU a latch-hez tartozó címre ír, a latch eszköz átveszi az adatot és azt elérhet˝ové teszi olyan vezetékeken, amelyek a CPU és a memória alrendszer számára küls˝o egységek (lásd 3.4 ábra) kommunikálnak. Megjegyezzük, hogy az output portok lehetnek csak írható, vagy írható/olvasható portok. Mivel a latch regiszteren lev˝o output érték nem csatolódik vissza a CPU adatbuszára, a CPU nem tudja visszaolvasni a latch által tartalmazott adatot. Mind a címdekóder, mind az írás engedélyezés vonalaknak aktívaknak kell lenniük, hogy a latch muködjön; ˝ amikor a latch címér˝ol olvasunk, a címdekóder vonal aktív, de az írás engedélyezés vonal nem. A 3.5 ábra azt mutatja, hogyan ké-
3.2. I/O
c 2006 http://physics.usask.ca
3.3. ábra. Az I/O címek tere
c 2006 http://www.artofasm.com
3.4. ábra. Egy tipikus output port szíthetünk egy írást/olvasást egyaránt támogató input/output portot: az output portra írt érték visszacsatolódik egy bemeneti latch-re. Amikor a CPU olvassa a felismert címet, mind az olvasó, mind a címdekódoló vonal aktív és ez aktiválja az alsó letch-et. Ez az el˝oz˝oleg az output portra kiírt adatot a CPU adatbuszára teszi, ami a CPU számára lehet˝ové teszi az adat beolvasását. Egy input (csak olvasható) port egyszeruen ˝ az ábra alsó fele; a rendszer elhanyagolja az input portra kiírt adatot. Az output port tökéletes példája egy nyomtató párhuzamos portja. A CPU egy ASCII karaktert kiír az egy-bájt széles output portra, ami a számítógép hátoldalán lev˝o DB-25F csatlakozóra kapcsolódik. A kábel átviszi ezt az adatot a nyomtatóra, ahol egy input port (a nyomtatóé) fogadja az adatot.
Hardver alapismeretek programozóknak A beviteli, illetve kiviteli egység egy lehetséges elektronikus megvalósítása látható a a 3.6 és a 3.7 ábrákon. Az egységet kiválasztó SEL jelet a címdekódolás eredménye adja meg.
12/23 Ezeket a portokat kontrol és státusz regisztereknek nevezik. Ezek a perifériás hardver részei, helyük, méretük és jelentésük a periféria jellegét˝ol függ. 3.2.2. Az I/O eszközök kezelése
c 2006 http://www.artofasm.com
A memóriára leképezett és az I/O térbeli címen át kezelt eszközök kezelésének különböz˝oségét a 3.8 ábráról érthetjük meg. Magas szintu ˝ nyelvu ˝ programjaink ugyanúgy érik el a memóriára leképezett eszközöket, mint bármely másik memóriát, az I/O térbeli címmel rendelkez˝o eszközökhöz viszont speciális I/O utasításokat kell használnunk.
3.5. ábra. Egy írás/olvasást támogató output port
c 2006 http://physics.usask.ca
3.7. ábra. Kiviteli illeszt˝o egység c 2006 http://physics.usask.ca
3.6. ábra. Beviteli illeszt˝o egység Egy adott perifériaberendezés általában egynél több I/O portot használ. Egy tipikus párhuzamos nyomtatóilleszt˝o például három portot használ: egy író/olvasó portot, egy bemen˝o portot és egy kimen˝o portot. Az író/olvasó port az adatport (azért írható/olvasható, hogy a CPU vissza tudja olvasni a nyomtató portra utoljára kiírt értéket). Az input port a printert˝ol vezérl˝ojeleket ad vissza; ezek a jelek mutatják, hogy a nyomtató kész-e újabb karaktert fogadni, off-line állapotban van-e, kifogyott-e a papír, stb. Az output port olyan vezérl˝ojeleket ad a nyomtatónak, mint például, hogy van-e nyomtatandó karakter. 3.3. Buszok
Ugyanez kicsit technikaibb kivitelben, lásd a a 3.9 ábra: a busz címés adatvonalak szabják meg, hogy mit hogyan érhetünk el. A küls˝o eszközökkel vagy a processzor kezdeményezésére, vagy az eszköz kezdeményezésére létesítünk adatátviteli kapcsolatot, lásd a 3.10 ábra.
3.3. A számítógép szere
buszrend-
Bár elvileg nem képeznek önálló alkotórészt, nagyon fontos az alkotórészek összekötése. A számítógép architektúra
Hardver alapismeretek programozóknak
13/23
c Butterworth, 2000/ W. Buchanan
c Butterworth, 2000/ W. Buchanan
3.8. ábra. Memóriára leképezett és I/O térbeli eszközök kezelése
3.10. ábra. Kiszolgálás lekérdezéssel és megszakítással
c Butterworth, 2000/ W. Buchanan
c Butterworth, 2000/ W. Buchanan
3.9. ábra. Memóriára leképezett és I/O térbeli eszközök elérése egy másfajta, inkább a f˝o komponensek összekötését hangsúlyozó ábrázolása látható a 3.11 ábrán. A tényleges megvalósításban az alkotórészek ún. buszokkal vannak összekapcsolva, lásd 3.12 ábra. A busz olyan vezetékekb˝ol áll, amelyen elektromos jelek haladnak a rendszer komponensei között. A buszok processzorról processzorra változnak, de mindegyik busz hasonló információt szállít a különböz˝o processzorokon. A busz rendszer valójában a számítógép komponenseit összeköt˝o sajátos vezetékrendszer, lásd a 3.12 ábra. A 80x86 családnak három f˝o busza van: a címbusz, az adatbusz és a vezérl˝obusz. Az adatbusz megvalósítása na3.3. Buszok
3.11. ábra. A számítógép buszrendszer blokkdiagramja gyon különböz˝o lehet a 80386 és a 8088 esetén, de mindkett˝o adatokat szállít a processzor, a be- és kiviteli egységek és a memória között. A buszok esetén a logikai szinteket különböz˝o nagyságú feszültségszintek realizálják, ezért mindig a logikai állapotokkal jellemezzük a jeleket. • A processzorok az adatbuszt használják arra, hogy a számítógéprendszer különböz˝o komponensei között adatokat cseréljenek. Ennek a busznak a mérete széles határok között változik a 80x86 családon belül. Valójában ez a busz határozza meg a processzor "méretét". Gyakran halljuk, hogy egy pro-
Hardver alapismeretek programozóknak cesszor 8, 16, 32 vagy 64 bites. Bár egy kicsit ellentmondásos a processzor méretér˝ol beszélni, a legtöbben egyetértenek abban, hogy a processzor adatvonalainak száma és a legnagyobb általános célú regiszter mérete közül a kisebbiket kell a processzor méretének tekinteni. A modern x86 CPUk 64-bites busszal, de csak 32-bites általános célú regiszterekkel rendelkeznek, így ezeket az eszközöket a legtöbben 32-bites processzornak tekintik. Bár a 80x86 család tagjai 8, 16, 32 és 64 bites adatbusszal a busz szélességét is elér˝o méretu ˝ adatokat is fel tudnak dolgozni, el tudnak érni 8, 16 vagy 32-bites kisebb egységeket is. Emiatt minden olyan muve˝ letet, amilyet egy kis adatbusszal el tudunk végezni, meg tudunk tenni egy nagy adatbusszal is; a nagyobb busz azonban gyorsabban érheti el a memóriát és nagyobb adattömböt ér el egyetlen memóriamuvelettel. ˝ • Egy processzoron az adatbusz egy bizonyos memóriahely vagy I/O eszköz és a CPU között visz át információt. A címbusz válaszol az egyetlen felmerül˝o kérdésre : "Melyik memóriahely vagy I/O eszköz?". Hogy meg tudjuk különböztetni a memóriahelyeket és az I/O eszközöket, a rendszer tervez˝oje egyedi címet rendel minden memóriaelemhez és I/O eszközhöz. Amikor egy szoftver hozzá akar férni egy bizonyos memóriahelyhez vagy I/O eszközhöz, a megfelel˝o címet a címbuszra teszi. A memóriához vagy I/O eszközhöz rendelt áramkörök felismerik ezt a címet és arra utasítják a memóriát vagy az I/O eszközt, hogy az adatbuszról adatot olvassanak be vagy arra adatot helyezzenek el. Mindkét esetben az
3.3. Buszok
14/23 összes többi memóriahely elhanyagolja a kérést; csak az az eszköz válaszol, amelyiknek a címe megegyezik az adatbuszon lev˝o címmel. Egyetlen címvezetékkel a processzor pontosan két címet tud el˝oállítani: a nullát és az egyet. Ha n címvezetékünk van, a processzor 2n címet tud el˝oállítani (mivel egy n bites számban 2n különböz˝o érték lehet). Emiatt a címbusz bitjeinek száma meghatározza a megcímezhet˝o memória és I/O helyek maximális számát. A korai x86 proceszorokon csak 20 bites címbusz volt, emiatt ezek legfeljebb csak 1,048,576 (avagy 220 ) memóriahelyet tudtak megcímezni. Nagyobb címbusszal több memóriát lehet elérni. • A vezérl˝obusz olyan jelek eklektikus gyujteménye, ˝ amelyek azt szabályozzák, hogy hogyan kommunikál a processzor a rendszer többi részével. Tekintsük most az adatbuszt. A CPU az adatbuszon küld adatokat a memóriának és azon kap onnét adatokat. Ez fölveti a kérdést "Most küldünk vagy fogadunk?" Két olyan vonal van az adatbuszon, a read és a write, amelyek meghatározzák az adatáramlás irányát. A többi jel az órajel, megszakításjel, állapotjel, stb. A vezérl˝obusz pontos megvalósítása a 80x86 családon belül is változik a processzorokkal. Bizonyos vezérl˝o vonalak azonban minden processzornál azonosak és érdemes azokat röviden megemlíteni. A read and write vezérl˝ovonalak szabják meg az adatok átvitelének irányát az adatbuszon. Amikor mindkett˝onek az értéke logikai egy, a CPU és a memória-I/O eszközök nem kommunikálnak egymással. Ha a read vezérl˝ovonal alacsony
Hardver alapismeretek programozóknak szintu ˝ (logikai nulla), a CPU adatot olvas a memóriából (azaz a rendszer adatot visz át a memóriából a CPU-ba). Ha a write vezérl˝ovonal alacsony szintu, ˝ a rendszer a CPUból a memóriába visz át adatokat. Egy másik fontos jelcsoport a byte enable (bájt engedélyez˝o) vezérl˝ovonalak, amelyek lehet˝ové teszik, hogy a 16, 32 és 64 bites processzorok kisebb adatdarabokkal foglalkozzanak. Sok más processzortól eltér˝oen, a 80x86 család két különböz˝o címtérrel rendelkezik: eggyel a memória és eggyel az I/O eszközök számára. Amíg azonban a memória címbuszok mérete eltér a különböz˝o 80x86 processzorokon, az I/O címbusz valamennyi 80x86 CPU esetén 16 bit széles. Ez a processzort 65,536 különböz˝o I/O hely megcímzésére teszi képessé. Mint majd látni fogjuk, a legtöbb eszköz (mint billentyuzet, ˝ nyomtató, mágneslemezes tároló, stb.) egynél több I/O helyre tart igényt. Ennek ellenére a 65,536 I/O hely több mint elegend˝o a legtöbb alkalmazás számára. Az eredeti IBM PC tervez˝oi még csak 1,024 I/O hely használatát tették lehet˝ové. Bár a 80x86 család két címtérrel rendelkezik, nincs két külön címbusza (az I/O eszközök és a memória számára). Ehelyett a rendszer megosztja a címbuszt az I/O eszközök és a memória címei között. További vezérl˝ovonalak döntik el, hogy a címet a memóriának vagy az I/O eszközöknek szánták-e. Amikor az ilyen jelek aktívak, az I/O eszközök a címbusz alsó 16 bitjét használják. Amikor inaktívak, az I/O eszközök elhanyagolják a címbusz jeleit (ebben az esetben a memória alrendszer veszi át a
3.4. CPU
15/23 szerepet).
3.4. A számítógép egysége
központi
A központi egység (Central Processing Unit, CPU) foglalja egységbe és vezérli az eddig felsorolt komponenseket. A CPU el˝oveszi az utasításokat a memóriából, értelmezi azok bináris tartalmát és végrehajtja azokat. Ennek során hozzá kell férnie a memóriához és ki/bemen˝o portokhoz, érzékelni bizonyos küls˝o jeleket, azokra reagálni. Az alábbi, egymással szorosan együttmuköd˝ ˝ o egységekb˝ol áll: • Regiszterek • Aritmetikai és logikai egység (ALU) • Vezérl˝o áramkörök
4. A számítógép verem tárolója A verem tároló a számítógép memóriájának része, amelyhez egy speciális célú verem mutató regiszter (ESP) is tartozik. Bár a tároló regisztereinek saját címe is van, azokat csak az ESP regiszteren keresztül használjuk. A processzorok a verem memória kezelésére külön adatmozgató utasításokat használnak. Ezek különlegessége, hogy a kért adatmozgatáson túl az ESP regiszter tartalmát is változtatják.
4.1. A verem tároló használata adat mozgató utasításokkal A 4.1 ábrán látható a verem muködé˝ se adat mozgató utasítások használata esetén: mi történik az EIP utasítás mutatóval és az ESP verem mutatóval
Hardver alapismeretek programozóknak
16/23 írja be. Az utasítás végrehajtásá-
egy adatmozgató utasítás hatására. Az ábrán a memória címek lefelé növekszenek. Ennek megfelel˝oen a program EIP utasítás mutatója a program szokásos módon való végrehajtása során lefelé
nak eredményeképpen ESP értéke a kivett adat méretének megfelel˝o mértékben n˝o. Bár az adat a fizikai memóriában változatlanul elérhet˝o, ESP most már nem az utolsóként, hanem azel˝ott beírt adatra mutat. Logikailag „kivettük az adatot a veremb˝ol”. Vegyük észre azt is, hogy az adat eredetileg az EBX regiszterben volt, és most a EDX regiszterbe kerül. A verem memória természetesen nem „emlékszik” arra, honnét került belé az elmentett adat.
halad. A ESP veremmutató értéke pedig ezzel ellentétesen, felfelé. A kezd˝oérték ennek megfelel˝oen alacsony, illetve magas memóriacím, így a programok sok adattal és kevés program utasítással, illetve fordítva is tudnak muködni. ˝ A számítógép muködésképtelenné ˝ válik, ha a a két tartomány összeér. 1
Kezdetben a két mutatót a mondott alaphelyzetbe állítják. EIP minden utasítás végrehajtása után növek-
6
Hasonlóképpen kivesszük EAX értékét és azt eredeti helyére tesszük vissza. Vegyük észre, hogy (a verem LIFO=Last In First Out muködése ˝ miatt) a verembe els˝oként elmentett adatot utoljára kapjuk vissza.
7
A két verem kezel˝o utasítás pár végrehajtása után visszaáll az eredeti
szik; az ábrán lefelé halad. ESP értéke és helyzete mindaddig nem változik, amíg nem használunk veremkezel˝o utasításokat. 2
Amikor EIP olyan utasításhoz ér, amelyik egy adatot a verem memóriába ír (PUSH EAX az EAX regiszter tartalmát írja be a verem memóriába), az adat az ESP által kijelölt helyre kerül, a mutató értéke pedig az adat hosszúságának megfelel˝o értékkel csökken, ezáltal a mutató az ábrán felfelé mozog, és az utoljára beírt értékre mutat. A korábban e helyen tárolt adat elvész.
3
A következ˝o utasítás újabb adatot helyez el a veremben. ESP utóbb beírt értékre mutat,
a leg-
4
A helyzet mindaddig nem változik, amíg veremkezel˝o utasítást nem hajtunk végre.
5
A POP EDX utasítás a verem memóriából kivett adatot (amire ESP
mutat) az EDX
regiszterbe
állapot, ESP értéke megegyezik a kezd˝oértékkel, bár a két elmentett adat a memóriában megmarad.
4.2. A verem tároló használata szubrutin hívására A programok végrehajtása során sokszor van szükség ismétl˝od˝o kódok végrehajtására. Ennek megvalósítására nagyon jó lehet˝oséget kínál a szubrutin hívás, amelyet a magas szintu ˝ nyelvekben kiterjedten használunk. Megvalósítása azonban nem is olyan egyszeru: ˝ az ismétl˝od˝o utasítások végrehajtása után vissza kell térni a f˝oprogram megfelel˝o helyére, és ehhez tárolni kell a visszatérési cím értékét. Mégpedig olyan módon, hogy az többszörös mélységu ˝ és rekurzív hívások esetén is muködjön. ˝ A 4.2 ábra mutatja be, mi történik az EIP
utasítás mutatóval és az
4.2. A verem tároló használata szubrutin hívására
ESP
verem
17/23
3 EIP PUSH EBX 4 EIP
Következ˝o utasítás
5 EIP POP EDX 6 EIP POP EAX 7 EIP
Következ˝o utasítás
Program memória (növekv˝o)
2 EIP PUSH EAX
Memória cím (növekv˝o)
1 EIP El˝oz˝o utasítás
Verem memória (csökken˝o)
Hardver alapismeretek programozóknak
xx
5 4 ESP Vermelt EBXxx 36 ESP Vermelt EAXxx ESP El˝oz˝o vermelt 17 ESP 2 4.1. ábra. A verem tároló használata adat mozgató utasításokkal a veremtárolóba elmenti annak az utasításnak a memória címét, amelyik akkor következett volna, ha nem szubrutin hívást hajtunk végre, és amelyikkel majd folytani kell a program végrehajtását a szubrutinból való visszatérés után (de MOST még NEM azt hajtjuk végre). A tárolóterület lefoglalása
mutatóval egy szubrutinhívás végrehajtásának lépései során. 1
2
3
Amint megtanultuk, az éppen végrehajtott program mindig a következ˝o utasításra lép, amíg el nem éri a szubrutin hívás utasítást. Az EIP utasítás mutató tehát mindig az éppen végrehajtandó utasításra mutat, annak el˝ovétele után továbblép a program tároló következ˝o címére. A szubrutin híváshoz érkezve, a program el˝oveszi a szubrutin hívó utasítást, és megtalálja azt a címet, ahol a szubrutin hívás kezd˝odik. A szubrutin hívó utasítás végrehajtása során két változás történik. EIP a szubrutin hívó utasításban megadott címre fog mutatni (tehát a program végrehajtása ott folytatódik), ugyanakkor a processzor
miatt megváltozik ESP értéke is: a szubrutin hívás visszatérési címére fog mutatni, amit a processzor (tehát, az adatmozgató utasításoktól eltér˝oen: NEM a programozó!) most mentett el a veremtárolóba. 4
A szubrutin végrehajtása során az EIP program mutató folyamatosan növekszik, és el˝obb-utóbb eléri azt a memóriacímet, amelyikben a RET visszatérési utasítás található. Ennek végrehajtása során a program el˝oveszi a veremben tá-
4.2. A verem tároló használata szubrutin hívására
18/23
5 EIP
Program memória (növekv˝o)
2 EIP CALL SUB1 Következ˝o utasítás
3 EIP SUB1 els˝o
Memória cím (növekv˝o)
1 EIP El˝oz˝o utasítás
Verem memória (csökken˝o)
Hardver alapismeretek programozóknak
xx xx
4 EIP RET 3 ESP 4
Vissza cím xx (EIP)
5 1 ESP El˝oz˝o vermelt 2 4.2. ábra. A CALL és RET utasítások hatása az EIP és ERP regiszterekre rolt visszatérési címet (amire
mutat), azt beleírja az EIP program mutatóba, ami ezáltal az a CALL utasítást követ˝o utasításra fog mutatni, és egyúttal az ESP verem mutatót visszaállítja arra a címre, ahová az a CALL utasítás végrehajtása el˝ott mutatott. Ezzel azt jelzi, hogy ezt a tárterületet már nem használjuk. 5
után más célra használhatja.
ESP
A processzor a CALL utasítást követ˝o utasítás el˝ovételével folytatja a program végrehajtását. Vegyük észre, hogy EIP és ESP most ugyanabban az állapotban van, amilyenben a CALL utasítás végrehajtása el˝ott volt. A verem tárolót csak annyi id˝ore vettük igénybe, amennyire a visszatérési cím tárolásához szükség volt; a tárterületet a program a szubrutinhívás el˝ott és
4.3. A verem tároló használata szubrutinon belül Vegyük észre, hogy a programozó és a processzor egyaránt használják a verem memóriát, akár egyidejuleg ˝ is. Emiatt a program készítésekor külön figyelni kell a verem helyes használatára. A PUSH/POP utasításokat mindig párokban kell használni; erre különösen vigyázni kell elágazó programkód esetén. Ilyen hiba elkövetése fatális programhibát eredményez, lásd 4.3 ábra. 1
A szubrutin hívásakor még minden alapállapotban van.
2
A vezérlés átadódik a szubrutinnak, a visszatérési cím a verem tetejére kerül.
4.3. A verem tároló használata szubrutinon belül
Hardver alapismeretek programozóknak 3
Amíg el nem érjük a verem kezel˝o utasítást, nincs változás.
4
A PUSH EAX utasítás a verem tetejére menti az EAX tartalmát.
5
A RET utasítás el˝oveszi a verem tetejér˝ol azt az értéket, aminek a visszatérési címnek kellene lennie, és az így kapott címen folytatja a program végrehajtását. Annak esélye, hogy ez az érték megegyezik a valódi címmel, (szóhossztól függ˝oen, pl.) 1 : 232 . A következmény megjósolhatatlan.
19/23 program extraPop; #include( "stdlib.hhf" ); procedure SUB1;@noframe; @nodisplay; begin SUB1; stdout.put("In SUB1" ’\nl’); 3 pop( eax ); 4 ret(); end SUB1; procedure SUB2;@noframe; @nodisplay; begin SUB2; stdout.put("Call SUB1" ’\nl’); 2 SUB1(); stdout.put("SUB1 back" ’\nl’); ret(); end SUB2; begin extraPop; stdout.put("Call SUB2" ’\nl’); 1 SUB2(); 5 stdout.put("SUB2 back" ’\nl’); end extraPop;
c 2007 http://www.software-engineer-training.com
3.12. ábra. A Neumann-féle számítógép tényleges architektúrája Hasonlóan gondot okozhat egy felesleges POP utasítás is, mint pl. az 1 programlista esetén, ahol a megjelölt sorban egy szükségtelen POP EAX található. A hibajelenség egy hiányzó üzenet. A program muködése ˝ során a verem mutató állapota a ?? ábrán látható. 1
A program a muködés ˝ során meghívja a SUB2 szubruint.
2
Amikor a SUB2 szubrutin meghívja a SUB1 szubrutint, a verem tetején a f˝oprogramhoz való visszatérés címe található.
Programlista 1: Egy felesleges POP utasítás hatása 3
Amikor a SUB1 szubrutinban a POP EAX utasításhoz ér a program mutató, a verem tetején a SUB2 szubrutinba való visszatérés címe van, ezt betesszük EAX -be, és a mutató a verem következ˝o helyére áll be.
4
A SUB1 szubrutin RET utasítása kiveszi a veremb˝ol a visszatérési címet (ami valójában SUB2 számára elmentett visszatérési cím!) és visszatér a f˝oprogramhoz.
5
A f˝oprogramban megkapjuk a SUB2 visszatérésér˝ol szóló üzenetet, de nem a SUB2 visszatérésér˝ol szólót.
4.3. A verem tároló használata szubrutinon belül
Hardver alapismeretek programozóknak
20/23
El˝oz˝o utasítás 1 EIP CALL SUB1 Következ˝o utasítás
BUMM! 1 : 232
2 EIP SUB1 els˝o 3 EIP PUSH EAX xx
4 EIP 5 EIP RET
5 4 ESP EAX mentésxx 3 2 ESP
Vissza cím xx (EIP)
1 ESP El˝oz˝o vermelt 4.3. ábra. Extra PUSH használatának hatása szubrutinban
xx
Az 1 programlistán bemutatott esetben a felesleges POP nehezen észrevehet˝o hibát eredményez. Érdemes végiggondolni, mi történik, ha a a két szubrutin sorrendjét felcseréljük a forráskódban!
3 ESP Vissza SUB2xx 2 ESP 4
Vissza extraPOP
xx
5 1 ESP El˝oz˝o vermelt 4.4. ábra. Extra POP használatának hatása szubrutinban A program több sornyi, ’*’ karakterrel követett betuközt ˝ akar kíratni. Azonban, ez mindaddig nem sikeres, amíg el nem menti a processzor két olyan regiszterét, amelyet mind a f˝oprogram, mind a szubrutin használ. A megjelölt helyen el kell végezni a mentést/visszaállítást. A
program részletes muködése: ˝ 1
A program az ECX regiszterbe beírja, hogy hány sornyi ilyen szöveget akar nyomtatni.
2
Meghívja a PrintSpaces szubrutint, amelyiknek a feladata megadott számú betuközt ˝ nyomtatni.
3
A visszatérés után a programnak egy ’*’ karaktert kell nyomtatnia. Azonban a program végtelen ciklusba kerül, nem az elvárt módon viselkedik.
4.3. A verem tároló használata szubrutinon belül
Hardver alapismeretek programozóknak program nonWorking; #include("stdlib.hhf"); procedure PrintSpaces; begin nonWorkingProgram; 1 mov( 20, ecx ); repeat 2 PrintSpaces(); 3 stdout.put(’*’, nl); dec( ecx ); until( ecx = 0 ); end nonWorkingProgram; procedure PrintSpaces; begin PrintSpaces; mov( 40, ecx ); repeat stdout.put( ’ ’ ); dec( ecx ); until( ecx = 0 ); end PrintSpaces; Programlista 2: Szubrutin a betuközök ˝ nyomtatására, hibás 4
5
Ennek oka az, hogy a hívott szubrutin is használja az ECX regisztert, és ezáltal felülírja az abba a f˝oprogram által beírt értéket. A megjelölt helyeken beírva a bels˝o regiszterek mentését a felülírás el˝ott, majd azokat visszaállítva, a f˝oprogramhoz az ott kapott értékekkel tér vissza a szubrutin. Figyeljük meg, hogy a visszaállítás alkalmával a regiszterek sorrendje fordított (LIFO!). (Az EAX regisztert pedig a kiviteli könyvtári rutin használja, ezért kell elmenteni.)
Az ilyen, állapot meg˝orz˝o jellegu, ˝ mentéseket mind a hívott, mind a hívó szubrutin elvégezheti. A hívott pontosan tudja, hogy miket fog használni, de nem tudhatja, hogy ezek közül a
21/23 hívónak ténylegesen melyik regiszterekre van szüksége, így néhány esetben felesleges mentés/visszaállítást végez. A hívó viszont pontosan tudja, miket kell meg˝orizni, de nem tudja, hogy a hívott ezek közül miket fog változtatni, ráadásul a mentés/visszaállítást minden hívás alkalmával külön kódolni kell.
4.4. Paraméter átadás szubrutin hívás során A szubrutinok az egymást követ˝o hívások során más-más adato(ka)t dolgoznak fel, így valamilyen formában paramétereket kell átadnunk számukra. A legegyszerubb ˝ és leggyorsabb természetesen regiszterben átadni adatot, az átadható adatok számának azonban határt szab a processzorban elérhet˝o általános célú regiszterek száma. Emiatt két másik mechanizmust használnak elterjedten: vagy a kódfolyamban, vagy a veremtároló használatával adnak át adatokat. A paraméterátadás a veremtárolón át eléggé magától értet˝od˝onek tunik. ˝ Mint a 4 lista mutatja, a szükséges paramétereket elmentjük a verembe, meghívjuk a szubrutint, és a szubrutin pedig el˝oszedi a veremb˝ol a paramétereket. Ez majdnem így is van, de még figyelembe kell venni, hogy a szubrutin visszatérési címe is a verem memóriába kerül, (feltéve, hogy a fordító programot a mutatott módon ( 1 ) arra utasítjuk, hogy ne generáljon "láthatatlan" kódokat, így azt el˝oször el kell menteni (
2
), majd
visszaállítani ( 3 ). Emiatt csak az 5 listán bemutatott program muködik. ˝ A helyzet lényegesen bonyolultabbá válik, ha a szubrutin maga is használja a verem tárolót. A 6 programlista egy olyan szubrutinhívást mutat, ahol a hívó program paramétereket ad át a szubrutinnak, és
4.4. Paraméter átadás szubrutin hívás során
Hardver alapismeretek programozóknak program nonWorking; #include("stdlib.hhf"); procedure PrintSpaces; begin nonWorkingProgram; 1 mov( 20, ecx ); repeat 2 PrintSpaces(); 3 stdout.put(’*’, nl); dec( ecx ); until( ecx = 0 ); end nonWorkingProgram; procedure PrintSpaces; begin PrintSpaces; 4 push(eax); push(ecx); mov( 40, ecx ); repeat stdout.put( ’ ’ ); dec( ecx ); until( ecx = 0 ); 5 pop(ecx); pop(eax); end PrintSpaces;
22/23 push( i ); push( j ); push( k ); call CallProc; static RtnAdrs: dword; p1Parm: dword; p2Parm: dword; p3Parm: dword; procedure CallProc( p1:dword; p2:dword; p3:dword ); 1 @nodisplay; @noframe; begin CallProc; pop( p3Parm ); pop( p2Parm ); pop( p1Parm ); . . . ret(); end CallProc; Programlista 4: Paraméter átadás veremtárolón át, hibás
Programlista 3: Szubrutin a betuközök ˝ nyomtatására, helyes a szubrutin maga is használ lokális paramétereket. A veremtároló állapotának változását a ?? ábra mutatja. (Az ábrán csak azonos hosszúságú (4 bájtos) adatokat látunk, ezért négy bájtos a cím növekménye. A módszer más méretek esetén is használható. A részletes muködés: ˝ 1
A szubrutinhívás el˝ott a verem alapállapotban van.
2
A szubrutinhívó utasításhoz érve, a f˝oprogram beírja a verem memóriába a a két paraméter értékét, majd a szubrutin visszatérési címét.
3
rutinból való kilépésig EBP értéke már nem változik. 4
Ezután a szubrutin helyet biztosít a lokális paramétereknek, majd elkezd˝odik a végrehajtás.
5
A szubrutinon belül az ESP használattól függ˝oen változhat, az EBP azonban a kilépésig állandó. Ezért a helyi változókhoz és az aktuális paraméterekhez állandó címet rendelhetünk: az EBP mutatóhoz viszonyított állandó értéket, az ún. eltolási (offset) címet. Az aktuális paraméterek eltolási címe pozitív, a helyi paraméterekét negatív.
6
A szubrutinból való kilépés során felszámoljuk a helyi változókat, visszaállítjuk EBP eredeti értékét, el˝ovesszük a visszatérési címet, és felszámoljuk az aktuális paraméte-
A szubrutinba belépve, el˝oször elmenti az EBP regiszter értékét, majd az ESP regiszter tartalmát átírja az EBP regiszterbe. A szub-
4.4. Paraméter átadás szubrutin hívás során
Hardver alapismeretek programozóknak rek számára fenntartott helyet is. Ezzel a verem visszaáll a szubrutinhívás el˝otti helyzetbe. Néhány megjegyzést érdemes push( i ); push( j ); push( k ); call CallProc; static RtnAdrs: dword; p1Parm: dword; p2Parm: dword; p3Parm: dword; procedure CallProc( p1:dword; p2:dword; p3:dword ); 1 @nodisplay; @noframe; begin CallProc; 2 pop( RtnAdrs ); pop( p3Parm ); pop( p2Parm ); pop( p1Parm ); 3 push( RtnAdrs ); . . . ret(); end CallProc; Programlista 5: Paraméter átadás veremtárolón át, helyes
procedure ARDemo ( i:uns32; j:int32); nodisplay; 4 var a:int32; r:real32; 3
begin ARDemo; . . . 6 end ARDemo; 5
1 2
Call ARDemo( i, &j);
Programlista 6: Paraméter átadás aktivációs rekord készítéssel
23/23
II. rész
Szoftver driverek