Sunteți pe pagina 1din 5

Laboratorul 4. Rezolvări.

Laboratorul 4. Rezolvări.

Exemplu:
Să se calculeze în registrul AX lungimea unui șir de caractere din memoria de date:

include \masm32\include64\masm64rt.inc

.data
string db "Sir de caractere!", 0 ; declarare sir de caractere

.code
main proc ; main() {
xor ax, ax ; AX = 0 (initializare contor)
lea rdi, string ; RDI = pointer la sirul de caractere "string"
@@: ; eticheta anonima pentru inceputul buclei WHILE
cmp byte ptr [rdi], 0 ; compar caracterul curent din sir cu \0
jz @F ; daca ==0 parasesc bucla WHILE (salt la @@ jos)
inc ax ; daca nu: AX++ (incrementez contor)
inc rdi ; RDI++ (si actualizez pointerul la sir)
jmp @B ; reiau bucla WHILE (salt la @@ anterior/sus)
@@: ; eticheta anonima pentru sfarsitul buclei WHILE
invoke ExitProcess, 0 ; invoke ExitProcess API
ret ; revenire din procedura main()
main endp ; }
end

1. Încărcați programul compilat al exemplului de mai sus în Visual Studio și verificați


funcționarea acestuia (rulați pas cu pas).
Rezolvare:

Surpriză, programul merge! AX = 17 la final (pentru sirul "Sir de caractere!").

2. Implementați programul din exemplul de mai sus folosind combinația de instrucțiuni


REPNE SCANSB.
Rezolvare:

include \masm32\include64\masm64rt.inc

.data
string db "Sir de caractere!", 0

.code
main proc
xor al, al ; AL = 0 (terminatorul de sir)
xor rcx, rcx ; RCX = 0
not rcx ; RCX = !RCX = -1 = nr maxim reprezentabil pe 64 biti
; instr. REPxx repeta instr. compusa de RCX ori
lea rdi, string ; RDI = pointer la sirul de caractere

1
Programare în limbaj de asamblare (PLA)

cld ; CLD (Clear Direction Flag) => DF = 0


; DF = 0 => instructiunile REPxx vor incrementa RDI/RSI
repne scasb ; REPNE: while ((--RCX)!=0)
; SCASB: if (AL==[RDI++]) break
; => RCX (initializat cu -1) va fi decrementat cu numarul de caractere al
; sirului (inclusiv terminatorul de sir 0) => RCX = -(strlen()+2) = -strlen()-2
inc rcx ; RCX++ => RCX = -strlen()+1
not rcx ; RCX = !RCX = -RCX-1 = strlen()

mov rax, rcx ; in RAX avem numarul de caractere al sirului


invoke ExitProcess, 0 ; invoke ExitProcess API
ret
main endp
end

3. Realizați un program care afișează în ordine inversă un sir de caractere declarat în zona
de date.
Rezolvare:

include \masm32\include64\masm64rt.inc

.data
str1 db "Sir de caractere!", 0 ; sirul de caractere initial
dim equ $-str1 ; calcul dimensiune ocupata de "str1"
str2 db dim DUP(?) ; un sir de aceeasi dimensiune ca "str1"
crlf db 13, 10, 0 ; sirul ce contine caracterele
; CR+LF echivalente cu "\n" din C
.code
main proc
; Calculam dimensiunea sirului str1
xor al, al ; AL = 0 (terminatorul de sir)
xor rcx, rcx ; RCX = 0
not rcx ; RCX = !RCX = -1 = nr maxim reprezentabil pe 64 biti
; instr. REPxx repeta instr. compusa de RCX ori
lea rdi, str1 ; RDI = pointer la sirul de caractere
cld ; CLD (Clear Direction Flag) => DF = 0
; DF=0 => instructiunile REPxx vor incrementa RDI/RSI
repne scasb ; REPNE: while ((--RCX)!=0)
; SCASB: if (AL==[RDI++]) break
; => RCX (initializat cu -1) va fi decrementat cu numarul de caractere al
; sirului (inclusiv terminatorul de sir 0) => RCX = -(strlen()+2) = -strlen()-2
inc rcx ; RCX++ => RCX = -strlen()+1
not rcx ; RCX = !RCX = -RCX-1 = strlen()
; Dupa "repne scasb", [RDI] este pozitionat pe caracterul de dupa teminatorul
; de sir => ultimul caracter al sirului este la adresa [RDI-2]
sub rdi, 2
mov rsi, rdi ; [RSI] = pointer la ultimul caracter din "str1"
lea rdi, str2 ; [RDI] = pointer la primul caracter din "str2"
@@:
std ; STD (Set Direction Flag) => DF = 1
; DF = 1 => instr. LODSx vor decrementa RSI

2
Laboratorul 4. Rezolvări.

lodsb ; AL = [RSI--]
cld ; DF = 0 => instr. STOSx vor incrementa RDI
stosb ; [RDI++] = AL
loop @B ; bucla LOOP se va executa de RCX=strlen() ori
mov byte ptr [rdi], 0 ; adaugam terminatorul de sir

invoke StdOut, addr str1 ; Afisam sirul "str1"


