LAB 9. Instrucţiuni de manipulare a șirurilor
9.1. Instrucţiuni pentru operaţii primitive
Există 7 operaţii primitive specifice șirurilor, suportate încă de la 8086↑, acestea sunt date de instrucţiunile MOVS, LODS, STOS, CMPS, SCAS; INS, OUTS Aceste instrucţiuni operează asupra unui octet (8 biţi) sau cuvânt (16 biţi) din memorie (deci asupra unor locaţii succesive). Începând cu 386↑, acestea au fost suportate și la nivel de dublucuvânt (32 biţi), iar de la modul pe 64 biţi, pentru procesoare Pentium 4↑ sau Core 2↑, sunt suportate chiar şi la nivel de cvadruplucuvânt (64 biţi).
Tipul operanzilor (adică la ce nivel se operează: de byte, de word, de doubleword sau de quadword) poate fi:
- detectat automat de către asamblor prin specificarea operanzilor în mod explicit (la instrucţiunile MOVS, CMPS, SCAS, etc de exemplu o instrucţiune MOVS la nivel de octet va fi automat înlocuită cu MOVSB)
- precizat în mod explicit în mnemonica instrucţiunii (MOVSB, CMPSB, etc);
Distincţia între dimensiunea operanzilor se realizează prin folosirea sufixelor:
B (byte), W (word), D (doubleword), respectiv Q (quadword).
Sintaxa instrucțiunii movs de exemplu poate lua formele:
movs {mem8,16,32,64},{mem8,16,32,64} sau movsb sau movsw sau movsd sau movsq
Adresa din memorie (unde începe şirul) va fi specificată de : ES:DI pt operandul „destinație” şi DS:SI pt operandul „sursă”
Astfel, adresele fiind deja stabilite pentru destinație şi sursă, mai e necesară doar precizarea dimensiunii operanzilor sau numărul de locații afectate - aceasta poate fi: un octet - va fi vizată o singură locație, un cuvânt - vor fi vizate 2 locații, începând de la acele adrese. Dimensiunea operanzilor se va putea deduce fie din operanzii expliciți - byte pt mem8
- word pt mem16
fie din tipul mnemonicii folosite: - byte pt MOVSB, LODSB, STOSB, CMPSB, SCASB - word pt MOVSW, LODSW, STOSW, CMPSW, SCASW
Instrucţiunile pentru şiruri realizează inclusiv actualizarea adreselor, însă acestea nu ştiu să repete operaţia de un număr de ori câte elemente are şirul de prelucrat. Astfel, se folosește combinarea instrucţiunii pt lucrul cu şiruri cu algoritmi de repetare, gen: prefixe de repetare (rep/repe/repz/repne/repnz) sau bucle cu salt condiţionat (cu loopz, loopnz, loope, etc); uneori se poate folosi loop pentru repetarea operației de CX ori.
În mod implicit, la instrucţiunile pe şiruri, se consideră următoarele:
Observații:
Sursa şi destinația sunt implicite:
- perechea de regiştrii DS:SI se foloseşte pentru adresarea sursei; - perechea de regiştrii ES:DI se foloseşte pentru adresarea destinaţiei;
Segmentul implicit ES nu poate fi modificat prin specificarea explicită a unui alt registru segment în instrucţiune (de exemplu DS:DI), dar DS poate fi schimbat.
Şirul poate fi stocat în memorie:
- în sens crescător (de la adrese mai mici -> adrese mai mari) dacă DF=0, mod auto-incrementare: dinspre primul -> înspre ultimul
- în sens descrescător (de la adrese mai mari -> adrese mai mici) dacă DF=1, mod auto-decrementare: dinspre ultimul -> înspre primul
La parcurgerea şirului în sens crescător
=> SI sau/ şi DI vor fi actualizaţi prin incrementare,
iar la parcurgerea şirului în sens descrescător
=> SI sau/ şi DI vor fi actualizaţi prin decrementare;
Numărul de octeţi cu care se incrementează/ decrementează regiştrii SI şi DI este dat de dimensiunea elementelor şirului: d=1 pt octeţi, d=2 pt cuvinte,
9.1.1. Instrucţiunile MOVS şi MOVS B/W
Instrucţiunile de copiere sau transfer (MOVe String) MOVS[-B/W] transferă un octet sau un cuvânt din şirul sursă (adresat de DS:SI în şirul destinaţie (adresat de ES:DI, transfer
urmat de actualizarea adreselor. mod pe 16biți,
mov ES:[DI], DS:[SI] și actualizeazӑ
DI = DI ± d şi SI = SI ± d,
unde operaţia e cu “+” dacă DF=0, respectiv cu ”-“ dacă DF=1,
iar d = {1-octet, 2-cuvânt} Observații: Instrucţiunile MOVS şi MOVS B/W nu afectează flagurile.
9.1.2. Instrucţiunile LODS şi LODS B/W
Instrucţiunile de încărcare a elementelor din şir (LOaD String) LODS[-/B/W] încarcă în „Acc” (AL sau AX), un octet sau un cuvânt (cel de la adresa DS:SI), iar apoi se actualizează adresa pentru a accesa următorul element al şirului.
mod pe 16biți,
mov AL/AX, [DS:SI]
SI = SI ± d,
unde operaţia e cu “+” dacă DF=0, respectiv cu ”-“ dacă DF=1,
iar d = {1-octet, 2-cuvânt} Observații: Instrucţiunile LODS şi LODS B/W nu afectează flagurile.
9.1.3. Instrucţiunile STOS şi STOS B/W
Instrucţiunile de memorare şir (STOre String) STOSB/W încarcă valoarea din AL sau AX în octetul sau cuvântul de la adresa DS:DI, iar apoi se actualizează adresa. mod pe 16biți,
mov [ES:DI], AL/AX
DI = DI ± d,
unde operaţia e cu “+” dacă DF=0, respectiv cu ”-“ dacă DF=1,
iar d = {1-octet, 2-cuvânt } Observații: Instrucţiunile STOS şi STOS B/W nu afectează flagurile. movs, lods, stos dest, sursa cmps, scas sursa, dest
9.1.4. Instrucţiunile CMPS şi CMPS B/W
Instrucţiunile de comparare şir (CoMPare String) CMPSB/W testează egalitatea şirurilor prin comparare element cu element. Se execută o scădere fictivă între octeții,resp.
cuvintele, de la adresele DS:SI şi ES:DI, fără modificarea operanzilor, dar cu poziţionarea tuturor flagurilor. mod pe 16biți,
cmp [DS:SI], [ES:DI] ; rez=[DS:SI] – [ES:DI]-> flag
setează FLAGS şi apoi
DI = DI ± d, SI = SI ± d,
unde operaţia e cu “+” dacă DF=0, respectiv cu ”-“ dacă DF=1,
iar d = {1-octet, 2-cuvânt } Observații: Instrucţiunile CMPS şi CMPS B/W afectează flagurile OF, SF, ZF, AF, PF, CF.
9.1.5. Instrucţiunile SCAS şi SCAS B/W
Instrucţiunile de scanare (SCAn String) SCASB/W testează/ caută un anumit octet sau cuvânt, într-un şir. Se execută diferenţa fictivă dintre AL sau AX şi octetul,resp. cuvântul,
de la adresa DS:DI, fără modificarea operanzilor, dar cu poziţionarea tuturor flagurilor. mod pe 16biți,
cmp AL/AX, [ES:DI] setează FLAGS şi apoi
DI = DI ± d,
unde operaţia e cu “+” dacă DF=0, respectiv cu ”-“ dacă DF=1, iar d = {1-octet, 2-cuvânt}
Observații: Instrucţiunile SCAS şi SCAS B/W afectează flagurile OF, SF, ZF, AF, PF, CF.
9.2. Instrucţiuni cu şiruri pe port
Instrucţiunile INS (Input String) şi OUTS (Output String) (implementate de la procesoarele 80186↑) preiau/ trimit un şir de elemente (octet, word sau doubleword) de la/ la un port de intrare/ieşire. Instrucţiunile INSB/W/D şi OUTSB/W/D nu au operanzi şi sunt formele scurte ale instrucţiunilor INS şi OUTS, furnizând implicit dimensiunea datelor de pe port: octet, cuvânt sau dublucuvânt. Registrul DX în mod implicit este adresa portului, iar destinaţia implicită este dată de perechea de regiştri ES:DI, respectiv DS:SI.
Exemple de instrucţiuni ilegale:
movsb EAX, EBX ; instrucţiunile pe şiruri au operanzii impliciţi, aceştia nu trebuie precizaţi în instrucţiune
Exemple de instrucţiuni legale:
Exemplele care urmează au rolul de a fixa anumite noţiuni ale instrucţiuilor pe şiruri şi de a se însuşi deprinderea lucrului cu acestea. In secţiunile următoare aceste exemple vor fi reluate în cadrul unor exemple de programe complete.
Exemple 9-1.1: În mod pe 16 biți: movsb ; ES:[DI]=DS:[SI]; DI=DI±1, SI=SI±1 (transfer la nivel de byte) movsw ; ES:[DI]=DS:[SI]; DI=DI±2, SI=SI±2 (transfer la nivel de word) Exemple 9-1.2: stosb ; ES:[DI]=AL, DI=DI±1 lodsb ; AL=DS:[SI], SI=SI±1 insb ; ES:[DI]=[DX], DI=DI±1 outsb ; [DX]=DS:[SI], SI=SI±1
Exemplul 9-1.3 Secvenţa următoare defineşte 2 şiruri: unul sursă şi unul destinaţie, poziţionează regiştrii index pe zonele de început ale şirurilor (vor pointa spre primul element din fiecare şir), iar apoi execută instrucţiunea MOVSB: SIRs DB 1,2,3,4,5 ; se def. şirul destinaţie cu 5 elem. octet, iniţilizat cu 1,2,3,4,5 SIRd DB 5 DUP(0) ; se def şirul sursă cu 5 elemente pe octet, neiniţilizat ... lea SI, SIRs ; SI=adresa de început a SIRs = 102h lea DI, SIRd ; DI=adresa de început a SIRd = 107h cld ; DF=0, şirurile vor fi parcurse în sens crescător movsb ; se mută doar primul elem. din şir şi se poziţionează pe cel de-al doillea element din cadrul fiecărui şir Exemplul 9-1.4 Exemplul anterior poate fi rescris fol. instrucţiunile LODSB şi STOSB, iar astfel elementul din şirul sursă este preluat în registrul acumulator şi abia apoi depus în şirul destinaţie. lodsb ; AL = element curent din SIRs stosb ; din AL se depune elementul curent în SIRd Exemplul 9-1.5 Secvenţa următoare verifică în cadrul unui şir cu 10 elemente definite pe octet dacă primul element este egal cu valoarea din registrul AL, prin utilizarea instrucţiunii SCASB: SIRd DB 0,1,2,3,2,4,2,5,2,6 ; se def şirul destinaţie cu 10 elem. pe octet, iniţilizat cu 0,1,2,3,2,4,2,5,2,6 ... mov AL, 2 ; numărul (elementul) de căutat lea DI, SIRd ; DI=adresa de început a SIRd
cld ; DF=0, şirul va fi parcurs în sens crescător scasb ; se verifică egalitatea elem: cel din şir şi cel căutat şi se poziţionează pe următorul elem din şir Exemplul 9-1.6 Exemplul anterior s-ar putea transpune pentru verificarea egalităţii primului element din 2 şiruri prin utilizarea instrucţiunii CMPSB: SIRd DB 0,1,2,3,2,4,2,5,2,6 ; se def şirul destinaţie cu 10 elemente pe octet, iniţilizat cu 0,1,2,3,2,4,2,5,2,6 SIRs DB 0,1,2,3,2,4,2,5,2,6 ; se def şirul sursă cu 10 elemente pe octet, iniţilizat cu 0,1,2,3,2,4,2,5,2,6 ... lea SI, SIRs ; SI=adresa de început a SIRs lea DI, SIRd ; DI=adresa de început a SIRd cld ; DF=0, şirul va fi parcurs în sens crescător cmpsb ; se verifică egalitatea primului element din cele 2 şiruri şi se poziţionează pe următ. elem. din şir Exemplul 9-1.7 insb ; preia un şir de octeţi de pe portul ce are adresa specificată în registrul DX şi îl depune în memorie
; la adresa dată de ES:DI, DI=DI±1 din memorie, de la adresa dată de DS:SI trimite outsw ; un şir de cuvinte pe portul cu adresa specificată în registrul DX, SI=SI±1 Observaţii:
Trebuie acordată atenţie sporită la valorile CX la intrarea în buclă, pentru a evita buclarea de 216ori sau o eventuală buclare infinită (şi nedorită). Cele 2 de mai jos sunt echivalente semantic, dar nu au acelaşi efect ! (Instrucţiunea DEC afectează flagurile O,Z,S,P, dar LOOP nu le afectează. )
LOOP eti dec CX
jnz eti Exemplul 9-2.1 Pentru a realiza copierea unui şir (SIRs) de 5 elemente într-un alt şir (SIRd) se poate pleca de la secvenţa de instrucţiuni din Exemplul 9-1.3 (inserate în culoare mai deschisă în exemplul curent) şi se poate adapta pentru repetarea acţiunii la numărul de elemente al şirului.
Pentru aceasta, va trebui la început să poziţionăm regiştrii index pe zonele de început ale şirurilor (să pointeze spre primul element din fiecare şir), iar apoi pentru fiecare element să execute instrucţiunea MOVSB/W, să decrementeze numărul de elemente pentru care se repetă algoritmul şi să reia algoritmul până când nr. de elemente pentru care se repetă algoritmul a ajuns la zero. Astfel, vom obţine secvenţa:
SIRs DB 1,2,3,4,5 ; se def. şirul destinaţie cu 5 elem. octet, iniţilizat cu 1,2,3,4,5 SIRd DB 5 DUP(0) ; se def şirul sursă cu 5 elemente pe octet, neiniţilizat ... lea SI, SIRs ; SI=adr de început a SIRs lea DI, SIRd ; DI=adr de început a SIRd mov CX,5 ; CX=5 numărul de elemente cld ; DF=0, şirurile vor fi parcurse în sens crescător et: movsb ;eticheta et se fol. pt a asigura revenirea în acest punct dec cx ;după execuţia mosvb (mută element şi
; actualizează adresa), CX=CX-1 jnz et ; dacă încă CX nu a ajuns să fie zero
; (jump if not ZF-> dacă ZF=0, face salt), se reia bucla
Exemplul 9-2.2 Exemplul precedent poate fi rescris folosind instrucţiunile LODSB şi STOSB, iar astfel fiecare element al şirului sursă este preluat în registrul acumulator, şi abia apoi depus în şirul destinaţie. Bucla de repetiţie se va rescrie astfel: et: lodsb ; AL = element curent din SIRs stosb ; din AL se depune elementul curent în SIRd dec cx ; după execuţia mosvb (mutare element şi actualizare adrese), CX=CX-1 jnz et ; dacă încă CX nu a ajuns să fie zero, se reia bucla
Exemplul 9-2.3 Pentru a realiza căutarea (prin scanare) unui anumit caracter într-un şir de elemente va trebui la început să repetăm raţionamentul descris în primul exemplu adaptat la operaţia SCASB: condiţia de repetare nu se mai referă la un anumit număr de elemente, ci la o anumită condiţie (egalitatea a 2 elemente). Astfel, vor interveni flagurile, mai exact ZF care se setează doar în momentul când cei 2 operanzi ce se compară sunt egali. In secvenţa următoare se caută primul element de valoare 2 din acest șir:
SIR DB 0,1,7,3,2,4,2,5,2,6 ; se def şirul destinaţie cu 10 elem. pe octet, lungSIR equ ($-SIRd) ... mov AL, 2 ; numărul (elementul) de căutat lea DI, SIR ; DI=adr de început a SIR mov CX, lungSIR ; CX= nr. de elemente, determinat cu operatorul $ cld ; DF=0, şirul va fi parcurs în sens crescător
et: scasb ; eticheta et se fol. pt a asigura revenirea în acest punct jz gasit ; se verifică egalitatea elementelor (cel din şir cu cel căutat) şi în funcţie de ZF se face salt dec CX jnz et ; dacă s-a găsit,sare la eticheta gasit, altfel ajunge aici şi face salt la et, atât timp cât CX încă nu a ajuns la
; sfârşit, deci reia căutarea pt următorul element din şir mov DI,0 ; dacă elementul nu există în şir, pun 0 în registrul DI jmp exit ; sar la eticheta care duce la sfârşitul programului gasit: dec DI ; din cauză că instrucţ. scasb a actualizat deja adresa pe următorul element al şirului,
; trebuie să ne întoarcem o poziţie înapoi mov BX, DI ; în BX vom avea poziția elementului cӑutat
exit: ... scas AL/AX - ??? DI
Exemplul 9-2.4 Pentru a testa egalitatea a 2 şiruri vor trebui comparate şirurile element cu element, iar dacă înainte de a ajunge la sfârşitul celor 2 şiruri (se pp. că au acelaşi nr de elem.) se întâlneşte o nepotrivire, concluzionăm că şirurile nu sunt egale (şi în registrul DI se va obţine poziţia primei nepotriviri). Astfel, asemănător cu exemplul precedent, vom obţine: SIRd DB 0,1,2,3,2,4,2,5,2,6 ; se def şirul destinaţie cu 10 elemente pe octet, lungSIRd equ ($-SIRd) ; se def. imediat după variabila corespunzătoare SIRs DB 0,1,2,3,2,4,2,5,2,6 ; se def şirul sursă cu 10 elemente pe octet,
; iniţializat cu 0,1,2,3,2,4,2,5,2,6 ... lea SI, SIRs ; SI=adr de început a SIRs
lea DI, SIRd ; DI=adr de început a SIRd mov CX, lungSIRd ; CX= numărul de elemente, determinat cu operatorul $ cld ; DF=0, şirul va fi parcurs în sens crescător et: cmpsb ;eticheta et se fol. pt a asigura revenirea în acest punct jnz nepotrivire ; se verifică egalitatea elementelor din cele 2 şiruri şi
; în funcţie de ZF se face salt dec CX jnz et ;dacă s-a găsit o inegalitate, sare la eticheta nepotrivire, altfel ajunge aici şi
; face salt la et, (doar dacă încă nu s-a ajuns la sfârşitul şirurilor) și deci repetӑ compararea a 2 elemente;
potrivire: call AfisMesaj ; dacă s-a ajuns aici, înseamnă că s-au parcurs şirurile până la sfârşit şi nu s-a găsit nici o nepotrivire, ; deci şirurile sunt egale, astfel că se afişează mesajul corespunzător
nepotrivire: dec DI ; deoarece instrucţ. scasb a actualizat deja adresa pe următ. elem al şirului, ; trebuie să ne întoarcem o poziţie
Exemplul 9-2.5 Secvenţa de buclare din exemplul 9-2.3: et: movsb ; eticheta et se fol. pt a asigura revenirea în acest punct dec CX ; după execuţia mosvb (mută element şi actualizează adresa), CX=CX-1 jnz et ; dacă încă CX nu a ajuns să fie zero (jump if not ZF-> dacă ZF=0, face salt),
; se reia bucla ;se poate înlocui cu: et: movsb loop et ; reg. CX e automat decrementat şi verificat prin folosirea loop
Exemplul 9-2.6 Secvenţa de buclare poate fi rescrisă: et: scasb ; eticheta et se fol. pt a asigura revenirea în acest punct jz gasit ; se verifică egalitatea elementelor (cel din şir cu cel căutat) şi în funcţie de ZF se face salt dec CX jnz et ; dacă s-a găsit,sare la eticheta gasit, altfel ajunge aici şi face salt la et, atât timp cât CX încă nu a ajuns la
; sfârşit, deci reia căutarea pt următ. element din şir ;se poate înlocui cu: et: scasb je gasit loop et ; reg.CX e automat decrementat şi verificat prin folosirea loop Exemplul 9-3.1 Secvenţa de buclare din exemplul 6.2-1: et: movsb ;eticheta et se fol. pt a asigura revenirea în acest punct dec cx ; după execuţia mosvb (mută element şi actualizează adrese), CX=CX-1 jnz et ; dacă încă CX nu a ajuns să fie zero (jump if not ZF-> dacă ZF=0, face salt), se reia bucla ;se poate înlocui cu: rep movsb ; registrul CX este automat decrementat şi verificat prin folosirea prefixului rep.
Exemplul 9-3.2 Secvenţa de buclare din exemplul 6-2.3: et: scasb ;eticheta et se fol. pt a asigura revenirea în acest punct jz gasit ; se verifică egalitatea elementelor (cel din şir cu cel căutat) şi în funcţie de ZF se face salt dec CX jnz et ; dacă s-a găsit,sare la eticheta gasit, altfel ajunge aici şi face salt la et, atât timp cât CX încă nu a ajuns la
; sfârşit, deci reia căutarea pt următ. element din şir mov DI,0 ; dacă elementul nu există în şir, pun 0 în registrul DI jmp exit ; sar la eticheta care duce la sfârşitul programului ;se poate înlocui cu: repnz scasb ; prefixul repnz face ca instrucţ. scasb să se repete până când CX=0 sau până găseşte elementul căutat jcxz exit ; dacă CX a ajuns în 0, am terminat şi nu s-a găsit
9.4. Instrucţiuni pentru control indicatori (flags)
Instrucţiunile pentru controlul indicatorilor sau flagurilor – se folosesc în general atunci când programatorul doreşte să modifice / controleze modul de execuţie al unor instrucţiuni care exploatează acele flaguri (de exemplu direcţia de parcurgere a elementelor octet/ cuvânt, etc la instrucţiunile pe şiruri).
Instrucţiune Efect Instrucţiune Efect
CLC CF=0 STC CF=1
CMC CF=/CF
CLD DF=0 STD DF=1
CLI IF=0 STI IF=1
CLAC ACF=0 (EFLAGS|b18) STAC ACF=1 (EFLAGS|b18)
Sinteza: adresa primului (DF=0)/ ultimului element (DF=1) => este o adresa FAR memorata astfel:
in DS:SI - pentru sirul sursa in ES:DI - pentru sirul destinatie
directia de parcurgere => - indicata de valoarea din flagul DF (0 – CLD - adrese mai mici -> adrese mai mari, 1 – STD - adrese mai mari -> adrese mai mici.) numărul de elemente => cand este nevoie de el, se pune în CX (daca folosim loop sau prefix de repetare)
1. MOVS(B/W): mov ES:[DI], DS:[SI], cu DI = DI ± d şi SI = SI ± d
2. LODS(B/W): mov AL/AX, DS:[SI], cu SI = SI ± d
3. STOS(B/W): mov ES:[DI], AL/AX, cu DI = DI ± d
LODS + STOS = MOVS
4. CMPS(B/W): cmp DS:[SI], ES:[DI] cu DI = DI ± d şi SI = SI ± d si seteaza FLAGS , scade sursa-dest
5. SCAS(B/W): cmp AL/AX, ES:[DI] cu DI = DI ± d si seteaza FLAGS , scade Acc-dest
operaţia e cu “+” dacă DF=0, resp. cu ”-“ dacă DF=1, iar d = {1-octet, 2-cuvânt}
PR9-1. Să se scrie un program care să realizeze copierea unui şir (SIRs) de 5 elemente de tip octet într-un alt şir (SIRd) cu instrucţiuni pe şiruri.
Elementele se vor copia în aceeaşi ordine în şirul destinaţie cum au fost în şirul sursă.
Rezolvare: Se poate folosi instrucţiunea specifică operaţiilor pe şiruri, movsb. Pentru repetarea acţiunii la numărul de elemente al şirului, va trebui la început
să poziţionăm regiştrii index pe zonele de început ale şirurilor (să pointeze spre primul element din fiecare şir), pentru fiecare element să execute instrucţiunea
movsb, iar apoi să decrementeze numărul de elemente de prelucrat până când acest număr devine 0. Astom obţine secvenţa:
org 100h ; p9_01
.data def. şirul sursă cu 5 elemente octet
lung equ $-SIRs
SIRd db lung DUP(0) ; se def şirul destinaţie cu 5 elemente pe octet, neiniţilizat
.code
lea SI, SIRs ; SI=adresa de început a SIRs
lea DI, SIRd ; DI=adresa de început a SIRd
mov CX, lung ; CX=5 numărul de elemente
cld ; DF=0, şirurile vor fi parcurse în sens crescător
et: movsb ; eticheta et se fol. pt a asigura revenirea în acest punct
loop et ; se reia bucla de lung ori
Figura 9-1. Datele problemei PR9-1 (stânga), respectiv PR9-2 (dreapta)
PR9-2. Să se scrie un program care să realizeze copierea unui şir (SIRs) de 5 elemente de tip octet într-un alt şir (SIRd) cu instrucţiuni pe şiruri. Elementele
se vor copia în ordine inversă în şirul destinaţie faţă de cum au fost în şirul sursă.
Rezolvare: Se pot folosi instrucţiunile specifice operaţiilor pe şiruri, movsb.
org 100h ; p9_02
.data
SIRs DB 1,2,3,4,5 ; se def. şirul sursă cu 5 elemente octet
lung equ $-SIRs
SIRd db lung DUP(0) ; se def şirul destinaţie cu 5 elemente pe octet, neiniţilizat
.code
lea SI, SIRs ; SI=adresa de început a SIRs
lea DI, SIRd+lung-1 ; DI=adresa ultimului element din SIRd
mov CX, lung ; CX=5 numărul de elemente
et: cld ; DF=0, şirul SIRs va fi parcurs în sens crescător
lodsb ; încarcă în AL elementul curent din SIRs
std ; DF=1, şirul SIRd va fi parcurs în sens descrescător
stosb ; încarcă din AL în SIRd
loop et ; se reia bucla de lung ori
PR9-3. Se dau două șiruri de câte 5 elemente, reprezentate pe octet, în segmentul de date. Să se genereze un al treilea șir prin interclasarea elementelor
celor două șiruri. Se presupune că cele 2 şiruri sursă au aceeaşi lungime.
Exemplu: SIR1: 1,3,5,7,9
SIR2 : 2,4,6,8,10 => SIR3 va fi 1,2,3,4,5,6,7,8,9,10
Rezolvare: Interclasarea se referă la întrepătrunderea elementelor: astfel, în şirul destinaţie se va depune un element din primul șir, apoi un element din al
doilea şir, apoi iar un element din primul şir, şi tot aşa. Astfel, se depun mai întâi elementele din șirul 1 în șirul 3, pe pozițiile impare; după terminarea
elementelor din primul şir, se depun elementele din șirul 2 în șirul 3, în pozițiile pare.
org 100h ; p9_03
.data
SIR1 DB 1,3,5,7,9
SIR2 DB 2,4,6,8,10
lung equ $-SIR2
SIR3 db lung*2 DUP(0)
.code ; se depun elementele din șirul 1 în șirul 3:
mov CX, lung
mov SI, offset sir1 ; şirul sursă1
mov DI, offset sir3 ; şirul destinație
iar1: movsb
inc DI ; o dată DI se incrementează automat de la movsb,
; se mai incrementează încă o dată, pt că
loop iar1 ; elementele se pun din două în două poziții
; se depun elementele din șirul 2 în șirul 3:
mov CX, lung
mov SI, offset sir2 ; şirul sursă2
mov DI, offset sir3 ; şirul destinație
inc DI ; pentru a începe de la poziția a doua
iar2: movsb ; o dată DI se incrementează automat de la movsb,
inc DI ; se mai incrementează încă o dată, pt că
loop iar2 ; elementele se pun din două în două poziții
PR9-4. Se dă un şir de octeţi interpretaţi ca numere fără semn. Să se scrie o secvenţă de program care să găsească maximul dintr-un şir atât folosind
instrucţiuni pe şiruri cât şi fără utilizarea acestora.
Rezolvare: ; cu jge găsim maximul pt numere cu semn
; cu jae găsim maximul pt numere fără semn
Fără instrucţiuni pe şiruri Cu instrucţiuni pe şiruri
org 100h ; p9_04_a
.data
sir db 4h, 0FFh,3h,0FEh,5h,7h,6h
; 4,-1,3,-2,5,7,6
lung EQU $-sir
max db ?
index dw 0
.code
mov SI, 0 ; index pt parcurgere
mov CX, lung-1 ; nr de comparări
mov AL, sir[0] ; AL=sir[0]
start:
inc SI ; poziţionare pe sir[1]
cmp AL, sir[SI] ; cmp sir[0] cu sir[1]
jae et1 ; dacă e > trece la următ
mov AL, sir[SI] ; altfel, înlocuieşte
mov BX, SI ; păstrează indexul
et1:
loop start ; reia de lung-1 ori
mov max, AL ; depune maximul
mov index, BX ; şi indexul lui
ret
org 100h ; p9_04_b
.data
sir db 4h, 0FFh,3h,0FEh,5h,7h,6h
; 4,-1,3,-2,5,7,6
lung EQU $-sir
max db ? ; maximul gasit
index db ? ; ce indexul maximului
adresa dw ? ; adresa maximului
.code
cld ; DF=0
mov SI, offset sir ; SI=offset sir
mov CX, lung-1 ; nr de comparări
lodsb ; AL=sir[0]
mov max, AL ; max=sir[0]
mov BX, offset sir+1; poate fi primul
start:
lodsb ; AL=sir[1]
cmp max, AL ; cmp sir[0] cu sir[1]
jae et1 ; dacă e > trece la următ
mov max, AL ; altfel, înlocuieşte
mov BX, SI ; păstrează offsetul
et1:
loop start ; reia de lung-1 ori
dec BX ; merge înapoi o poz.
mov adresa, BX ; calcul index
sub BX, offset sir
mov index, BL
ret
Figura 9-2. Datele problemei PR9-3
Figura 9-3. Datele problemei PR9-4
PR9-5 (de analizat). Se dau 2 șiruri de câte 8 elemente fiecare, reprezentate pe octet, în segmentul de date. a) Să se verifice dacă cele două șiruri sunt
identice (ca valori). Să se rezolve atât folosind instrucţiuni pe şiruri cât şi fără utilizarea acestora.
b) Să se realizeze şi un program de tip EXE, nu COM. Rezolvare:
a) Se realizează compararea șirurilor, element cu element, cât timp elementele sunt egale; dacă am ajuns la sfârşitul şirurilor şi nu s-a găsit o pereche de
elemente diferite, atunci şirurile sunt identice. Pentru rezolvare, s-a folosit şablon de program de tip COM, acesta având specific faptul că toate segmentele
sunt înghesuite într-o singură zonă de maxim 64k şi toţi regiştrii segment încep la aceeaşi adresă. Astfel, şirurile date de indecşii SI şi DI se vor găsi în
acelaşi segment (nu a fost nevoie de poziţionarea lui ES şi DS pe aceeaşi zonă).
Fără instrucţiuni pe şiruri
org 100h ; p9_05_a
.data
sir1 db 1,2,3,4,5,6,7,8
sir2 db 1,2,3,4,5,7,7,8
lung equ $-sir2
var db 0 ;variabilă indicator:
; var=1 => șiruri identice
; var=0 => șiruri diferite
Cu instrucţiuni pe şiruri
org 100h ; p9_05_b
.data
sir1 db 1,2,3,4,5,6,7,9
sir2 db 1,2,3,4,5,6,7,9
lung equ $-sir2
var db 0 ;variabilă indicator:
; var=1 => șiruri identice
; var=0 => șiruri diferite
.code
mov CX, lung
mov SI, offset sir1
;mov AX, seg sir1
;mov DS, AX
mov DI, offset sir2
;mov AX, seg sir2
;mov ES, AX
iar: mov AL, [SI]
mov BL, [DI]
inc SI
inc DI
cmp AL, BL
jne sf
loop iar
mov var, 1 ; șiruri identice
sf: ret
.code
mov CX, lung
mov SI, offset sir1
;mov AX, seg sir1
;mov DS, AX
mov DI, offset sir2
;mov AX, seg sir2
;mov ES, AX
iar:
cmpsb
jne sf
loop iar
mov var,1 ; șiruri identice
sf: ret
Figura 9-4. Datele problemei PR9-5
Următoarele (secvenţe de ) instrucţiuni sunt echivalente:
iar:
cmpsb
jne sf
repe cmpsb
b) Un program EXE trebuie să respecte un anumit format pentru a funcţiona în simulator, aşa cum se poate observa mai jos:
; program cu mai multe segmente (program de tip EXE) ; p9_05_c
data segment ; segment de date
sir1 db 1,2,3,4,8,6,7,9
sir2 db 1,2,3,4,8,6,7,9
lung equ $-sir2
var db 0
ends
stack segment ; segment de stivă
dw 128 dup(0)
ends
code segment ; segment de cod
start:
; setarea regiştrilor segment pe aceeaşi zonă a datelor
mov ax, data
mov ds, ax
mov es, ax
mov CX, lung
mov SI, offset sir1
mov AX, seg sir1
mov DS, AX
mov DI, offset sir2
mov AX, seg sir2
mov ES, AX
iar:
cmpsb
jne sf
loop iar
mov var,1 ; şiruri identice
sf:
mov ax, 4c00h ; exit
int 21h
ends
end start ; punctul de intrare în program e start
PR9-6. Să se scrie o secvenţă de program prin care să se caute un anumit caracter într-un şir de caractere. Să se rezolve atât folosind instrucţiuni pe şiruri
cât şi fără utilizarea acestora. Rezolvare:
Pentru a realiza căutarea (prin scanare) unui anumit caracter într-un şir de elemente, va trebui să repetăm instrucţiunea scasb: condiţia de repetare nu se
referă la un anumit număr de elemente, ci la o anumită condiţie (egalitatea a 2 elemente: unul din AL şi unul din şir). Astfel, vor interveni flagurile, mai exact
ZF care se setează doar în momentul când cei 2 operanzi ce se compară sunt egali.
Fără instrucţiuni pe şiruri Cu instrucţiuni pe şiruri
org 100h ; p9_06_a
.data
sirCar db 'Programare in limbaj asm'
lung equ $-sirCar ; lungimea şirului
car db 's' ; caracterul de cautat;
mesA db "caracterul a fost gasit", '$'
mesF db "caracterul NU a fost gasit", '$'
.code
mov SI, offset sirCar
mov CL, lung
mov AL, car
; caracterul de căutat este în AL
repeta: cmp AL, [SI]
je gasit
inc SI ; trece la următorul
loop repeta ; caută până la sfârşit
mov DX, offset mesF
jmp afis
gasit: mov DX, offset mesA
afis: mov AH,09h ; afişare mesaj
int 21h
ret
org 100h ; p9_06_b
.data
sirCar db 'Programare in limbaj asm'
lung equ $-sirCar ; lungimea şirului
car db 's' ; caracterul de cautat;
mesA db "caracterul a fost gasit", '$'
mesF db "caracterul NU a fost gasit", '$'
.code
cld ; DF=0
mov DI, offset sirCar
mov CL, lung
mov AL, car
; caracterul de căutat este în AL
repeta: scasb ; scasb foloseşte DI
je gasit ; sau jz
; inc DI ; se realiz. automat.
loop repeta ; caută până la sfârşit
mov DX, offset mesF
jmp afis
gasit: mov DX, offset mesA
afis: mov AH,09h ; afişare mesaj
int 21h
ret
Figura 9-5. Afişarea mesajului la problema PR7-6 pentru caracterul căutat ‚s’
PR9-7. Să se scrie o secvenţă de program prin care să se înlocuiască elementele nule dintr-un șir cu caracterul '*'.
Exemplu: sir : 1, 2, 0, 5, 8, 0, 10, 12, 0 => sir: 1, 2, '*', 5, 8, '*', 10, 12,'*' Rezolvare:
Se pune 0 în registrul AL și se compară elementele șirului cu AL, prin scasb.
org 100h ; p9_07
.data
sir db 1, 2, 0, 5, 8, 0, 10, 12, 0
lung equ $-sir
.code
cld
mov DI, offset sir
mov AL, 0
mov CX, lung
iar: scasb
jne et1
mov ES:[DI-1], '*' ; dacă am găsit un element egal cu 0, se înlocuieşte
et1: loop iar
PR9-8. Să se scrie o secvenţă de program prin care să se indice dacă un şir de 8 elemente conţine un subşir de 3 elemente.
Exemplu: SIR: 1,2,3,4,5,6,7,8
SUBSIR: 4,5,6 => SIR contine SUBSIR (var=1)
SUBSIR: 4,6,8 => SIR NU contine SUBSIR (var=0)
Rezolvare: Se caută mereu câte 3 elemente ale subşirului în şirul iniţial, începând de la poziţia dată de registrul BX (BX=0,1,2...5). Dacă se găsesc toate
cele 3 elemente, căutarea se opreşte; dacă nu, algoritmul continuă în următoarea fereastră de căutare (se compară cât timp acestea sunt egale).
org 100h ; p9_08
.data
sir db 1,2,3,4,5,6,7,8
lung equ $-sir
subsir db 4,5,8
var db 0
.code
cld
mov BX,0
iar: mov CX,3 ; se realizează 3 comparări cu elem. subşirului
mov SI, offset sir
add SI, BX ; compararea începe în şir de la poziţia SI+BX
mov DI,offset subsir
repe cmpsb ; se compară elementele din şir cu elem. din subşir
jne et1 ; dacă elem. sunt diferite, trece la următ. fereastră de căutare
mov var,1 ; aici s-au găsit în şirul iniţial toate elementele din subşir
jmp sfarsit ; iese din program
et1: inc BX ; trece la următoarea fereastră de căutare
cmp BX, lung-3 ; se verifică dacă s-a ajuns la capăt
jle iar ; dacă nu, se reia căutarea
sfarsit: ret
Figura 9-6. Rezultatele obţinute la problema PR9-8
PR9-9. Se dau 2 şiruri de câte 8 elemente, reprezentate pe octet, în segmentul de date. Să se determine câte elemente din şirul 2 nu se regăsesc în şirul
1.
Rezolvare: Se ia pe rând câte un elem. din şirul S2. Acesta se compară cu toate elementele din şirul S1; dacă acesta nu se găseşte în şirul S1, se
contabilizează într-un contor. Dacă acesta a fost găsit, se trece la următorul element din şirul S2. Pentru implementare, elementul din şirul S2 se depune în
registrul AL, iar apoi se compară cu elementele din şirul S1 prin instucţiunea scasb cu prefixul de repetare repne (astfel compararea cu elementele din sirul
S1 decurge automat, cat timp elementele sunt diferite);
Instrucţiunea prefixată repne scasb se opreşte:
(a) fie atunci când elementul din AL s-a găsit în şirul S1,
(b) fie atunci când am ajuns la sfârsitul şirului S1, fără a găsi elementul din AL;
- în cazul (a), se trece la următorul element din şirul S2, care se depune în AL;
- în cazul (b), se contabilizează elementul găsit.
org 100h ; p9_09
.data
s1 db 1,2,3,4,5,6,7,8
lung equ $-s1
s2 db 1,9,12,4,7,0,10,8
nr db 0 ; aici se vor contabiliza elementele din s2 care nu apar în s1
.code
mov CX, lung
mov SI, offset s2 ; sursa
iar: mov DI,offset s1 ; destinaţia
lodsb ; se încarcă elementul din s1 în reg. AL
push CX ; se salvează CX din ciclul loop, pentru a putea
; face comparările dintre elem. din AL si elem. şirului s1
mov CX, lung ; se vor face maxim lung comparări
repne scasb ; se compară elem. din AL cu toate elem. din s1,
; (cât timp elem. sunt diferite)
je next ; elem. din AL a fost gasit in sirul s1; nu il contabilizăm
inc nr ; aici: dacă toate elem. din s1 au fost diferite de elem. din AL
; s-a contabilizat nr de elem. în variabila nr
next: pop cx ; se reface CX din cadrul buclei loop
loop iar ; se trece la următorul element din şirul s2
PR9-10. Se dau două șiruri de câte 8 elemente pe octet (cu semn) în segmentul de date. Să se compare cele două șiruri element cu element, iar valoare
maximă de la fiecare comparare să se pună într-un al treilea șir.
Exemplu: SIR1: 1,5,7,20,...
SIR2: 2,3,9,10,.... => SIR3: 2,5,9,20,... Rezolvare:
Fără instrucţiuni pe şiruri Cu instrucţiuni pe şiruri
org 100h ; p9_10_a
.data
sir1 db 1, 5, 7, 20, 8, 32, 7, 21
lung equ $-sir1
sir2 db 2, 3, 9, 10, 20, 5, 13, 72
sir3 db lung dup(0)
.code
mov SI, 0
mov CX, lung
start:
mov AL, sir1[SI]
mov BL, sir2[SI]
cmp AL, BL
jl et1
; AL > BL; se pune val. din AL în șir3:
mov sir3[SI], AL
jmp et2
et1:
; AL < BL; se pune val. din BL în șir3:
mov sir3[SI], BL
et2: inc SI
loop start
org 100h ; p9_10_b
.data
sir1 db 1, 5, 7, 20, 8, 32, 7, 21
lung equ $-sir1
sir2 db 2, 3, 9, 10, 20, 5, 13, 72
sir3 db lung dup(0)
.code
lea SI, sir1
lea di, sir2
mov CX, lung
lea BX, sir3
cld
start:
cmpsb
jl et1
; AL > BL; se pune val. din AL în șir3:
mov AL, [SI-1]
mov [BX], AL
jmp et2
et1:
; AL < BL; se pune val. din BL în șir3:
mov AL, [DI-1]
mov [BX], AL
et2: inc BX
loop start
PR9-11. Se dă un şir de 4 dublucuvinte în memorie. Să se scrie o secvenţă de program prin care să se adune octeţii de rang 2 ai acestor dubluvinte.
Exemplu: sir: 01234567h, 89ABCDEFh, 13579BDFh, 02468ACEh
se va aduna 23h + 0ABh + 57h + 46h = 016Bh Rezolvare:
org 100h ; p9_11
.data
sir dd 01234567h, 89ABCDEFh, 13579BDFh, 02468ACEh
nrElem equ ($-sir)/4
suma dw ?
.code
mov BX, 0 ; suma se va depune temporar în BX
lea SI, sir
mov CX, nrElem
iar: lodsw ; se preiau octeţii 1,0 din fiecare dublucuv
lodsb ; se preia octetul 2
mov AH, 0
add BX, AX ; se adună la BL cu tot cu eventuala depăşire
lodsb ; se preia şi octetul 3, dar nu se face nimic cu el
loop iar
mov suma, BX
ret
Figura 9-7. Rezultatele obţinute la problema PR9-11