Laborator 8 - Exemple
Apeluri de functii sistem
Atentie la utilizarea functiei scanf
Atentie la dimensiunea de reprezentare a variabilelor in functie de formatul dorit.
Vezi tabel la sectiunea Functii standard din msvcrt din Teorie.
Urmariti exemplul de mai jos care e GRESIT (greseala frecventa) si spuneti ce se intampla:
; Ne propunem ca programul de mai jos sa citeasca de la tastatura un numar si sa afiseze pe ecran valoarea numarului citit impreuna cu un mesaj.
bits 32
global start
; declararea functiilor externe folosite de program
extern exit, printf, scanf ; adaugam printf si scanf ca functii externe
import exit msvcrt.dll
import printf msvcrt.dll ; indicam asamblorului ca functia printf se gaseste in libraria msvcrt.dll
import scanf msvcrt.dll ; similar pentru scanf
segment data use32 class=data
n db 0 ; in aceasta variabila se va stoca valoarea citita de la tastatura
message db "Numarul citit este n= %d", 0
format db "%d", 0 ; %d <=> un numar decimal (baza 10)
segment code use32 class=code
start:
; vom apela scanf(format, n) => se va citi un numar in variabila n
; punem parametrii pe stiva de la dreapta la stanga
push dword n ; ! adresa lui n, nu valoarea
push dword format
call [scanf] ; apelam functia scanf pentru citire
add esp, 4 * 2 ; eliberam parametrii de pe stiva; 4 = dimensiunea unui dword; 2 = nr de parametri
;convertim n la dword pentru a pune valoarea pe stiva
mov eax,0
mov al,[n]
;afisam mesajul si valoarea lui n
push eax
push dword message
call [printf]
add esp,4*2
; exit(0)
push dword 0 ; punem pe stiva parametrul pentru exit
call [exit] ; apelam exit pentru a incheia programul
In exemplul de mai sus se suprascrie inceputul din mesaj si nu se mai afiseaza nimic pe ecran.
Afisarea unui mesaj
; Codul de mai jos va afisa mesajul "Ana are 17 mere"
bits 32
global start
; declararea functiilor externe folosite de program
extern exit, printf ; adaugam printf ca functie externa
import exit msvcrt.dll
import printf msvcrt.dll ; indicam asamblorului ca functia printf se gaseste in libraria msvcrt.dll
segment data use32 class=data
; sirurile de caractere sunt de tip byte
format db "Ana are %d mere", 0 ; %d va fi inlocuit cu un numar
; sirurile de caractere pt functiile C trebuie terminate cu valoarea 0
segment code use32 class=code
start:
mov eax, 17
; vom apela printf(format, 17) => se va afisa: „Ana are 17 mere”
; punem parametrii pe stiva de la dreapta la stanga
push dword eax
push dword format ; ! pe stiva se pune adresa string-ului, nu valoarea
call [printf] ; apelam functia printf pentru afisare
add esp, 4 * 2 ; eliberam parametrii de pe stiva; 4 = dimensiunea unui dword; 2 = nr de parametri
; exit(0)
push dword 0 ; punem pe stiva parametrul pentru exit
call [exit] ; apelam exit pentru a incheia programul
Afisarea unui quadword pe ecran
segment data use32 class=data
a dq 300765694775808
format db '%lld',0
segment code use32 class=code
start:
push dword [a+4]
push dword [a]
push dword format
call [printf]
add esp,4*3
push dword 0
call [exit]
Citirea unui numar de la tastatura
; Codul de mai jos va afisa mesajul ”n=”, apoi va citi de la tastatura valoarea numarului n.
bits 32
global start
; declararea functiilor externe folosite de program
extern exit, printf, scanf ; adaugam printf si scanf ca functii externa
import exit msvcrt.dll
import printf msvcrt.dll ; indicam asamblorului ca functia printf se gaseste in libraria msvcrt.dll
import scanf msvcrt.dll ; similar pentru scanf
segment data use32 class=data
n dd 0 ; in aceasta variabila se va stoca valoarea citita de la tastatura
; sirurile de caractere sunt de tip byte
message db "n=", 0 ; sirurile de caractere pentru functiile C trebuie sa se termine cu valoarea 0 (nu caracterul)
format db "%d", 0 ; %d <=> un numar decimal (baza 10)
segment code use32 class=code
start:
; vom apela printf(message) => se va afisa "n="
; punem parametrii pe stiva
push dword message ; ! pe stiva se pune adresa string-ului, nu valoarea
call [printf] ; apelam functia printf pentru afisare
add esp, 4*1 ; eliberam parametrii de pe stiva ; 4 = dimensiunea unui dword; 1 = nr de parametri
; vom apela scanf(format, n) => se va citi un numar in variabila n
; punem parametrii pe stiva de la dreapta la stanga
push dword n ; ! adresa lui n, nu valoarea
push dword format
call [scanf] ; apelam functia scanf pentru citire
add esp, 4 * 2 ; eliberam parametrii de pe stiva
; 4 = dimensiunea unui dword; 2 = nr de parametri
; exit(0)
push dword 0 ; punem pe stiva parametrul pentru exit
call [exit] ; apelam exit pentru a incheia programul
Salvarea valorilor din registrii inaintea apelurilor de functii sistem
; Codul de mai jos va calcula rezultatul unor operatii aritmetice in registrul EAX, va salva valoarea registrilor, apoi va afisa valoarea rezultatului si va restaura valoarea registrilor.
bits 32
global start
; declararea functiilor externe folosite de program
extern exit, printf ; adaugam printf ca functie externa
import exit msvcrt.dll
import printf msvcrt.dll ; indicam asamblorului ca functia printf se gaseste in libraria msvcrt.dll
segment data use32 class=data
; sirurile de caractere sunt de tip byte
format db "%d", 0 ; %d <=> un numar decimal (baza 10)
segment code use32 class=code
start:
; vom calcula 20 + 123 + 7 in EAX
mov eax, 20
add eax, 123
add eax, 7 ; eax = 150 (baza 10) sau 0x96 (baza 16)
; salvam valoarea registrilor deoarece apelul functiei sistem printf va modifica valoarea acestora
; folosim instructiunea PUSHAD care salveaza pe stiva valorile mai multor registrii, printre care EAX, ECX, EDX si EBX
; in acest exemplu este important sa salvam doar valoarea registrului EAX, dar instructiunea poate fi aplicata generic
PUSHAD
; vom apela printf(format, eax) => vom afisa valoarea din eax
; punem parametrii pe stiva de la dreapta la stanga
push dword eax
push dword format ; ! pe stiva se pune adresa string-ului, nu valoarea
call [printf] ; apelam functia printf pentru afisare
add esp, 4*2 ; eliberam parametrii de pe stiva ; 4 = dimensiunea unui dword; 2 = nr de parametri
; dupa apelul functiei printf registrul EAX are o valoare setata de aceasta functie (nu valoarea 150 pe care am calculat-o la inceputul programului)
; restauram valoarea registrilor salvati pe stiva la apelul instructii PUSHAD folosind instructiunea POPAD
; aceasta instructiune ia valori de pe stiva si le completeaza in mai multi registrii printre care EAX, ECX, EDX si EBX
; este important ca inaintea unui apel al instructiunii POPAD sa ne asiguram ca exista suficiente valori
; pe stiva pentru a fi incarcate in registrii (de exemplu ca anterior a fost apelata instructiunea PUSHA)
POPAD
; acum valoarea registrului EAX a fost restaurata la valoarea de dinaintea apelului instructiunii PUSHAD (in acest caz valoarea 150)
; exit(0)
push dword 0 ; punem pe stiva parametrul pentru exit
call [exit] ; apelam exit pentru a incheia programul
Operatii cu fisiere text
Crearea unui fisier nou
Fisier asm: create_file.asm
Scrierea unui text intr-un fisier nou
Fisier asm: create_write_file.asm
Adaugarea unui text intr-un fisier
Fisier asm: create_append_file.asm
Citirea unui text scurt (max 100 caractere) dintr-un fisier
Fisier asm: read_short_text_from_file_no_display.asm
Citirea unui text scurt (max 100 caractere) dintr-un fisier – cu afisarea textului
Fisier asm: read_short_text_from_file_and_display.asm
Citirea intregului text dintr-un fisier (in etape)
Fisier asm: read_full_file.asm