invoke StdOut, addr crlf ; Afisam sirul "crlf" = "\n"
invoke StdOut, addr str2 ; Afisam sirul "str2"
invoke ExitProcess, 0 ; invoke ExitProcess API
ret
main endp
end

4. Realizați un program care convertește literele mici în majuscule într-un sir de caractere
declarat în memorie. Afișați rezultatul.
Rezolvare:

include \masm32\include64\masm64rt.inc

.data
sir db "Sir de caractere de Test 123!", 0 ; sirul de caractere initial
crlf db 13, 10, 0 ; sirul CRLF = "\n"

.code
main proc
invoke StdOut, addr sir ; Afisam sirul initial
invoke StdOut, addr crlf ; Afisam "\n"
lea rsi, sir ; RSI = adresa sirului de caractere
WhileStart: ; eticheta de start a buclei WHILE
mov al, [rsi] ; AL = [RSI] = caracterul curent
test al, al ; compar AL cu 0 (terminatorul de sir)
jz WhileEnd ; daca am ajuns la \0 iesim din WHILE
cmp al, 'a' ; compar AL cu caracterul 'a'
jl @F ; AL<'a' (fara semn) => salt la @@ de mai jos
cmp al, 'z' ; compar AL cu caracterul 'z'
ja @F ; AL>'z' (fara semn) => salt la @@ de mai jos
sub al, 'a'-'A' ; altfel (AL intre 'a'-'z') conv. la majuscula
mov [rsi], al ; [RSI] = AL copiem caracterul modificat in sir
@@:
inc rsi ; RSI++ actualizam pointerul la sir
jmp WhileStart ; salt la inceputul buclei WHILE
WhileEnd: ; eticheta de sfarsit a buclei WHILE
invoke StdOut, addr sir ; Afisam sirul modificat
invoke ExitProcess, 0 ; invoke ExitProcess API
ret
main endp
end

5. Realizați un program care convertește vocalele dintr-un sir de caractere în litere mari și
consoanele în litere mici. Afișați rezultatul.

3
Programare în limbaj de asamblare (PLA)

Rezolvare:

include \masm32\include64\masm64rt.inc

.data
sir db "My name is Bond, James Bond! AKA 007!", 0 ; sirul de caractere
crlf db 13, 10, 0 ; CR+FL = "\n"

.code
main proc
invoke StdOut, addr sir ; afisam sirul initial
invoke StdOut, addr crlf ; afisam "\n"
lea rsi, sir ; RSI = adresa sirului de caractere
WhileStart: ; eticheta de start a buclei WHILE
mov al, [rsi] ; AL = [RSI] = caracterul curent
test al, al ; compar AL cu 0 (terminatorul de sir)
jz WhileEnd ; daca ma ajuns la \0 => iesim din WHILE
cmp al, 'a' ; daca AL este vocala 'a'

je @F ; atunci sar la @@ de mai jos


cmp al, 'e' ; daca AL este vocala 'e'
je @F ; atunci sar la @@ de mai jos
cmp al, 'i' ; daca AL este vocala 'i'
je @F ; atunci sar la @@ de mai jos
cmp al, 'o' ; daca AL este vocala 'o'
je @F ; atunci sar la @@ de mai jos
cmp al, 'u' ; daca AL este vocala 'u'
je @F ; atunci sar la @@ de mai jos
jmp TestConsoane ; altfel nu este vocala mica si sar la "TestConsoane"
@@: ; atunci este vocala "minuscula"
sub al, 'a'-'A' ; convertesc AL la majuscula
mov [rsi], al ; actualizez caracterul in sir
jmp @F ; apoi sar la @@ de mai jos peste testul de consoane
TestConsoane:
cmp al, 'A' ; compar AL cu caracterul 'A'
jb @F ; AL<'A' (comp. fara semn) => salt la @@ de mai jos
cmp al, 'Z' ; compar AL cu caracterul 'Z'
ja @F ; AL>'Z' (comp. fara semn) => salt la @@ de mai jos
cmp al, 'A' ; daca AL este vocala 'A'
je @F ; atunci sar la @@ de mai jos
cmp al, 'E' ; daca AL este vocala 'E'
je @F ; atunci sar la @@ de mai jos
cmp al, 'I' ; daca AL este vocala 'I'
je @F ; atunci sar la @@ de mai jos
cmp al, 'O' ; daca AL este vocala 'O'
je @F ; atunci sar la @@ de mai jos
cmp al, 'U' ; daca AL este vocala 'U'
je @F ; atunci sar la @@ de mai jos
; altfel este majuscula consoana (diferita de vocala)
add al, 'a'-'A' ; convertim caracterul din majuscula in "minuscula"
mov [rsi], al ; copiem caracterul modificat in sir

4
Laboratorul 4. Rezolvări.

@@:
inc rsi ; RSI++ (actualizam pointerul la sir)
jmp WhileStart ; salt la inceputul buclei WHILE
WhileEnd: ; eticheta de sfarsit a buclei WHILE
invoke StdOut, addr sir ; afisam sirul modificat
invoke ExitProcess, 0 ; invoke ExitProcess API
ret
main endp
end

S-ar putea să vă placă și