Sunteți pe pagina 1din 8

Laboratorul 5. Rezolvări.

Laboratorul 5. Rezolvări.

Exemplu:
Fie un program care conține procedura de afișare recursivă cu parametrul (numărul de
afișat) transmis prin registrul EAX:
1 include \masm32\include64\masm64rt.inc
2
3 .data
4 cifra db ?, 0
5
6 .code
7 main proc
8 mov eax, 123456 ; incarcare numar de afisat
9 call PutU32 ; apel procedura
10 invoke ExitProcess, 0 ; invoke ExitProcess API
11 ret
12 main endp
13
14 PutU32 proc ; parametru: numar intreg fara semn pe 32 biti in EAX
15 test eax, eax ; EAX == 0 (conditia de iesire)
16 jz @F ; daca EAX == 0 salt la @@ de mai jos
17 xor edx, edx ; EDX = 0
18 mov ecx, 10 ; ECX = 10
19 div ecx ; EDX:EAX / baza (EAX=cat, EDX = rest)
20 push dx ; DX (rest) -> stiva
21 call PutU32 ; apel recursiv
22 pop dx ; DX <- stiva
23 add dl, '0' ; conversie cifra din DL in caracter ASCII
24 mov cifra, dl ; salvam in sirul "cifra", cifra din numar
25 invoke StdOut, addr cifra
26 @@:
27 ret
28 PutU32 EndP
29 end

Probleme propuse:
1. Încărcați programul de mai sus și modificați numărul din EAX pentru e verifica execuția
programului și afișarea corectă a numărului. Ce se întâmplă dacă numărul din EAX
(numărul de afișat) este 0 (zero)?
Rezultatul rulării programului: Procedura funcționează corect exceptând cazul când numărul
de afișat (valoarea din EAX) este 0 (zero), situație în care nu se afișează nimic.
2. Modificați procedura PutU astfel încât să afișeze corect numărul 0.
Rezolvare:
În procedura PutU din exemplul de mai sus condiția de revenire din recursivitate este
incorectă. Varianta din exemplu părăsește procedura în cazul în care valoarea din EAX este 0.
Condiția corectă ar fi: „câtul împărțirii la baza de numerație să fie 0”. În acest caz liniile de

1
Programare în limbaj de asamblare (PLA)

cod 17, 18, 19 (împărțirea la baza de numerație) trebuie mutate înainte de linia 15 test eax, eax
iar eticheta pentru saltul de la linia 21, aflată pe linia 26 trebuie mutată între de liniile 22 și 23,
(după pop dx) astfel încât în cazul în care EAX este 0 să se afișeze corect caracterul '0' pe ecran.
În blocul de tip IF în care condiția de intrare în recursivitate (câtul este 0) ne va rămâne doar
salvarea pe stivă a restului, apelul recursiv și refacerea câtului de pe stivă. Codul rezultat va fi:
include \masm32\include64\masm64rt.inc

.data
cifra db ?, 0

.code
main proc
mov eax, 123456 ; incarcare numar de afisat
call PutU32 ; apel procedura
invoke ExitProcess, 0 ; invoke ExitProcess API
ret
main endp

PutU32 proc ; parametru: numar intreg fara semn pe 32 biti in EAX


xor edx, edx ; EDX = 0 (partea HIGH a deimpartitului)
mov ecx, 10 ; ECX = 10 (baza)
div ecx ; EDX:EAX / baza (EAX=cat, EDX = rest)
test eax, eax ; EAX == 0 (conditia de iesire)
jz @F ; daca EAX == 0 salt la @@ de mai jos

push dx ; DX (rest) -> stiva


call PutU32 ; apel recursiv
pop dx ; DX <- stiva (resturile in ordine inversa)
@@:
add dl, '0' ; conversie cifra din DL in caracter ASCII
mov cifra, dl ; salvam in sirul "cifra", cifra din numar
invoke StdOut, addr cifra
ret
PutU32 EndP
end

3. Pe baza procedurii PutU32 creați o procedură PutH32 care să afișeze un numărul întreg
fără semn în hexazecimal.
Rezolvarea 1:
include \masm32\include64\masm64rt.inc

.data
cifra db ?, 0

.code
main proc
mov eax, 0C1E2F3Ah ; incarcare numar de afisat
call PutH32 ; apel procedura
invoke ExitProcess, 0 ; invoke ExitProcess API

2
Laboratorul 5. Rezolvări.

ret
main endp

PutH32 proc ; parametru: numar intreg fara semn pe 32 biti in EAX


xor edx, edx ; EDX = 0 (partea HIGH a deimpartitului)
mov ecx, 16 ; ECX = 16 (baza de numeratie de afisat)
div ecx ; EDX:EAX / baza (EAX=cat, EDX = rest)
test eax, eax ; EAX == 0 (conditia de iesire)
jz @F ; daca EAX == 0 salt la @@ de mai jos
push dx ; DX (rest) -> stiva
call PutH32 ; apel recursiv
pop dx ; DX <- stiva (resturile in ordine inversa)
@@:
add dl, '0' ; conversie cifra din DL in caracter ASCII
cmp dl, '9' ; compensam pentru ciferele mai mari ca '9'
jna @F ; daca DL<='9' (fara semn) skip la @@
add dl, 'A'-('9'+1) ; altfel transformam DL='9'+x in 'A'+x, x=1..5
@@:
mov cifra, dl ; salvam in sirul "cifra", cifra din numar
invoke StdOut, addr cifra
ret
PutH32 EndP
end

Rezolvarea 2: (fără recursivitate)


include \masm32\include64\masm64rt.inc

.data
octet db ?, ?, 0 ; sir din 2 caractere pt afisarea unui octet in hexa

.code
main proc
mov eax, 1F23C456h ; EAX = nr de afisat
call PutH32 ; apel procedura
invoke ExitProcess, 0 ; invoke ExitProcess API
ret
main endp

PutH32 proc ; parametru: numar intreg fara semn pe 32 biti in EAX


push rbx ; salvare registri nevolatili utilizati
push rdi
mov ebx, eax ; incarcare in RBX a paramentrului din RAX
mov octet, '0' ; salvam primul caracter "octet", caracterul '0'
mov octet+1, 'x' ; in caracterul al doilea din "octet", 'x'
invoke StdOut, addr octet ; afisam sirul
bswap ebx ; Byte Swap = inversarea octetilor numarului
mov di, 4 ; contor octeti (nr pe 32 biti au 4 octeti)
PutU32_repeat:
mov al, bl ; AL = octetul cel mai nesemnificativ din EBX
shr ebx, 8 ; R15 = R15 >> 8 (deplasae cu un octet la dreapta)

3
Programare în limbaj de asamblare (PLA)

mov ah, al ; AH = CL
and al, 0Fh ; pastram doar partea LOW (low nibble)
add al, '0' ; conversie cifra din AL in caracter ASCII
cmp al, '9' ; comparam AL cu '9'
jna @F ; nu este mai mare sarim
add al, 'A'-'9'-1 ; altfel compensam pt ciferele hexa 'A'..'F'
@@:
shr ah, 4 ; pastram doar partea HIGH (high nibble)
add ah, '0' ; conversie cifra din AH in caracter ASCII
cmp ah, '9' ; comparam AH cu '9'
jna @F ; nu este mai mare sarim
add ah, 'A'-'9'-1 ; altfel compensam pt ciferele hexa 'A'..'F'
@@:
mov octet, ah ; salvam in sirul "octet", cifra HIGH
mov octet+1, al ; salvam in sirul "octet", cifra LOW
invoke StdOut, addr octet ; afisam sirul
dec di ; decrementare contor DI
test di, di ; testam contorul DI
jnz PutU32_repeat ; daca este != repetam bucla

pop rdi ; refacere registri nevolatili utilizati


pop rbx
ret
PutH32 EndP
end

4. Pe baza procedurii PutU32 creați o procedură PutU64 care să afișeze un număr pe 64 de


biți transmis prin stivă.
Rezolvare:
include \masm32\include64\masm64rt.inc

.data
cifra db ?, 0

.code
main proc
mov rax, 1234567890 ; RAX = nr de afisat
push rax ; incarcare numar de afisat (RAX) pe stiva
call PutU64 ; apel procedura
add rsp, 8 ; refacere stiva ocupata de parametru
invoke ExitProcess, 0 ; invoke ExitProcess API
ret
main endp
NOSTACKFRAME ; dezactivare creare automata pentru STACK FRAME
PutU64 proc ; parametru: numar intreg fara semn pe 64 biti pe stiva
push rbp ; salvare RBP
mov rbp, rsp ; RBP = RSP (creare STACK FRAME)
mov rax, [rbp+16] ; incarcare in RAX paramentrul de pe stiva
xor rdx, rdx ; RDX = 0
mov rcx, 10 ; RCX = 10 baza de numeratie de afisat

