Scrigroup - Documente si articole

     

HomeDocumenteUploadResurseAlte limbi doc
AccessAdobe photoshopAlgoritmiAutocadBaze de dateC
C sharpCalculatoareCorel drawDot netExcelFox pro
FrontpageHardwareHtmlInternetJavaLinux
MatlabMs dosPascalPhpPower pointRetele calculatoare
SqlTutorialsWebdesignWindowsWordXml

Instructiuni de apel de procedura si de salt (CALL, RET, JMP)

calculatoare



+ Font mai mare | - Font mai mic



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 SHORT PTR tinta

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.

JMP / CALL de tip direct

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:

Jump (Salt) on (pe) <Interpretare>

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 AL, 0FFH

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.

Instructiunea LOOP

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

JNZ start_bucla

JMP end_bucla

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:

CX <- CX - 1

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



DISTRIBUIE DOCUMENTUL

Comentarii


Vizualizari: 2948
Importanta: rank

Comenteaza documentul:

Te rugam sa te autentifici sau sa iti faci cont pentru a putea comenta

Creaza cont nou

Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved