Documente Academic
Documente Profesional
Documente Cultură
Laboratorul 6. Rezolvări.
1. Realizați un macro care definește în zona de date un sir de caractere de forma:
"ABBCCCDDDD ... IIIIIIIIIJJJJJJJJJJ" (1xA 2xB 3xC .... 10xJ). Afișați șirul de
caractere obținut.
Rezolvare:
include \masm32\include64\masm64rt.inc
.data
sir1 LABEL BYTE ; eticheta sir1 (adresa de inceput)
FOR cnt, <1,2,3,4,5,6,7,8,9,10> ;; FOR arg = 1..10
BYTE cnt DUP (cnt-1+'A') ;; declar "arg" BYTEs initializati cu
ENDM ;; cu val: arg-1+'A' ('A'..'J')
BYTE 0 ; terminatorul de sir
.code
main proc
invoke StdOut, addr sir1 ; afisare sir1
invoke StdOut, addr crlf ; afisare "\n"
invoke StdOut, addr sir2 ; afisare sir2
invoke StdOut, addr crlf ; afisare "\n"
invoke StdOut, addr sir3 ; afisare sir3
invoke ExitProcess, 0 ; invoke ExitProcess API
ret
main endp
end
2. Realizați o funcție de conversie dintr-un șir de caractere într-un număr pe 64 de biți fără
semn. Funcția va fi conformă Microsoft x64 calling convention și se va numi „_atou” și
va primi ca parametri: pointer la șir și pointer (referință) la număr.
Rezolvare:
include \masm32\include64\masm64rt.inc
1
Programare în limbaj de asamblare (PLA)
.data
sir db "9223372036854775807", 0
nr dq ?
NOSTACKFRAME
.code
main proc
sub rsp, 32+8 ; alocare shadow area + aliniere stiva la 16o
lea rcx, sir ; RCX = primul parametru
lea rdx, nr ; RDX = al doilea parametru
call _atou ; apel procedura
add rsp, 32+8 ; eliberare stiva alocata
ret
main endp
_atou Proc
; Argumente: RCX = pointer la sir, RDX = referinta la QWORD
; Procedura nu apeleaza alte proceduri => nu mai alocam shadow area
; Procedura va returna FLAG-urile:
; PF & ZF vor reflecta valoarea returnata
; CF = 0
; OF = 1 > o valoare in afara gamei: 0 .. (2^64)-1
; val. returnata va fi 0 daca OF = 1.
mov [rsp+8], rcx ; salvare Arg.1 in shadow area
mov [rsp+16], rdx ; salvare Arg.2 in shadow area
xor r8, r8 ; R8 = 0, va contine valoarea cifrei
xor rax, rax ; R9 = 0 = suma partiala
@@:
mov r8b, [rcx] ; R8B = caracterul curent din sir
cmp r8b, '0' ; comparatie cu '0'
jb @F ; nu e caracter daca < '0' (inclusiv '\0')
cmp r8b, '9' ; comparatie cu '9'
ja @F ; nu e caracter daca > '9'
sub r8b, '0' ; in RAX conversie ASCII -> cifra
mov rdx, 10 ; RDX = 10
mul rdx ; RDX:RAX = RAX * 10 (suma *= 10)
jo @@overflow ; daca OF=1 produsul e prea mare (RDX!=0)
add rax, r8 ; adaugam cifra la suma partiala
jc @@overflow ; daca CF=1 suma partiala e prea mare
inc rcx ; incrementare pointer sir
jmp @B ; urmatorul caracter
@@:
jmp @F ; salt peste secventa de overflow
@@overflow: ; daca detectam depasire
xor eax, eax ; rezultatul = 0 in cazul depasirii
pushf ; Push FLAGS pe stiva
bts word ptr [rsp], 11 ; set bitul 11 din cuvantul din stiva
popf ; Pop FLAGS
@@:
mov rcx, [rsp+16] ; RCX = referinta la nr de returnat
mov [rcx], rax ; salvam rezultatul in Arg.2
2
Laboratorul 6. Rezolvări.
3. Similar realizați o funcție „_atoi” de conversie dintr-un șir de caractere într-un număr
pe 64 de biți cu semn.
Rezolvare:
_atoi Proc
; argumente: RCX = pointer la sir, RDX = referinta la QWORD
; Procedura nu apeleaza alte proceduri => nu mai alocam shadow area
; Procedura va returna FLAG-urile:
; PF & ZF vor reflecta valoarea returnata
; CF = 0
; OF = 1 -> o valoare in afara gamei: -(2^63) .. (2^63)-1
; val. returnata va fi 0 daca OF = 1.
mov [rsp+8], rcx ; salvare arg 1 in shadow area
mov [rsp+16], rdx ; salvare arg 2 in shadow area
xor r8, r8 ; R8 = 0, va contine valoarea cifrei
xor rax, rax ; RAX = 0 = suma partiala
xor r9b, r9b ; R9B = 0 (salvam semnul)
mov r8b, [rcx] ; R8B = primul caracter din sir
cmp r8b, '-' ; sirul incepe cu '-'?
jne @F ; daca nu skip
not r9b ; altfel R9B = !R9B
inc rcx ; RCX++ incrementare pointer la sir
@@:
mov r8b, [rcx] ; R8B = caracterul curent din sir
cmp r8b, '0' ; comparatie cu '0'
jb @F ; nu e caracter daca < '0' (inclusiv '\0')
cmp r8b, '9' ; comparatie cu '9'
ja @F ; nu e caracter daca > '9'
sub r8b, '0' ; in RAX conversie ASCII -> cifra
mov rdx, 10 ; RDX = 10
mul rdx ; RDX:RAX = RAX * 10 (suma *= 10)
jo @@overflow ; daca OF=1 produsul e prea mare (RDX!=0)
add rax, r8 ; adaugam cifra la suma partiala
jc @@overflow ; daca CF=1 suma partiala e prea mare
inc rcx ; incrementare pointer sir
jmp @B ; urmatorul caracter
@@
test r9b, r9b ; verific semnul salvat in R9B
jz @F ; daca nu avea semn -> skip
neg rax ; altfel inversam semnul numarului
test rax, rax ; testam nr "negativ" rezultat
js @F ; daca este neg. salt peste tratare overflow
@@overflow: ; eticheta locala - tratarea depasirilor
xor eax, eax ; rezultatul = 0 in cazul depasirii
pushf ; Push FLAGS pe stiva
bts word ptr [rsp], 11 ; set bitul 11 (OF) din cuvantul din stiva
popf ; Pop FLAGS
3
Programare în limbaj de asamblare (PLA)
@@:
mov rcx, [rsp+16] ; RCX = referinta la nr de returnat
mov [rcx], rax ; salvam rezultatul in param. 2
ret ; revenire din procedura
_atoi EndP
5. Realizați un program care sortează un vector de numere întregi pe 32 biți definit în zona
de memorie după algoritmul bubble sort.
Rezolvare:
include \masm32\include64\masm64rt.inc
.data
vect QWORD 500, 333, 100, 70000, -100h, 9999, 55, -1, 0
v_len EQU ($-vect) / SIZEOF QWORD
msg_1 BYTE "Vectorul initial: ", 0
msg_2 BYTE "Vectorul rezultat: ", 0
4
Laboratorul 6. Rezolvări.
NOSTACKFRAME
.code
main proc
sub rsp, 32+8
; *** Afisare vector initial ***
invoke StdOut, addr msg_1 ; Afisare sir msg_1
lea rbx, vect
xor rdi, rdi ; RDI = 0
@@: ; WHILE \
cmp rdi, v_len ; (RDI < v_len)
jnb @F ; {
PutI [rbx+rdi*8] ; Afisare "vect[RDI]"
PutCh ' ' ; Afisare caracterul ' '
inc rdi ; RDI++
jmp @B ; }
@@: ; END_WHILE
PutCh 13, 10 ; Afisare "\n"
; *** Ordonare vector dupa alg. BubbleSort ***
; for (i = n-1; i!=0 ; i--)
; for (j = 0; j<i; j++)
; if (arr[j] < arr[j+1])
; swap(&arr[j], &arr[j+1]);
; *** Daca implementam cu WHILE obtinem ***
; i = n-1
; while (i != 0) {
; j = 0
; while (j < i) {
; if (vect[j] < arr[j+1])
; swap(&vect[j], &vect[j+1])
; j++ }
; i-- }
lea rbx, vect ; RBX = adresa vectorului
mov rdx, v_len-1 ; RDX = v_len-1 ("i")
While1_Begin: ; WHILE \
test rdx, rdx ; (RDX != 0)
jz While1_End ; {
xor rcx, rcx ; RCX = 0 ("j")
mov r8, [rbx] ; R8 = "vect[0]"
While2_Begin: ; WHILE \
cmp rcx, rdx ; (RCX < RDX)
jnb While2_End ; {
mov r9, [rbx+rcx*8+8] ; R9 = "vect[j+1]"
cmp r8, r9 ; IF
jng @F ; (R8 > R9)
xchg r8, r9 ; { exchange R8 cu R9
mov [rbx+rcx*8], r8 ; "vect[j]" = R8
mov [rbx+rcx*8+8], r9 ; "vect[j+1]" = R9
@@:
mov r8, r9 ; R8="vect[j+1]"
inc rcx ; RCX++
jmp While2_Begin ; }
5
Programare în limbaj de asamblare (PLA)
While2_End: ; END_WHILE
dec rdx ; RDX--
jmp While1_Begin ; }
While1_End: ; END_WHILE
; *** Afisare vector rezultat ***
invoke StdOut, addr msg_2 ; Afisare sir msg_2
lea rbx, vect
xor rdi, rdi ; RDI = 0
@@: ; WHILE \
cmp rdi, v_len ; (RDI < v_len)
jnb @F ; {
PutI [rbx+rdi*8] ; Afisare "vect[RDI]"
PutCh ' ' ; Afisare caracterul ' '
inc rdi ; RDI++
jmp @B ; }
@@: ; END_WHILE
PutCh 13, 10 ; Afisare "\n"
invoke ExitProcess, 0 ; invoke ExitProcess API
add rsp, 40
ret
main endp
6
Laboratorul 6. Rezolvări.
_PutI EndP
end
.data
VMAX EQU 25 ; constanta pt dim. maxima pt vect
vect QWORD VMAX DUP (?) ; vector de "VMAX" DWORDs
v_len QWORD ? ; dimensiune vectorului
txt_0 BYTE "Re-", 0 ; pentru Re-introducerea datelor
txt_1 BYTE "Introduceti dimensiunea vectorului [2-", 0
txt_2 BYTE "Introduceti elementul [", 0
txt_X BYTE "]: ", 0 ; extra bracket
msg_1 BYTE "Vectorul initial: ", 0
msg_2 BYTE "Vectorul ordonat: ", 0
buffer DB 260 DUP(?) ; buffer pt citire de la tastatura
NOSTACKFRAME
.code
main proc
sub rsp, 32+8 ; Creaar SHADOW AREA + aliniere 16o
Citire:
invoke StdOut, addr txt_1 ; Afisare sir txt_1
PutI VMAX ; Afisare nr VMAX
invoke StdOut, addr txt_X ; Afisare "]: "
7
Programare în limbaj de asamblare (PLA)
8
Laboratorul 6. Rezolvări.
dec rdx
While1_Begin: ; WHILE \
test rdx, rdx ; (RDX != 0)
jz While1_End ; {
xor rcx, rcx ; RCX = 0 ("j")
mov r8, [rbx] ; R8 = "vect[0]"
While2_Begin: ; WHILE \
cmp rcx, rdx ; (RCX < RDX)
jnb While2_End ; {
mov r9, [rbx+rcx*8+8] ; R9 = "vect[j+1]"
cmp r8, r9 ; IF
jng @F ; (R8 > R9)
xchg r8, r9 ; { exchange R8 cu R9
mov [rbx+rcx*8], r8 ; "vect[j]" = R8
mov [rbx+rcx*8+8], r9 ; "vect[j+1]" = R9
@@:
mov r8, r9 ; R8="vect[j+1]"
inc rcx ; RCX++
jmp While2_Begin ; }
While2_End: ; END_WHILE
dec rdx ; RDX--
jmp While1_Begin ; }
While1_End: ; END_WHILE
; *** Afisare vector rezultat ***
invoke StdOut, addr msg_2 ; Afisare sir msg_2
lea rbx, vect
xor rdi, rdi ; RDI = 0
@@: ; WHILE \
cmp rdi, v_len ; (RDI < v_len)
jnb @F ; {
PutI [rbx+rdi*8] ; Afisare "vect[RDI]"
PutCh ' ' ; Afisare caracterul ' '
inc rdi ; RDI++
jmp @B ; }
@@: ; END_WHILE
PutCh 13, 10 ; Afisare "\n"
invoke ExitProcess, 0 ; invoke ExitProcess API
add rsp, 40
ret
main endp
9
Programare în limbaj de asamblare (PLA)
10
Laboratorul 6. Rezolvări.
end
11