Académique Documents
Professionnel Documents
Culture Documents
Iványi Péter
Miért?
• Ma már ritkán készül program csak assembly-ben
– Általában bizonyos kritikus rutinoknál használják
– Miért nem használjuk?
• Magas szintű nyelven könnyebb programozni
• Nehéz más gépre átvinni a programot
– Miért tanítjuk?
• Az assembly rutin kisebb és gyorsabb lehet
• Közvetlen hardware elérés, amit magasabb szintű nyelvből
esetleg lehetetlen
• Mélyebb tudás a számítógépekről
• Fordítók megértése, magasabb nyelvek megértése
Miért?
• Sajnos kis és gyors rutinok írásához nagy
gyakorlat, tapasztalat kell
– A rendszer részletes ismerete
• Assembly esetén lemondunk szinte minden
rendszer támogatásról és a saját kezünkbe vesszük
a vezérlést
– Gondosan válasszuk meg a programozási eszközt
– Általában a középút az ideális
• Program készítés
• Karbantartás
• Költség, munkaráfordítás, stb.
Miért?
• Hatékony, gyors, kis program létrehozása idő és
munkaigényes
• Milyen célt szolgál a rutin?
• Hányszor fut le?
– Ha csak egyszer fut le, minek javítani?
– Ha többször, pl. JIT compiler nem elég?
Mit?
• IBM PC
• Intel processzorok
• Windows
• (Linux)
• Példa:
3045 = 3 ×103 + 0 ×10 2 + 4 ×101 + 5 ×100
= 3000 + 0 + 40 + 5 = 3045
Kettes számrendszer
• Számjegyek: 0-1
d n × 2 n + d n -1 × 2 n -1 + K + d 2 × 2 2 + d1 × 21 + d 0 × 20
• Példa:
101101 = 1 × 2 + 0 × 2 + 1 × 2 + 1 × 2 + 0 × 2 + 1 × 2
5 4 3 2 1 0
= 32 + 0 + 8 + 4 + 0 + 1 = 45
Tizenhatos számrendszer
• Hexadecimális számok
• Számjegyek: 0-9,A,B,C,D,E,F
d n ×16 n + d n -1 ×16 n -1 + K + d 2 ×16 2 + d1 ×161 + d 0 ×160
• Példa:
3AF = 3 ×16 2 + 10 ×161 + 15 ×160
= 3 × 256 + 10 ×16 + 15 = 943
Konverzió
• Mennyi decimális 45 binárisan?
– 45 / 32 (25) = 1 maradt 13
– 13 / 24 = 0 maradt 13
– 13 / 23 = 1 maradt 5
– 5 / 22 = 1 maradt 1
– 1 / 21 = 0 maradt 1
– 1 / 20 = 1 maradék nulla
4510 = 1011012
Összeadás
• Mindegyik számrendszerben működik
Előjeles számok
• Hogyan reprezentáljuk a negatív számokat?
• Egyszerű megoldás:
– Használjunk egy bitet az előjel jelölésére
• S=0 pozitív (+)
• S=1 negatív (-)
– Probléma:
• Két darab zérus értékünk van
1000 0000
0000 0000
Előjeles számok
• Kettes komplemens
n -1
- d n × 2 + d n -1 × 2
n
+ K + d 2 × 2 + d1 × 2 + d 0 × 2
2 1 0
1000 -8 0 0000
-7 -1
1001 1111
-6 -2
-5 -3
1010 -4 1110
adatbusz Memória és
8086 egyéb egységek
rendszer 16 bit
vezérlőbusz
Intel processzorok
Processzor Adatbusz Címbusz Memória
8088 8 20 1MB
8086 16 20 1MB
80286 16 24 16MB
80386dx 32 32 4GB
80486 32 32 4GB
80586/Pentium 64 32 4GB
Egyszerű mikroprocesszor
Következő Utasítás
Utasítás
Kezdés utasítás
dekódolása végrehajtása
betöltése
Vége
Egyszerű mikroprocesszor, 8086
idő
80486 mikroprocesszor
Fetch Fetch Fetch Fetch Tárol Fetch Fetch
Busz
1 2 3 4 1 5 6
Dekód Dekód Dekód Dekód Dekód Dekódoló
Vár egység
1 2 3 4 5
Futtat Futtat Futtat Futtat Végrahajtó
Vár
1 2 3 4 egység
Címzés Címzés Címző
Vár Vár
1 2 egység
„pipelining”
Vezérlő regiszterek
• IP (Instruction pointer)
– Utasításmutató, az éppen végrehajtandó utasítás címe
• SP (Stack pointer)
– Veremmutató, utoljára beírt elem címe
• BP (Base pointer)
– Bázismutató, a verem címzéséhez
• SI (Source index)
– Kiindulási terület indexe
• DI (Destination index)
– Célterület indexe
Általános regiszterek
• AX (Accumulator register)
– Általános célú, majdnem mindenre használható
– matematikai műveleteknél gyakran használjuk
– AL (Low) és AH (High) részre osztható
AH AL
8 bit 8 bit
16 bit
Általános regiszterek
• BX (Base register)
– Általános célú
– Főleg címzésnél használjuk
BH BL
8 bit 8 bit
16 bit
Általános regiszterek
• CX (Counter register)
– Számláló regiszter, ciklusszervezésnél használjuk
CH CL
8 bit 8 bit
16 bit
Általános regiszterek
• DX (Data register)
– Adat regiszter
– Szorzás és osztás esetén speciális szerepe van
DH DL
8 bit 8 bit
16 bit
Szegmens regiszterek
• CS (Code segment)
– Az aktuális program báziscíme
– Minden utasításelérésnél használja a CPU
– Módosítása csak vezérlésátadással
• SS (Stack segment)
– A veremként használt terület szegmensének címe
– Csak ha nagyon szükséges, akkor módosítsuk
Szegmens regiszterek
• DS (Data segment)
– Adatszegmens regiszter
– A címzett területről lehet adatot elérni
– Írható/olvasható
• ES (Extra segment)
– Extra szegmens regiszter
– Másodlagos memória terület elérésére szolgál
Státusz regiszter
0. Bit (Carry): „átviteli” bit, egy 8 bites művelet 9.
bitje
1. Bit (Parity): értéke egy, ha az eredmény byte-ban
az egyes bitek száma páros, különben zérus
4. Bit (Auxiliarry carry): BCD számok kezelése
esetén használt
6. Bit (Zero): ha az utolsó művelet eredménye zérus,
akkor az értéke 1, egyébként zérus
Státusz regiszter
7. Bit (Sign): értéke zérus ha az eredmény pozitív,
egyébként 1
8. Bit (Trap): debug-golásnál használt
9. Bit (Interrupt): megszakítás tíltás vagy
engedélyezés, ha 1 minden megszakítást fogad
10. Bit (Direction): string kezelő műveletek
használják, ha értéke zérus, akkor az SI és DI
regisztereket automatikusan növeli, ha egy akkor
csökkenti
Státusz regiszter
11. Bit (Overflow): túlcsordulás jelzése
32 bites regiszterek
Veremkezelés
• Alapvető fontosságú !!!
• Függvények közötti kapcsolat
– Visszatérési cím
– Paraméterátadás
– Visszatérési érték
Függvényhívás
void f3(int a3)
{
printf(”%d”,a3);
}
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
}
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) 1 (argumentum)
{
f3(a2);
SP
a2 = (a2+1);
f3(a2);
}
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 1
{
f3(a2);
SP
a2 = (a2+1);
f3(a2);
}
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 1
{
SP visszatérési cím
f3(a2);
a2 = (a2+1); 1 (argumentum)
f3(a2);
}
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 1
{ visszatérési cím
f3(a2);
a3 1
a2 = (a2+1);
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 1
{ visszatérési cím
f3(a2);
a3 1
a2 = (a2+1);
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
} Ekkor is függvényhívás történik, de most ignoráljuk.
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 1
{ visszatérési cím
f3(a2);
a3 1
a2 = (a2+1);
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 1
{ visszatérési cím
f3(a2);
a2 = (a2+1);
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 2
{
f3(a2);
a2 = (a2+1);
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 2
{ visszatérési cím
f3(a2);
a2 = (a2+1); 2 (argumentum)
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 2
{ visszatérési cím
f3(a2);
a3 2
a2 = (a2+1);
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 2
{ visszatérési cím
f3(a2);
a3 2
a2 = (a2+1);
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
} Ekkor is függvényhívás történik, de most ignoráljuk.
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 2
{ visszatérési cím
f3(a2);
a3 2
a2 = (a2+1);
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 2
{ visszatérési cím
f3(a2);
a3 2
a2 = (a2+1);
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 2
{
f3(a2);
a2 = (a2+1);
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2) a2 2
{
f3(a2);
a2 = (a2+1);
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
} visszatérési cím
void f2(int a2)
{
f3(a2);
a2 = (a2+1);
f3(a2);
} SP
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
void f3(int a3) a1 1
{
printf(”%d”,a3); b1 akármi
}
void f1()
{
int a1 = 1;
int b1;
f2(a1);
}
Függvényhívás
• A függvényhívás során a verem adja a függvény
„környezetét, állapotát”
– Argumentumait
– Hova kell a függvény után visszatérni
Adattípusok
• Számok:
– bit: 0 vagy 1
– nibble: 4 bit
– DB: byte = octet = 8 bit
– DW: word (szó) = 2 byte = 16 bit
– DD: double word = 4 byte = 32 bit
• Szöveg:
– Karakterek, ASCII kód, 8 bit
Memória címzés
• 8086-os címzés
– Real mode
– 20 bites lineáris memória címet kell generálni 16 bites
címekből
• Szegmens címet 4 bittel balra toljuk, majd egy offset címmel
összeadjuk
…
DS:ESI
szegmens
DS:0
32 0
ESI …
15 0 …
DS 0 0000 0000 0011 0 XX
GDT
48 0
GDTR
…
0000 0000
Szegmens címzés, LDT-vel FFFF FFFF
…
DS:ESI
szegmens
DS:0
…
32 0
ESI
… LDT
15 0
DS 0 0000 0000 0001 1 XX
…
LDTR GDT
48 0
GDTR …
0000 0000
Program és adatterület szervezése
Eredeti SP
Felhasznált
SS:BP
verem
SS:SP
Szabad verem
SS
CS:IP Program
CS
DS:DI
Adat
DS:SI DS
Megszakítás
• Interrupt
• A normál végrehajtási folyamat megszakítása
• Egy folyamat felfüggesztése, a folyamathoz
képesti külső esemény hatására, olyan módon
hogy a folyamathoz vissza lehet térni
• Hardware események váltják ki
Megszakítás kezelő
Felhasználói mód
alkalmazás
megszakítás kezelő
Kernel mód
Megszakítás
• A 8086-os processzor egy 256 elemű megszakítás
rendszerrel rendelkezik
• A memória elején, a 0. címen található a táblázat
• Minden interrupthoz egy 4 byte hosszú blokk
tartozik
• 1. szó: IP
• 2. szó: CS
Megszakítás lépései
• A külső egység a processzor egyik lábán jelzi,
hogy megszakítást kér
• A proc befejezi az utasítás végrehajtását
• A kérő egység elküldi 8 biten a megszakítás
számát
– Valójában egy interrupt kezelő van a proc és az
egységek között,
– Ez sorolja be a megszakításokat, ha több is jön
egyszerre
Megszakítás lépései
• A megszakítás számának beolvasása után
– Elmenti a státusz regisztert
– Elmenti IP és CS regisztereket a veremre
• A sorszámnak megfelelő CS és IP értéket
kiolvassa a táblázatból és betölti
• Letiltja a megszakításokat
– Az Interrupt bitet törli
• Végrehajtja a megszakítás rutinját
Megszakítás lépései
• A megszakítás rutin egy IRET paranccsal tér
vissza
– Visszatölti a státusz, CS és IP regisztereket
Szoftver megszakítás
• Programból is kiváltható a megszakítás az INT
utasítással !!!
• Software interrupt
• A szubrutin hívás egy speciális formája
– A memória bármely részére átadhatjuk a vezérlést
– Nem címet adunk meg, hanem egy megszakítás számot
• Programok közötti kommunikációra is alkalmas
– 60h - 7Fh : user interruptok