Vous êtes sur la page 1sur 79

Assembly

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)

• Programozás alacsony szintű nyelven


• Magas szintű nyelvek által generált kód
Ismétlés
• Számítógép története
– Ez most kihagyjuk!
• Számrendszerek közti konverzió
– 2, 10, 16 alapú számrendszer
• Számítógép architektúrája
– Végrehajtás
– Regiszterek
– Memória címzés
– Megszakítás
Tizes számrendszer
• Számjegyek: 0-9
d n ×10 n + d n -1 ×10 n -1 + K + d 2 ×10 2 + d1 ×101 + d 0 ×100

• 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

• Negatív szám (n) előállítása:


– Invertáljuk a biteket és adjunk hozzá 1-et
– Vegyük a legnagyobb számot (csupa 1), vonjunk ki n-
et, majd adjunk hozzá 1-et
– Jobbrol balra haladva másoljuk a zérusokat, az első 1-
est is másoljuk, a többit invertáljuk
Kettes komplemens
0101 0100 0011
0110
4 0010
5 3
6 2
0111 0001
7 1

1000 -8 0 0000

-7 -1
1001 1111
-6 -2
-5 -3
1010 -4 1110

1011 1100 1101


Kettes komplemens 1.
• 8-bites számok, előjel nélkül: 0 - 255
• 4510 = 0010 11012
– Invertáljuk Ellenőrzés
• 1101 00102
0010 1101
– Adjunk hozzá 1-et
+ 1101 0011
• 1101 00112
1 0000 0000
– Eredmény:
• 1101 00112 = 21110 = -4510
Kettes komplemens 2.
• 4510 = 0010 11012
– A legnagyobb szám
• 1111 11112 =25510
– Vonjunk ki 45-öt
• 255 - 45 = 21010 = 1101 00102
– Adjunk hozzá 1-et
• 1101 00112
– Eredmény:
• 1101 00112 = 21110 = -4510
Kettes komplemens 3.
• 2810 = 0001 11002
– Másoljuk a zérusokat jobbról balra
• 002
– Másoljuk le az első 1-est
• 1002
– Invertáljuk a többi bitet
• 1110 01002 = 22810 Ellenőrzés
0001 1100
+ 1110 0100
1 0000 0000
Kettes komplemens
• 8 bit esetén
-1 = 1111 1111
-2 = 1111 1110
-128 = 1000 0000
+1 = 0000 0001
+127 = 0111 1111
+128 = érvénytelen !!!
Kettes komplemens
• 16 bit esetén
-1 = 1111 1111 1111 1111
-2 = 1111 1111 1111 1110
-32768 = 1000 0000 0000 0000
8-ból 16 bites számok
• 6410
– 8 bites reprezentálás: 40h
– 16 bites reprezentálás: 0040h
• -6410
– 8 bites reprezentálás: C0h = 1100 0000
– 16 bites reprezentálás: FFC0h = 1111 1111 1100 0000
• Szabály:
– Az előjel bitet minden további bit helyébe bemásoljuk
16-ból 8 bites számok
• -448
– 16 bites reprezentálás: FE40h
– 8 bites reprezentálás: nem lehet !!!
• „Sign contraction” csak akkor lehetséges ha az
összes felső bit mind zérus vagy 1-es
– Példa: FF80h -ból 80h lesz
Architektúra
• 8086-os processzor
• Regiszterek
• Memória
8086
• 16 bites processzor
• Busz
– Címbusz
• A processzor a memóriával közli a kívánt címet
– Adatbusz
• A processzor és egyéb egységek közötti adatfrogalomra
– Vezérlőbusz
• A vezérlőjeleket továbbítjuk

Az adatbusz „vonalainak” száma adja meg hány


bites a processzor
8086
címbusz

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

Fetch Dekód Futtat Fetch Dekód Futtat Processzor


1 1 1 2 2 2
Tölt Vár Vár Tölt Vár Vár Busz

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 f2(int a2)


{
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
}

void f2(int a2)


{
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) 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 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
• 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

szegmens 0000 16 bit


+ offszet 16 bit

= lineáris cím 20 bit


Példa
• Lineáris cím: 25553
– Szegmens:offszet = 2222:3333
– Szegmens:offszet = 2000:5553
Szegmentálás, Intel
• 8086 (régi szegmentálás)
– Max 1 MB memória
– 64 KB szegmensek
– 16 x 64 KB = 1MB
– Bármely cím elérhető, csak be kell tölteni a szegmens
regiszterbe
• CS : kód szegmens szelektor
• DS : adat szegmens szelektor
Szegmentálás , Intel
• 80386, védett módú címzés
– 4 GB memória
– A memória nem elérhető szabadon
– A szegmens bármekkora lehet
• 1 byte
• 64 KB
• 4 GB
Szegmenstáblák
• GDT (Globális leíró tábla)
– Csak egy van
– Általános célú
– Minden program használhatja
• IDT (Megszakítás leíró tábla)
– Megszakítás kezelő rutinok címe
• LDT (Lokális leíró tábla)
– Minden processzusnak lehet
– Opcionális
Szegmenstáblák
• Miután a memóriába helyeztük a leíró táblákat, a
processzornak is meg kell mondani
– 3 speciális regiszter:
• GDTR, IDTR, LDTR
• 32 bites regiszterek

• Szegmens regiszter (DS, CS) 16 bitesek


Szegmens címzés
• Hogyan lehet egy 16 bites regiszterben 32 bites
címet tárolni?
– Sehogy

– Vesszük a 16 bites címet


– Eltoljuk jobbra 3 bittel (13 bites cím)
• Ez 8192 különböző értéket jelent, ami pont megfelel a
szegmenstáblák méretének
– A szegmens regiszter a szegmenstáblán belüli indexet
adja meg
Szegmens címzés
• Mire kell az alsó 3 bit?
– 2 bit: a védelmi szint: 0-3
– 1 bit: GDT vagy LDT táblát használjuk-e?
Szegmens címzés FFFF FFFF


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

Vous aimerez peut-être aussi