CATEGORII DOCUMENTE |
Instructiuni de apel de procedura si de salt (CALL, RET, JMP)
Procedurile se definesc in textul sursa dupa sablonul:
nume_proc PROC [ FAR | NEAR ]
RET
nume_proc ENDP
unde nume_proc este numele procedurii, iar parametrii FAR sau NEAR (optionali) indica tipul procedurii.
Procedurile sunt de doua tipuri: FAR si NEAR. O procedura FAR poate fi apelata si din alte segmente de cod decat cel in care este definita, pe cand o procedura NEAR poate fi apelata numai din segmentul de cod in care este definita.
Daca se omit parametrii FAR sau NEAR, tipul procedurii este dedus din directivele simplificate de definire a segmentelor (modelul de memorie folosit). De exemplu, modelul LARGE presupune ca toate procedurile sunt implicit de tip FAR.
In mod corespunzator, exista apeluri de tip FAR, respectiv NEAR, precum si instructiuni de revenire de tip FAR, respectiv NEAR.
Instructiunea RET (Return) provoaca revenirea in programul apelant. Putem scrie o instructiune Return explicita, in formele RETN (Return Near) sau RETF (Return Far), sau RET pur si simplu, caz in care tipul instructiunii Return este dedus din tipul procedurii (FAR sau NEAR).
1 Apelul procedurilor si revenirea din proceduri
Instructiunea CALL (Apel de procedura)
Poate avea una din formele:
. CALL nume_proc
. CALL FAR PTR nume_proc
. CALL NEAR PTR nume_proc
In primul caz, tipul apelului este dedus din tipul procedurii, iar in celelalte, este specificat explicit (FAR sau NEAR).
Tipul apelului trebuie sa coincida cu tipul procedurii si cu tipul instructiunilor Return din interiorul procedurii, altfel se ajunge la functionari defectuoase ale programului.
Semnificatia instructiunii CALL este urmatoarea:
CALL de tip NEAR
(SP) <- (SP) - 2
SS:((SP) + 1 : (SP)) <- (IP)
(IP) <- offset-ul primei instructiuni din procedura
Descrierea de mai sus spune ca se salveaza in stiva contorul program curent, intr-o maniera similara instructiunii PUSH (se decrementeaza registrul SP cu 2 si se inscrie continutul lui IP in varful stivei). Registrul IP contine totdeauna adresa instructiunii care urmeaza (in memorie), dupa instructiunea care se executa in mod curent. Practic, se salveaza in stiva adresa instructiunii de dupa instructiunea CALL. Aceasta adresa este numita adresa de revenire.
Dupa aceasta salvare, se incarca in IP adresa (deplasamentul) primei instructiuni din procedura, ceea ce inseamna un transfer al controlului catre procedura.
Este important de retinut ca, in momentul intrarii in procedura, in varful stivei exista adresa de revenire. Aceasta adresa nu trebuie modificata in nici un fel, in caz contrar, revenirea in programul apelant nemaifiind posibila.
De observat ca, in secventa de apel a procedurii, registrul CS nu se modifica, ceea ce inseamna ca se ramane in acelasi segment de cod.
CALL de tip FAR
(SP) <- (SP) - 2
SS:((SP) + 1 : (SP)) <- (CS)
(SP) <- (SP) - 2
SS:((SP) + 1 : (SP)) <- (IP)
(CS) <- adresa de segment a primei instructiuni din
procedura
(IP) <- offset-ul primei instructiuni din procedura
Ceea ce este diferit fata de apelul de tip NEAR este faptul ca se salveaza adresa completa de revenire (pe 32 de biti), prin plasarea in stiva atat a registrului IP, cat si a registrului CS. Similar, transferul controlului se face prin modificarea explicita a perechii de registre (CS:IP).
De observat ca instructiunea CALL de tip FAR este una din putinele instructiuni care modifica explicit registrul CS.
Instructiunea RET (Return - Revenire din procedura)
Exista Return de tip FAR si Return de tip NEAR. Formele posibile ale instructiunii sunt:
. RETN[N]
. RETF[N]
. RET[N]
in care parantezele drepte spun ca N este o constanta intreaga optionala.
In cea de-a treia forma, tipul instructiunii (NEAR sau FAR) este dedus din tipul procedurii.
Semnificatia este urmatoarea:
Return de tip NEAR
(IP) <- SS:((SP) + 1 : (SP))
(SP) <- (SP) + 2
[(SP) <- (SP) + N]
Se observa ca se reface registrul (IP), prin copierea varfului stivei si incrementarea registrului SP cu 2. Daca SP are aceeasi valoare ca la intrarea in procedura si continutul stivei nu a fost alterat intre timp, atunci se copiaza practic in IP adresa de revenire, ceea ce provoaca transferul controlului la instructiunea care urmeaza instructiunii CALL care a provocat apelul procedurii.
Daca in formatul instructiunii RET exista constanta optionala N, atunci se aduna aceasta constanta la registrul SP. Acest tip de Return se numeste Return cu descarcarea stivei.
Return de tip FAR
(IP) <- SS:((SP) + 1 : (SP))
(SP) <- (SP) + 2
(CS) <- SS:((SP) + 1 : (SP))
(SP) <- (SP) + 2
[(SP) <- (SP) + N]
Se reface din stiva perechea de registre (CS:IP), cu actualizarea registrului SP si, daca este prezenta constanta N, se aduna N la SP.
Este important de retinut ca instructiunile CALL si RET sunt instructiuni pereche:
ele salveaza, respectiv refac adresa de revenire. Pentru ca mecanismul de apel / revenire sa functioneze corect, trebuie indeplinite conditiile:
. tipul instructiunii CALL si tipul instructiunii RET trebuie sa coincida (FAR sau NEAR);
. registrul SP din momentul executiei instructiunii RET sa aiba aceeasi valoare ca la intrarea in procedura (sa indice adresa de revenire);
. adresa de revenire salvata in stiva sa nu fi fost alterata de catre procedura.
Incalcarea unora din cele trei conditii de mai sus constituie o eroare frecventa de programare. In astfel de cazuri, functionarea programului este compromisa, deoarece se plaseaza in CS si / sau IP o adresa incorecta, unde probabil nici nu exista vreun program cu sens. Acest tip de eroare se numeste "executie de date', adica procesorul ajunge sa execute nu instructiuni cu sens (definite intr-un segment de cod), ci o zona oarecare de memorie (date).
Recunoasterea acestei erori este destul de usoara: se blocheaza tastatura, pe ecranul calculatorului apar tot felul de caractere ciudate, difuzorul incepe sa tiuie etc. Singura solutie este in acest caz un reset general al calculatorului.
Putem, deci, enunta o regula de aur a programarii in limbaj de asamblare:
Verificati controlul stivei!
2 Instructiunea de salt (JMP)
Are forma generala:
JMP tinta
in care tinta specifica adresa de salt (punctul in care se va da controlul). Specificarea tintei se poate face printr-o eticheta sau printr-o expresie (vezi 3). Etichetele au asociat un tip (NEAR sau FAR) si pot fi:
. un nume de procedura;
. o eticheta definita cu : (de tip NEAR);
. o eticheta definita cu directiva LABEL.
Exemple de etichete:
et1:
aici:
et3 LABEL FAR
gata LABEL NEAR
Exista trei tipuri de instructiuni JMP:
. de tip SHORT - adresa tinta este situata la o adresa in domeniul [-128, +127] fata de adresa instructiunii JMP;
. de tip NEAR - adresa tinta este in acelasi segment de cod cu instructiunea JMP;
. de tip FAR - adresa tinta poate fi in alt segment de cod fata de instructiunea
JMP.
Tipurile de salt pot fi explicitate prin operatorul PTR, intr-una din formele:
JMP NEAR PTR tinta
JNP FAR PTR tinta
sau se deduc din atributele expresiei care precizeaza tinta. In cazul etichetelor, tipul etichetei (FAR sau NEAR) furnizeaza tipul saltului.
Semnificatia instructiunii JMP este:
JMP de tip SHORT
(IP) <- (IP) + distanta dintre offset-ul curent si
cel tinta
JMP de tip NEAR
(IP) <- offset-ul adresei tinta
JMP de tip FAR
(IP) <- offset-ul adresei tinta
(CS) <- segmentul adresei tinta
Din punctul de vedere al programatorului, faptul ca la saltul de tip SHORT se aduna la IP o diferenta este similar cu modificarea explicita a lui IP de la JMP de tip NEAR.
Ceea ce difera este codificarea interna a celor doua instructiuni:
. la salt de tip SHORT, codul instructiunii contine diferenta dintre offset-ul curent si cel al tintei. Aceasta diferenta se memoreaza intern pe un octet, de unde restrictia de domeniu
. la salt de tip NEAR, codul instructiunii contine explicit offset-ul tintei. Se observa ca salturile de tip NEAR si FAR sunt similare cu apelurile de procedura de tip NEAR sau FAR, fara insa a se salva adresa de revenire si identificand numele procedurii cu o eticheta.
3 Tipuri de salt / apel
Tipurile de instructiuni de salt si de apel specifica modul de determinare a adresei tinta, respectiv al adresei procedurii. Deoarece aceste tipuri sunt identice pentru instructiunile JMP si CALL, vor fi prezentate impreuna. Prin instructiuni de salt intelegem aici cele de tip NEAR sau FAR (salturile de tip SHORT sunt implicit directe). De asemenea, in cele ce urmeaza identificam etichetele cu numele de proceduri.
Operandul care apare in formatul instructiunii este o eticheta care identifica Punctul in care se da controlul (adresa tinta). Salturile / apelurile directe pot fi:
. salturi / apeluri directe intrasegment (NEAR) - eticheta este in acelasi segment de cod cu instructiunea JMP/CALL;
. salturi / apeluri intersegment (FAR) - eticheta poate fi definita si in alt segment de cod decat cel care contine instructiunea JMP/CALL.
Exemplu:
. code
ALFA:
BETA LABEL FAR
. . . .
GAMMA PROC FAR
. . . .
GAMMA ENDP
. . . .
JMP/CALL ALFA ; NEAR
JMP/CALL BETA ; FAR implicit
JMP/CALL FAR PTR GAMMA ; FAR explicit
JMP / CALL de tip indirect
Operandul care apare in formatul instructiunii JMP/CALL reprezinta un cuvant (sau un dublu-cuvant) din memorie, care contine adresa NEAR (sau FAR) unde se va da controlul.
Salturile / apelurile indirecte pot fi:
. Salt / apel indirect intrasegment (NEAR)
Forma generala este:
JMP/CALL expr
in care expr poate fi:
a) un registru care contine offset-ul tintei;
b) o variabila de tip WORD care contine offset-ul tintei;
c) o expresie cu indici reprezentand un cuvant din memorie care contine offset-ul tintei;
. d) o referire anonima la un cuvant din memorie care contine offset-ul tintei. Sa consideram cateva exemple:
.data
W__ALFA dw N_ETIC
W_TAB_PROC dw N_PROC_0
dw N_PROC_1
dw N_PROC_2
.code
N_ETIC: ; Eticheta NEAR
. . . .
N_PROC_i PROC NEAR ; i = 0, 1, 2
. . . .
N_PROC_i ENDP
LEA BX, N_PROC_1
JMP/CALL BX ; Tipul a)
JMP/CALL W_ALFA ; Tipul b)
JMP/CALL W_TAB_PROC [SI] ; Tipul c); SI = 0, 2, 4
LEA BX, W_TAB_PROC
JMP/CALL WORD PTR [BX] [SI]; Tipul d); SI = 0, 2, 4
LEA BX, W_ALFA
JMP/CALL WORD PTR [BX] ; Tipul d)
Formele cu referiri anonime la memorie trebuie insotite de operatorul WORD PTR. Ultimele doua exemple de salt / apel (tipul d) pun in evidenta doua nivele de indirectare (vezi Figura 2.4): de la BX la variabila W_ALFA si de la W_ALFA la eticheta N_ETIC.
Figura 2.4 Cele doua nivele de indirectare la CALL WORD PTR [BX]
. Salt / apel indirect intersegment (FAR)
Forma generala este:
JMP/CALL expr
in care expr poate fi:
. a) o variabila de tip DWORD care contine adresa completa a tintei;
. b) o expresie cu indici reprezentand un dublu cuvant din memorie care contine adresa completa a tintei;
. c) o referire anonima la un dublu cuvant de memorie care contine adresa tintei.
Sa consideram cateva exemple:
.data
D_ALFA dd F_ETIC
D_TAB_IROC dd F_PROC_0
dd F_PROC_1
dd F_PROC_2
. code
F_ETIC LABEL FAR ; Eticheta FAR
. . . .
E_PROC_i PROC FAR ; i = 0, 1, 2
. . . .
E_PROC_i ENDP
. . . .
JMP/CALL D_ALFA ; Tipul a)
JMP/CALL D_TAB_PROC [SI] ; Tipul b); SI = 0, 4, 8
LEA BX, D_TAB_PROC
JMP/CALL DWORD PTR [BX SI] ; Tipul c); SI = 0, 4, 8
LEA BX, D_ALFA
JMP/CALL DWORD PTR [BX] ; Tipul c)
Formele cu referiri anonime la memorie trebuie insotite de operatorul DWORD PTR. Ultimele doua exemple de salt / apel (tipul c) pun in evidenta doua nivele de indirectare (vezi Figura 2.5): de la BX la variabila DALFA si de la DALFA la eticheta ETIC.
Apelurile indirecte de proceduri trebuie sa respecte tipul procedurii. Astfel, o instructiune de forma CALL WORD PTR [BX] trebuie folosita numai cu proceduri de tip NEAR, iar una de tip CALL DWORD PTR [BX] numai cu proceduri de tip FAR.
Figura 2.5 Cele doua nivele de indirectare la CALL DWORD PTR [BX]
Sa consideram un exemplu de utilizare a tabelelor de adrese. Presupunem dezvoltarea unui meniu de comenzi, fiecare comanda fiind reprezentata de un caracter alfabetic (de la 'A' la 'Z'). Unele caractere pot sa nu fie utilizate in meniu. De asemenea, presupunem caracterul in registrul AL si existenta, pentru fiecare comanda, a unei proceduri de tratare.
O solutie evidenta, dar ineficienta este compararea lui AL cu toate caracterele meniului si cu apeluri corespunzatoare de proceduri, deci ceva de genul:
CMP AL, 'A'
JZ et_A
CMP AL, 'B'
JZ et_B ; etc.
Evident ca, daca meniul este mare, o asemenea secventa de program este greu de intretinut. Adaugarea sau eliminarea unei comenzi presupune parcurgerea cu atentie a codului sursa.
Solutia adecvata a problemei consta in definirea unei tabele cu adresele procedurilor de tratare, in ordinea alfabetica a comenzilor. Pentru literele de alfabet care nu sunt alocate nici unei comenzi, se scrie o procedura speciala PROC_NULL. La executie, se va calcula pozitia respectiva din tabela, chiar pe baza caracterului din AL si se va genera un apel indirect de procedura.
.data
TAB_CMD DW PROC_A
DW PROC_B
DW PROC_NULL ; Comanda 'C' nu exista
DW PROC_D
; etc.
DW PROC_Z
.code
SUB AL, 'A' ; AL = 027
ADD AL, AL ; AL <-- 2*AL
ADD AL, AL ; Se pune in cazul
; procedurilor FAR
MOV BL, AL
XOR BH, BH ; BX = intrare
; in tabela
CALL WORD PTR TAB_CMD[BX]
In cazul procedurilor far, se defineste tabela TAB_CMD cu directiva Define DoubleWord si se calculeaza BX <- 4*AL, in loc de BX <- 2*AL.
Aceasta implementare este foarte usor de intretinut. Eliminarea unei comenzi se face punand adresa procedurii PROC_NULL pe pozitia corespunzatoare. Adaugarea unei comenzi se face inlocuind procedura PROC_NULL cu procedura de tratare a noii comenzi.
Nici un tip de instructiune de salt sau de apel de procedura nu modifica vreun bistabil de conditie.
4 Instructiuni de salt conditionat
Instructiunile din aceasta categorie implementeaza salturi conditionate de valoarea unor bistabili de conditie. Prin extensie, instructiunile de salt obisnuite (JMP) se mai numesc si salturi neconditionate. Instructiunile de salt conditionat au urmatoarele caracteristici:
. toate instructiunile de salt conditionat sunt de tip SHORT (deci directe), ceea ce inseamna ca adresa tinta trebuie sa fie la o distanta cuprinsa intre -127 si +128 de octeti fata de instructiunea de salt;
. exista mai multe mnemonice pentru aceeasi instructiune;
. daca conditia nu este indeplinita, saltul nu are loc, deci executia continua cu instructiunea urmatoare;
. exista instructiuni atat pe conditia directa, cat si pe conditia negata;
. bistabilii de conditie nu sunt afectati.
In Tabelul 2.6, se prezinta instructiunile de salt conditionat. Prima coloana (listeaza rnnemonicele instructiunilor, coloana a doua listeaza conditia de salt, iar coloana a treia interpretarea conditiei respective. Primele opt linii reprezinta salturile pe conditiile directe, iar celelalte opt, salturile pe conditiile corespunzatoare negate.
Denumirile instructiunilor se citesc in forma:
unde < lnterpretare > este textul din coloana a treia.
Instructiunile de salt conditionat se utilizeaza dupa o instructiune care modifica bistabilii de conditie. Cea mai des intalnita situatie este instructiunea de comparatie CMP.
Se observa ca (exista doua categorii de instructiuni pentru notiunile de "mai mic' si "mai mare': cele care contin cuvintele "above' sau "bellow' si cele care contin cuvintele "less' sau "greater'. Primele se folosesc in situatia comparatiei a doua cantitati fara semn, iar ultimele, in situatia comparatiei unor cantitati cu semn.
Sa consideram urmatoarele secvente de program, in care se compara valorile 0FFH si 1:
MOV AL, 0FFH MOV
MOV BL, 1 MOV BL, 1
CMP AL, BL CMP AL, BL
JA ET_1 JG ET_1
Se observa ca AL) > (BL) daca interpretam cete doua valori fara semn (255 > 1) si ca (AL) < (BL) daca interpretam cele doua valori cu semn (-1 < 1). Astfel, in primul exemplu, saltul la eticheta ET_1 are loc, pe cand in cel de-al doilea nu.
Conditiile asupra bistabililor in cele doua tipuri de instructiuni si semnificatia bistabililor respectivi (vezi 2.2.1) explica cele doua tipuri de conditii.
Retinem deci urmatoarele reguli:
. La comparatii cu semn, folosim "GREATER' si "LESS'
. La comparatii fara semn, folosim "ABOVE' si "BELLOW'
Instructiune (mnemonica) |
Conditie de salt |
Interpretare |
JE, JZ |
ZF = 1 |
Zero, Equal |
JL, JNGE |
SF ≠ OF |
Less, Not Greater or Equal |
JLE, JNG |
SF ≠ OF sau ZF = 1 |
Less of Equal, Not Greater |
JB, JNAE, JC |
CF = 1 |
Below, Not Above or Equal, Carry |
JBE, JNA |
CF = 1 sau ZF = 1 |
Below or Equal, Not Above |
JP, JPE |
PF = 1 |
Parity, Parity Even |
JO |
OF = 1 |
Overflow |
JS |
SF = 1 |
Sign |
JNE, JNZ |
ZF = 0 |
Not Zero, Not Equal |
JNL, JGE |
SF = OF |
Not Less, Greater or Equal |
JNLE, JG |
SF = OF sau ZF = 0 |
Not Less of Equal, Greater |
JNB, JAE, JNC |
CF = 0 |
Not Below, Above or Equal, Not Carry |
JNBE, JA |
CF = 0 sau ZF = 0 |
Not Below or Equal, Above |
JNP, JPO |
PF = 0 |
Not Parity, Parity Odd |
JNO |
OF = 0 |
Not Overflow |
JNS |
SF = 0 |
Not Sign |
Tabelul 2.6 Instructiunile de salt conditionat
Uneori este necesar sa scriem instructiuni de salt conditionat la etichete care ies in afara domeniului [-128, +127] fata de instructiunea curenta. In aceasta situatie, folosim urmatoarea schema, prin care inlocuim saltul pe o conditie directa "departe' cu un salt pe conditia negata "aproape' si cu un salt neconditionat "departe'.
Salt conditionat pe conditie directa la ET_1
Eticheta ET_1 e prea departe
ET_1:
Forma echivalenta este:
Salt conditionat pe conditie negata la ET_2
Salt neconditionat la ET_1
ET_2:
De exemplu, instructiunea:
JE ET_1
se substituie cu:
JNE ET_2
JMP ET_1
ET_2:
In schema echivalenta, eticheta ET_1 poate fi la orice distanta fata de punctul de salt.
5 Instructiuni pentru controlul buclelor de program (JCXZ, LOOP, LOOPZ / LOOPE, LOOPNZ / LOOPNE)
Instructiunea JCXZ (Jump if CX is Zero - Salt daca CX este zero)
Are forma generala:
JCXZ etic
unde etic este o eticheta aflata in domeniul [-128, +127] fata de instructiunea curenta (la fel ca la salturile de tip SHORT).
Semnificatia este evidenta:
daca (CX) = 0
(IP) <- (IP) + distanta dintre offset-ul curent si cel tinta
adica se sare la eticheta specificata daca CX contine valoarea 0.
Instructiuni de ciclare (LOOPxx - Cicleaza)
Aceste instructiuni sunt, de fapt, salturi conditionate de valoarea registrului CX si de bistabilul ZF. La fel ca prefixele de repetare, cu care, de altfel, se aseamana oarecum, exista cate doua mnemonice pentru aceeasi instructiune. Forma lor generala este:
LOOPxx etic
unde etic este o eticheta aflata in domeniul [-128, +127] fata de instructiunea curenta.
Toate aceste instructiuni utilizeaza registrul CX ca numar de iteratii.
Semnificatia este urmatoarea:
CX <- CX - 1
daca CX != 0, atunci
(IP) <- (IP) + distanta dintre offset-ul curent si cel tinta
Cu alte cuvinte, se decrementeaza CX si, daca acesta este diferit de zero, se sare la eticheta specificata.
Urmatoarea secventa calculeaza suma (pe 16 biti) a elementelor unui tablou TAB DE 100 de intregi si o depune in variabila SUMA.
. data
TAB DW 100 DUP (0)
SUMA DW ?
.code
XOR AX, AX ; Initializeaza suma
MOV CX, 100 ; Numar de iteratii
MOV SI, AX ; Initializeaza indice
NEXT:
ADD AX, TAB [SI] ; Calcul suma
ADD SI, 2 ; Actualizare indice
LOOP NEXT ; Cicleaza
MOV SUMA, AX ; Depune rezultat
Forma generala a unei bucle de program realizata cu instructiunea LOOP este:
start_bucla:
;
; Corp bucla ;
;
LOOP start_bucla
Corpul buclei se va executa de atatea ori cat este continutul initial al registrului CX (presupunand ca acesta nu este modificat explicit in interiorul buclei).
Trebuie observat ca registrul CX este mai intai decrementat si apoi testat. Ca atare, daca (CX) este initial 0, bucla de program se va executa de 65535 de ori. Protectia fata de o asemenea situatie se realizeaza prin instructiunea JCXZ. Forma corecta a buclei de program va fi:
JCXZ end_bucla
start_bucla:
;
; Corp bucla ;
;
LOOP start_bucla
end_bucla:
In forma de mai sus, daca (CX) este initial 0, corpul buclei nu se executa niciodata.
In situatia in care corpul buclei ocupa mai mult de 128 de octeti, trebuie sa renuntam la JCXZ si LOOP si sa le inlocuim cu comparatii si cu salturi explicite. Bucla de program va avea forma generala:
TEST CX, CX
start_bucla:
; ;
; Corp bucla;
; ;
DEC CX
TEST CX, CX
JZ end_bucla
JMP start_bucla
end_bucla:
Urmatorul exemplu calculeaza primele 20 de numere Fibonacci (fib(n), n =1,,20), definite recursiv prin:
f(0)=0,f(1)=1
f(k)=f(k-1)+f(k-2), daca n > 1
si le depune in tabloul FIBO. Cele trei valori (f(k), f(k-1) si f(k-2)) care intervin in calcul sunt tinute in registrele AX, BX si DX.
.data
FIBO DW 20 DUP (?)
.code
MOV BX, 0 ; f(0)
MOV DX, 1 ; f(1)
MOV CX, 20 ; Contor
MOV DI, 0 ; Indice in tabloul
bucla:
MOV AX, BX
ADD AX, DX ; f(k) <-- f(k-1) + f(k-2)
MOV FIBO [DI], AX ; Depune rezultat
ADD DI, 2 ; Actualizeaza indice
MOV DX, BX ; f(k-1) devine f(k-2)
MOV BX, AX ; f(k) devine fk-1)
LOOP bucla ; Cicleaza
Instructiunea LOOPZ / LOOPE (Loop While Zero / Equal - Cicleaza cat timp este zero / egal)
Semnificatia este urmatoarea:
daca CX != 0 si ZF = 1, atunci
(IP) <- (IP) + distanta dintre offset-ul curent si
cel tinta
Se decrementeaza deci CX si, daca acesta este diferit de zero si bistabilul ZF este 1 (adica rezultatul ultimei operatii aritmetice a fost zero), se sare la eticheta specificata. De obicei, pentru pozitionarea bistabilului ZF se utilizeaza o instructiune de comparatie.
Exemplul urmator determina primul intreg diferit de zero dintr-un tablou TABL de 100 de intregi.
.code
MOV CX, 100
LEA BX, TABL
MOV SI, -2
next:
ADD SI, 2
CMP WORD PTR [BX][SI], 0
LOOPZ next
JNZ gasit
Daca bistabilul ZF este 0 la iesirea din bucla inseamna ca s-a identificat primul intreg diferit de 0, iar SI contine adresa acestui intreg. In caz contrar, toate cele 100 de elemente ale tabloului sunt nule.
Instructiunea LOOPNZ / LOOPNE (Loop While Not Zero / Not Equal - Cicleaza cat timp este diferit de zero / diferit)
Semnificatia este urmatoarea:
CX <- CX - 1
daca CX != 0 si ZF = 0, atunci
(IP) <- (IP) + distanta dintre offset-ul curent si cel
tinta
Conditia asupra bistabilului ZF este negata conditiei de la LOOPZ / LOOPE. Efectul este ca se cicleaza cat timp rezultatul ultimei operatii aritmetice este diferit de zero, dar nu de mai multe ori cat este continutul initial al lui CX.
De remarcat asemanarile si deosebirile care exista intre instructiunile de ciclare si prefixele de repetare de ia operatii cu siruri (vezi 2.3.2).
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 2948
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved