Documente Academic
Documente Profesional
Documente Cultură
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
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
.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
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
.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.
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
5
Programare în limbaj de asamblare (PLA)
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.
.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
7
Programare în limbaj de asamblare (PLA)