4
Laboratorul 5. Rezolvări.

div rcx ; RDX:RAX / baza (RAX=cat, RDX = rest)


test rax, rax ; RAX == 0 (conditia de iesire)
jz @F ; daca RAX == 0 salt la @@ de mai jos
push rdx ; RDX (rest) -> stiva
push rax ; depunere parametru pe stiva (catul)
call PutU64 ; apel recursiv
add rsp, 8 ; eliberare stiva ocupata de parametru
pop rdx ; RDX <- stiva (resturile in ordine inversa)
@@:
add dl, '0' ; conversie cifra din DL in caracter ASCII
mov cifra, dl ; salvam in sirul "cifra", cifra din numar
sub rsp, 40 ; alocare spatiu pe stiva SHADOW AREA
; spatiu pentru primii 4 parametri ai unei
; functii aliniat la 16 octeti
invoke StdOut, addr cifra
add rsp, 40 ; aliberare spatiu pe stiva SHADOW AREA
pop rbp ; refacere RBP
ret
PutU64 EndP
STACKFRAME ; reactivare creare automata pentru STACK FRAME
end

5. Pe baza procedurii PutU64 creați o procedură PutI64 care să afișeze numere întregi cu
semn pe 64 biți.
Rezolvare:
include \masm32\include64\masm64rt.inc

.data
cifra db ?, 0

.code
main proc
mov rax, 1234567890 ; RAX = nr de afisat
push rax ; incarcare numar de afisat (RAX) pe stiva
call PutI64 ; apel procedura
add rsp, 8 ; refacere stiva ocupata de parametru
invoke ExitProcess, 0 ; invoke ExitProcess API
ret
main endp

NOSTACKFRAME ; dezactivare creare automata pentru STACK FRAME


PutI64 proc ; parametru: numar intreg fara semn pe 64 biti pe stiva
push rbp ; salvare RBP
mov rbp, rsp ; RBP = RSP (creare STACK FRAME)
mov rax, [rbp+16] ; incarcare in RAX paramentrul de pe stiva
cmp rax, 0
jnl @F ; salt daca nr este pozitiv
mov byte ptr cifra, '-' ; daca este negativ afisam semnul '-'
sub rsp, 40 ; alocare spatiu pe stiva SHADOW AREA
invoke StdOut, addr cifra ; afisare semnul '-'

5
Programare în limbaj de asamblare (PLA)

add rsp, 40 ; aliberare spatiu pe stiva SHADOW AREA


mov rax, [rbp+16] ; reincarcam nr in RAX (invoke modifica RAX)
neg rax ; RAX = -RAX, negam nr. negativ = nr. pozitiv
@@:
push rax ; depunem numarul pozitiv pe stiva
call PutU64 ; afisam numarul pozitiv
add rsp, 8 ; eliberam spatiul ocupar de argument
pop rbp ; refacere RBP
ret
PutI64 EndP

PutU64 proc ; parametru: numar intreg fara semn pe 64 biti pe stiva


push rbp ; salvare RBP
mov rbp, rsp ; RBP = RSP (creare STACK FRAME)
mov rax, [rbp+16] ; incarcare in RAX paramentrul de pe stiva
xor rdx, rdx ; RDX = 0
mov rcx, 10 ; RCX = 16 baza de numeratie de afisat
div rcx ; RDX:RAX / baza (RAX=cat, RDX = rest)
test rax, rax ; RAX == 0 (conditia de iesire)
jz @F ; daca RAX == 0 salt la @@ de mai jos
push rdx ; RDX (rest) -> stiva
push rax ; depunere parametru pe stiva (catul)
call PutU64 ; apel recursiv
add rsp, 8 ; eliberare stiva ocupata de parametru
pop rdx ; RDX <- stiva (resturile in ordine inversa)
@@:
add dl, '0' ; conversie cifra din DL in caracter ASCII
mov cifra, dl ; salvam in sirul "cifra", cifra din numar
sub rsp, 40 ; alocare spatiu pe stiva SHADOW AREA
; spatiu pentru primii 4 parametri ai unei
; functii aliniat la 16 octeti
invoke StdOut, addr cifra
add rsp, 40 ; aliberare spatiu pe stiva SHADOW AREA
pop rbp ; refacere RBP
ret
PutU64 EndP
STACKFRAME ; reactivare creare automata pentru STACK FRAME
end

