Assembly programoz´as szerkesztette: Iv´anyi P´eter September 27, 2010
2
Tartalomjegyz´ek 1
Bevezet´es
11
1.1
RISC e´ s CISC processzor architekt´ur´ak . . . . . . . . . . . . . . . . . . . . . . . . .
11
1.2
Assembly els˝ore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
1.3
Mi´ert tanuljunk assembly nyelvet? . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
1.4
Mikor ne haszn´aljunk assembly nyelvet? . . . . . . . . . . . . . . . . . . . . . . . . .
13
1.4.1
A magas szint˝u programoz´asi nyelvek el˝onye . . . . . . . . . . . . . . . . . .
14
1.4.2
Az assembly h´atr´anyai . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
1.5
Miel˝ott elkezden´enk assembly-ben programozni ... . . . . . . . . . . . . . . . . . . .
14
1.6
Szintakszis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
1.7
Assemblerek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
1.7.1
MASM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
1.7.2
GAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
1.7.3
TASM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
1.7.4
NASM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15 15
1.8
1.7.5 Melyik assembler? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ¨ Osszefoglal´ as . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
1.9
Ellen˝orz˝o k´erd´esek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
2 A sz´am´ıt´og´ep fel´ep´ıt´ese 2.1
17
A processzor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
2.1.1
V´egrehajt´asi ciklus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
2.1.2
A rendszer o´ ra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
C´ımz´esi architekt´ura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
2.2.1
H´arom c´ımes architekt´ura . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
2.2.2
K´et c´ımes architekt´ura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
2.2.3
Egy c´ımes architekt´ura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
2.2.4
Z´er´o c´ım architekt´ura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
2.2.5
Load/Store architekt´ura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
2.3
Regiszterek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
2.4
V´egrehajt´asi sorrend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
2.4.1
Branching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
Mem´oria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
2.5.1
22
2.2
2.5
Mem´oria m˝uveletek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
2.5.2
Olvas´asi ciklus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
2.5.3
Olvas´asi ciklus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
2.5.4
Mem´oria t´ıpusok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
2.5.5
Byte sorozatok t´arol´asa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
24
2.5.6
Adat “alignment” problema . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
2.6
Input/Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
2.7
2.6.1 I/O eszk¨oz¨ok el´er´ese . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ¨ Osszefoglal´ as . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
2.8
Ellen˝orz˝o k´erd´esek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
3 A processzor ´ anos regiszterek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1 Altal´
30
27
29
3.2
Szegment´alt c´ımz´es el˝osz¨or . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30
3.3
C´ımz´esi m´odok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
3.3.1
Direkt c´ımz´esi m´od . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
3.3.2
Indirekt c´ımz´esi m´od . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
34
3.4
St´atusz regiszter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
3.5
Ellen˝orz˝o k´erd´esek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
36
4 NASM assembler
37
4.1
Egy forr´as file szerkezete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
37
4.2
Pszeudo utas´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
37
4.2.1
DB e´ s t´arsai . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
4.2.2
RESB e´ s t´arsai . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
4.2.3
Konstansok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
4.2.4
TIMES pszeudo utas´ıt´as . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
4.3
SEG kulcssz´o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
4.3.1
Tov´abbi hasznos´ıt´asi ter¨uletek . . . . . . . . . . . . . . . . . . . . . . . . . .
40
4.4
WRT kulcssz´o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
4.5
Parancssori opci´ok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
4.6
Hiba¨uzenetek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
5 DEBUG program
41
5.1
Jel¨ol´esek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
5.2
A DEBUG ind´ıt´asa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
5.3
A DEBUG parancsai . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
5.4
P´eld´ak . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
5.4.1
1. P´elda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
5.4.2
2. P´elda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
5.4.3
3. P´elda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
6 Els˝o programok
47
6.1
Els˝o program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
6.2
Egy karakter kinyomtat´asa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
4
6.3
Egy sz¨oveg kinyomtat´asa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
6.4
Egy karakter beolvas´asa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
7 Assembly nyelv utas´ıt´asai 7.1
7.2
7.3
7.4
53
Adatmozgat´o utas´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
7.1.1
MOV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
7.1.2
XCHG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
7.1.3
XLAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
7.1.4
LDS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
7.1.5
LES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
7.1.6
LEA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
7.1.7
PUSH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
7.1.8
PUSHF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
7.1.9
PUSHA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
7.1.10 POP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
7.1.11 POPF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
58
7.1.12 POPA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
58
7.1.13 LAHF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
7.1.14 SAHF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
Matematikai utas´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60
7.2.1
INC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60
7.2.2
DEC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60
7.2.3
ADD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60
7.2.4
ADC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
7.2.5
SUB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
7.2.6
SBB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
62
7.2.7
MUL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
62
7.2.8
IMUL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
63
7.2.9
DIV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
63
7.2.10 IDIV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
7.2.11 NEG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
7.2.12 CBW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
65
7.2.13 CWD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
65
Bitforgat´o e´ s bitl´eptet˝o utas´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
66
7.3.1
RCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
66
7.3.2
RCR
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
66
7.3.3
ROL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
67
7.3.4
ROR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
68
7.3.5
SAL, SHL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
68
7.3.6
SAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
69
7.3.7
SHR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
69
Logikai utas´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
7.4.1
71
AND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
7.5
7.6
7.7
7.8
7.9
7.4.2
OR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
7.4.3
XOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
7.4.4
NOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
7.4.5
TEST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
7.4.6
CMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
Vez´erl´es´atad´o utas´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
7.5.1
JMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
7.5.2
Felt´eteles utas´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
7.5.3
JCXZ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
7.5.4
LOOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
7.5.5
LOOPNZ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
7.5.6
LOOPZ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
73
7.5.7
CALL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
73
7.5.8
RET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
73
7.5.9
INT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
73
String kezel˝o utas´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
74
7.6.1
MOVSB, MOVSW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
74
7.6.2
CMPSB, CMPSW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
7.6.3
LODSB, LODSW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
7.6.4
STOSB, STOSW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
7.6.5
SCASB, SCASW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
7.6.6
REP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
76
7.6.7
REPZ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
77
7.6.8
REPNZ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
77
Processzor vez´erl˝o utas´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
7.7.1
CLC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
7.7.2
STC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
7.7.3
CMC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
7.7.4
CLD
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
7.7.5
STD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
7.7.6
CLI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
7.7.7
STI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
Egy´eb utas´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
7.8.1
NOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
7.8.2
IN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
7.8.3
OUT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
Ellen˝orz˝o k´erd´esek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
81
8 Assembly programokr´ol
83
8.1
Programoz´asi m´odszer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
8.2
Megszak´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
84
8.2.1
Hardware-es megszak´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . .
84
8.2.2
Megszak´ıt´asok 8086-os processzorokon . . . . . . . . . . . . . . . . . . . . .
85
6
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
86 86 87 87 88 88 88 88 88 89
9 P´elda programok 9.1 Egy byte bin´aris kinyomtat´asa . . . . . . . . . . . . . . . . . . 9.2 Egy hexadecim´alis sz´am kinyomtat´asa . . . . . . . . . . . . . . 9.3 Egy byte hexadecim´alis kinyomtat´asa . . . . . . . . . . . . . . 9.4 Egy decim´alis sz´amjegy ellen˝orz¨ott beolvas´asa e´ s kinyomtat´asa . 9.5 Egy karakter beolvas´asa e´ s m´odos´ıt´asa . . . . . . . . . . . . . . ¨ karakter bolvas´asa e´ s kinyomtat´asa ford´ıtott sorrendben . . . 9.6 Ot 9.7 K´et egyjegy˝u sz´am o¨ sszead´asa . . . . . . . . . . . . . . . . . . 9.8 Egy karakter n-szeri kinyomtat´asa . . . . . . . . . . . . . . . . 9.9 T´eglalap kinyomtat´asa . . . . . . . . . . . . . . . . . . . . . . 9.10 Sakkt´abla nyomtat´asa . . . . . . . . . . . . . . . . . . . . . . . 9.11 ASCII t´abla kinyomtat´asa . . . . . . . . . . . . . . . . . . . . . 9.12 Sz´am ki´ır´asa decim´alis form´aban . . . . . . . . . . . . . . . . . 9.13 Olvas´as a mem´ori´ab´ol . . . . . . . . . . . . . . . . . . . . . . . 9.14 K¨ozvetlen vide´o mem´ori´aba ´ır´as . . . . . . . . . . . . . . . . . 9.15 Sz¨oveg beolvas´asa . . . . . . . . . . . . . . . . . . . . . . . . 9.16 Beolvasott sz¨ovegben karakterek sz´aml´al´asa . . . . . . . . . . . 9.17 Beolvasott sz¨oveg nagy bet˝usre konvert´al´asa . . . . . . . . . . . 9.18 Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
91 91 93 95 97 98 100 101 104 105 108 111 112 114 115 116 117 118 119
. . . . . . . . . . . .
121 121 121 123 123 123 124 126 126 128 128 130 135
8.3 8.4 8.5 8.6 8.7 8.8
8.2.3 INT 21h megszak´ıt´as . . 8.2.4 Kiv´etelek . . . . . . . . Kit´er˝o Linux-ra . . . . . . . . . COM programok . . . . . . . . 8.4.1 Program Segment Prefix EXE programok . . . . . . . . . XOR haszn´alata . . . . . . . . . Assembly integer aritmetika . . 8.7.1 BCD aritmetika . . . . . Ellen˝orz˝o k´erd´esek . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
10 Fuggv´ ¨ enyek 10.1 A verem adatszerkezet . . . . . . . . . . . . 10.1.1 A verem implement´aci´oja . . . . . . 10.1.2 Verem m˝uveletek . . . . . . . . . . . 10.2 A verem haszn´alata . . . . . . . . . . . . . . ´ ekek id˝oleges t´arol´as . . . . . . . 10.2.1 Ert´ 10.3 F¨uggv´enyek defin´ıci´oja . . . . . . . . . . . . 10.3.1 Egym´asba a´ gyazott f¨uggv´enyh´ıv´asok 10.4 Param´eter a´ tad´as f¨uggv´enyeknek . . . . . . . 10.4.1 Param´eter a´ tad´as regiszteren kereszt¨ul 10.4.2 Param´eter a´ tad´as mem´ori´an kereszt¨ul 10.4.3 Param´eter a´ tad´as vermen kereszt¨ul . . ´ ek e´ s c´ım szerinti param´eter a´ tad´as 10.4.4 Ert´
7
. . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
10.5 10.6 10.7 10.8 10.9
10.4.5 V´altoz´o sz´am´u param´eter a´ tad´asa f¨uggv´enynek Lok´alis v´altoz´ok f¨uggv´enyekben . . . . . . . . . . . . 10.5.1 ENTER e´ s LEAVE utas´ıt´asok . . . . . . . . . Rekurz´ıv f¨uggv´enyek . . . . . . . . . . . . . . . . . . Hat´ekonys´ag . . . . . . . . . . . . . . . . . . . . . . . Ellen˝orz˝o k´erd´esek . . . . . . . . . . . . . . . . . . . Feladatok . . . . . . . . . . . . . . . . . . . . . . . .
11 Makr´ok 11.1 Egy soros makr´ok . . . . . . . . . . . 11.2 T¨obb soros makr´ok . . . . . . . . . . 11.2.1 C´ımk´ek makr´okban . . . . . . 11.2.2 “Greedy” makr´o param´eterek 11.3 Makr´ok e´ s f¨uggv´enyek m´eg egyszer . 11.4 Makr´ok gy˝ujtem´enyek . . . . . . . . 11.5 Ellen˝orz˝o k´erd´esek . . . . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
12 String muveletek ˝ 12.1 String utas´ıt´asok . . . . . . . . . . . . . . . . . . 12.1.1 String m´asol´as . . . . . . . . . . . . . . 12.1.2 Stringek o¨ sszehasonl´ıt´asa . . . . . . . . . 12.1.3 Keres´es stringek-ben . . . . . . . . . . . 12.1.4 LODSB e´ s STOSB utas´ıt´asok haszn´alata 12.2 String utas´ıt´asok el˝onyei e´ s h´atr´anyai . . . . . . . 12.3 Ellen˝orz˝o k´erd´esek . . . . . . . . . . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
136 141 142 143 144 144 148
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
149 149 151 152 153 154 154 157
. . . . . . .
159 160 160 163 165 166 166 168
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
13 P´eld´ak fuggv´ ¨ enyekre e´ s sz¨oveg kezel´esre 169 13.1 Sz¨oveg hossz´anak meg´allap´ıt´asa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 14 C e´ s assembly programok kapcsolata 171 14.1 F¨uggv´eny h´ıv´asi konvenci´ok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 14.1.1 16 bites m´od . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 14.1.2 32 bites m´od . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 15 Optimaliz´al´as 15.1 Optimaliz´al´as sebess´egre . . . . . . . . . . . . . . 15.1.1 Sorrenden k´ıv¨uli v´egrehajt´as . . . . . . . . 15.1.2 Utas´ıt´as bet¨olt´es e´ s dek´odol´as . . . . . . . 15.1.3 Utas´ıt´as k´esleltet´es e´ s a´ tbocs´at´asi k´epess´eg 15.1.4 F¨ugg˝os´egi l´anc megt¨or´ese . . . . . . . . . 15.1.5 Ugr´asok e´ s f¨uggv´eny h´ıv´asok . . . . . . . 15.2 Optimaliz´al´as m´eretre . . . . . . . . . . . . . . . . 15.3 Mem´oria hozz´af´er´es optimaliz´al´asa . . . . . . . . 15.4 Ciklusok optimaliz´al´asa . . . . . . . . . . . . . . . 15.5 Vector programoz´as . . . . . . . . . . . . . . . . .
8
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
173 173 173 174 174 174 174 174 174 174 174
15.6 Probl´em´as utas´ıt´asok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 16 Optimaliz´alt p´eld´ak 175 16.1 ASCII t´abla nyomtat´asa r¨ovidebben . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 17 Megjegyz´esek 177 17.1 Szok´asos hib´ak . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 A ASCII t´abl´azat
179
B Felhaszn´alt irodalom 181 P´elda programok list´aja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 T´argymutat´o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
9
10
1. Fejezet
Bevezet´es Ez a jegyzet egy o¨ ssze´all´ıt´asnak, szerkesztett jegyzetnek indult ink´abb, mint egy o¨ n´all´o k¨onyv. A jegyzet anyag´at igyekeztem u´ gy o¨ sszeszedni, hogy az egy egys´eges eg´eszt alkosson. A jegyzet c´elja az assembly nyelv megismertet´ese a hallgat´okkal. Ugyanakkor az assembly nyelv nagyon er˝osen k¨ot˝odik a processzor architekt´ur´ahoz, ´ıgy az assembly programoz´ashoz az architekt´ur´aval is meg kell ismerkedni egy kicsit. A jegyzet kifejezetten az Intel x86-os processzor´anak alacsony szint˝u programoz´as´aval foglalkozik, ezek k¨oz¨ul is a 8086-os processzorral. Ez az egyik legkor´abbi Intel processzor e´ s furcs´anak t˝unhet a v´alaszt´as, hogy 2010 k¨orny´ek´en is err˝ol a processzorr´ol besz´el¨unk. A jegyzet ´ır´asa sor´an f˝o c´elom az volt, hogy az alapokat minden hallgat´o meg tudja e´ rteni e´ s el tudja saj´at´ıtani. Ehhez egy viszonylag “egyszer˝u” processzorra volt sz¨uks´eg e´ s f˝oleg ez´ert v´alasztottam a 8086-os processzort alapul. A m´asik indok, hogy a szimul´atorok e´ s virtu´alis g´epek biztos t´amogatj´ak ezt a processzort e´ s ´ıgy b´armilyen k¨ornyezetben lehet az assembly programoz´ast gyakorolni. ´Igy a jegyzet f˝oleg kezd˝oknek sz´ol, de azt rem´elem, hogy a gyakorlottabb hallgat´ok is profit´alnak a jegyzet elolvas´as´ab´ol. A jegyzet term´eszetesen igyekszik foglalkozni az u´ jabb utas´ıt´asokkal e´ s m´odszerekkel, amiket p´eld´aul a Pentium processzorokra fejlesztettek.
´ ak 1.1 RISC e´ s CISC processzor architektur´ A processzor architekt´ur´ak k´et nagy csoportba sorolhat´ok: CISC (Complex Instruction Set Computers)1 , RISC (Reduced Instruction Set Computers)2 . A domin´ans processzor architekt´ura a piacon a Pentium processzor, ami a CISC csal´adhoz tartozik, de ugyanakkor a jelenlegi trendek szerint egyre ink´abb a RISC architekt´ura ker¨ul el˝ot´erbe. A RISC processzorok k¨oz´e tartoznak a MIPS, SPARC, PowerPC e´ s ARM processzorok. A 64-bites Itanium is RISC alap´u processzor. Mit jelent az, hogy komplex utas´ıt´as a CISC architekt´ura eset´en? K´et sz´am o¨ sszead´asa egyszer˝u m˝uveletnek sz´am´ıt. Ugyanakkor, ha egy t¨omb¨ot a´ tm´asolunk e´ s k¨ozben a t¨omb mutat´okat folyamatosan friss´ıtj¨uk, az m´ar komplex utas´ıt´asnak sz´am´ıt.3 A RISC rendszerek csak egyszer˝u utas´ıt´asokat haszn´alnak, e´ s bizonyos felt´eteleket is szabnak. P´eld´aul az utas´ıt´asok argumentumainak a regiszterekben kell lenni¨uk e´ s nem a mem´ori´aban.
1 Szabad
ford´ıt´asban: Komplex utas´ıt´ask´eszlet˝u sz´am´ıt´og´ep ford´ıt´asban: Egyszer˝us´ıtett utas´ıt´ask´eszlet˝u sz´am´ıt´og´ep 3 L´ etezik ilyen utas´ıt´as a CISC processzorokon, ez a MOVSB utas´ıt´as, l´asd 7.6.1. bekezd´es.
2 Szabad
11
1.2 Assembly els˝ore Az assembly nyelven ´ırt programokat processz´alni kell egy m´asik program, assembler, a´ ltal ami g´epi k´odot gener´al. A g´epi k´odot fogja futtatni a processzor. N´ezz¨unk n´eh´any assembly utas´ıt´ast: inc mov add
[result] [meret], 45 [mask1], 256
Az els˝o sorban megadott utas´ıt´as megn¨oveli a ‘result’ v´altoz´o e´ rt´ek´et. A m´asodik sorban megadott utas´ıt´as a 45-¨os e´ rt´eket t¨olti a ‘m´eret’ v´altoz´oba, m´ıg a harmadik utas´ıt´as 256-ot add a ‘mask1’ v´altoz´ohoz. A fenti k´odr´eszlet C programoz´asi nyelven a k¨ovetkez˝ok´eppen n´ez ki: result++; meret = 45; mask1 = mask1+ 256; A p´elda alapj´an a k¨ovetkez˝oket lehet meg´allap´ıtani az assembly nyelvr˝ol: • Az assembly nyelv utas´ıt´asai kriptikusak. • Az assembly nyelv m˝uveleteit mnemonikok ´ırj´ak le, p´eld´aul add vagy mov. • Az assembly nyelv utas´ıt´asai nagyon alacsony szint˝uek. P´eld´aul a k¨ovetkez˝ot m´ar nem ´ırhatjuk le4 : mov
[meret], [adat]
A 1.1. t´abl´azat n´eh´any assembly utas´ıt´ast e´ s a neki megfelel˝o g´epi k´odot mutatja. A t´abl´azatn´al az els˝o e´ szrev´etel, hogy a RISC processzorokon az utas´ıt´asok hossza fix. (Ezzel is cs¨okkentve a komplexit´ast.) A m´asik fontos e´ szrev´etel, hogy a g´ep k´od meg´ert´ese nagyon neh´ez az emberek sz´am´ara, hiszen t¨obb ezer sz´am kombin´aci´ot kellene megjegyezni. Ugyanakkor k¨ozvetlen, egy az egyes megfeleltet´es van az assembly utas´ıt´as e´ s a g´epi k´od k¨oz¨ott ez´ert ha az utas´ıt´ast ´ırjuk le az pontosan megfelel a sz´and´ek szerinti g´epi k´odnak e´ s ´ıgy csak ‘mazochist´ak’ programozn´anak g´epi k´odban. Mindenki ink´abb az emberek sz´am´ara jobban e´ rtelmezhet˝o assembly parancsokat, mnemonikokat haszn´alja. Persze a digit´alis forradalom elej´en n´eh´any programot m´eg g´epi k´odban ´ırtak.
1.3 Mi´ert tanuljunk assembly nyelvet? Az assembly programoz´as nem annyira n´epszer˝u mint n´eh´any e´ ve volt. Ugyanakkor m´eg mindig t¨obb oka van annak, hogy megtanuljunk assembly-ben programozni: • Tanul´as: Fontos tudni hogyan m˝uk¨odnek a processzorok e´ s ford´ıt´ok az utas´ıt´as szinten. Ezen ismeretek seg´ıts´eg´evel meg lehet a´ llap´ıtani mely programoz´asi m´odok a leghat´ekonyabbak, illetve, hogy a magasabb szint˝u programoz´asi szerkezetek hogyan m˝uk¨odnek. • Debuggol´as: T¨obb szempontb´ol is hasznos lehet ha a ford´ıt´ok a´ ltal gener´alt k´odot meg tudjuk e´ rteni illetve meg tudjuk a´ llap´ıtani, hogy mennyire j´o, optimaliz´alt k´odot gener´al egy ford´ıt´o. • Ford´ıt´ok: Az assembly k´od meg´ert´ese elengedhetetlen ahhoz, hogy ford´ıt´ot, debugger-t vagy egy´eb fejleszt˝o eszk¨oz¨oket fejlessz¨unk. • Be´agyazott rendszerek: A be´agyazott rendszereknek nincs annyi er˝oforr´asa mint egy hagyom´anyos PC-nek e´ s ez´ert sz¨uks´eg lehet az assembly nyelvre, hogy ilyen rendszerekre gyors e´ s hat´ekony k´odot ´ırjunk. 4A
magyar´azat a 3. fejezetben tal´alhat´o.
12
Pentium processzor Assembly M˝uvelet G´epi k´od (hex) ¨ nop Ures m˝uvelet 90 inc result N¨ovel´es FF060A00 mov result, 45 M´asol´as C7060C002D00 and mask, 128 Maszkol´as 80260E0080 MIPS processzor Assembly M˝uvelet ¨ Ures m˝uvelet nop mov $t2, $t15 M´asol´as ´ and $t2, $t1, 15 Logikai ES ¨ addu $t3, $t1, $t2 Osszead´as
G´epi k´od (hex) 00000000 000A2021 312A000F 012A5821
1.1. t´abla: Assembly parancsok e´ s a megfelel˝o g´epi k´od
• Hardware eszk¨oz¨ok: A magas szint˝u programoz´asi nyelvek korl´atozott (absztrakt) hozz´af´er´est engednek a hardware elemekhez, ´ıgy a hardware eszk¨oz¨ok haszn´alat´at e´ s el´er´es´et biztos´ıt´o eszk¨ozvez´erl˝ot ´ırni magas szint˝u nyelven neh´ez vagy lehetetlen. Ilyen esetben is j´ol j¨ohet az assembly nyelv ismerete. • Olyan utas´ıt´asokat is haszn´alhatunk assembly-ben aminek a magasabb szint˝u nyelvekben nincs megfelel˝oje. • M´eretre val´o optimaliz´al´as: A m´eretre val´o optimaliz´al´as azt jelenti, hogy Program A kevesebb helyet foglal mint Program B de ugyanazt a feladatot l´atja el. A mem´oria ma m´ar olyan olcs´o, hogy tulajdonk´eppen nem e´ ri meg assembly-ben k´odot ´ırni a program m´eret´enek cs¨okkent´ese miatt. Ugyanakkor a cache m´eg midig kis m´eret˝u e´ s dr´aga, ´ıgy az erre optimaliz´alt k´od eset´en m´eg mindig fontos az assembly nyelv haszn´alata. • Sebess´egre val´o optimaliz´al´as: A sebess´egre optimaliz´alt program a lehet˝o legr¨ovidebb id˝o alatt v´egzi el a feladatot. Hab´ar a modern ford´ıt´ok viszonylag j´ol optimaliz´alj´ak a gener´alt k´odot, bizonyos esetekben a k´ezzel optimaliz´alt assembly program r´eszlet dr´amaian fel tudja gyors´ıtani a programot. Az utols´o k´et szempontb´ol az ut´obbi a fontosabb. Egyr´eszt a hely megtakar´ıt´as csak a program k´odra vonatkozik e´ s az adatra nem, m´asr´eszt a mem´oria m´eret´enek n¨oveked´ese miatt. Assemblyben az´ert lehet hat´ekony k´odot ´ırni, mivel a nyelv saj´atoss´aga, hogy a gener´alt k´od csak azt tartalmazza amit bele´ırtunk, vagyis ami a feladat megold´as´ahoz kell. Semmi m´as, extra inform´aci´ot nem ford´ıt bele az assembler. A sebess´egre optimaliz´alt alkalmaz´asok k´et kateg´ori´aba sorolhat´ok: – id˝o hat´ekony alkalmaz´asok: ezekn´el a programokn´al a gyorsabb fut´as jelent el˝onyt, de nincs k¨ul¨on¨osebb probl´ema ha a sebess´eg lassabb; – id˝o kritikus alkalmaz´asok: ebben az esetben a feladatot adott id˝o alatt kell elv´egezni. ´ aban ezek a val´os idej˝u alkalmaz´asok (real-time systems), p´eld´aul: rep¨ul˝og´ep navig´aci´os Altal´ eszk¨ozei, robot kontroll rendszerek, kommunik´aci´os szoftverek.
1.4 Mikor ne haszn´aljunk assembly nyelvet? Olyan sok h´atr´anya van az assembly nyelven val´o programoz´asnak, hogy miel˝ott elkezden´enk programozni assembly-ben m´as alternat´ıv´akat is vegy¨unk figyelembe.
13
1.4.1 A magas szintu˝ programoz´asi nyelvek el˝onye A magas szint˝u programoz´asi nyelvek viszonylag k´enyelmes absztrakci´ot tesznek lehet˝ov´e, hogy az adott probl´em´at megoldjuk. A magas szint˝u programoz´asi nyelvek el˝onyei: • A programfejleszt´es gyorsabb: A magas szint˝u programoz´asi nyelvekben sokf´ele programoz´asi ´ aban r¨ovidebbek is a programok. konstrukci´o a´ ll rendelkez´esre. Altal´ • A programokat k¨onnyebb karbantartani: A magas szint˝u programoz´asi nyelven ´ırt programokat egyszer˝ubb meg´erteni e´ s ez´ert k¨onnyebb m´asok a´ ltal ´ırt programot a´ ttekinteni e´ s meg´erteni. • A programok hordozhat´oak: A program nem tartalmaz processzor specifikus r´eszleteket e´ s ez´ert b´armilyen rendszeren haszn´alhat´oak.5
1.4.2 Az assembly h´atr´anyai Az assembly-ben val´o programoz´as ellen sz´ol´o legfontosabb e´ rvek: 1. Fejleszt´esi id˝o: Az assembly-ben val´o programoz´as szinte mindig t¨obb id˝ot ig´enyel mint a magasabb szint˝u programoz´asi nyelv haszn´alata. 2. Megb´ızhat´os´ag e´ s biztons´ag: Assembly nyelven k¨onny˝u hib´at v´eteni. Az assembler csak szintaktikai ellen˝orz´eseket v´egez. 3. Debuggol´as e´ s ellen˝orz´es: Az assembly nyelven ´ırt programokban nehezebb hib´at keresni, illetve nehezebb ellen˝orizni a k´odot, hogy az el˝o´ırt feladatot oldja meg. 4. Karbantart´as: Az assembly nyelven ´ırt programokat nehezebb m´odos´ıtani e´ s karbantartani. A nyelv megengedi a “spagetti” k´od ´ır´asi technik´at e´ s egy´eb tr¨ukk¨ok is megengedettek a nyelvben, melyeket m´as nyelven nem lehet megval´os´ıtani. 5. Hordozhat´os´ag: Az assembly k´od a hardware platformhoz kapcsol´odik, csak az adott processzoron, architekt´ur´an lehet lefuttatni. 6. Modern ford´ıt´ok: A modern ford´ıt´ok sokat fejl˝odtek az elm´ult e´ vekben e´ s m´ar nagyon j´o k´odot tudnak gener´alni e´ s gyakran nehezebb jobb assembly k´odot gener´alni.
1.5 Miel˝ott elkezden´enk assembly-ben programozni ... Van n´eh´any szempont amit figyelembe kell venni miel˝ott egy komplex alkalmaz´ast elkezden´enk assemblyben programozni: • Ha az a c´elunk, hogy egy program sebess´eg´et optimaliz´aljuk, akkor el˝osz¨or azonos´ıtsuk, hogy a program mely r´esze fut a legt¨obbet a processzoron. Ellen˝orizz¨uk, hogy mivel t¨olti a legt¨obb id˝ot a program, p´eld´aul a mem´oria el´er´essel, CPU utas´ıt´asok v´egrehajt´as´aval, file-ok el´er´es´evel vagy valami m´assal. • D¨onts¨uk el, hogy a fejlesztett program u´ jrahasznos´ıthat´o vagy csak egy egyedi alkalmaz´as. Ha a k´odot u´ jra fel akarjuk haszn´alni, akkor e´ rdemes t¨obb id˝ot t¨olteni az optimaliz´al´assal. • El kell d¨onteni, melyik assemblert haszn´aljuk, mivel a k¨ul¨onb¨oz˝o assemblerek m´as-m´as szintakszist haszn´alhatnak. • A jelent˝os m´ert´ekben optimaliz´alt k´odot neh´ez lehet olvasni, ´ıgy a karbantart´as miatt e´ rdemes kisebb egys´egekbe szervezni a programot melyeknek j´ol defini´alt interface-e van e´ s megfelel˝oen van dokument´alva. 5 Itt
f˝oleg a forr´ask´odr´ol besz´el¨unk, nem a futtathat´o, m´ar leford´ıtott g´epi k´od´u programr´ol.
14
1.6 Szintakszis K´etf´ele jelent˝osebb szintakszis alakult ki az e´ vek sor´an, amiket az assembly programok ı´r´as´an´al haszn´alhatunk: • AT&T szintakszis • Intel szintakszis
1.7 Assemblerek T¨obb assembler is l´etezik az Intel processzorokra, melyek az x86-os utas´ıt´as k´eszletet haszn´alj´ak, vagyis a mnemonikokb´ol Intel g´epi k´odot hoznak l´etre. Az al´abbiakban csak n´eh´anyat mutatunk be.
1.7.1 MASM Ez a Microsoft Assembler, mely a mai napig r´esze a Microsoft fejleszt˝o k¨ornyezet´enek, a Visual Studionak. A program neve: ml.exe. A MASM sok´aig a “de-facto” ipari szabv´any volt e´ s t¨obb magasabb szint˝u programoz´asi konstrukci´ot is tudott kezelni. A form´atuma nem teljesen ‘tiszta’, vannak inkonzisztens r´eszek benne. Microsoft tov´abbra is fejleszti, de igaz´ab´ol minim´alis m´odon.
1.7.2 GAS GAS r¨ovidit´es megfelel˝oje a GNU Assembler, mely a GNU binutils csomag r´esze is. A GNU ford´ıt´ok olyan form´atumot gener´alnak, melyet ez az assembler k´epes leford´ıtani. GAS az u´ gynevezett AT&T szintakszist haszn´alja, b´ar ma m´ar az Intel szintakszisnak megfelel˝o k´odot is el tud fogadni. Ez az assembler haszn´alhat´o Linux, Mac OS X e´ s Windows alatt is.
1.7.3 TASM Az egyik legn´epszer˝ubb fejleszt˝oi eszk¨oz¨oket a Borland c´eg k´esz´ıtette. Az a´ ltaluk k´esz´ıtett programfejleszt˝o csal´adba tartozik a Turbo Assembler is. Sajnos ma m´ar nem fejlesztik, az u´ jabb utas´ıt´asok nem ker¨ulnek bele, de m´eg mindig el´erhet˝o az Interneten. Az assembler a´ ltal haszn´alt szintakszis nagyon hasonl´o a MASM assembler szintakszis´ahoz.
1.7.4 NASM NASM megfelel a Netwide Assembler n´evnek e´ s egy szabad forr´askod´u assembler, mely t¨obbf´ele objektum form´atumot k´epes gener´alni e´ s ´ıgy t¨obb oper´aci´os rendszert t´amogat (Linux, Windows, Mac OS X, FreeBSD, stb). A szintakszisa tiszt´abb mint a MASM assembler-´e, de kevesebb magas szint˝u programoz´asi konstrukci´ot k´epes kezelni.
1.7.5 Melyik assembler? Ez a jegyzet a NASM assemblert haszn´alja k´et f˝o ok miatt: • Az egyszer˝u szintakszis nagyon logikus e´ s konzisztens. • Windows e´ s Linux rendszeren is haszn´alhat´o, melyek manaps´ag a legjobban elterjedt oper´aci´os rendszerek.
15
¨ 1.8 Osszefoglal´ as Az assembly nyelv tanul´asa mind gyakorlati e´ s pedag´ogia c´elokat szolg´alhat. M´eg ha nem is sz´and´ekozunk assembly-ben programozni, akkor is e´ rdemes megtanulni, mivel egy nagyon j´o alapot ad ahhoz hogy meg´erts¨uk, hogyan m˝uk¨odnek a sz´am´ıt´og´epek. Amikor magas szint˝u programoz´asi nyelvet haszn´alunk, akkor a rendszert egy “fekete dobozk´ent” kezelj¨uk. Ezzel szemben assembly programoz´as eset´en a rendszert r´eszleteit is ismerni kell, p´eld´aul a regisztereket.
1.9 Ellen˝orz˝o k´erd´esek 1. Soroljon fel k¨ul¨onb¨oz˝o processzorokat! 2. Mit jelent a CISC kifejez´es e´ s mi jellemz˝o az ilyen processzorokra? 3. Soroljon fel indokokat mi´ert e´ rdemes assembly nyelvet tanulni? 4. Soroljon fel indokokat mikor kell assembly nyelvet tanulni? 5. Soroljon fel indokokat mikor ne haszn´aljunk assembly nyelvet? 6. Mi az assembly nyelv e´ s a g´epi k´od kapcsolata? 7. Magas szint˝u programoz´asi nyelvben mi´ert nem tudjuk teljes m´ert´ekben kontroll´alni a hardwaret? 8. Mi´ert h´ıvjuk az assembly programoz´asi nyelvet alacsony szint˝u nyelvnek e´ s a C programoz´asi nyelvet magas szint˝unek? 9. Soroljon fel n´eh´any k¨ul¨onbs´eget a CISC e´ s RISC processzorok k¨oz¨ott? 10. Hasonl´ıtsa o¨ ssze a k´et f´ele assembly szintakszist! 11. Soroljon fel assemblereket! 12. Mi´ert lehet sz¨uks´eg az assembly haszn´alat´ara id˝o kritikus alkalmaz´asok eset´en? 13. Soroljon fel id˝o kritikus alkalmaz´asokat!
16
2. Fejezet
A sz´am´ıt´og´ep fel´ep´ıt´ese A sz´am´ıt´og´epnek alapvet˝oen h´arom f˝o komponense van: a k¨ozponti egys´eg vagy processzor (CPU), a mem´oria, e´ s az Input/Output eszk¨oz¨ok. L´asd a 2.1. a´ bra. A r´eszek k¨oz¨otti kapcsolatot a rendszer busz biztos´ıtja. A mem´oria t´arolja a programokat e´ s az adatokat is egyszerre. Az Input/Output eszk¨oz¨ok lehetnek a billenty˝uzet, a k´eperny˝o e´ s ´ıgy tov´abb. A 2.2. a´ bra egy r´eszletesebb n´ezet´et adja a sz´am´ıt´og´epnek, ahol j´ol l´athat´o hogy a rendszer busz h´arom r´eszb˝ol a´ ll: c´ım busz, adat busz e´ s kontroll busz. A c´ım busz sz´eless´ege hat´arozza meg az el´erhet˝o mem´oria kapacit´ast, illetve az adat busz adja meg, hogy milyen m´eret˝u adatok mozoghatnak a CPU, a mem´oria e´ s az I/O eszk¨oz¨ok k¨oz¨ott. P´eld´aul a 8086-os processzornak 20 bites a c´ım busza e´ s 16 bites az adat busza. Ezek alapj´an a processzor 220 byte-ot tud megc´ımezni, vagyis 1 MByte-ot e´ s minden alkalommal 16 bit mozog az egys´egek k¨oz¨ott. A Pentium processzoroknak 32 c´ım vonaluk van a c´ım buszban e´ s 64 adat vonala. ´Igy a Pentium 4 GByte mem´ori´at tud megc´ımezni. A 2.2. a´ br´an az is fontos, hogy a buszok milyen ir´anyba k´epesek adatot k¨uldeni. L´athat´o, hogy a CPU a kontroll buszon kereszt¨ul ad utas´ıt´asokat a mem´ori´anak e´ s az I/O alrendszernek, adatot viszont az adat buszon kereszt¨ul fogad. A kontroll buszon kiadhat´o jelek: mem´oria olvas´as, mem´oria ´ır´as, I/O olvas´as, I/O ´ır´as, megszak´ıt´as e´ s ´ıgy tov´abb.
2.1 A processzor ´ A processzor kontroll´alja a legt¨obb tev´ekenys´eget a rendszerben. Ugy e´ rdemes r´a gondolni, hogy a k¨ovetkez˝o ciklust hajtja v´egre: 1. Egy utas´ıt´as bet¨olt´ese a mem´ori´ab´ol (fetch), 2. Az utas´ıt´as dek´odol´asa, azonos´ıt´asa (decode),
CPU
Memória Kapcsolat
Input/Output
2.1. a´ bra: Absztrakt e´ rtelmez´ese a sz´am´ıt´og´epnek
17
CPU
Memória
Cím busz Adat busz
I/O alrendszer
Kontroll busz
2.2. a´ bra: Egy sz´am´ıt´og´ep egyszer˝us´ıtett diagramja
3. Az utas´ıt´as v´egrehajt´asa (execute). Ez a v´egrehajt´asi ciklus, vagy fetch-decode-execute ciklus.
2.1.1 V´egrehajt´asi ciklus • Fetch – A processzor a bet¨oltend˝o utas´ıt´as c´ım´et felrakja a c´ım buszra. – A processzor a kontroll buszon kereszt¨ul mem´oria olvas´asra ad utas´ıt´ast a mem´oria egys´egnek. A processzor addig v´ar am´ıg az utas´ıt´as meg nem jelenik az adat buszon. – A mem´oria egys´egnek id˝o kell m´ıg hozz´af´er a sz¨uks´eges r´eszhez. Ez a hozz´af´er´esi id˝o. – A mem´oria a beolvasott utas´ıt´ast az adat buszra helyezi. – A processzor beolvassa az adat buszr´ol az utas´ıt´ast • Decode – Azonos´ıtani kell a beolvasott utas´ıt´ast. Ezt seg´ıtend˝o az utas´ıt´asok bizonyos k´odol´asi mint´at k¨ovetnek, melyet majd a 7. fejezetben t´argyalunk. • Execute – A v´egrehajt´ashoz k´et egys´egre van sz¨uks´eg: egy kontrol e´ s egy aritmetikai (ALU) egys´egre. A kontroll egys´eg seg´ıt az id˝oz´ıt´esben, m´ıg az ALU egys´eg a matematikai sz´am´ıt´asokat v´egzi el. Megjegyezz¨uk, hogy az adatok e´ s az utas´ıt´asok nem mindig k¨ozvetlen¨ul a mem´ori´ab´ol j¨onnek, hanem az u´ gynevezett cache-b˝ol. A cache mem´ori´ahoz val´o hozz´af´er´es gyorsabb. A Pentium processzoron 16 KB-os cache van a chipen, melynek fele adat e´ s fele utas´ıt´as cache. Szerencs´ere a cache haszn´alata hardware-ben van megoldva e´ s teljesen transzparens a programoz´o sz´am´ara.
18
2.1.2 A rendszer o´ ra A rendszer o´ ra a system clock. A rendszer o´ ra teszi lehet˝ov´e, hogy a m˝uveleteket o¨ sszeszinkroniz´aljuk. Az o´ rajel 1-eseket e´ s 0-kat ad ki sorozatban, szekvenci´aban. Az o´ ra frekvencia e´ rt´ek´et a m´asodpercenk´enti ciklusok sz´ama adja meg e´ s a m´ert´ekegys´ege Hertz (Hz). A MHz e´ s GHz 106 e´ s 109 ciklust jelent m´asodpercenk´ent. 1 o´ ra frekvencia = (2.1) o´ ra ciklus hossza A rendszer o´ ra adja meg a sz´am´ıt´og´ep sebess´eg´et. Minden processzor m˝uvelet v´egrehajt´asa t¨obb o´ rajel ciklust ig´enyel. P´eld´aul egy 1 GHz-es Pentium processzoron egy adat tov´abb´ıt´asa a mem´ori´ab´ol a processzorra h´arom o´ rajel ciklust ig´enyel. Egy o´ ra ciklus hossza: 1 = 1ns 1 × 109
(2.2)
e´ s ´ıgy az adattov´abb´ıt´ashoz 3 ns-ra van sz¨uks´eg. A sz´am´ıt´og´epek sebess´eg´et n¨ovelhetj¨uk u´ gy, hogy nagyobb o´ rajel frekvenci´at haszn´alunk. P´eld´aul egy 2 GHz-es processzoron az adat tov´abb´ıt´as m´ar csak 1.5 ns-ig fog tartani.
´ 2.2 C´ımz´esi architektura ´ Erdekes m´odon az egyik legfontosabb tulajdons´aga egy architekt´ur´anak hogy h´any c´ımet haszn´alunk az utas´ıt´asokban. A legt¨obb m˝uvelethez egy vagy k´et argumentumra van sz¨uks´eg. Ezek alapj´an szokt´ak a m˝uveleteket binary e´ s unary m˝uveleteknek nevezni, ahol a a “bi-” kett˝ot, az “un-” egyet jelent. “Unary” m˝uvelet p´eld´aul a tagad´as (NOT) m˝uvelet, m´ıg “binary” m˝uvelet az o¨ sszead´as e´ s a kivon´as. Ezek a m˝uveletek egy eredm´enyt adnak. Term´eszetesen vannak kiv´etelek, p´eld´aul az oszt´as. Az oszt´asn´al k´et argumentumra van sz¨uks´eg, az osztand´ora e´ s az oszt´ora, viszont k´et eredm´eny is keletkezik: az eredm´eny e´ s a marad´ek. Mivel a “binary” m˝uveletek a leggyakoribbak e´ s ebben az esetben k´et input argumentumra e´ s egy eredm´eny, output argumentumra van sz¨uks´eg ez´ert ez´ert a´ ltal´aban h´arom c´ımre van sz¨uks´eg egy utas´ıt´asn´al. Ebben a r´eszben azt n´ezz¨uk meg, hogyan lehet h´arom, kett˝o, egy e´ s z´erus c´ımet haszn´alni az utas´ıt´asokkal.
´ 2.2.1 H´arom c´ımes architektura A h´arom c´ımet haszn´al´o utas´ıt´ask´eszlettel rendelkez˝o processzorokn´al a k´et input argumentumot e´ s az egyetlen output argumentumot tudjuk megadni. A legt¨obb modern processzor ilyen utas´ıt´ask´eszletet haszn´al. N´ezz¨unk egy p´eld´at: A = B + C * D - E + F + A mely pszeudo assembly-ben a k¨ovetkez˝ok´eppen n´ez ki: mult add sub add add
T,C,D T,T,B T,T,E T,T,F A,A,T
; ; ; ; ;
T T T T A
= = = = =
C B B B B
* + + + +
D C C C C
* * * *
D D - E D - E + F D - E + F + A
A p´eld´aban az l´athat´o, hogy matematikai m˝uveletre egy utas´ıt´ast kell megadni. Ami szint´en szembet˝un˝o, hogy az els˝o utas´ıt´ast kiv´eve az els˝o k´et argumentum azonos. Mivel az esetek jelent˝os r´esz´eben ´ıgy van, ez´ert a sok duplik´aci´o elker¨ul´ese v´egett “k´et-c´ımes” utas´ıt´ask´eszleteket is szoktak implement´alni processzorokban.
19
´ 2.2.2 K´et c´ımes architektura Ebben az esetben az utas´ıt´asoknak csak c´ım argumentuma van e´ s az egyik c´ım inputk´ent e´ s outputk´ent is szolg´al. Az Intel processzorok, p´eld´aul a Pentium is ilyen utas´ıt´asokat haszn´al. N´ezz¨uk az el˝oz˝o p´eld´at u´ jra: A = B + C * D - E + F + A mely pszeudo assembly-ben a k¨ovetkez˝ok´eppen n´ez ki: load mult add sub add add
T,C T,D T,B T,E T,F A,T
; ; ; ; ; ;
T T T T T A
= = = = = =
C C B B B B
* + + + +
D C C C C
* * * *
D D - E D - E + F D - E + F + A
Mivel csak k´et argumentum a´ ll rendelkez´esre ez´ert az els˝o utas´ıt´assal bet¨oltj¨uk az adatot T-be. Ebben az esetben az a felt˝un˝o, hogy az els˝o 6 utas´ıt´asban a T argumentum k¨oz¨os. Ha ez lesz az alap eset, akkor m´ar csak egy c´ım, argumentum kell az utas´ıt´asokhoz.
´ 2.2.3 Egy c´ımes architektura Ha a mem´oria dr´aga vagy lass´u akkor egy speci´alis regisztert haszn´al a processzor. Ez a regiszter szolg´altatja az input e´ s az output argumentumot egy utas´ıt´asnak. Ezt a regisztert akkumul´ator regiszternek is szokt´ak nevezni, mivel benne gy˝ulik o¨ ssze, akkumul´al´odik, az eredm´eny. A legt¨obb arhitekt´ura eset´en csak egy akkumul´ator regiszter van. Ezt a regisztert nem kell megadni az utas´ıt´asnak csak a m´asik argumentumot.
´ 2.2.4 Z´er´o c´ım architektura Arra is van lehet˝os´eg, hogy mindk´et argumentum speci´alis helyen t´arol´odik e´ s ´ıgy nem kell megadni o˝ ket az utas´ıt´asokn´al. Ezek a processzorok egy vermet haszn´alnak. Az argumentumok a verem tetej´en vannak amiket az utas´ıt´as levesz onnan, majd az eredm´enyt is a verem tetej´ere teszi vissza.
´ 2.2.5 Load/Store architektura Ebben az esetben a m˝uveleteket a processzor bels˝o regiszterein v´egezhetj¨uk el e´ s k¨ul¨on utas´ıt´assal kell beolvasni az adatokat a mem´ori´ab´ol a regiszterekbe, illetve a regiszterekb˝ol ki´ırni a mem´ori´aba. A fenti p´elda a k¨ovetkez˝ok´eppen m´odosul: A = B + C * D - E + F + A mely pszeudo assembly-ben a k¨ovetkez˝ok´eppen n´ez ki: load load load load load load mult add
R1,B R2,C R3,D R4,E R5,F R6,A R2,R2,R3 R2,R2,R1
; R2 = C * D ; R2 = B + C * D
20
sub add add store
R2,R2,R4 R2,R2,R5 R2,R2,R6 A,R2
; R2 = B + C * D - E ; R2 = B + C * D - E + F ; R2 = B + C * D - E + F + A
A fenti p´eld´aban hat regisztert is haszn´alunk. B´ar nincs ennyire sz¨uks´eg, de ez a´ ltal´aban jellemz˝o ezekre az architekt´ur´akra, hogy sok regiszter¨uk van. A RISC processzoroknak t¨obb regiszter¨uk van mint a CISC processzoroknak. A MIPS processzornak 32 regisztere van, az Intel Itanium processzornak 128 regisztere e´ s az Intel Pentium processzornak csak 10 regisztere van.
2.3 Regiszterek Minden processzorban vannak regiszterek, melyeket k´et f˝o csoportba sorolhatunk: • a´ ltal´anos c´el´u regiszterek, • speci´alis c´el´u regiszterek. A speci´alis c´el´u regisztereket tov´abbi k´et csoportba oszthatjuk: felhaszn´al´o a´ ltal el´erhet˝o regiszterek e´ s csak a rendszer a´ ltal el´erhet˝o regiszterek. A Pentium regisztereit a 3. fejezetben t´argyaljuk.
2.4 V´egrehajt´asi sorrend A program v´egrehajt´asa a´ ltal´aban szekvenci´alisan t¨ort´enik, az utas´ıt´asokat egym´as ut´an hajtjuk v´egre. Az egyik regiszter, a “Program Counter” (PC) vagy “Instructon Pointer” (IP) regiszter, fontos szerept j´atszik a v´egrehajt´asi sorrend kezel´es´eben. A processzor mindig azt az utas´ıt´ast t¨olti be (fetch) amire a PC regiszter mutat. A bet¨olt´es ut´an a PC regiszter e´ rt´ek´et megn¨ovelj¨uk, hogy a k¨ovetkez˝o utas´ıt´asra mutasson. Ez a megn¨ovel´es lehet fix m´eret˝u, p´eld´aul a RISC processzorokn´al, vagy v´altoz´o m´eret˝u a CISC processzorokn´al, ahogy ez l´athat´o a 1.1. A CISC processzorok eset´en minden utas´ıt´asn´al k¨ul¨on meg kell a´ llap´ıtani, hogy mennyivel n¨ovelj¨uk meg a PC regiszter e´ rt´ek´et. A magasabb szint˝u programoz´asi nyelvekben ugyanakkor vannak felt´eteles v´egrehajt´asi e´ s ciklikus programoz´asi konstrukci´ok, melyek a v´egrehajt´asi sorrendet v´altoztatj´ak meg valamilyen fut´as k¨ozbeni felt´etelt˝ol f¨ugg˝oen. Ezek megval´os´ıt´asa a processzorokban “speci´alis” m´odon t¨ort´enik.
2.4.1 Branching A “branching” sz´o ford´ıt´asa tal´an az el´agaz´as lehet. Arr´ol van sz´o, hogy az eredeti szekvenci´at megszak´ıtva, m´ashol folytat´odik a program v´egrehajt´asa. K´et v´altozata van: a felt´etel n´elk¨uli e´ s felt´eteles ugr´o utas´ıt´as. Ezeknek az utas´ıt´asoknak egy argumentuma van, mely explicit m´odon megadja az u´ j utas´ıt´as c´ım´et. Ez azt jelenti, hogy amikor m´ashol kell folytatni a v´egrehajt´ast, akkor a PC regiszterbe az u´ j c´ımet t¨oltj¨uk be e´ s ´ıgy a k¨ovetkez˝o “fetch”-n´el m´ar ezt a c´ımet fogja haszn´alni a processzor. A v´egrehajt´asi sorrend a felt´etel n´elk¨uli ugr´o utas´ıt´as eset´en a 2.3. a´ br´an l´athat´o. Felt´eteles ugr´as A felt´eteles ugr´as eset´en az u´ j c´ım csak akkor t¨olt˝odik be a PC regiszterbe, ha valamilyen felt´etel teljes¨ul. K´etf´ele m´odon szokt´ak ezt megadni a k¨ul¨onb¨oz˝o processzorokban: Set-Then-Jump : Az ilyen architekt´ur´aj´u processzorokban a vizsg´alat e´ s az ugr´as sz´et van v´alasztva. A k´et, k¨ul¨on´all´o r´esz k¨oz¨otti kapcsolatot egy regiszter biztos´ıtja. A vizsg´alat be´all´ıtja a regiszter e´ rt´ek´et, majd az ugr´o utas´ıt´as ezt a regisztert vizsg´alja meg hogy bek¨ovetkezzen-e az ugr´as vagy sem. A Pentium processzorok ezt a technik´at haszn´alj´ak.
21
utasítás a jump cím utasítás b
utasítás utasítás
c d
2.3. a´ bra: Ugr´o utas´ıt´as
Test-And-Jump : A legt¨obb processzor o¨ sszekombin´alja a k´et r´eszt, p´eld´aul a MIPS processzorok. P´eld´aul: beq
Rsrc1, Rsrc2, c´ elc´ ım
o¨ sszehasonl´ıtja az Rsrc1 e´ s Rsrc2 regiszterek tartalm´at e´ s ha egyenl˝oek, akkor a c´ elc´ ım-n´el folytat´odik a v´egrehajt´as.
2.5 Mem´oria A sz´am´ıt´og´ep mem´ori´aj´at u´ gy e´ rdemes elk´epzelni mint sok elektronikus “kapcsol´o” o¨ sszess´ege. Ezek a “kapcsol´ok” k´et a´ llapotban lehetnek: nyitott vagy z´art a´ llapotban. Ugyanakkor ezeket az a´ llapotokat e´ rdemesebb 1 e´ s 0 a´ llapottal jellemezni. ´Igy minden “kapcsol´ot” reprezent´alni lehet egy bin´aris sz´ammal vagy bittel. A mem´oria milli´o sz´am tartalmaz biteket. A jobb kezelhet˝os´eg miatt a mem´oria a biteket csoportokba szervezik. 8 bit csoportja egy byte. ´Igy a mem´oria mint egy byte sorozat k´epzelhet˝o el. Minden byte-ra egy index sz´ammal lehet hivatkozni. Az els˝o index e´ rt´eke 0. Az utols´o index e´ rt´eke 2n − 1, ahol az n az adatbusz sz´eless´ege (h´any bites). A mem´oria sematikus k´epe a 2.4. a´ br´an l´athat´o.
˝ 2.5.1 Mem´oria muveletek K´et alapvet˝o m˝uvelet van: adat olvas´as a mem´ori´ab´ol e´ s adat ´ır´as a mem´ori´aba. Mindk´et esetben sz¨uks´eg van egy mem´oria c´ımre ahonnan olvashatunk, vagy ahova ´ırhatunk. Ezenk´ıv˝ul az ´ır´asi m˝uvelet m´eg egy adatot is ig´enyel.
2.5.2 Olvas´asi ciklus 1. A processor elhelyezi az olvasand´o adat c´ım´et a c´ım buszon. 2. A kontroll buszon a processzor kiadja a mem´oria olvas´asi jelet. 3. A processzor v´arakozik am´ıg az olvas´as megt¨ort´enik e´ s az adat megjelenik az adat buszon. 4. A processzor beolvassa az adatot az adat buszr´ol.
22
232-1
FFFF FFFF FFFF FFFE
1
0000 0001
0
0000 0000
2.4. a´ bra: A mem´oria sematikus k´epe
5. A kontroll buszon jelzi a processzor, hogy v´eget e´ rt az olvas´as. Egy Pentium processzor olvas´asi ciklusa h´arom o´ rajel ciklusnak felel meg. Az els˝o o´ rajel ciklus alatt az 1. e´ s 2. l´ep´es hajt´odik v´egre. A m´asodik o´ rajel ciklus alatt a processzor v´arakozik. A harmadik o´ rajel ciklus alatt az utols´o k´et l´ep´es fut le. Ha a mem´ori´anak m´egsem siker¨ul az olvas´as, akkor ezt jelzi a processzornak ami egy u´ jabb o´ rajel ciklusig v´ar.
2.5.3 Olvas´asi ciklus 1. A processzor elhelyezi az ´ırand´o adat c´ım´et a c´ım buszon. 2. A processzor elhelyezi az adatot az adat buszra. 3. A kontroll buszon a processzor kiadja a mem´oria ´ır´asi jelet. 4. A processzor v´arakozik am´ıg az ´ır´as megt¨ort´enik. 5. A kontroll buszon jelezz¨uk az ´ır´as v´eg´et. A Pentium processzor ´ır´asi c´ıklusa is h´arom o´ rajel ciklust ig´enyel. Az 1. e´ s 3. l´ep´es az els˝o o´ rajel alatt k¨ovetkezik be. A 2. l´ep´es csak a m´asodik o´ rajel ciklus alatt t¨ort´enik. A m´asodik o´ rajel ciklus v´eg´en jelzi az ´ır´as v´eg´et.
2.5.4 Mem´oria t´ıpusok A mem´ori´akat k¨ul¨onb¨oz˝o kateg´ori´akba lehet csoportos´ıtani. Az egyik legfontosabb tulajdons´aga a mem´ori´aknak, hogy csak olvashat´ok vagy ´ırhat´ok-olvashat´ok. Szint´en fontos tulajdons´ag, hogy a mem´oria minden r´esz´enek el´er´ese azonos id˝oben lehets´eges (random-access) vagy csak szekvenci´alisan. A szekvenci´alis el´er´es magyar´azat´ahoz a legjobb p´elda egy kazetta, amikor is addig kell olvasni a kazett´at, am´ıg el nem e´ rt¨uk a keresett adatot. V´eg¨ul vannak a “volatile” mem´ori´ak, melyekn´el am´ıg fesz¨ults´eg alatt van az egys´eg csak addig o˝ rzi meg a tartalmat. A “nonvolatile” mem´oria akkor is meg˝orzi a tartalm´at ha nincs fesz¨ults´eg alatt az egys´eg. Csak olvashat´o mem´ori´ak A csak olvashat´o mem´ori´ak (Read Only Memory vagy ROM) csak olvas´asi m˝uveletet enged. Ebbe a mem´ori´aba nem tudunk ´ırni. A f˝o el˝ony¨uk, hogy egyben “nonvolatile” mem´ori´ak is. A ROM mem´ori´ak
23
tartalm´at a “gy´arban” e´ getik bele. Ezeket a mem´ori´akat olcs´o gy´artani. A r´egebbi sz´am´ıt´og´epekben a BIOS a´ ltal´aban ROM. Vannak u´ gynevezett programozhat´o ROM-ok is (PROM), illetve t¨or¨olhet˝o (erasbale) PROM-ok (EPROM). ´ Irhat´ o-olvashat´o mem´ori´ak Az ´ırhat´o-olvashat´o mem´ori´akat a´ ltal´aban RAM-nak (random access memory-nak) is szokt´ak nevezni, hab´ar a ROM-ok eset´en is igaz az, hogy minden r´esze azonos id˝oben e´ rhet˝o el. Ezeket a mem´ori´akat k´et csoportba lehet sorolni: statikus e´ s dinamikus. A statikus RAM mem´ori´ak (SRAM) meg˝orzi az adatot a be´ır´as ut´an, minden tov´abbi menipul´aci´o n´elk¨ul, am´ıg a rendszer fesz¨ults´eg alatt van. Ilyen mem´oria a cache vagy a regiszterek. Ezzel szemben a f˝o mem´oria dinamikus (DRAM). A DRAM egy komplex eszk¨oz, mely kondenz´atorok seg´ıts´eg´evel t´arol egy bitet. A felt¨olt¨ott kondenz´ator jel¨oli az 1-es e´ rt´eket. Mivel a kondenz´atorok id˝ovel vesztenek a t¨olt´es¨ukb˝ol ez´ert id˝ok¨oz¨onk´ent friss´ıteni kell. Tipikusan 64 ms a friss´ıt´esi peri´odus. Az olvas´as sor´an azt tesztelj¨uk, hogy a kondenz´ator fel van-e t¨oltve. Ugyanakkor ez a tesztel´es t¨onkre is teszi a t¨olt´est. Ebben az e´ rtelemben a DRAM egy speci´alis mem´oria, mivel az olvas´as is destrukt´ıv, nem csak az ´ır´as. A legt¨obb mem´oria eset´en csak az ´ır´as destrukt´ıv. A destrukt´ıv olvas´as k¨ovetkezm´enye, hogy az olvas´as ut´an egy helyre´all´ıt´asi ciklus sz¨uks´eges. Ennek az a k¨ovetkezm´enye, hogy az olvas´as k´etszer olyan sok´aig tart mint m´as mem´ori´ak eset´en. Modern mem´oria t´ıpusok: • FPM DRAM: Fast page-mode DRAM • EDO DRAM: Extended Data Output DRAM • SDRAM: synchronous DRAM • DDR SDRAM • RDRAM: Rambus DRAM
2.5.5 Byte sorozatok t´arol´asa Term´eszetesen a´ ltal´aban nem csak egy byte-ot kell t´arolni, hanem t¨obb byte-ot is. P´eld´aul egy eg´esz sz´amot a C programoz´asi nyelvben a´ ltal´aban 4 byte-on t´arolunk. Felmer¨ulhet a k´erd´es, hogy hogyan t´aroljuk ezt a 4 byte-ot a mem´ori´aban? A 2.5. a´ bra k´et megold´ast is mutat. Az a´ br´an az MSB jel¨ol´es a “Most Significant Byte”-nek felel meg, m´ıg az LSB a “Least Significant Byte”. Mindk´et megold´as eset´en a 100-as c´ımet adtuk meg, e´ s ehhez k´epest t¨ort´enik a t´arol´as. A “Little-endian” t´arol´asi m´odban a legkisebb helyi´ert´ek˝u byte (LSB) t´arol´odik el˝osz¨or. Ezzel szemben a “Big-endian” t´arol´asi m´odban a legnagyobb helyi´ert´ek˝u byte (MSB) t´arol´odik legel˝osz¨or. N´ezz¨unk egy m´asik p´eld´at a “Little-endian” t´arol´asi m´odra. Az 1234h hexadecim´alis sz´am eset´en el˝osz¨or a 34h, majd a 12h byte-ot t´arolja a rendszer. Az 12345678h sz´am eset´en a t´arol´asi sorrend: 78h, 56h, 34h, 12h. Melyik t´arol´asi m´odszer a jobb? Mindkett˝o ugyanolyan j´o. Csak a processzor tervez˝o d¨ont´ese, hogy melyiket haszn´alja. A Pentium processzorok a “Little-endian” t´arol´asi m´odot haszn´alj´ak. A MIPS e´ s PowerPC processzorokon a “Big-endian” t´arol´asi m´od az alap´ertelmezett, de a´ t lehet konfigur´alni o˝ ket ´ aban a k¨ul¨onb¨oz˝o t´arol´asi m´od nem okoz probl´em´at, ha mindig “Little-endian” t´arol´asi m´odra is. Altal´ csak egyf´ele processzort haszn´alunk. Az igazi probl´em´ak akkor jelennek meg, ha k¨ul¨onb¨oz˝o t´arol´asi m´odszert haszn´al´o processzorok k¨oz¨ott akarunk egy programot hordozni. Ebben az esetben az adatokat konvert´alni kell!
24
MSB LSB 11110100 10011000 10110111 00001111
cím 103 102 101 100
cím
11110100 10011000 10110111 00001111
103 102 101 100
Little-endian
00001111 10110111 10011000 11110100 Big-endian
2.5. a´ bra: “Little-endian” e´ s “Big-endian” t´arol´asi m´od
2.5.6 Adat “alignment” problema Egy program v´egrehajt´asi sebess´eg´et t¨obb t´enyez˝o is befoly´asolja. A t´enyez˝ok k¨oz¨ul n´eh´any a programoz´o befoly´asa alatt van, m´ıg m´asokat nem tudnak befoly´asolni. Ebben a fejezetben az egyik fontos t´enyez˝ot vizsg´aljuk meg. Tegy¨uk fel, hogy egy 32 bites adatot szeretn´enk olvasni a mem´ori´ab´ol. Azt is tegy¨uk fel, hogy az adat busz szint´en 32 bites. Ha az olvasni k´ıv´ant adat c´ıme n´eggyel oszthat´o, akkor a mem´ori´aban pont u´ gy van elhelyezve, hogy egy sorba esik. Ez l´athat´o a 2.6. a´ br´an e´ s ezt szoktuk illesztett, “aligned” adatnak nevezni. Mivel az adatbusz 32 bites, ez´ert egyszerre 4 byte-ot, egy sort lehet beolvasni a mem´ori´ab´ol. Ez azt jelenti, hogy ha a c´ım nem oszthat´o n´eggyel, akkor az adat k´et sorba ker¨ul e´ s k´etszer kell olvasni a mem´ori´ab´ol, majd ezekb˝ol fogja a processzor o¨ ssze´all´ıtani a sz¨uks´eges 32 bites adatot. A k´etszeri olvas´asnak hat´asa van a program fut´as´ara, mivel a nem illesztett adatok miatt lassabban fog futni! n+3 k+2 24-31 n+2 k+1 16-23 n+1
8-15
k
0-7 n+0
CPU
adatbusz 32 bit
k+3
memória adat1 adat2
2.6. a´ bra: Adat illeszt´es - “data alignment”
Az adat illeszt´es probl´em´aja teljesen transzparans m´odon, vagyis nem jelenik meg a felhaszn´al´o sz´am´ara, kiv´eve, hogy a program lassabban fut. A 16 bites adatokat 2 byte-ra kell illeszteni. Ez azt
25
Cím busz Adat
Adat busz
Státusz Parancs
Kontroll busz
I/O eszköz
I/O kontroller
2.7. a´ bra: Input/Output eszk¨oz sematikus a´ br´aja
jelenti, hogy a c´ım legkisebb helyi´ert´ek˝u bite z´erus, vagyis a c´ım p´aros. A 32 bites adatokat 4 byte-ra ´ ´ıgy tov´abb. A Pentium processzorok kell illeszteni vagyis a c´ım k´et legkisebb helyi´ert´ek˝u bite z´erus. Es megengedik az illesztett (“aligned”) e´ s nem illesztett adatt´arol´ast is. Bizonyos processzorok az el˝obb le´ırt hat´ekonys´agi probl´ema miatt nem engedik meg, hogy az adat ne legyen illeszteve.
2.6 Input/Output Az Input/Output eszk¨oz¨ok teszik lehet˝ov´e, hogy a sz´am´ıt´og´epek kommunik´aljanak a “k¨ulvil´aggal”. Input/Output eszk¨oz lehet hogy csak adatszolg´altat´asra alkalmas, input-ra, p´eld´aul az eg´er, vagy csak output-ra k´epes, p´eld´aul a monitor, vagy input-ra e´ s output-ra is k´epes. ´Igy l´enyeg´eben az I/O eszk¨oz¨oknek k´et f˝o c´elja van, a k¨ulvil´aggal kommunik´alni e´ s adatot t´arolni. Mindegyik kommunik´aci´o a rendszer buszon kereszt¨ul t¨ort´enik, b´ar az I/O eszk¨oz¨ok nem k¨ozvetlen¨ul kapcsol´odnak a buszhoz, hanem van egy I/O kontroller az eszk¨oz e´ s a rendszer busz k¨oz¨ott, ahogy ez 2.7. a´ br´an l´athat´o. K´et fontos ok miatt van sz¨uks´eg ezekre az I/O kontrollerekre: 1. A k¨ul¨onb¨oz˝o I/O eszk¨oz¨oket k¨ul¨onb¨oz˝o m´odon kell kezelni. Ez azt jelenti, hogy a k¨ul¨onb¨oz˝o eszk¨oz¨okkel k¨ul¨onb¨oz˝o m´odon kell kommunik´alni, n´eha v´arni kell az adat meg´erkez´es´ere vagy vez´erl˝o jeleket kell adni. Ha a processzornak kellen mind ezt a feladatot ell´atni, akkor t¨obb id˝ot t¨oltene ezzel, mint a felhaszn´al´o kiszolg´al´as´aval, vagyis a programok futtat´as´aval. Az I/O eszk¨oz kontroller elv´egzi a processzor helyett ezeket a feladatokat. 2. A m´asik ok, hogy a rendszer buszon kereszt¨ul k¨uld¨ott elektromos jel igen alacsony, ami azt is jelenti, hogy a rendszer busz nem lehet t´ul hossz´u. Emiatt az I/O eszk¨oz kontrollerek k¨ozel vannak a processzorhoz, p´eld´aul a sz´am´ıt´og´ep h´azban, e´ s majd a kontroller tud k¨ul¨on, er˝osebb jelet k¨uldeni az eszk¨oznek. Az 2.7. a´ bra azt is mutatja, hogy az I/O eszk¨oz kontrollerekben a´ ltal´aban h´arom regiszter is van. P´eld´aul egy nyomtat´o eset´en a “St´atusz regiszter” jelzi, hogy az eszk¨oz k´eszen a´ ll-e, az “Adat regiszterbe” kell tenni a nyomtatand´o karaktert e´ s a “Parancs regiszterben” kell utas´ıt´ast adni az eszk¨oznek, hogy nyomtassa ki a karaktert. A processzor I/O portokon kereszt¨ul e´ ri el ezekete a regisztereket. Az I/O port nem m´as mint az I/O eszk¨oz¨on lev˝o regiszter c´ıme. Az I/O portok lehetnek a mem´ori´ara illesztettek, memory-mapped I/O. Ilyen rendszer p´eld´aul a MIPS processzorban van. A Pentium processzorok egy I/O c´ım tartom´anyt haszn´alnak. Ez a c´ım tartom´any k¨ul¨onb¨ozik a mem´oria c´ım tartom´any´at´ol. Ebben az esetben k¨ul¨on I/O utas´ıt´asokat kell haszn´alni. Ugyanakkor ez az ut´obbi technika a mem´ori´ara illesztett I/O-t is lehet˝o teszi. K´es˝obb l´atni fogjuk, hogy p´eld´aul a k´eperny˝o a mem´ori´ara illeszthet˝o e´ s u´ gy is ´ırhatunk a k´eperny˝ore, hogy egy speci´alis mem´oria ter¨uletre ´ırunk. Ezzel szemben a billenty˝uzettel lehet I/O utas´ıt´asokkal is kommunik´alni.
26
2.6.1 I/O eszk¨oz¨ok el´er´ese Amikor assembly-ben programozunk k¨ozvetlen¨ul vez´erelhetj¨uk az I/O eszk¨oz¨oket. B´ar erre lehet˝os´eg¨unk van, de le´ır´asok e´ s seg´ıts´eg n´elk¨ul gyakran nagyon bonyolult lehet, illetve minden esetben saj´at input e´ s output f¨uggv´enyeket kellene kifejleszten¨unk. Ezenk´ıv¨ul, ha mindenkinek teljesen szabad hozz´af´er´ese van az I/O eszk¨oz¨okh¨oz, akkor rosszindulat´u emberek ezt ki is haszn´alhatj´ak. Ez´ert van az, hogy a´ ltal´aban az oper´aci´os rendszer kontroll´alja az eszk¨oz¨okh¨oz val´o hozz´af´er´est, illetve biztos´ıtja a rutinokat is amiket haszn´alhatunk. A rutinok a´ ltal´aban valamilyen megszak´ıt´ast haszn´alnak. A megszak´ıt´asokat a 8.2. bekezd´esben t´argyaljuk.
¨ 2.7 Osszefoglal´ as Ebben a fejezetben a sz´am´ıt´og´ep alapvet˝o elemeit ismert¨uk meg olyan m´elys´egben amire sz¨uks´eg¨unk lehet az assembly programoz´as sor´an. Ezek az ismeretek lehetnek u´ jak, illetve bizonyos fogalmak el˝ofordulhattak m´as t´argyak keret´eben.
2.8 Ellen˝orz˝o k´erd´esek 1. Milyen r´eszekb˝ol a´ ll egy sematikus sz´am´ıt´og´ep? 2. Mi a fetch-decode-execute ciklus? Melyik l´ep´esben, mi t¨ort´enik? 3. A rendszer busz milyen f˝o r´eszekb˝ol a´ ll? Melyiknek mi a szerepe? 4. Ha a processzornak 64 c´ım vonala van, mekkora lehet maxim´alisan a mem´oria m´erete? Mi az utols´o byte c´ıme? 5. Mi hat´arozza meg, hogy a mem´oria e´ s a processzor k¨oz¨ott adatok m´erete mekkora? 6. Egy 2GH-es processzorban mekkora egy o´ ra jel ciklus? 7. Miben k¨ul¨onb¨ozik a “load/store” architekt´ura a t¨obbi architekt´ur´at´ol? 8. Adjon magyar´azatot arra hogy a RISC processzorokon az utas´ıt´asok egym´as ut´ani v´egrehajt´asa mi´ert lehet gyorsabb mint a CISC processzorokon! 9. Mit jelent a h´arom c´ımes architekt´ura? 10. Miben k¨ul¨onb¨ozik a h´arom e´ s k´et c´ımes architekt´ura? 11. Hogyan lehet olyan architekt´ur´at megval´os´ıtani, amelyikben az utas´ıt´asoknak nem kell argumentumot megadni? 12. Adja meg a k¨ovetkez˝o matematikai m˝uveleteket pszeudo assembly-ben k´et c´ımes architekt´ura eset´en: E = A * B + C - D 13. A RISC vagy a CISC processzorokra jellemz˝o a nagy sz´am´u regiszter? Melyik c´ımz´esi architekt´ura eset´en van sz¨uks´eg erre a nagysz´am´u regiszterre? 14. A Pentium processzor a RISC vagy CISC processzorok csal´adj´aba tartozik? 15. A MIPS processzor a RISC vagy CISC processzorok csal´adj´aba tartozik? 16. Hogyan lehet megval´os´ıtani a felt´eteles ugr´o utas´ıt´ast k¨ul¨onb¨oz˝o architekt´ur´akon? 17. Mi a PC regiszter szerepe a felt´eteles ugr´o utas´ıt´as v´egrehajt´asa sor´an?
27
18. Hogyan n´ez ki a mem´oria sematikus k´epe? Jel¨olje a minimum e´ s maximum indexet 16 bites adatbusz eset´en. 19. Mi jellemzi a ROM mem´ori´akat? 20. Mi a k¨ul¨onbs´eg a statik e´ s dinamikus RAM-ok k¨oz¨ott? 21. Mi a DRAM m˝uk¨od´es´enek alapelve? Mi´ert dinamikus mem´oria? 22. Mi´ert kell friss´ıteni a DRAM mem´ori´at? 23. Mi a k¨ul¨onbs´eg a “volatile” e´ s “nonvolatile” mem´oria k¨oz¨ott? 24. Mit jelent a “little-endian” t´arol´asi m´od? 25. Hogyan t´arol´odik a 44443333h hexadecim´alis sz´am a “big-endian” t´arol´asi m´oddal? 26. Milyen t´arol´asi m´odot haszn´al a Pentium processzor? 27. Mit jelent az adat “alignment”? 28. Mi´ert van hat´assal a nem illesztett adat t´arol´as a programok sebess´eg´ere? 29. Mi´ert van sz¨uks´eg I/O kontrollerre? 30. A processzor milyen m´odokon kommunik´alhat az I/O kontrollerrel?
28
3. Fejezet
A processzor Az Intel c´eg 1969-ben vezette be az els˝o processzor´at, a 4004 processzort. Ezt k¨ovette a 8080 e´ s 8085 processzorok. Ezek a processzorok vezettek az Intel Architekt´ura (IA) kidolgoz´as´ahoz, a 8086os processzorhoz, 1979-ben. A 8086 processzornak 20 bites c´ım busza e´ s 16 bites adatbusza van. A k¨ovetkez˝o gener´aci´o a 80186 processzor volt, melyben u´ jabb utas´ıt´asokat vezettek be, de a c´ım e´ s adat busz m´erete v´altozatlan maradt. Mivel ezt a processzort nem igaz´an haszn´alt´ak, ´ıgy az igazi k¨ovetkez˝o gener´aci´os processzor a 8086 ut´an a 80286 processzor volt. A 80286 processzornak 24 bites c´ım busza van, amivel 16 MByte mem´ori´at lehet megc´ımezni. Ugyanakkor az adatbusz megmaradt 16 bites. A m´asik u´ j´ıt´as a v´edett m´od (protected mode) bevezet´ese volt. Az Intel c´eg els˝o igazi 32 bites processzora a 80386-os processzor volt, melynek 32 bites c´ım e´ s adat busza van. Ezzel a processzorral 4GByte mem´ori´at lehet megc´ımezni, r´aad´asul ak´ar egyben, ami lehet˝ov´e tette a “flat” m´odot. A 80486 processzor 1989-ben jelent meg. A processzorba be´ep¨ult a matematikai ko-processzor, egy 8KB-os L1-es cache is ker¨ult a hardware-be, t´amogatta az L2 cache-t is e´ s lehet˝ov´e v´alt a p´arhuzamos futtat´as. A Pentium processzorok a “leg´ujabbak” az Intel-t˝ol, b´ar itt a Pentium nevet mint a processzorok egy csal´adj´anak a nevek´ent haszn´aljuk. Az els˝o Pentium processzort 1983-ban mutatt´ak be. Az´ota megjelentek a Pentium Pro, Pentium II, Pentium III e´ s Pentium 4 processzorok. A processzorokr´ol ad a´ ttekint´est a 3.1. t´abl´azat. A hagyom´anyos Intel architekt´ur´at´ol jelent˝osen elt´er az Itanium processzor, mely RISC alap´u, elt´er˝oen az Intel m´as processzorait´ol, e´ s m´as u´ j´ıt´asokat is tartalmaz. Ugyanakkor, ma (2009. szeptember) m´ar kijelenthetj¨uk, hogy ez a processzor nem v´altotta be a hozz´a f˝uz¨ott rem´enyeket e´ s nem terjedt el olyan m´ert´ekben a sz´am´ıt´og´epes piacon, hogy jelent˝os szerepl˝oje legyen.
Processzor
´ Ev
8086 80286 80386 80486 Pentium Pentium Pro Pentium II Pentium III Pentium 4
1979 1982 1985 1989 1993 1995 1997 1999 2000
Frekvencia (MHz) 8 12.5 20 25 60 200 266 500 1500
Regiszter m´eret 16 16 32 32 32 32 32 32 32
Adat busz m´eret 16 16 32 32 64 64 64 64 64
3.1. t´abla: Processzorok a´ ttekint´ese
29
Maximum mem´oria 1 MB 16 MB 4 GB 4 GB 4 GB 64 GB 64 GB 64 GB 64 GB
´ 3.1 Altal´ anos regiszterek A 3.2. t´abl´azat tartalmazza a 8086-os processzor a´ ltal´anos c´el´u regisztereinek list´aj´at. A t´abl´azatban az is l´athat´o, hogy a 16 bites regiszterek k¨oz¨ul melyeket lehet 8 bites “darabokban”, regiszterekk´ent haszn´alni. Fontos megjegyezni, hogy 8 bites regiszterek eset´en az egyik regiszter e´ rt´ek´enek megv´altoztat´asa nincs hat´assal a regiszter t¨obbi r´esz´ere. P´eld´aul ha az AL regiszter r´esznek e´ rt´eket adunk att´ol m´eg az AH regiszter r´esz nem fog megv´altozni! Speci´alis regiszter az IP vagy instruction pointer regiszter, mely a k¨ovetkez˝o v´egrehajtand´o utas´ıt´asra mutat. Ezt a regisztert kontroll regiszternek is szoktuk nevezni. V´eg¨ul a szegmens regiszterek list´aj´at a 3.3. t´abl´azat tartalmazza. Ezek a regiszterek t´amogatj´ak a szegment´alt mem´oria kezel´es´et. N´ev Akkumul´ator B´azis Sz´aml´al´o Adat Forr´as index C´el index B´azis pointer Stack pointer
Teljes regiszterek 0-15 bit AX BX CX DX SI DI BP SP
8-15 bit AH BH CH DH
0-7 bit AL BL CL DL
´ anos c´el´u regiszterek 3.2. t´abla: Altal´
N´ev K´od szegmens Data szegmens Extra szegmens Stack szegmens
Regiszterek 0-15 bit CS DS ES SS
3.3. t´abla: Szegmens regiszterek
3.2 Szegment´alt c´ımz´es el˝osz¨or Ebben a fejezetben csak az u´ gynevezett val´os m´od´u mem´oria architekt´ur´at (real-mode memory architecture) t´argyaljuk, mely a 8086-os processzorra jellemz˝o. A processzor 1MB mem´ori´at tud megc´ımezni. A mem´oria megc´ımz´es´ehez 20 bites e´ rt´ekre van sz¨uks´eg. Az els˝o mem´oria hely c´ıme: 00000h, m´ıg az utols´o mem´oria hely c´ıme: FFFFFh. Mivel minden regiszter 16 bites a 8086 processzorban, ez´ert az ´ıgy megc´ımezhet˝o mem´oria m´erete korl´atozott: 216 vagy 65536 byte. Ennek k¨ovetkezt´eben a mem´ori´at szegmensekre kell osztani, melyek m´erete 65536 byte. ´Igy, ebben a szegment´alt mem´ori´aban meg kell adni egy szegmens b´azis c´ımet e´ s egy offszetet. Ez a k´et e´ rt´ek adja meg a logikai c´ımet. A szegmens b´azis c´ım adja meg, hogy a szegmens hol kezd˝odik a mem´ori´an bel¨ul, m´ıg az offszet a szegmensen bel¨uli helyet adja meg. A 3.1. a´ bra a fizikai mem´oria c´ımek e´ s a szegment´alt, logikai c´ımz´es k¨oz¨otti kapcsolatot mutatja. Amint l´athat´o, a szegmens fizikai c´ıme 20 bites (12000h). Hogyan lehet 20 bites c´ımet t´arolni 16 bites regiszterekben? A v´alasz az, hogy sehogy, e´ s egy tr¨ukk¨ot kell alkalmazni. A l´enyeg, hogy a szegmens regiszter a 20 bites c´ımb˝ol a 16 legnagyobb helyi´ert´ek˝u bitet t´arolja (most significant bit) e´ s felt´etelezz¨uk,
30
fizikai cím
12345 offszet (345) szegmens bázis (1200)
12000
3.1. a´ bra: Kapcsolat a fizikai e´ s logikai c´ımek k¨oz¨ott hogy az utols´o 4 bit z´erus, amit nem kell t´arolni. Ez persze azt is jelenti, hogy a szegmensek fizikai c´ıme csak olyan lehet, aminek a 4 legkisebb helyi´ert´ek˝u bite z´erus lesz, vagyis: 00000h, 00010h, 00020h, 00030h, ... FFFE0h, FFFF0h. A szegmensen bel¨uli mem´oria helyet az offszet adja meg. A programoz´onak csak a logikai c´ımz´essel, vagyis a szegmens:offszet p´arral kell foglalkoznia, ami automatikusan konvert´al´odik 20 bites fizikai c´ımm´e, ahogy ez a 3.2. a´ br´an l´athat´o. L´enyeg´eben a szegmens regiszter tartalm´ahoz jobbr´ol hozz´ailleszt¨unk n´egy darab z´erus bitet, majd ehhez az e´ rt´ekhez hozz´aadjuk az offszet e´ rt´ek´et. Ha hexadecim´alis sz´amrendszerben dolgozunk, akkor a szegmens regiszter tartalm´ahoz egy null´at kell hozz´a´ırni e´ s ehhez kell az offszet e´ rt´ek´et hozz´aadni. N´ezz¨unk egy p´eld´at, ahol a logikai c´ım hexadecim´alis sz´amrendszerben: 1200:0345 e´ s ´ıgy a fizikai c´ım: 12345, mivel: 1
2
1
2
+
0 3 3
0 4 4
0 5 5
Minden logikai c´ımhez tartozik egyetlen fizikai c´ım. Ugyanakkor a ford´ıtottja nem igaz, vagyis egy fizikai c´ımhez t¨obb logikai c´ım is tartozhat. P´eld´aul a 1200:0345 e´ s 1000:2345 logikai c´ımek ugyanazt a fizikai c´ımet adj´ak meg. A logikai c´ım t´arol´as´ahoz teh´at kell egy szegmens regiszter e´ s egy offszet regiszter. A szegmens regisztereket a 3.3. t´abl´azat sorolta fel. Ezek a regiszterek teljesen f¨uggetlenek egym´ast´ol e´ s a megc´ımzett szegmensek lehetnek szomsz´edosak, a´ tfed˝ok, ugyanazok illetve egym´ast´ol t´avoli mem´oria tartom´anyok, ahogy ezt a 3.3. a´ bra is mutatja. Offszet regiszterk´ent csak azok a regiszterek haszn´alhat´ok, melyeket a c´ımz´esben lehet haszn´alni: BX, BP, SP, SI, DI.
3.3 C´ımz´esi m´odok A CISC processzorok nagy sz´am´u c´ımz´esi m´odot t´amogatnak, szemben a RISC processzorokkal. A 8086-os processzor, mint egy CISC t´ıpus´u processzor, h´arom f˝o c´ımz´esi m´odot t´amogat: 1. Regiszter m´od: Ebben az esetben regiszterek adj´ak az utas´ıt´as a bemeneti param´eter´et e´ s az
31
19 szegmens regiszter
0 4 3 0000
19 16 15 0000
0 offszet regiszter
Összeadó
19
0 20 bites fizikai cím
3.2. a´ bra: Fizikai c´ım gener´al´asa 8086 processzoron
3.3. a´ bra: A szegmensek egym´ashoz val´o viszonya eredm´enyt is regiszterben t´aroljuk. P´eld´aul: MOV AX, BX. Ez a leghat´ekonyabb c´ımz´esi m´od, mivel az adat a processzoron bel¨ul marad, nincs sz¨uks´eg mem´oria m˝uveletre. 2. K¨ozvetlen m´od: Ebben az esetben az adat az utas´ıt´as r´esze e´ s b´ar az adat a mem´ori´aban van, de a k´od szegmensben, nem az adat szegmensben. Az adat mindig egy konstans sz´am e´ s csak forr´as lehet, vagyis a k¨ozvetlen¨ul megadott sz´amot t´aroljuk, vagy manipul´aljuk az utas´ıt´assal. Az utas´ıt´as m´asik operandusa mindig valamilyen m´as t´ıpus´u, c´ımz´es˝u kell legyen, p´eld´aul regiszter. P´eld´aul: MOV AX, 1234h 3. Mem´oria m´od: Amikor az egyik operandus a mem´ori´ara hivatkozik, akkor t¨obb c´ımz´esi lehet˝os´eg¨unk is van. Itt e´ rdemes az el˝oz˝o bekezd´esre eml´ekezni, hogy egy szegmens e´ s egy offszet c´ım komponenst kell megadni a v´egs˝o, fizikai c´ımhez. A szegmens r´eszt vagy explicit m´odon adjuk meg, vagy a haszn´alt regiszterek e´ s kontextus hat´arozza meg az egyik szegmens regisztert. A k¨ul¨onb¨oz˝o c´ımz´esi m´odok csak az offszet form´ait adja meg. A c´ımz´esi m´odok form´ait a 3.4. t´abl´azat foglalja o¨ ssze. Ezekben az esetekben az adat mindig az adat szegmensben van e´ s a hozz´af´er´es lassabb mint az el˝oz˝o k´et esetben. Mem´oria c´ımz´esre csak a BX, BP, SP, SI, DI regiszterek haszn´alhat´ok. A BP e´ s SP regiszter eset´en az SS szegmens regisztert felt´etelezz¨uk, m´ıg a t¨obbi regiszter eset´en (BX, SI, DI) a DS szegmens reg-
32
Direkt Regiszter [disp]
[BX] [BP] [SI] [DI]
C´ımz´esi m´od Indirekt B´azisrelat´ıv Indexelt [BX+disp] [BP+disp]
[SI+disp] [DI+disp]
B´azisrelat´ıv indexelt eltol´as n´elk¨ul eltol´assal [BX+SI] [BX+SI+disp] [BX+DI] [BX+DI+disp] [BP+SI] [BP+SI+disp] [BP+DI] [BP+DI+disp]
3.4. t´abla: C´ımz´esi m´odok Szegmens regiszter DS DS SS DS DS DS DS SS SS
Offszet [disp] [BX+disp] [BP+disp] [DI+disp] [SI+disp] [BX+SI+disp] [BX+DI+disp] [BP+SI+disp] [BP+DI+disp]
C´ımz´esi p´elda [DS:4423] [DS:BX+3] [SS:BP+5512] [DS:DI+6201] [DS:SI+18] [DS:BX+SI+35] [DS:BX+DI+43] [SS:BP+SI+12] [SS:BP+dI+22]
3.5. t´abla: C´ımz´esi m´od p´eld´ak
isztert felt´etelezz¨uk a c´ımz´esn´el, ha nincs szegmens regiszter megadva az utas´ıt´asban. Term´eszetesen a szegmens regiszter explicit m´odon is megadhat´o, ´ıgy p´eld´aul a BX regiszterrel az ES szegmens regiszter is haszn´alhat´o. C´ımz´esi p´eld´akat a 3.5. t´abl´azat tartalmaz.
3.3.1 Direkt c´ımz´esi m´od Ez az egyik legegyszer˝ubb c´ımz´esi m´od. Az adat az adat szegmensben tal´alhat´o e´ s a´ ltal´aban elegend˝o az offszetet megadni. Ilyenkor automatikusan a DS regisztert felt´etelezhetj¨uk. Term´eszetesen explicit m´odon el˝o is ´ırhatjuk a szegmens regisztert. M´ıg a v´egs˝o g´epi k´odban konkr´et sz´amnak, c´ımnek kell szerepelnie, assembly-ben lehet˝os´eg¨unk van szimb´olikus c´ımek haszn´alat´ara. Ha szimb´olikus c´ımet haszn´alunk az assembler majd kisz´amolja e´ s behelyettes´ıti a konkr´et c´ımet a g´epi k´odba. Vegy¨uk a k¨ovetkez˝o adat defin´ıci´okat a 4.2.1. fejezet alapj´an: valasz tabla1 nev1
DB ’i’ DB 0, 0, 0, 0, 0 DB ’Jim Doe’
majd n´ezz¨unk n´eh´any p´eld´at ezeknek az adatoknak a direkt c´ımz´es´ere: MOV MOV MOV MOV
AL, [valasz] [valasz], ’n’ [nev1], ’K’ [tabla1], 32
; ; ; ;
AL-be az ’i’ karakter ırjuk ’n’ karakterrel valasz-t felul´ Ezut´ an ’Kim Doe’ lesz a n´ ev az els} o t´ arolt ´ ert´ ek 32 lesz
Nagyon fontos, hogy a sz¨ogletes z´ar´ojelet haszn´aljuk, ha mag´at az adatot akarjuk bet¨olteni vagy ki´ırni. Hasonl´ıtsuk o¨ ssze az al´abbi k´et utas´ıt´ast: MOV BX, [tabla1] MOV BX, tabla1
33
Az els˝o utas´ıt´as a ‘tabla1’ c´ımen tal´alhat´o 16 bites, word e´ rt´eket t¨olti be a BX regiszterbe. A m´asodik utas´ıt´asban a ‘tabla1’ c´ım´et t¨oltj¨uk be a BX regiszterbe! Ez ut´obbi jel¨ol´esre p´eld´aul az indirekt c´ımz´esn´el van sz¨uks´eg¨unk.
3.3.2 Indirekt c´ımz´esi m´od A direkt c´ımz´esi m´odot az egyszer˝us´ege folyt´an legink´abb arra haszn´aljuk, hogy egy-egy v´altoz´ot k¨ozvetlen¨ul olvassunk vagy ´ırjunk. Ugyanakkor arra m´ar nem alkalmas, hogy egy t¨omb n-edik elem´et m´odos´ıtsuk,1 erre ink´abb az indirekt c´ımz´es alkalmas. Az indirekt c´ımz´es sor´an valamelyik c´ım regisztert haszn´aljuk arra, hogy p´eld´aul egy t¨omb c´ımet a regiszterbe t¨otlts¨uk, majd a regiszter m´odos´ıt´as´aval a t¨omb k¨ul¨onb¨oz˝o elemeit el´erj¨uk. Vegy¨uk azt a p´eld´at amelyben egy 10 elem˝u t¨omb elemit e´ rj¨uk el: tomb DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; | ; [BX+4] ... MOV BX, tomb MOV [BX], byte 11 ; tomb[0] = 11 ADD BX, 4 MOV [BX], byte 66 ; tomb[4] = 66 Fontos megjegyezni, hogy az adat m´eret´et is figyelembe kell venni a c´ımz´es sor´an. A fenti p´eld´aban 10 darab byte adatot kezelt¨unk, m´ıg a k¨ovetkez˝o p´eld´aban word m´eret˝u adatokat haszn´alunk: tomb DW 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; | ; [BX+4] ... MOV BX, tomb MOV [BX], word 11 ; tomb[0] = 11 ADD BX, 4 MOV [BX], word 66 ; tomb[2] = 66 Enn´el a p´eld´an´al arra e´ rdemes eml´ekezni, hogy egy word adat k´et byte-b´ol a´ ll, e´ s a BX regiszterhez n´egyet hozz´aadva a BX a´ ltal mutatott c´ımet n´egy byte-al toljuk el. A k´et p´elda k¨oz¨otti k¨ul¨onbs´eget a 3.4. a´ bra mutatja. Az a´ br´an nem v´eletlen a 66 00 adat, mivel b´ar a programban csak 66 szerepel, de ez word m´eret˝u adatk´ent 0066 lesz, amit viszont az Intel processzorok a “Little endian” m´odon t´arolnak. Az indirekt c´ımz´eshez sz¨uks´eges c´ımet m´ask´eppen is bet¨olthetj¨uk a regiszterbe: MOV BX, tomb helyett LEA BX, [tomb] A f˝o k¨ul¨onbs´eg az, hogy az els˝o esetben a c´ımet az assembler a g´epi k´od gener´al´asa k¨ozben sz´amolja ki addig a m´asodik esetben a c´ımet fut´asi id˝oben hat´arozza meg a rendszer. B´ar ebben az esetben nincs k¨ozvetlen el˝onye, de o¨ sszetettebb c´ımz´es eset´en m´ar igen, p´eld´aul: MOV BX, tomb ADD BX, SI 1 Hacsak
nincs minden elemnek a t¨ombben saj´at neve.
34
tomb[4]
tomb[0] 0 1 byte
2 3
11
4 5 ... 66
tomb[0] tomb[1] tomb[2] 0 1 word
2 3
11 00
4 5 ... 66 00
3.4. a´ bra: Byte e´ s word m´eret˝u t¨omb¨ok k¨oz¨otti k¨ul¨onbs´eg helyett LEA BX, [tomb+SI] lehet haszn´alni.
3.4 St´atusz regiszter A st´atusz regiszter 16 bitb˝ol a´ ll. Ebb˝ol a 16 bitb˝ol kilencet haszn´al a 8086-os processzor. A tov´abbi 7 bit nincs defini´alva illetve nem haszn´alja a processzor. A st´atusz bitek f¨uggetlenek egym´ast´ol e´ s term´eszetesen az e´ rt´ek¨uk csak 1 vagy 0 lehet. A st´atusz bitek alapvet˝oen jelz´esek. L´enyeg´eben e´ rtes´ıtik a programoz´ot hogy a processzor valamilyen a´ llapotban van ´ıgy a program reag´alni tud ezekre az a´ llapotokra. Minden st´atusz bitnek k¨ul¨on jelent´ese van e´ s k¨ul¨on k´et bet˝us szimb´olummal jel¨olj¨uk o˝ ket. A 3.6. t´abl´azat mutatja a bitek jel¨ol´es´et. ´ eke 1 ha az utols´o eredm´eny az el˝ojeles sz´am a´ br´azol´asi tartom´anyon k´ıv¨ulre OF : Overflow bit. Ert´ esik. Minden m´as esetben az e´ rt´eke nulla. DF : Direction bit. Ez egy furcsa st´atusz bit, mivel ebben az esetben nem a processzor jelez a programoz´onak, hanem ford´ıtva, a programoz´o jelez a processzornak. Ez a bit adja meg hogy string m˝uveletek sor´an a c´ımek n¨ovekedjenek vagy cs¨okkenjenek. Amikor a bit e´ rt´eke 1, akkor a string m˝uveletek sor´an a c´ımek cs¨okkennek, ha a bit e´ rt´eke 0, akkor pedig cs¨okkennek a c´ımek. Ezt a bitet m´eg u´ jra megvizsg´aljuk a 7.6. fejezetben. IF : Interrupt enable bit. Ez egy k´et ir´any´u st´atusz bit, vagyis nem csak a processzor jelezhet egy a´ llapotot, hanem mi is k´epesek vagyunk jelezni a processzornak. Amikor ennek a bitnek az e´ rt´eke 1, akkor a megszak´ıt´asok enged´elyezettek e´ s b´armikor bek¨ovetkezhetnek. Ha a bit e´ rt´eke z´erus akkor CPU nem veszi figyelembe a megszak´ıt´asokat. TF : Trap bit. Ennek a bitnek a seg´ıts´eg´evel lehet programokat l´ep´esenk´ent v´egrehajtani. Ha be van a´ ll´ıtva (´ert´eke 1), akkor a processzor egy utas´ıt´ast hajt v´egre majd megh´ıv egy megszak´ıt´ast. ´ anos esetben a programoz´ok nem haszn´alj´ak, de p´eld´aul a DEBUG programn´al elengedAltal´ hetetlen. ´ eke 1 ha az utols´o eredm´enyben a legmagasabb helyi´ert´ek˝u bit e´ rt´eke 1, vagyis SF : Overflow bit. Ert´ negat´ıv sz´am az eredm´eny. Ha az eredm´eny pozit´ıv sz´am, akkor a legmagasabb helyi´ert´ek˝u bit e´ rt´eke z´erus e´ s a ez a bit is z´erus lesz. ´ eke 1 ha az utols´o eredm´eny z´erus volt. Ha az utols´o eredm´eny b´armilyen z´erust´ol ZF : Z´erus bit. Ert´ k¨ul¨onb¨oz˝o e´ rt´ek˝u, akkor ennek a bitnek az e´ rt´eke z´erus.
35
15
14
13
12
11 OF
10 DF
9 IF
8 TF
7 SF
6 ZF
5
4 AF
3
2 PF
1
0 CF
3.6. t´abla: St´atusz regiszter bitjei
AF : Auxiliary bit. Ezt a bitet csak a BCD aritmetika sor´an haszn´aljuk. A BCD aritmetik´at a 8.7.1. fejezetben t´argyaljuk. PF : Parity (parit´as) bit. Ez a bit azt jelzi, hogy az utols´o m˝uvelet eredm´eny´eben (mint bin´aris sz´amban) h´any darab 1-es bit van. P´eld´aul a 0F2h hexadecim´alis sz´am bin´arisan 1111 0010 amiben p´aratlan sz´am´u 1-es van e´ s ´ıgy a parit´as bit e´ rt´eke z´erus lesz. A 03Ah bin´arisan 0011 1100 e´ s mivel p´aros sz´am´u 1-es tal´alhat´o az eredm´enyben ´ıgy a parit´as bit e´ rt´eke egy lesz. Ez bit tulajdonk´eppen abb´ol az id˝ob˝ol sz´armazik, amikor m´eg minden kommunik´aci´o soros porton kereszt¨ul zajlott. A soros kommunik´aci´o eset´en a hiba e´ rz´ekel´es´enek egyik m´odja volt, hogy a k¨uld´es el˝ott meg´allap´ıtjuk az adat parit´as´at, majd a´ tk¨uldj¨uk az adatot e´ s a parit´as bitet. A “t´uloldalra” meg´erkezett adatot a parit´as bittel lehet ellen˝orizni. ´ eke 1 ha az utols´o eredm´eny az el˝ojel n´elkuli CF : Carry bit. Ert´ ¨ sz´am a´ br´azol´asi tartom´anyon k´ıv¨ulre esik. P´eld´aul ha egy aritmetikai vagy shift m˝uvelet sor´an egy 9. vagy 17. bit is keletkezik, akkor ennek a bitnek az e´ rt´eke 1 lesz. Minden m´as esetben az e´ rt´eke nulla. P´elda a 8.7. fejezetben l´athat´o.
3.5 Ellen˝orz˝o k´erd´esek 1. Mi a szegmens? Mi´ert kell a Pentium processzorokon szegment´alt mem´oria architekt´ur´at haszn´alni? 2. Val´os m´odban mi´ert 64KByte m´eret˝u egy szegmens? 3. Val´os m´odban egy szegmens nem kezd˝odhet b´arhol a mem´ori´aban. Mi´ert? 4. A 8086-os processzoron n´egy szegmens lehet egyszerre kezelni. Mi´ert? 5. Mutassa be a fizikai c´ım kisz´am´ıt´as´anak m´odj´at logikai c´ımb˝ol! 6. Konvert´alja az al´abbi logikai c´ımet fizikai c´ımm´e: 3911:0200, 3000:0333 7. Az IP regiszterhez, melyik szegmens regiszter tartozik? 8. Lehet-e a CS e´ s DS regiszter e´ rt´eke ugyanaz? 9. Lehet-e a ES regiszter e´ rt´eke: 1234h? 10. Melyik szegmens regiszter j´arul az SP regiszterhez? 11. Mire val´o a st´atusz regiszter? 12. Soroljon fel n´eh´any dolgot, hogy mit jelezhet a st´atusz regiszter! 13. Mi a k¨ul¨onbs´eg a sor orient´alt e´ s oszlop orient´alt t¨omb t´arol´asi m´odok k¨oz¨ott? 14. Adva van a k¨ovetkez˝o adat: tomb resb 12 t¨oltse ki a hi´anyz´o r´eszeket, hogy a 4. e´ s 5. elemet hasonl´ıtsuk o¨ ssze: MOV SI, ____ MOV AX, [tomb+SI] CMP AX, ____
36
4. Fejezet
NASM assembler 4.1 Egy forr´as file szerkezete Az assembly nyelvben, illetve a legt¨obb assembler alatt e´ s ´ıgy a NASM assembler alatt is, a forr´ask´odban a sor a k¨ovetkez˝o n´egyf´ele dolgot tartalmazhatja: es as operandus ; megjegyz´ ıt´ ımke: utas´ c´ A n´egyf´ele r´esz k¨oz¨ul a legt¨obb opcion´alis, hiszen egy sorban lehet csak megjegyz´es, csak c´ımke, ezek kombin´aci´oja, esetleg c´ımke e´ s utas´ıt´as e´ s ´ıgy tov´abb. Az operandus jelenl´ete mindig az utas´ıt´ast´ol f¨ugg. Ha a sor v´eg´en a ’backslash’ (\) karakter a´ ll, ez azt jelenti, hogy a k¨ovetkez˝o sor is az adott sorhoz tartozik, annak folytat´asa. A NASM assemblerben nincs semmilyen megk¨ot´es a SPACE-ek e´ s tabul´atorok haszn´alat´ara. Ezekb˝ol a karakterekb˝ol, a sor r´eszei k¨oz¨ott b´armennyit haszn´alhatunk. R´aa´ ad´asul a c´ımke ut´an a kett˝ospont is opcion´alis. Ez sajnos hib´akhoz vezethet! P´eld´aul, hab´ar a lodsb utas´ıt´ast szeretn´enk le´ırni egy sorba, de a lodab sz¨oveget ´ırtuk le, az assembler nem fog sz´olni mivel u´ gy tekint r´a mintha abban a sorban csak egy c´ımk´et defini´altunk volna. A NASM assemblernek van egy kapcsol´oja (-w+orphan-labels) melynek megad´asa eset´en az assembler sz´olni fog ha egy sorba, kett˝ospont n´elk¨ul, ´ırunk le egy c´ımet. A c´ımk´ekben haszn´alhat´o e´ rv´enyes karakterek a bet˝uk e´ s sz´amok, ‘_’, ‘$’, ‘#’, ‘@’, ‘˜’, ‘.’ e´ s ‘?’. A c´ımke els˝o karaktere bet˝u, ‘_’, ‘?’ vagy pont (.) lehet. Ha egy c´ımke ponttal kezd˝odik, annek sepci´alis jelent´ese van. A NASM assembler k´epes leford´ıtani a 8086, 386, 486, Pentium, P6, FPU e´ s MMX utas´ıt´ask´eszleteket. Az utas´ıt´asok el˝ott szerepelhet egy prefix: REP, REPE/REPZ, REPNE/REPNZ, LOCK. A szegmens regiszter is megadhat´o prefixk´ent: es mov [bx], ax ami egyen´ert´ek˝u azzal, hogy mov [es:bx], ax Az ut´obbi jel¨ol´es prefer´alt, mivel m´as szintaktikai elemekkel ez konzisztens. Ha nem adtunk meg prefixet, p´eld´aul nem adtunk meg szegmens regisztert, akkor a NASM automatikusan gener´alni fogja.
4.2 Pszeudo utas´ıt´asok A pszeudo utas´ıt´asok nem igazi processzor utas´ıt´asok, de egy forr´as sorban az ‘utas´ıt´as’ r´eszben szerepelhet.
37
4.2.1 DB e´ s t´arsai A DB, DW, DD, DQ, DT adatokat ad meg a forr´ask´odban. A f˝o k¨ul¨onbs´eg, hogy milyen m´eret˝u adatot/adatokat defini´alnak. DB : egy byte-ot vagy byte sorozatot defini´al. DW : egy word-ot vagy word sorozatot defini´al. Egy word k´et byte-b´ol a´ ll. Itt azt is figyelembe kell venni, hogy az Intel processzor ‘Little endian’ t´arol´asi m´odot haszn´al, vagyis a t´arol´as sor´an a byte-okat felcser´eli. DD : egy vagy t¨obb double word-ot defini´al. Egy double word 4 byte-b´ol a´ ll. Ez az adatm´eret haszn´alhat´o egyszeres precizit´as´u floating-point sz´amok (float) megad´as´ara is a matematikai koprocesszor sz´am´ara. DQ : egy vagy t¨obb quad word-ot defini´al. Egy quad word 8 byte-b´ol a´ ll. Ez az adatm´eret haszn´alhat´o dupla precizit´as´u floating-point sz´amok (double) megad´as´ara is a matematikai koprocesszor sz´am´ara. DT : egy vagy t¨obb ten byte-ot defini´al. Egy ten byte adat 10 byte-b´ol a´ ll. Az al´abbi lista t¨obb p´eld´at is mutat az adatok defini´al´as´ara: db db db db dw dw dw dw dd dd dq
0x55 0x55,0x56,0x57 ’a’,0x55 ’hello’,13,10,’$’ 0x1234 ’a’ ’ab’ ’abc’ 0x12345678 1.234567e20 1.234567e20
; ; ; ; ; ; ; ; ; ; ;
egy byte 0x55 3 bytes egym´ as ut´ an egy karakter ´ es egy byte keverve karakter sorozat ´ es sz´ amok keverve 0x34 0x12 0x41 0x00 0x41 0x42 0x41 0x42 0x43 0x00 0x78 0x56 0x34 0x12 floating-point konstans double-precision konstans
A fenti p´eld´aban e´ rdemes megfigyelni a 6. e´ s 8. sort. A 6. sorban u´ gy t˝unik, hogy csak egy karaktert defini´alunk, de mivel a sor elej´en a DW pszeudo utas´ıt´as szerepel, ami ‘word’ adatm´eretet, vagyis k´et byte-ot jelent. Ennek megfelel˝oen a leford´ıt´as ut´an val´oj´aban k´et byte-ot foglal le az assembler, amelyb˝ol az egyik z´erus lesz. A fenti p´eld´akb´ol az is l´athat´o, hogy a karakterek (ASCII k´odok) e´ s sz´amok szabadon keverhet˝ok. A karaktersorozatok t¨obbf´elek´eppen is megadhat´ok, egyszeres vagy dupla aposztrofok k¨oz¨ott, illetve egyben vagy karakterenk´ent: db ’hello’ db ’h’,’e’,’l’,’l’,’o’ db "hello"
4.2.2 RESB e´ s t´arsai A RESB, RESW, RESD, RESQ e´ s REST pszeudo utas´ıt´asok inicializ´al´as n´elk¨uli adatoknak foglal helyet. Az ‘inicializ´al´as n´elk¨uli adat’ azt jelenti, hogy csak az adat t´arol´as´ara sz¨uks´eges helyet foglalja le az assembler, de a helyen t´aroland´o adat b´armi lehet kezdetben. (Lehet z´erus vagy a mem´oria egy r´eszlete, b´armi.) Ezek a pszeudo utas´ıt´asok t¨obb adatnak foglalnak helyet, p´eld´aul: buffer: resb 64 wordvar: resw 1 db "hello"
; 64 byte-nyi helyet foglal ; 1 word-nyi helyet foglal
38
4.2.3 Konstansok Ugyan´ugy mint a legt¨obb programoz´asi nyelvben, p´eld´aul a C programoz´asi nyelvben, assembly-ben is lehet konstansokat defini´alni a forr´ask´odban. A konstansokat egy helyen defini´aljuk e´ s a programban mindenhol csak egy n´evvel, szimbolikusan hivatkozunk r´ajuk. Ezeknek a konstansoknak kett˝os lehet szerepe: • ha k´es˝obbi fejleszt´esek sor´an a konstans e´ rt´ek´et meg kellene v´altoztatni, akkor csak a defin´ıci´o hely´en kell megv´altoztatni az e´ rt´eket, hiszen a programban csak a szimb´olikus n´ev szerepel e´ s • ha a konstans neve ‘olvasm´anyos’, vagyis jelent´essel b´ır, akkor a program olvas´asa sor´an k¨onnyebb e´ rtelmezni a forr´ask´odot. P´eld´aul nem csak egy sz´am szerepel az adott helyen, argumentumban, hanem a sz´am funkci´oj´at le´ır´o n´ev. A C programoz´asi nyelvben a konstansok defin´ıci´oja makr´okkal lehets´eges: #define PI 3.1415 A NASM assemblerben az ennek megfelel˝o konstans defin´ıci´o: hossz EQU 12
4.2.4 TIMES pszeudo utas´ıt´as Ha a TIMES pszeudo prefixet haszn´aljuk, akkor arra utas´ıtjuk a NASM Assemblert, hogy az adott utas´ıt´ast vagy adatot t¨obbsz¨or ford´ıtsa bele az eredm´eny programba. P´eld´aul: zerobuffer:
TIMES 64 db 0
Ennek a sornak a hat´as´ara 64 darab z´erus byte ker¨ul az eredm´eny programba. Ezt a sort e´ rdemes o¨ sszevetni az al´abbi sorral, ami csak a helyet lefoglalja le, de a helyen t´arolt adatr´ol nem mond semmit. (L´asd: 4.2.2. fejezetet) zerobuffer: resb 64 A TIMES pszeudo utas´ıt´as egy´eb, o¨ sszetett m´odon is haszn´alhat´o, illetve egyszer˝uen utas´ıt´asokn´al is. P´eld´aul az al´abbi sor azt adja meg, hogy a MOVSB (7.6.1. fejezet) utas´ıt´ast h´aromszor kell a programba beleford´ıtani: TIMES 3 movsb
4.3 SEG kulcssz´o Ha egy olyan programot ´ırunk amelyik t¨obb szegmensb˝ol a´ ll, akkor egy mem´oria hely (p´eld´aul v´altoz´o) el´er´es´en´el sz¨uks´eg lehet a mem´oria hely prefer´alt szegmens c´ım´ere is.1 A prefer´alt itt annyit jelent, hogy az assembler prefer´alja ezt a c´ımet. Ilyen esetben lehet haszn´alni a seg kulcssz´ot. P´eld´aul: mov ax, SEG valami mov es, ax mov bx, valami aminek hat´as´ara a ES:BX regiszterek a valami v´altoz´o mem´oria c´ım´et fogja tartalmazni. 1A
szegmens e´ s offszet regisztereket haszn´al´o mem´oria c´ımz´esr˝ol r´eszletesebb le´ır´as tal´alhat´o a 3.2. fejezetben.
39
¨ 4.3.1 Tov´abbi hasznos´ıt´asi teruletek A seg kulcssz´o haszn´alhat´o t´avoli f¨uggv´eny h´ıv´asn´al is, amikor a f¨uggv´enynek a szegmense e´ s offszet c´ıme is kell. P´eld´aul: call (SEG nyomtat):nyomtat Ha egy mem´oria hely teljes c´ım´et, szegmens e´ s offszetet, is t´arolni kell akkor a k¨ovetkez˝o m´odon lehet ezt megadni: db valami, SEG valami Itt se felejts¨uk el, hogy a ford´ıtott sorrend a ‘Little endian’ t´arol´asi m´od miatt van.
4.4 WRT kulcssz´o El˝ofordulhat, hogy nem a prefer´alt szegmensen kereszt¨ul akarunk hivatkozni egy mem´oria helyre. (Ezt megtehetj¨uk, hiszen a szegmensek a´ tfedik egym´ast a 8086-os g´epeken.) Ilyen esetben a wrt (With Reference To) kulcssz´ot lehet hazn´alni. P´eld´aul: mov ax, egy_masik_szegmens mov es, ax mov bx, valami wrt egy_masik_szegmens
4.5 Parancssori opci´ok ¨ 4.6 Hibauzenetek
40
5. Fejezet
DEBUG program Ez a fejezet a DEBUG program haszn´alat´at mutatja be. A DEBUG program seg´ıts´eg´evel m´ar leford´ıtott programokat tudunk “debuggolni”, l´ep´esenk´ent v´egrehajtani e´ s k¨ozben a rendszer a´ llapot´at megvizsg´alni, illetve hib´akat (bug-okat) keresni. B´ar a program igen egyszer˝u, azt is mondhatn´ank “fapados”, az´ert is e´ rdemes megismerni ezt a programot, mivel minden Microsoft Windows rendszeren l´etezik.
5.1 Jel¨ol´esek c´ ım - c´ımle´ır´as • segmens:offset - pl. 0044:0f57 • segmens reg:offset - pl. ES:0f30 • offset - pl. 400 tartom´ any - egy mem´oriatartom´any kijel¨ol´ese ım ım c´ • c´ • c´ ım, c´ ım • c´ ım L hossz lista - egym´as ut´an le´ırt hexadecim´alis sz´amok sz¨ oveg - dupla aposztrofok k¨oz¨ott karaktersorozat
5.2 A DEBUG ind´ıt´asa • D:\DEBUG <ENTER> : A program elindul e´ s egy minusz jel jelzi, hogy a program v´arja a felhaszn´al´o parancsait • D:\DEBUG file<ENTER> : Bet¨olti a file programot e´ s bel´ep a DEBUG programba
5.3 A DEBUG parancsai q - (Quit) kil´ep´es a programb´ol h val1 val2 - (Hex) ki´ırja a k´et e´ rt´ek o¨ sszeg´et e´ s k¨ul¨onbs´eg´et
41
-h 9 000A -h 1 000A
1 0008 9 FFF8
d tartom´any - (Dump) mem´oria tartalm´anak ki´ır´asa a k´eperny˝ore -d c000:0010 C000:0010 24 C000:0020 4D C000:0030 52 C000:0040 2F C000:0050 29 C000:0060 50 C000:0070 40 C000:0080 E8 -
12 20 4F 56 00 43 00 26
FF 43 58 42 87 49 12 56
FF 4F 2F 45 DB 52 10 8B
00 4D 4D 20 87 2B 00 D8
00 50 47 42 DB 10 80 E8
00 41 41 49 87 01 00 C6
00-60 54-49 2D-47 4F-53 DB-87 10-00 00-38 56-74
00 42 31 20 DB 00 37 22
00 4C 30 28 87 18 34 8C
00 45 30 56 DB 00 2D C8
00 20 20 31 87 00 32 3D
20 4D 56 2E DB 00 00 00
49 41 47 32 87 00 FF C0
42 54 41 20 DB 03 FF 74
$.......‘.... IB M COMPATIBLE MAT ROX/MGA-G100 VGA /VBE BIOS (V1.2 )............... PCIR+........... @.......874-2... .&V....Vt"..=..t
-d 100 130 xxxx:0100 EB 24 0D 0A 54 68 69 73-20 69 73 20 6D 79 20 66 xxxx:0110 69 72 73 74 20 44 45 42-55 47 20 70 72 6F 67 72 xxxx:0120 61 6D 21 0D 0A 24 B4 09-BA 02 01 CD 21 B4 00 CD xxxx:0130 21 -
.$..This is my f irst DEBUG progr am!..$......!... !
s tartom´any sz¨oveg - (Search) mem´oria tartom´anyban megkeresi a sz¨oveg valamennyi el˝ofordul´as´at -s fe00:0 ffff "BIOS" FE00:0021 FE00:006F -d fe00:0 FE00:0000 FE00:0010 FE00:0020 FE00:0030 FE00:0040 FE00:0050 FE00:0060 FE00:0070
41 4D 20 41 6E 41 1B 49
77 20 42 77 63 77 41 4F
61 43 49 61 2E 03 77 53
72 4F 4F 72 6F 0C 61 20
64 4D 53 64 66 04 72 76
20 50 20 20 74 01 64 34
53 41 43 53 77 01 20 2E
6F-66 54-49 4F-50 6F-66 61-72 6F-66 4D-6F 35-31
74 42 59 74 65 74 64 50
77 4C 52 77 20 77 75 47
61 45 49 61 49 E9 6C 00
72 20 47 72 6E 12 61 DB
65 34 48 65 63 14 72 32
49 38 54 20 2E 20 20 EC
42 36 20 49 20 43 42 33
Award SoftwareIB M COMPATIBLE 486 BIOS COPYRIGHT Award Software I nc.oftware Inc. Aw.....oftw... C .Award Modular B IOS v4.51PG..2.3
c tartom´any c´ım - (Compare) o¨ sszehasonl´ıt k´et mem´oria tartom´anyt f tartom´any sz¨oveg - (Fill) mem´oria tartom´any felt¨olt´ese a sz¨oveggel -f 100 12f -d 100 12f xxxx:0100 xxxx:0110 xxxx:0120
’BUFFER’ 42 55 46 46 45 52 42 55-46 46 45 52 42 55 46 46 BUFFERBUFFERBUFF 45 52 42 55 46 46 45 52-42 55 46 46 45 52 42 55 ERBUFFERBUFFERBU 46 46 45 52 42 55 46 46-45 52 42 55 46 46 45 52 FFERBUFFERBUFFER
e c´ım lista - (Enter) e´ rt´ekek bevitele a mem´ori´aba. Ezzel a paranccsal byte sorozatot lehet be´ırni a mem´ori´aba.1 -e 100 B4 09 BA 0B 01 CD 21 B4 00 CD 21
g [c´ım] - (Go) programv´egrehajt´as folytat´asa. Ha a c´ ım is adva van akkor a megadott c´ımre egy t¨or´espontot tesz a debugger e´ s az IP regiszter a´ ltal megadott c´ımt˝ol folytatja a v´egrehajt´ast. A t¨or´espont azt jelenti, hogy ha a v´egrehajt´as sor´an a t¨or´espont c´ım´et el´erj¨uk, akkor a v´egrehajt´as 1 Mivel
a g´epi k´od is csak egy byte sorozat, ez´ert amit ´ıgy be´ırunk a mem´ori´aba az lehet egyszer˝uen adat, de lehet program is!
42
le´all (megt¨orik) e´ s egy parancssor jelenik meg aminek seg´ıts´eg´evel sz´etn´ezhet¨unk a rendszerben. Megvizsg´alhatjuk a regiszterek a´ llapot´at vagy a mem´oria tartalm´at. Persze az is el˝ofordulhat, hogy a v´egrehajt´as sor´an soha nem jutunk el a t¨or´espontig. Ebben az esetben a “program” v´egigfut e´ s v´eg¨ul vagy hib´aval vagy sikeresen le´all a fut´as. a [c´ım] - (Assemble) az opcion´alisan megadott c´ımt˝ol kezdve assembly parancsokat g´epelhet¨unk be. Ebben az esetben a DEBUG program, mint egy assembler m˝uk¨odik. -a 100 xxxx:0100 xxxx:0102 xxxx:0123 xxxx:0126 xxxx:0128 xxxx:012B xxxx:012D xxxx:012F
jmp 126 ; adat ´ atugr´ asa db 0d,0a,"This is my first DEBUG program!" db 0d,0a,"$" mov ah,9 ; 09-es funkcionalit´ as mov dx,102 ; DS:DX -en a $-al lez´ art string int 21 ; string ki´ ır´ asa int 20 ; kil´ ep´ es
u [tartom´any] vagy u [c´ım] - (Unassemble) az aktu´alis vagy a megadott c´ımt˝ol az opcion´alisan megadott tartom´anyban assembly mnemonikra ford´ıtja a g´epi k´odot. -u 126 12F xxxx:0126 B409 xxxx:0128 BA0201 xxxx:012B CD21 xxxx:012D B400 xxxx:012F CD21 -
MOV MOV INT MOV INT
AH,09 DX,0102 21 AH,00 21
i port - (Input) a megadott port-r´ol beolvas egy byte-ot o port byte - (Output) a megadott port-ra ki´ır egy byte-ot Portra val´o ki´ır´as, vagy portb´ol val´o beolvas´as k¨ozvetlen kommunik´aci´ot jelent a hardware-rel. -o -i 18 -o -i 55
70 04 71 70 02 71
; ; ; ; ; ;
K´ erdezz¨ uk le az ´ or´ at Olvassuk vissza az ´ ert´ eket 18 ´ ora K´ erdezz¨ uk le a percet Olvassuk vissza az ´ ert´ eket 55 perc
n filen´ev - (Name) a file nev´enek megad´asa. Erre a parancsra akkor van sz¨uks´eg, ha a mem´oria egy darabj´at mint programot szeretn´enk ki´ırni. p - egy f¨uggv´eny h´ıv´as vagy megszak´ıt´as v´egrehajt´asa eg´eszben. Ebben az esetben a f¨uggv´eny utas´ıt´asait nem l´ep´esr˝ol-l´ep´esre hajtjuk v´egre, hanem egyben. r [reg] - (Register) alapesetben a regiszterek tartalm´at ´ırja ki a k´eperny˝ore. A st´atusz bitek sz¨ovegesen jelennek meg, melyek e´ rtelmez´es´et a 5.1. t´abl´azatban jelennek meg. Ha a regiszter is meg van adva, akkor lehet˝ov´e teszi a megadott regiszter e´ rt´ek´enek megad´as´at. -r cx CX 0100 :273
t - (Trace) egy utas´ıt´as v´egrehajt´asa w - (Write) a BX e´ s CX regiszterekben egy¨uttesen megadott byte-nyi adatot ´ır ki az ‘n’ paranccsal megnevezett file-ba. Ha a file m´ar l´etezett akkor a DEBUG felul´ ¨ ırja!
43
St´atusz bit Carry Parity Aux. carry Zero Sign Trap Direction Interrupt Overflow
1 CY PO AU ZR PL
0 NC NE NA NZ NG
UP EI OV
DW DI NV
5.1. t´abla: A st´atusz bitek sz¨oveges megjelen´ese
5.4 P´eld´ak N´ezz¨unk n´eh´any p´eld´at a DEBUG program haszn´alat´ara. A p´eld´akban a szegmens c´ımet n´egy darab ‘x’ jel¨oli (xxxx), mivel a mem´ori´aban b´arhova bet¨olt˝odhetnek a programok. A p´eld´akban a DEBUG programot kell elind´ıtani a megadott m´odon, illetve a minusz (‘-’) jel ut´ani r´eszt kell beg´epelni.
5.4.1 1. P´elda ´Irjunk egy programot mely egy csillag karaktert nyomtat ki. A programot assembly mnemonikok seg´ıts´eg´evel adjuk meg. Ut´ana a programot lefuttatjuk a DEBUG programban, majd ki´ırjuk a merev lemezre, az aktu´alis k¨onyvt´arba. C:\> DEBUG -a 100 xxxx:100 mov ah,02 xxxx:102 mov dl,2a xxxx:104 int 21 xxxx:106 int 20 xxxx:108 ; csak ENTERT nyomjunk -r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=xxxx ES=xxxx SS=xxxx CS=xxxx IP=0100 NV UP EI PL NZ NA PO NC xxxx:0100 MOV AH,02 -g * Program terminated normally -r cx :8 -n csillag.com -w -q C:\>csillag.com * C:\>
5.4.2 2. P´elda Haszn´aljuk a DEBUG programot arra, hogy megn´ezz¨uk az el˝oz˝o program fut´as´at l´ep´esr˝ol-l´ep´esre. Az “egyszer˝u” utas´ıt´asokn´al a ‘t parancsot, a megszak´ıt´asok v´egrehajt´as´an´al a ‘p’ parancsot haszn´aljuk. A megszak´ıt´asokn´al az´ert kell a ’p‘ parancsot haszn´alni, hogy a megszak´ıt´as sor´an v´egrehajtand´o utas´ıt´asokat ne l´ep´esenk´ent, hanem egyszerre hajtsuk v´egre. C:\> DEBUG csillag.com
44
-r AX=0000 BX=0000 DS=xxxx ES=xxxx xxxx:0100 B402 -u xxxx:0100 B402 xxxx:0102 B22A xxxx:0104 CD21 xxxx:0106 CD20 xxxx:0108 0000 xxxx:010A 0000 xxxx:010C 0000 xxxx:010E 0000 xxxx:0110 0000 xxxx:0112 0000 xxxx:0114 0000 xxxx:0116 0000 xxxx:0118 0000 xxxx:011A 0000 xxxx:011C 0000 xxxx:011E 0000 -t AX=0200 BX=0000 DS=xxxx ES=xxxx xxxx:0102 B402 -t AX=0200 BX=0000 DS=xxxx ES=xxxx xxxx:0104 CD21 -p * AX=022A BX=0000 DS=xxxx ES=xxxx xxxx:0106 CD20 -p
CX=0008 DX=0000 SP=FFFE SS=xxxx CS=xxxx IP=0100 MOV AH,02 MOV MOV INT INT ADD ADD ADD ADD ADD ADD ADD ADD ADD ADD ADD ADD
BP=0000 SI=0000 DI=0000 NV UP EI PL NZ NA PO NC
AH,02 DL,2A 21 20 [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL
CX=0008 DX=0000 SP=FFFE SS=xxxx CS=xxxx IP=0100 MOV DL,2A
BP=0000 SI=0000 DI=0000 NV UP EI PL NZ NA PO NC
CX=0008 DX=002A SS=xxxx CS=xxxx INT 21
SP=FFFE IP=0100
BP=0000 SI=0000 DI=0000 NV UP EI PL NZ NA PO NC
CX=0008 DX=002A SS=xxxx CS=xxxx INT 20
SP=FFFE IP=0100
BP=0000 SI=0000 DI=0000 NV UP EI PL NZ NA PO NC
Program terminated normally -q C:\>
5.4.3 3. P´elda ´Irjuk meg az els˝o p´eld´aban szerepl˝o programot g´epi k´odban. Ebben az esetben a programot mint byte sorozatot vissz¨uk be. C:\> DEBUG -e 100 b4 02 b2 2a cd 21 cd 20 -u xxxx:0100 B402 MOV AH,02 xxxx:0102 B22A MOV DL,2A xxxx:0104 CD21 INT 21 xxxx:0106 CD20 INT 20 xxxx:0108 0000 ADD [BX+SI],AL xxxx:010A 0000 ADD [BX+SI],AL xxxx:010C 0000 ADD [BX+SI],AL xxxx:010E 0000 ADD [BX+SI],AL xxxx:0110 0000 ADD [BX+SI],AL xxxx:0112 0000 ADD [BX+SI],AL xxxx:0114 0000 ADD [BX+SI],AL xxxx:0116 0000 ADD [BX+SI],AL xxxx:0118 0000 ADD [BX+SI],AL xxxx:011A 0000 ADD [BX+SI],AL xxxx:011C 0000 ADD [BX+SI],AL xxxx:011E 0000 ADD [BX+SI],AL -q
45
C:\>
46
6. Fejezet
Els˝o programok Ez a fejezet n´eh´any egyszer˝u programot mutat be r´eszletes magyar´azattal. A magyar´azat n´eha nagyon r´eszletes e´ s t¨obb k¨ul¨onb¨oz˝o vari´aci´ot mutat be, hogy a teljesen kezd˝ok is megszerezz´ek a sz¨uks´eges alapokat bonyolultabb programok meg´ır´as´ahoz.
6.1 Els˝o program N´ezz¨uk meg az els˝o assembly programot NASM assemblerre ´ırva. A program az 6.1. t´abl´an l´athat´o. Ez a program az egyik legkisebb program amit ´ırni lehet Microsoft Window alatt.1 1 2
org 100h INT 20h
6.1. t´abla: Els˝o program Az 1. sor nem assembly utas´ıt´as, hanem azt jel¨oli, hogy a program a 100-as hexadecim´alis c´ımen kezd˝odik. A hexidecim´alis sz´amot a sz´am ut´an ´ırt kis ‘h’ bet˝u jelenti. Ha a ‘h’ bet˝u nem szerepel 100-as sz´am ut´an, akkor a program a 100-as decim´alis c´ımen kezd˝odik, ami 64 hexadecim´alis sz´amnak felelne meg e´ s ez komoly hiba! A magyar´azat arra, hogy mi´ert a 100-as hexadecim´alis c´ımen kell kezd˝odj¨on a program a 8.4. fejezetben tal´alhat´o. A 2. sor egy szoftveres megszak´ıt´ast h´ıv meg. Az INT az utas´ıt´as m´ıg a “20h” a megszak´ıt´as sz´am´at jelenti. Ez a sz´am is hexadecim´alisan van megadva. Term´eszetesen, ha akarjuk, decim´alisan is megadhat´o a megszak´ıt´as sz´ama. Ez a p´elda a 6.2. t´abl´an l´athat´o. Az “INT 20h” megszak´ıt´as arra val´o, hogy egy COM programb´ol kil´epj¨unk. A kil´ep´es azt jelenti, hogy visszat´er¨unk az oper´aci´os rendszerhez. 1 2
org 100h INT 32
6.2. t´abla: Els˝o program egy v´altozata Ha a programot az elso.asm file-ba mentett¨uk, akkor a leford´ıt´asa a NASM seg´ıts´eg´evel a k¨ovetkez˝o sor beg´epel´es´evel lehets´eges: 1 Lehet
kisebb programot is ´ırni, de ennek most nincs jelent˝os´ege.
47
C:\> nasm -o elso.com elso.asm A NASM alap esetben “COM” programokat ford´ıt, ´ıgy a t´ıpust nem kell megadni. A -o opci´oval azt adjuk meg, hogy a ford´ıt´as eredm´eny´et milyen file-ba ´ırjuk. Az utols´o param´eter adja meg, hogy melyik assembly forr´as file-t kell leford´ıtani. A NASM program param´etereinek r´eszletes list´aj´at a 4. fejezet tartalmazza. A ford´ıt´as eredm´enye egy bin´aris file lesz, mely csak k´et byte-ot (!) fog tartalmazni. A file tartalma hexadecim´alis form´aban: CD 20 Ez a p´elda azt mutatja, hogy az INT utas´ıt´as g´epi k´odja a CD hexadecim´alis e´ rt´ek. Az is l´athat´o, hogy az “org 100h” sorb´ol nem gener´al´odik bin´aris k´od, hiszen ez a sor csak azt jel¨oli, hogy a program milyen c´ımen kezd˝odj¨on a mem´ori´aban. Mivel minden COM program a 100h c´ımen kezd˝odik a mem´ori´aban, ez´ert semmilyen extra utas´ıt´asra nincs sz¨uks´eg a bin´aris programban. Mit jelent az, hogy a program a 100 hexadecim´alis c´ımen kezd˝odik? N´ezz¨uk meg a programot a DEBUG program seg´ıts´eg´evel. (A DEBUG program haszn´alat´at a 5. fejezetben t´argyaltuk.) C:\> DEBUG elso.com -r AX=0000 BX=0000 CX=0002 DX=0000 DS=1481 ES=1481 SS=1481 CS=1481 1481:0100 CD20 INT 20 -q
SP=FFFE IP=0100
BP=0000 SI=0000 DI=0000 NV UP EI PL NZ NA PO NC
A p´eld´aban az l´athat´o, hogy a programot az 1481 szegmensre t¨olti be az oper´aci´os rendszer. A szegmens c´ım lehet m´as is! Ami enn´el fontosabb, hogy az offszet c´ım e´ ppen a 100 hexadecim´alis c´ım!
6.2 Egy karakter kinyomtat´asa A k¨ovetkez˝o program egy csillag karaktert nyomtat ki. A program list´aja az 6.3. t´abl´an l´athat´o. 1 2 3 4 5
org 100h MOV AH, 2 MOV DL, 2ah INT 21h INT 20h
6.3. t´abla: Egy karakter kinyomtat´as´ara szolg´al´o program A program nagyon egyszer˝u, mivel az 2. e´ s 3. sor az INT 21h szoftveres megszak´ıt´as param´etereit a´ ll´ıtja be. Ebben az esetben az AH regiszter hat´arozza meg a megszak´ıt´as a´ ltal v´egrehajtand´o m˝uveletet e´ s a DL regiszter adja a kinyomtatand´o karakter ASCII k´odj´at. A MOV utas´ıt´as a jobb oldali argumentum e´ rt´ek´et a´ tm´asolja a bal oldali argumentumba. A 2. sorban azt adjuk meg, hogy az AH regiszter e´ rt´eke a 2-es sz´am legyen. Ez l´enyeg´eben megfelel az e´ rt´ekad´as m˝uveletnek m´as programoz´asi nyelvben. A 3. sorban a DL regiszternek a 2A hexadecim´alis sz´amot adjuk meg. A 2A hexadecim´alis sz´am a csillag (‘*’) karakternek felel meg. (L´asd az A. f¨uggel´ek.) A 4.2.1. bekezd´esben azt l´attuk, hogy egy byte adatot sz´ammal e´ s karakterrel is megadhatunk. R´aad´asul a karaktert egyszeres (’) vagy k´etszeres (”) aposztrofok k¨oz¨ott is megadhatjuk. A 6.4. t´abl´an l´athat´o programban a nyomtatand´o karakter nem sz´ammal, hanem t´enylegesen karakterk´ent van megadva. Ezt az ut´obbi ´ır´asm´odot e´ rdemes haszn´alni, mert ebben az esetben egy´ertelm˝u, ASCII t´abl´azat haszn´alata n´elk¨ul, hogy melyik karaktert akarjuk kinyomtatni.
48
1 2 3 4 5
org 100h MOV AH, 2 MOV DL, ’*’ INT 21h INT 20h
6.4. t´abla: Alternat´ıva a m´asodik programra
6.3 Egy sz¨oveg kinyomtat´asa A harmadik program egy sz¨oveget nyomtat ki a k´eperny˝ore. A program list´aja az 6.5. t´abl´an l´athat´o. 1 2 3 4 5 6
org 100h MOV AH, 9 MOV DX, adat INT 21h INT 20h adat: db ’HELLO$’
6.5. t´abla: Egy sz¨oveg kinyomtat´as´ara szolg´al´o program Ebben a programban is az INT 21h szoftveres megszak´ıt´ast kell haszn´alni. Az AH regiszter most is megszak´ıt´as a´ ltal v´egrehajtand´o m˝uveletet hat´arozza meg. Mivel most egy eg´esz sor karaktert kell kinyomtatni a DL regiszter nem elegend˝o, de a DX regiszter is csak k´et byte-nyi karaktert tud t´arolni. Ebben az esetben a DX regiszter a karaktersorozat c´ım´et tartalmazza. Az assembly programban szerencs´ere nem kell pontosan megadni a c´ımet. Mi´ert szerencse? Mert ahhoz, hogy pontosan megadjuk az adat c´ım´et minden assembly utas´ıt´as eset´en tudnunk kellene, hogy h´any byte-os g´epi k´od gener´al´odik bel˝ole e´ s ezek seg´ıts´eg´evel kellene kisz´amolnunk az aktu´alis c´ımet. A programban szimb´olikusan lehet megadni a karaktersorozat c´ım´et. Maga a karaktersorozat a program v´eg´ere ker¨ult. A karaktersorozat a 4.2.1. bekezd´esnek megfelel˝oen van defini´alva: egy c´ım, ut´ana egy kett˝ospont, a db kulcssz´o e´ s egyszeres aposztrofok k¨oz¨ott maguk a karakterek. Az utols´o karakternek a doll´ar jelnek (‘$’) kell lennie. Ez a doll´ar jel z´arja le a sz¨oveget.2 Ennek a speci´alis karakternek a seg´ıts´eg´evel a´ llap´ıtja meg a rendszert, hogy meddig kell a byte-okat kinyomtatni.3 Ha a doll´ar jelet nem adn´ank meg, akkor a rendszer addig nyomtatn´a a karaktereket am´ıg el nem e´ r egy doll´ar jelet. Elvileg el˝ofordulhat, ha nincs doll´ar jel a mem´ori´aban, hogy az eg´esz mem´ori´at kinyomtatja a program e´ s soha nem a´ ll le. Ezt a programot is e´ rdemes megn´ezni a DEBUG programban, hogy t¨obb dolgot is megn´ezz¨unk: C:\> DEBUG hello.com -u xxxx:0100 B409 xxxx:0102 BA0901 xxxx:0105 CD21 xxxx:0107 CD20 xxxx:0109 48 xxxx:010A 45 xxxx:010B 4C xxxx:010C 4C xxxx:010D 4D
MOV MOV INT INT DEC INC DEC DEC DEC
AH,02 DX,109 21 20 AX BP SP SP DI
2 Kor´ abbi
tanulm´anyokb´ol ismert lehet, hogy a C programoz´asi nyelvben z´er´o a´ ll a sz¨oveg v´eg´en. m´asik strat´egia, hogy megadjuk a karaktereket e´ s a karakterek sz´am´at. Ezt m´odszert a Pascal programoz´asi nyelv haszn´alja. 3A
49
xxxx:010E xxxx:0110 xxxx:0112 xxxx:0114 xxxx:0116 xxxx:0118 xxxx:011A xxxx:011C xxxx:011E -d 100 xxxx:0010 xxxx:0020 xxxx:0030 xxxx:0040 xxxx:0050 xxxx:0060 xxxx:0070 xxxx:0080 -q
2400 0000 0000 0000 0000 0000 0000 0000 0000 B4 00 00 00 00 00 00 00
09 00 00 00 00 00 00 00
AND ADD ADD ADD ADD ADD ADD ADD ADD BA 00 00 00 00 00 00 00
09 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00
CD 00 00 00 00 00 00 00
AL,00 [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL 21 00 00 00 00 00 00 00
CD-20 00-00 00-00 00-00 00-00 00-00 00-00 00-00
48 00 00 00 00 00 00 00
45 00 00 00 00 00 00 00
4C 00 00 00 00 00 00 00
4C 00 00 00 00 00 00 00
4D 00 00 00 00 00 00 00
24 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
......!. HELLO$. ................ ................ ................ ................ ................ ................ ................
A k¨ovetkez˝o e´ szrev´eteleket tehetj¨uk: • Az assembler a ford´ıt´as sor´an kisz´amolta a karaktersorozat c´ım´et, ami jelenleg a 109h c´ımt˝ol indul. • A c´ım k´et byte-b´ol a´ ll e´ s ezt a rendszer “little-endian” m´odon t´arolja: BA 09 01. • A DEBUG program teljesen azonos m´odon kezeli az adatot e´ s a programot is. Igaz´ab´ol nincs is k¨ul¨onbs´eg, hiszen mind a kett˝o egy byte sorozat. P´eld´aul l´athat´o, hogy az “unassemble” parancs sor´an a karaktersorozatot is utas´ıt´ask´ent e´ rtelmezi a DEBUG program. Ez´ert van az, hogy az adatokat e´ s a programot nem szabad keverni. Erre a hib´ara egy p´eld´at mutat az 6.6. t´abla. Ha ezt a programot megn´ezz¨uk a DEBUG programban, akkor azt fogjuk tapasztalni, hogy az adatot is mint utas´ıt´asokat fogja e´ rtelmezni a DEBUG e´ s r´aad´asul e´ rtelmetlen k´odot kapunk. A p´elda azt mutatja, hogy az adatokat e´ s a programot nem szabad o¨ sszekeverni!
1 2 3 4 5 6
org 100h adat: db ’HELLO$’ MOV AH, 9 MOV DX, adat INT 21h INT 20h
6.6. t´abla: Hib´as program C:\> DEBUG hello.com -u xxxx:0100 48 xxxx:0101 45 xxxx:0102 4C xxxx:0103 4C xxxx:0104 4D xxxx:0105 24B4 xxxx:0107 09BA0001 xxxx:010B CD21 xxxx:010D CD20 xxxx:010F 0000 xxxx:0111 0000 xxxx:0113 0000
DEC INC DEC DEC DEC AND OR INT INT ADD ADD ADD
AX BP SP SP DI AL,B4 [BP+SI+0100],DI 21 20 [BX+SI],AL [BX+SI],AL [BX+SI],AL
50
xxxx:0115 xxxx:0117 xxxx:0119 xxxx:011B xxxx:011D xxxx:011F -q
0000 0000 0000 0000 0000 0000
ADD ADD ADD ADD ADD ADD
[BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL [BX+SI],AL
6.4 Egy karakter beolvas´asa A 6.7. t´abl´azat egy nagyon egyszer˝u programot mutat, ami beolvas egy karaktert a felhaszn´al´ot´ol e´ s u´ jra kinyomtatja. A karakter beolvas´asra is haszn´alhat´o az oper´aci´os rendszer megszak´ıt´asa e´ s ekkor a funkci´o k´odnak 1-nek kell lennie. A funkic´o k´odot a 2. sorban a´ ll´ıtjuk be. A 3. sorban az INT 21h megszak´ıt´as lefut´asa ut´an a beolvasott karakter ASCII k´odja az AL regiszterben lesz. Ezt akarjuk u´ jra kinyomtatni, ez´ert m´asoljuk a´ t a DL regiszterbe a 4. sorban, majd az 5. sorban az u´ j funkci´o k´odot is be´all´ıtjuk. V´eg¨ul az INT 21h megszak´ıt´as megh´ıv´as´aval v´egezz¨uk a nyomtat´ast a 6. sorban. 1 2 3 4 5 6 7
org 100h MOV AH, 1 INT 21h MOV DL, AL MOV AH, 2 INT 21h INT 20h
6.7. t´abla: Egy karakter beolvas´asa e´ s kinyomtat´asa
51
52
7. Fejezet
Assembly nyelv utas´ıt´asai Ebben a fejezetben az assembly utas´ıt´asok k¨oz¨ul a legfontosabbakat tekintj¨uk a´ t. A fontoss´agi sorrendet u´ gy pr´ob´altam meg´allap´ıtani, hogy amelyeket a leggyakrabban haszn´aljuk a programokban, vagy amelyekre legink´abb sz¨uks´eg lehet a tanul´as sor´an. Azt is meg kell jegyezni, hogy a fejezetben csak a 8086 processzor utas´ıt´ask´eszlet´eb˝ol ker¨ultek kiv´alaszt´asra az itt felsorolt utas´ıt´asok. Ennek az a magyar´azata, hogy v´elem´enyem szerint ezek az utas´ıt´asok elegend˝oek a fontosabb koncepci´ok bemutat´as´ara. A fejezet v´eg´en a be nem mutatott parancsokat az´ert felsoroljuk. Szintakszis: • mem: mem´oria c´ım • reg: regiszter • op: mem´oria c´ım vagy regiszter
53
7.1 Adatmozgat´o utas´ıt´asok 7.1.1 MOV Szintakszis MOV op1, op2 Az op2 tartalm´at az op1-be ´ırja, fel¨ul´ırva annak kor´abbi e´ rt´ek´et. Az utas´ıt´as operandusai a k¨ovetkez˝ok lehetnek: MOV MOV MOV MOV MOV
regiszter, sz´ amadat regiszter, regiszter regiszter, mem´ oria mem´ oria, sz´ amadat mem´ oria, regiszter
Mint l´athat´o, az nem fordulhat el˝o, hogy egy utas´ıt´as mindk´et operandusa a mem´ori´ara hivatkozzon! Egy utas´ıt´as csak egyszer hivatkozhat a mem´ori´ara! Szint´en fontos, hogy k¨ozvetlen¨ul nem lehet egyik szegmens regiszterbe sem ´ırni, csak a´ tt´etelesen, p´eld´aul: MOV AX, 1234h MOV DS, AX P´eld´ak MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV MOV
AX, 1234 AX, ES ES, AX AL, 0ffH AH, AL AL, [BX] [SI], DL AX, [BX] [DI], BP AX, [0ffffh] [0200h], DX [ES:0100h], CX
7.1.2 XCHG Szintakszis XCHG op1, op2 Az op1 e´ s op2 tartalm´at felcser´eli. Mind a k´et operandusnak azonos m´eret˝unek kell lennie, 8 vagy 16 bitesnek. Az utas´ıt´as el˝onye, hogy a cser´et seg´edv´altoz´o n´elk¨ul hajtja v´egre. Az operandusok cser´eje a´ ltal´aban a k¨ovetkez˝ok´eppen t¨ort´enik: MOV temp, op2 MOV op2, op1 MOV op1, temp
54
P´eld´ak XCHG XCHG XCHG XCHG
AL, BL CX, DX DH, [4351h] [DS:3333h], BP
7.1.3 XLAT Szintakszis XLAT A BX regiszter egy maximum 256 bytes t´abl´azatra mutat e´ s az AL regiszterben lev˝o e´ rt´eknek megfelel˝o elemet veszi ki a t´abl´azatb´ol e´ s t¨olti be az AL regiszterbe. Az utas´ıt´as tulajdonk´eppen egy konverzi´ot hajt v´egre. P´eld´ak MOV BX, tabla MOV AL, 0fh XLAT MOV DL, AL MOV AH, 2 INT 21h ... ... tabla: db ’0123456789ABCDEF’
7.1.4 LDS Szintakszis LDS reg, mem A utas´ıt´as m´asodik operandusa a´ ltal megadott mem´oriahelyen tal´alhat´o 4 byte-os mutat´ot bet¨olti a DS szegmens regiszterbe e´ s az els˝o operandusk´ent megadott regiszterbe. Ilyen m´odon egyetlen utas´ıt´assal lehet bet¨olteni egy m´asik szegmensben lev˝o v´altoz´o c´ım´et. Az utas´ıt´as v´egrehajt´asa ut´an azonnal c´ımezhet˝o a mem´orapoz´ıci´o. P´eld´ak LDS BX, [valtozo] MOV AX, [DS:BX]
7.1.5 LES Szintakszis LES reg, mem
55
A utas´ıt´as m´asodik operandusa a´ ltal megadott mem´oriahelyen tal´alhat´o 4 byte-os mutat´ot bet¨olti az ES szegmens regiszterbe e´ s az els˝o operandusk´ent megadott regiszterbe. Ilyen m´odon egyetlen utas´ıt´assal lehet bet¨olteni egy m´asik szegmensben lev˝o v´altoz´o c´ım´et. Az utas´ıt´as v´egrehajt´asa ut´an azonnal c´ımezhet˝o a mem´orapoz´ıci´o. P´eld´ak LES BX, [valtozo] MOV AX, [ES:BX]
7.1.6 LEA Szintakszis LEA reg, mem Az utas´ıt´as els˝o operandusak´ent megadott regiszterbe bet¨olti a m´asodik operandus offszet c´ım´et. A c´ımet fut´as k¨ozben sz´amolja ki, nem el˝ore, illetve b´armilyen c´ımz´esi m´od haszn´alhat´o. P´eld´ak LEA BX, [valtozo+BX] LEA DI, [BX+4] LEA DI, [AX+CX]
7.1.7 PUSH Szintakszis PUSH op A k´et byte-os operandust a veremre helyezi az utas´ıt´as. Az utas´ıt´as egyen´ert´ek˝u a k¨ovetkez˝o k´et utas´ıt´assal: SUB SP, 2 MOV [SS:SP], op Az operandus lehet szegmens regiszter vagy b´armilyen 16 bites regiszter, mem´oria c´ım vagy konstans sz´am adat. Az utas´ıt´as ford´ıtottja a POP utas´ıt´as. P´eld´ak PUSH PUSH PUSH PUSH
AX DS [0003h] 7
; [DS:0003] tartalma a veremre ; 0007h word a veremre
7.1.8 PUSHF Szintakszis PUSHF
56
A st´atusz regiszter teljes tartalm´at a verem tetej´ere m´asolja. Az utas´ıt´as egyen´ert´ek˝u a k¨ovetkez˝o k´et utas´ıt´assal: SUB SP, 2 MOV [SS:SP], statusz-regiszter Az utas´ıt´as ford´ıtottja a POPF utas´ıt´as, mellyel egy¨utt j´ol haszn´alhat´o olyan esetekben, amikor a st´atusz regiszter egy-egy vagy t¨obb bitj´et akarjuk m´odos´ıtani vagy lek´erdezni. P´eld´ak PUSHF AND [SS:SP], 1 POPF
; statusz regiszter elment´ ese ; csak az 1-es bitet tartjuk meg, maszkoljuk ırjuk eket a statusz regiszterbe ´ ert´ uj ´ ; az ´
Tegy¨uk fel, hogy azt szeretn´enk meg´allap´ıtani, hogy a carry bit e´ rt´eke nulla vagy egy: PUSHF POP AX AND AL, 00000001b JZ nulla_volt egy_volt: ... Az els˝o sor elmenti a st´atusz biteket a vermen, amit ezut´an let¨olt¨unk az AX regiszterbe. Az AX regiszter als´o byte-j´anak a nulladik bitje felel meg a carry bitnek ´ıgy a harmadik sorban ezt a bitet maszkoljuk. Ezut´an ugr´o utas´ıt´ast v´egz¨unk att´ol f¨ugg˝oen, hogy a maszkol´as eredm´enye z´erus vagy nem z´erus volt. Persze ez a “komplik´alt” utas´ıt´as sorozat egyszer˝uen helyettes´ıthet˝o a JC cim e´ s az JNC cim utas´ıt´asokkal, melyek att´ol f¨ugg˝oen ugranak a megadott c´ımre, hogy a carry bit egy vagy e´ ppen nulla volt.
7.1.9 PUSHA Szintakszis PUSHA Az utas´ıt´as 8 regisztert t¨olt fel a veremre. A veremmutat´ot (SP) 16-al cs¨okkenti, majd a k¨ovetkez˝o sorrendben a regiszterek tartalm´at felm´asolja a veremre: AX, CX, DX, BX, SP, BP, SI, DI. Az SP regiszter eset´en az utas´ıt´as v´egrehajt´asa el˝otti e´ rt´eket menti el! Az utas´ıt´as ford´ıtottja a POPA utas´ıt´as.
7.1.10 POP Szintakszis POP op Az utas´ıt´as a veremmutat´o (SP) regiszter a´ ltal mutatott word e´ rt´eket az op operandusba ´ırja bele. Az utas´ıt´as egyen´ert´ek˝u a k¨ovetkez˝o k´et utas´ıt´assal: MOV op, [SS:SP] ADD SP, 2
57
Az operandus lehet szegmens regiszter, b´armilyen 16 bites regiszter vagy mem´oria c´ım. Fontos, hogy az operandus nem lehet a CS regiszter. Ez az´ert van, mert ha ilyen m´odon engedn´enk fel¨ul´ırni a CS regisztert akkor ezzel a´ tt´etelesen szegmensek k¨oz¨otti ugr´o utas´ıt´ast engedn´enk meg, hiszen a k¨ovetkez˝o utas´ıt´asra a CS:IP regiszter p´aros mutat. P´eld´ak POP POP POP POP
AX DS [0003h] [ES:0003h]
7.1.11 POPF Szintakszis POPF A st´atusz regiszter teljes tartalm´at fel¨ul´ırja a verem tetej´en t´arolt 16 bites e´ rt´ekkel. Az utas´ıt´as egyen´ert´ek˝u a k¨ovetkez˝o k´et utas´ıt´assal: MOV statusz-regiszter, [SS:SP] ADD SP, 2 Az utas´ıt´as a PUSHF utas´ıt´assal egy¨utt haszn´alhat´o j´ol olyan esetben, amikor a st´atusz regiszter egy-egy vagy t¨obb bitj´et akarjuk m´odos´ıtani vagy lek´erdezni. P´eld´ak PUSHF AND [SS:SP], 1 POPF
; statusz regiszter elment´ ese ; csak az 1-es bitet tartjuk meg, maszkoljuk ; az ´ uj ´ ert´ eket a statusz regiszterbe ´ ırjuk
7.1.12 POPA Szintakszis POPA Az utas´ıt´as 8 regisztert a´ ll´ıt helyre a vermen elt´arolt e´ rt´ekekb˝ol. Az utas´ıt´as a PUSHA ford´ıtottja e´ s megfelel a k¨ovetkez˝o utas´ıt´asoknak: POP POP POP ADD POP POP POP POP
DI SI BP SP, 2 BX DX CX AX
58
7.1.13 LAHF Szintakszis LAHF Az utas´ıt´as bet¨olti az AH regiszter megfelel˝o poz´ıci´oj´aba a SF, ZF, AF, PF e´ s CF st´atusz biteket. A 7.1. t´abla mutatja a bitek hely´et az AH regiszterben. 7. SF
6. ZF
5.
4. AF
3.
2. PF
1.
0. CF
7.1. t´abla: LAHF utas´ıt´as ut´an az AH regiszter tartalma
P´eld´ak LAHF SHR AH, 6 AND AH, 1
; AH ´ ert´ eke 1 vagy 0 a ZF bittol fuggoen
7.1.14 SAHF Szintakszis SAHF Az utas´ıt´as az AH regiszter megfelel˝o bitjeivel fel¨ul´ırja a SF, ZF, AF, PF e´ s CF st´atusz biteket. A 7.1. t´abla mutatja a bitek hely´et az AH regiszterben.
59
7.2 Matematikai utas´ıt´asok Az ebben a fejezetben t´argyalt utas´ıt´asok eset´en az is felt¨untet´esre ker¨ul, hogy az utas´ıt´as hogyan befoly´asolja a st´atusz regiszter egyes bitjeit. A t´abl´azatokban az ‘x’ jelzi a megv´altoztatott biteket, m´ıg a ‘?’ jel azt jelenti, hogy a bit meghat´arozatlan, vagyis lehet 1 e´ s 0 is.
7.2.1 INC Szintakszis INC op Az utas´ıt´as az operandus e´ rt´ek´ehez 1-et ad hozz´a a CF st´atusz bit megv´altoztat´asa n´elk¨ul. ´ Erintett st´atusz bitek OF DF IF x
TF SF ZF x x
AF x
PF x
CF
P´eld´ak INC INC INC INC
AX BL [100h] [ES:220h]
7.2.2 DEC Szintakszis DEC op Az utas´ıt´as az operandus e´ rt´ek´eb˝ol 1-et von le a CF st´atusz bit megv´altoztat´asa n´elk¨ul. ´ Erintett st´atusz bitek OF DF IF x
TF SF ZF x x
P´eld´ak DEC DEC DEC DEC
AX BL [100h] [ES:220h]
7.2.3 ADD Szintakszis ADD op1, op2
60
AF x
PF x
CF
Az utas´ıt´as az op1 operandushoz adja az op2 operandus e´ rt´ek´et e´ s az eredm´enyt az op1-be ´ırja. Az operandusok m´eret´enek meg kell egyeznie, k´et 8 bites vagy k´et 16 bites e´ rt´eket lehet csak o¨ sszeadni. ´ Erintett st´atusz bitek OF DF IF x
TF SF ZF x x
AF x
PF x
CF x
P´eld´ak ADD ADD ADD ADD ADD
AX, BX [adat], CX CX, [valtozo] BL, 4 SI, [BP+8]
7.2.4 ADC Szintakszis ADC op1, op2 Az utas´ıt´as az op1 operandushoz adja az op2 operandus e´ rt´ek´et e´ s a Carry flag (CF) e´ rt´ek´et is, majd az eredm´enyt az op1-be ´ırja. Az operandusok m´eret´enek meg kell egyeznie, k´et 8 bites vagy k´et 16 bites e´ rt´eket lehet csak o¨ sszeadni. ´ Erintett st´atusz bitek OF DF IF x
TF SF ZF x x
AF x
P´eld´ak ADC AX, BX ADC [adat], CX ADC CX, [valtozo] ADC BL, 4 ADC SI, [BP+8] ... atvitellel as ´ osszead´ ; ¨ MOV CX, 0 MOV AL, 80h MOV AH, 80h MOV CL, AL ADD CL, AH ADC CH, 0 ; eredm´ eny: CX tartalma 100h lesz
7.2.5 SUB Szintakszis SUB op1, op2
61
PF x
CF x
Az utas´ıt´as az op1 operandusb´ol kivonja az op2 operandus e´ rt´ek´et e´ s az eredm´enyt az op1-be ´ırja. Az operandusok m´eret´enek meg kell egyeznie, k´et 8 bites vagy k´et 16 bites e´ rt´eket lehet csak o¨ sszeadni. ´ Erintett st´atusz bitek OF DF IF x
TF SF ZF x x
AF x
PF x
CF x
P´eld´ak SUB SUB SUB SUB SUB
AX, BX [adat], CX CX, [valtozo] BL, 4 SI, [BP+8]
7.2.6 SBB Szintakszis SBB op1, op2 Az utas´ıt´as az op1 operandusb´ol kivonja az op2 operandus e´ rt´ek´et e´ s a Carry flag (CF) e´ rt´ek´et is, majd az eredm´enyt az op1-be ´ırja. Az operandusok m´eret´enek meg kell egyeznie, k´et 8 bites vagy k´et 16 bites e´ rt´eket lehet csak o¨ sszeadni. ´ Erintett st´atusz bitek OF DF IF x
TF SF ZF x x
AF x
PF x
CF x
P´eld´ak SBB SBB SBB SBB SBB
AX, BX [adat], CX CX, [valtozo] BL, 4 SI, [BP+8]
7.2.7 MUL Szintakszis MUL op Ez az utas´ıt´as 8 vagy 16 bites el˝ojel n´elk¨uli sz´amok k¨oz¨otti szorz´ast hajt v´egre. Az operandus hat´arozza meg, hogy 8 vagy 16 bites sz´amokat szoroz-e o¨ ssze. 8 bites szorz´as eset´en az AL regiszter tartalm´at o¨ sszeszorozza az op operandussal e´ s az eredm´enyt az AX regiszterben t´arolja el. Ha az eredm´enyben az AH regiszter tartalma z´erus akkor a CF e´ s OF st´atusz bitek e´ rt´eke z´erus lesz, egy´ebk´ent 1. 16 bites szorz´as eset´en az AX regiszter tartalm´at o¨ sszeszorozza az op operandussal e´ s az eredm´enyt az DX:AX regiszterekben t´arolja el. Az operandusok el˝ojel n´elk¨uli sz´amok e´ s b´armilyen c´ımz´esi m´od haszn´alhat´o. Ha az eredm´enyben az DX regiszter tartalma z´erus akkor a CF e´ s OF st´atusz bitek e´ rt´eke z´erus lesz, egy´ebk´ent 1.
62
´ Erintett st´atusz bitek OF DF IF x
TF SF ZF ? ?
AF ?
PF ?
CF x
P´eld´ak MOV AL, 2 MUL 4 ... adat: db 4 ... MOV AL, 2 MUL [adat]
; AX tartalma 8 lesz
; AX tartalma 8 lesz
7.2.8 IMUL Szintakszis IMUL op Ez az utas´ıt´as 8 vagy 16 bites el˝ojeles szorz´ast hajt v´egre. Az operandus hat´arozza meg, hogy 8 vagy 16 bites sz´amokat szoroz-e o¨ ssze. 8 bites szorz´as eset´en az AL regiszter tartalm´at o¨ sszeszorozza az op operandussal e´ s az eredm´enyt az AX regiszterben t´arolja el. Ha az eredm´enyben az AH regiszter tartalma z´erus akkor a CF e´ s OF st´atusz bitek e´ rt´eke z´erus lesz, egy´ebk´ent 1. 16 bites szorz´as eset´en az AX regiszter tartalm´at o¨ sszeszorozza az op operandussal e´ s az eredm´enyt az DX:AX regiszterekben t´arolja el. Az operandusok el˝ojel n´elk¨uli sz´amok e´ s b´armilyen c´ımz´esi m´od haszn´alhat´o. Ha az eredm´enyben az DX regiszter tartalma z´erus akkor a CF e´ s OF st´atusz bitek e´ rt´eke z´erus lesz, egy´ebk´ent 1. ´ Erintett st´atusz bitek OF DF IF x
TF SF ZF ? ?
AF ?
PF ?
CF x
P´eld´ak MOV AL, 2 IMUL 4 ... adat: db 4 ... MOV AL, 2 IMUL [adat]
; AX tartalma 8 lesz
; AX tartalma 8 lesz
7.2.9 DIV Szintakszis DIV op Ez az utas´ıt´as el˝ojel n´elk¨uli oszt´ast hajt v´egre. Ha byte, 8 bites, operandust adunk meg az utas´ıt´asban, akkor az AX regiszter tartalm´at az operandussal elosztja e´ s a h´anyadost az AL regiszterben, a marad´ekot az AH regiszterben t´arolja el. Word vagy sz´o m´eret˝u operandus eset´en a DX:AX regisztrerek tartalm´at
63
elosztja az operandussal majd a h´anyadost a AX regiszterben e´ s a marad´ekot a DX regiszterben t´arolja el. Ha az oszt´o z´erus vagy a h´anyados t´ul nagy, hogy elf´erjen az AL vagy AX regiszterben, akkor az INT 0 megszak´ıt´as h´ıv´odik meg. ´ Erintett st´atusz bitek OF DF IF ?
TF SF ZF ? ?
AF ?
PF ?
CF ?
P´eld´ak MOV AX, 12 DIV 10
; AL = 1, AH = 2
7.2.10 IDIV Szintakszis IDIV op Ez az utas´ıt´as el˝ojeles oszt´ast hajt v´egre. Ha byte, 8 bites, operandust adunk meg az utas´ıt´asban, akkor az AX regiszter tartalm´at az operandussal elosztja e´ s a h´anyadost az AL regiszterben, a marad´ekot az AH regiszterben t´arolja el. Word vagy sz´o m´eret˝u operandus eset´en a DX:AX regisztrerek tartalm´at elosztja az operandussal majd a h´anyadost a AX regiszterben e´ s a marad´ekot a DX regiszterben t´arolja el. Ha az oszt´o z´erus vagy a h´anyados t´ul nagy, hogy elf´erjen az AL vagy AX regiszterben, akkor az INT 0 megszak´ıt´as h´ıv´odik meg. ´ Erintett st´atusz bitek OF DF IF ?
TF SF ZF ? ?
AF ?
PF ?
CF ?
P´eld´ak MOV AX, 12 IDIV 10
; AL = 1, AH = 2
7.2.11 NEG Szintakszis NEG op Az operandust null´ab´ol kivonja e´ s hozz´aad egyet, majd az eredm´enyt elt´arolja az operandusban, fel¨ul´ırva annak kor´abbi e´ rt´ek´et. Az utas´ıt´as l´enyeg´eben kettes komplemens´et k´epzi az operandusnak. Ha az eredm´eny operandus z´erus, akkor a CF bit e´ rt´eke z´erus lesz, egy´ebk´ent pedig 1. ´ Erintett st´atusz bitek OF DF IF x
TF SF ZF x x
64
AF x
PF x
CF x
P´eld´ak NEG AX NEG BL NEG [DS:100h]
7.2.12 CBW Szintakszis CBW Az utas´ıt´as az AL regiszterben tal´alhat´o el˝ojeles byte-ot el˝ojeles sz´ov´a alak´ıtja az AX regiszterben. Ez u´ gy t¨ort´enik, hogy az AL regiszter legnagyobb helyi´ert´ek˝u bitj´et bem´asolja az AH regiszter minden bitj´ebe. Assembly-ben ez a k¨ovetkez˝o utas´ıt´asoknak felel meg: TEST AL, 128 JNZ egy zerus: MOV AH, 00h JMP vege egy: MOV AH, 0FFh vege: Az utas´ıt´as egy 8 bites sz´am el˝ok´esz´ıt´es´et v´egzi el˝ojeles oszt´ashoz.
7.2.13 CWD Szintakszis CWD Az utas´ıt´as az AX regiszterben tal´alhat´o el˝ojeles word-ot el˝ojeles e´ rt´ekk´e alak´ıtja az DX:AX regiszterekben. Az utas´ıt´as egy 16 bites sz´am el˝ok´esz´ıt´es´et v´egzi el˝ojeles oszt´ashoz.
65
7.3 Bitforgat´o e´ s bitl´eptet˝o utas´ıt´asok Az al´abbi utas´ıt´asokban az op operandus lehet 8 vagy 16 bites e´ s tetsz˝oleges c´ımz´esi m´odot alkalmazhatunk. Az utas´ıt´asokn´al a “kil´ep˝o” bit minden esetben megjelenik Carry bitben. Az utas´ıt´asok k´et csoportba sorolhat´ok: • Bitforgat´o, rot´al´o utas´ıt´asok: RCL, RCR, ROL, ROR • Bitl´eptet˝o, shiftel˝o utas´ıt´asok: SAL, SAR, SHL, SHR
7.3.1 RCL Szintakszis RCL op, 1 RCL op, CL RCL op, szamlalo
CF
Az utas´ıt´as balra forgatja az operandus e´ rt´ek´et olyan m´odon, hogy a legnagyobb helyi´ert´ek˝u bit a Carry bitbe ker¨ul, a Carry bit pedig a legkisebb helyi´ert´ek˝u bit hely´ebe. Minden m´as bit eggyel balra tol´odik. Az utas´ıt´as m˝uk¨od´es´et a 7.1. a´ bra is szeml´elteti. Az utas´ıt´as k´epes a forgat´ast egyszer vagy t¨obbsz¨or v´egrehajtani, a m´asodik operandust´ol f¨ugg˝oen.
7.1. a´ bra: Az RCL utas´ıt´as m˝uk¨od´ese ´ Erintett st´atusz bitek OF DF IF x
TF SF ZF
AF
PF
CF x
Ha a CF bit az operandus magas bitj´evel egyenl˝o, akkor az OF bit e´ rt´eke z´erus lesz, m´ıg ha nem egyenl˝o akkor 1 lesz. P´eld´ak RCL RCL RCL RCL
AL, 1 AX, 3 BX, CL [DS:2456h], CL
Az utas´ıt´as haszn´alat´ara a 9.1. fejezet mutat egy p´elda programot.
7.3.2 RCR Szintakszis RCR op, 1 RCR op, CL RCR op, szamlalo
66
CF
Az utas´ıt´as jobbra forgatja az operandus e´ rt´ek´et olyan m´odon, hogy a Carry bit a legnagyobb helyi´ert´ek˝u bitbe m´asol´odik, a legkisebb helyi´ert´ek˝u bit pedig a Carry bitbe ker¨ul. Minden m´as bit eggyel jobbra tol´odik. Az utas´ıt´as m˝uk¨od´es´et a 7.2. a´ bra is szeml´elteti. Az utas´ıt´as k´epes a forgat´ast egyszer vagy t¨obbsz¨or v´egrehajtani, a m´asodik operandust´ol f¨ugg˝oen.
7.2. a´ bra: Az RCR utas´ıt´as m˝uk¨od´ese
´ Erintett st´atusz bitek OF DF IF x
TF SF ZF
AF
PF
CF x
P´eld´ak RCR RCR RCR RCR
AL, 1 AX, 3 BX, CL [DS:2456h], CL
7.3.3 ROL Szintakszis ROL op, 1 ROL op, CL ROL op, szamlalo
CF
Az utas´ıt´as az els˝o operandust balra rot´alja “¨onmag´an” e´ s a “kicsorg´o” legmagasabb helyi´ert´ek˝u bit ker¨ul a Carry bitbe. A m˝uk¨od´est a 7.3. a´ bra mutatja be. Az utas´ıt´as k´epes a forgat´ast egyszer vagy t¨obbsz¨or v´egrehajtani, a m´asodik operandust´ol f¨ugg˝oen.
7.3. a´ bra: Az ROL utas´ıt´as m˝uk¨od´ese
´ Erintett st´atusz bitek OF DF IF x
TF SF ZF
P´eld´ak ROL AL, 1
67
AF
PF
CF x
ROL AX, 3 ROL BX, CL ROl [DS:2456h], CL
7.3.4 ROR Szintakszis ROR op, 1 ROR op, CL ROR op, szamlalo
CF
Az utas´ıt´as az els˝o operandust jobbra rot´alja “¨onmag´an” e´ s a “kicsorg´o” legalacsonyabb helyi´ert´ek˝u bit ker¨ul a Carry bitbe. A m˝uk¨od´est a 7.4. a´ bra mutatja be. Az utas´ıt´as k´epes a forgat´ast egyszer vagy t¨obbsz¨or v´egrehajtani, a m´asodik operandust´ol f¨ugg˝oen.
7.4. a´ bra: Az ROR utas´ıt´as m˝uk¨od´ese
´ Erintett st´atusz bitek OF DF IF x
TF SF ZF
AF
PF
CF x
P´eld´ak ROR ROR ROR ROR
AL, 1 AX, 3 BX, CL [DS:2456h], CL
7.3.5 SAL, SHL Szintakszis SAL SAL SAL SHL SHL SHL
op, op, op, op, op, op,
1 CL szamlalo 1 CL szamlalo
Az utas´ıt´as balra l´eptet minden bitet. A legmagasabb helyi´ert´ek˝u bit a Carry bitbe ker¨ul, m´ıg a legalacsonyabb helyi´ert´ek˝u bit t¨orl˝odik. Az utas´ıt´as m˝uk¨od´es´et a 7.5. a´ bra mutatja be. Az utas´ıt´as k´epes a bit l´eptet´est egyszer vagy t¨obbsz¨or v´egrehajtani, a m´asodik operandust´ol f¨ugg˝oen. ´ Erdemes megjegyezni, hogy ha egyszer hajtjuk v´egre az utas´ıt´ast, akkor ez megfelel a 2-vel val´o szorz´asnak. Az esetleges szorz´asi t´ulcsordul´as a Carry bitben jelenik meg.
68
CF
0 7.5. a´ bra: Az SAL utas´ıt´as m˝uk¨od´ese ´ Erintett st´atusz bitek OF DF IF x
TF SF ZF x x
AF
PF
CF x
P´eld´ak SHL SHL SHL SHL
AL, 1 AX, 3 BX, CL [DS:2456h], CL
Az utas´ıt´as haszn´alat´ara a 8.7. fejezet mutat n´eh´any p´eld´at.
7.3.6 SAR Szintakszis SAR op, 1 SAR op, CL SAR op, szamlalo
CF
Az utas´ıt´as jobbra l´eptet minden bitet. A legalacsonyabb helyi´ert´ek˝u bit a Carry bitbe ker¨ul, m´ıg a legmagasabb helyi´ert´ek˝u bit ism´etl˝odik. Az utas´ıt´as m˝uk¨od´es´et a 7.6. a´ bra mutatja be. Az utas´ıt´as k´epes a bit l´eptet´est egyszer vagy t¨obbsz¨or v´egrehajtani, a m´asodik operandust´ol f¨ugg˝oen. ´ Erdemes megjegyezni, hogy ha egyszer hajtjuk v´egre az utas´ıt´ast, akkor ez megfelel a 2-vel val´o el˝ojeles oszt´asnak. A h´anyados az operandusban marad, m´ıg a marad´ek a Carry bitbe ker¨ul.
7.6. a´ bra: Az SAR utas´ıt´as m˝uk¨od´ese ´ Erintett st´atusz bitek OF DF IF x
TF SF ZF x x
7.3.7 SHR Szintakszis SHR op, 1
69
AF
PF
CF x
SHR op, CL SHR op, szamlalo
CF
Az utas´ıt´as jobbra l´eptet minden bitet. A legalacsonyabb helyi´ert´ek˝u bit a Carry bitbe ker¨ul, m´ıg a legmagasabb helyi´ert´ek˝u bit t¨orl˝odik. Az utas´ıt´as m˝uk¨od´es´et a 7.7. a´ bra mutatja be. Az utas´ıt´as k´epes a bit l´eptet´est egyszer vagy t¨obbsz¨or v´egrehajtani, a m´asodik operandust´ol f¨ugg˝oen. ´ Erdemes megjegyezni, hogy ha egyszer hajtjuk v´egre az utas´ıt´ast, akkor ez megfelel a 2-vel val´o el˝ojel n´elkuli ¨ oszt´asnak. A h´anyados az operandusban marad, m´ıg a marad´ek a Carry bitbe ker¨ul.
0 7.7. a´ bra: Az SHR utas´ıt´as m˝uk¨od´ese
´ Erintett st´atusz bitek OF DF IF x
TF SF ZF x x
AF
PF
CF x
P´eld´ak Az al´abbi programr´eszlet azt ellen˝orzi, hogy a legalacsonyabb helyi´ert´ek˝u bit z´erus vagy egy: ... SHR AL, 1 JNC zerus ; k´ od v´ egrehajt´ asa ha a bit 1 JMP vege zerus: ; k´ od v´ egrehajt´ asa ha a bit 0 vege: ...
70
7.4 Logikai utas´ıt´asok 7.4.1 AND A 0 1 0 1
B 0 0 1 1
A AND B 0 0 0 1
7.2. t´abla: AND utas´ıt´as igazs´ag t´abl´aja
7.4.2 OR A 0 1 0 1
B 0 0 1 1
A OR B 0 1 1 1
7.3. t´abla: OR utas´ıt´as igazs´ag t´abl´aja
7.4.3 XOR A 0 1 0 1
B 0 0 1 1
A XOR B 0 1 1 0
7.4. t´abla: XOR utas´ıt´as igazs´ag t´abl´aja
7.4.4 NOT A 0 1
NOT A 1 0
7.5. t´abla: NOT utas´ıt´as igazs´ag t´abl´aja
7.4.5 TEST 7.4.6 CMP
71
Felt´etel = nem = > >= < <=
El˝ojeles JE, JZ JNE, JNZ JG, JNLE JGE, JNL JL, JNGE JLE, JNG
El˝ojel n´elk¨ul JE, JZ JNE, JNZ JA, JNBE JAE, JNB JB, JNAE JBE, JNA
7.6. t´abla: Felt´eteles utas´ıt´asok.
7.5 Vez´erl´es´atad´o utas´ıt´asok 7.5.1 JMP 7.5.2 Felt´eteles utas´ıt´asok Az assembly programoz´asi nyelvben nincsennek magasabb szint˝u programoz´asi konstrukci´ok, p´eld´aul ciklus. Minden ilyen szerkezetet felt´eteles ugr´asokkal kell megval´os´ıtani. A felt´eteles ugr´as azt jelenti, hogy a program fut´asa nem a k¨ovetkez˝o utas´ıt´assal folytat´odik, hanem a felt´eteles ugr´as a´ ltal megadott c´ımen, ha a felt´etel teljes¨ul. Itt a felt´etel nem jelenti azt, hogy az utas´ıt´as valamilyen o¨ sszehasonl´ıt´ast v´egezne, csak annyit, hogy egy kor´abbi utas´ıt´as a´ ltal be´all´ıtott st´atusz bit e´ rt´eke alapj´an t¨ort´enhet ugr´as. P´eld´aul a JE c´ ım utas´ıt´as azt jelenti, hogy ha a ZF (z´erus st´atusz bit) e´ rt´eke egy (1) akkor a ’c´ım’-en folytat´odik a program v´egrehajt´asa. Ha a z´erus st´atusz bit e´ rt´eke nulla (0) akkor a JE c´ ım utas´ıt´as ut´ani utas´ıt´assal folytat´odik a program v´egrehajt´asa. A 7.6. t´abl´azat sorolja fel a k¨ul¨onb¨oz˝o felt´eteles ugr´o utas´ıt´asokat. Fontos, hogy lehet˝os´eg szerint ne keverj¨uk az el˝ojeles e´ s el˝ojel n´ek¨uli felt´eteles ugr´o utas´ıt´asokat.
7.5.3 JCXZ 7.5.4 LOOP Szintakszis LOOP cim Az utas´ıt´as 1-el cs¨okkenti a CX regiszter e´ rt´ek´et e´ s ha az ´ıgy kapott e´ rt´ek nem nulla akkor a cim c´ımre adja a´ t a vez´erl´est. Ha a cs¨okkent´es ut´an a CX e´ rt´eke z´erus lesz, akkor a LOOP utas´ıt´as ut´ani utas´ıt´assal folytatja program a v´egrehajt´ast. Fontos meg´erteni, hogy ez az utas´ıt´as egy h´atul tesztel˝o ciklusnak felel meg. ´Igy el˝osz¨or mindig a cs¨okkent´es k¨ovetkezik be e´ s csak ut´ana az ellen˝orz´es.
7.5.5 LOOPNZ Szintakszis LOOPNZ cim LOOPNE cim Az utas´ıt´as angol neve: “Loop while Non Zero” vagy “Loop while Not Equal”. Az utas´ıt´as el˝osz¨or is megvizsg´alja a ZF st´atusz bit e´ rt´ek´et. Ha a st´atusz bit e´ rt´eke nulla, akkor cs¨okkenti a CX regiszter e´ rt´ek´et 1-el e´ s ha ´ıgy a CX regiszter e´ rt´eke m´eg nem nulla, akkor v´egrehajtja az ugr´ast a cim c´ımre. Ellenkez˝o esetben az utas´ıt´as ut´an folytatja a program a v´egrehajt´ast.
72
7.5.6 LOOPZ Szintakszis LOOPZ cim LOOPE cim Az utas´ıt´as angol neve: “Loop while Zero” vagy “Loop while Equal”. Az utas´ıt´as el˝osz¨or is megvizsg´alja a ZF st´atusz bit e´ rt´ek´et. Ha a st´atusz bit e´ rt´eke 1, akkor cs¨okkenti a CX regiszter e´ rt´ek´et 1-el e´ s ha ´ıgy a CX regiszter e´ rt´eke m´eg nem nulla, akkor v´egrehajtja az ugr´ast a cim c´ımre. Ellenkez˝o esetben az utas´ıt´as ut´an folytatja a program a v´egrehajt´ast. Enn´el az utas´ıt´asn´al a ZF st´atusz bit jel¨oli, hogy mi´ert e´ r v´eget a ciklus. Ha CX regiszter lett z´erus, akkor a ZF st´atusz bit e´ rt´eke 1 lesz, ha pedig az utols´o st´atusz bit m˝uvelet eredm´enye volt null´at´ol k¨ul¨onb¨oz˝o, akkor a ZF st´atusz bit e´ rt´eke nulla lesz.
7.5.7 CALL Szintakszis CALL cim Az utas´ıt´as el˝osz¨or elmenti a CALL utas´ıt´ast k¨ovet˝o utas´ıt´as c´ım´et a verem tetej´en. Ez lesz a f¨uggv´eny visszat´er´esi c´ıme. Ezut´an az argumentumk´ent megadott c´ımre adja a´ t a vez´erl´est, vagyis a cim c´ımen folytat´odik a vg´erehajt´as. Az utas´ıt´assal lehet k¨ozeli vagy t´avoli vez´erl´es a´ tad´ast v´egrehajtani. M´as szavakkal az argumentum lehet csak offszet vagy szegmens e´ s offszet c´ım. Az utas´ıt´ast a f¨uggv´enyek megh´ıv´as´ara haszn´aljuk. A f¨uggv´enyb˝ol visszat´er´est a RET utas´ıt´as v´egzi, l´asd 7.5.8. bekezd´es. A f¨uggv´enyekr˝ol r´eszletesebb le´ır´as a 10. fejezetben tal´alhat´o.
7.5.8 RET Szintakszis RET vagy RET n Az utas´ıt´as egy f¨uggv´eny v´eg´en szokott szerepelni. Feladata, hogy a verem tetej´er˝ol levegyen egy visszat´er´esi c´ımet, majd a vez´erl´est a´ tadja erre a c´ımre. Fontos meg´erteni, hogy az utas´ıt´as nem vizsg´alja meg a verem tetej´et, ak´armit tal´al ott az utas´ıt´as azt visszaat´er´esi c´ımnek fogja tekinteni. Az utas´ıt´ashoz optcion´alisan tartozhat egy argumentum. Ebben az esetben az argumentum egy sz´am n, ami megadja, hogy a visszat´er´esi c´ım lev´etele ut´an m´eg h´agy byte-ot kell levenni a veremr˝ol. Ezeket a levett e´ rt´ekeket eldobjuk. A k¨ul¨onb¨oz˝o f¨uggv´eny h´ıv´as ut´ani takar´ıt´asi strat´egi´akr´ol a 10.4.3. bekezd´esben olvashatunk.
7.5.9 INT
73
7.6 String kezel˝o utas´ıt´asok A string kezel˝o utas´ıt´asok mem´oriablokkokkal v´egeznek m˝uveletet. A string, tulajdonk´eppen sz¨oveg, a sz¨oveg pedig nem m´as mint egy karakter sorozat vagy byte sorozat e´ s egy byte sorozat amikor a mem´ori´aban t´aroljuk akkor pedig megfelel egy mem´oriablokknak. Az utas´ıt´asok a´ ltal´aban a DS:SI, ES:DI e´ s AX regisztereket haszn´alj´ak. A regisztereken k´ıv¨ul fontos szerepet j´atszik m´eg a Direction (Ir´any) st´atusz bit, mivel ez hat´arozza meg, hogy a m˝uvelet sor´an a c´ımekhez hozz´aadunk vagy a c´ımekb˝ol kivonunk e´ rt´ekeket. A Direction (Ir´any) st´atusz bitet a CLD (7.7.4. bekezd´es) e´ s STD (7.7.5. bekezd´es) utas´ıt´asok a´ ll´ıtj´ak be. A string kezel˝o parancsokat r´eszletesen t´argyaljuk a 12. fejezetben.
7.6.1 MOVSB, MOVSW Szintakszis MOVSB MOVSW Az utas´ıt´asok angol neve: “MOVe String Byte” illetve “MOVe String Word”. Az utas´ıt´as a DS:SI regiszterek a´ ltal megc´ımzett byte-ot a´ tm´asolja az ES:DI c´ımre. Az SI e´ s DI regiszterek e´ rt´eke 1-el n¨ovekszik ha a Direction st´atusz bit e´ rt´eke nulla vagy a regiszterek e´ rt´eke 1-el cs¨okken, ha a Direction st´atusz bit e´ rt´eke egy. A MOVSW utas´ıt´as csak annyiban k¨ul¨onb¨ozik, hogy k´et byte-ot vagyis egy sz´ot (word) m´asol a´ t e´ s az SI e´ s DI regiszterek e´ rt´eke kett˝ovel m´odosul a Direction st´atusz bit e´ rt´ek´et˝ol f¨ugg˝oen. Ezek az utas´ıt´asok a kiv´etelek k¨oz´e tartoznak, mivel egy utas´ıt´as k´etszer is hozz´af´er a mem´ori´ahoz. A m´asik fontos megjegyz´es, hogy ezek az utas´ıt´asok csak egy szegmensnyi adatot k´epesek a´ tm´asolni, mivel ha a DI regiszter e´ rt´eke el´eris a FFFFh e´ rt´eket e´ s 1-el megn¨ovelj¨uk az e´ rt´ek´et akkor a nulla e´ rt´eket kapjuk, ami a szegmens els˝o byte-j´ara mutat, ´ıgy “k¨orbefordul´as” k¨ovetkezik be. Ez az´ert van, mert az utas´ıt´as nem m´odos´ıtja a szegmens regisztereket, azokat nem n¨oveli e´ s nem cs¨okkenti. A 8086osn´al modernebb processzorokon az´ert lehet t¨obb adatot a´ tm´asolni, mivel az ESI e´ s EDI 32 bites regisztereket haszn´aljuk a m˝uveletben. Nagyon fontos, hogy az utas´ıt´as a haszn´alt regiszterek kezdeti e´ rt´ek´et nem a´ ll´ıtja be, azt a programoz´onak kell megadni! P´eld´ak Az al´abbbi k´odr´eszlet a´ tm´asol 4 word m´eret˝u adatot: forras: dw 1111h, 2222h, 3333h, 4444h cel: dw 0000h, 0000h, 0000h, 0000h ... MOV SI, forras MOV DI, cel MOV CX, 4 CLD ujra: MOVSW LOOP ujra ... Ezt a p´eld´at e´ rdemes o¨ sszehasonl´ıtani egy egyszer˝us´ıtett v´altozattal, ami a 7.6.6. bekezd´esben tal´alhat´o.
74
7.6.2 CMPSB, CMPSW Szintakszis CMPSB CMPSW Az utas´ıt´asok angol neve: “CoMPare String Byte” illetve “CoMPare String Word”. A CMPSB utas´ıt´as a DS:SI regiszterek a´ ltal megc´ımzett byte-ot o¨ sszehasonl´ıtja az ES:DI a´ ltal megc´ımzett byte-al. Az SI e´ s DI regiszterek e´ rt´eke 1-el n¨ovekszik ha a Direction st´atusz bit e´ rt´eke nulla vagy a regiszterek e´ rt´eke 1-el cs¨okken, ha a Direction st´atusz bit e´ rt´eke egy. Az utas´ıt´asok a st´atusz biteket is be´all´ıtja u´ gy, mintha egy CMP utas´ıt´ast (l´asd 7.4.6. bekezd´es) hajtottunk volna v´egre. A CMPSW utas´ıt´as hasonl´oan m˝uk¨odik, de word m´eret˝u adatokkal dolgozik, e´ s az SI e´ s DI regiszterek e´ rt´eke is 2-vel v´altozik.
7.6.3 LODSB, LODSW Szintakszis LODSB LODSW Az utas´ıt´asok angol neve: “LOaD String Byte” illetve “LOaD String Word”. A LODSB utas´ıt´as a DS:SI regiszterek a´ ltal megc´ımzett byte-ot bet¨olti az AL regiszterbe. Az SI regiszter e´ rt´eke 1-el n¨ovekszik ha a Direction st´atusz bit e´ rt´eke nulla vagy az SI regiszter e´ rt´eke 1-el cs¨okken, ha a Direction st´atusz bit e´ rt´eke egy. A LODSW utas´ıt´as csak abban k¨ul¨onb¨ozik, hogy a DS:SI regiszterek a´ ltal megadott c´ımr˝ol egy word-¨ot (2 byte-ot) t¨olt¨unk be az AX regiszterbe.
7.6.4 STOSB, STOSW Szintakszis STOSB STOSW Az utas´ıt´asok angol neve: “STOre String Byte” illetve “STOre String Word”. A STOSB utas´ıt´as az AL regiszter e´ rt´ek´et az ES:DI regiszterek a´ ltal megadott c´ımre ´ırja. Az DI regiszter e´ rt´eke 1-el n¨ovekszik ha a Direction st´atusz bit e´ rt´eke nulla vagy az DI regiszter e´ rt´eke 1-el cs¨okken, ha a Direction st´atusz bit e´ rt´eke egy. A STOSW utas´ıt´as csak abban k¨ul¨onb¨ozik, hogy az AX regiszter tartalm´at ´ırja ki az ES:DI regiszterek a´ ltal megadott c´ımre. A DI regiszter e´ rt´eke 2-vel v´altozik a Directioin st´atusz bit e´ rt´ek´et˝ol f¨ugg˝oen.
7.6.5 SCASB, SCASW Szintakszis SCASB SCASW Az utas´ıt´asok angol neve: “SCAn String Byte” illetve “SCAn String Word”. A SCASB utas´ıt´as az AL regiszter e´ rt´ek´et o¨ sszehasonl´ıtja az ES:DI regiszterek a´ ltal megc´ımzett byte-al. A st´atusz biteket az ‘[ES:DI] - AL’ k¨ul¨onbs´eg szerint lesznek be´all´ıtva. Az DI regiszter e´ rt´eke 1-el n¨ovekszik ha a
75
Direction st´atusz bit e´ rt´eke nulla vagy az DI regiszter e´ rt´eke 1-el cs¨okken, ha a Direction st´atusz bit e´ rt´eke egy. A SCASW utas´ıt´as csak abban k¨ul¨onb¨ozik, hogy az AX regiszter tartalm´at hasonl´ıtja o¨ ssze az ES:DI regiszterek a´ ltal megc´ımzett word-el. A DI regiszter e´ rt´eke 2-vel v´altozik a Directioin st´atusz bit e´ rt´ek´et˝ol f¨ugg˝oen. Amikor a REP prefix-el egy¨utt haszn´aljuk, akkor ez az utas´ıt´as, a megadott mem´oria blokkban az AL vagy AX regiszter tartalm´at keresi meg.
7.6.6 REP Szintakszis REP string-utas´ ıt´ as Ez tulajdonk´eppen nem is utas´ıt´as, hanem egy prefix, amit a string kezel˝o utas´ıt´asok el´e tehet¨unk. A neve a “REPeat”, ism´etl´es angol sz´ob´ol sz´armazik. Ennek a prefixnek az a feladata, hogy az ut´ana megadott string kezel˝o utas´ıt´ast t¨obbsz¨or hajtsa v´egre. Az ism´etl´esek sz´am´at a CX regiszter adja meg, amit el˝ore be kell a´ ll´ıtani. Fontos, hogy a CX e´ rt´eke az adatok sz´am´at adja meg, nem pedig az adatok byte-jainak sz´am´at. P´eld´aul 4 word adat m´asol´asa eset´en az al´abb k´et k´odr´eszlet egyen´ert´ek˝u, de figyelj¨uk meg a k¨ul¨onb¨oz˝o CX e´ rt´ekeket: ... MOV CX, 4 REP MOVSW ... egyen´ert´ek˝u a k¨ovetkez˝o k´oddal: ... MOV CX, 8 REP MOVSB ... Ennek a prefixnek az a nagy el˝onye, hogy egyetlen utas´ıt´assal ak´ar eg´esz szegmenst a´ t lehet m´asolni (MOVSB), szegmensnyi adatokat o¨ ssze lehet hasonl´ıtani (CMPSB), fel¨ul lehet ´ırni (STOSB) vagy egy e´ rt´eket a szegmensben megkeresni (SCASB). Tov´abbi r´eszletek a 12. fejezetben tal´alhat´o. Ezzel a prefix-el sem lehet a szegmensek hat´ar´at a´ tl´epni. ´Igy p´eld´aul word adatokkal v´egzett m˝uveletek eset´en a 8086-os processzoron nincs e´ rtelme a 7FFFh e´ rt´ekn´el nagyobb e´ rt´eket adni a CX regiszternek a REP prefix eset´en. P´eld´ak Az al´abbbi k´odr´eszlet a´ tm´asol 4 word m´eret˝u adatot. A programr´eszlet egyen´ert´ek˝u a 7.6.1. bekezd´essben bemutatott p´eld´aval. forras: dw 1111h, 2222h, 3333h, 4444h cel: dw 0000h, 0000h, 0000h, 0000h ... MOV SI, forras MOV DI, cel MOV CX, 4 CLD REP MOVSW ...
76
7.6.7 REPZ Szintakszis REPZ string-utas´ ıt´ as REPE string-utas´ ıt´ as Ennek a prefixnek a neve az “REPeat while Zero” illetve “REPeat while Equal” kifejez´esekb˝ol sz´armazik. Ez a prefix is a CX regisztert haszn´alja, az e´ rt´ek´et cs¨okkenti am´ıg el nem e´ ri a z´erust. A prefix ezen k´ıv¨ul a Z´erus st´atusz bitet (ZF) is megvizsg´alja e´ s ha a bit e´ rt´eke z´erus (vagyis a m˝uvelet eredm´enye nem volt z´erus) akkor abbahagyja az utas´ıt´as ism´etl´es´et. Fontos, hogy a kil´ep´es ok´at a Z´erus (ZF) st´atusz bitb˝ol lehet megtudni. Ha az ism´etl´es az´ert a´ llt le, mert az utols´o m˝uvelet eredm´enye null´at´ol k¨ul¨onb¨oz¨ott, akkor a ZF e´ rt´eke z´erus lesz, ha pedig a CX regiszter lett z´erus, akkor a ZF e´ rt´eke egy lesz. ´ Erdekes, hogy a REPZ prefixnek e´ s REP prefixnek az oper´aci´o k´odja megegyezik. Ez azt jelenti, hogy a MOVS, LODS e´ s STOS utas´ıt´asok eset´en csak a REP prefixnek van e´ rteme. A SCAS e´ s CMPS utas´ıt´asok eset´en a prefix pedig mindig REPZ-nek felel meg. Ez az´ert van, mert a MOVS, LODS e´ s STOS utas´ıt´asok nem m´odos´ıtj´ak a st´atusz biteket, ´ıgy nem gond, hogy csak a REP prefixet lehet haszn´alni.
7.6.8 REPNZ Szintakszis REPNZ string-utas´ ıt´ as REPNE string-utas´ ıt´ as Ennek a prefixnek a neve az “REPeat while Non Zero” illetve “REPeat while Not Equal” kifejez´esekb˝ol sz´armazik. Ez a prefix is a CX regisztert haszn´alja, az e´ rt´ek´et cs¨okkenti am´ıg el nem e´ ri a z´erust. A prefix ezen k´ıv¨ul a Z´erus st´atusz bitet (ZF) is megvizsg´alja e´ s ha a bit e´ rt´eke egy (vagyis az utols´o m˝uvelet eredm´enye z´erus volt) akkor abbahagyja az utas´ıt´as ism´etl´es´et. Fontos, hogy a kil´ep´es ok´at a Z´erus (ZF) st´atusz bitb˝ol lehet megtudni. Ha az ism´etl´es az´ert a´ llt le, mert az utols´o m˝uvelet eredm´enye z´erus volt, akkor a ZF e´ rt´eke egy lesz, ha pedig a CX regiszter lett z´erus, akkor a ZF e´ rt´eke z´erus lesz.
77
7.7 Processzor vez´erl˝o utas´ıt´asok 7.7.1 CLC Szintakszis CLC Az utas´ıt´as angol neve: “CLear Carry”. Az utas´ıt´as null´ara a´ ll´ıtja a Carry st´atusz bit e´ rt´ek´et.
7.7.2 STC Szintakszis STC Az utas´ıt´as angol neve: “SeT Carry”. Az utas´ıt´as 1-re a´ ll´ıtja a Carry st´atusz bit e´ rt´ek´et.
7.7.3 CMC Szintakszis CMC Az utas´ıt´as angol neve: “CoMplement Carry”. Az utas´ıt´as null´ara a´ ll´ıtja a Carry st´atusz bit e´ rt´ek´et.
7.7.4 CLD Szintakszis CLD Az utas´ıt´as angol neve: “CLear Direction”. Az utas´ıt´as 0-ra a´ ll´ıtja a Direction (Ir´any) st´atusz bitet, aminek a string kezel˝o utas´ıt´asok eset´en van jelent˝os´ege. Ebben az esetben a MOVS, LODS, STOS, SCAS e´ s CMPS parancsok n¨ovelik a DI e´ s/vagy SI regiszter e´ rt´ek´et.
7.7.5 STD Szintakszis STD Az utas´ıt´as angol neve: “SeT Direction”. Az utas´ıt´as 1-re a´ ll´ıtja a Direction (Ir´any) st´atusz bitet, aminek a string kezel˝o utas´ıt´asok eset´en van jelent˝os´ege. Ebben az esetben a MOVS, LODS, STOS, SCAS e´ s CMPS parancsok cs¨okkentik a DI e´ s/vagy SI regiszter e´ rt´ek´et.
7.7.6 CLI Szintakszis CLI Az utas´ıt´as angol neve: “CLear Interrupt”. Az utas´ıt´as null´ara a´ ll´ıtja az Interrupt st´atusz bit e´ rt´ek´et. Ez az utas´ıt´as let´ıltja a hardware megszak´ıt´asok fogad´as´at.
78
7.7.7 STI Szintakszis STI Az utas´ıt´as angol neve: “SeT Interrupt”. Az utas´ıt´as 1-re a´ ll´ıtja az Interrupt st´atusz bit e´ rt´ek´et. Ez az utas´ıt´as enged´elyezi a hardware megszak´ıt´asok fogad´as´at.
79
7.8 Egy´eb utas´ıt´asok 7.8.1 NOP Szintakszis NOP Ez egy nagyon egyszer˝u utas´ıt´as, mivel nem csin´al semmit. Angol nev´en: “No OPeration”.
7.8.2 IN 7.8.3 OUT
80
7.9 Ellen˝orz˝o k´erd´esek 1. Tegy¨uk fel, hogy az Intel processzorokon nem lenne LDS utas´ıt´as. Hogyan implement´aln´a ezt az utas´ıt´ast? ´Irja le a k´odot ami egyen´ert´ek˝u az LDS utas´ıt´assal. 2. Tegy¨uk fel, hogy a k¨ovetkez˝o adatok vannak defini´alva: num1 DW 100 num2 DB 225 char1 DB ’Y’ num3 DD 0 ´ enyesek-e az al´abbi utas´ıt´asok: Erv´ (a) MOV AX, BX (b) MOV AX, num2 (c) MOV BL, num1 (d) MOV BL, [num1] (e) MOV DH, char1 (f) MOV char1, num2 (g) MOV [char1], [num2] (h) MOV IP, num1 (i) ADD 75, AX (j) CMP 75, AX (k) SUB char1, ’A’ (l) SUB [char1], ’A’ (m) XCHG AL, num2 (n) XCHG AL, [num2] (o) XCHG AL, 23d (p) XCHG AL, [23d] (q) INC num3 (r) INC [num3] 3. Az al´abbi k´odr´eszletekben a ‘MOV AX, 1’ vagy az ‘MOV BX, 1’ utas´ıt´as fog lefutni: (a)
(b)
mov CX,5 sub DX,DX cmp DX,CX jge jump1 mov BX,1 jmp skip1 jump1: mov AX,10 skip1: ... mov mov shr cmp
CX,5 DX,10 DX,1 CX,DX
81
je jump1 mov BX,1 jmp skip1 jump1: mov AX,10 skip1: ... 4. Magyar´azza el sz¨ovegesen, hogy mit csin´al a k¨ovetkez˝o k´od r´eszlet: (a) NOT AX ADD AX, 1 (b) NOT BX ADD BX, 1 (c) SUB SUB MOV ADD ADD ADD ADD
AH, DH, DL, DX, DX, DX, DX,
AH DH AL DX DX AX DX
(d) SUB SUB MOV MOV SHL SHL ADD
AH, DH, DL, CL, DX, AX, DX,
AH DH AL 3 CL 1 AX
5. Kell-e tudni az AX regiszter kezdeti tartalm´at ahhoz, hogy meg´allap´ıtsuk az AX regiszter tartalm´at az al´abbi k´odr´eszlet lefut´asa ut´an? Ha igen, magyar´azza meg mi´ert! Ha nem, magyar´azza el mi lesz az AX regiszter tartalma? (a) MOV DX, AX NOT AX OR AX, DX (b) MOV DX, AX NOT AX AND AX, DX
82
8. Fejezet
Assembly programokr´ol Tal´an csod´alkozunk, hogy az eddigi fejezetek mi´ert kellettek. Ahhoz, hogy assembly nyelven programot tudjunk ´ırni, sz¨uks´eges tudni: • a CPU regiszterek neveit • a verem hogyan m˝uk¨odik • hogyan l´epj¨unk ki • hogyan defini´aljunk szimb´olumokat, lok´alis e´ s glob´alis • hogyan haszn´aljuk az eszk¨oz¨oket (ford´ıt´okat, linkereket)
8.1 Programoz´asi m´odszer Az assembly programoz´asra jellemz˝o, hogy mindent explicit m´odon meg kell adni a programban. Nincsennek magas szint˝u programoz´asi konstrukci´ok, azokat magunknak kell l´etrehoznunk. A 8.1. t´abl´an l´athat´o egy el¨oltesztel˝o ciklus megval´os´ıt´asa. A t´abl´an l´athat´o hogyan “alakul a´ t” az el¨oltesztel˝o ciklus felt´eteles ugr´o utas´ıt´asokk´a, hiszen csak ezek a´ llnak rendelkez´esre az assembly programoz´asi nyelvben. Ugyanakkor az is l´athat´o, hogy a magas szint˝u programban a felt´etelben az szerepel, hogy ism´etelj¨uk meg az utas´ıt´asokat ha az AX regiszter nem egyenl˝o a z´erus e´ rt´ekkel. Ezzel szemben az assembly k´odban a felt´eteles ugr´as akkor ugrik a ciklus v´eg´ere, ha az utols´o m˝uveletben a z´erus st´atusz bit be lett a´ ll´ıtva, vagyis az o¨ sszehasonl´ıt´asn´al az AX regisztert z´erusnak tal´altuk. Vagyis a felt´etel megfordult az assembly k´odban. Val´oj´aban nem kell ennek ´ıgy lenni, lehet˝os´eg¨unk van arra, hogy ugyanazt a felt´etelt haszn´aljuk az assembly-ben, mint a magasabb szint˝u programoz´asi nyelvben. L´enyeg´eben arr´ol van sz´o, hogy a felt´eteles assembly utas´ıt´asok “megford´ıthat´ok”. Ez l´athat´o a 8.2. t´abl´an. ´Igy a program egy kicsit komplik´altabb. ujra: CMP AX, 0 JZ vege ... JMP ujra vege:
while(AX != 0) { ... }
8.1. t´abla: El¨oltesztel˝o ciklus megval´os´ıt´asa
83
ujra: CMP JNZ JMP tovabb: ... JMP vege:
while(AX != 0) { ... }
AX, 0 tovabb vege
ujra
8.2. t´abla: Alternat´ıv megval´os´ıt´asa az el¨oltesztel˝o ciklusnak
8.1. a´ bra: A megszak´ıt´asok oszt´alyoz´asa
8.2 Megszak´ıt´asok A megszak´ıt´as, vagy angol nev´en interrupt, egy mechanizmus ami a´ ltal a program v´egrehajt´as´anak folyamata megv´altozhat. Ilyen mechanizmus az ugr´o utas´ıt´asok e´ s ide tartozik a f¨uggv´eny is (l´asd 10. fejezet). L´enyeg´eben a megszak´ıt´as felf¨uggeszti a jelenlegi program fut´as´at e´ s a vez´erl´est a´ tadja egy megszak´ıt´as kezel˝onek (interrupt service routine, ISR). Amikor a megszak´ıt´as kezel˝o befejezte a m˝uveleteit, visszaadja a vez´erl´es arra a pontra, ahol a programot megszak´ıtottuk, u´ gy mintha a programot meg sem szak´ıtottuk volna. A f˝o k¨ul¨onbs´eg a f¨uggv´enyek e´ s a megszak´ıt´asok k¨oz¨ott, hogy a megszak´ıt´ast szoftver is megh´ıvhatja e´ s hardware esem´eny is kiv´althatja, m´ıg egy f¨uggv´enyt csak szoftver h´ıvhatja meg. Tulajdonk´eppen ez a k¨ul¨onbs´eg nagyon fontos, mivel amikor egy hardware-s esem´eny bek¨ovetkezik, akkor a hardware csak megszak´ıt´as seg´ıts´eg´evel tud a processzort´ol sz´am´ıt´asi id˝ot “szerezni”, hogy az adott esem´enyt lekezelj¨uk. ´Igy a megszak´ıt´asok egy hat´ekony lehet˝os´eget biztos´ıtanak nem v´art esem´enyek kezel´es´ere is. A m´asik nagyon fontos k¨ul¨onbs´eg a f¨uggv´enyek e´ s a megszak´ıt´asok k¨oz¨ott, hogy a megszak´ıt´as kezel˝ok mem´oria rezidensek (´alland´oan a mem´ori´aban vannak), m´ıg a f¨uggv´enyeket a programmal egy¨utt t¨olt¨unk be a mem´ori´aba csak egy “id˝ore”. A szoftveres megszak´ıt´asok “kiv´alt´as´ara” az INT utas´ıt´ast lehet haszn´alni. P´eld´aul amikor a felhaszn´al´ot´ol szeretn´enk egy karaktert beolvasni, akkor a megfelel˝o INT utas´ıt´as v´egrehajt´as´aval a megfelel˝o megszak´ıt´as indul el, amely a billenty˝uzetr˝ol beolvassa a karaktert. Val´oj´aban a szoftveres e´ s hardware-es magszak´ıt´asokon k´ıv˝ul van egy harmadik t´ıpus´u megszak´ıt´as is, az u´ gynevezett kiv´etelek (exception). A kiv´etelek az utas´ıt´as hib´akat kezelik, mint p´eld´aul a z´erussal val´o oszt´as. A 8.1. a´ bra mutatja a megszak´ıt´asok oszt´alyoz´as´at.
8.2.1 Hardware-es megszak´ıt´asok A hardware-es megszak´ıt´asok is k´et csoportba sorolhat´ok: • maszk´olhat´o e´ s
84
• nem maszkolhat´o hardware-es megszak´ıt´asok. A nem maszkolhat´o megszak´ıt´asokat (Non-maskable Interrupt, NMI) a processzor mindig azonnal kezeli. Ilyen megszak´ıt´as gener´al´odik p´eld´aul a RAM parit´as hiba eset´en ami mem´oria hib´at jel¨ol. A maszkolhat´o megszak´ıt´asok eset´en a megszak´ıt´as v´egrehajt´asa k´esleltethet˝o addig, am´ıg a v´egrehajt´as egy “kedvez˝obb” pontot e´ r el. A maszkolhat´o megszak´ıt´asok m˝uk¨od´es´ere a k¨ovetkez˝o p´eld´aval mutathat´o be. Egy program fut´asa sor´an egy megszak´ıt´as k¨ovetkezik be. Ekkor a program fut´asa felf¨uggeszt˝odik e´ s elindul a megszak´ıt´as kezel˝o fut´asa. Ha a megszak´ıt´as nem akarja, hogy egy u´ jabb megszak´ıt´as beavatkozhasson akkor a processzor maszkolhatja a megszak´ıt´asokat. Ha a megszak´ıt´asokat maszkoljuk, akkor egy u´ jabb megszak´ıt´asnak v´arnia kell. (Kiv´eve a nem maszkolhat´o megszak´ıt´asok!)
8.2.2 Megszak´ıt´asok 8086-os processzorokon Ez a fejezet csak a 8086-os processzorok megszak´ıt´as kezel´es´evel foglalkozik. Ez a modern processzorokon a “val´os mod´u” (real mode) megszak´ıt´as kezel´esnek felel meg. A “v´edett mod´u” (protected mode) megszak´ıt´as kezel´essel itt nem foglalkozunk. A processzor 256 megszak´ıt´ast t´amogat, amelyek sz´ama null´at´ol 255-ig tart. A megszak´ıt´as sz´ama nagyon fontos mivel ezzel azonos´ıthatjuk a megszak´ıt´asokat e´ s ez a sz´am a megszak´ıt´as t´abla index´et is megadja. A megszak´ıt´as t´abla a null´as fizikai c´ımen tal´alhat´o. A megszak´ıt´as t´abl´aban minden bejegyz´es 4 byte-b´ol a´ ll. Egy ilyen bejegyz´est megszak´ıt´as vektornak szoktunk nevezni. Egy bejegyz´es egy CS:IP regiszter p´arost ad meg, 2 byte a CS regiszternek e´ s 2 byte az IP regiszternek. Ezek ut´an ha egy megszak´ıt´as c´ım´et szeretn´enk megtal´alni a megszak´ıt´as t´abl´aban, akkor a megszak´ıt´as index´et szorozni kell 4-el e´ s a kapott hexadecim´alis sz´am adja meg az offszetet. P´eld´aul az INT 10h megszak´ıt´as c´ıme: 10h × 4 = 40h, ami a 0000:0040h c´ımnek felel meg. Ha m´ar ki tudjuk sz´amolni egy megszak´ıt´as c´ım´et, akkor az INT 10h megszak´ıt´ast m´ask´eppen is meg tudjuk h´ıvni: mov bx,0h mov es,bx mov bx,40h mov ah,0eh ; megszak´ ıt´ as param´ eterei mov al, 1 pushf call far es:[bx] popf R´eszletesen a k¨ovetkez˝o t¨ort´enik egy megszak´ıt´as v´egrehajt´asa sor´an: 1. El˝osz¨or a st´atusz biteket elmentj¨uk a vermen 2. T¨or¨olj¨uk a TRAP e´ s INTERRUPT st´atusz biteket, hogy m´as megszak´ıt´as ne szak´ıthassa meg az aktu´alis megszak´ıt´as kezel˝o v´egrehajt´as´at 3. A CS e´ s IP regisztereket felt¨oltj¨uk a veremre 4. A megszak´ıt´as t´abl´ab´ol bet¨oltj¨uk a CS regiszter e´ rt´ek´et: (index × 4) + 2 5. A megszak´ıt´as t´abl´ab´ol bet¨oltj¨uk az IP regiszter e´ rt´ek´et: (index × 4) 6. Megszak´ıt´as kezel´ese 7. Helyre´all´ıtjuk az IP regisztert a veremb˝ol
85
8.2. a´ bra: Kommunik´aci´os lehet˝os´egek alkalmaz´asok e´ s a hardware k¨oz¨ott 8. Helyre´all´ıtjuk a CS regisztert a veremb˝ol 9. Helyre´all´ıtjuk a st´atusz regisztert a veremb˝ol Az utols´o h´arom m˝uveletet az IRET utas´ıt´as v´egzi el
8.2.3 INT 21h megszak´ıt´as A szoftveres megszak´ıt´asokat az INT utas´ıt´as kiad´as´aval lehet elind´ıtani. A DOS rendszereken (l´enyeg´eben a Windows alatt is) az INT 21h szoftveres megszak´ıt´as nagyon sokf´ele szolg´altat´ast biztos´ıt a programoz´o sz´am´ara. A 8.2. a´ bra mutatja, hogy egy alkalmaz´asnak t¨obb lehet˝os´ege is a hardware eszk¨oz¨okkel val´o kommunik´aci´ora. A legmagasabb szint˝u szolg´altat´asokat az INT 21h adja, p´eld´aul file kezel´es. A BIOS szolg´altat´as azt jelenti, hogy olyan megszak´ıt´asokat h´ıvunk meg amelyek k¨ozvetlenebb¨ul kommunik´alnak a hardware-el. Ilyen megszak´ıt´as az INT 10h amelyik a grafikus megjelen´ıt˝o k´arty´aval e´ s az INT 16h amelyik a billenty˝uzettel kommunik´al. Egy harmadik lehet˝os´eg, amikor k¨ozvetlen¨ul egy porton kereszt¨ul k¨uld¨unk ki adatokat a hardware-re e´ s ugyan´ıgy a portb´ol olvasunk adatokat. Ez a legalacsonyabb szint˝u hardware vez´erl´es, amihez m´ar az adott hardware eszk¨oz k´ezik¨onyve is sz¨uks´eges, hiszen tudnunk kell, hogy milyen byte-okat k¨uldj¨unk, milyen sorrendben e´ s milyen id˝oz´ıt´essel.
8.2.4 Kiv´etelek A kiv´eteleket h´arom csoportja soroljuk: 1. faults (hib´ak), 2. traps (csapd´ak) e´ s 3. aborts (kil´ep´esek). A faults e´ s traps kiv´etelek utas´ıt´as hat´aron jelennek meg. A faults kiv´etelek az utas´ıt´as v´egrehajt´asa el˝otti a´ llapotot haszn´alj´ak a bek¨ovetkezt¨uk sor´an. Ilyen p´eld´aul a null´aval val´o oszt´as, ami a DIV e´ s IDIV utas´ıt´asok v´egrehajt´asa sor´an k¨ovetkezhet be. ´Igy ha ilyen hiba k¨ovetkezik be a kiv´etel a hiba v´egrehajt´asa el˝otti a´ llapotra fogja vissza´all´ıtani a processzort. M´asik tipikus fault kiv´etel a “segmentnot-present” hiba, ami azt jelenti, hogy az adott szegmens nincs a mem´ori´aban. A hiba bek¨ovetkezte ut´an a hi´anyz´o szegmenst be kell t¨olteni e´ s a program v´egrehajt´asa ezut´an folytat´odhat. Itt is az utas´ıt´as
86
el˝otti a´ llapott´ol folytat´odik a v´egrehajt´as, hiszen az utas´ıt´ashoz sz¨uks´eges szegmens m´ar jelen van a mem´or´aban e´ s ´ıgy u´ jra v´egrehajthat´o az utas´ıt´as. Traps kiv´etelek ezzel szemben az utas´ıt´ast k¨ovet˝o “hat´aron” hajt´odnak v´egre, vagyis ebben az esetben nincs utas´ıt´as u´ jrav´egrehajt´as. P´eld´aul a t´ulcsordul´as (overflow) megszak´ıt´as egy ilyen trap-nek felel meg. A felhaszn´al´o a´ ltal defini´alt megszak´ıt´asok is trap-nek felelnek meg. Az abort megszak´ıt´asok hib´akat jelentenek, p´eld´aul hardware hib´akat vagy nem konzisztens rendszer t´abl´akr´ol jelentenek a felhaszn´al´o fel´e.
8.3 Kit´er˝o Linux-ra B´ar eddig nem sok sz´o esett a Linuxr´ol de egy r¨ovid bekezd´esig itt megeml´ıten´em. A Linux rendszer nagyon sok szolg´altat´ast biztos´ıt a 80h megszak´ıt´ason kereszt¨ul. Val´oj´aban 180 k¨ul¨onb¨oz˝o rendszer h´ıv´ast biztos´ıt ez a megszak´ıt´as. A szolg´altat´ast itt is az EAX regiszter e´ rt´ek´evel lehet be´all´ıtani.
8.4 COM programok A DOS 1.0 ”oper´aci´os rendszer” csak COM t´ıpus´u programokat haszn´alt. Az ut´ana k¨ovetkez˝o DOS 2.0 sor´an vezett´ek csak be az EXE programokat. A DOS 1.0 rendszer alatt egy igen egyszer˝u szab´aly szerint m˝uk¨odtek a programok: miut´an elindult a program a teljes mem´ori´at kezelhette a program. Ebben az id˝oben az ”oper´aci´os rendszer” m´eg nem haszn´alt mem´oria menedzsel´est (memory management), ´ıgy egy program b´armit csin´alhatott a teljes mem´ori´aban. Az ”oper´aci´os rendszer” csak azt tartotta nyilv´an, hogy hol van az els˝o szabad hely ahova a k¨ovetkez˝o programot bet¨oltheti. Amikor a DOS egy u´ j programot akart elind´ıtani, akkor el˝ok´esz´ıtett egy speci´alis ter¨uletet a program sz´am´ara a szabad ter¨ulet els˝o 256 byte-nyi hely´en. A speci´alis ter¨ulet neve: Program Segment Prefix (PSP). Az el˝ok´esz´ıt´es ut´an a DOS egyszer˝uen bet¨olt¨otte a programot a 256 byte-nyi PSP ut´ani ter¨uletre. Mindenf´ele ellen˝orz´es e´ s tov´abbi feldolgoz´as n´elk¨ul. A bet¨olt´es ut´an m´eg egy-k´et regisztert el˝ok´esz´ıtett a rendszer, be´all´ıtott egy visszat´er´esi c´ımet, majd a program elej´ere ugorva elind´ıtotta azt. Mivel 256 byte egyenl˝o 100h hexadecim´alis e´ rt´ekkel ez´ert van az, hogy a COM programok a 100h c´ımen kezd˝odnek. Mindig! A DOS a´ ltal elv´egzett be´all´ıt´asok egy COM programhoz: • A CS, DS, ES, SS regisztereket be´all´ıtja a PSP elej´ere. • Az IP regiszternek a 100h e´ rt´eket adja, ahol majd a program fut´asa elkezd˝odik. • Az SP regiszter a verem tetej´ere van a´ ll´ıtva. Ez a´ ltal´aban az FFFEh e´ rt´eknek felel meg. (Ez a szegmens tetej´enek c´ıme.) • A BX:CX regiszter p´ar a COM program m´eret´et fogja t¨ukr¨ozni. A BX regiszter a 32 bites e´ rt´eknek a fels˝o 16 bitj´et m´ıg a CX az als´o 16 bitj´et t´arolja. ´Igy egy 256d byte m´eret˝u program eset´en:
BX = 0000h CX = 0100h • Az AX, DX, SI e´ s DI regiszterek e´ rt´eke z´erus lesz.
87
8.4.1 Program Segment Prefix
8.5 EXE programok 8.6 XOR haszn´alata 8.7 Assembly integer aritmetika 8.7.1 BCD aritmetika
88
8.8 Ellen˝orz˝o k´erd´esek 1. Mik a k¨ul¨onbs´egek f¨uggv´enyek e´ s megszak´ıt´asok k¨oz¨ott? 2. Amikor egy megszak´ıt´as v´egrehajt´odik, akkor a st´atusz bitek automatikusan elment˝odnek. Ugyanakkor egy f¨uggv´enyh´ıv´as sor´an a st´atusz bitek nem ment˝odnek el automatikusan. Magyar´azza meg mi´ert van ez ´ıgy? 3. Hogyan lehet “kikapcsolni” a maszkolhat´o megszak´ıt´asokat? 4. Hogyan csoportos´ıtjuk a megszak´ıt´asokat?
89
90
9. Fejezet
P´elda programok Ebben a fejezetben n´eh´any p´elda program ker¨ul bemutat´asra, melyek rem´elhet˝oleg el˝oseg´ıtik az assembly programoz´as elsaj´at´ıt´as´at. A programok nincsennek optimaliz´alva e´ s ebben a fejezetben a lehet˝o legegyszer˝ubb v´altozatban ker¨ulnek bemutat´asra. A k´es˝obbi fejezetek a´ tolvas´asa ut´an arra biztatn´am az olvas´ot, hogy t´erjen vissza ezekhez a programokhoz e´ s pr´ob´alja meg o˝ ket a´ talak´ıtani, r¨ovidebb, m´as m´odon is meg´ırni.
9.1 Egy byte bin´aris kinyomtat´asa Ez a program egy szok´asos gyakorlat az assembly nyelv tanul´as sor´an. A program azt mutatja be, hogy egy byte hogyan e´ p¨ul fel bitekb˝ol, e´ s a biteket hogyan lehet megfelel˝o sorrendben kinyomtatni. A 9.1. t´abla mutatja a program list´aj´at. 1 org 100h 2 MOV BL, [adat] 3 MOV AH, 02 4 MOV CX, 0008 5 ujra: 6 MOV DL, 0 7 RCL BL, 1 8 ADC DL, 30h 9 INT 21h 10 LOOP ujra 11 INT 20h 12 adat: 13 db 10100011b
9.1. t´abla: Egy byte bin´aris kinyomtat´as´ara szolg´al´o program A 2. sorban bet¨oltj¨uk az adat c´ım alatt t´arolt e´ rt´eket. Az adat a program v´eg´en van t´arolva e´ s bin´aris form´atumban van megadva. A 3. sorban el˝ok´esz´ıtj¨uk a nyomtat´ast, vagyis megadjuk az INT 21h megszak´ıt´as funkci´o k´odj´at. A 4. sorban a CX regiszterbe bet¨olt¨unk 8-at, mivel egy byte-ban 8 bit van e´ s a nyomtat´ast nyolcszor kell megism´etelni, vagyis nyolcszor kell 1-et vagy 0-´at nyomtatni. Mivel egy karaktert fogunk kinyomtatni, ez´ert a nyomtatand´o karakternek v´eg¨ul a DL regiszterben kell lennie, ´ıgy a 6. sorban null´aval inicializ´aljuk a DL regisztert. A 7. sorban az RCL utas´ıt´ast haszn´aljuk (L´asd 7.3.1. fejezet). Mi´ert? El˝osz¨or is az L bet˝u az utas´ıt´as nev´enek v´eg´en azt jelenti, hogy balra
91
L´ep´es Kezdeti 1. 2. 3. 4. 5. 6. 7. 8.
CF ?? 1 1 0 1 0 1 1 0
128 1 1 0 1 0 1 1 0 ??
64 1 0 1 0 1 1 0 ?? 1
32 0 1 0 1 1 0 ?? 1 1
Byte 16 8 1 0 0 1 1 1 1 0 0 ?? ?? 1 1 1 1 0 0 1
4 1 1 0 ?? 1 1 0 1 0
2 1 0 ?? 1 1 0 1 0 1
1 0 ?? 1 1 0 1 0 1 1
9.2. t´abla: Egy byte balra forgat´asa a Carry biten kereszt¨ul v´egezz¨uk a bit l´eptet´est vagy bit forgt´ast. Ez az´ert fontos, mert a legmagasabb helyi´ert´ek˝u bit a byte bal oldal´an tal´alhat´o (l´asd ??. a´ bra) e´ s a k´eperny˝ore is balr´ol-jobbra v´egezz¨uk a nyomtat´ast, vagyis el˝osz¨or a legmagasabb helyi´ert´ek˝u bitet kell kinyomtatni. Ha megn´ezz¨uk a 7.1. vagy 7.5. a´ br´akat, akkor azt l´atjuk, hogy egy l´eptet´es vagy forgat´as sor´an a legmagasabb helyi´ert´ek˝u bit a Carry bitbe ker¨ul. A Carry bitet a CF doboz jel¨oli. Amikor egy bitet ilyen m´odon bet¨olt¨unk a Carry bitbe, akkor k´es˝obb haszn´alhatjuk ezt a bitet egy felt´eteles ugr´asn´al, l´asd JC (7.5.2. fejezet) e´ s JNC (7.5.2. fejezet) utas´ıt´asokat. Ugyanakkor ebben a programban a Carry bitet m´ask´epp haszn´aljuk. A programnak v´eg¨ul vagy az ‘0’ vagy a ‘1’ karaktert kell kinyomtatnia amelyek ASCII k´odja 30h e´ s 31h. Ez azt jelenti, hogy a DL regiszterhez hozz´a kell adni 30h e´ s m´eg a Carry bit e´ rt´ek´et. Erre szerencs´ere van k¨ul¨on utas´ıt´as, az ADC utas´ıt´as (l´asd 7.2.4. fejezetet). Mivel ez az utas´ıt´as hozz´aadja az e´ rt´ekeket a DL regiszterhez, ez´ert kellett a 6. sorban null´at t¨olteni a DL regiszterbe. V´eg¨ul a 9. sorban az INT 21h megszak´ıt´as seg´ıts´eg´evel kinyomtatjuk a karaktert. A 10. sorban a LOOP utas´ıt´as (l´asd 7.5.4.fejezet) cs¨okkenti a CX regiszter tartalm´at eggyel e´ s ha a CX regiszter e´ rt´eke nem z´erus, akkor a megadott c´ımre ugrik. Ez azt jelenti, hogy a legbaloldalibb bit nyomtat´asa ut´an ism´et a legbaloldalibb bitet fogja nyomtatni, hiszen a byte-ot mindig balra forgatjuk. A 9.2. t´abl´azat mutat egy p´eld´at arra, hogy hogyan alakul a byte e´ s a Carry bit e´ rt´eke az egyes l´ep´esek, forgat´as sor´an.
92
9.2 Egy hexadecim´alis sz´am kinyomtat´asa Egy hexadecim´alis sz´am 0 e´ s 16 k¨oz¨otti e´ rt´ek lehet. Ezeket az e´ rt´ekeket 4 biten lehet reprezent´alni, ´ıgy ez a program csak egy byte (8 bit) fel´et tudja kinyomtatni. A hexadecim´alis sz´amrendszerben 16 sz´amjegy van: • 0 - 9 sz´amjegyek ASCII k´odja: 30h - 39h • A - F sz´amjegyek ASCII k´odja: 41h - 46h A programban felt´etelezz¨uk, hogy a hexadecim´alis sz´am a BL 8 bites regiszterben van elt´arolva. Ez azt jelenti, hogy a byte e´ rt´eket meg kell vizsg´alni, hogy a fenti tartom´anyokb´ol melyikbe esik e´ s aszerint kell hozz´aadni a megfelel˝o e´ rt´eket, hogy sz´amjegy ASCII k´odj´at kapjuk meg. A pszeudo k´odban az algoritmus a k¨ovetkez˝ok´eppen n´ez ki: IF BL < 0Ah THEN BL = BL + 30h ELSE BL = BL + 37h Ez azt jelenti, hogy ha a BL regiszter tartalma kisebb mint 10, akkor csak 30h e´ rt´ekkel kell m´odos´ıtani, egy´ebk´ent 37h e´ rt´eket kell a BL regiszter tartalm´ahoz hozz´aadni. B´ar az assembly programoz´asi nyelvben megval´os´ıthat´o a felt´eteles utas´ıt´as, de k¨ozvetlen ELSE a´ g nincs. (Az ELSE a´ gba es˝o utas´ıt´asok akkor hajt´odnak v´egre, ha a felt´etel hamis volt.) Ennek k¨ovetkezt´eben a k´odot egy kicsit a´ t kell szervezni, ami pszeudo k´odban ez lesz: BL = BL + 30h IF BL >= 03Ah THEN BL = BL + 07h Az el˝oz˝o v´altozatban 30h vagy 37h e´ rt´eket kellett a regiszterhez hozz´aadni, ´ıgy ebben a v´altozatban 30h-at mindenk´eppen hozz´aadunk e´ s 07h-et m´ar csak akkor kell hozz´aadni, ha a kapott e´ rt´ek nagyobb vagy egyenl˝o mint 3Ah. (Sz´amoljuk v´egig, hogy a nulla sz´am ASCII karakter´enek sz´ama 30h, az egy sz´am´e 31h e´ s ´ıgy tov´abb. V´eg¨ul a kilences sz´am karakter´enek sz´ama 39h, vagyis a 3Ah m´ar a tizes sz´amjegynek felelne meg, de a tizes sz´amjegyet m´ar az A bet˝u jel¨oli aminek az ASCII k´odja m´ar 41h.) Az assembly program list´aja az 9.3. t´abl´an l´athat´o. A hexadecim´alis e´ rt´ek a programban van defini´alva a szam c´ımen, e´ s ezt az e´ rt´eket t¨oltj¨uk be a BL regiszterbe. A program v´eg¨ul kinyomtatja a hexadecim´alis sz´amjegyet, ebben az esetben a B bet˝ut. Az 9.3. t´abl´an l´athat´o programban a m´asodik sorban a BL regiszterbe t¨oltj¨uk a szam c´ımen t´arolt byte e´ rt´eket. A harmadik sorban az AH regiszterbe a 2-es e´ rt´eket t¨oltj¨uk. Ennek az e´ rt´eknek csa k´es˝obb van jelent˝os´ege de mivel a k´es˝obbi utas´ıt´asok nem m´odos´ıtj´ak az AH regiszter tartalm´at ez´ert itt is nyugodtan be´all´ıthatjuk ezt az e´ rt´ek´et. A negyedik sorban a BL regiszter tartalm´at a´ tm´asoljuk a DL regiszterbe. Most m´ar felt˝unhet, hogy val´oj´aban arra t¨oreksz¨unk, hogy a program v´eg´en az INT 21h megszak´ıt´ast haszn´aljuk a karakter kinyomtat´as´ara. (Ha egy karaktert akarunk kinyomtatni a INT 21h megszak´ıt´assal, akkor az AH adja meg a funkc´o k´odot – 02h – e´ s a DL regiszter fogja tartalmazni a kinyomtatand´o karakter ASCII k´odj´at. L´asd 6.2. bekezd´est.) Az 5-8 sorok val´os´ıtj´ak meg az el˝obb t´argyalt pszeudo k´odot. El˝osz¨or a DL regiszterhez hozz´aadunk 30h e´ rt´eket, majd az ´ıgy kapott e´ rt´eket a k¨ovetkez˝o sorban o¨ sszehasonl´ıtjuk a 3Ah e´ rt´ekkel. A CMP utas´ıt´as csak o¨ sszehasonl´ıt´ast v´egez e´ s be´all´ıtja a st´atusz regisztert. A JL utas´ıt´as a felt´eteles ugr´as e´ s a st´atusz bitek e´ rt´ek´et˝ol f¨ugg˝oen folytat´odik a v´egrehajt´es. Ez aztjelenti, hogy ha a DL regiszter e´ rt´eke kisebb mint 3Ah akkor a´ tugorjuk a 8. sort. Ha nagyobb, akkkor a 8. sorban folytat´odik a v´egrehajt´as e´ s m´eg hozz´aadunk 7-et, hogy az A karakter ASCII k´odj´at´olindul´o e´ rt´ekeket kapjunk. A karakter kinyomtat´asa a 10. sorban t¨ort´enik az INT 21h megszak´ıt´assal.
93
1 org 100h 2 MOV BL, [szam] 3 MOV AH, 02 4 MOV DL, BL 5 ADD DL, 30h 6 CMP DL, 3ah 7 JL szamjegy 8 ADD DL, 07 9 szamjegy: 10 INT 21h 11 INT 20h 12 szam: 13 db 0bh
; DL < 3ah
9.3. t´abla: Egy hexadecim´alis sz´am kinyomtat´as´ara szolg´al´o program
94
9.3 Egy byte hexadecim´alis kinyomtat´asa Ez a program annyiban k¨ul¨onb¨ozik az el˝oz˝o programt´ol, hogy ez a program 2 hexadecim´alis sz´amot fog kinyomtatni. Mi´ert? Egy byte 8 bitet vagy k´etszer 4 bitet tartalmaz. 4 biten pedig pontosan 16 f´ele sz´amot lehet a´ br´azolni ami megfelel egy hexadecim´alis sz´amjegynek. B´ar mostanra m´ar egy´ertelm˝unek kell lennie hogyan lehet 4 biten 16 sz´amot a´ br´azolni, de a teljess´eg kedv´ee´ rt a 9.4. t´abl´azat felsorolja a 4 biten t´arolhat´o sz´amokat decim´alis e´ s bin´aris alakban. Ez azt jelenti, hogy egy byte-ban az als´o n´egy bit e´ s a fels˝o n´egy bit is megfelel egy hexadecim´alis sz´amjegynek, vagyis ha egy byte-ot headecim´alisan akarunk kinyomtatni, akkor k´et hexadecim´alis sz´amjegyet kell kinyomtatni. A 9.5. t´abla tartalmazza az assembly program list´aj´at. Ez a program a 9.3. programot k´etszer tartalmazza. (Igaz´ab´ol f¨uggv´enyeket kellene haszn´alni, hogy kevesebb legyen a k´od ism´etl´es, de a f¨uggv´enyekr˝ol majd a 10. fejezetben tanulunk.) Az extra utas´ıt´asok a 9.5. t´abl´an l´athat´o programhoz k´epest azt biztos´ıtj´ak, hogy mindig az als´o 4 bit tartalmazza a hexadecim´alis sz´amot e´ s a fels˝o 4 bit pedig mindig z´erus legyen! A m´asodik sorban bet¨oltj¨uk a byte-ot a BL regiszterbe, majd a harmadik sorban az INT 21h megszak´ıt´as funkci´o k´odj´at a´ ll´ıtjuk be az AH regizterben. Mivel k´etszer kell kezeln¨unk a BL regisztert (als´o e´ s fels˝o n´egy bit) ez´ert az eredeti e´ rt´eket a BL regiszterben t´aroljuk e´ s majd a DL regisztert m´odos´ıtjuk. Ez´ert a BL regiszter tartalm´at a´ tm´asoljuk a DL regiszterbe a 4. sorban. Mivel a sz´amokat balr´ol jobbra ´ırjuk, ez´ert el˝osz¨or a magasabb helyi´ert´ek˝u biteket kell figyelembe venni, vagyis a fels˝o 4 bitnek megfelel˝o sz´amot kell kinyomtatni. B´ar ez igaz, de azt is figyelembe kell venni, hogy a 9.3. program az als´o n´egy bittel dolgozott. Ez´ert nincs m´as teend˝onk, mint a fels˝o n´egy bitet “eltolni” az als´o n´egy bitbe. Sokf´elek´eppen lehet ezt megtenni, de a legegyszer˝ubb bitl´eptet˝o utas´ıt´ast haszn´alni. A bitl´eptet˝o utas´ıt´asok k¨oz¨ul az SHR utas´ıt´as diagramja a 7.7. a´ br´an l´athat´o. Fontos, hogy ez az utas´ıt´as a jobbra l´eptet´es sor´an balr´ol null´akat l´eptet be, vagyis a fels˝o 4 bitet lenull´azza. Miut´an az als´o 4 biten van a kinyomtatand´o hexadecim´alis sz´amjegy, a 9.3. programot lehet haszn´alni a nyomtat´asra. (A 9.3. program jel¨olve van a 9.5 t´abl´an.) A 13. sorban helyre´all´ıtjuk a DL regiszter e´ rt´ek´et a BL regiszterb˝ol. (Itt kell megjegyezni, hogy term´eszetesen a szam cimr˝ol u´ jra bet¨olthetn´enk az e´ rt´eket, de itt n´eh´any o´ rajel ciklust megtakar´ıtva a BL regisztert haszn´aljuk mint gyors, id˝oleges t´arol´ohely. Ha valami´ert m´egis sz¨uks´eg¨unk lenne a BX regiszterre a programban, p´eld´aul c´ımz´esn´el, akkor term´eszetesen c´elszer˝ubb lenne a szam c´ımr˝ol bet¨olteni az e´ rt´eket a DL regiszterbe.) A m´asodik sz´am kinyomtat´as´an´al csak az als´o 4 bitre van sz¨uks´eg¨unk. Igen a´ m, de figyelni kell arra, hogy a fels˝o 4 bit is ott van byte-ban. A 9.3. program felt´etelezi, hogy a fels˝o 4 bit z´erus. Ennek el´er´es´ere “maszkol´ast” fogunk haszn´alni, vagyis a fels˝o 4 bitet ki kell null´azni, u´ gy hogy az als´o 4 bit e´ rt´eke ne v´altozzon. A maszkol´as a 14. sorban az AND utas´ıt´assal val´os´ıtsjuk meg. A 0Fh hexadecim´alis sz´am bin´arisan 00001111b e´ s ezt haszn´aljuk az AND utas´ıt´assal, vagyis ahol a bit e´ rt´eke 1 ott a DL regiszter tartalma v´altozatlan marad, ahol pedig nulla, ott a DL regiszter bitje biztos hogy z´erus lesz. (Ez el´eg egyszer˝uen bel´athat´o, ha megn´ezz¨uk az AND utas´ıt´as igazs´ag t´abl´aj´at, l´asd 7.2. t´abla.) Miut´an a DL regiszter megfelel˝oen be van a´ ll´ıtva, nincs m´as h´atra mint kinyomtatni a 9.3. program szerint. Ez is jel¨olve van a 9.5. t´abl´an.)
95
Decim´alis 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Bin´aris 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
9.4. t´abla: 4 biten a´ br´azolhat´o sz´amok bin´aris alakban
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
org 100h MOV BL, [szam] MOV AH, 02 MOV DL, BL MOV CL, 4 SHR DL, CL ; ADD DL, 30h ; CMP DL, 3ah ; JL szam1 ; ADD DL, 07 ; szam1: ; INT 21h ; MOV DL, BL ; AND DL, 0Fh ; ADD DL, 30h ; CMP DL, 3ah ; JL szam2 ; ADD DL, 07 ; szam2: ; INT 21h ; INT 20h szam: db 0FFh
bit l´ eptet´ es jobbra --| | | elozo program | | --| DL helyreallitasa maszkol´ as --| | | elozo program | | --|
9.5. t´abla: Egy byte hexadecim´alis form´atum´u kinyomtat´as´ara szolg´al´o program
96
9.4 Egy decim´alis sz´amjegy ellen˝orz¨ott beolvas´asa e´ s kinyomtat´asa A 9.6. program azt mutatja be, hogyan lehet megvizsg´alni, hogy a beolvasott karakter sz´amjegy-e. Az e´ rv´enyes karakterek tartom´anya: 0-9, melyek ASCII k´odja egym´as ut´ani az ASCII t´abl´aban, l´asd A.1. t´abl´azat. B´ar a program sz´amjegyeket fogad csak el, term´eszetesen a programot k¨onny˝u u´ gy a´ t´ırni, hogy m´as, egym´as ut´ani karaktereket fogadjon el. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
org 100h ujra: MOV MOV INT MOV INT CMP JB CMP JA MOV MOV INT INT
AH, 9 DX, uzenet 21h AH,1 21h ; beolvasott karakter AL-ben AL, ’0’ ; also korlat hiba AL, ’9’ ; felso korlat hiba DL, AL ; nyomtatas elokeszitese AH, 2 21h 20h
MOV MOV INT JMP
DX, hiba_str AH, 9 21h ujra
hiba:
uzenet: db 0Dh,0Ah,’Adjon meg egy szamot: $’ hiba_str: db 0Dh,0Ah,’Ervenytelen karakter!$’
9.6. t´abla: Egy sz´amjegy beolvas´asa e´ s kinyomtat´asa. A 3-5. sorokban egy u¨ zenetet ´ırunk ki a k´eperny˝ore a felhaszn´al´o sz´am´ara. A 6. e´ s 7. sorban a INT 21h megszak´ıt´ast haszn´aljuk, hogy egy karaktert beolvassunk a felhaszn´al´ot´ol. A beolvasott karakter az AL regiszterbe ker¨ul. A 8. sorban az AL regiszter tartalm´at o¨ sszehasonl´ıtjuk a ‘0’ karakter ASCII k´odj´aval. A CMP utast´as be´all´ıtja a st´atusz regiszter bitjeit a k´et e´ rt´ek egym´ashoz val´o viszonya alapj´an. Ezeknek a biteknek az a´ llapot´at vizsg´alja meg a 9. sorban a JB utas´ıt´as e´ s ha az AL regiszter tartalma kisebb mint a ‘0’ karakter ASCII k´odja, akkor a hiba c´ımre ugrik a program. Ellenkez˝o esetben a k¨ovetkez˝o, 10., sorban folytat´odik a program. A 10. e´ s 11. sorban az AL regiszter tartalm´at a ‘9’ karakter ASCII k´odj´aval hasonl´ıtjuk o¨ ssze e´ s ha az AL regiszter tartalma nagyobb akkor szint´en a hiba c´ımre ugrik a program. Ha az AL regiszter tartalma a megfelel˝o tartom´anyban van, akkor a program a 12. sorban folytat´odik. A 12-14. sorok k¨oz¨ott csak annyi t¨ort´enik, hogy a megfelel˝o regiszterek tartalm´at be´all´ıtjuk, olyan m´odon, hogy egy karaktert ki tudjunk nyomtatni a k´eperny˝ore. A 15. sorban kil´ep¨unk a programb´ol. A 16-19 sorok k¨oz¨otti utas´ıt´asok egy hiba u¨ zenetet ´ırnak ki a k´eperny˝ore. A 20. sorban egy felt´etel n´elk¨uli ugr´assal a program elej´ere ugrunk, hogy u´ jra be lehessen olvasni egy karaktert. A 22. e´ s 24. ssorban a karaktersorozat elej´en a 0Dh e´ s 0Ah byte-ok az´ert vannak megadva, hogy egy “sort emeljenek a k´eperny˝on”, vagyis a k¨ovetkez˝o sorba nyomtassuk ki a sz¨oveget. (Pr´ob´aljuk ki a programot u´ gy, hogy ezeket a byte-okat kit¨or¨olj¨uk.)
97
9.5 Egy karakter beolvas´asa e´ s m´odos´ıt´asa Ez a program egy karaktert olvas be e´ s az ut´ana k¨ovetkez˝o karaktert nyomtatja ki. Az “a” bet˝u helyett a “b” bet˝ut, a “b” bet˝u helyett a “c” be˝ut e´ s ´ıgy tov´abb. 1 2 3 4 5 6 7 8
org 100h MOV AH, 1 INT 21h MOV DL, AL INC DL MOV AH, 2 INT 21h INT 20h
9.7. t´abla: Egy karakter beolvas´asa e´ s az ut´ana k¨ovetkez˝o kinyomtat´asa. A fenti programban semmilyen ellen˝orz´es nincs ´ıgy a programot most kieg´esz´ıtj¨uk annak vizsg´alatval hogy a bolvasott karakter t´enyleg kis bet˝u-e. A programnak van m´eg egy “rejtett” hib´aja: Mi t¨ort´enik ha a “z” bet˝ut adjuk meg? Mivel a karakter sz´amszer˝u e´ rt´ek´ehez hozz´aadunk egyet e´ s a “z” bet˝u ASCII k´odja (ASCII sz´ama) 122 decim´alis vagy 7A hexadecim´alis ez´ert a program a 123-as ASCII k´od´u karaktert nyomtatja ki, a “{ karaktert. A 9.8. program ezt a probl´em´at is kijav´ıtja.
98
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
org 100h MOV AH, 1 INT 21h MOV DL, AL CMP DL, ’a’ JB nem_betu CMP DL, ’z’ JA nem_betu JNE novel MOV DL, ’a’ JMP nyomtat novel: INC DL nyomtat: MOV AH, 2 INT 21h vege: INT 20h nem_betu: MOV AH, 9 MOV DX, nem_betu_szoveg INT 21h JMP vege nem_betu_szoveg: db 10,13,’Nem betut adtal meg!$’
9.8. t´abla: Egy karakter beolvas´asa e´ s az ut´ana k¨ovetkez˝o kinyomtat´asa.
99
¨ karakter bolvas´asa e´ s kinyomtat´asa ford´ıtott sorrendben 9.6 Ot A 9.9. t´abl´an l´athat´o program beolvas o¨ t karaktert, ezeket elt´arolja, majd ford´ıtott sorrendben kinyomtatja a beolvasott karaktereket. A program j´o p´elda az regiszteres c´ımz´esre. (A c´ımz´esi m´odokat a 3.3. fejezet t´argyalja.) A 2. sorban a CX regiszter e´ rt´ek´et 5-re a´ ll´ıtjuk, mivel egy ciklusban fogjuk beolvasni a karaktereket e´ s a CX regiszter lesz a ciklus v´altoz´o. A 3. sorban a DI regiszterbe a t´arol´asra haszn´alt hely c´ım´et t¨oltj¨uk be. Az 5. e´ s 6. sorban az INT 21h megszak´ıt´assal beolvasunk egy karaktert az AL regiszterbe. A 7. sorban elt´aroljuk a beolvasott karaktert a DI regiszter a´ ltal megadott c´ımre. (B´ar nincs megadva szegmens regiszter, de adat eset´en automatikusan felt´etelezhetj¨uk a DS szegmens regisztert, ´ıgy a 7. sor a k¨ovetkez˝o is lehetne: MOV [DS:DI], AL A 8. sorban a DI regiszter e´ rt´ek´et 1-el n¨ovelj¨uk meg, mivel minden karakter 1 byte m´eret˝u, ´ıgy a k¨ovetkez˝o karaktert majd a k¨ovetkez˝o byte-on kell elt´arolni. A 9. sorban tal´alhat´o LOOP utas´ıt´assal val´os´ıtjuk meg a ciklust. Az utas´ıt´as cs¨okkenti a CX regiszter e´ rt´ek´et 1-el e´ s ha a regiszter nem nulla, akkor a megadott c´ımre ugrik, jelen esetben u´ jabb karaktert olvas be. A ciklus v´eg´en a 10. sor fog v´egrehajt´odni, ahol a DI regiszter e´ rt´ek´et 1-el cs¨okkentj¨uk. Erre az´ert van sz¨uks´eg, mert az 5. karakter elt´arol´asa ut´an is megn¨ovelj¨uk a DI regiszter tartalm´at, ´ıgy az m´ar egy hatodik karakterre mutatna, ami nem defini´alt a programban. ´Igy a 10. sorban v´egrehajtott cs¨okkent´es ut´an a DI regiszter megint az 5. karakterre fog mutatni, amit majd kinyomtatunk el˝osz¨or. A 11. sorban ism´et a ciklus v´altoz´ot a´ ll´ıtjuk be, m´ıg a 12. sorban az INT 21h megszak´ıt´as funkci´ok´odj´at adjuk meg. A cikluson bel¨ul a 14. sorban a DL regiszterbe t¨oltj¨uk be a karaktert amit a 15. sorban nyomtatunk ki. A 16. sorban a DI regisztert ism´et cs¨okkentj¨uk, mivel ford´ıtott sorrendben akarjuk kinyomtatni a karaktereket mint ahogy beolvastuk o˝ ket. A ciklust itt is a LOOP utas´ıt´assal val´os´ıtjuk meg. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
org 100h MOV CX, 5 MOV DI, karakterek ujra: MOV AH, 1 INT 21h MOV [DI], AL INC DI LOOP ujra DEC DI MOV CX, 5 MOV AH, 2 nyomtat: MOV DL, [DI] INT 21h DEC DI LOOP nyomtat INT 20h karakterek: db 0,0,0,0,0
¨ karakter beolvas´asa e´ s kinyomtat´asa ford´ıtott sorrendben. 9.9. t´abla: Ot
100
9.7 K´et egyjegyu˝ sz´am o¨ sszead´asa A 9.10. program beolvas k´et decim´alis sz´amjegyet, o¨ sszeadja o˝ ket, majd az eredm´enynek megfelel˝o sz´am´u csillag (‘*’) karaktert nyomtat ki. A programban a sz´amjegyek beolvas´asa k´etszer szerepel. A k´od ism´etl´es elker¨ul´es´ere a legjobb lenne f¨uggv´enyt haszn´alni, de err˝ol csak k´es˝obb lesz sz´o a 10. fejezetben. Az els˝o beolvasott sz´amot a CL regiszterben t´aroljuk el a 13. sorban. A m´asodik beolvasott sz´amjegy az AL regiszterben alakul ki a 24. sorban. A 25. sorban o¨ sszeadjuk a k´et sz´amot e´ s az eredm´enyt a CL regiszterben t´aroljuk el. A 26. sorban a CH regisztert kinull´azzuk, hogy a teljes CX regiszter tartalmazza az eredm´enyt e´ s a LOOP utas´ıt´ast tudjuk haszn´alni. A karakterek nyomtat´as´anak el˝ok´esz´ıt´ese a 27. e´ s 28. sorban t¨ort´enik, m´ıg a nyomtat´asi ciklus a 30. e´ s 31. sorban tal´alhat´o. A 9.11. program egy m´asik lehet˝os´eget mutat a program megval´os´ıt´as´ara. Ebben a programban a beolvas´ast egy ciklussal v´egezz¨uk el. Mivel a ciklushoz sz¨uks´eg van a CL regiszterre ez´ert a beolvasott sz´amokat itt a mem´ori´aban t´aroljuk el. Ebben a programban a sz´amok o¨ sszead´as´at a 21. e´ s 22. sorban v´egezz¨uk el, majd a nyomtat´ast az el˝oz˝oekhez hasonl´oan, ciklussal oldjuk meg.
101
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
org 100h szam_1: MOV AH, 9 ; elso szam bekerese MOV DX, uzenet INT 21h MOV AH, 1 INT 21h CMP AL, ’0’ JB nem_szam_1 CMP AL, ’9’ JA nem_szam_1 SUB AL, ’0’ ; karakterbol szam MOV CL, AL ; karakter t´ arolasa szam_2: MOV AH, 9 ; masodik szam bekerese MOV DX, uzenet INT 21h MOV AH, 1 INT 21h CMP AL, ’0’ JB nem_szam_2 CMP AL, ’9’ JA nem_szam_2 SUB AL, ’0’ ; karakterbol szam ADD CL, AL ; osszeadas XOR CH, CH MOV AH, 2 ; nyomtatas elokeszitese MOV DL, ’*’ ujra: INT 21h LOOP ujra INT 20h nem_szam_1: MOV AH, 9 MOV DX, nem_szam_szoveg INT 21h JMP szam_1 nem_szam_2: MOV AH, 9 MOV DX, nem_szam_szoveg INT 21h JMP szam_2 uzenet: db 0Dh,0Ah,’Adjon meg egy szamot: $’ nem_szam_szoveg: db 10,13,’Nem szamot adtal meg!$’
9.10. t´abla: K´et sz´am o¨ sszead´asa e´ s az eredm´eny kinyomtat´asa.
102
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
org 100h MOV DI, szamok MOV CL, 0 szam_be: MOV AH, 9 ; elso szam bekerese MOV DX, uzenet INT 21h MOV AH, 1 INT 21h CMP AL, ’0’ JB nem_szam CMP AL, ’9’ JA nem_szam SUB AL, ’0’ MOV [DI], AL INC DI INC CL CMP CL, 2 JNE szam_be ; olvasas vege MOV CL, byte [szamok] ADD CL, byte [szamok+1] XOR CH, CH MOV AH, 2 ; nyomtatas elokeszitese MOV DL, ’*’ ujra: INT 21h LOOP ujra INT 20h nem_szam: MOV AH, 9 MOV DX, nem_szam_szoveg INT 21h JMP szam_be szamok: db 0, 0 uzenet: db 0Dh,0Ah,’Adjon meg egy szamot: $’ nem_szam_szoveg: db 10,13,’Nem szamot adtal meg!$’
9.11. t´abla: K´et sz´am o¨ sszead´asa e´ s az eredm´eny kinyomtat´asa ciklussal.
103
9.8 Egy karakter n-szeri kinyomtat´asa A 9.12. t´abl´an l´athat´o program beolvas egy karaktert, ut´ana egy decim´alis sz´amjegyet e´ s az els˝ok´ent beolvasott karaktert annyiszor nyomtatja ki, amekkora a m´asodiknak beolvasott sz´am volt. A program mostanra tal´an nem ig´enyel magyar´azatot, mivel minden r´eszlete eddig m´ar szerepelt egy kor´abbi programban. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
org 100h MOV AH, 9 MOV DX, uzenet1 INT 21h MOV AH, 1 INT 21h MOV [karakter], AL olvas: MOV AH, 9 MOV DX, uzenet2 INT 21h MOV AH, 1 INT 21h CMP AL, ’0’ JB hiba CMP AL, ’9’ JA hiba SUB AL, ’0’ XOR CX, CX MOV CL, AL MOV AH, 9 ; uj sor nyomtatasa MOV DX, ujsor INT 21h MOV AH, 2 ; karakter sorozat nyomtatasa MOV DL, [karakter] nyomtat: INT 21h LOOP nyomtat INT 20h hiba: MOV AH, 9 MOV DX, uzenet_nem_szam INT 21h JMP olvas ujsor: db 10, 13, ’$’ karakter: db 0 uzenet1: db 10, 13, ’Adjon meg egy karaktert: $’ uzenet2: amjegyet: $’ db 10, 13, ’Adjon meg egy sz´ uzenet_nem_szam: amjegyet adott meg!’ db 10, 13, ’Nem sz´
9.12. t´abla: Egy karakter n-szeri kinyomtat´as´ara szolg´al´o program
104
9.9 T´eglalap kinyomtat´asa A 9.13. e´ s 9.14. t´abl´akon bemutatott program beolvas k´et egyjegy˝u sz´amot ellen˝orz´essel, a sorok e´ s oszlopok sz´am´at, majd a sz´amoknak megfelel˝o m´eret˝u t´eglalapot nyomtat ki a k´eperny˝ore. A program igaz´ab´ol nem t´ul bonyolult, de az u¨ zenetek nyomtat´asa e´ s az ellen˝orz´esek miatt olyan hossz´u lett, hogy k´et t´abl´an ker¨ul bemutat´asra. A program speci´alis abban az e´ rtelemben, hogy ez a program nem “line´aris”. Ez azt jelenti, hogy a 2. sorban m´ar r¨ogt¨on 19. sorra ugrunk e´ s ott folytat´odik a program v´egrehajt´asa. A 2. e´ s 19. sor k¨oz´e beker¨ult n´eh´any adat, illetve a hiba kezel˝o programr´eszletek is. Itt ez jelenti azt, hogy a program nem line´aris, nem csak fentr˝ol, lefel´e fut a program e´ s adat is be´ekel˝odik a programba. A 20-22. sorokban egy u¨ zenete ´ırunk ki a felhaszn´al´onak, majd a 23. e´ s 24. sorokban beolvasunk egy karaktert. A 25. e´ s 28. sorok k¨oz¨ott ellen˝orizz¨uk, hogy a beolvasott karakter sz´amjegy-e. Ha nem sz´amjegyet olvastunk be, a program egy hiba¨uzenetet ´ır ki e´ s u´ jra megpr´ob´al beolvasni egy sz´amjegyet. A 29. sorban a beolvasott sz´amjegy ASCII k´odj´at sz´amm´a konvert´aljuk e´ s elt´aroljuk a CH regiszterben. A 32-34. sorokban egy u´ jabb u¨ zenetet ´ırunk ki, majd ism´et egy karaktert olvasunk be a 35. e´ s 36. sorban. A 37-40. sorok k¨oz¨ott ism´et ellen˝orz´est hajtunk v´egre, hogy a beolvasott karakter sz´am-e. ´ Erdemes megfigyelni, hogy a k´et beolvas´asn´al k¨ul¨on hiba u¨ zenet nyomtat´o r´eszt haszn´altunk: hiba1 e´ s hiba2. Mi´ert? Ez az´ert van, mert ha csak egy hiba¨uzenet nyomtat´o programr´eszlet lenne, akkor a hiba u¨ zenet kinyomtat´asa ut´an k´et k¨ul¨onb¨oz˝o helyre kellene valahogy visszat´ernie. Egyszer a hiba1 c´ımre, m´askor pedig a hiba2 c´ımre. Term´eszetesen ezt nem lehet. A f¨uggv´enyekn´el majd l´atni fogjuk, hogy ezt hogyan lehet megval´os´ıtani, de itt most azt az egyszer˝u megold´ast haszn´aljuk, hogy a k´odot megism´etelj¨uk. A m´asodszorra beolvasott e´ rt´eket a BL regiszterben t´aroljuk el. A t´eglalap nyomtat´as´at a 9.14. t´abla mutatja be. A 46-48. sorokban csak egy soremel´est nyomtatunk. A 50. sorban be´all´ıtjuk a karakter nyomtat´asi funkci´o k´odot e´ s az 51. sorban a nyomtatand´o karaktert adjuk meg. Az 52. sorban a CL regiszterbe a´ tm´asoljuk a BL regiszter tartalm´at, az oszlopok sz´am´at. A CL regiszter lesz az egyik ciklus v´altoz´o. A m´asik ciklus v´altoz´o a CH regiszter. Mi´ert kell k´et ciklus v´altoz´o? N´ezz¨uk meg a k¨ovetkez˝o C k´odot, ami egy t´eglalapot nyomtat ki: for(ch = n; ch > 0; ch--) { for(cl = m; cl > 0; cl--) { printf(’’o’’ } printf(’’\n’’ } A fenti k´odban az l´athat´o, hogy van egy bels˝o e´ s egy k¨uls˝o ciklus. Ezeket jel¨oli a belso e´ s kulso c´ım az assembly programban. Az is l´athat´o, hogy amikor a bels˝o ciklus elkezd˝odik a CL regisztert mindig u´ jra kell inicializ´alni. Ez t¨ort´enik a 52. sorban, amikor a CL regiszterbe a´ tm´asoljuk a BL regiszter tartalm´at. (A BL regiszter tartalma nem v´altozik meg a nyomtat´as sor´an.) A bels˝o ciklusban a 54. sor v´egzi a nyomtat´ast. A 55. sor v´egzi a ciklus v´altoz´o cs¨okkent´es´et, majd a 56. sor val´os´ıtja meg a felt´eteles ugr´ast. Ha a CL regiszter tartalma a cs¨okkent´es ut´an nem z´erus, akkor megism´etelj¨uk a nyomtat´ast, mivel a belso c´ımre ugrik a program. Ha z´erus lett a CL regiszter, akkor a 57. sorban folytat´odik a program fut´asa. A 57-59. sorokban egy soremel´est nyomtatunk ki. Mivel itt megv´altozik a funkci´o k´od az AH regiszterben, ez´ert kell az 50. sorban ism´et be´all´ıtani a karakter nyomtat´o funkci´o k´odot. A 60. e´ s 61. sorok val´os´ıtj´ak meg a k¨uls˝o ciklust. A 62. sorban l´ep¨unk ki a programb´ol.
105
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
org 100h JMP olvas1 hiba1: MOV AH, 9 MOV DX, uzenet_nem_szam INT 21h JMP olvas1 hiba2: MOV AH, 9 MOV DX, uzenet_nem_szam INT 21h JMP olvas2 uzenet_nem_szam: amjegyet adott meg!’ db 10, 13, ’Nem sz´ uzenet1: db 10, 13, ’Adja meg a sorok szamat: $’ uzenet2: db 10, 13, ’Adja meg az oszlopok szamat: $’ olvas1: MOV AH, 9 MOV DX, uzenet1 INT 21h MOV AH, 1 INT 21h CMP AL, ’0’ JB hiba1 CMP AL, ’9’ JA hiba1 SUB AL, ’0’ MOV CH, AL olvas2: MOV AH, 9 MOV DX, uzenet2 INT 21h MOV AH, 1 INT 21h CMP AL, ’0’ JB hiba2 CMP AL, ’9’ JA hiba2 SUB AL, ’0’ MOV BL, AL ; folytat´ odik ...
9.13. t´abla: Egy t´eglalap kinyomtat´as´ara szolg´al´o program els˝o r´esze
106
45 ; nyomtatas itt kezdodik 46 MOV AH, 9 ; uj sor 47 MOV DX, ujsor 48 INT 21h 49 kulso: 50 MOV AH, 2 51 MOV DL, ’o’ 52 MOV CL, BL 53 belso: 54 INT 21h 55 DEC CL 56 JNE belso 57 MOV AH, 9 58 MOV DX, ujsor 59 INT 21h 60 DEC CH 61 JNE kulso 62 INT 20h 63 ujsor: 64 db 10, 13, ’$’
9.14. t´abla: Egy t´eglalap kinyomtat´as´ara szolg´al´o program m´asodik r´esze
107
9.10 Sakkt´abla nyomtat´asa Ez a program tulajdonk´eppen nagyon hasonl´ıt a t´eglalap nyomtat´o programhoz (9.9. fejezet), de itt nem egyf´ele karaktert kell nyomtatni, hanem felv´altva k¨ul¨onb¨oz˝o karaktereket. A 9.15. program mutatja be a sakkt´abla nyomtat´as´at megval´os´ıt´o assembly program. Ebben a programban is k´et egym´asba a´ gyazott ciklus van. Az egyik ciklus v´altoz´o a BX regiszter, m´ıg a m´asik a CX regiszter. B´ar a program 8x8-as t´eglalapot nyomtat ki, de a CX regiszter kezdeti e´ rt´eke csak 4. Ez az´ert van mert n´egy darab dupla karaktert nyomtatunk ki egy sorba: vagy XO vagy OX karaktereket. Az´ert van k´etf´ele dupla karakter, mivel az egyiket a p´aros a m´asikat a p´aratlan sorokba nyomtatjuk. A 7. sorban vizsg´aljuk meg, hogy a sor sz´ama, BX regiszter, p´aros-e. Hogyan csin´aljuk? A 7. sorban a TEST utas´ıt´as egy maszkol´ast v´egez e´ s a legkisebb helyi´ert´ek˝u bitet tartja meg a BX regiszterb˝ol. Ez az´ert elegend˝o, mivel a fels˝obb bitek minden kett˝o hatv´anyai azok csak p´arosak lehetnek, ez´ert a legals´o bit az ami eld¨onti, hogy a BX-ben t´arolt e´ rt´ek p´aros vagy p´aratlan. Ha a legkisebb helyi´ert´ek˝u bit 1 akkor a BX regiszter tartalma p´aratlan, ha z´erus, akkor p´aros. Miut´an eld˝olt, hogy p´aros vagy p´aratlan sort nyomtatunk, kinyomtatjuk a k´et megfelel˝o karaktert a bels˝o ciklusban. A bels˝o ciklus a 6. e´ s 21. sor k¨oz¨ott van. A 22. e´ s 26. sorok k¨oz¨ott csak egy sor emel´est nyomtatunk. A 27. sorban cs¨okkentj¨uk a BX regisztert, a k¨uls˝o ciklus ciklusv´altoz´oj´at e´ s ha nem z´erus akkor a 28. sorban a k¨uls˝o ciklus elej´ere ugrunk. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
org 100h mov bx, 8 mov ah,2 kulso: mov cx, 4 belso: test bx,1 jz paros paratlan: ; ez a cim igaz´ abol nem kellene mov dl,’O’ int 21h mov dl,’X’ int 21h jmp ciklus paros: mov dl,’X’ int 21h mov dl,’O’ int 21h ciklus: loop belso ; uj sor mov dl, 0dh int 21h mov dl, 0ah int 21h dec bx jnz kulso int 20h
9.15. t´abla: Egy sakkt´abla kinyomtat´as´ara szolg´al´o program
108
Ez a sakkt´abla nyomtat´asi feladat arra is j´o, hogy a XOR utas´ıt´as egy m´asik jellemz˝o alkalmaz´as´at is bemutassuk. K´et e´ rt´ekre alkalmazva a XOR utas´ıt´ast egy harmadik e´ rt´eket fogunk kapni a 7.4. t´abl´azat szerint. Ha u´ jra alkalmazzuk ugyanazt a XOR utas´ıt´ast az eredm´enyre, akkor az eredeti e´ rt´eket kapjuk vissza. N´ezz¨unk erre egy p´eld´at: MOV XOR XOR XOR XOR
AL, AL, AL, AL, AL,
33h 11h 11h 11h 11h
; ; ; ; ;
AL AL AL AL AL
= = = = =
33h !!! 22h 33h !!! 22h 33h !!!
A XOR utas´ıt´asnak ezt a tulajdons´ag´at haszn´alja ki a 9.16. program. A 6. sorban a nyomtatand´o karaktereket o¨ ssze-XOR-oljuk, (amib˝ol kapunk valamilyen e´ rt´eket) de ezut´an ezt az e´ rt´eket u´ jra XORolva az egyik karakterrel, hol az egyik, ‘X’, hol a m´asik, ‘O’, karaktert kapjuk meg a 10. sorban. Ebben a programban is a BX regiszter a k¨uls˝o ciklusv´altoz´o e´ s a CX regiszter a bels˝o ciklusv´altoz´o, aminek viszont 8 a kezdeti e´ rt´eke, mivel itt egyes´evel nyomtatjuk ki a karaktereket. A bels˝o ciklus ut´an a 13. sorban elmentj¨uk a DX regiszter tartalm´at, mert a soremel´es nyomtat´asn´al t¨onkretessz¨uk a regiszter tartalm´at. A 14-17. sorokban nyomtatjuk ki a soremel´es karaktereket e´ s a 18. sorban vissza´all´ıtjuk a DX regiszter tartalm´at. A 21. sor szorul m´eg magyar´azatra. N´ezz¨uk meg a k¨ovetkez˝o k´et sort: XOXOXOXO OXOXOXOX Azt lehet l´atni, hogy a m´asodik sort ugyanazzal a karakterrel kell kezdeni, mint amivel az els˝o sort lez´artuk. A 21. sor ezt biztos´ıtja, hogy a XOR utas´ıt´as alkalmaz´as´aval a ‘X’ karaktert “´atugorjuk”. V´eg¨ul a 22. e´ s 23. sor a k¨uls˝o ciklust val´os´ıtja meg.
109
1 org 100h 2 mov ah,2 3 mov bx, 8 4 mov dl, ’X’ 5 mov dh, ’O’ 6 xor dh, dl 7 kulso: 8 mov cx, 8 9 belso: 10 xor dl,dh 11 int 21h 12 loop belso 13 mov bp, dx ; elmenti DX-et ´j sor nyomtat´ 14 mov dl, 0dh ; u asa 15 int 21h 16 mov dl, 0ah 17 int 21h as DX-et allit´ 18 mov dx, bp ; vissza´ 19 ; mivel ugyanazzal a karakterrel 20 ; folytat´ odik a k¨ ovetkez¨ o sor 21 xor dl,dh 22 dec bx 23 jnz kulso 24 int 20h
9.16. t´abla: Egy sakkt´abla kinyomtat´as´ara szolg´al´o program XOR utas´ıt´assal
110
9.11 ASCII t´abla kinyomtat´asa A 9.17. t´abl´an l´athat´o program az ASCII t´abl´aban tal´alhat´o karaktereket nyomtatja ki a k´eperny˝ore. A program igen egyszer˝u. A 2. sorban adjuk meg, hogy 256 darab karaktert fogunk kinyomtatni. A 3. sorban megadjuk az els˝o karakter ASCII k´odj´at. A 4. sorban az INT 21h megszak´ıt´as funkci´o k´odj´at adjuk meg. A 6. sor v´egzi a nyomtat´ast, majd a 7. sorban a DL regiszter megn¨ovel´es´evel a k¨ovetkez˝o ASCII karaktert a´ ll´ıtjuk be. A 8. sor cs¨okkenti a CX regiszter tartalm´at eggyel e´ s ha m´eg nem z´erus, akkor az ujra c´ımre ugrik. A LOOP utas´ıt´as seg´ıts´eg´evel k´epezz¨uk a ciklust mely 256-szor fut le. Az utols´o sorban kil´ep¨unk a programb´ol. 1 2 3 4 5 6 7 8 9
org 100h MOV CX, 256 MOV DL, 0 MOV AH, 2 ujra: INT 21h INC DL LOOP ujra INT 20h
9.17. t´abla: Az ASCII t´abla kinyomtat´as´ara szolg´al´o program
111
9.12 Sz´am ki´ır´asa decim´alis form´aban Ha egy sz´amot decim´alis form´aban akarunk kinyomtatni, speci´alis nyomtat´asi elj´ar´ast kell alkalmazni. A 9.18. program erre mutat egy p´eld´at. Az algoritmus l´enyege, hogy a sz´amot mindig 10-el osztjuk e´ s az oszt´as marad´eka mindig egy decim´alis sz´amjegyet ad, hiszen a marad´ek 0 e´ s 9 k¨oz¨otti lehet. N´ezz¨unk egy p´eld´at: 152 / 10 -> 15 ´ es a marad´ ek: 2 ´s a marad´ 15 / 10 -> 1 e ek: 5 1 / 10 -> 0 ´ es a marad´ ek: 1 Amint ez l´athat´o t´enyleg a sz´am sz´amjegyeit kapjuk meg, de ford´ıtott sorrendben. Ezt is figyelembe kell venni az algoritmusn´al. A 2. sorban az AX regiszterbe t¨oltj¨uk be azt a sz´amot amit decim´alis form´aban szeretn´enk kiny´ omtatni. Erdemes arra is gondolni, hogy mivel az AX regiszter 16 bites regiszter ez´ert 21 6 = 65536 f´ele sz´amot tud csak t´arolni, ahol a legkisebb sz´am a nulla e´ s a legnagyobb sz´am a 65535. Erre az inform´aci´ora az´ert van sz¨uks´eg, mivel ´ıgy m´ar tudjuk, hogy maximum 5 sz´amjegyet kell majd kinyomtatni. Ezt mutatja a 18. sorban az szamstr v´altoz´o defin´ıci´oja, ami 5 darab SPACE karaktert tartalmaz e´ s a v´eg´en egy doll´ar jelet ($). A doll´ar jel az´ert kell a v´eg´ere, hogy majd egyben tudjuk a sz´amokat kinyomtatni az INT 21h megszak´ıt´assal. A 3. sorban az SI regiszterbe azt a c´ımet t¨oltj¨uk be ami az utols´o SPACE karakterre mutat a szamstr v´altoz´oban. Az 5. sorban adjuk meg az oszt´ot. A 6. sorban azt k´esz´ıtj¨uk el˝o, hogy majd az DX:AX sz´amot osztjuk egy 16 bites regiszterrel e´ s ´ıgy majd az eredm´eny is egy 16 bites regiszterbe ker¨ul. Az oszt´ast a 7. sorban v´egezz¨uk el. A h´anyados az AX regiszterbe, a marad´ek a DX regiszterbe ker¨ul. A marad´ek csak 0 e´ s 9 k¨oz¨otti sz´am lehet. A nyomtat´ashoz a sz´amot ASCII karakterr´e kell konvert´alni, vagyis a sz´amhoz hozz´aadjuk a ‘0’ karakter ASCII k´odj´at. A 8. sor ut´an a DL regiszter tartalma a 30h e´ s 39h e´ rt´ekek k¨oz¨otti sz´am lesz, mely megfelel a 0 e´ s 9-es sz´amok ASCII k´odj´anak. A 9. sorban elt´aroljuk az ASCII k´odot az SI regiszter a´ ltal megadott helyre. A 10. sorban az SI regisztert az´ert cs¨okkentj¨uk eggyel, hogy a k¨ovetkez˝o karaktert az el˝oz˝o el´e ´ırjuk. A 11. sor a le´all´ıt´asi felt´etel. Itt azt vizsg´aljuk, hogy a h´anyados z´erus-e, vagyis nincs tov´abbi sz´amjegy amit konvert´alni kellene. A 12. sor tartalmazza a felt´eteles ugr´ast, ami az ujra c´ımre ugrik ha ha van m´eg sz´am amit konvert´alni kell. Ha a h´anyados z´eros, AX regiszter tartalma z´erus, akkor nincs m´as h´atra mint kinyomtatni az elt´arolt sz´amokat. A program olyan e´ rtelemben tr¨ukk¨os, hogy a szamstr v´altoz´o alap esetben SPACE karaktereket tartalmaz, e´ s ´ıgy ha csak k´et jegy˝u sz´amot t´arolunk el, az´ert m´eg a program j´ol fog m˝uk¨odni, mivel ebben az esetben a program legfeljebb 3 SPACE karaktert nyomtat a sz´amok el˝ott.
112
1 org 100h 2 MOV AX, 54321 3 MOV SI, szamstr 4 ujra: 5 MOV BX, 10 ; 6 MOV DX, 0 ; 7 DIV BX ; 8 ADD DL, ’0’ ; 9 MOV [SI], DL ; 10 DEC SI ; 11 CMP AX, 0 12 JNZ ujra 13 MOV AH, 9 14 MOV DX, szamstr 15 INT 21h 16 INT 20h 17 szamstr: ’,’$’ 18 db ’
+ 4 10-es osztassal valasztunk le egy jegyet DX:AX az osztando szam, BX az oszto hanyados -> AX, maradek -> DX szamjegy karakterre eltaroljuk aroljuk e t´ visszafel´
9.18. t´abla: Sz´am ki´ır´asa decim´alis form´aban
113
9.13 Olvas´as a mem´ori´ab´ol A 9.19. program arra mutat egy p´eld´at, hogyan lehet a mem´ori´aban, egy fix c´ımen l´ev˝o byte-ot megc´ımezni, illetve azt vizsg´alni, hogy annak a byte-nak valah´anyadik bitje 1-e. A 0:417-es c´ımen tal´alhat´o byte ´ırja le a billenty˝uzet LED-ek a´ llapot´at. P´eld´aul ha a 7. bit e´ rt´eke 1, akkor a CAPS LOCK be van kapcsolva. Az al´abbi program azt fogja vizsg´alni, hogy a CAPS LOCK be van-e kapcsolva e´ s annek megfelel˝o u¨ zenetet fog ki´ırni. A 2. e´ s 3. sorban az ES szegmens regiszterbe a z´erus szegmens c´ımet t¨oltj¨uk. Mivel szegmens regiszterbe nem lehet k¨ozvetlen¨ul e´ rt´eket t¨olteni, ez´ert haszn´aljuk az AX regisztert. A 4. sorban direkt m´odon, szegmens regiszterrel egy¨utt adjuk meg a vizsg´aland´o byte c´ım´et. A byte-ot bet¨oltj¨uk a BL regiszterbe. Az 5. sor egy maszkol´ast hajt v´egre. L´enyeg´eben a 40h = 0100 0000b e´ rt´ekkel e´ s mivel az AND utas´ıt´ast haszn´aljuk ez´ert a m˝uvelet ut´an csak a 7. bit e´ rt´eke marad meg. P´eld´aul: 0101 1001 <- BL AND 0100 0000 <- Maszk -------------0100 0000 Ez azt jelenti, hogy az 5. sor ut´an a BL regiszter e´ rt´eke vagy z´erus vagy pedig 40h lesz. Ezt a felt´etelt haszn´alja ki a 6. sorban a felt´eteles ugr´as. (Nem kell k¨ul¨on o¨ sszehasonl´ıt´o utas´ıt´as, CMP, mivel az AND utas´ıt´as m´ar megfelel˝oen be´all´ıtja a Z´erus bitet, ZF.) Mivel csak egy u¨ zenetet akarunk kinyomtatni e´ s csak a nyomtatand´o u¨ zenet m´as ez´ert att´ol f¨ugg˝oen hogy a z´erust kaptunk-e a DX regiszterbe m´as c´ımet t¨olt¨unk. Fontos lehet m´eg kiemelni a 8. sorban a felt´etel n´elk¨uli ugr´ast, JMP. Erre az´ert van sz¨uks´eg, mert miut´an be´all´ıtottuk a DX regiszter tartalm´at a 7. sorban, m´ar csak nyomtatni kell e´ s nem szabad engedni hogy a DX regiszter tartalm´at fel¨ul´ırjuk. Ha nincs a felt´etel n´elk¨uli ugr´as akkor pedig ez t¨ort´enne, mivel a 9. sorban folytat´odna a program. A 12. sort´ol m´ar ugyanazt kell csin´alni mind a k´et esetben, be´all´ıtani a funkci´o k´odot az INT 21h megszak´ıt´asnak, megh´ıvni a megszak´ıt´ast, majd kil´epni a programb´ol. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
org 100h mov mov mov and jnz mov jmp
ax,0 es,ax bl,[es:417h] bl, 40h eg dx,kikapcs kiir
eg: mov dx,bekapcs kiir: mov ah,9 int 21h int 20h kikapcs: db ’Ki van kapcsolva$’ bekapcs: db ’Be van kapcsolva$’
9.19. t´abla: CAPS LOCK a´ llapot´anak nyomtat´as´ara szolg´al´o program
114
0.bit 1.bit 2.bit 3.bit 4.bit 5.bit 6.bit 7.bit
az el˝ot´er k´ek sz´ın¨osszetev˝oje az el˝ot´er z¨old sz´ın¨osszetev˝oje az el˝ot´er piros sz´ın¨osszetev˝oje az el˝ot´er intenzit´asa a h´att´er k´ek sz´ın¨osszetev˝oje a h´att´er z¨old sz´ın¨osszetev˝oje a h´att´er piros sz´ın¨osszetev˝oje a villog´as ki-bekapcsol´asa (a bit 1 e´ rt´ek´en´el villog)
9.20. t´abla: A k´eperny˝o byte attrib´utum´anak bitjei
9.14 K¨ozvetlen vide´o mem´ori´aba ´ır´as Lehet˝os´eg van arra, hogy egy program k¨ozvetlen¨ul a videok´artya mem´ori´aj´aba ´ırjon adatot e´ s ilyen m´odon k¨ozvetlen¨ul a k´eperny˝ore ´ırjunk. Ehhez persze tudnunk kell, hogy melyik szegmensen kezd˝odik ´ aban a 0B800h a a k´eperny˝o mem´oria, vagyis hova van lek´epezve a videok´artya mem´ori´aja. Altal´ szegmens c´ıme, kiv´eve p´eld´aul a Herkules video k´artya (ma m´ar nem haszn´alj´ak ezt a k´arty´at). Teh´at a 0B800h a szegmens c´ımet fogjuk haszn´alni a 80x25 karakteres sz¨oveges k´eperny˝o eset´en. A nyomtat´ashoz m´eg azt is tudnunk kell, hogy milyen a k´eperny˝o fel´ep´ıt´ese. Minden megjelen´ıtett karakterhez k´et byte tartozik: az egyik byte maga a karakter, a m´asik byte pedig a karakter attrib´utuma. Az attrib´utum a karakter sz´ın´et, intenzit´as´at e´ s villog´as´at jelenti a 9.20. t´abl´azat szerint. A k´eperny˝o bal fels˝o sark´ahoz tartozik a z´erus oszlop e´ s z´erus sor karakter poz´ıci´o. Hogyan lehet egy tetsz˝oleges poz´ıci´oj´u karaktert kinyomtatni?
115
9.15 Sz¨oveg beolvas´asa Karakterenk´ent olvasunk. ESC-re v´ege Az INT 21 el˝ok´esz´ıt´ese e´ s haszn´alata.
116
9.16 Beolvasott sz¨ovegben karakterek sz´aml´al´asa
117
˝ 9.17 Beolvasott sz¨oveg nagy betusre konvert´al´asa
118
9.18 Feladatok 1. ´Irjunk programot, mely megsz´amolja, hogy egy byte-ban h´any darab 1-es e´ rt´ek˝u bit van. ´ 2. Irjunk programot, mely bek´er egy decim´alis sz´amjegyet. A sz´amjegyr˝ol eld¨onti, hogy nagyobb-e mint o¨ t e´ s ennek megfelel˝o u¨ zenetet ´ır ki: “Nagyobb mint o¨ t”, “Kisebb mint o¨ t”, “Egyenl˝o o¨ ttel”.
119
120
10. Fejezet
¨ Fuggv´ enyek 10.1 A verem adatszerkezet A verem tulajdonk´eppen egy LIFO (Last In First Out) adatszerkezet. Ez azt jelenti, hogy az utolj´ara ellt´arolt e´ rt´eket olvashatjuk ki legel˝osz¨or. A vermet angolul stack-nek is szokt´ak nevezni. Ha anal´ogi´at keres¨unk a verem adatszerkezetre, akkor tal´an egy rakt´arat k´epzelhet¨unk el. A padl´o a legals´o szint, amire tehet¨unk egy dobozt, amire u´ jabb dobozt tehet¨unk e´ s ´ıgy tov´abb. Ha a legfels˝o dobozra van sz¨uks´eg¨unk, akkor csak levessz¨uk a kupac tetej´er˝ol. Ezzel szemben, ahhoz hogy a legals´o dobozt kivegy¨uk, az o¨ sszes t¨obbi felette lev˝o dobozt le kell emelni. Amint l´athat´o egy verem eset´en mindig csak a tetej´ehez f´er¨unk hozz´a (top-of-stack, TOS). A verembe helyez´es m˝uvelet´et PUSH-nak, a verem tetej´er˝ol val´o kiv´etelt pedig POP-nak szoktuk nevezni. A 10.1. a´ bra bemutatja a verem egyszer˝us´ıtett m˝uk¨od´es´et.
10.1.1 A verem implement´aci´oja Az x86-os architekt´ura eset´en a verem a mem´ori´aban tal´alhat´o. Erre fontos lesz eml´ekezni k´es˝obb, mivel ezek szerint a vermet kezelhetj¨uk LIFO adatszerkezetk´ent, de mint v´eletlen hozz´af´er´es˝u adatszerkezetk´ent is! Mivel a verem a mem´ori´aban van ez´ert a megval´os´ıt´as´ahoz az SS szegmens e´ s SP regisztert kell haszn´alni. Ez a regiszter p´aros (SS:SP) mutat mindig a verem tetej´ere. Az SS szegmens regiszter a verem szegmens´enek a c´ım´et hat´arozza meg, m´ıg az SP regiszter a szegmensen bel¨ul adja meg a verem tetej´enek az offszetj´et. Az 10.2.a. a´ bra azt mutatja, hogy az eddigiek alapj´an hogyan k´epzelhetj¨uk el a vermet x86-os architekt´ura eset´en. Sajnos ez a k´ep helytelen. Az x86-os architekt´ura eset´en a verem helyes k´epe a 10.2.b. a´ br´an l´athat´o. Ezek alapj´an a verem adatszerkezet legfontosabb tulajdons´agai: • Csak word m´eret˝u adat t¨olthet˝o fel a veremre. Byte o¨ nmag´aban nem. • A verem a magasabb mem´oria c´ımt˝ol az alacsonyabb mem´oria c´ım fel´e “n¨ovekszik”. Ez a 10.2.b. a´ bra alapj´an azt jelenti, hogy a verem lefel´e “n¨ovekszik”.
10.1. a´ bra: A verem m˝uk¨od´ese
121
(a)
(b)
10.2. a´ bra: a) A verem adatszerkezet helytelen k´epe. b) A verem adatszerkezet val´odi k´epe x86-os architekt´ur´an.
(a)
(b)
(c)
10.3. a´ bra: a) A verem elm´eleti k´epe u¨ res a´ llapotban. b) A verem a´ llapota FEABh e´ rt´ek t´arol´asa ut´an. c) A verem a´ llapota 1234h e´ rt´ek t´arol´asa ut´an.
• Az SS:SP regiszter p´aros mindig az utolj´ara elt´arolt elemre mutat. Pontosabban az utolj´ara elt´arolt sz´o (word) als´o byte-j´ara.
A 10.3.a. a´ bra azt mutatja, hogy amikor a verem u¨ res, akkor a verem hogyan n´ez ki “elm´eletileg”. A 10.3.b. e´ s 10.3.c. a´ bra azt mutatja, mi t¨ort´enik amikor adatokat tesz¨unk a verembe. Egy word felt¨olt´ese sor´an el˝osz¨or az SP regiszter e´ rt´ek´et 2-vel cs¨okkentj¨uk majd a word-¨ot elt´aroljuk az SS:SP a´ ltal mutatott mem´oria c´ımen. Amikor egy word-¨ot kivesz¨unk a veremb˝ol, el˝osz¨or kim´asoljuk az e´ rt´eket az SS:SP a´ ltal mutatott c´ımr˝ol, majd az SP regiszter e´ rt´ek´et 2-vel cs¨okkentj¨uk. Itt kell megjegyezn¨unk, hogy a 10.3.a. a´ bra val´oban csak elm´eleti k´epe a verem u¨ res a´ llapot´anak. A magyar´azathoz tegy¨uk fel, hogy a veremben egy e´ rt´ek, egy sz´o (word) van elt´arolva. Amikor csak egy elem van a vermen akkor az SP regiszter e´ rt´eke FFFEh. Amikor ezt az e´ rt´eket kivessz¨uk a veremb˝ol, akkor az SP regisztert meg kell n¨ovelni 2-vel. Ebben az esetben az SP e´ rt´eke 10000h, ami nagyobb mint amit 16 biten t´arolni lehetne, ´ıgy az SP regiszter val´oj´aban a 0000h e´ rt´eket t´arolja majd. Ez azt jelenti, hogy a regiszter e´ rt´eke “k¨orbefordul” (wrap around) e´ s az SP regiszter a szegmens elej´ere fog mutatni.
122
˝ 10.1.2 Verem muveletek Az x86-os architekt´ur´an t¨obbf´ele utas´ıt´as is l´etezik a verem kezel´es´ere. Az alapvet˝o verem m˝uveleteknek mint push e´ s pop van megfelel˝o assembly utas´ıt´asa: PUSH e´ s POP. (L´asd 7.1.7. e´ s 7.1.10. bekezd´es.) Tov´abbi assembly utas´ıt´asok, melyek a vermet kezelik: • PUSHF (7.1.8. bekezd´es) • PUSHA (7.1.9. bekezd´es) • POPF (7.1.11. bekezd´es) • POPA (7.1.12. bekezd´es)
10.2 A verem haszn´alata A veremnek t¨obb haszna is van az assembly nyelvben: • e´ rt´ekek id˝oleges t´arol´asa • param´eter´atad´as f¨uggv´enyeknek • lok´alis v´altoz´oknak mem´oria ter¨ulet • vez´erl´es a´ tad´as
´ ekek id˝oleges t´arol´as 10.2.1 Ert´ A verem j´ol haszn´alhat´o arra, hogy v´altoz´okat e´ s e´ rt´ekeket id˝olegesen elt´aroljunk. P´eld´aul vegy¨uk azt az esetet, hogy k´et v´altoz´ot fel akarunk cser´elni: xchg [valtozo1], [valtozo2] Sajnos ez nem m˝uk¨odik, mivel egy utas´ıt´as k´etszer nem f´erhet hozz´a a memori´ahoz. Az egyik megold´as a k¨ovetkez˝o lehet: mov mov mov mov
ax, [valtozo1] bx, [valtozo2] [valtozo1], bx [valtozo2], ax
de ekkor k´et regisztert is haszn´alnunk kell e´ s 4 mem´oria m˝uveletet v´egz¨unk. Ez a megold´as gondot jelenthet, mivel a v´egrehajt´as´ahoz tal´alnunk kellene 2 szabad regisztert, e´ s sokszor probl´em´as lehet egy programban. De mi van akkor, ha a fenti p´eld´aban az AX e´ s BX regiszterek e´ rt´ekeire a csere ut´an is sz¨uks´eg van? A megold´as az, hogy id˝olegesen el kell menteni az e´ rt´ek¨uket, el kell v´egezni a m˝uveletet, majd helyre kell a´ ll´ıtani a regiszterek e´ rt´ek´et. ; ments¨ uk el a regisztereket push ax push bx ; v´ egezz¨ uk el a cser´ et mov ax, [valtozo1] mov bx, [valtozo2] mov [valtozo1], bx mov [valtozo2], ax
123
ıtsuk helyre a regisztereket all´ ; ´ pop bx pop ax B´ar ez a megold´as m˝uk¨odik, de sz¨uks´eges n´eh´any megjegyz´est tenni: 1. El˝osz¨or is a fenti megold´asban nyolcszor f´er¨unk hozz´a a mem´ori´ahoz. Ne felejts¨uk, hogy a verem m˝uveletek is hozz´a f´ernek a mem´ori´ahoz. 2. M´asodszor, fontos e´ szre venni, hogy ha a regiszterek eredeti e´ rt´ek´et szeretn´enk visszakapni, akkor amilyen sorrendben a regisztereket elmentj¨uk a vermen azzal ellent´etes sorrendben kell helyre´all´ıtani a regisztereket. Egy m´asik p´elda az id˝oleges t´arol´asra: push dx push bx push cx ... ; utas´ ıt´ asok pop cx pop bx pop dx 3. Harmadszor, l´etezik egy eleg´ansabb megold´as a v´altoz´ok cser´ej´ere. push push pop pop
[valtozo1] [valtozo2] [valtozo1] [valtozo2]
Ebben a megold´asban pont az el˝oz˝o szab´alyt s´ertj¨uk meg, de sz´and´ekosan, mivel ´ıgy pontosan azt a hat´ast e´ rj¨uk el, hogy a regiszterek e´ rt´ekei felcser´el˝odnek. Ezen k´ıv¨ul az is e´ rdekes itt, hogy a fenti POP utas´ıt´asok k´etszer f´ernek hozz´a a mem´ori´ahoz, hiszen a veremb˝ol (mem´ori´ab´ol) olvasunk e´ s az argumentumban megadott mem´oria c´ımre ´ırunk. A POP utas´ıt´as egy kiv´etel a szab´aly al´ol, vagyis hogy a´ ltal´aban egy utas´ıt´as nem f´erhet hozz´a k´etszer a mem´ori´ahoz. A m´asik kiv´etel ez al´ol a szab´aly al´ol a sz¨oveg kezel˝o m˝uveletek lesznek (l´asd 12. fejezet). Nagyon fontos meg´erteni a fenti list´aban a 2. e´ s 3. pont k¨oz¨otti kul¨ ¨ onbs´eget. Ebb˝ol a bekezd´esb˝ol is j´ol l´athat´o, hogy a verem m´erete folyamatosan n¨ovekszik e´ s cs¨okken a program fut´asa sor´an. A param´eter a´ tad´ast, lok´alis v´altoz´ok kezel´es´et e´ s vermen kereszt¨uli vez´erl´es a´ tad´ast a k¨ovetkez˝o fejezetben t´argyaljuk.
¨ 10.3 Fuggv´ enyek defin´ıci´oja A f¨uggv´enyek o¨ n´all´o logikai program egys´egek amelyek valamilyen konkr´et feladatot v´egeznek el. A f¨uggv´enyeket szokt´ak alprogramnak is nevezni e´ s nagyon fontos szerepet j´atszanak a modul´aris program fejleszt´esben. B´ar bizonyos programoz´asi nyelvek k¨ul¨onbs´eget tesznek f¨uggv´enyek e´ s procedur´ak k¨oz¨ott, az assembly programoz´asi nyelvben erre nincs sz¨uks´eg. Az assembly programoz´asi nyelvben csak f¨uggv´enyeket defini´alhatunk, amelyeknek param´etereket adhatunk a´ t e´ s kaphatunk vissza e´ rt´eket. Ez a felfog´as nagyban hasonl´ıt a C programoz´asi nyelvhez. Nagyon egyszer˝u defini´alni egy f¨uggv´enyt assembly-ben. K´et utas´ıt´asra van sz¨uks´eg: CALL (l´asd 7.5.7. bekezd´es) e´ s RET (l´asd 7.5.8. bekezd´es) utas´ıt´asokra. N´ezz¨unk egy egyszer˝u p´eld´at:
124
org 100h xor ax, ax call fvg int 20h fvg: add ax, 2 ret Ebben a p´eld´aban a f¨uggv´eny neve fvg. M´as assemblerekkel ellent´etben, ahol speci´alisan kell egy f¨uggv´enyt defini´alni a NASM assembler eset´en igen egyszer˝uen csak egy mem´oria c´ımet kell megadni, ami a f¨uggv´eny eleje e´ s a v´eg´ere egy RET utas´ıt´as kell. ´ Erdemes megvizsg´alnunk a f¨uggv´enyek m˝uk¨od´es´et is. A CALL utas´ıt´as v´egrehajt´asa sor´an, mivel a CALL utas´ıt´as m´ar bet¨olt˝od¨ott az utas´ıt´as “´ertelmez˝obe” ez´ert az IP regiszter a k¨ovetkez˝o utas´ıt´asra mutat, ahol a programnak folytatnia kell a m˝uk¨od´es´et miut´an a f¨uggv´eny lefutott. Erre a processzor u´ gy fog eml´ekezni, hogy ezt a c´ımet elmenti a veremre. Ezut´an a CALL utas´ıt´as a megadott c´ımre adja a´ t a vez´erl´est, vagyis az IP regiszter e´ rt´ek´et megv´altoztatja. N´ezz¨uk meg az el˝oz˝o p´eld´ab´ol gener´alt g´epi k´odot:
xxxx:0100 31C0 xxxx:0102 E80200 xxxx:0105 CD20 xxxx:0107 050200 xxxx:010A C3
org 100h xor ax, ax call fvg int 20h fvg: add ax, 2 ret
L´athat´o, hogy a CALL fvg utas´ıt´asb´ol E8 02 00 g´epi k´od keletkezik. Az E8-as e´ rt´ek adja meg az utas´ıt´as k´odj´at e´ s a k¨ovetkez˝o k´et sz´am pedig az fvg szimb´olikus c´ımnek felel meg. A 02 00 e´ rt´ekek viszont nem felelnek meg a 107-es c´ımnek. Mi t¨ort´enik itt? Arr´ol van sz´o, hogy a CALL utas´ıt´as k´epes k¨ozeli e´ s t´avoli ugr´asra is. Amikor a CALL utas´ıt´as e´ s a f¨uggv´eny egy szegmensen bel¨ul van, akkor elegend˝o csak az offszetet megadni. A szegmens regiszterre nincs sz¨uks´eg. Ez l´athat´o a jelenlegi p´eld´aban is, b´ar itt az fvg szimb´olikus c´ımb˝ol nem konkr´et c´ımet sz´amol ki az assembler, hanem egy eltol´asi e´ rt´eket. Azt sz´amolja ki, hogy h´any byte-nyit kell ugrania a CALL utas´ıt´asnak ahhoz, hogy a program a f¨uggv´eny kezd˝o c´ım´en´el folytassa a v´egrehajt´ast. A g´epi k´odban a 02 00 byte sorozat tal´alhat´o az E8-as utas´ıt´as k´od ut´an, ami val´oj´aban 0002-nak felel meg, hiszen little-endian t´arol´asi m´odot haszn´al az x86-os architekt´ura. A 0002 e´ rt´ek azt adja meg, hogy a f¨uggv´eny kezdete k´et byte-nyi t´avols´agra van e´ s ´ıgy a 105+2=107-es c´ımen kell folytatni a v´egrehajt´ast. A f¨uggv´enyekn´el az is nagyon fontos, hogy a f¨uggv´eny v´eg´en a RET utas´ıt´asnak szerepelnie kell. Ez az´ert nagyon fontos, mivel a CALL utas´ıt´as a´ ltal a vermen elt´arolt c´ımet ez az utas´ıt´as veszi le a veremr˝ol majd az ´ıgy kapott c´ımre adja a´ t a vez´erl´est. Az utas´ıt´as m˝uk¨od´es´enek egy “k¨ul¨onleges” demonstr´al´as´ara n´ezz¨unk egy utas´ıt´as sorozatot ami megfelel egy felt´etel n´elk¨uli ugr´o utas´ıt´asnak: ... push cim ret ... cim:
; jmp cim
A PUSH utas´ıt´as a cim szimb´olikus c´ımet t¨olti fel a veremre, amit a RET utas´ıt´as levesz e´ s erre a c´ımre adja a´ t a vez´erl´est. Tulajdonk´eppen a RET utas´ıt´as ´ıgy vez´erl´es a´ tad´ast v´egez a verem felhaszn´al´as´aval, ami a verem egyik felhaszn´al´asi m´odja.
125
¨ 10.3.1 Egym´asba a´ gyazott fuggv´ enyh´ıv´asok A f¨uggv´enyek egym´asba a´ gyazhat´ok, ami azt jelenti, hogy egy f¨uggv´eny is h´ıvhat egy m´asik f¨uggv´enyt. A 10.1. t´abla egy “mesters´eges” p´eld´at mutat arra, hogy a f¨uggv´enyeket hogyan lehet egym´asba a´ gyazni. A 10.4. a´ bra pedig azt mutatja be, hogy a 10.1. t´abl´an bemutatott program v´egrehajt´asa sor´an az IP regiszter milyen e´ rt´ekeket vesz fel (az utas´ıt´asokat milyen sorrendben hajtjuk v´egre) e´ s a verem milyen e´ rt´ekeket t´arol egy adott pillanatban. A veremben t´arolt e´ rt´ekek ebben a p´eld´aban csak visszat´er´esi c´ımek, a forr´as program sorsz´amai. Az a´ br´aban a ny´ıl az SS:SP regiszter p´aros a´ ltal mutatott c´ımet jel¨oli. N´ezz¨unk egy p´eld´at, ahol a 10.4.d. a´ br´an a verem tetej´en a visszat´er´esi e´ rt´ek 6, ami a jelen p´eld´aban a 6. sort jelenti a forr´ask´odban, e´ s a k¨ovetkez˝o v´egrehajtand´o utas´ıt´as a 10. sorban tal´alhat´o (IP=10). A 10. sorban egy RET utas´ıt´as van, ami a verem tetej´er˝ol leveszi a 6-os e´ rt´eket e´ s ezt t¨olti be az IP regiszterbe, ´ıgy nem v´eletlen, hogy a 10.4.e. a´ br´an m´ar eggyel kevesebb e´ rt´ek van e´ s a k¨ovetkez˝o utas´ıt´as amit v´egre kell hajtani az a 6. sorban tal´alhat´o, vagyis IP=6.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
org 100h call muvelet int 20h muvelet: call torol call addketto ret torol: xor ax, ax ret addegy: inc ax ret addketto: call addegy call addegy ret
10.1. t´abla: P´elda az egym´asba a´ gyazott f¨uggv´enyekre
¨ 10.4 Param´eter a´ tad´as fuggv´ enyeknek A param´eter a´ tad´as egy kicsit komplik´altabb mint m´as magas szint˝u programoz´asi nyelvekben. Assemblyben az a program r´eszlet amelyik szeretne egy f¨uggv´enyt megh´ıvni a param´etereket egy olyan helyre m´asolja amit o¨ nmaga e´ s a f¨uggv´eny is el´er, e´ s csak ezut´an t¨ort´enik a f¨uggv´enyh´ıv´as. H´aromf´ele lehet˝os´eg¨unk van a param´eter a´ tad´asra k¨oz¨os ter¨uleten kereszt¨ul: • regiszteren, • mem´ori´an e´ s • vermen kereszt¨ul.
126
(a) IP=2
(b) IP=5
(c) IP=9
(d) IP=10
(e) IP=6
(f) IP=15
(g) IP=12
(h) IP=13
(i) IP=16
(j) IP=12
(k) IP=13
(l) IP=17
(m) IP=7
(n) IP=3
10.4. a´ bra: A 10.1. t´abl´an l´athat´o program nyomonk¨ovet´ese
127
¨ 10.4.1 Param´eter a´ tad´as regiszteren keresztul A f¨uggv´eny m˝uk¨od´es´ehez sz¨uks´eges param´etereket regiszterekbe tessz¨uk a f¨uggv´eny megh´ıv´asa el˝ott. A m´odszerre n´ezz¨unk egy p´eld´at, melyet a 10.2. t´abla mutat be. A program beolvas egy karaktert majd azt egy f¨uggv´eny seg´ıts´eg´evel ism´et kinyomtatja, de a nyomtat´ast egy f¨uggv´eny v´egzi. 1 org 100h 2 MOV AH, 01 3 INT 21h 4 CALL charnyomtat 5 INT 20h 6 ; nyomtatand´ o karakter AL-ben ad´ odik ´ at 7 charnyomtat: 8 MOV AH, 02 9 MOV DL, AL 10 INT 21h 11 RET
10.2. t´abla: Param´eter a´ tad´as regiszteren kereszt¨ul A m´odszernek vannak el˝onyei e´ s h´atr´anyai: • El˝ony¨ok – A m´odszer k´enyelmes e´ s k¨onny˝u kis sz´am´u param´etert a´ tadni egy f¨uggv´enynek. – A m´odszer nagyon gyors, mivel minden param´eter m´ar a regiszterekben lesz a f¨uggv´enyben. • H´atr´anyok – A f˝o h´atr´any, hogy csak n´eh´any param´etert lehet regiszteren kereszt¨ul a´ tadni, mivel csak limit´alt mennyis´eg˝u a´ ltal´anos regiszter a´ ll rendelkez´esre. – Mivel a h´ıv´asi met´odus sor´an bizonyos regisztereknek speci´alis szerep¨uk lehet, ez´ert sz¨uks´eg lehet ezeket addig a vermen elmenteni, am´ıg a param´eter´atad´as meg nem t¨ort´enik. Ugyanakkor ez azt is jelenti, hogy a m´asodik el˝onyt elvesz´ıtj¨uk, hiszen a param´eter´atad´asban verem m˝uveletre is sz¨uks´eg van.
¨ 10.4.2 Param´eter a´ tad´as mem´ori´an keresztul A mem´ori´an kereszt¨uli param´eter a´ tad´as hasonl´o a regiszteren kereszt¨uli param´eter a´ tad´ashoz. Ebben az esetben l´enyeg´eben a mem´ori´aban kijel¨ol¨unk egy ter¨uletet ahova a param´etereket a h´ıv´o program r´eszlet bem´asolhatja e´ s ahonnan a f¨uggv´eny majd kiveheti a param´etereket. Ezt a megold´ast is e´ rdemes egy p´eld´aval demonstr´alni, ami 10.3. t´abl´an l´athat´o. A m´odszer el˝onye, hogy ak´arh´any param´eter a´ tadhat´o egy f¨uggv´enynek. F˝o h´atr´anya, hogy mem´oria el´er´esre van sz¨uks´eg az o¨ sszes param´eter a´ tad´asa sor´an. Erre egy p´eld´at a 10.4. t´abla mutat. Ebben a p´eld´aban a f¨uggv´eny h´arom sz´amot ad o¨ ssze.
128
1 2 3 4 5 6 7 8 9 10 11 12 13 14
org 100h MOV AH, 01 INT 21h MOV [char], AL CALL charnyomtat INT 20h ; nyomtatand´ o karakter a mem´ ori´ aban charnyomtat: MOV AH, 02 MOV DL, [char] INT 21h RET char: db 0
10.3. t´abla: Param´eter a´ tad´as mem´ori´an kereszt¨ul
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
org 100h ; regiszterek be´ all´ ıt´ asa, ; amit valamilyen sz´ am´ ıt´ asb´ ol kaptunk MOV AX, 0001h MOV BX, 0010h MOV CX, 0100h ; ... ul an kereszt¨ ori´ as mem´ atad´ eter ´ ; param´ MOV SI, paramtabla MOV [SI], AX MOV [SI+2], BX MOV [SI+4], CX CALL osszead ; az eredmeny a DX regiszterben INT 20h ; regiszterek ¨ osszead´ asa osszead: MOV SI, paramtabla MOV DX, [SI] ADD DX, [SI+2] ADD DX, [SI+4] RET paramtable: dw 0, 0, 0
10.4. t´abla: M´asodik p´elda a param´eter a´ tad´asra mem´ori´an kereszt¨ul
129
10.5. a´ bra: Verem a´ llapota amikor k´et param´etert adunk a´ t egy f¨uggv´enynek a vermen kereszt¨ul
¨ 10.4.3 Param´eter a´ tad´as vermen keresztul Ez az egyik leggyakoribb param´eter a´ tad´asi m´odszer. Ebben az esetben a f¨uggv´eny param´etereit a vermen t´aroljuk el e´ s csak ut´ana h´ıvjuk meg a f¨uggv´enyt. Ezt a m´odszert is egy p´eld´an kereszt¨ul lehet a legjobban bemutatni. Vegy¨unk egy olyan f¨uggv´enyt aminek k´et sz´amot kell a´ tadni: push [szam1] push [szam2] call osszead Miut´an a CALL utas´ıt´ast v´egrehajtottuk a verem a´ llapota a 10.5. a´ br´an l´athat´o. Az a´ br´ab´ol kit˝unik, hogy a f¨uggv´enyen bel¨ul igen neh´ez hozz´af´erni a param´eterekhez, mivel a verem tetej´en a visszat´er´esi c´ım is ott van. A f¨uggv´enyen bel¨ul p´eld´aul megtehetj¨uk a k¨ovetkez˝ot: pop ax pop bx pop cx push ax
; ; ; ;
IP ide ker¨ ul szam2 ide ker¨ ul szam1 ide ker¨ ul IP c´ ım vissza ker¨ ul a veremre
L´enyeg´eben el˝osz¨or a visszat´er´esi c´ımet vessz¨uk le, ut´ana a param´etereket e´ s v´eg¨ul a visszat´er´esi c´ımet vissza kell tenni a veremre. A probl´ema ezzel a megold´assal az, hogy f´elre kell tenni regisztereket a param´eterek kinyer´es´ere, vagyis ezeket a regisztereket m´asra nem haszn´alhatjuk e´ s r´aad´asul azt a helyzetet sem tudjuk kezelni amikor p´eld´aul t¨obb mint 10 param´etert szeretn´enk a´ tadni a f¨uggv´enynek. A probl´em´ara a legjobb megold´as, hogy a param´etereket hagyjuk a vermen e´ s csak akkor f´erj¨unk hozz´ajuk amikor a param´eterek kellenek. Ez az a pont ahol fontos arra eml´ekezni, hogy a verem a mem´ori´aban tal´alhat´o e´ s ´ıgy mem´oriak´ent is kezelhet˝o (l´asd 10.1.1. bekezd´es). Ez azt jelenti, hogy az adatok a veremben egym´as ut´ani mem´oria c´ımeken tal´alhat´ok e´ s hivatkozhatunk r´ajuk SP, SP+2 e´ s SP+4 c´ımekkel. Ebben az esetben az SP (Stack Pointer) regiszter mint egy viszon´ıt´asi pont szolg´al. ´Igy egy param´eter kiolvas´as´at a k¨ovetkez˝ok´eppen tehetj¨uk meg: MOV BX, [SP+2] ; szam2 ide ker¨ ul MOV CX, [SP+4] ; szam1 ide ker¨ ul Sajnos m´eg ezzel a megold´assal is van egy kis probl´ema. Az jelenti itt a problem´at, hogy az SP regiszter e´ rt´eke folyamatosan v´altozhat a f¨uggv´enyen bel¨ul, mivel a f¨uggv´enyben b´arhol haszn´alhatunk PUSH e´ s POP utas´ıt´asokat. Ha m´egis enn´el a megold´asn´al maradunk, akkor arra kell nagyon figyelni, hogy az SP regiszternek mindig az aktu´alis e´ rt´ek´et vegy¨uk alapul. P´eld´aul az el˝oz˝o programn´al maradva a param´eterek kiolvas´asa m´odosul amikor a f¨uggv´enyen bel¨ul tov´abbi verem m˝uveleteket v´egz¨unk. PUSH [szam1] PUSH [szam2] CALL osszead
130
10.6. a´ bra: Verem a´ llapota amikor k´et param´etert adunk a´ t egy f¨uggv´enynek a vermen kereszt¨ul, de f¨uggv´enyben az SP regiszter e´ rt´eke is m´odosul ... osszead: PUSH AX PUSH BX ; verem ´ allapota az ´ abr´ an MOV AX, [SP+6] ; szam2 ide ker¨ ul MOV BX, [SP+8] ; szam1 ide ker¨ ul ... A 10.6. a´ bra a verem a´ llapot´at mutatja be akkor, amikor e´ ppen a szam2 param´etert szeretn´enk kiolvasni. Az a´ br´ab´ol l´athat´o, hogy az SP regiszter a´ ltal mutatott c´ım e´ s a p´eld´aul a szam2 param´eter c´ıme k¨oz¨otti t´avols´ag megv´altozott. Mindezek ut´an n´ezz¨uk a “legjobb” megold´ast. Az el˝oz˝o megold´assal az volt a probl´ema, hogy az SP regiszter a´ lland´oan v´altozhat. Ennek megold´as´ara amikor bel´ep¨unk a f¨uggv´enybe k´esz´ıt¨unk egy “fix” pontot, amihez k´epest a param´etereket el´erhetj¨uk. Az SP regiszter helyett a BP regisztert is haszn´alhatjuk referencia pontk´ent, miut´an az SP e´ rt´ek´et belem´asoltuk. Az el˝oz˝o p´elda v´egleges megold´as´at a vermen kereszt-li param´eter a´ tad´asra a 10.5. t´abla mutatja be. A programhoz tartoz´o verem a´ llapotait a 10.7. a´ bra mutatja be. A k¨ovetkez˝okben n´ezz¨uk meg, hogyan alakul ki a verem a´ llapota. A programban a param´eterek elt´arol´asa ugyan´ugy t¨ort´enik mint eddig, k´et PUSH utas´ıt´assal felt¨oltj¨uk az e´ rt´ekeket a veremre a 4. e´ s 5. sorban. Ez l´athat´o a 10.7.a. a´ br´an. A 6. sorban tal´alhat´o CALL utas´ıt´as felt¨olti a 7. sor c´ım´et a veremre, l´asd a 10.7.b. a´ bra. Ez az a´ br´aban az IP e´ rt´ekkel van jel¨olve. Ezut´an a CALL utas´ıt´as a´ tadja a vez´erl´est az osszead c´ımre. Itt el˝osz¨or elt´aroljuk a BP regiszter e´ rt´ek´et a 12. sorban, ahogy ez a a 10.7.c. a´ br´an l´athat´o. Erre az´ert van sz¨uks´eg, mivel minden f¨uggv´eny ezt a regisztert haszn´alja e´ s fel¨ul fogjuk ´ırni, de a f¨uggv´enyb˝ol kil´epve sz¨uks´eg lehet az eredeti e´ rt´ek´ere. (´Igy a 12. sorban a vermet id˝oleges e´ rt´ek t´arol´asra haszn´aljuk.) Ezut´an az SP regiszter aktu´alis e´ rt´ek´et a´ tm´asoljuk a BP regiszterbe a 13. sorban. Ezzel l´enyeg´eben l´etrej¨ott a stack frame vagy “f¨uggv´eny keret”. Ez l´athat´o a 10.7.d. a´ br´an. A f¨uggv´enyhez tartoz´o stack frame a f¨uggv´enyre vonatkoz´o minden fontos inform´aci´ot tartalmaz: • a f¨uggv´eny param´etereit, • a f¨uggv´eny visszat´er´esi e´ rt´ek´et, • az elmentett BP regiszter e´ rt´ek´et e´ s • a lok´alis v´altoz´okat is. (A lok´alis v´altoz´okr´ol a 10.5. bekezd´esben olvashatunk.) A fenti kialak´ıt´as miatt szokt´ak a BP regisztert “frame pointer”-nek is nevezni. Ezut´an a 14. e´ s 15. sorban elment¨unk 2 regisztert, mely utas´ıt´asok m´odos´ıtj´ak az SP regisztert. Ez l´athat´o a 10.7.e. a´ br´an.
131
V´eg¨ul a 16. e´ s 17. sorban kiolvassuk a k´et param´etert e´ s o¨ sszeadjuk o˝ ket. A 10.7.f. a´ br´an l´athat´o az, hogy a param´eterek kiolvas´as´ahoz sz¨uks´eges c´ımeket hogyan sz´amolhatjuk ki. Term´eszetesen ahogy fel´ep´ıtett¨uk a vermet, u´ gy a f¨uggv´eny v´eg´en vissza is kell a´ ll´ıtani, hogy az eredeti a´ llapotot kapjuk vissza, mintha a f¨uggv´eny h´ıv´assal semmi sem t¨ort´ent volna. Ez azt jelenti, hogy amilyen sorrendben felt¨olt¨ott¨uk az e´ rt´ekeket a veremre, azzal ellent´etes sorrendben le kell venn¨unk a veremr˝ol. ´Igy el˝osz¨or helyre´all´ıtjuk az elmentett regisztereket a 18. e´ s 19. sorban. A f¨uggv´eny v´eg´en a BP regisztert is vissza kell a´ ll´ıtani, hiszen lehet hogy ezt a f¨uggv´enyt egy m´asik f¨uggv´eny h´ıvta meg e´ s a BP regiszter a h´ıv´o f¨uggv´eny frame pointer-´et tartalmazza. A BP regiszter vissza´all´ıt´as´at a 20. sorban v´egezz¨uk el. V´eg¨ul a f¨uggv´enyb˝ol a RET paranccsal l´ep¨unk ki a 21. sorban. Ahogy ezt m´ar fent le´ırtuk, a RET utas´ıt´as leveszi a f¨uggv´eny visszat´er´esi e´ rt´ek´et. Ebben a pillanatban a verem a´ llapot´at a 10.7.a. a´ br´anak felel meg. Az a´ bra j´ol mutatja, hogy a f¨uggv´eny hi´aba t´ert vissza a 7. sorhoz a veremben m´eg vannak adatok. Ezeket az adatokat el kell t´avol´ıtani a veremr˝ol, mivel a f¨uggv´enyh´ıv´as ut´an nincs e´ rtelme a vermen tartogatni, hiszen nincs t¨obb´e hasznuk. Ezen k´ıv¨ul ha nem t´avol´ıtjuk el, akkor a sokszori f¨uggv´enyh´ıv´as megt¨olten´e a vermet. K´et lehet˝os´eg¨unk van ezt a probl´em´at orvosolni: • a h´ıv´o programr´eszlet takar´ıt vagy. • a h´ıvott programr´eszlet takar´ıt. Ezeket a strat´egi´akat t´argyaljuk a k¨ovetkez˝o bekezd´esben. 1 org 100h 2 ... ul as vermen kereszt¨ atad´ eter ´ 3 ; param´ 4 PUSH [szam1] 5 PUSH [szam2] 6 CALL osszead 7 ADD SP, 4 8 ; az eredmeny az CX regiszterben 9 ... 10 INT 20h 11 osszead: 12 PUSH BP 13 MOV BP, SP 14 PUSH AX 15 PUSH BX 16 MOV CX, [BP+6] ; szam1 kiolvas´ asa 17 ADD CX, [BP+4] ; szam2 hozz´ aad´ asa 18 POP BX 19 POP AX 20 POP BP 21 RET
10.5. t´abla: P´elda a param´eter a´ tad´asra a vermen kereszt¨ul
Fuggv´ ¨ enyh´ıv´as ut´ani takar´ıt´as Az el˝oz˝o bekezd´esben, a 10.5. t´abl´an bemutatott programban a f¨uggv´enyh´ıv´as ut´an t¨or¨olni kell 4 bytenyi e´ rt´eket. Haszn´alhatn´ank p´eld´aul ezt a megold´ast is: POP CX POP CX
132
(a)
(b)
(d)
(c)
(e)
(f)
10.7. a´ bra: Verem a´ llapotai a 10.5. t´abl´an bemutatott programban
133
de ezzel az a gond, hogy t¨onkretessz¨uk a CX regiszter e´ rt´ek´et. ´Igy itt is ink´abb a vermet, mint mem´oria t¨omb¨ot kezelj¨uk e´ s ez´ert csak az SP regisztert m´odos´ıtjuk: ADD SP, 4 Mivel a 10.7. a´ br´an a mem´oria c´ımek lentr˝ol felfel´e n¨ovekednek, ez´ert ahhoz hogy “eldobjunk” 4 byte-nyi e´ rt´eket a veremr˝ol az SP regiszter e´ rt´ek´et meg kell megn¨ovelni. Az eldob´as sz´o az´ert szerepel id´ez˝ojelek k¨oz¨ott, mert val´oj´aban az e´ rt´ekeket nem t¨or¨olj¨uk, csak annyi t¨ort´enik, hogy az SP regiszter mozgat´as´aval a´ t´all´ıtjuk a foglalt e´ s a szabad r´eszek k¨oz¨otti hat´art. Az SP regiszter a´ ltal mutatott c´ımn´el nagyobb c´ımen elhelyezked˝o e´ rt´ekek foglaltak, a kisebb c´ımen elhelyezked˝o e´ rt´ekek szabadok, azokat b´armikor fel¨ul´ırhatjuk, t¨or¨olhetj¨uk. Azt is fontos meg´erteni, hogy a k¨ovetkez˝o teljesen helytelen: osszead: ... ADD SP, 4 RET mivel ´ıgy a visszat´er´esi e´ rt´eket is elt´avol´ıtan´ank az ADD utas´ıt´assal. Ebben az esetben a LIFO szab´aly is s´er¨ul, hiszen a f¨uggv´eny h´ıv´as sor´an alkalmazott sorrenddel ellent´etes m´odon kellene mindent helyre´all´ıtani, de itt el˝obb pr´ob´aljuk meg felszabad´ıtani a param´eterek hely´et e´ s csak ut´ana akarjuk levenni a veremr˝ol a visszat´er´esi e´ rt´eket. Ha m´egis ezt a megold´ast szeretn´enk, vagyis hogy a h´ıvott f¨uggv´eny takar´ıtson a vermen, akkor a RET utas´ıt´asnak egy opcion´alis param´etert kell megadni. P´eld´aul a: RET 4 utas´ıt´as azt jelenti: IP = [SS:SP] SP = SP + 2 + 4 A fenti m˝uveletben a 2 az´ert kell, hogy a visszat´er´esi c´ımet elt´avol´ıtsuk a veremr˝ol, a 4-es e´ rt´ek pedig a RET ut´an megadott e´ rt´ek, e´ s annyi byte-ot “dobunk el” a veremr˝ol. ´Igy els˝o r´an´ez´esre furcsa lehet, hogy k´et k¨ul¨onb¨oz˝o strat´egia is van egy f¨uggv´eny param´etereinek letakar´ıt´as´ara a veremr˝ol: 1. a h´ıv´o programr´eszlet takar´ıt vagy. 2. a h´ıvott programr´eszlet takar´ıt. Hogy melyiket hazn´aljuk, az att´ol f¨ugg, hogy a f¨uggv´eny param´etereinek sz´ama fix vagy v´altoz´o lehet. Ha egy f¨uggv´enynek fix sz´am´u argumentuma van, akkor assembly-ben a 2. megold´as prefer´alt. Ez az´ert van, mert ´ıgy csak egyszer, a f¨uggv´eny v´eg´en kell implement´alni ezt a k´odr´eszletet. Ugyanakkor ha egy f¨uggv´enynek v´altoz´o sz´am´u argumentuma lehet, akkor csak az 1. megold´as haszn´alhat´o. Mit jelent az, hogy v´altoz´o sz´am´u argumentum? Itt gondoljunk p´eld´aul a C programoz´asi nyelvben haszn´alt printf f¨uggv´enyre. Ezt a f¨uggv´enyt t¨obbf´elek´eppen is megh´ıvhatjuk: printf(’’Hello’’); printf(’’Az eredmeny: %d’’, ertek); printf(’’x: %lf -- y: %lf’’, x, y); Erre a k´erd´esre m´eg visszat´er¨unk a 14. fejezetben.
134
´ Allapotmeg¨ orz´es A 10.5. t´abl´an bemutatott programban a f¨uggv´eny elej´en elment¨unk regisztereket a PUSH utas´ıt´assal, illetve a v´eg´en helyre´all´ıtjuk o˝ ket a POP paranccsal. Mi´ert lehet erre sz¨uks´eg? Vegy¨uk a k¨ovetkez˝o programr´eszletet: MOV CX, szam ciklus: CALL szamolo ... LOOP ciklus ... Ebben a programr´eszletben a CX regiszter t´arolja a ciklus v´altoz´o e´ rt´ek´et. Ha a szamolo f¨uggv´eny m´odos´ıtja a CX regisztert, akkor a program logik´aja helytelen lesz, hiszen a CX regiszter e´ rt´eke nem fut v´egig az a´ ltalunk megadott tartom´anyon. Ez´ert nagyon fontos, hogy minden olyan regisztert amit a fuggv´ ¨ enyben haszn´alunk, azt a fuggv´ ¨ eny elej´en elmentsunk, ¨ majd a fuggv´ ¨ eny v´eg´en helyre´all´ıtsunk. Itt is felmer¨ulhet a k´erd´es, hogy a h´ıv´o vagy a h´ıvott programr´eszlet v´egezze a ment´est e´ s a helyre´all´ıt´ast. Mi t¨ort´enik akkor, ha a h´ıv´o programr´eszletnek kell a regisztereket elmenteni? • A program karbantart´asa hihetetlen¨ul neh´ez lenne, mivel ha k´es˝obb a h´ıvott f¨uggv´eny m´odos´ıtjuk e´ s az eredetit˝ol elt´er˝o regisztereket haszn´alna a f¨uggv´eny, akkor mindenhol ahol a f¨uggv´enyt megh´ıvjuk m´odos´ıtani kellene a programot. • A program m´erete megn¨ovekedne, mivel ha egy f¨uggv´enyt t¨obbsz¨or megh´ıvunk, akkor minden alkalommal a regiszterek elment´es´et e´ s helyre´all´ıt´as´at is le kell programozni. Ezen okokn´al fogva a regiszterek ment´es´et e´ s helyre´all´ıt´as´at csak a h´ıvott f¨uggv´enyben szoktuk leprogramozni, ahogy ez a 10.5. t´abl´an bemutatott programban is l´attuk. Ez az megfontol´as megfelel a modul´aris programoz´as elveinek is. M´eg egy k´erd´est e´ rdemes tiszt´azni: mi´ert nem haszn´aljuk mindig a PUSHA e´ s POPA utas´ıt´asokat, amelyek minden regisztert elmentenek e´ s helyre´all´ıtanak? • El˝osz¨or is el˝ofordulhat, hogy egy f¨uggv´eny vissza akar adni egy e´ rt´eket a h´ıv´o f¨uggv´enynek. Ezt a´ ltal´aban regiszteren kereszt¨ul szoktuk megtenni, m´eghozz´a az AX regiszteren kereszt¨ul. Ebben az esetben az AX regisztert nem kell elmenteni e´ s nem szabad vissza´all´ıtani, vagyis fel¨ul´ırni a visszaadand´o e´ rt´eket. • M´asodszor a PUSHA utas´ıt´as v´egrehajt´asa 5 o´ rajel ciklust ig´enyel, m´ıg egy PUSH utas´ıt´as csak 1 o´ rajel ciklusig tart. Ez azt jelenti, hogy a PUSHA utas´ıt´asnak csak akkor van e´ rtelme ha 5 regisztern´el t¨obbet akarunk elmenteni.
´ ek e´ s c´ım szerinti param´eter a´ tad´as 10.4.4 Ert´ Csak a teljess´eg kedv´ee´ rt e´ rdemes itt megeml´ıteni az e´ rt´ek e´ s c´ım szerinti param´eter a´ tad´as k¨oz¨otti k¨ul¨onbs´eget. A t´em´ara m´eg visszat´er¨unk a 14. fejezetben is. A legt¨obb programoz´asi nyelvben, ´ıgy a C programoz´asi nyelvben is, az e´ rt´ek szerinti param´eter a´ tad´as az alap´ertelmezett m´odszer. Ez azt jelenti, hogy egy e´ rt´eket amit szeretn´enk a´ tadni a f¨uggv´enynek azt a´ tm´asoljuk a f¨uggv´eny “ter¨ulet´ere”. Az eddigiek alapj´an ez megfelel annak, hogy az e´ rt´eket felm´asoljuk a f¨uggv´eny stack frame-j´ebe. A c´ım szerinti param´eter a´ tad´as eset´en a v´altoz´o c´ım´et adjuk a´ t a f¨uggv´enynek, vagyis a v´altoz´o c´ım´et felm´asoljuk a f¨uggv´eny stack frame-j´ebe. A k´et m´odszer k¨oz¨otti k¨ul¨onbs´eg bemutat´as´ara a 10.6. t´abl´an e´ s a 10.7. t´abl´an bemutatott programokat e´ rdemes o¨ sszehasonl´ıtani. Mind a k´et program beolvas k´et karaktert, amelyeket elt´arolunk a mem´ori´aban, majd
135
1 org 100h 2 ; k´ et karakter beolvas´ asa 3 MOV AH, 01 4 INT 21h 5 MOV [char], AL 6 MOV AH, 01 7 INT 21h 8 MOV [char+1], AL 9 10 PUSH word [char] 11 CALL char2nyomtat 12 INT 20h 13 14 char2nyomtat: 15 PUSH BP 16 MOV BP, SP 17 PUSH AX 18 PUSH DX 19 PUSH BX 20 MOV BX, [BP+4] 21 MOV AH, 02 22 MOV DL, BL 23 INT 21h 24 MOV DL, BH 25 INT 21h 26 POP BX 27 POP DX 28 POP AX 29 POP BP 30 RET 31 char: db 0, 0
´ ek szerinti param´eter a´ tad´as a vermen kereszt¨ul 10.6. t´abla: Ert´ egy f¨uggv´eny seg´ıts´eg´evel a karaktereket kinyomtatjuk. A 10.6. t´abl´an l´athat´o programban, a 10. sorban a char v´altoz´o e´ rt´ek´et felt¨oltj¨uk a veremre. Az ´ıgy felt¨olt¨ott e´ rt´eket a frame stack-b˝ol a 20. sorban visszaolvassuk a BX regiszterbe, majd k¨ul¨on-k¨ul¨on kinyomtatjuk a BL e´ s BH regiszter tartalm´at. A 10.7. t´abl´an l´athat´o program egy kicsit m´as. Ebben a programban a 10. sorban a char v´altoz´o c´ım´et t¨oltj¨uk fel a verembe e´ s a 20. sorban ezt a c´ımet olvassuk ki a veremb˝ol majd m´asoljuk a´ t a BX regiszterbe. ´Igy a 22. e´ s 24. sorban az a´ tadott c´ımr˝ol olvassuk ki a nyomtatand´o karaktereket. Egy kicsit mesterk´eltnek t˝unhet ez a p´elda, de a val´odi programok eset´en is van jelent˝os´ege a c´ım szerinti param´eter a´ tad´asnak. Az egyik legfontosabb alkalmaz´asi ter¨ulete a c´ım szerinti param´eter a´ tad´asnak, amikor egy t¨omb¨ot szeretn´enk a´ tadni egy f¨uggv´enynek. Ilyenkor nem e´ rdemes a teljes t¨omb¨ot felt¨olteni a veremre, hanem elegend˝o csak a t¨omb c´ım´et a´ tadni a f¨uggv´enynek. A 10.8. t´abla egy m´asik p´eld´at mutat a c´ım szerinti param´eter a´ tad´asra, amiben egy sz¨oveget nyomtatunk ki egy f¨uggv´ennyel.
¨ 10.4.5 V´altoz´o sz´amu´ param´eter a´ tad´asa fuggv´ enynek A C programoz´asi nyelvben arra is lehet˝os´eg van, hogy egy f¨uggv´eny v´altoz´o sz´am´u param´etert fogadjon el. Ilyen f¨uggv´enyek a scanf e´ s a printf f¨uggv´enyek. Ebben az esetben a h´ıvott f¨uggv´eny
136
1 org 100h 2 ; k´ et karakter beolvas´ asa 3 MOV AH, 01 4 INT 21h 5 MOV [char], AL 6 MOV AH, 01 7 INT 21h 8 MOV [char+1], AL 9 10 PUSH char 11 CALL char2nyomtat 12 INT 20h 13 14 char2nyomtat: 15 PUSH BP 16 MOV BP, SP 17 PUSH AX 18 PUSH DX 19 PUSH BX 20 MOV BX, [BP+4] 21 MOV AH, 02 22 MOV DL, [BX] 23 INT 21h 24 MOV DL, [BX+1] 25 INT 21h 26 POP BX 27 POP DX 28 POP AX 29 POP BP 30 RET 31 char: db 0, 0
10.7. t´abla: C´ım szerinti param´eter a´ tad´as a vermen kereszt¨ul
nem tudja el˝ore, hogy param´etert adunk a´ t neki. T¨obbf´ele megold´as is l´etezik ennek a szitu´aci´onak a kezel´es´ere. Az egyik legegyszer˝ubb m´odszer, hogy az els˝o param´eter megadja, hogy h´any tov´abbi param´eter ker¨ul a veremre. Egy dologra azonban figyelni kell, hogy a param´eterek sz´ama az utols´o legyen amit felt¨olt¨unk a veremre, e´ ppen a visszat´er´esi c´ım f¨ol´e. Ezt a helyzetet a 10.8. a´ bra mutatja be. A 10.9. t´abla egy e´ rdekes minta programot mutat be az el˝obb bemutatott v´altoz´o param´eter˝u f¨uggv´enyekre. A program folyamatosan olvas sz´amjegyeket (“b´armennyit”), am´ıg null´at nem adunk meg. Ezeket a sz´amjegyeket a´ tadjuk egy f¨uggv´enynek, ami o¨ sszeadja a sz´amokat e´ s visszaadja az o¨ sszeg¨uket. V´eg¨ul a program az o¨ sszegnek megfelel˝o darab pontot nyomtat ki a k´eperny˝ore. N´ezz¨uk a program m˝uk¨od´es´et: A 2. sor egy el˝ok´esz´ıt´es, a CX regisztert lenull´azzuk, mivel a CX regiszterben fogjuk sz´amolni, hogy h´any sz´amot adott meg a felhaszn´al´o. Az 4. e´ s 5. sorban olvasunk be egy sz´amjegyet. Itt ellen˝orizni is kellene, hogy csak sz´amjegyeket adhat meg a felhaszn´al´o, de ett˝ol az ellen˝orz´est˝ol most eltekint¨unk. A 6. sorban a karakter ASCII k´odj´at sz´amm´a konvert´aljuk. Ha ennek a m˝uveletnek az eredm´enye z´erus, akkor a felhaszn´al´o a z´erus sz´amot adta meg, e´ s v´eget e´ r a beolvas´as. A 8. e´ s 9. sor seg´ıts´eg´evel felt¨oltj¨uk a beolvasott sz´amot a veremre e´ s a 10. sorban megn¨ovelj¨uk a sz´aml´al´ot. ´Igy a CX regiszter azt fogja mutatni, hogy h´any e´ rt´eket t¨olt¨ott¨unk fel a veremre. A 14. sorban mag´at a sz´aml´al´ot is felt¨oltj¨uk a veremre. A 15. sorban szerepl˝o CALL utas´ıt´assal a´ tadjuk a
137
1 org 100h 2 PUSH szoveg ; sz¨ oveg c´ ıme 3 CALL nyomtat 4 INT 20h 5 6 nyomtat: 7 PUSH BP 8 MOV BP, SP 9 PUSH AX 10 PUSH DX 11 MOV AH, 09 12 MOV DX, [BP+4] ; a c´ ımet olvassuk ki 13 INT 21h 14 POP DX 15 POP AX 16 POP BP 17 RET 18 szoveg: db ’Hello vilag$’
10.8. t´abla: Sz¨oveg nyomtat´asa f¨uggv´ennyel, mely demonstr´alja a c´ım szerinti param´eter a´ tad´ast a vermen kereszt¨ul vez´erl´est a f¨uggv´enynek. A 29. e´ s 30. sor befejezi a f¨uggv´eny stack frame-j´enek el˝ok´esz´ıt´es´et. Ekkor a 10.8. a´ br´an l´athat´o a´ llapot alakul ki a vermen. A 31. sorban elmentj¨uk a CX regisztert, mivel a 32. sorban bet¨oltj¨uk a param´eterek sz´am´at a CX regiszterbe. A v´egeredm´eny az AX regiszterben fog kialakulni ez´ert a 33. sorban lenull´azzuk az AX regisztert. A 34. sorban az SI regisztert u´ gy k´esz´ıtj¨uk el˝o, hogy ha ezt az e´ rt´eket hozz´aadjuk a BP regiszterhez, akkor r¨ogt¨on az els˝o param´eterre fog mutatni. Ezut´an a 36. sorban az AX regiszterhez adjuk az aktu´alis param´etert. A 37. sorban az SI regiszter e´ rt´ek´et kett˝ovel n¨ovelj¨uk meg, mivel a vermen 2 byte-onk´ent, vagyis word-¨onk´ent, vannak a param´eterek elt´arolva. A 38. sorban tal´alhat´o LOOP utas´ıt´as az el˝oz˝oleg a CX regiszterbe bet¨olt¨ott sz´amszor v´egrehajtja a ciklust. A 34-38. sorok k¨oz¨otti r´eszt meg lehetne oldani m´ask´eppen is, p´eld´aul: ADD BP, 6 ujra_ad: ADD AX, [BP] LOOP ujra_ad
10.8. a´ bra: A verem a´ llapota, v´altoz´o sz´am´u param´eter eset´en
138
de ennek a m´odszernek az a h´atr´anya, hogy a BP regisztert folyamatosan m´odos´ıtjuk e´ s ´ıgy t¨obbet nincs lehet˝os´eg¨unk az eredeti sz´aml´al´ot el´erni. A 39-41. sorok k¨oz¨ott megfelel˝oen befejezz¨uk a f¨uggv´enyt. Az egyik e´ rdekesebb r´eszlet a 16-18. sorok k¨oz¨ott tal´alhat´o, mivel a f¨uggv´eny el˝ott felt¨olt¨ott e´ rt´ekeket le is kell takar´ıtani a veremr˝ol. Ugyanakkor nem tudjuk el˝ore, hogy h´any darab e´ rt´eket kell let¨or¨olni a veremr˝ol. Ezt a probl´em´at itt u´ gy oldjuk meg, hogy el˝osz¨or a CX regiszter e´ rt´ek´et megn¨oveljuk 1-el. ´Igy most a CX regiszter a param´eterket sz´am´at plusz egy e´ rt´eket tartalmaz. A plusz egy arra kell, hogy a sz´aml´al´ot is felt¨olt¨ott¨uk a veremre. Ezut´an megdupl´azzuk a CX e´ rt´ek´et, mivel a vermen word m´eret˝u adatokat t´arolunk. V´eg¨ul a 18. sorban az SP regiszter m´odos´ıt´as´aval eldobjuk a felt¨olt¨ott e´ rt´ekeket a veremr˝ol. A 20-25. sorok k¨oz¨ott annyi pont karaktert nyomtatunk ki, amekkora sz´amot az AX regiszterben a f¨uggv´eny visszaadott. Erre m´ar l´attunk p´eld´at kor´abban.
139
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
org 100h mov cx, 0 ujra_olvas: mov ah, 1 int 21h sub al, ’0’ jz olvas_vege xor ah, ah push ax inc cx jmp ujra_olvas olvas_vege: push cx call osszead inc cx ; a szamlalo is bele tartozzon add cx, cx ; cx = cx * 2 add sp, cx mov cx, ax mov ah, 2 mov dl, ’.’ nyomtat: int 21h loop nyomtat int 20h osszead: push bp mov bp, sp push cx mov cx, [bp+4] xor ax,ax mov si, 6 ujra_ad: add ax, [bp+si] add si, 2 loop ujra_ad pop cx pop bp ret
10.9. t´abla: V´altoz´o sz´am´u sz´am o¨ sszead´asa e´ s annyi pont nyomtat´asa
140
¨ 10.5 Lok´alis v´altoz´ok fuggv´ enyekben Az eddigi bekezd´esekben nem esett arr´ol sz´o, hogy hogyan kezelj¨uk a f¨uggv´enyek lok´alis v´alotz´oit. P´eld´aul vegy¨uk a k¨ovetkez˝o C program r´eszletet: int szamol(int a, int b) { int temp, n; temp = a; n = b; ... } Ebben a a program r´eszletben az n e´ s temp v´altoz´ok akkor j¨onnek l´etre amikor bel´ep¨unk a f¨uggv´enybe, e´ s a v´altoz´ok megsz¨unnek amikor kil´ep¨unk a f¨uggv´enyb˝ol. ´Igy ezekre a v´altoz´ok lok´alisak e´ s “dinamikusak”. Az ilyen dinamikus v´altoz´oknak helyet foglalhatn´ank az adat szegmensben is, de ezt a m´odszert k´et okn´al fogva nem szoktuk haszn´alni: 1. Helyfoglal´as az adat szegmensben statikus e´ s akkor is megmarad a ter¨ulet amikor m´ar nem a f¨uggv´enyben vagyunk, nem a f¨uggv´eny utas´ıt´asait hajtjuk v´egre. 2. Enn´el fontosabb indok, hogy ez a fajta helyfoglal´as nem m˝uk¨odik rekurz´ıv f¨uggv´enyekkel. A rekurz´ıv f¨uggv´enyekkel a 10.6. bekezd´esben foglalkozunk. Ez´ert a lok´alis v´altoz´okat a vermen szoktuk l´etrehozni. A fenti C f¨uggv´eny eset´en az assembly-ben l´etrehozott verem a 10.9. a´ br´an l´athat´o m´odon n´ez ki. Ahogy ez l´athat´o, a BP regiszter, mint frame pointer, a lok´alis v´altoz´ok el´er´es´ere is alkalmas. A lok´alis v´altoz´ok lefoglal´asa igen egyszer˝uen megoldhat´o, csak megint mem´oria t¨ombk´ent kell tekinteni a veremre e´ s k´et lok´alis v´altoz´o eset´en ´ıgy n´ez ki: SUB SP, 4 Mivel egy v´altoz´ot 2 byte-on t´arolunk, ez´ert n´egyet vonunk ki az SP regiszterb˝ol. A kivon´asra pedig az´ert van sz¨uks´eg, mert ´ıgy a verem tetej´et elmozd´ıtjuk e´ s szabad helyek j¨onnek l´etre. Ezek ut´an n´ezz¨uk meg, hogyan lehet a fenti C programr´eszletet megval´os´ıtani assembly-ben: PUSH [b] PUSH [a] CALL szamol ADD SP, 4 ... szamol: PUSH BP MOV BP, SP SUB SP, 4 PUSH AX ... MOV AX, [BP+4] MOV [BP-2], AX MOV AX, [BP+6] MOV [BP-4], AX ... POP AX ADD SP, 4 POP BP RET
; ; ; ;
’a’ v´ altoz´ o bet¨ olt´ ese ’temp’ v´ altoz´ oban t´ arol´ as ’b’ v´ altoz´ o bet¨ olt´ ese ’n’ v´ altoz´ oban t´ arol´ as
141
10.9. a´ bra: Lok´alis v´altoz´ok helye a stack frame-ben Itt fontos meg´erteni, hogy a lok´alis v´altoz´ok az assembly k´odban tulajdonk´eppen “´atalakulnak” abban az e´ rtelemben, hogy p´eld´aul a fenti programr´eszletben a temp v´altoz´ora [BP-2] m´odon lehet hivatkozni, illetve a n v´altoz´ora [BP-4] m´odon lehet hivatkozni. Ez´ert az assembly programokban makr´ot (11. fejezet) szoktak haszn´alni az ilyen v´altoz´ok megnevez´es´ere: %define temp [BP-2] %define n [BP-4] ... PUSH [b] PUSH [a] CALL szamol ADD SP, 4 ... szamol: PUSH BP MOV BP, SP SUB SP, 4 PUSH AX ... MOV AX, [BP+4] ; MOV temp, AX ; MOV AX, [BP+6] ; MOV n, AX ; ... POP AX ADD SP, 4 POP BP RET
’a’ v´ altoz´ o bet¨ olt´ ese ’temp’ v´ altoz´ oban t´ arol´ as ’b’ v´ altoz´ o bet¨ olt´ ese ’n’ v´ altoz´ oban t´ arol´ as
10.5.1 ENTER e´ s LEAVE utas´ıt´asok A 386-os Intel processzor o´ ta van k´et speci´alis utas´ıt´as amely k¨ozvetlen¨ul t´amogatja a lok´alis v´altoz´ok l´atrehoz´as´at e´ s megsz¨untet´es´et. Az ENTER utas´ıt´as form´atuma: ENTER bytes, level A bytes param´eter azt adja meg, hogy h´any byte-ot kell lefoglalni lok´alis v´altoz´oknak. Ha nincs sz¨uks´eg lok´alis v´altoz´okra, akkor az e´ rt´eke lehet z´erus is. A m´asodik param´eter a f¨uggv´enyek egym´asba
142
a´ gyazotts´ag´at adja meg. Ha itt nem z´erust adunk meg, akkor level darab frame pointert m´asolunk a frame stack-be, a kor´abbi stack frame-b˝ol. ´Igy a: ENTER XXX, 0 utas´ıt´as megfelel az PUSH BP MOV BP, SP SUB SP, XXX utas´ıt´asoknak. A LEAVE utas´ıt´as az ENTER utas´ıt´as a´ ltal lefoglalt stack frame-t szabad´ıtja fel.
¨ 10.6 Rekurz´ıv fuggv´ enyek A rekurz´ıv f¨uggv´enyek abban speci´alisak, hogy a f¨uggv´eny tulajdonk´eppen o¨ nmag´at h´ıvja meg. M´as sz´oval u´ gy is elk´epzelhetn´enk a dolgot, hogy a f¨uggv´eny egy u´ jabb p´eld´any´at hozza l´etre, e´ s azt a f¨uggv´enyt h´ıvjuk meg. Ez val´oj´aban nincs ´ıgy, a f¨uggv´eny k´odb´ol csak egy van, de a f¨uggv´eny k¨ornyezete az ami “megdupl´az´odik”. Ez´ert nagyon fontos a verem haszn´alata, hiszen a vermen ak´arh´any stack frame-t elhelyezhet¨unk. A regiszteren vagy mem´ori´an kereszt˝uli param´eter´atad´asn´al csak egy ter¨ulet van ahova a param´etereket ´ırhatjuk, ez´ert egy u´ jabb f¨uggv´eny h´ıv´as fel¨ul´ırja az e´ rt´ekeket e´ s ´ıgy a f¨uggv´eny visszat´er´ese ut´an helytelen k´odot hajtan´ank v´egre. A rekurz´ıv f¨uggv´enyek bemutat´as´ara vegy¨unk el˝osz¨or egy pseudo k´odban ´ırt f¨uggv´enyt: F¨ UGGV´ ENY nyomtat(n) print n HA n != 0 nyomtat(n-1) HA V´ EGE F¨ UGGV´ ENY V´ EGE Ha ezt a f¨uggv´enyt megh´ıvjuk a nyomtat(2) m´odon, akkor a program kinyomtatja a 210 e´ rt´ekeket. Ebben az az e´ rdekes, hogy egy sz´amsorozatot nyomtatunk ki, pedig a k´odban semmilyen ciklus nincs! Ez´ert szokt´ak a rekurzi´ot a 4. ciklus k´epz˝o programoz´asi m´oszernek is nevezni.1 A pseudo k´odnak megfelel˝o assembly program a 10.10. t´abl´an l´athat´o, illetve a verem a´ llapotai a program fut´asa sor´an a 10.10. a´ br´an l´athat´o. Az egyes al´abr´ak azt az a´ llapotot mutatj´ak, amit az alc´ımben megadott program sorban szerepl˝o utas´ıt´as v´egrehajt´asa ut´an kapn´ank a vermen. Az a´ br´aban a sz´ınes dobozok a foglalt mem´oria ter¨uletet jel¨olik a feh´er dobozok a szabad mem´oria ter¨uletek. Az SS:SP regiszter p´aros, ami a verem tetej´et jel¨oli, mindig a sz´ınes e´ s a feh´er dobozok k¨oz´e mutat. Az a´ br´akban a dobozban szerepl˝o IP=4 jel¨oli a f¨uggv´eny visszat´er´esi e´ rt´eket, a sz´amok a dobozban pedig a f¨uggv´eny param´eternek (n) felelnek meg. Ezek ut´an n´ezz¨uk a program m˝uk¨od´es´et r´eszletesen, hogy mindenki sz´am´ara vil´agos legyen a m˝uk¨od´esi elv. A 2. sorban a 2 e´ rt´eket t¨oltj¨uk fel a veremre, mint word adatt´ıpus (10.10.a. a´ bra). A 3. sorban megh´ıvjuk a nyomtat f¨uggv´enyt, ami a visszat´er´esi e´ rt´eket felt¨olti a veremre (10.10.b. a´ bra), majd a´ tadja a vez´erl´est a 8. sornak. A 8. sorban elt´aroljuk a a BP regiszter e´ rt´ek´et e´ s ezzel l´etrehoztuk a f¨uggv´eny stack frame-j´et. Ez l´athat´o a 10.10.c. a´ br´an. Mivel a f¨uggv´enyben az AX, BX 1 Eml´ ekezz¨unk
az algoritmusok tant´argy ismereteire:
1. el˝ol tesztel˝o ciklus 2. h´atul tesztel˝o ciklus 3. sz´aml´al´o ciklus
143
e´ s DX regisztereket is haszn´aljuk, ez´ert ezeket a regisztereket elmentj¨uk a 10-12. sorokban (10.10.d.10.10.f. a´ br´ak). A 13. sorban az INT 21h megszak´ıt´as funkci´o k´odj´at a´ ll´ıtjuk be, majd a 14. sorban a veremr˝ol bet¨oltj¨uk a f¨uggv´eny param´eter´et a BX regiszterbe. A 15. sorban a´ tm´asoljuk a param´etert a DL regiszterbe, mivel a nyomtat´asn´al az INT 21h megszak´ıt´as ezt a regisztert fogja haszn´alni. Mi´ert nem r¨ogt¨on a DX regiszterbe ´ırtuk bele a f¨uggv´eny param´eter´et a 14. sorban? Az´ert nem, mert a nyomtat´ashoz a DL regiszter e´ rt´ek´et m´odos´ıtani kell, a sz´amot a sz´amnak megfelel˝o karakter ASCII k´odj´av´a kell alak´ıtani u´ gy, hogy hozz´aadunk 30h e´ rt´ek´et. A 17. sorban elv´egezz¨uk a nyomtat´ast a megszak´ıt´assal. A 18. sorban megvizsg´aljuk, hogy a f¨uggv´eny param´etere, a BL regiszter, z´eruse. Mivel nem z´erus a BL regiszter e´ rt´eke, ez´ert a 20. sorban folytatjuk. El˝osz¨or is cs¨okkentj¨uk a param´eter e´ rt´ek´et, majd ezt az e´ rt´eket felt¨oltj¨uk a veremre (10.10.g. a´ bra) a 21. sorban. A 22. sorban a f¨uggv´enyh´ıv´as ism´et felt¨olti a visszat´er´esi e´ rt´eket (10.10.h. a´ bra) e´ s a´ tadja a vez´erl´est a 8. sornak. A 8. e´ s 9. sor befejezi a stack frame el˝ok´esz´ıt´es´et (10.10.i. a´ bra). Itt l´athat´o az, hogy csak egy f¨uggv´eny van, de mivel a verem tetej´en m´as adatok vannak, ez´ert ez egy “´uj” f¨uggv´enynek sz´am´ıt, hiszen m´as adatokkal fog sz´amolni. Ezt k¨oveti a param´eter beolvas´asa (14. sor), a nyomtat´as (13-17. sor), illetve az ellen˝orz´es, hogy z´erus-e a f¨uggv´eny param´etere. Mivel a f¨uggv´eny param´etere nem z´erus, ez´ert cs¨okkentj¨uk a param´eter e´ rt´ek´et 1-el (20. sor), majd felt¨oltj¨uk a veremre a 21. sorban (10.10.m. a´ bra). A 22. sor u´ jra megh´ıvja a nyomtat f¨uggv´enyt, vagyis a 23. sor mint visszat´er´esi e´ rt´ek felker¨ul a veremre (10.10.n. a´ bra) e´ s a´ tadja a vez´erl´est ism´et a 8. sornak. Imm´ar harmadszor a BP regiszter felker¨ul a veremre (10.10.o. a´ bra) a 8. sorban, ezzel a harmadik stack frame-et el˝ok´esz´ıtve. A 10-12. sorokban a regisztereket ism´et elmentj¨uk, illetve a 13-17. sorokban a null´as e´ rt´eket kinyomtatjuk. A 18. sorban a BL regiszter e´ rt´ek´et null´anak fogjuk tal´alni, ´ıgy a 25. sorba ugrunk. A 25-28. sorokban eldobjuk az elmentett AX, BX, DX e´ s BP e´ rt´ekeket. Ez l´athat´o a 10.11.a.-10.11.d. a´ br´akon. A 29. sorban a verem tetej´en l´athat´o c´ımre (10.11.d. a´ bra) ad´odik a´ t a vez´erl´es, vagyis a 23. sorra. A 23. sorban eldobjuk a verem tetej´ere felt¨olt¨ott param´etert (10.11.e. a´ bra). Ezt k¨oveti a 25-28. sorok v´egrehajt´asa, ahol megint helyre´all´ıtjuk az elmentett regisztereket (10.11.f.-10.11.j. a´ br´ak), majd a 29. sorban a verem tetej´en tal´alhat´o c´ımre visszat´er a f¨uggv´eny, vagyis a 23. sorba. Itt ism´et eldobjuk a vermen tal´alhat´o e´ rt´ekekeket (10.11.k.-10.11.p. a´ br´ak). Amikor ism´et a 29. sorba e´ r¨unk akkor a verem tetej´er˝ol levessz¨uk a visszat´er´esi c´ımet (10.11.p. a´ bra) e´ s elugrunk az ´ıgy megadott c´ımre, a 4. sorba. A 4. sor v´egrehajt´as´aval az utols´o e´ rt´eket is letakar´ıtjuk a veremr˝ol e´ s vissza´all az eredeti a´ llapot, amikor is semmi nem volt a vermen (10.11.r. a´ bra).
10.7 Hat´ekonys´ag Ahogy ebben a fejezetben l´attuk a f¨uggv´enyek nagy m´ert´ekben t´amogatj´ak a modul´aris programoz´ast. Ugyanakkor a f¨uggv´enyek haszn´alat´ae´ rt “fizetn¨unk” is kell, mivel a param´eter a´ tad´asi m´odszerek megval´os´ıt´as´ahoz extra utas´ıt´asokat kell alkalmazni, amelyek nem k¨ozvetlen¨ul az algoritmushoz tartoznak. Az ilyen extra utas´ıt´asokat “overhead”-nek nevezz¨uk. Vegy¨unk egy programr´eszletet, k´et v´altoz´o cser´ej´et. Ez l´athat´o a 10.11. t´abl´an. A bal oldali programr´eszlet egyszer˝uen v´egrehajtja a cser´et, a jobb oldali program f¨uggv´enyk´ent v´egzi el ugyanezt. A m´asodik esetben l´enyeg´eben csak a f¨uggv´enyh´ıv´assal e´ s a RET utas´ıt´assal eg´esz´ıtj¨uk ki a programot. Mind a k´et programr´eszletben ECX-szer hajtjuk v´egre a m˝uveletet. (Jelen p´eld´aban az´ert haszn´aljuk a 32 bites regisztereket, mert “nagyon sokszor” szeretn´enk v´egrehajtani, hogy m´erhet˝o adatokat kapjunk.) Amennyiben mind a k´et k´odr´eszletet lem´erj¨uk 50 000 000 fut´as ut´an, azt kapjuk, hogy alap esetben 160 ms-ig, m´ıg f¨uggv´enyk´ent val´o futtat´as eset´en 240 ms-ig tart a programr´eszlet fut´asa. A k¨ul¨onbs´eg ezen m´er´esek szerint m´asf´elszeres. (M´as m´er´esek szerint ez lehet 2.3-szeres k¨ul¨onbs´eg is [2.]) Azt is e´ rdemes meggondolni, hogy ha param´etereket is a´ tadunk a f¨uggv´enynek akkor ez az “overhead” m´eg nagyobb lehet, ´ıgy sebess´egre val´o optimaliz´al´as eset´en a f¨uggv´eny hiv´asok minimaliz´aland´ok (l´asd 15.1. e´ s 15.1.5. bekezd´es).
10.8 Ellen˝orz˝o k´erd´esek 1. Mi a k¨ul¨onbs´eg a sor e´ s verem adatszerkezetek k¨oz¨ott?
144
(a) IP=2
(b) IP=3
(c) IP=8
(d) IP=10
(e) IP=11
(n) IP=22
(f) IP=12
(o) IP=8
(g) IP=21
(p) IP=10
(h) IP=22
(q) IP=11
(i) IP=8
(j) IP=10
(k) IP=11
(l) IP=12
(m) IP=21
(r) IP=12
10.10. a´ bra: A verem a´ llapotai a 10.10. t´abl´an bemutatott rekurz´ıv f¨uggv´eny v´egrehajt´asa sor´an
145
(a) IP=25
(b) IP=26
(k) IP=29
(c) IP=27
(l) IP=23
(d) IP=28
(m) IP=25
(e) IP=29
(n) IP=26
(f) IP=23
(o) IP=27
(g) IP=25
(p) IP=28
(h) IP=26
(q) IP=29
(i) IP=27
(j) IP=28
(r) IP=4
10.11. a´ bra: A verem a´ llapotai a 10.10. t´abl´an bemutatott rekurz´ıv f¨uggv´eny v´egrehajt´asa sor´an
146
1 org 100h 2 push 2 3 call nyomtat ; nyomtat(3) 4 add sp,2 5 int 20h 6 7 nyomtat: 8 push bp 9 mov bp,sp 10 push ax 11 push bx 12 push dx 13 mov ah, 2 ; 14 mov bx, word [bp+4] ; | 15 mov dl, bl ; | print n 16 add dl, 30h ; | 17 int 21h ; 18 cmp bl, 0 ; HA n != 0 19 jz nyomtat_vege 20 dec bl ; 21 push bx ; | nyomtat(n-1) 22 call nyomtat ; 23 add sp,2 24 nyomtat_vege: 25 pop dx 26 pop bx 27 pop ax 28 pop bp 29 ret
10.10. t´abla: Sz´amjegyek nyomtat´asa rekurz´ıv f¨uggv´ennyel 2. Mi az a stack underflow? Melyik m˝uvelet tudn´a ezt okozni? 3. Mi az a stack overflow? Melyik m˝uvelet tudn´a ezt okozni? 4. Melyek a verem f˝o felhaszn´al´asi ter¨uletei? 5. Melyik utas´ıt´assal lehet felt¨olteni egy e´ rt´eket a veremre? 6. Ha POP utas´ıt´as nem megengedett, akkor hogyan tudunk levenni egy e´ rt´eket a veremr˝ol? 7. Mely regiszterek mutatj´ak meg a verem tetej´enek c´ım´et? 8. Hogyan cser´elhetj¨uk fel k´et regiszter tartalm´at a vermen kereszt¨ul? 9. Mi az a stack frame e´ s mit tartalmaz? 10. Melyik regiszter a frame pointer? 11. Milyen m´odszerekkel adhatunk a´ t param´etert egy f¨uggv´enynek? 12. Ha a regiszteren kereszt¨ul adunk a´ t param´etert, akkor ennek a m´odszernek milyen el˝onyei e´ s h´atr´anyai vannak?
147
ujra: mov mov mov mov
eax, ertek1 ebx, ertek2 ertek2, eax ertek1, ebx
dec ecx jnz ujra
ujra: call csere dec ecx jnz ujra jmp vege csere: mov eax, ertek1 mov ebx, ertek2 mov ertek2, eax mov ertek1, ebx ret vege:
10.11. t´abla: Programr´eszlet k´et v´altoz´o cser´ej´ere f¨uggv´eny n´elk¨ul e´ s f¨uggv´ennyel 13. Mely mem´oria ter¨uleten defini´alunk lok´alis v´altoz´okat egy f¨uggv´enyben? 14. Mi´ert nem az adat szegmensben defini´aljuk a lok´alis v´altoz´okat?
10.9 Feladatok 9. fejezetben bemutatott programokat ´ırjuk a´ t u´ gy, hogy az id˝oleges t´arol´asra ne a MOV utas´ıt´ast haszn´aljuk, hanem a vermet.
148
11. Fejezet
Makr´ok A makr´ok nagyon e´ rdekes e´ s hasznos programoz´asi konstrukci´ok. Mit nevez¨unk makr´onak? Ez sajnos a programoz´asi nyelvt˝ol is f¨ugg. Az assembly programoz´asi nyelvben a makr´ok hasonl´ok a C programoz´asi nyelvben haszn´alt makr´okhoz, de e´ rdekes m´odon egy kicsit t¨obbet is tudnak. Persze erre az extra seg´ıts´egre sz¨uks´eg is van, mivel az assembly programoz´asi nyelv egy alacsony szint˝u vagyis g´epk¨ozeli programoz´asi nyelv. Assembly-ben a makr´o arra ad lehet˝os´eget, hogy egy sz¨oveg blokkhoz egy nevet rendelj¨unk hozz´a, majd amikor az assembler az adott n´evvel tal´alkozik a forr´ask´odban, akkor a n´ev hely´ere a sz¨oveg blokkot illeszti be. A behelyettes´ıt´es angol neve: macro expansion. Egyszer˝uen fogalmazva a macro egy fejlett sz¨oveg behelyettes´ıt´esi mechanizmus.
11.1 Egy soros makr´ok A legegyszer˝ubb makr´ok egy sorosak. Erre egy p´elda: %define csereaxbx
XCHG AX, BX
amit egy programk´odban a k¨ovetkez˝ok´eppen is haszn´alhatunk: MOV AX, 1 MOV BX, 2 ... csereaxbx ... Amikor az assembler ezt leford´ıtja, akkor azt k´et l´ep´esben teszi. El˝osz¨or is elv´egzi a makr´o behelyettes´ıt´eseket: MOV AX, 1 MOV BX, 2 ... XCHG AX, BX ... majd ezut´an az assembler legener´alja a bin´aris k´odot. Ez azt jelenti, hogy egy k´et l´ep´eses (two-pass) ford´ıt´asi folyamat v´egeredm´enyek´ent j¨on l´etre a bin´aris k´od. Ez a k´et l´ep´eses folyamat jellemz˝o a C programoz´asi nyelvre is, ahol az els˝o l´ep´es az el˝ofeldolgoz´as (preprocessing) e´ s a m´asodik l´ep´es a ford´ıt´as (compiling).
149
A makr´ok o¨ sszetettebbek is lehetnek, mivel rendelkezhetnek argumentummal vagy param´eterrel, mint a f¨uggv´enyek. Ugyanakkor ez felveti a makr´ok e´ s f¨uggv´enyek k¨oz¨otti kapcsolatot. Mikor, melyiket e´ s hogyan haszn´aljuk? Egy f¨uggv´eny tulajdonk´eppen egy al-programnak felel meg. Egy gyakorlatiasabb megfogalmaz´as szerint a f¨uggv´eny egy olyan utas´ıt´as sorozatnak felel meg, amelyet sokszor, t¨obb k¨ul¨onb¨oz˝o helyen haszn´alunk a programunkban. ´Igy a f¨uggv´eny l´etrehoz´as´ahoz az ism´etl˝od˝o k´odr´eszletet “kiemelj¨uk”, nevet adunk neki, majd amikor sz¨uks´eg¨unk van r´a, akkor a nev´evel hivatkozunk r´a e´ s ezzel a´ tadjuk a f¨uggv´enynek a vez´erl´est (megh´ıvjuk). Ez a defin´ıci´o nagyon hasonl´o a fenti makr´o defin´ıci´ohoz. N´ezz¨uk makr´ok e´ s f¨uggv´enyek k¨oz¨otti k¨ul¨onbs´egeket: • A legfontosabb k¨ul¨onbs´eg a makr´ok e´ s f¨uggv´enyek k¨oz¨ott a gener´alt bin´aris k´odban van. – Egy f¨uggv´eny eset´en a bin´aris k´odot az assembler egyszer gener´alja le, majd minden alkalommal amikor a k´odr´eszletre sz¨uks´eg van, akkor a CALL utas´ıt´assal h´ıvjuk meg. Ez azt is jelenti, hogy a f¨uggv´enyh´ıv´as hely´ere a CALL utas´ıt´as bin´aris k´odja ker¨ul. – Egy makr´ok eset´en, ahol a makr´o neve szerepel, oda lesz behelyettes´ıtve a makr´o forr´ask´odja e´ s oda ker¨ul a bin´aris k´od is. Minden alkalommal. Ez azt jelenti, hogy mindenhol, ahol a makr´o neve szerepel a k´odban, oda a makr´o teljes bin´aris k´odja belefordul. • A m´asik nagyon fontos k¨ul¨onbs´eg a param´eter a´ tad´asi m´odszerben van. – F¨uggv´enyek eset´en a 10. fejezetben t´argyalt param´eter a´ tad´asi m´odszerek lehets´egesek: regiszteren, mem´ori´an e´ s vermen kereszt¨ul. – Makr´ok eset´en k¨ozvetlen param´eter a´ tad´as lehets´eges, u´ gy mintha egy magas szint˝u programoz´asi nyelvet haszn´aln´ank. P´eld´aul: %define csere(a,b) XCHG a, b ... csere(AX, BX) ... Ebb˝ol a k´odr´eszletb˝ol az al´abbi k´od gener´al´odik a makr´o behelyettes´ıt´es ut´an: ... XCHG AX, BX ... Ezek ut´an a makr´o defini´al´as n´eh´any tov´abbi fontos szab´alya a k¨ovetkez˝o: • Egy makr´o defin´ıci´o sor´an a kis e´ s nagy bet˝u k¨oz¨otti k¨ul¨onbs´eg sz´am´ıt. • Rekurz´ıv defin´ıci´o eset´en a behelyettes´ıt´es csak egyszer t¨ort´enik meg. P´eld´aul: %define a(x) 1+a(x) mov ax, a(3) amib˝ol a k¨ovetkez˝o k´od gener´al´odik: mov ax, 1+a(3) • Nagyon fontos, hogy a behelyettes´ıt´es a makr´o haszn´alatakor t¨ort´enik e´ s nem a defini´al´askor. P´eld´aul: %define b(x) 2*x %define a(x) 1+b(x) mov ax, a(8)
150
A p´eld´aban amikor az assembler megl´atja a a(8) kifejez´est, akkor el˝osz¨or az a(x) makr´o helyettes´ıt˝odik be: mov ax,1+b(8) ezut´an pedig a b(x) makr´o behelyettes´ıt´ese t¨ort´enik meg: mov ax,1+2*8
11.2 T¨obb soros makr´ok T¨obb soros makr´ok eset´en a szintakszis a k¨ovetkez˝o: %macro n´ ev param_sz´ am asok ıt´ utas´ asok ıt´ utas´ ... %endmacro A n´ ev adja meg a makr´o nev´et, amivel hivatkozni lehet r´a. A param_sz´ am adja meg a makr´onak megadhat´o param´eterek sz´am´at. N´ezz¨uk az els˝o egyszer˝u p´eld´at, amely tulajdonk´eppen egy szorz´asnak felel meg: %macro szorzasAX_4el shl AX, 2 %endmacro Ez egy olyan makr´o, aminek nincs param´etere e´ s haszn´alata igen egyszer˝u: mov AX, 3 szorzasAX_4el amib˝ol a gener´alt k´od a k¨ovetkez˝o lesz: mov AX, 3 shl AX, 2 Ez a p´elda el´eg korl´atozott, mivel csak az AX regisztert k´epes 4-el megszorozni. Ha szeretn´enk ezt a korl´atoz´ast elt´avol´ıtani, akkor egy olyan makr´ot kellene defini´alnunk, amelyiknek megadhatjuk, hogy melyik regisztert akarjuk megszorozni: %macro szorzas_4el 1 shl %1, 2 %endmacro A n´ev ut´an megadott sz´am adja meg, hogy a makr´onak van egy argumentuma. Erre az argumentummal egy sz´azal´ek jellel e´ s ut´ana a param´eter sz´am´aval lehet hivatkozni, p´eld´aul: %1. ´Igy ha ezt a makr´ot haszn´aljuk: mov BL, 3 szorzas_4el BL akkor b´armilyen regiszter megadhatunk, p´eld´aul BL, e´ s ´ıgy a behelyettes´ıtett k´od a k¨ovetkez˝o lesz:
151
mov BL, 3 shl BL, 2 Ha t¨obb param´etert akarunk a´ tadni egy makr´onak, erre is lehet˝os´eg van: %macro csere 2 XCHG %1, %2 %endmacro Ennek a makr´onak a haszn´alata a k¨ovetkez˝o lesz: csere AX, BX Amint ez l´athat´o a makr´ok teljesen “integr´al´odhatnak” az assembly nyelvbe. Ennek sajnos az is a k¨ovetkezm´enye, hogy a makr´ok e´ s az utas´ıt´asok n´eha egy kicsit o¨ ssze is keverhet˝ok, p´eld´aul: %macro push 2 push %1 push %2 %endmacro ... push ax push bx, cx Itt is l´athat´o, hogy az els˝o alkalommal a push egy utas´ıt´as, m´ıg a m´asodik alkalommal a push egy makr´o, amit majd az assembler lecser´el a defin´ıci´oban megadott utas´ıt´asokra.
11.2.1 C´ımk´ek makr´okban Eddig csak olyan makr´okat l´attunk amelyekben nem haszn´altunk semmilyen mem´oria c´ımet, ugyanakkor a c´ımek egy kis figyelmet e´ rdemelnek. Tegy¨uk fel, hogy a k¨ovetkez˝o makr´ot defini´aljuk, amely egy e´ rt´eket o¨ sszehasonl´ıt z´erussal e´ s aszerint a´ ll´ıtja be az AX regiszter e´ rt´ek´et, hogy z´erus volt-e az e´ rt´ek: %macro cmp_zero 1 cmp %1, 0 jz nulla mov AX, 1 nulla: mov AX, 0 %endmacro Ha ezt a makr´ot t¨obbsz¨or is haszn´aljuk: cmp_zero CX ... cmp_zero DX ... akkor a k¨ovetkez˝o k´od gener´al´odik: cmp CX, 0 jz nulla mov AX, 1 nulla: mov AX, 0
152
... cmp DX, 0 jz nulla mov AX, 1 nulla: mov AX, 0 ... Ahogy ez itt is l´athat´o, ebben az esetben a nulla c´ım k´etszer is megjelenik a k´odban. Ezt az assembler nem engedi meg e´ s hib´at fog gener´alni. Ilyen esetben a megold´as az, hogy a nulla c´ımnek “lok´alisnak”, egyedinek kell lennie az egyes makr´o behelyettes´ıt´esek sor´an. Ezt u´ gy lehet el´erni, hogy a c´ım el´e kett˝o darab sz´azal´ek jelet kell tenni: %macro cmp_zero 1 cmp %1, 0 jz %%nulla mov AX, 1 %%nulla: mov AX, 0 %endmacro Ha ezt az u´ jabb makr´o defin´ıci´ot haszn´aljuk: cmp_zero CX ... cmp_zero DX ... akkor m´ar nem lesz semmi gond, hiszen a k¨ovetkez˝o k´od gener´al´odik: cmp CX, 0 jz nulla2345 mov AX, 1 nulla2345: mov AX, 0 ... cmp DX, 0 jz nulla7453 mov AX, 1 nulla7453: mov AX, 0 ... A makr´okban a dupla sz´azal´ek jellel defini´alt c´ımek eset´en az assembler garant´alja, hogy minden egy´eb, a programban el˝ofordul´o c´ımt˝ol elt´er˝o c´ımet fog gener´alni, vagyis minden makr´o behelyettes´ıt´es eset´en a c´ım egyedi lesz.
11.2.2 “Greedy” makr´o param´eterek Az is el˝ofordulhat, hogy nem csak fix sz´am´u argumentumot akarunk megadni egy makr´onak, hanem n´eha t¨obbet is. Erre az esetre val´o a “greedy” param´eter, ami azt jelenti, hogy minden ut´ana k¨ovetkez˝o e´ rt´ek hozz´a tartozik. P´eld´aul: %macro
PRINT 1+
153
JMP %%atlep %%szoveg: DB %1, ’$’ %%atlep: MOV DX, %%szoveg MOV AH,9 INT 21H %endmacro A p´eld´aban a 1+ azt jelenti, hogy a makr´onak egy param´etere biztosan van, de lehet t¨obb is. Abban az esetben ha t¨obb param´etert is megadunk, akkor mindegyik, egym´as ut´an a %1 hely´ere ker¨ul. A fenti makr´o haszn´alat´ara a p´elda: PRINT ’Hello vilag’, 10, 13 amib˝ol a k¨ovetkez˝o k´od gener´al´odik: JMP atlep87643 szoveg8964: DB ’Hello vilag’, 10, 13, ’$’ atlep87643: MOV DX, szoveg8964 MOV AH,9 INT 21H
¨ 11.3 Makr´ok e´ s fuggv´ enyek m´eg egyszer A fenti ismeretek t¨ukr´eben e´ rdemes m´eg egyszer o¨ sszehasonl´ıtani a f¨uggv´enyeket e´ s a makr´okat egy p´eld´an kereszt¨ul. A p´eld´aban az el˝oz˝o bekezd´es makr´oj´at hasonl´ıtjuk o¨ ssze egy f¨uggv´ennyel, amelyik szint´en egy sz¨oveget nyomtat ki. Az o¨ sszehasonl´ıt´as a 11.1. t´abl´an tal´alhat´o. A t´abl´ab´ol u´ gy t˝unik, hogy a makr´ok r¨ovidebb k´odot gener´alnak, de a´ ltal´aban ink´abb az a helyzet, hogy a tov´abbi makr´o h´ıv´asok eset´en u´ jra e´ s u´ jra t¨obb k´od ker¨ul be a forr´ask´odba, m´ıg az u´ jabb f¨uggv´enyh´ıv´asok eset´en csak u´ jabb PUSH, CALL e´ s ADD utas´ıt´asok ad´odnak hozz´a a programhoz.
˝ 11.4 Makr´ok gyujtem´ enyek A gyakran haszn´alt makr´okat o¨ ssze lehet gy˝ujteni egy file-ba, majd ezeket k´es˝obb igen k¨onnyen lehet haszn´alni. P´eld´aul defini´aljunk k´et egyszer˝u makr´ot. Az egyik makr´o egy billenty˝u le¨ut´es´ere v´ar, a m´asik makr´o pedig a programb´ol val´o kil´ep´est hajtja v´egre: %macro BillVar 0 MOV AH, 0 INT 16h %endmacro %macro Kilep 0 INT 20h %endmacro Ezeket a makr´okat ments¨uk el egy makro.inc file-ba. Ha ezut´an ezeket a makr´okat egy programban haszn´alni szeretn´enk, akkor a k¨ovetkez˝o m´odon j´arhatunk el:
154
%include "makro.inc" org 100h BillVar Kilep Ebb˝ol is l´athat´o, hogy ha megfelel˝o neveket haszn´alunk a makr´ok eset´en, akkor nagyon “besz´edes” (k¨onnyen e´ rthet˝o, e´ rtelmezhet˝o) programokat tudunk ´ırni a seg´ıts´eg¨ukkel.
155
Makr´o defin´ıci´o %macro PRINT 1+ JMP %%atlep %%szoveg: DB %1, ’$’ %%atlep: MOV DX, %%szoveg MOV AH,9 INT 21H %endmacro Makr´o haszn´alat
PRINT ’Hello’, 13, 10 PRINT ’Vilag’, 13, 10
Makr´ob´ol gener´alt k´od
JMP atlep6345 szoveg9092: DB ’Hello’, 13, 10, ’$’ atlep6345: MOV DX, szoveg9092 MOV AH,9 INT 21H JMP atlep7231 szoveg1235: DB ’Vilag’, 13, 10, ’$’ atlep7231: MOV DX, szoveg1235 MOV AH,9 INT 21H
F¨uggv´eny defin´ıci´o PRINT: PUSH BP MOV BP, SP PUSH AX PUSH DX MOV AH, 9 MOV DX, [BP+4] INT 21h POP DX POP AX POP BP RET F¨uggv´eny haszn´alat PUSH szoveg1 CALL PRINT ADD SP, 2 PUSH szoveg2 CALL PRINT ADD SP, 2 ... szoveg1: db ’Hello’, 13, szoveg2: db ’Vilag’, 13, F¨uggv´enyb˝ol gener´alt k´od PRINT: PUSH BP MOV BP, SP PUSH AX PUSH DX MOV AH, 9 MOV DX, [BP+4] INT 21h POP DX POP AX POP BP RET ... PUSH szoveg1 CALL PRINT ADD SP, 2 PUSH szoveg2 CALL PRINT ADD SP, 2 ... szoveg1: db ’Hello’, 13, szoveg2: db ’Vilag’, 13,
11.1. t´abla: Makr´ok e´ s f¨uggv´enyek o¨ sszehasonl´ıt´asa
156
10, ’$’ 10, ’$’
10, ’$’ 10, ’$’
11.5 Ellen˝orz˝o k´erd´esek 1. Mi az a makr´o? 2. Miben hasonl´ıtanak e´ s miben k¨ul¨onb¨oznek a makr´ok e´ s a f¨uggv´enyek? 3. Hogyan defini´alhatunk lok´alis c´ımeket makr´okban? 4. Hogyan defini´alhatunk t¨obb soros makr´ot? 5. Mi t¨ort´enik rekurz´ıv makr´ok eset´en? 6. Fel kell-e t¨olteni a makr´o param´etereit a veremre a makr´o megh´ıv´asa el˝ott? 7. Mit jelent az, hogy “greedy” makr´o param´eter? 8. Mi lesz a forr´as k´od a k¨ovetkez˝o makr´o haszn´alata ut´an: %define %define %define ... MOV AX,
bb(x) 2+x aa(x) 1+bb(x) cc(x) [BX+aa(x)] cc(1)
157
158
12. Fejezet
˝ String muveletek A string kezel˝o utas´ıt´asok mem´oriablokkokkal v´egeznek m˝uveletet. A string, tulajdonk´eppen sz¨oveg, a sz¨oveg pedig nem m´as mint egy karakter sorozat vagy byte sorozat e´ s egy byte sorozat amikor a mem´ori´aban t´aroljuk akkor pedig megfelel egy mem´oriablokknak. A sz¨ovegek t´arol´as´ara k´et strat´egi´at alkalmazhatunk: • fix m´eret˝u sz¨ovegek e´ s • v´altoz´o m´eret˝u sz¨ovegek. A fix m´eret˝u sz¨ovegek eset´en minden sz¨oveg azonos m´eret˝u e´ s ´ıgy egyszer˝u a kezel´es¨uk. Ugyanakkor k´et probl´ema is lehet a fix m´eret˝u sz¨ovegekkel: • Ha az adott sz¨oveg hosszabb mint a fix m´eret, akkor azok a karakterek amelyek a fix m´ereten t´ulra esnek elvesznek. Ilyenkor ler¨ovid´ıtj¨uk (truncation) a sz¨oveget. • Ha az adott sz¨oveg r¨ovidebb mint a fix m´eret, akkor a marad´ek karaktereket ki szokt´ak t¨olteni (padding). Ezt a k´et probl´em´at figyelembe kell venni akkor, amikor a fix m´eret˝u sz¨ovegek m´eret´et pr´ob´aljuk ¨ on¨osen nagy e´ rt´eket akarunk v´alasztani, ´ıgy minden sz¨oveg belef´er e´ s egy sz¨oveget meghat´arozni. Oszt¨ sem kell ler¨ovid´ıteni. Ugyanakkor ha csak egy nagy e´ s t¨obb kisebb sz¨oveg van, akkor el´eg sok helyet elpazarolhatunk. Erre a dilemm´ara jelent megold´ast a v´altoz´o m´eret˝u sz¨oveg. A v´altoz´o m´eret˝u sz¨ovegek eset´en a sz¨oveg pontosant annyi karaktert t´arol, mint amennyire sz¨uks´eg van. Ugyanakkor a sz¨oveg karakterein k´ıv¨ul m´eg egy adatra sz¨uks´eg van e´ s ez a sz¨oveg hossza. A sz¨oveg hossz´at k´etf´ele strat´egi´aval lehet megadni: • explicit m´odon t´aroljuk a sz¨oveg m´eret´et • egy lez´ar´o karaktert (sentinel character) haszn´alunk. N´ezz¨unk egy p´eld´at arra, amikor explicit m´odon t´aroljuk a sz¨oveg m´eret´et: szoveg: db ’Valamilyen szoveg’ hossz: db $-szoveg ahol a $ jel az aktu´alis c´ımet jelenti. Ez a megold´as az´ert m˝uk¨odik, mivel a $ jel e´ ppen a szoveg c´ımen tal´alhat´o sz¨oveg utols´o karaktere ut´ani c´ımet jelenti e´ s ebb˝ol vonjuk ki mag´at a szoveg c´ımet. Felt´etelezve, hogy a NASM ford´ıt´o a szoveg szimb´olikus c´ımet a 200d decim´alis c´ımre ford´ıtja le, akkor a fenti p´eld´aban a $ jel e´ rt´eke 217d lesz e´ s ´ıgy a hossz c´ımen a 17d e´ rt´eket fogjuk t´arolni. ´Igy term´eszetesen ezt is ´ırhatn´ank:
159
szoveg: db ’Valamilyen szoveg’ hossz: db 17 de ezzel az a probl´ema, hogy ha k´es˝obb megv´altoztatjuk a sz¨oveg tartalm´at akkor a hossz v´altoz´ot is meg kell v´atloztatni. Az el˝oz˝o megold´ast alkalmazva a sz¨oveg hossza automatikusan sz´amol´odik ki ´ıgy leveszi ezt a terhet r´olunk. A m´asik megold´asban egy lez´ar´o karakterrel jel¨olj¨uk a sz¨oveg v´eg´et, ´ıgy nincs sz¨uks´eg explicit m´odon t´arolni a sz¨oveg hossz´at, hiszen a sz¨oveg elej´et˝ol a lez´ar´o karakterig kell csak megsz´amolni a karakterek sz´am´at. Enn´el a m´odszern´el fontos felt´etelez´es, hogy a lez´ar´o karakter nem fog el˝ofordulni mag´aban a sz¨ovegben. Azt m´ar l´attuk, hogy ha az INT 21h megszak´ıt´ast haszn´aljuk a 09h funkci´ok´oddal akkor a sz¨oveg v´eg´en a $ jelnek kell szerepelnie. Ezzel szemben a C programoz´asi nyelvben a sz¨oveg v´eg´en az ASCII NULL karakter szerepel. Ez a karakter nem o¨ sszekeverend˝o a null´as sz´am ASCII k´odj´aval, mivel ez az e´ rt´ek 30h lenne, m´ıg az ASCII NULL karakter e´ rt´eke 00h. Az ilyen null´aval lez´art sz¨ovegeket ASCIIZ sz¨ovegnek is szokt´ak nevezni. N´ezz¨uk erre is egy p´eld´at: szoveg: db ’Valamilyen szoveg’,0
12.1 String utas´ıt´asok A string utas´ıt´asok a 7.6. bekezd´esben tal´alhat´ok. Amint a bekezd´esb˝ol l´athat´o, az utas´ıt´asok operandusai lehetnek egy forr´as c´ım, egy c´el c´ım vagy mindkett˝o. A 8086-os processzoron a forr´as c´ım a DS:SI (SI = source index) regiszter p´ar adja meg, m´ıg 32 bites rendszeren a DS:ESI regiszterek adj´ak meg a forr´as c´ımet. Hasonl´oan a 8086-os processzoron a c´el c´ımet az ES:DI (DI = destination index) regiszterek, m´ıg 32 bites rendszeren az ES:EDI regiszterek adj´ak meg. Az utas´ıt´asok a le´ırtak alapj´an automatikusan friss´ıtik az SI illetve DI regisztereket az adat m´eret´evel: byte, 2 byte (word) vagy 4 byte (dword). A friss´ıt´es lehet cs¨okkent´es vagy n¨ovel´es is, az ir´any (Direction) st´atusz bitt˝ol f¨ugg˝oen. Az utas´ıt´asok jelent˝os´ege abban van, hogy ism´etl˝o prefix-el lehet haszn´alni, amelyeket a 7.6. bekezd´es szint´en t´argyal. A prefix lehet felt´eteles vagy felt´etel n´elk¨uli.
12.1.1 String m´asol´as Az adatok m´asol´as´at e´ rdemes egy kicsit jobban megvizsg´alni, mivel e´ rdekes m˝uk¨od´esi m´odokat fedezhet¨unk fel, illetve k´es˝obbiekben azokat j´ol haszn´alhatjuk is. A m´asol´as alapja a MOVS utas´ıt´as (l´asd ??. bekezd´es), melynek m˝uk¨od´es´et a k¨ovetkez˝o pseudo-k´od tudja le´ırni: [ES:DI] = [DS:SI] if(DF == 0) { DI = DI + 1 SI = SI + 1 } else { DI = DI - 1 SI = SI - 1 } String m´asol´as egyszeruen ˝ Az adatok m´asol´asa eset´en a´ ltal´aban nem kell azzal foglalkozni, hogy az index regisztereket n¨ovelj¨uk vagy cs¨okkentj¨uk a m´asol´as sor´an. A k¨ovetkez˝o assembly programr´eszletben n¨ovekv˝o c´ımek mellett
160
(a)
(b)
(c)
(d)
(e)
(f)
12.1. a´ bra: A MOVSB utas´ıt´as egyszer˝u m˝uk¨od´ese m´asoljuk a´ t a t¨omb¨ot: cld lea lea mov rep ... array1: array2:
si, array1 di, array2 cx, 321 movsb repb 321 repb 321
A m´asol´as folyamat´at a 12.1. a´ bra mutatja be. String m´asol´as a´ tlapol´assal Ezek ut´an n´ezz¨uk meg mi t¨ort´enik a k¨ovetkez˝o programr´eszletben? cld lea si, array1
161
(a)
(b)
(c)
(d)
(e)
(f)
12.2. a´ bra: A MOVSB utas´ıt´as m˝uk¨od´ese a´ tlapol´assal e´ s n¨ovekv˝o c´ımekkel lea di, array2 mov cx, 321 rep movsb ... array1: db ’X’ array2: repb 321 ´ A v´altoz´as abban van, hogy Ugy t˝unik mintha az array1 nev˝u v´altoz´o most csak 1 elem˝u lenne. Akkor m´egis hogyan fog ez a programr´eszlet 321 byte-ot a´ tm´asolni? Azt kell figyelembe venni, hogy az assembler az egym´as ut´an ´ırt adat vagy k´odr´eszleteket k¨ozvetlen¨ul egym´as ut´an fogja elhelyezni a mem´ori´aban a ford´ıt´as sor´an. A jelen esetben ez azt jelenti, hogy el˝osz¨or az array1 c´ım a´ ltal jel¨olt egy byte-ot teszi a mem´ori´aba, majd k¨ozvetlen¨ul ut´ana m´asik 321 byte-ot helyez el. Ez az elrendez´es a 12.2.a. a´ br´an l´athat´o. Ennek az a k¨ovetkezm´enye, hogy ´ıgy a k´et t¨omb (array1 e´ s array2) tulajdonk´eppen a´ t van lapolva, m´as sz´oval egym´asba e´ rnek. Ebben az esetben nem mindegy, hogy n¨ovekv˝o vagy cs¨okken˝o c´ımek mellett m´asoljuk a´ t az adatokat. A 12.2. a´ bra azt a helyzetet mutatja, amikor a Direction st´atusz bit z´erus e´ s az SI illetve DI regiszterek n¨ovekednek a MOVSB utas´ıt´as ism´etelt v´egrehajt´asa sor´an. Az a´ br´aban a szagggatott vonallal jel¨olt ny´ıl jel¨oli, hogy melyik adat hova lesz a´ tm´asolva. Amint l´athat´o az a´ br´ab´ol, ebben az esetben l´enyeg´eben azt kapjuk, hogy az array1 c´ımen l´ev˝o byte e´ rt´ek´evel fel¨ul´ırjuk az array2 t¨omb minden elem´et. Egy t¨omb adott byte-al val´o fel¨ul´ır´as´ara ugyanakkor jobb a STOS utas´ıt´asa (l´asd 7.6.4. bekezd´es). String m´asol´as nagyobb a´ tlapol´assal Esetleg valakiben felmer¨ulhet, hogy ezek ut´an mi van akkor, ha nem csak egy byte-ot defini´alunk az array1 c´ımen? A helyzet az, hogy a m˝uk¨od´es nem v´altozik, csak most, az array1 c´ımen defini´alt t¨obb e´ rt´ekkel, mint mint´aval ´ırjuk fel¨ul az array2 c´ımen tal´alhat´o t¨omb¨ot. P´eld´aul az al´abbi k´od m˝uk¨od´es´et: cld lea lea mov rep
si, array1 di, array2 cx, 321 movsb
162
(a)
(b)
(c)
(d)
(e)
(f)
12.3. a´ bra: A MOVSB utas´ıt´as m˝uk¨od´ese nagyob a´ tlapol´assal e´ s n¨ovekv˝o c´ımekkel. V´egeredm´enyben ism´etl˝od˝o mint´at kapunk. ... array1: array2:
db ’X’, ’Y’, ’Z’ repb 321
a 12.3. a´ bra mutatja be. Az a´ bra azt mutatja, hogy a programr´eszletben megadott h´arom byte fog ism´etl˝odni az array2 c´ımt˝ol is. Erre m´ar nem lenne k´epes a STOSB utas´ıt´as, csak akkor ha az ism´etl˝od˝o minta byte, word vagy double word m´eret˝u. String m´asol´as a´ tlapol´assal ford´ıtott forr´as e´ s c´el c´ımmel A 12.1.1. bekezd´esben bemutatott m´asol´ast egy kicsit m´ask´eppen is fel´ırhatjuk, vagyis p´eld´aul a forr´as e´ s c´el c´ımet felcser´elhetj¨uk. Nezz¨uk meg mi t¨ort´enik ilyenkor: cld lea lea mov rep ... array1: array2:
si, array2 di, array1 cx, 321 movsb db ’X’ repb 321
Amint a 12.4. a´ br´an is l´athat´o, ebben az esetben az array2 c´ımen tal´alhat´o t¨omb¨ot “eggyel el˝ore m´asoljuk”. Ha csak az array2 t¨omb¨ot tekintj¨uk, akkor ez l´enyeg´eben azt jelenti, hogy a t¨omb els˝o elem´et “t¨or¨olj¨uk”, hiszen a programr´eszlet v´egrehajt´asa ut´an az array2 t¨ombben m´ar nem tal´alhat´o az els˝o elem, illetve az utols´o elem a t¨omb v´eg´en k´etszer szerepel. Ha a legutols´o elemre nincs sz¨uks´eg dupl´an akkor az array2 t¨omb l´enyeg´eben egy elemmel kevesebbet tartalmaz. Ez helyzet l´athat´o a 12.5. a´ br´an.
12.1.2 Stringek o¨ sszehasonl´ıt´asa Az o¨ sszehasonl´ıt´as alapja a CMPS utas´ıt´as melynek m˝uk¨od´es´et a k¨ovetkez˝o pseudo-k´od ´ırja le:
163
(a)
(b)
(c)
(d)
(e)
(f)
12.4. a´ bra: A MOVSB utas´ıt´as m˝uk¨od´ese a´ tlapol´assal e´ s ford´ıtott forr´as e´ s c´el c´ımmel.
(a)
12.5. a´ bra: A t¨omb¨ok a´ llapota a MOVSB utas´ıt´as v´egrehajt´asa ut´ana, amikor a t¨omb¨ok a´ t vannak lapolva e´ s ford´ıtott forr´as e´ s c´el c´ımmel. [ES:DI] ¨ osszehasonl´ ıt´ asa [DS:SI] if(DF == 0) { DI = DI + 1 SI = SI + 1 } else { DI = DI - 1 SI = SI - 1 } Fontos azt tudni, hogy az o¨ sszehasonl´ıt´as az assembly nyelvben u´ gy t¨ort´enik, hogy tulajdonk´eppen a k´et e´ rt´eket kivonjuk egym´asb´ol e´ s az eredm´eny alapj´an a st´atusz biteket be´all´ıtjuk. P´eld´aul ha a k´et e´ rt´ek egyenl˝o, akkor a k¨ul¨onbs´eg¨uk z´erus lesz. Ez´ert van, hogy a z´erus st´atusz bit jelzi az e´ rt´ekek egyenl˝os´eg´et vagy nem egyenl˝os´eg´et. A CMPS utas´ıt´as nagyon j´ol kombin´alhat´o a REPZ, REPE, REPNZ e´ s REPNE prefixekkel. Stringek egyenl˝os´ege A k¨ovetkez˝o programr´eszlet k´et sz¨oveget hasonl´ıt o¨ ssze: string1: db ’abcxef’,0 strlen EQU $ - string1 string2: db ’abcdef’,0 ...
164
mov CX, strlen mov SI,string1 mov DI,string2 cld repe cmpsb Az o¨ sszehasonl´ıt´as addig folytat´odik ameddig a karakterek megegyeznek, illetve a CX regiszter e´ rt´eke nem z´erus. A fenti p´eld´aban a program addig fog futni, am´ıg meg nem tal´alja a string1 sz¨ovegben az x e´ s a string2 sz¨ovegben a d karaktereket, melyek nem egyenl˝oek. Ugyanakkor fontos, hogy amikor az o¨ sszehasonl´ıt´as v´eget e´ r az SI e´ s DI regiszterek az utolj´ara o¨ sszehasonl´ıtott karakterek ut´ani karakterre mutatnak, vagyis az e karakterre. Teh´at ha a sz¨ovegekben az els˝o elt´er˝o karakterre vagyunk kiv´ancsiak, akkor az SI e´ s DI regisztereket cs¨okkenteni kell eggyel.
12.1.3 Keres´es stringek-ben A sz¨ovegben val´o keres´esre a SCAS utas´ıt´as haszn´alhat´o. Az utas´ıt´as pseudo k´odja: asa AL-el ıt´ osszehasonl´ [ES:DI] ¨ if(DF == 0) { DI = DI + 1 } else { DI = DI - 1 } Ez az utas´ıt´as is az ism´etl˝o prefixekkel haszn´alhat´o a legjobban. Egy karakter keres´ese N´ezz¨unk egy egyszer˝u p´eld´at, amikor azt szeretn´enk ellen˝orizni, hogy egy karakter megtal´alhat´o-e a sz¨ovegben e´ s ha igen, akkor a c´ım´ere is kiv´ancsiak vagyunk, teh´at, hogy hol tal´alhat´o a karakter a sz¨ovegben: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
string1: db ’abcxef’,0 strlen EQU $ - string1 ... mov CX, strlen mov DI, string1 mov AL, ’x’ cld repne scasb jnz nincs_meg dec di ... jmp vege nincs_meg: ... vege:
A 8. sorban a keres˝o parancsot addig ism´etelj¨uk, amig az AL regiszter e´ rt´eke nem egyenl˝o az ES:DI regiszterp´ar a´ ltal mutatott e´ rt´ekkel, vagy a CX regiszter e´ rt´eke z´erus nem lesz. A 9. sorban azt ellen˝orizz¨uk, hogy mi´ert e´ rt v´eget a keres´es. Ha a z´erus st´atusz bit e´ rt´eke nulla, akkor nem tal´altuk
165
meg a karaktert ez´ert ugrunk a 9. sorban. Ha val´oban megtal´altuk a karaktert, akkor a z´erus st´atusz bit e´ rt´eke 1 lesz e´ s “´ates¨unk” a 10. sorba. A 10. sorban az´ert cs¨okkentj¨uk a DI regiszter e´ rt´ek´et, hogy a regiszter val´oban arra a karakterre mutasson, amelyiket megtal´altunk. l´enyeg´eben a keres´est meg is ford´ıthatjuk. Ebben az esetben am´ıg a mem´oria e´ rt´ekei megegyeznek (egyenl˝oek) a megadott karakterrel, addig folyamatosan tov´abbl´ep¨unk a mem´ori´aban, m´ıg ha a mem´ori´aban tal´alhat´o e´ rt´ek k¨ul¨onb¨ozik az AL regiszter e´ rt´ek´et˝ol akkor le´all a keres´es. P´eld´aul egy sz¨oveg elej´en ugorjunk a´ t minden SPACE karaktert: 1 string1: db ’ abc’,0 2 strlen EQU $ - string1 3 ... 4 mov CX, strlen 5 mov DI, string1 6 mov AL, ’ ’ 7 cld 8 repe scasb 9 dec di 10 ... A program v´eg´en a DI regiszter az els˝o nem SPACE karakterre fog mutatni. ´Igy a programban a 8. sorban a REPE prefix azt jelenti, hogy ism´etelj¨uk addig a SCASB utas´ıt´ast, am´ıg egyenl˝o az AL regiszterrel.
12.1.4 LODSB e´ s STOSB utas´ıt´asok haszn´alata Els˝ore furcs´anak t˝unhetnek a LODSB e´ s STOSB utas´ıt´asok. F˝oleg az´ert mert nem igaz´an haszn´alhat´ok a REP prefixekkel. (Az´ert nincs e´ rtelme haszn´alni a REP prefixet p´eld´aul a LODSB utas´ıt´assal mivel ez csak azt jelenten´e, hogy n-szer bet¨olt¨unk e´ rt´eket az AL regiszterbe.) Ugyanakkor abban az esetben, ha nem csak a´ t kell m´asolni az adatokat, hanem k¨ozben valamilyen m´odon m´odos´ıtani is kell, akkor a LODSB utas´ıt´assal be tudjuk t¨olteni az adatot, majd a m´odos´ıt´as ut´an a STOSB utas´ıt´assal t´arolni tudjuk. Erre n´ezz¨unk egy p´eld´at, amelyben minden karakter helyett az ut´ana k¨ovetkez˝o karaktert szeretn´enk t´arolni: 1 2 3 4 5 6 7 8 9
cld lea si, forras lea di, cel mov cx, [hossz] ujra: lodsb inc al stosb loop ujra
12.2 String utas´ıt´asok el˝onyei e´ s h´atr´anyai K´et f˝o el˝onye van ezeknek az utas´ıt´asoknak: • Az index regiszterek automatikusan m´odosulnak a Direction st´atusz bit szerint. • K´epesek egyszerre k´et, a mem´ori´aban lev˝o operandussal dolgozni, vagyis p´eld´aul k´epesek mem´ori´ab´ol mem´ori´aba m´asolni. Az utas´ıt´asok nem csak, hogy egyszer˝uek e´ s eleg´ansak, de nagyon hat´ekonyak is. Az utas´ıa´ ts ann´al gyorsabb minn´el nagyobb m´eret˝u adatokat m´asolunk egyszerre, ´ıgy a MOVSB utas´ıt´asn´al “gyorsabb”
166
a MOVSW e´ s enn´el “gyorsabb” a MOVSD utas´ıt´as. ´Igy p´eld´aul ha 4099 byte-ot szeretn´enk a lehet˝o leggyrosabban a´ tm´asolni egyik c´ımr˝ol egy m´asikra, akkor a k¨ovetkez˝o k´odr´eszlet haszn´alhat´o: 1 2 3 4 5 6 7 8
cld lea lea mov rep movsw movsb ...
si, forras di, cel cx, 1024 movsd
; 4096 byte ; 2 byte ; 1 byte
A 4. sorban az´ert adunk meg 1024-et, mivel a MOVSD utas´ıt´asok 4 byte-ot mozgatnak e´ s ´ıgy 1024 × 4 = 4096 byte-ot m´asolunk a´ t, majd a 6. e´ s 7. sorban a marad´ek kett˝o e´ s egy byte-ot mozgatjuk a´ t. Ebben a k´odr´eszletben a sz¨oveg m´erete el˝ore ismert volt, de lehet˝os´eg van hasonl´oan gyors adat m´asol´asra akkor is, ha a sz¨oveg m´eret´et nem ismerj¨uk el˝ore. Erre mutat p´eld´at a k¨ovetkez˝o programr´eszlet: 1 cld 2 lea si, forras 3 lea di, cel 4 mov cx, [meret] 5 shr cx, 2 6 jz kevesebb_mint_4 7 rep movsd 8 kevesebb_mint_4: 9 mov cx, [meret] 10 and cx, 11b 11 jz vege 12 rep movsb 13 vege:
; oszt´ as 4-el
; maszkol´ as, 0-3 lehet
A 4. sorban bet¨oltj¨uk a m´asoland´o adat m´eret´et, amit az 5. sorban elosztunk 4-el. Az´ert 4-el, mert megpr´ob´aljuk a MOVSD utas´ıt´ast haszn´alni e´ s ez az utas´ıt´as 4 byte-ot mozgat egyszerre, ´ıgy a CX regiszterbe a meret negyed´et kell t´arolni. Ugyanakkor a 6. sorban ellen˝orizni kell, hogy a meret negyede az nagyobb-e mint z´erus. Ha kisebb, p´eld´aul csak 3 byte-ot kell a´ tm´asolni, akkor nem szabad haszn´alni a MOVSD utas´ıt´ast e´ s ez´ert a´ tugorjuk azt. Ha nagyobb, akkor 4 byte-onk´ent a´ tm´asoljuk az adatokat. Ekkor m´eg mindig el˝ofordulhat az, hogy amikor a meret e´ rt´ek´et eloszottuk 4-el, akkor volt valamennyi marad´ek. Ezt a marad´ekot az 5. sorban “eldobtuk”, vagyis nem vett¨uk figyelembe. A 4-el val´o oszt´asnak a marad´eka lehet: 0, 1, 2 e´ s 3. Ahhoz, hogy meg´allap´ıtsuk, hogy mennyi a marad´ek a 10. sorban maszkoljuk a meret e´ rt´ek´et u´ gy, hogy a CX e´ rt´eke csal 0, 1, 2 e´ s 3 lehet. Itt is megvizsg´aljuk, hogy volt-e marad´ek. Ha nem volt marad´ek, akkor a 11. sorb´ol a 13. sorba ugrunk. Ha volt marad´ek, akkor a 12. sorban a REP MOVSB utas´ıt´assal m´asoljuk a´ t a byte-okat.
167
12.3 Ellen˝orz˝o k´erd´esek 1. Mik az el˝onyei e´ s h´atr´anyai a fix m´eret˝u sz¨ovegeknek? 2. Mik az el˝onyei e´ s h´atr´anyai a v´altoz´o m´eret˝u sz¨ovegeknek? 3. Hasonl´ıtsa o¨ ssze a k¨ul¨onb¨oz˝o sz¨oveg t´arol´asi m´odokat, amikor lez´ar´o karaktert t´arolunk illetve amikor k¨ozvetlen¨ul t´aroljuk a sz¨oveg hossz´at. 4. Mik az el˝onyei a string kezel˝o utas´ıt´asok haszn´alat´anak? 5. Mi´ert nincs e´ rtelme a REP prefixnek a LODSB utas´ıt´as eset´en? 6. Adjon meg olyan esetet, amikor fontos a Direction st´atusz bit e´ rt´eke! 7. Hasonl´ıtsa o¨ ssze a k¨ovetkez˝o k´et sz¨oveg defin´ıci´ot. Mik az el˝ony¨ok e´ s h´atr´anyok: szoveg: db ’Hello vilag’ hossz: dw $-szoveg illetve szoveg: db ’Hello vilag’ hossz: dw 11
168
13. Fejezet
¨ P´eld´ak fuggv´ enyekre e´ s sz¨oveg kezel´esre 13.1 Sz¨oveg hossz´anak meg´allap´ıt´asa
169
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
org 100h push szoveg call strlen add sp, 2 int 20h szoveg: db ’abcd’,0 strlen: push bp mov bp, sp push cx push di push es les di, [bp+4] mov cx, 0ffffh cld mov al,0 repne scasb jcxz sl_no_string inc di mov ax, di sub ax, [bp+4] clc jmp sl_done sl_no_string: stc sl_done: pop es pop di pop cx pop bp ret
; sz¨ oveg pointer ES:DI-be ; lehets´ eges maxim´ alis hossz ; NULL karakter ; if ECX = 0, not a string ıgy 0-ra mutat uk 1-el, ´ ovelj¨ ; n¨ oveg hossz AX-ben ; sz¨ ; nem volt hiba
; carry 1 => nem sz¨ oveg
13.1. t´abla: Egy sz¨oveg hossz´at meg´allap´ıt´o f¨uggv´eny
170
14. Fejezet
C e´ s assembly programok kapcsolata ¨ 14.1 Fuggv´ eny h´ıv´asi konvenci´ok 14.1.1 16 bites m´od Egy f¨uggv´enynek a param´etereket a vermen kereszt¨ul adjuk a´ t. A legels˝o param´eter ker¨ul a legalacsonyabb mem´oria c´ımre. Ak´ar 8 vagy 16 bite e´ rt´eket akarunk felt¨olteni a veremre minden alkalommal egy 16 bites, word e´ rt´eket kell t´arolni a vermen. Ha 16 bitn´el t¨obb bites e´ rt´eket akarunk t´arolni, akkor is word e´ rt´ekekeket kell felt¨olteni a veremre little-endiam m´odon. Ez azt jelenti, hogy a legkisebb mem´oria c´ımre ker¨ul a legkisebb helyi´ert´ek˝u word. Mindez azt jelenti, hogy minden e´ rt´ek a vermen 2 byte-ra van illesztve (2 byte aligned). A f¨uggv´enyek a visszat´er´esi e´ rt´ek¨ukett regiszteren kereszt¨ul adjuk a´ t. 8 bites eg´esz sz´am eset´en az AL regisztert haszn´aljuk, 16 bites eg´esz sz´am eset´en az AX regisztert haszn´aljuk, 32 bites eg´esz sz´am eset´en a DX:AX regisztereket haszn´aljuk, boolean e´ rt´ek eset´en az AX regisztert haszn´aljuk e´ s val´os sz´am eset´en az ST0 FPU regisztert haszn´aljuk.
14.1.2 32 bites m´od A __cdecl h´ıv´asi konvenci´o az alap eset Linux-on.
Konvenci´o __cdecl __stdcall __fastcall, Microsoft e´ s GNU __fastcall, Borland
Param´eter sorrend a vermen Els˝o param´eter az alacsony c´ımen Els˝o param´eter az alacsony c´ımen Az els˝o k´et param´eter ECX e´ s EDX regiszterekben, a t¨obbi param´eter __stdcall szerint Az els˝o h´arom param´eter EAX, ECX e´ s EDX regiszterekben, a t¨obbi param´eter __stdcall szerint
14.1. t´abla: F¨uggv´eny h´ıv´asi konvenci´ok 32 bites m´odban
171
Param´eter elt´avol´ıt´o a h´ıv´o a f¨uggv´eny a f¨uggv´eny a f¨uggv´eny
172
15. Fejezet
Optimaliz´al´as A fejezetben t´argyalt elj´ar´asok e´ s m´odszerek egy r´esze csak a modern x86-os processzorok eset´en haszn´alhat´o, mivel egy r´esz¨uk m´eg nem is l´etezett az 8086-os processzor idej´eben.
15.1 Optimaliz´al´as sebess´egre Az els˝o e´ s legfontosabb dolog, hogy azonos´ıtsuk azt a k´od r´eszletet, ahol a programunk legt¨obb id˝ot t¨olti.1 Ez az egyik legfontosabb alapelv, mivel a mai programok egy jelent˝os r´esze gyakran sokkal t¨obb id˝ot t¨olt modulok, er˝oforr´asok bet¨olt´es´evel, adatb´azisok el´er´es´evel mint valamilyen sz´am´ıt´assal a programban. ´Igy ha csak a sz´am´ıt´ast optimaliz´aljuk akkor a program a´ ltal felhaszn´alt id˝onek csak az 1%-´at jav´ıtjuk, m´ıg a t¨obbi id˝o v´altozatlan marad. Az assembly k´od haszn´alata egy programban csak akkor hasznos, ha a program CPU intenz´ıv, p´eld´aul: k´ep e´ s hang feldolgoz´as, titkos´ıt´as, rendez´es, adat t¨om¨or´ıt´es e´ s komplik´alt matematikai sz´am´ıt´as. A CPU intenz´ıv programokra a´ ltal´aban az jellemz˝o, hogy van egy olyan ciklus amit a program nagyon sokszor v´egrehajt. Ez a´ ltal´aban az u´ gynevezett legbels˝o ciklus (innermost loop). Ezt a program r´eszletet kell megtal´alni e´ s optimaliz´alni. Ha b´armilyen m´as program r´eszt optimaliz´alunk, akkor tulajdonk´eppen csak az id˝onket pazaroljuk, mivel nem tudunk gyors´ıt´ast el´erni e´ s a programunkat csak a´ tl´athatatlann´a tessz¨uk az optimaliz´al´assal. A m´asik fontos alapelv, hogy e´ rdemes mag´at az optimaliz´aland´o algoritmust tanulm´anyozni, mivel sokszor egy m´asik algoritmus v´alaszt´as´aval m´ar jobb eredm´enyt e´ rhet¨unk el.
¨ v´egrehajt´as 15.1.1 Sorrenden k´ıvuli L´enyeg´eben minden modern x86-os processzor k´epes a sorrenden k´ıv¨uli v´egrehajt´asra (out-of-order execution).
1 “Premature
optimization is the root of the evil”.
173
1 2 3 4 5 6
mov ax, [mem1] imul 6 mov [mem2], ax mov bx, [mem3] add bx, 2 mov [mem4], bx
15.1. t´abla: Sorrenden k´ıv¨uli v´egrehajt´as
15.1.2 Utas´ıt´as bet¨olt´es e´ s dek´odol´as 15.1.3 Utas´ıt´as k´esleltet´es e´ s a´ tbocs´at´asi k´epess´eg ¨ os´egi l´anc megt¨or´ese 15.1.4 Fugg˝ ¨ 15.1.5 Ugr´asok e´ s fuggv´ eny h´ıv´asok Fuggv´ ¨ enyh´ıv´asok eltuntet´ ¨ ese Felt´etel n´elkuli ¨ ugr´asok eltuntet´ ¨ ese
15.2 Optimaliz´al´as m´eretre 15.3 Mem´oria hozz´af´er´es optimaliz´al´asa 15.4 Ciklusok optimaliz´al´asa 15.5 Vector programoz´as 15.6 Probl´em´as utas´ıt´asok
174
16. Fejezet
Optimaliz´alt p´eld´ak 16.1 ASCII t´abla nyomtat´asa r¨ovidebben Ez a program a 9.11. fejezetben bemutatott program r¨ovidebb v´altozata. Ebben a programban k´et dolgot haszn´alunk ki. Az egyik az, hogy a DL regiszter egy 8 bites regiszter e´ s ´ıgy 0 e´ s 255 k¨oz¨otti sz´amokat tud t´arolni, illetve az ASCII karaktereket is 0 e´ s 255 k¨oz¨otti sz´amok reprezent´alnak. ´Igy a regiszter e´ s az ASCII karakterek sz´amai k¨oz¨ott egy az egyes megfeleltet´est tudunk l´etrehozni. Az igazi tr¨ukk a 6. sorban van, itt n¨ovelj¨uk meg mindig a DL regiszter tartalm´at. Igen a´ m de amikor a DL regiszter tartalma 255, majd megn¨ovelj¨uk az e´ rt´ek´et, akkor b´ar 256-ot kellene kapni, de ezt nem k´epes a regiszter t´arolni, ´ıgy “´atfordul”. Ez azt jelenti, hogy a 255 ut´an a 0 k¨ovetkezik. Ez fog t¨ort´enni 6. sorban e´ s az INC utas´ıt´as be is a´ ll´ıtja a ZF st´atusz bitet megfelel˝oen, vagyis nincs sz¨uks´eg CMP utas´ıt´asra, elegend˝o a felt´eteles utas´ıt´ast haszn´alni. Ezeknek a tr¨ukk¨oknek a seg´ıts´eg´evel 15 byte-r´ol 12 byte-ra lehet cs¨okkenteni a leford´ıtott program m´eret´et. 1 2 3 4 5 6 7 8
org 100h MOV DL, 0 MOV AH, 2 ujra: INT 21h INC DL JNZ ujra INT 20h
16.1. t´abla: Az ASCII t´abla kinyomtat´as´ara szolg´al´o optimaliz´alt program
175
176
17. Fejezet
Megjegyz´esek 17.1 Szok´asos hib´ak Az al´abbi lista a leggyakrabban elk¨ovetett hib´akat tartalmazza: • Elfelejtj¨uk a regisztereket elmenteni! Minden m˝uvelet vagy f¨uggv´eny elej´en ments¨uk el a regisztereket, illetve a m˝uvelet vagy f¨uggv´eny v´eg´en a´ ll´ıtsuk helyre a regisztereket. Erre az´ert lehet sz¨uks´eg, mert a regiszter e´ rt´ek´ere k´es˝obb sz¨uks´eg¨unk van, vagy nem szeretn´enk, hogy a m˝uvelet vagy f¨uggv´eny az a´ ltala megv´altoztatott regiszterekkel a v´egrehajt´asban az ut´ana k¨ovetkez˝o m˝uveleteket befoly´aolja. Ne felejts¨uk el, hogy a POP e´ s PUSH utas´ıt´asok sorrendje k¨ul¨onb¨oz˝o kell legyen (l´asd ??. fejezet). • A PUSH vagy POP utas´ıt´asnak nincs megfelel˝o p´arja. Ez l´enyeg´eben azt jelenti, hogy b´armilyen v´egrehajt´asi u´ tvonalon fut le a program a PUSH e´ s POP m˝uveletek sz´am´anak meg kell egyeznie. Vegy¨uk a k¨ovetkez˝o p´eld´at: push bx test cx, cx jz vege ... pop bx vege: ret Ha a program a vege c´ımre ugrik, akkor a pop bx utas´ıt´as nem hajt´odik v´egre. Ez azt jelenti, hogy a ret utas´ıt´as a BX regiszter kor´abbi e´ rt´ek´et fogja levenni a veremr˝ol e´ s ´ıgy rossz c´ımre fog ugrani a program. • Egy speci´alis c´elra foglalt regisztert nem rendelet´esszer˝uen haszn´alunk. P´eld´aul a BP regiszternek speci´alis rendeltet´ese van amikor f¨uggv´enyeket haszn´alunk • Stack-relat´ıv c´ımz´es haszn´alata PUSH m˝uveletek ut´an. A stack-relat´ıv c´ımz´es itt azt jelenti, hogy az SP regisztert haszn´aljuk a c´ımz´esben. P´eld´aul: mov [sp+4], di push ax push bx push bp cmp si, [sp+4]
177
A fenti k´odr´eszletben a programoz´o eredeti c´elja val´osz´ın˝uleg az volt, hogy az SI e´ s DI regisztereket o¨ sszehasonl´ıtsa, de a k´et PUSH utas´ıt´as megv´altoztatja az SP regiszter e´ rt´ek´et. Gyakorl´ask´eppen gondoljuk v´egig, hogy az SI regiszter mivel lesz o¨ sszehasonl´ıtva? A v´alasz l´abjegyzetben tal´alhat´o.1 • Egy v´altoz´o e´ rt´ek´enek e´ s c´ım´enek o¨ sszekever´ese! valtozo: dw 0 ... mov bx, valtozo ; valtozo c´ ıme ker¨ ul BX-be mov ax, [valtozo] ; valtozo ´ ert´ eke ker¨ ul AX-be ´rt´ mov cx, [bx] ; valtozo e eke ker¨ ul CX-be • A f¨uggv´eny h´ıv´asi k¨onvenci´okat nem tartjuk be. Fontos, hogy a programokban a f¨uggv´enyeknek a megfelel˝o sorrendben adjuk a´ t a param´etereket. • Elfelejtj¨uk a RET utas´ıt´ast a f¨uggv´eny v´eg´er˝ol. Ha a RET utas´ıt´ast nem tessz¨uk a f¨uggv´eny v´eg´ere, akkor a program a f¨uggv´eny utols´o utas´ıt´asa ut´ani m˝uvelettel fog folytat´odni an´elk¨ul, hogy visszat´erne a h´ıv´asi ponthoz. • Elfelejtj¨uk ki¨ur´ıteni a Floating-Point Unit verm´et. Miel˝ott az FPU verem b´armelyik “regiszter´ebe” e´ rt´eket ´ırhatn´ank a regisztert t¨or¨olni kell. (L´asd ??. fejezet.) • Az ir´any st´atusz bitet (direction flag) elfelejtj¨uk megfelel˝oen be´all´ıtani. • El˝ojeles e´ s el˝ojel n´ek¨uli eg´esz sz´amok o¨ sszekever´ese a m˝uveletek sor´an. • Rossz indexel´est haszn´alunk egy t¨omb adatszerkezet el´er´ese sor´an. A t¨omb indexet meg kell szorozni a t¨omb egy elem´enek m´eret´evel: tomb: dw 0, 0, 0, 0, 0, 0, 0, 0, 0 ... mov bx, tomb ... mov si, 2 lea di, [bx+si*2] • Egy t¨omb c´ımz´es´en´el a nem megfelel˝o indexet haszn´aljuk. Figyelj¨unk arra, hogy egy n elem˝u t¨ombben az elemek indexe null´at´ol n − 1-ig tart. • A LOOP m˝uveletet u´ gy haszn´aljuk, hogy a CX regiszter e´ rt´eke z´erus. Ne feledj¨uk, hogy a LOOP m˝uvelet el˝osz¨or cs¨okkenti a CX regiszter e´ rt´ek´et e´ s csak ut´ana ellen˝orzi, hogy a regiszter z´erus lett-e. Vegy¨uk p´eld´aul a k¨ovetkez˝o k´odr´ezletet: mov cx, 0 ujra: ... loop ujra Gyakorl´ask´eppen hat´arozzuk meg, hogy a fenti k´odr´eszlet h´anyszor fut le? A v´alasz l´abjegyzetben tal´alhat´o.2
1A 2A
fenti k´odr´eszletben val´oj´aban az SI e´ s az AX regiszterek tartalma lesz o¨ sszehasonl´ıtva. fenti k´odr´eszlet 216 -szor fog lefutni.
178
¨ A. Fuggel´ ek
ASCII t´abl´azat Elvileg 256 ASCII karakter van. Az A.1. t´abl´an l´athat´o ASCII t´abl´azat csak a fontosabb karaktereket tartalmazza e´ s direkt ilyen m´odon van a´ br´azolva. dec ⇓ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
⇒ hex 0 1 2 3 4 5 6 7 8 9 A B C D E F
0 0 NULL
BELL BS HT LF VT FF CR
16 1
32 2 SPC ! ” # $ % & ’ ( ) * + , . /
48 3 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
64 4 @ A B C D E F G H I J K L M N O
80 5 P Q R S T U V W X Y Z [ \ ] ˆ _
A.1. t´abla: Egyszer˝us´ıtett ASCII t´abl´azat A t´abl´azatban szerepl˝o speci´alis szimb´olumok magyar´azata: BELL - Alarm BS - Backspace HT - Horizontal TAB LF - Linefeed VT - Vertical TAB FF - Formfeed CR - Carriage return
179
96 6 ‘ a b c d e f g h i j k l m n o
112 7 p q r s t u v w x y z { | } ˜ DEL
SPC - Space DEL - Delete
180
¨ B. Fuggel´ ek
Felhaszn´alt irodalom 1. Agner Fog: Optimizing subroutines in assembly language An optimization guide for x86 platforms, Copenhagen University College of Engineering, 2009. 2. Sivarama P. Dandamudi: Introduction to Assembly Language Programming, For Pentium and RISC Processors, Springer, 2005.
181
P´elda programok list´aja ¨ karakter beolvas´asa e´ s kinyomtat´asa ford´ıtott Ot sorrendben, 100 ´ ek szerinti param´eter a´ tad´as a vermen kereszt¨ul, Ert´ 136 ASCII t´abla kinyomtat´asa, 111 ASCII t´abla nyomtat´asa r¨ovidebben, 175 C´ım szerinti param´eter a´ tad´as a vermen kereszt¨ul, 136 CAPS LOCK a´ llapot´anak nyomtat´asa, 114 Egy byte bin´aris kinyomtat´asa, 91 Egy byte hexadecim´alis kinyomtat´asa, 95 Egy hexadecim´alis sz´am kinyomtat´asa, 93 Egy karakter beolvas´asa e´ s a k¨ov. kinyomtat´asa (a), 98 Egy karakter beolvas´asa e´ s az ut´ana k¨ov. kinyomtat´asa (b), 98 Egy karakter kinyomtat´asa, 48 Egy karakter n-szeri kinyomtat´asa, 104 Egy sakkt´abla kinyomtat´asa, 108 Egy sakkt´abla kinyomtat´asa XOR-al, 109 Egy sz¨oveg kinyomtat´asa, 49 Egy sz´amjegy beolvas´asa e´ s kinyomtat´asa, 97 Egy t´eglalap kinyomtat´asa, els˝o r´esz, 105 Egy t´eglalap kinyomtat´asa, m´asodik r´esz, 105 Egym´asba a´ gyazott f¨uggv´enyek, 126 Els˝o program, 47 K´et sz´am o¨ sszead´asa, 101 K´et sz´am o¨ sszead´asa ciklussal, 101 M´asodik p´elda a param´eter a´ tad´asra mem´ori´an kereszt¨ul, 128 P´elda a param´eter a´ tad´asra a vermen kereszt¨ul, 132 Param´eter a´ tad´as mem´ori´an kereszt¨ul, 128 Param´eter a´ tad´as regiszteren kereszt¨ul, 128 Sz¨oveg hossz´at meg´allap´ıt´o f¨uggv´eny, 169 Sz¨oveg nyomtat´asa f¨uggv´ennyel, 136 Sz´am ki´ır´asa decim´alis form´aban, 112 Sz´amjegyek nyomtat´asa rekurz´ıv f¨uggv´ennyel, 144 V´altoz´o sz´am´u sz´am o¨ sszead´asa e´ s annyi pont nyomtat´asa, 139
182
T´argymutat´o ASCII, 48 AT&T, 15
rekurz´ıv f¨uggv´eny, 141, 143 rendszer busz, 17 RISC, 11
big-endian, 24 branching, 21
seg kulcssz´o, 39 stack, 121 stack frame, 131
C programoz´asi nyelv, 124, 135, 136 CALL, 130 Carry bit, 92 CISC, 11 COM, 87
times kulcssz´o, 39 TOS, 121 ugr´o utas´ıt´as, 21
data alignment, 25
wrt kulcssz´o, 40
EXE, 88 f¨uggv´eny, 124 frame pointer, 131, 141 g´epi k´od, 12 I/O kontroller, 26 id˝oleges t´arol´as, 123 Intel, 15 LIFO, 121, 134 Little endian, 38, 40 Little-endian, 125 little-endian, 24 lok´alis v´altoz´ok, 141 LSB, 24 maszkol´as, 95 megszak´ıt´as, 27 memory management, 87 modul´aris programoz´as, 124, 144 MSB, 24 nasm, 125 overhead, 144 param´eter a´ tad´as, 126 param´eter a´ tad´as mem´ori´aval, 126, 128 param´eter a´ tad´as regiszterrel, 126, 128 param´eter a´ tad´as veremmel, 126, 130 POP, 121, 123, 124, 130 POPA, 135 Program Segment Prefix, 87 PSP, 87 PUSH, 121, 123, 130 PUSHA, 135
183