Documente Academic
Documente Profesional
Documente Cultură
Acest tutorial are ca scop descrierea cunostintelor teoretice si practice cu privire la programarea in limbaj de
asamblare pentru procesoarele din familia Intel 8086 pe 16 biti. Folosind aceste elemente de baza se poate trece
cu usurinta la o arhitectura superioara, 32 sau 64 de biti.
Inainte de a realiza o aplicatie in limbaj de asamblare, trebuie intelese o serie de elemente de baza cu privire la:
Registre de
Segment
CS
Code Segment
DS
Data Segment
SS
Stack Segment
ES
Extra Segment
IP
Instruction
Pointer
SP
Stack Pointer
BP
Base Pointer
Accumulator
Register
Registre index
Registre de
baza
AX
BX
Base Register
Utilizat ca index
CX
Count Register
DX
Data Register
SI
Source Index
DI
Registre index
Registrele de baza pot fi accesate si din punctul de vedere a primilor 8 biti, respectiv a ultimilor 8 biti.
AX
AH AL
BX
BH BL
CX
CH CL
DX
DH DL
De exemplu, daca registrul AX contine valoarea 1234h atunci AH are valoarea 12h si AL are 34h.
Un registru pe 16 biti numit registru FLAG este utilizat pentru a controla executia instructiunilor. Flag-urile
reprezinta biti ce pot avea valoarea 1 (SET) sau 0 (NOT SET).
Registru de FLAG-uri
Abr.
Nume
Nr. bit
OF
Overflow Flag
11
DF
Direction Flag
10
IF
Interrupt Flag
TF
Trap Flag
SF
Sign Flag
ZF
Zero Flag
AF
Auxiliary Carry
PF
Parity Flag
CF
Carry Flag
CF (Carry Flag, indicator de transport) semnifica un transport sau un mprumut n, respectiv din bitul cel mai
semnificativ al rezultatului.
PF (Parity Flag, indicator de paritate) este pozitionat dupa cum bitii din cel mai putin semnificativ octet al
rezultatului sunt n numar par (pozitionare pe 1) sau impar (pozitionare pe 0).
AF (Adjust Flag, indicator de ajustare) este folosit n aritmetica zecimala si semnifica un transport sau un
mprumut n, respectiv din bitul 4 (cel mai semnificativ bit al jumatatii celei mai putin semnificative) al
rezultatului.
ZF (Zero Flag, indicator de zero) indica daca rezultatul unei operatii a fost sau nu zero.
SF (Sign Flag, indicator de semn) are aceeasi valoare ca bitul cel mai semnificativ al rezultatului (bitul de
semn): 0 pozitiv, 1 negativ.
TF (Trap Flag, indicator de urmarire a executiei) este folosit la depanarea programelor prin executia lor pas
cu pas daca este setat, procesorul forteaza automat o exceptie dupa executia fiecarei instructiuni.
IF (Interrupt Flag, indicator de ntreruperi) precizeaza daca procesorul ia n considerare sau nu ntreruperile
externe.
DF (Direction Flag, indicator de directie) precizeaza sensul (0 crescator sau 1 -descrescator) n care este
modificat contorul de adrese la operatiile cu siruri.
o
o
o
o
o
o
o
o
o
o
Se salveaza fisierul cu numele executa.bat Din linia de comanda se tasteaza executa nume_programsi automat
se urmaresc pasii de realizare a unui program assembler.
Fereastra E
Forma Assembler a unui program .EXE (un singur segment de date, unul de cod si stiva)
Programarea in limbaj de asamblare este dificila deoarece sintaxa utilizata si modul in care este vazuta aplicatia
prin prisma codului sunt foarte apropriate de limbajul masina si de modul in care aplicatia va fi executata de
catre procesor. Compilatorul de Assembler, reprezentat in aceste tutoriale de Turbo Assembler si Turbo Linker
realizeaza operatii destul de simple in comparatie cu compilatorul de C (cl.exe in MS Visual Studio). In cazul unor
exemple simple, de genul celor prezentate in acest tutorial, cele 2 instrumente vor face, in principal, o
translatare a codului din limbaj de asamblare in limbaj masina binar. Din acest motiv, se acorda o atentie
deosebita structurii si a modului in care este scris programul.
Structura standard, chiar daca nu este strict obligatorie, a unui program assembler este
.model
.stack
.data
.code
end
Descriere program:
.model small : Liniile care incep cu .reprezinta instructiuni speciale care indica programului assembler anumite
informatii, descrise de cuvintele cheie ce urmeaza, cu privire la programul de construit. in aceasta
situatie model indica faptul ca urmeaza a se indica modelul de memorie (si cantitatea de memorie) utilizat de
program. Acest program necesita un spatiu redus de memorie, fapt indicat prin small. Un model de memorie
specifica modul in care codul si datele sunt adresate, ori sunt in acelasi segment fizic ori in mai multe segmente.
Cnd toate datele (sau tot codul) se afla in acelasi segment atunci elementele sunt adresate prin adrese near date
de deplasarea lor (offset) fata de adresa de inceput a segmentului. Daca se utilizeaza mai multe segmente atunci
elementele sunt adresate prin adrese far date de adresa segmentului si offset. Tipuri standard de modele sunt:
SMALL, MEDIUM, COMPACT si LARGE.
Model de memorie
Tip adrese
Adrese COD
near
near
far
far
Adrese DATE
near
far
near
far
.stack : Alta linie care descrie programul. Instructiunea indica locul in care incepe segmentul de stiva. Acesta este
utilizat ca zona temporara de stocare a rezultatelor intermediare sau pentru a conserva starea sistemului (descrisa
de valorile din registre) inainte de a efectua operatii care sa altereze datele existente. De asemenea stiva este
utilizata si in transferul parametrilor catre si din proceduri. Indiferent daca este utilizata sau nu este obligatorie
definirea segmentului de stiva deoarece un program .EXE trebuie sa aiba o stiva. Optional se poate defini si
dimensiunea stivei ca numar de octeti. Daca nu se specifica dimensiunea se iau implicit 1024 de bytes.
.data : indica faptul ca incepe segmentul de date. Implicit, reprezinta terminarea segmentului de stiva. In
segmentul de date sunt definite variabilele cu care se lucreaza in program.
mov AX, @data : Instructiunea incarca in registrul AX adresa segmentului de date. Alte simboluri predefinite
@code adresa segmentului de cod.
mov DS,AX : Instructiunea incarca in registrul segment DS adresa segmentului de date din registrul AX. Operatia
este necesara deoarece nu este permisa incarcarea registrului DS cu o valoare constanta (adresa).
int 21h : Apelul intreruperii 21h. In registrul AH se gaseste valoarea 4ch deoarece AX are valoarea 4c00h. Pentru
rutina DOS acest lucru semnifica iesire din program. Valoarea din AL, adica 00h, reprezinta codul de iesire din
program ce indica terminare executie fara eroare.
.end : marcheaza sfrsitul fisierului sursa. ATENTIE: Daca se specifica numele unei etichete definita anterior (de
obicei inainte de prima instructiune) atunci aceasta reprezinta adresa din CS la care porneste executia programului.
De exemplu programul
...
.code
mov AX,@data
mov DS,AX
Start:
mov AL,a
add AL,b
mov e,AL
...
end Start
.code
main
proc
AX,seg mesaj
mov
DS,AX
mov
mov
lea
int
AH,09
DX,mesaj
21h
AX,4c00h
mov
21h
int
main
endp
end main
Descriere program:
main proc : codul poate fi structurat prin intermediul procedurilor. Pentru a face analogie cu programul C care
trebuie sa contina obligatoriu o procedura numita main, se defineste procedura si in programul assembler.
Instructiunea indica inceputul subprogramului numit main. Sfarsitul subprogramului este indicat de
instructiunea end main.
mesaj db
Afisare mesaj !!! : defineste o variabila sir de caractere numita message ce contine textul Afisare mesaj
!!!.
mov AX, seg mesaj : Instructiunea incarca in registrul AX adresa segmentului de date. Reprezinta o alternativa la
instructiunea mov AX, @data pentru ca instructiunea seg intoarce adresa segmentului in care se afla definita
variabila respectiva. Situatia este posibila pentru ca fiecare variabila este identificata printr-o adresa de
forma segment:offset. Fara a incarca registrul DS cu adresa segmentului activ de date nu se incarca corect
adresa variabilei mesaj.
mov AH, 09 : incarca in registrul AH valoarea constanta 09. Este necesar pentru a afisa un mesaj pe ecran
utiliznd intreruperea DOS 21h.
lea DX, message : Instructiunea LEA (Load Efective Address) incarca in registrul DX offset-ul din cadrul
segmentului de date la care se gaseste variabila mesaj . Acest lucru este necesar pentru a afisa mesajul pe ecran
utiliznd intreruperea 21h.
int 21h : Instructiunea genereaza o intrerupere DOS. Procesorul apeleaza rutina indicata de numarul intreruperii,
in acest caz o rutina DOS. Procedura verifica registrul AH pentru a vedea ce trebuie sa faca. In acest caz, valoarea
09 din AH indica faptul ca trebuie sa scrie pe ecran un sir de biti.
permite multiple combinatii de tipuri ale sursei si destinatiei (registru, valoare imediata, locatie de memorie)
insa exclude situatiile:
destinatia nu poate fi segmentul CS; cum segmentul CS contine intotdeauna adresa codului de executat
nu este indicat a se modifica aceasta valoarea in timpul prelucrarii.; singurul mod de a modifica CS este
prin intermediul instructiunilor int, jmp sau call;
destinatia si sursa nu pot fi in acelasi timp operanzi din memorie (variabile definite in segmentul de
date); aceasta restrictie se aplica tuturor instructiunilor procesoarelor 8086 care necesita doi operanzi;
.data
exemplu:
vb1 DW 300
vb2 DW ?
.
mov vb2,vb1
;EROARE
pentru a evita situatia se utilizeaza un registru asemenea unei zone temporare; de exemplu:
.data
vb1 DW 300
vb2 DW ?
.
mov AX, vb1
mov vb2,AX
daca sursa este o valoare imediata (constanta valorica), destinatia nu poate fi unul dintre registrele de
segment (CS, DS, ES, SS); pentru a evita situatia se utilizeaza un registru;
mov 5, AX
;EROARE
Instructiunea XCHG
lds DX,pointer_mesaj
offest-ul
Instructiunea ADD
permite multiple combinatii de tipuri ale sursei si destinatiei (registru, valoare imediata, locatie de
memorie) insa exclude situatiile:
destinatia nu poate fi segmentul CS; cum segmentul CS contine intotdeauna adresa codului de
executat nu este indicat a se modifica aceasta valoarea in timpul prelucrarii.; singurul mod de a
modifica CS este prin intermediul instructiunilor int, jmp sau call;
destinatia si sursa nu pot fi in acelasi timp operanzi din memorie (variabile definite in segmentul de
date); aceasta restrictie se aplica tuturor instructiunilor procesoarelor 8086 care necesita doi
operanzi; exemplu:
.data
vb1 DW 300
vb2 DW ?
.
add vb2,vb1
;EROARE
pentru a evita situatia se utilizeaza un registru asemenea unei zone temporare; de exemplu:
.data
vb1 DW 300
vb2 DW ?
.
mov AX, vb1
add vb2,AX
daca sursa este o valoare imediata (constanta valorica), destinatia nu poate fi unul dintre registrele de
segment (CS, DS, ES, SS); pentru a evita situatia se utilizeaza un registru;
add 5, AX
;EROARE
.data
vb1 DW 300
vb2 DW 50
.
mov
mov
sub
sub
sub
sub
AX, vb1
CX, vb2
vb1, 50
AX, CX
AX, vb1
AX,10
Instructiunea NEG
NEG operand
registru FLAG afectat: OF,SF, ZF, AF, PF, CF;
operandul trebuie sa fie registru sau variabila;
cnd operandul contine valoarea minima posibila aceasta nu este afectata;
Instructiunea MUL (MULtiply)
multiplica o valoare unsigned din AL (cnd operandul este de tip byte) sau din AX (cnd operandul este de
tip word) cu valoarea operandului specificat; rezultatul este returnat in AX cnd operandul este de tip byte
si in DX:AX (cei 2 octeti superiori in DX) cnd acesta este de tip word;
forma analitica:
MUL operand
registru FLAG modificat: OF si CF sunt setati daca partea superioara a rezultatului (DX daca operandul este
de tip word, sau AH este de tip byte) este diferita de 0;alte flag-uri SF, ZF, AF, PF;
vb1 dw 55
vb2 dw 15
cat dw ?
rest dw ?
...
mov AX,vb1
cwd
div vb2
mov cat,AX
mov rest,DX<span style="text-decoration: underline;"><span style="text-decoration: underline;">
</span></span>
utilizata pentru a roti la dreapta bitii destinatiei de attea ori ct este specificat; cum fiecare bit este rotit la
dreapta, cel mai putin semnificativ bit al destinatiei este copiat in locul celui mai semnificativ bit si in CF
(carry flag);
forma analitica:
destinatia poate fi registru sau variabila; contorul poate fi constanta sau registrul CL; exemple:
registru FLAG: OF este setat doar daca contorul are valoarea 1 si bitul cel mai semnificativ al destinatiei este
mov CL, 4
ror AX, CL
ror AX,4
ror vb, CL
ror vb, 4
diferit de bitul vecin; pentru alte valori nu exista regula de modificare a lui OF; se modifica si CF;
Instructiunea ROL (ROtate Left)
utilizata pentru a roti la stnga bitii destinatiei de attea ori ct este specificat; cum fiecare bit este rotit la
stnga, cel mai semnificativ bit al destinatiei este copiat in locul celui mai putin semnificativ bit si in CF
(carry flag);
analogie cu ROR;
se utilizeaza pentru a muta la stnga bitii din destinatie cu attea pozitii cte sunt specificate in contor; cu
fiecare pozitie se adauga la stnga in bitul cel mai putin semnificativ valoarea 0;
forma analitica:
SAL destinatie, contor
registrul FLAG: SF, ZF si PF; cel mai semnificativ bit al destinatiei este mutat in CF; OF este setat daca
contorul are valoarea 1 iar bitul de semn isi pastreaza valoarea;
se utilizeaza pentru a muta la dreapta bitii din destinatie cu attea pozitii cte sunt specificate in contor; cu
fiecare pozitie se adauga la dreapta in vecinul bitului cel mai semnificativ valoarea 0; bitul cel semnificativ
(bitul de semn) isi pastreaza valoarea;
forma analitica:
SAR destinatie, contor
registrul FLAG: SF, ZF si PF; cel mai putin semnificativ bit al destinatiei este mutat in CF; OF este setat daca
contorul are valoarea 1 iar bitul de semn si vecinul sau sunt diferiti;
utilizat pentru a imparti un numar negativ (destinatia) la o putere a lui 2;
destinatia poate fi registru sau variabila; contorul poate fi constanta sau registrul CL;
Instructiunea SHR (Shift Rigth)
se utilizeaza pentru a muta la dreapta bitii din destinatie cu attea pozitii cte sunt specificate in contor; cu
fiecare pozitie se adauga in vecinul bitului cel mai semnificativ valoarea 0;
forma analitica:
SHR destinatie, contor
registrul FLAG: SF, ZF si PF; cel mai putin semnificativ bit al destinatiei este mutat in CF; OF este setat daca
contorul are valoarea 1 iar bitul de semn si vecinul sau sunt diferiti;
utilizat pentru a imparti un numar pozitiv (destinatia) la o putere a lui 2;
destinatia poate fi registru sau variabila; contorul poate fi constanta sau registrul CL;
o
o
o
Adresare indexata
Adresare bazata
Adresare indexata si bazata
Pentru a intelege mai bine conceptele teoretice descrise, in acest tutorial sunt prezentate si exemple care pun in
practica modurile de adresare pentru:
Citirea unui caracter de la tastatura cu ecou intr-un program scris in limbaj de asamblare (assembler)
Afisarea unui caracter pe ecran intr-un program scris in limbaj de asamblare (assembler)
Citirea unui sir de la tastatura intr-un program scris in limbaj de asamblare (assembler)
Afisarea unui sir pe ecran intr-un program scris in limbaj de asamblare (assembler)
Exemplu:
mov AX, 1234h
Exemplu:
vector dw 10 dup(5)
ATENTIE, in exemplul anterior cum elementele vectorului incep de la offset cu valoare multiplu de 2, rezulta ca in
BX se copiaza valoarea 0500h.
Vectorul numit vector se gaseste in segmentul de date memorat astfel:
DS:0000 05 00 05 00 05 00 05 00 05 00
DS:0008 05 00 00 00 00 00 00 00 00 00
iar instructiunea mov BX,vector[3] copiaza in BX 2 octeti (deoarece vector contine elemente de tip word) insa
incepand de la offset-ul 0003 din DS. Deci BX va contine valoarea 0500h.
Valoarea offset-ului este utilizata pentru a citi date direct din segmentul DS.
Exemplu:
vector dw 10 dup(5)
mov
AX, DS:[00h]
mov BX,DS:[08h]
Cand se specifica offset-ul este absolut necesar sa se utilizeze expresia DS:[valoare_offset] pentru ca, daca se
scrie instructiunea:
mov AX,[08h]
se copiaza in AX doar valoarea 8h (Veti primi si un WARNING [Constant] assumed to mean immediate constant.)
registrul SI este utilizat pentru a retine offset-ul elementului pe care dorim sa-l accesam;
vector dw 1234h,1235h,3222h,4343h,5455h
vector db 1,2,3,4,5,6
XOR SI,SI
inc SI
mov AH, vector[SI]
mov CL,vector[SI+1]
mov AL,vector[SI][2]
valoarea 1
in cazul in care vectorul are elemente de tip word parcurgerea acestuia se face marind SI cu valoarea 2 de fiecare
data:
vector dw 1243,2342,3342,44324,53242,63432
XOR SI,SI
inc SI
inc SI
mov AX, vector[SI]
mov CX,vector[SI+2]
mov AX,vector[SI][4]
valoarea 2
vector db 1,2,3,4,5,6
XOR SI,SI
inc SI
add AL, [BX+SI]
add AL, [BX+SI+1]
add AL,[BX][SI][2]
valoarea 1
copiaza in CX, valoarea din stiva aflata la offset-ul dat de BP, adica SS:BP.
Pentru a forta citirea din segmentul DS la offset-ul dat de BP, instructiunea devine
mov CX,DS:[BP]
LOOP nume_eticheta
decrementeaza registrul CX si sare la eticheta nume_eticheta cu conditia ca valoarea din CX sa fie mai mare
decat zero;
;dimensiunea vectorului
;suma elementelor
.code
mov AX,@data
mov DS,AX
xor SI,SI
xor CX,CX
mov CL,n
repeat:
mov AL,vector[SI]
add suma,AL
inc SI
;elementul urmator
loop repeat
mov AX,4c00h
int 21h
end
Instructiunea LEA
.data
vb dw 1234h,1235h
.code
mov SI,offset vb
lea DI,vb
exemplu:
.data
nr db ?
.code
mov ah,01h
int 21h
sub al,30h
mov nr,al
Afisarea unui caracter pe ecran intr-un program scris in limbaj de asamblare (assembler).
exemplu:
.data
nr db 5
caracter db 'g'
.code
mov DL,caracter
mov ah,02h
int 21h
mov DL,nr
mov ah,02h
int 21h
mov DL,nr
add, DL,30h
mov ah,02h
int 21h
Afisarea unei valori numerice mai mari decat 9 pe ecran implica prelucrari prin intermediul carora sa se obtina
codul ASCII al tuturor cifrelor din numar.
Afisarea unui sir pe ecran intr-un program scris in limbaj de asamblare (assembler).
Important: ultimul caracter din sir trebuie sa fie $ (24h); functia afiseaza sirul pana intalneste primul
caracter $
exemplu:
...
.data
mesaj
.code
...
mov
AH,09
lea
DX,mesaj
int
21h
...
Citirea unui sir de la tastatura intr-un program scris in limbaj de asamblare (assembler).
primul octet de la adresa DS:DX trebuie sa contina numarul maxim n de caractere al sirului (rutina permite
citirea de la tastatura doar a n-1 caractere); neinitializarea primului octet cu valoarea n poate conduce la
situatiile: acesta are valoarea 0 si nu se citesc caractere sau acesta are o valoarea reziduala mai mare / mica
decat lungimea maxima dorita;
.data
vb dw 1234h,1234h,1234h
sir db 5
;valoare necesara pentru a indica numarul maxim de caractere de citit
.code
mov AX,@data
mov DS,AX
mov dx,0006h
mov ah,0ah
int 21h
mov AX,4c00h
int 21h
end
Structura alternativa IF
In limbajele de nivel inalt structura de control alternativa este asociata cu expresia IF-THEN-ELSE. Implementarea
structurii alternative presupune:
CMP
CMPSB
CMPSW.
Tip jump
Forma interna
Jump intersegment
5 octeti: 1 pentru codul operatiei (EAh), 2 pentru offset i 2 pentru adresa segment.
Jump intrasegment
Jump-uri scurte
(short jumps)
2 octeti: 1 pentru codul operatiei (EBh), 1 pentru a reprezenta o valoare cu semn aferenta
offset-ului. In acest caz, destinatia trebuie sa fie intre +127 i -128 de octeti fata de
instructiunea de salt.
Instructiunea CMP
Flag-urile (descrise in Partea 1 Elemente de baza) modificate de rezultatul instructiunii CMP sunt:
OF;
SF;
ZF;
AF;
PF;
CF;
Instructiunea CMP compara cei doi operanzi prin intermediul unei scaderi logice. Asta inseamna ca cei doi
operanzi nu sunt modificati, insa bitii de flag sunt setati astfel incat sa indice rezultatul diferentei.
Exemplu de secventa de cod necesara compararii a doua valori intregi in limbaj de asamblare.
CMP DX, BX;
CMP BX, AX
BX AX = -22
NG (negative, SF=1), NC (no carry, CF=0), NV (no
Overflow, OF=0), NZ (not zero, ZF=0)
CMP AX, AX
AX AX = 0
PL (positive, SF=0), NC (no carry, CF=0;), NV (no
Overflow, OF=0), ZR (zero, ZF=1)
Ce putem compara?
Salturi conditionate
Salturile conditionate sunt utilizate pentru a trece la o alta locatie in segmentul de cod in fucntie de valorile
anumitor biti de flag;
Numerele care sunt comparate pot reprezenta atat valori cu semn cat i fara semn. Flag-uri diferite sunt
Operatie
<> or !=
= or ==
JE sau JZ
JE sau JZ
>=
JNB
JNL
>
JNBE sau JA
JNLE or JG
<=
JNA
JNG
<
JNAE sau JB
JNGE sau JL
Exemplu program assembler in care este evidentiata diferenta dintre Valori cu semn vs. Valori fara semn
.data
total dw 0FFFFh
.code
CMP total, 10
JL less10
less10:
;FFFFh = -1, codul va sari la less10 pt. ca 1 < 10.
;sari daca total < 10 (fara semn)
CMP total, 10
JB less10
.
less10:
valoarea
<expresie1>
<expresie 2>
end if
jne fals
< expresie 1>
op1 db 10
op2 db 12
op3 db ?
.code
mov al, op1
;why?
; op1 = op2?
jne eticheta
;expresia 1
mov op3, bl
;expresia 2
eticheta:
add al, op2
jle else
<statement1>
if (temp > max) then <statement2>
max = temp
else
max = max + 1
endif
jmp done
else:
<statement3>
<statement4>
done:
Exemplu aplicatie assembler in care este utilizata structura de control de tip IF-THEN-ELSE
mov ax, temp
mov bx, max
cmp ax, bx
if:
;"if"
jle els
mov max, ax
jmp done
;salt neconditionat
else:
inc bx
mov max, bx
done:
do
{
<statement1>
<statement2>
i=i-1;
} while (i>=0)
repeat:
<statement1>
<statement2>
loop repeat
Exemplu aplicatie assembler pentru determinarea sumei elementelor unui vector, ce implementeaza structura de
control Do-While prin intermediul instructiunii Loop.
.model small
.286
.stack 100h
.data
vector db 1,2,3,4,5,6,7
n db 7
suma db 0
;dimensiunea vectorului
;suma elementelor
.code
mov AX,@data
mov DS,AX
xor SI,SI
xor CX,CX
mov CL,n
repeat:
mov AL,vector[SI]
add suma,AL
inc SI
loop repeat
mov AX,4c00h
int 21h
end
while (i>=0) do
mov cx,n
{
<statement1>
<statement2>
i=i-1;
}
repeat:
cmp op1,op2 ;verificare conditie
jle exit ;conditie iesire
<statement1>
<statement2>
loop repeat
exit:
je case1
cmp value,constant2
je case2
switch (value) {
jmp default
case constant1:
<statement1>
break;
case constant2:
<statement2>
break;
default:
<statements>
case1:
<statement1>
jmp final
case2:
<statement2>
Jmp final
default:
<statements>
final:
near; salveaza pe stiva valoarea pe 16 biti din IP si face salt la prima instructiune din corpul procedurii; are
forma interna pe 3 bytes: 1 byte codul operatiei (E8h), 2 bytes reprezentand distanta ca numar de bytes pana
la codul procedurii;
far; salveaza pe stiva valoarea din CS si apoi din IP; are forma interna pe 5 bytes: 1 byte codul operatiei (9Ah),
2 bytes offset si 2 bytes adresa segemntului.
Tip operand
Descriere
CALL
nume_procedura
CALL eticheta
Procesorul presupune in aceasta situati ca eticheta este locala si atunci face un salt de
tip NEAR. Aceasta trebuie sa fie la o distanta cuprinsa in intervalul [-32768,32676] de
bytes. A se vedea exemplul de mai jos.
Continutul din registru sau variabila este copiat in IP dupa ce acesta a fost salvat pe
stiva. Deci variabilasau registrul respectiv reprezinta de fapt un pointer near (tine doar
offsetul unei proceduri sau etichete)
Continutul variabilei reprezinta un offset si are loc un salt de tip NEAR. De obicei
variabila este reprezentata de o adresare indirecta cu registru index (SI,DI), [SI] sau
registru de baza (BX). [BX] si atunci trebuie specificat cati bytes trebuie cititi (trebuie
indicat procesorului tipul de salt near, se citesc 2 octeti; far se citesc 4 octeti). De
vazut exemplul cu apeluri indirecte de proceduri.
Continutul variabilei reprezinta un segment + offset si are loc un salt de tip FAR. De
obicei variabila este reprezentata de o adresare indirecta cu registru index (SI,DI), [SI]
sau registru de baza (BX). [BX]. De vazut exemplul cu apeluri indirecte de proceduri.
JMP adresa_salt
Imaginea stivei dupa CALL si la pozitionarea pe prima instructiune din corpul procedurii
SP
adresa( IP ) de intors
pentru FAR
PUSH CS
PUSH IP
JMP adresa_salt
Imaginea stivei dupa CALL si la pozitionarea pe prima instructiune din corpul procedurii
SP adresa offset ( IP ) de intors
SP +2 Adresa segment (CS) de intors
daca se da si valoarea numerica optionala are loc curatarea stivei prin modificarea pozitiei curente din stiva
instructiunea stie ce iesire sa faca in functie de modul in care a fost declarata procedura sau mai exact in
functie de tipul apelului FAR sau NEAR; la asamblare fiecare instructiune de tip returneste inlocuita cu RETN
sau RETF (instructiunile pot fi utilizate a se vedea exemplul urmator) care reprezinta forma explicita a
instructiunii de iesire.
;pun rezultatul in s
SP
SP
valoare din AX
SP + 2
valoare din BP
Stiva creste pe directia
BP+2
BP+4
SP + 6
valoare b
BP+6
SP + 8
valoare a
! Adresele scad
int 21h
suma PROC
push BP
mov BP,SP
push AX
mov AX,[BP+6]
add AX,[BP+4]
mov CX,AX
pop AX
mov SP,BP
pop BP
ret
ENDP
end
Variabile SEGMENT
;declar un segment numit Variabile in care declar
;datele
a
1234677
dd
b
3456123
dd
sum
?
dd
Variabile ENDS
;sfarsit segment de date
Stiva SEGMENT
mov AX,4c00h
int 21h
Principal ENDS
;sfarsit segment de cod principal
Procedura SEGMENT
;definesc un alt segment de cod in care scriu
;procedura
ASSUME CS:Procedura
;asociere logica
suma PROC FAR
;definesc procedura
push BP ;salvez BP
mov BP,SP
;initializez BP cu valoarea lui SP
push AX ;salvez AX
mov SI,[BP+10]
;copiez in SI offset a
mov DI,[BP+8]
;copiez in DI offset b
mov AX,[SI]
;copiez in AX cuvant inferior din a
add AX,[DI]
;adun la AX cuvant inferior din b
push SI
;salvez continut SI adica affset a
mov SI,[BP+6]
;copiez in SI offset sum
;a se vedea figura urmatoare ce descrie stiva in acest punct
mov [SI],AX
;copiez in sum suma cuvintelor inferioare
pop SI
;restaurez SI adica offset a
mov AX,[Si+2]
;adun cu carry cuvinte superioare din a si b
adc AX,[DI+2]
mov SI,[BP+6]
mov [SI+2],AX
;copiez in partea superioara a sum rezultatul
pop AX
;restaurez AX
mov SP,BP
pop BP
ret 6
;curat stiva stergand logic cele 3 offset-uri
suma ENDP
Procedura ENDS
end start
Imaginea stivei la momentul copierii in sum a rezultatului adunarii cuvintelor inferioare din a si b
Pozitie in stiva relativa fata de
BP
SP
BP-4
SP
valoare din SI
BP-2
SP + 2
valoare din AX
BP
SP + 4
valoare din BP
BP+2
SP + 6
BP+4
SP + 8
BP+6
SP + 10
offset sum
BP+8
SP + 12
offset b
BP+10
SP + 14
offset a
! Adresele scad
ProcTest PROC
push AX
push BX
push CX
Pop CX
Pop BX
Pop AX
ret
ENDP
dw ?
DD ?
mov AX,@data
mov DS,AX
mov AX, offset suma
mov pointer_functie,AX
NEAR
mov s,CX
; incarc pointerul cu offsetul si adresa segmentului
mov WORD PTR pointer_functie_far,offset diferenta
mov WORD PTR pointer_functie_far+2,seg diferenta
mov AX,a ;trimit parametrii prin registrii
call pointer_functie_far ;apelez procedura
; sau call FAR PTR diferenta
;apel prin nume
mov dif,CX
mov AX, 4c00h
int 21h
suma PROC
add AX,BX
mov CX,AX
ret
ENDP
diferenta PROC FAR
sub AX,BX
mov CX,AX
ret
ENDP
end
FAR
In exemplul anterior procesorul stie ce tip de procedura sa apeleze pentru ca pointerii sunt declarati ca fiind de
tip word, respectiv, double, ceea ce inseamna ca poate sa contina doar offsetul procedurii apelate (in cazul near)
sau adresa completa, segment de cod + offset (pentru far).
In caz ca exista un vector de variabile de tip pointeri la functii, la apelul procedurii trebuie indicat explicit tipul
acesteia prin WORD PTR (pentru NEAR) sau DWORD PTR (pentru FAR).
Daca in exemplul anterior incarc in SI offsetul de inceput al variabilei pointer_functie (simulez utilizarea unui
vector) si atunci apelurile echivalente sunt:
call WORD PTR [SI]
Daca se da apelul call [SI] atunci implicit se considera ca apelul este de tip NEAR si se vor citi 2 octeti de la
adresa [SI] reprezentand offsetul saltului. De aceea este important (mai ales in cazul salturilor de tip FAR) sa se
indice explicit tipul saltului prin WORD sau DWORD.
variabile declarate in memorie in segmentul de date; situatia este echivalenta in limbajele de nivel inalt cu
utilizarea variabilelor declarate global in interiorul subprogramelor; prima varianta a programului
implementeaza modelul small de definire a segmentelor si a tipului de memorie.
.model small
.286
.stack 100h
.data
student struc
;definesc structura de date
nume db 10 dup (?)
varsta db ?
nr_matricol dw ?
ends
dimStudent equ size student
;dimensiune student 13 octeti
s1 student
s2 student
mes_eroare
mes_corect
<'Popescu',22,1234>
<'Ionescu',21,1235>
db 'Depasire limite!','$'
db 'Date corecte!','$'
lim_inf db 14
lim_sup db 89
.code
Validare PROC
;procedura valideaza doar varsta studentului s1
push BP
mov BP,SP
push aX
xor AX,AX
mov AL,lim_inf
mov AH,lim_sup
cmp AL,s1.varsta
ja eroare
cmp AH,s1.varsta
jb eroare
mov
lea
int
jmp
AH,09h
;afisez mesaj date corecte
DX,mes_corect
21h
final
eroare:
mov AH,09h
;afisez mesaj eroare
lea DX,mes_eroare
int 21h
final:
pop AX
mov SP,BP
pop BP
ret
;termin procedura
ENDP
start:
int 21h
end start
Main SEGMENT
;segmentul aferent codului
ASSUME CS:Main,DS:Date,SS:Stiva
;fac asocieri logice
Validare PROC
;procedura valideaza doar varsta studentului s1
push BP
mov BP,SP
push aX
xor AX,AX
mov AL,lim_inf
;copiez in AL valoarea limitei inferioare
mov AH,lim_sup
;copiez in AH valoarea limitei superioare
cmp AL,s1.varsta ;compar varsta cu limita inferioara
ja eroare
;daca varsta e mai mica, afisez mesaj
cmp AH,s1.varsta ;compar varsta cu limita superioara
jb eroare
;daca varsta e mai mare,afisez mesaj
mov
lea
int
jmp
AH,09h
;afisez mesaj date corecte
DX,mes_corect
21h
final
eroare:
mov AH,09h
;afisez mesaj eroare
lea DX,mes_eroare
int 21h
final:
pop AX
mov SP,BP
pop BP
ret
;termin procedura
ENDP
start:
mov
mov
mov
mov
mov
mov
AX,Date
DS,AX
AX,Stiva
SS,AX
AX,varf
SP,AX
call validare
mov AX,4c00h
int 21h
Main ENDS
end start
Marele dezavantaj al acestei metode de transmitere a parametrilor este diminuarea caracterului de generalitate pe
care procedura trebuie sa-l aiba, deoarece este conditionata de existenta variabilelor (in cazul anterior lim_inf,
lim_sup si s1) definite in segmentul de date.
registrele pentru a transmite parametrii de intrare; consider mesajele de avertizare ca fiind declarate global
si atunci trebuie doar sa trimit in procedura limitele intervalului si valoarea de verificat; pentru a realiza acest
lucru folosesc AX pentru limitele intervalului (lim_inf in AL si lim_sup in AH) si CL pentru valoarea de verificat;
se observa ca din toate datele studentului intereseaza doar varsta si atunci trimit doar aceasta data.
.model small
.286
.stack 100h
.data
student struc
nume db 10 dup (?)
varsta db ?
nr_matricol dw ?
ends
dimStudent equ size student
;dimensiune student 13 octeti
s1 student <'Popescu',22,1234>
mes_eroare db 'Depasire limite!','$'
mes_corect db 'Date corecte!','$'
lim_inf db 14
lim_sup db 89
.code
Validare PROC
;procedura valideaza varsta oricarui student, aceasta ;fiind trimisa prin CL
push BP
mov BP,SP
push AX ;salvez valoarea din AX, poate mai trebuie
push CX;
cmp AL,CL
ja eroare
cmp AH,CL
jb eroare
mov
lea
int
jmp
;compar varsta
;daca varsta e
;compar varsta
;daca varsta e
cu limita inferioara
mai mica, afisez mesaj
cu limita superioara
mai mare,afisez mesaj
AH,09h
;afisez mesaj date corecte
DX,mes_corect
21h
final
eroare:
mov AH,09h
;afisez mesaj eroare
lea DX,mes_eroare
int 21h
final:
pop CX
pop AX
mov SP,BP
pop BP
ret
;termin procedura
ENDP
start:
AL,lim_inf
AH,lim_sup
CX,CX
CL,s1.varsta
call validare
mov AX,4c00h
int 21h
end start
Dezavantajul metodei deriva din numarul limitat de registre si din faptul ca instructiunile salvare/restaurare a
valorilor registrelor pe/de pe stiva consuma resurse (de exemplu daca valoarea parametrului de intrare ce a fost
trimisa prin intermediul registrului AX este necesara in procedura dupa efectuarea altor prelucrari trebuie sa ne
asiguram ca nu o pierdem salvand-o pe stiva).
stiva pe post de zona de transfer a datelor catre proceduri; utilizarea stivei in acest sens se face in doua
moduri in functie de semnificatia valorilor de pe stiva: adresa variabilei (referinta) sau valoarea ei; indiferent
de modul ales, secventa se rezuma la a salva valorile respective pe stiva (prin instructiunea PUSH) inainte de
a apela procedura si la a le accesa in procedura prin intermediul registrului BP; primul program exemplifica
transmiterea parametrilor pe stiva prin valoare, iar al doilea transmite referinta variabilelor de intrare.
.model small
.286
.stack 100h
.data
student struc
nume db 10 dup (?)
varsta db ?
nr_matricol dw ?
ends
dimStudent equ size student
;dimensiune student 13 octeti
s1 student <'Popescu',22,1234>
mes_eroare db 'Depasire limite!','$'
mes_corect db 'Date corecte!','$'
lim_inf db 14
lim_sup db 89
.code
Validare PROC
;procedura valideaza varsta oricarui student, aceasta ;fiind trimisa prin stiva
push BP
mov BP,SP
push AX
push CX
;* a se vedea figura stivei de mai jos
mov AL,[BP+6]
mov AH,[BP+7]
mov CL,[BP+4]
cmp AL,CL
ja eroare
cmp AH,CL
jb eroare
mov
lea
int
jmp
;compar varsta
;daca varsta e
;compar varsta
;daca varsta e
cu limita inferioara
mai mica, afisez mesaj
cu limita superioara
mai mare,afisez mesaj
AH,09h
;afisez mesaj date corecte
DX,mes_corect
21h
final
eroare:
mov AH,09h
;afisez mesaj eroare
lea DX,mes_eroare
int 21h
final:
pop
pop
mov
pop
ret
CX
AX
SP,BP
BP
4
;termin procedura si golesc stiva
ENDP
start:
;apelez procedura
mov AX,4c00h
int 21h
end start
SP
BP-4
SP
valoare din CX
BP-2
SP + 2
valoare din AX
BP
SP + 4
valoare din BP
SP + 6
BP+2
Stiva creste
directia
pe
! Adresele scad
BP+4
SP + 8
BP+6
SP + 10
Atentie ! In cazul trimiterii parametrilor de tip sir de caractere este indicat sa se utilizeze metoda prin referinta
deoarece punerea unui sir pe stiva este o operatie ineficienta ce consuma spatiu si cicluri masina. Din acest motiv,
s-a trimis doar valoarea varstei studentului pe stiva si nu intreaga structura.
Al doilea exemplu de program assembler descrie trimiterea referintelor pe stiva.
.model small
.286
.stack 100h
.data
student struc
nume db 10 dup (?)
varsta db ?
nr_matricol dw ?
ends
dimStudent equ size student
;dimensiune student 13 octeti
s1 student <'Popescu',22,1234>
mes_eroare db 'Depasire limite!','$'
mes_corect db 'Date corecte!','$'
lim_inf db 14
lim_sup db 89
.code
Validare PROC
;procedura valideaza varsta oricarui student, acesta
;este trimis prin stiva utilizand referinta sa
push BP
mov BP,SP
push AX
push CX
push SI
push DI
;* a se vedea figura stivei de mai jos
mov
mov
mov
mov
mov
cmp
SI,[BP+8]
AL,[SI]
SI,[BP+6]
AH,[SI]
SI,[BP+4]
AL,[SI].varsta
ja eroare
cmp AH,[SI].varsta
jb eroare
mov
lea
int
jmp
AH,09h
;afisez mesaj date corecte
DX,mes_corect
21h
final
eroare:
mov AH,09h
;afisez mesaj eroare
lea DX,mes_eroare
int 21h
final:
pop DI
pop SI
pop CX
pop
mov
pop
ret
AX
SP,BP
BP
6
ENDP
start:
mov AX,@data
mov DS,AX
mov AX,offset lim_inf
push AX
mov AX,offset lim_sup
push AX
mov AX, offset s1
push AX
call validare
mov AX,4c00h
int 21h
end start
SP
BP-8
SP
valoarea din DI
BP-6
SP + 2
valoarea din SI
BP-4
SP + 4
valoare din CX
BP-2
SP + 6
valoare din AX
BP
SP + 8
valoare din BP
BP+2
SP + 10
BP+4
SP + 12
BP+6
SP + 14
BP+8
SP + 16
Atentie ! In cazul trimiterii parametrilor prin referinta pe stiva orice modificare a valorii lor utilizand o adresare
indirecta (bazata sau indexata) are loc in segmentul de date si valoarea se pastreaza si dupa iesirea din procedura.
Intoarcerea rezultatelor din proceduri se realizeaza prin intermediul registrelor AX, BX, CX, DX. De exemplu,
programul care aduna doua numere de tip double trimise prin valoare returneaza suma in registrele CX (cuvantul
inferior) si DX (cuvantul superior).
Creare fisier
Inchidere fisier
Deschidere fisier
Scriere in fisier
Citire din fisier
Pozitionare in fisier
Extindere jump-uri de tip short
Valoare Denumire
Descriere
stdin
Intrare standard
stdout
Iesire standard
stderr
stdaux
Dispozitiv auxiliar
stdprn
Imprimanta standard
Operatie
3Ch
Creare fisier
3Dh
Deschidere fisier
3Eh
Inchidere fisier
3Fh
40h
Scriere in fisier
41h
Stergere in fisier
42h
Pozitionare in fisier
56h
Redenumire fisier
Considerand urmatoarele variabile definite in segmentul de date al unui program ce foloseste fisiere:
handler
dw
atribut
;handler la fisier
?
dw
tipDeschid
dw
;modul de deschidere a
rez
db
numeFis
db
'fisier.dat',0
fisierului
NrOctetideScris
dw
NrOctetiScrisi
dw
;nume fisier
CREARE FISIER
Parametrii intrare:
Registru corespondent
- cod functie
3Ch AH
- nume fisier
DX
- atribut fisier
CX
Parametrii returnati:
- handler
- rezultat operatie
La momentul crearii, tipul fisierul poate fi:
read-only (1)
hidden (2)
system (4)
normal (0)
AX
in functie de carry flag
mov CX,atribut
lea DX,numeFis
INT 21h
jc eroare
mov rez,0
jmp final
eroare:
mov handler,-1
mov rez,AX
final:
pop DX
pop CX
pop AX
ENDM
INCHIDERE FISIER
Parametrii intrare: Registru corespondent
- cod functie
- handler
3Eh AH
BX
Parametrii returnati:
- rezultat operatie
mov BX,handler
INT 21h
jc eroare
pop BX
pop AX
ENDM
DECHIDERE FISIER
Parametrii intrare: Registru corespondent
- cod functie
3Dh AH
- nume fisier
DX
- tip acces
AL
Parametrii returnati:
- handler
- rezultat operatie
AX
in functie de carry flag
citire (0)
scriere (1)
citire/scriere (2)
mov rez,0
jmp final
eroare:
mov handler,-1
mov rez,AX
final:
pop DX
pop AX
ENDM
SCRIERE in FISIER
Parametrii intrare:
Registru corespondent
- cod functie
40h AH
- handler fisier
BX
DX
CX
Parametrii returnati:
- numar octeti scrisi efectiv in fisier
- rezultat operatie
AX
in functie de carry flag
mov BX,handler
mov rez,0
jmp final
eroare:
mov rez,AX
final:
pop DX
pop CX
pop BX
pop AX
ENDM
Atentie Buffer-ul poate fi un element de tip articol, masiv sau variabila. De exemplu, pentru a scrie intr-un fisier
primele 3 elemente ale unui vector vector db 1,2,3,4,5b se scrie instructiunea:
Scrie handler,vector,3,NrOctetiScrisi,rez
Registru corespondent
3Fh AH
- handler fisier
BX
DX
CX
Parametrii returnati:
- numar octeti cititi efectiv din fisier
- rezultat operatie
AX
in functie de carry flag
mov BX,handler
mov rez,0
jmp final
eroare:
mov rez,AX
final:
pop DX
pop CX
pop BX
pop AX
ENDM
Pozitionare in fisier
Parametrii intrare:
Registru corespondent
- cod functie
42h AH
- handler fisier
BX
- punct de referinta
AL
cuv. inferior DX
cuv. superior CX
Parametrii returnati:
- noua pozitie in fisier (un double)
- rezultat operatie
cuv. inferior AX
cuv. superior DX
in functie de carry flag
0, inceputul fisierului;
1, pozitia curenta in fisier;
2, sfarsitul fisierului.
;noua pozitie
pop DX
pop CX
pop BX
pop AX
ENDM
Presupunand ca toate aceste macrodefinitii sunt definite in fisierul MacroFis.inc se scrie programul care
construieste un fisier si il foloseste pentru a memora elementele unui vector de elemente si de structuri. Ulterior,
se construiesc alti doi vectori in care se pun elementele aflate in fisier.
Atentie Fisierul MacroFis.inc contine doar codul fiecarei macrodefinitii in parte fara nici o alta declaratie in plus.
Acest
fisier
nu
necesita
asamblare
sau
link-editare.
Instructiunea include
MacroFis.inc din programul principal (dat mai jos) copiaza codul din fisierul indicat si il insereaza pe pozitia
instructiunii.
Atentie Pentru a determina dimensiunea unui vector se va utiliza simbolul $ asociat offset-ului curent in
segmentul de date.
Pentru un masiv de tip tip_vect (orice tip de baza sau structura) pentru lungime ca numar de elemente se
utilizeaza expresia:
vector tip_vector elem1, elem2, elem3, .., elemn
tip equ TYPE vector
nrElem equ ($ vector)/tip
In cazul masivelor definite cu dup se poate utiliza LENGTH pentru a obtine numarul de elemente.
.model small
.286
.stack 100h
.data
student STRUC
;articol de tip student
nume db 15 dup (?)
varsta db ?
nrMatricol dw ?
ENDS
dimStudent equ SIZE student
;articol de tip student
vector db 1,2,3,4,5
;vector de elemente
lvector equ $-vector
;lungime vector ca numar de octeti
;cum elementele vectorului sunt de tip octet atunci lvector
;da si numarul de elemente
vector2 db 5 dup(?)
;al doilea vactor
vectorStudenti
student <'Popescu',23,1234>,<'Ionescu',22,1235>,<'Gheorghe',22,1236>
;vector de articole
dimVectStud equ $-vectorStudenti ;dimensiune in octeti
nrStudenti equ dimVectStud/dimStudent
;numar elemente
vectorStudenti2 student nrStudenti dup(?) ;al doilea vector
handler
atribut
tipDeschid
rez
NrOctetideScris
NrOctetiScrisi
NrOctetiCititi
dw
dw
dw
dw
dw
dw
dw
?
?
?
?
?
?
?
;handler la fisier
;atribut creare fisier
;modul de deschidere a fisierului
;variabila verificare reusita operatie
;numar de octeti de scris in fisier
;numar de octeti scrisi in fisier
;numar de octeti de cititi din
dd
;dimensiunea saltului la
dd
;fisier
Pozitie
;pozitionare
PozitieNoua
numeFis db
mesajEroare db
'fisier.dat',0
;nume fisier
'Eroare executie functie!','$';mesaj eroare
.code
include MacroF.inc ;includ fisierul ce contine macrodefinitiile
start:
mov AX,@data
mov DS,AX
Creare numeFis,0,handler,rez
;creez fisierul
cmp rez,0
;verific executia operatiei
je continuare1
AfiseazaMesaj mesajEroare ;afisez mesaj eroare
continuare1:
Inchidere handler,rez
;inchid fisierul
cmp rez,0
;verific executia operatiei
je continuare2
AfiseazaMesaj mesajEroare ;afisez mesaj eroare
continuare2:
Deschidere numeFis,2,handler,rez ;deschid fisierul
cmp rez,0
;verific executia operatiei
je continuare3
AfiseazaMesaj mesajEroare ;afisez mesaj eroare
continuare3:
Scrie handler,vector,lvector,NrOctetiScrisi,rez
;scriu in fisier primul vector
Scrie handler,vectorStudenti,dimvectstud,NrOctetiScrisi,rez
;scriu in fisier primul vector de articole
mov word ptr pozitie,0
;indic pozitia saltului
mov word ptr pozitie[2],0 ;pun zero pt. a ma pozitiona la 0
;octeti fata de inceputul fisierului
POzitionare handler,pozitie,0,PozitieNoua,rez
;ma pozitionez pe inceputul fisierului
Citeste handler,vector2,lvector,NrOctetiCititi,rez
;citesc in al doilea vector elementele din
;fisier: 1,2,3,4,5
Citeste handler,vectorStudenti2,dimVectStud,NrOctetiCititi,rez
;citesc in al doilea vector de articole
;elementele din fisier
Inchidere handler,rez
;inchid fisierul
mov AX,4c00h
int 21h
end start
Codul macrodefinitiei AfiseazaMesaj este (este inclus tot in MacroF.inc) :
AfiseazaMesaj MACRO mesaj
push AX
push DX
mov Ah,09h
lea DX,mesaj
int 21h
pop DX
pop AX
ENDM
Atentie Salturile conditionate nu pot referi etichete aflate la mai mult de 128 octeti. Solutia consta in evitarea
acestor situatii prin rescrierea codului si a conditiei de verificat astfel incat sa avem salturi mai mici. In exemplul
anterior, verificarea realizarii corecte a unei macrodefinitii se realiza prin:
apel de macrodefinitie
cmp rez,0
jne afiseaza_eroare
apel macrodefinitie urmatoare
jmp exit
afiseaza_eroare:
AfiseazaMesaj mesajEroare
exit:
mov AX,4c00h
int 21h
insa eticheta afiseaza_eroare se afla la o distanta mai mare de 128 de octeti. Din acest motiv s-au folosit
etichetele continuarei cu i = 1,2.. iar verificarea a devenit:
apel de macrodefinitie
cmp rez,0
je continuarei
AfiseazaMesaj mesajEroare
continuarei
apel macrodefinitie urmatoare
care este corecta in cazul in care eticheta salt se gaseste la mai putin de 128 de octeti. In caz contrar saltul,
extinderea salturilor conditionate se realizeaza prin abordarea secventei de cod astfel:
utilizarea unui salt neconditionat (acesta poate face salturi mai mari de 128 de octeti):
efectuare comparatie
jne continuare
jmp salt
continuare:
...
salt:
salt:
salt:
...
continuare:
...
salt:
Instructiunea jne $+2+ dimensiune in octeti a instructiunii urmatoare adauga la offset-ul curent din segmentul
de cod (retinut in IP si indicat cu $) 2 octeti reprezentand dimensiunea acestei instructiunii si dimensiunea in octeti
a instructiunii urmatoare. Cum in aceasta abordare instructiunea urmatoare este jmp salt trebuie indicata
dimensiunea ei (vezi documentatie Structuri de control 3 octeti pentru jump near si 5 octeti pentru jump far).
Deci, in acest caz instructiunea se mai poate scrie jne $ + 5. Pentru a afla dimensiunea altor instructiuni se
utilizeaza TurboDebugger-ul si se fac diferente de offset-uri ale instructiunilor respective. Pentru a fi sigur de
tipul jump-ului se indica tipul acestuia explicit cu jmp NEAR PTR salt aceasta instructiune avand 3 octeti.
Arhitectura de segmente
Familia de procesoare 8086 implementeaza o arhitectura de segmente prin faptul ca fiecare adresa fizica este
reprezentata prin perechea adresa segment:offset.
Generatia de procesoare 8086/286 pe 16 biti permit lucru cu segmente mai mici de 64K (cea mai mare adresa
posibila din cadrul unui segment offset este 216).
Procesoarele 90386/486 utilizeaza arhitectura pe 16 biti (segmente de maxim 64K) cand prelucreaza date in
mod real, insa in mod protejat utilizeaza registre pe 32 de biti ce pot retine adrese de pana la 4 Gbytes.
Un segment fizic poate incepe numai de la o adresa divizibila cu 16, aceste locatii fiind numite (Intel) paragrafe.
Modul in care sunt definite datele si codul nu are importanta la programele mici pentru ca acestea ocupa mai putin
de 64Kbytes fiind grupate in segmente individuale si sunt accesate prin intermediul offset-ului relativ la adresa
de inceput a segmentului respectiv. Problema se complica in cazul programelor mari in care codul sau datele ocupa
mai mult de 64K si atunci sunt segmentate. In aceasta situatie, programatorul trebuie sa se asigure ca fiecare data
sau secventa de cod referita poate fi accesata prin segment:adresa.
Problema segmentarii datelor sau codului este mai putin acuta in cazul procesoarelor pe 32 de biti pentru ca
segmentele sunt destul de mari (4 Gbytes) astfel incat si cele mai complexe aplicatii sa se comporte asemenea
programelor mici, compacte.
Segmentele logice
Segmentele reprezinta seturi de date sau instructiuni ce sunt disponibile prin intermediul offset-ului relativ de
adresa de inceput a segmentului.
Adresele fizice ale segmentelor sunt cunoscute prin intermediul registrelor de segment:
Registru
Descriere
DS
- segmentul de date
CS
- segmentul de cod
SS
- segmentul de stiva
ES
- segmentul extins
, insa trebuie avut in vedere faptul ca, in cazul in care exista mai multe segmente definite de programator, numai
unul dintre ele, la un moment dat, poate fi asociat cu segmentele logice de date, de cod, de stiva sau extins.
La incarcarea in memorie a programului, sistemul initializeaza registrul de segment CS cu prima adresa se segment
disponibila instructiune, iar registrul IP cu adresa relativa din cadrul segmentului, a primei instructiuni ce trebuie
executata. Segmentele logice se incarca in memorie in ordinea cod, date, stiva.
Definirea segmentelor
Segmentele logice contin cele tei componente ale unui program: cod, date si stiva. Modul in care pot fi
specificate segmentele sunt:
definire simplificata;
definire completa a segmentelor.
Definirea simplificata ascunde multe detalii ale definirii segmentelor si utilizeaza aceleasi conventii implementate
de Microsoft in limbajele de nivel inalt.
Structura unui program ale carui segmente sunt descrise utilizand definirea simplificata este: (descrisa si in prima
parte a tutorialului)
END start
in care:
Optiune
Descriere
Valori posibile
tip_model
tip_stiva
tip_procesor
expresie
Simbol
Descriere
@Model
@Data
- segmentul de date
@DataSize
@CurSeg
- segmentul curent
Element
Descriere
nume_segment
tip_aliniere
READONLY
tip_combinare
- indica modul in care sunt combinate segmentele cu acelasi nume dar din module
separate la crearea executabilului;
tip_adresare
- descrie modul de lucru al procesoarelor (de la 386 in sus), fie pe 16 biti, fie pe 32
de biti;
clasa_segmente
- nume dat intre ce indica o clasa de segmente; segmentele din aceeasi clasa sunt
aranjate secvential; utilizat pentru a indica ordinea de aranjare a segmentelor.
[tip_aliniere]
element optional;
defineste multimea din care sa fie selectata adresa de la care este alocat segmentul;
descrie faptul ca adresa fizica de inceput a segmentului este divizibila cu 1,2,4,16 sau 265;
link-erul utilizeaza aceasta informatie pentru a determina adresa relativa de start a fiecarui segment; sistemul
determina adresa de start actuala cand programul este incarcat;
Tip aliniere
Adresa de start
BYTE
WORD
DWORD
PARA
PAGE
[tip_combinare]
element optional;
indica modul in care sunt combinate segmente cu acelasi nume, dar care apar in module diferite; informatie
utilizata de link-er, nu de asamblor, pentru ca este necesara la crearea executabilului si nu la asamblarea
fiecarui modul in parte;
Tip
combinare
Descriere
PRIVATE
PUBLIC
- combina segmentele cu acelasi nume din module separate intr-o zona de memorie
continua;
COMMON
- segmentul curent este asezat in memorie in spatiul ramas disponibil dupa alocarea
celorlalte segmente (catre sfarsitul memoriei); utilizat si ca sinonim pentru PUBLIC;
STACK
[tip_adresare]
element optional;
reprezinta atributul modului de utilizare pentru procesoare, incepand de la .386;
valorile pe care le poate lua:
Tip
adresare
Descriere
USE16
- indica faptul ca elementele din segment sunt adresate utilizand un offset pe 16 de biti;
daca se specifica .386 sau .486 dupa de directiva .MODEL atunci default este modul
USE16;
USE32
- indica faptul ca elementele din segment sunt adresate utilizand un offset pe 32 de biti;
daca se specifica .386 sau .486 inainte de directiva .MODEL atunci default este modul
USE32;
[clasa_segmente]
element optional;
indica modul de aranjare in memorie a segmentelor din aceeasi clasa;
doua segmente cu acelasi nume, dar cu clase diferite nu sunt combinate;
segmentele din aceeasi clasa sunt aranjate secvential in memorie in ordinea in care sunt intalnite.
In mod normal, asamblorul aranjeaza segmentele in fisierul .obj in ordinea in care apar in codul sursa. In schimb,
link-editorul proceseaza fisierele .obj in ordinea din linia de comanda. In cadrul fiecarui modul, acesta aloca
memorie pentru segmente in ordinea aparitiei, apartenentei la un grup, clasa si cerinte date de modul de aranjare
.DOSSEG (conventia de ordonare a segmentelor MS-DOS).
Modul de aranjare a segmentelor este important atunci cand e doreste ca anumite segmente sa apara la inceputul
sau sfarsitul unui program sau cand se fac presupuneri in legatura cu ce segmente se gasesc langa altele.
Pentru a controla ordinea in care segmentele apar in memorie se utilizeaza directivele:
.SEQ
.ALPHA
Atentie
Asocierea logica dintre registrul de segment si segmentul declarat se face prin intermediul directivei ASSUME.
Aceasta informatie este necesara asamblorului si link-editorului la transformarea programului in cod masina.
Multe dintre instructiunile assembler presupun existenta unui segment implicit. Accesul la o zona de memorie din
segmentul de date fie prin nume variabila, [registru index] sau [registru de baza][registru index] (toate reprezinta
adrese offset) se realizeaza fata de adresa fizica continuta de registrul DS. Fiecare instructiune de citire/scriere cu
stiva (POP/PUSH) se realizeaza implicit fata de SS. Instructiunile de salt conditionat/neconditionat reprezinta salturi
la adrese offset in cadrul segmentului de cod, a carui adresa se gaseste in CS.
De aceea in cazul programelor cu mai multe segmente este necesar sa se indice asocierea logica dintre segment
si registru de segment pentru ca programul (mai precis asamblorul si link-editorul care transforma codul in cod
masina) sa stie unde (in ce segmente) se gasesc adresele respective (date sau instructiuni).
Asocierea se realizeaza cu instructiunea
ASSUME registru_segment:nume_segment[,registru_segment:nume_segment]
ASSUME [registru_segment:] NOTHING [,registru_segment:NOTHING]
Un registru_segment reprezinta unul dintre registrele de segment: CS, DS, ES sau SS; nume_segmentreprezinta
numele unui segment sau grup de segmente.
Atentie
Odata ce s-a modificat unul dintre registrele DS, ES sau SS trebuie precizat acest lucru procesorului prin incarcarea
registrului de segment utilizat implicit cu adresa noului segment.Daca segmentul utilizat reprezinta o zona de
date initializarea registrului DS se face prin secventa:
mov AX, nume_segment
mov DS, AX
Daca segmentul utilizat reprezinta o zona de date extinsa initializarea registrului ES se face prin secventa:
mov AX, nume_segment
mov ES, AX
Se observa ca registrul CS nu trebuie incarcat. Acest lucru este realizat implicit (daca nu s-ar fi realizat acest lucru
nu se putea executa nici o instructiune din program ,iar initializarile reprezinta de fapt secvente de instructiuni)
prin indicarea punctului de start al programului (NU UITA de eticheta start: si de instructiunea de final end start)
si prin asocierea logica ASSUME CS:nume_segment.
Instructiunea ASSUME registru_segment:NOTHING sterge asocierea logica anterioara. Instructiunea ASSUME
NOTHING sterge asocierile logice pentru toate registrele de segment.
utilizate. De exemplu programul contine mai multe segmente de date iar accesul la ele implica schimbarea adresei
din registrul DS. Gruparea acestor segmente intr-un grup implica realizarea unui singur segment obtinut prin
concatenarea segmentelor din grup si incarcarea o singura data a registrului DS cu adresa grupului. Toate
datele/codul este astfel accesibil relativ la adresa de inceput a grupului. Sintaxa de definire a grupului este:
nume_grup GROUP nume_segment [, nume_segment]
AX,Stiva
;incarc in SS adresa segmentului de stiva
SS,AX
AX, offset varf
;incarc SP
SP,AX
mov
mov
mov
mov
AX,
AX,
AX,
AX,
b
vector
c
d
;se observa ca datele sunt accesibile fara a incarca de fiecare data DS cu adresa
;segmentului parinte
mov AX,4c00h
int 21h
Principal ENDS
end start
1
2
3
4
5
6
7
DS:0000
DS:0008
DS:0010
DS:0018
DS:0020
DS:0028
DS:0030
34
00
09
09
03
03
11
12
00
00
00
00
00
11
78
00
09
00
03
00
22
56
00
00
00
00
00
22
00
00
09
00
03
00
00
00
00
00
00
00
00
00
00
00
09
00
03
00
00
00
00
00
00
00
00
00
;date
;zona
;date
;date
;date
;date
;date
segment
de date
segment
segment
segment
segment
segment
Date1
Date2
Date2
Temporare
Temporare
Date3
Atentie !De ce fiecare segment pare ca ocupa 16 octeti (fiecare segment ocupa atata spatiu cate date sunt definite
in el, iar restul de octeti sunt nerezervati) ? Pentru ca implicit la definire tipul alinierii este PARA segmentele sunt
alocate in memorie numai de la adrese divizibile cu 16. Restul de octeti (pana la al 16-lea) sunt nerezervati, dar
pot fi accesati relativ fata de adresa de inceput a segmentului.
Atentie ! In exemplul anterior instructiunea mov AX,offset d va pune in AX valoarea 0002h si nu 0030h deoarece
intoarce offset-ul fata de adresa segmentului parinte si nu fata de adresa de start a grupului.
In Debugger (la dezasamblarea instructiunilor) se observa ca variabilele b, vector, c si d sunt referite prin offseturi relative fata de adresa de inceput a grupului: 0002h, 0010h, 0030h, 0032h evidentiindu-se faptul ca intre
segmentele grupului s-a intercalat segmentul Temporare (ordinea de alocare in memorie este implicit .SEQ). Pentru
a evita situatia:
se declara segmentul Temporare dupa declararea celor 3 segmente Date1, Date2 si Date3;
se utilizeaza o clasa de segmente clasa_seg in care sunt puse segmentele Date1, Date2 si Date3.
De exemplu:
Date1 SEGMENT 'clasa_date'
a dw 1234h
b dw 5678h
Date1 ENDS
Date2 SEGMENT 'clasa_date'
vector dw 5 dup (9)
Date2 ENDS
Temporare SEGMENT BYTE
;alocare la o adresa divizibila cu 1
temp dw 5 dup (3)
Temporare ENDS
Date3 SEGMENT 'clasa_date'
c dw 1111h
d dw 2222h
Date3 ENDS
Stiva SEGMENT
dw 100 dup(?)
varf label word
Stiva ENDS
Date GROUP Date1, Date2, Date3
.................
DS:0000
DS:0008
DS:0010
DS:0018
DS:0020
DS:0028
34
00
09
09
11
03
12
00
00
00
11
00
78
00
09
00
22
03
56
00
00
00
22
00
00
00
09
00
03
03
00
00
00
00
00
00
00
00
09
00
03
00
00
00
00
00
00
00
;date
;zona
;date
;date
;date
;date
segment
de date
segment
segment
segment
segment
Date1
Date2
Date2
Date3 si Temporare
Temporare
Se observa ca indicand ca segmentul Temporare sa fie alocat la o adresa de tip BYTE el urmeaza dupa segmentul
Date3 eliminandu-se octetii nefolositi.
Tip
Interval de valori
Declarare
Short real
32
6-7
vb DD 1.2
Long real
64
15-16
vb DQ 2.3
10-byte real
80
19
DD
DD
DQ
11.765
1.1765E+1
1176.5E-2
;forma zecimala
;forma exponentiala zecimala
;forma exponentiala zecimala
In format hexazecimal reprezentarea numerelor reale utilizeaza cifrele 0 9 si A F. Numarul trebuie sa inceapa
obligatoriu cu una din cifrele 09 si sa se termine cu eticheta r ce indica tipul numarului ca fiind real. Numarul de
simboluri din reprezentarea hexazecimala este 8 pentru Short real, 16 pentru Long real si 20 pentru 10-Byte real.
In caz ca primul simbol din numar este unul din caracterele A F atunci se mai pune un 0 in fata, iar dimensiunea
ca numar de simboluri creste cu unu. De exemplu:
a
b
c
DD
DQ
DT
3F800000r
3D60000000000000r
0A456C000000000000000r
Pentru a usura lucrul cu date de tip real se pot defini propriile tipuri de date:
float
TYPEDEF DD
double TYPEDEF DQ
long_double
TYPEDEF DT
Valoare reala
Mantisa; este normalizata; are valori cuprinse in intervalul [1.000 , 1.111]; primele 2 formate
Exponent; reprezinta forma binara a exponentului; utilizat pentru a reface forma zecimala a
numarului;
Bias
permite reprezentarea valorilor negative ale exponentului; faciliteaza comparatia intre numere
reale.
pentru short real (simpla precizie):
31
30 23
22 0
63
62 52
51 32
31 0
79
78 64
63
62 32
31 0
de
reprezentare
reprezinta
formatul
IEEE
[http://en.wikipedia.org/wiki/IEEE_754],
[http://grouper.ieee.org/groups/754/] .
Dupa cum se observa la numerele reale pe 10 octeti, partea intreaga este reprezentata de bitul 63. Acest bit
permite atingerea unei precizii de 19 cifre. Partea intreaga este intotdeauna 1 la numere short real si long real si
de aceea nu mai este memorata.
Valoarea exponentiala reprezinta o putere a lui 2n. Pentru a se retine si valori negative de tipul 2 -8, valoarea
exponentului este ajustata adunand la ea valoarea 127 pentru numere reale simpla precizie (short real), 1023
pentru numere reale dubla precizie (long real) si 16383 pentru precizie extinsa (real pe 10 octeti).
Valoarea de ajustare este scazuta la conversia inversa din format intern (binar) in format extern (zecimal).
Exemplu de transformare a unui numar real din format zecimal in format binar:
Se considera numarul real -134,25. Transformarea acestuia in formatul intern IEEE presupune:
1. Identificarea semnului numarului; S = 1;
2. Transformare in format binar: 10000110,01
3. Normalizare forma binara: 1.000011001 x 27
4. Transformare exponent prin aplicare deplasare (bias): 7 + 127 = 134
5. Transformare exponent in format binar: 10000110
6. Obtinere format intern:
EXPONENT
MANTISA
1 1 0 0 0 0 1 1 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
are propriile registre de date si de control: 8 registre de date organizate sub forma de stiva si 7 registre de
control (asemenea registrelor flag);
cele 8 registre de date sunt pe 80 de biti si sunt organizate sub forma de stiva, cu toate ca permit si acces
direct; datele sunt incarcate in registrul din varf, ST(0) si coboara catre baza, registrul ST(7);
registrul din varful stivei este ST(0) sau ST, urmand apoi ST(1), ST(2), , ST(7);
odata incarcate datele sunt convertite automat la format pe 10 octeti;
stiva registrelor coprocesorului este:
Registru 79
78 63
62 0
ST(0)
ST(1)
ST(2)
ST(3)
ST(4)
ST(5)
ST(6)
ST(7)
semn exponent parte zecimala
Tipuri de instructiuni
Cele 8 registre de date pot fi accesate ca elemente ale unei stive sau ca elemente individuale asemenea registrelor
procesorului. Toate instructiunile coprocesorului pentru prelucrarea valorilor reale incep cu F.
*
Format instructiune
Sintaxa
Operatori impliciti
Classical stack
Finstructiune
ST,ST(1)
Memory
Finstructiune variabila
ST
Register
Finstructiune ST(nr),ST
Finstructiune ST,ST(nr)
Register pop
*-
FinstructiuneP
ST(nr),ST
sinatxa Finstructiune
considera registrele coprocesorului ca parti componente ale unei stive; valorile sunt adaugate sau scoase din
varful stivei, adica ST sau ST(0);
Pentru programul anterior stiva registrelor coprocesorului trece prin urmatoarele faze:
#1
ST
#2
#3
#4
#5
#6
12.304 1.23
#7
#8
13.534
ST(1)
3.6
11.304
12.304
ST(2)
Formatul Memory
Main SEGMENT
ASSUME CS:Main, DS:DateIn
start:
mov AX,DateIn
mov DS,AX
Fld a
Fld b
Fstp a
;#1
;#2
;#3
Fstp b
;#4
Pentru programul anterior stiva registrelor coprocesorului trece prin urmatoarele faze:
#1
ST
#2
1.23 3.6
#3
#4
1.23
ST(1)
1.23
ST(2)
Formatul Register
rezultatul instructiunii este pus in destinatie, iar valoarea din sursa (ST varful stivei) este scoasa din stiva;
astfel de instructiuni sunt cele ce implementeaza operatii matematice si care necesita scoaterea valorii sursei
din stiva:
;#1
;#2
;#3
;#4
;#5
;#6
;#7
;#8
;#9
;#10
Ffree ST(1)
Fstp ES:e
;#11
mov AX,4c00h
int 21h
Main ENDS
end start
Pentru programul anterior stiva registrelor coprocesorului trece prin urmatoarele faze:
#1
#2
#3
#4
#5
#6
#7
#8
#9
#10
#11
#1
2
1.2
3
1.2
3
1.512
9
1.23
3.6
3.6
4.428
5.658
10.770
9
10.770
9
10.770
9
ST(1
)
1.2
3
1.23
1.512
9
1.23
1.23
1.23
1.23
1.23
1.23
ST(2
)
1.512
9
5.112
9
5.112
9
5.112
9
5.1129
ST
Formatul Register
astfel de instructiuni sunt cele ce implementeaza operatii matematice si care necesita scoaterea valorii din
varful stivei;
;#1
;#2
;#3
;#4
;#5
;#6
;#7
;#8
mov AX,4c00h
int 21h
Main ENDS
end start
Pentru programul anterior stiva registrelor coprocesorului trece prin urmatoarele faze:
#1
#2
#3
#4
#5
#6
#7
#8
1.23
3.6
3.5
7.43
3.5
3.6
15.76
ST(1)
1.23
3.6
3.5
3.6
12.16
ST(2)
1.23
3.6
8.66
ST(3)
1.23
ST
Exemplu complet de program in limbaj de asamblare ce rezolva ecuatia de gradul al 2-lea: aX2+bX+c=0 unde a
= 3.8, b = 8.2 si c = 1.6.
DateIn SEGMENT
a DD 3.8
b DD 8.2
c DD 1.6
DateIn ENDS
DateOut SEGMENT
x1 DD ?
x2 DD ?
DateOut ENDS
Main SEGMENT
ASSUME CS:Main, DS:DateIn
start:
mov AX,DateIn
mov DS,AX
Fld1
;incarc valoarea 1 in ST - #1
Fadd ST,ST
;adun ST cu ST si obtin 2 - #2
FLD ST ;incarc valoarea din ST - #3
Fmul a ;obtin 2*a - #4
Fmul ST(1),ST
;calculez valoarea lui 4*a - #5
Fxch
;interschimb ST cu ST(1) - #6
Fmul c ;inmultesc ST cu c si obtin valoarea lui 4*a*c - #7
Fld b
Fmul ST,ST
FsubR
;valoarea din ST - #10
Fdiv ST,ST(2)
Fstp x1
FdivR
Pentru programul anterior stiva registrelor coprocesorului trece prin urmatoarele faze:
#1
#2
#3
#4
#5
ST
7.6
7.6
15.2 24.32
ST(1)
15.2
7.6
ST(2)
ST(3)
ST(4)
#11
#12
#13
#6
#7
#8
#9
#10
8.2
67.24
42.92
7.6
24.32
24.32
7.6
7.6
7.6
#14
#15
#16
#17
#18
#19
#20
#21
ST
6.55
8.2
-8.2
6.55
-1.64
0.21
ST(1)
7.6
6.55
6.55
-8.2 6.55
6.55
ST(2)
7.6
7.6
7.6
-8.2
-8.2
-8.2
7.6
ST(3)
7.6
7.6
7.6
ST(4)
-14.75 -1.94
7.6
7.6
FSUB [operanzi]
FSUB op1,op2
FSUB vb
FSUBR [operanzi]
FSUBRPop1,op2
FSUBR vb
FDIV [operanzi]
FDIVP op1,op2
FIDIV vb
FDIVR [operanzi]
FDIVRP opl/op2
FDIVR vb
FSQRT
FSCALE
FPREM
FRNDINT
FXTRACT
FABS
FCHS
ST = -ST
FCOS
cosinusul lui ST
FPATAN
FPTAN
FSIN
sinusul lui ST
2ST-1; -1ST1
FYL2X
Nr. registru
Registre de control
Cuvant de control
Cuvant de stare
3
4
Instruction Pointer
5
6
Operand pointer
7
Registrul asociat cuvantului de stare este cel mai folosit, restul fiind utilizati de programatorii de sistem.
Modul in care sunt aranjati bitii din octetul superior este identic cu modul de aranjare a flag-urilor din registrul de
flag al procesorului. Situatia un este intamplatoare si faciliteaza controlul executiei programului in cazul
coprocesorului (acesta nu are instructiuni de salt conditionat si atunci trebuie sa trimita procesorului informatia).
Octetul superior al cuvantului de stare:
15 14 13 12 11 10
C3
C2 C1 C0
SF ZF
4
AF
2
PF
0
CF
Coprocesorul are instructiuni care seteaza flag-urile din cuvantul de stare (unul dintre registrele de stare). Acest
registru este utilizat pentru a controla executia programului si pentru a introduce structuri de control prin
intermediul salturilor conditionate. Singura problema este ca, coprocesorul matematic nu are instructiuni de salt,
doar procesorul are. Din acest motiv cuvantul de stare trebuie incarcat in memorie in Flag-urile procesorului astfel
incat sa se pastreze semnificatia valorilor. Solutia este data de incarcarea octetului superior din cuvantul de stare
in octetul inferior din registrul de flag-uri al procesorului prin secventa:
variabila_de_tip_word
Fstsw
;pun valoarea cuvantului de stare intr-o variabila
Fwait
AX, variabila_de_tip_word ;incarc valoarea variabilei in AX
mov
sahf
;incarc valoarea din AH in registrul de Flag al
;procesorului
Odata incarcata aceasta valoare se pot instructiuni de salt conditionat pe baza valorilor din registrele
coprocesorului matematic.
Coprocesorul are o serie de instructiuni care analizeaza valoare din registrul ST in relatie cu valoarea altui operand
si raporteaza rezultatul intr-un cod de conditie (dat de bitii C0, C1, C2, C3) ai cuvantului de stare. Operatiile de
baza sunt de comparare si de testare(comparare cu zero).
Dupa FCOM
Dupa FTEST
ST > sursa
ST > 0
ST < sursa
ST < 0
ST = sursa
ST = 0
C3 C2 C0
FCOM op
FCOMP op
FCOMPP
FICOM vb
FICOMP vb
FUCOM op
FUCOMP op
compara SI cu 0.0
FXAM
FINIT
FFREE [reg]
Valoare
zecimala
Valoare HEX
hexazecimala
Simbol
Cod numeric
HTML
Cod
HTML
NUL
null
SOH
start heading
STX
start text
ETX
sfarsit text
EOT
sfarsit transmisie
ENQ
enquiry
ACK
acknowledge (confirmare)
BEL
bell
BS
backspace
TAB
tabulation
10
LF
line feed
11
VT
vertical tabulation
12
FF
form feed
13
CR
carriage return
14
SO
shift out
15
SI
shift in
16
10
DLE
17
11
DC1
device control 1
Descriere
18
12
DC2
device control 2
19
13
DC3
device control 3
20
14
DC4
device control 4
21
15
NAK
negative acknowledge
22
16
SYN
synchronous idle
23
17
ETB
24
18
CAN
cancel
25
19
EM
end of medium
26
1A
SUB
substitute
27
1B
ESC
escape
28
1C
FS
file separator
29
1D
GS
group separator
30
1E
RS
record separator
31
1F
US
unit separator
32
20
33
21
!
34
22
"
35
23
#
diez
36
24
$
dolar
37
25
%
procent
38
26
&
&
(space)  
space (spatiu)
semn de exclamatie
"
&
ghilimele
39
27
'
apostrof
40
28
(
paranteza deschisa
41
29
)
paranteza inchisa
42
2A
*
asterix
43
2B
+
plus sign
44
2C
,
virgula
45
2D
-
minus
46
2E
.
punct
47
2F
/
slash
48
30
0
49
31
1
50
32
2
51
33
3
52
34
4
53
35
5
54
36
6
55
37
7
56
38
8
57
39
9
58
3A
:
doua puncte
59
3B
;
punct si virgula
60
3C
<
<
<
mai mic
61
3D
=
62
3E
>
>
63
3F
?
semnul intrebarii
64
40
@
65
41
A
66
42
B
67
43
C
68
44
D
69
45
E
70
46
F
71
47
G
72
48
H
73
49
I
74
4A
J
75
4B
K
76
4C
L
77
4D
M
78
4E
N
79
4F
O
80
50
P
egal
>
mai mare
81
51
Q
82
52
R
83
53
S
84
54
T
85
55
U
86
56
V
87
57
W
88
58
X
89
59
Y
90
5A
Z
91
5B
[
92
5C
\
93
5D
]
94
5E
^
95
5F
_
96
60
`
97
61
a
98
62
b
99
63
c
100
64
d
101
65
e
paranteza patrata
deschisa
102
66
f
103
67
g
104
68
h
105
69
i
106
6A
j
107
6B
k
108
6C
l
109
6D
m
110
6E
n
111
6F
o
112
70
p
113
71
q
114
72
r
115
73
s
116
74
t
117
75
u
118
76
v
119
77
w
120
78
x
121
79
y
122
7A
z
123
7B
{
124
7C
|
125
7D
}
126
7E
~
127
7F
160
A0
161
A1
162
tilda
 
spatiu
¡
¡
inverted exclamation
mark
A2
¢
¢
cent
163
A3
£
£
pound
164
A4
¤
¤
currency
165
A5
¥
¥
yen
166
A6
¦
¦
167
A7
§
§
section sign
168
A8
¨
¨
169
A9
©
©
copyright
170
AA
ª
ª
171
AB
«
«
172
AC
¬
¬
not sign
173
AD
­
­
soft hyphen
174
AE
®
®
175
AF
¯
¯
176
B0
°
°
degree sign
177
B1
±
±
plus-or-minus sign
178
B2
²
²
179
B3
³
³
180
B4
´
´
181
B5
µ
µ
micro sign
182
B6
¶
¶
183
B7
·
·
184
B8
¸
¸
spacing cedilla
185
B9
¹
¹
superscript one
186
BA
º
º
masculine ordinal
indicator
187
BB
»
»
188
BC
¼
¼
fractie sfert
189
BD
½
½
fractie jumatate
190
BE
¾
¾
fractie 3 sferturi
191
BF
¿
¿
192
C0
À
À
193
C1
Á
Á
194
C2
Â
Â
195
C3
Ã
Ã
196
C4
Ä
Ä
197
C5
Å
Å
198
C6
Æ
Æ
199
C7
Ç
Ç
200
C8
È
È
201
C9
É
É
202
CA
Ê
Ê
203
CB
Ë
Ë
204
CC
Ì
Ì
205
CD
Í
Í
206
CE
Î
Î
207
CF
Ï
Ï
208
D0
Ð
Ð
209
D1
Ñ
Ñ
210
D2
Ò
Ò
211
D3
Ó
Ó
212
D4
Ô
Ô
213
D5
Õ
Õ
214
D6
Ö
Ö
215
D7
×
×
multiplication sign
216
D8
Ø
Ø
217
D9
Ù
Ù
218
DA
Ú
Ú
219
DB
Û
Û
220
DC
Ü
Ü
221
DD
Ý
Ý
222
DE
Þ
Þ
223
DF
ß
ß
224
E0
à
à
225
E1
á
á
226
E2
â
â
227
E3
ã
ã
228
E4
ä
ä
229
E5
å
å
230
E6
æ
æ
231
E7
ç
ç
232
E8
è
è
233
E9
é
é
234
EA
ê
ê
235
EB
ë
ë
236
EC
ì
ì
237
ED
í
í
238
EE
î
î
239
EF
ï
ï
240
F0
ð
ð
241
F1
ñ
ñ
242
F2
ò
ò
243
F3
ó
ó
244
F4
ô
ô
245
F5
õ
õ
246
F6
ö
ö
247
F7
÷
÷
division sign
248
F8
ø
ø
249
F9
ù
ù
250
FA
ú
ú
251
FB
û
û
252
FC
ü
ü
253
FD
ý
ý
254
FE
þ
þ
255
FF
ÿ
ÿ
338
152
Œ
339
153
œ
352
160
Š
353
161
š
376
178
Ÿ
402
192
ƒ
8211
2013
–
en dash
8212
2014
—
em dash
8216
2018
‘
8217
2019
’
8218
201A
‚
8220
201C
“
8221
201D
”
8222
201E
„
8224
2020
†
dagger
8225
2021
‡
double dagger
8226
2022
•
bullet
8230
2026
…
horizontal ellipsis
8240
2030
‰
8364
20AC
€
8482
2122
™
€
euro
trade mark