6. Afișați pe ecran un vector de numere întregi cu semn pe 64 biți ( QWORD) inițializat în zona
de date.
Notă: pentru accesarea elementelor vectorului utilizați adresarea bazata, indexată scalată.
Rezolvare:
include \masm32\include64\masm64rt.inc

.data
vect dq 0, -1, 22, -333, 4444, -55555, 666666, -7777777, 88888888
len_v equ ($-vect)/8 ; lungimea vectorului
m_text db "Elementele vectorului: ", 0 ; mesaj text
cifra db ' ', 0 ; sir de un caracter

6
Laboratorul 5. Rezolvări.

CRLF db 13, 10, 0 ; CR+LF = "\n"

.code
main proc
invoke StdOut, addr m_text ; afisare mesaj
lea rsi, vect ; RSI = adresa de inceput a vectorului
xor rbx, rbx ; RBX = 0, indexul vectorului
@@: ; eticheta pt start bucla WHILE
cmp rbx, len_v ; am ajuns la finalul vvectorului ?
jnb @F ; iesim din bucla WHILE daca este mai mic
push [rsi+rbx*8] ; depunem pe stiva elementul din vector
call PutI64 ; apelam functia pentru afisare
add rbp, 8 ; eliberam spatiul ocupat de parametru
mov byte ptr cifra, ' ' ; incarcam in sirul cifra ' ' (spatiu)
invoke StdOut, addr cifra ; afisez un spatiu separator
inc rbx ; actualizam pointerul la vector
jmp @B ; salt la inceputul buclei
@@: ; eticheta de sfarsit a buclei WHILE
invoke StdOut, addr CRLF
invoke ExitProcess, 0 ; invoke ExitProcess API
ret
main endp

NOSTACKFRAME ; dezactivare creare automata pentru STACK FRAME


PutI64 proc ; parametru: numar intreg cu semn pe 64 biti pe stiva
push rbp ; salvare RBP
mov rbp, rsp ; RBP = RSP (creare STACK FRAME)
mov rax, [rbp+16] ; incarcare in RAX paramentrul de pe stiva
cmp rax, 0
jnl @F ; salt daca nr este pozitiv
mov byte ptr cifra, '-' ; daca este negativ afisam semnul '-'
sub rsp, 40 ; alocare spatiu pe stiva SHADOW AREA
invoke StdOut, addr cifra ; afisare semnul '-'
add rsp, 40 ; aliberare spatiu pe stiva SHADOW AREA
mov rax, [rbp+16] ; reincarcam nr in RAX (invoke modifica RAX)
neg rax ; negam nr negativ = nr pozitiv
@@:
push rax ; depunem numarul pozitiv pe stiva
call PutU64 ; afisam numarul pozitiv
add rsp, 8 ; eliberam spatiul ocupar de argument
pop rbp ; refacere RBP
ret
PutI64 EndP

PutU64 proc ; parametru: numar intreg fara semn pe 64 biti pe stiva


push rbp ; salvare RBP
mov rbp, rsp ; RBP = RSP (creare STACK FRAME)
mov rax, [rbp+16] ; incarcare in RAX paramentrul de pe stiva
xor rdx, rdx ; RDX = 0
mov rcx, 10 ; RCX = 16 baza de numeratie de afisat
div rcx ; RDX:RAX / baza (RAX=cat, RDX = rest)

7
Programare în limbaj de asamblare (PLA)

test rax, rax ; RAX == 0 (conditia de iesire)


jz @F ; daca RAX == 0 salt la @@ de mai jos
push rdx ; RDX (rest) -> stiva
push rax ; depunere parametru pe stiva (catul)
call PutU64 ; apel recursiv
add rsp, 8 ; eliberare stiva ocupata de parametru
pop rdx ; RDX <- stiva (resturile in ordine inversa)
@@:
add dl, '0' ; conversie cifra din DL in caracter ASCII
mov cifra, dl ; salvam in sirul "cifra", cifra din numar
sub rsp, 40 ; alocare spatiu pe stiva SHADOW AREA
; spatiu pentru primii 4 parametri ai unei
; functii aliniat la 16 octeti
invoke StdOut, addr cifra
add rsp, 40 ; aliberare spatiu pe stiva SHADOW AREA
pop rbp ; refacere RBP
ret
PutU64 EndP
STACKFRAME ; reactivare creare automata pentru STACK FRAME
end

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