Laborator 8 - Suport teoretic
Apeluri de functii sistem
Biblioteci de functii (function libraries)
Chiar daca limbajul de asamblare foloseste in mod direct componentele hardware ale sistemului, exista portiuni de cod utilizate frecvent, care ar fi impractic sa fie scrise de catre programator de fiecare data. De exemplu, comunicarea cu dispozitivele de intrare/iesire, care presupune de cele mai multe ori protocoale complexe. Unul dintre rolurile sistemului de operare este acela de a abstractiza masina hardware pentru programator, punand la dispozitie multiple biblioteci de functii ce pot fi apelate pentru anumite operatii frecvente, cum ar fi afisarea datelor intr-un anumit format, gasirea unui subsir intr-un sir sau diverse functii matematice.
Utilizarea unei functii presupune saltul la portiunea de cod corespunzatoare functiei, executia acestui cod, urmata de revenirea la instructiunea de dupa cea care a apelat functia, ca in figura de mai jos:
Utilizarea functiilor externe. Conventii de apel
Pentru apelul unei functii se foloseste instructiunea call.
Sintaxa:
call <nume_functie_sistem>
Semantica:
Aceasta instructiune pune adresa instructiunii urmatoare pe stiva, apoi sare la inceputul functiei apelate. Punerea pe stiva a adresei instructiunii urmatoare (adresa de revenire) se face pentru ca la finalul executiei sa se poata reveni la codul apelant.Apelarea unei functii sistem. Parametrii
De cele mai multe ori, functiile pot primi parametri, si pot intoarce rezultate. Exista mai multe conventii pentru a face aceste lucruri, dintre care in acest laborator vom folosi conventia cdecl.
O conventie de apel nu tine de sintaxa limbajului de asamblare, ci este un ”contract” intre autorul functiei si utilizatorii acesteia, ce specifica modul de transmitere a parametrilor, respectiv de intoarcere a rezultatului.
Conventia cdecl
- Argumentele se pun pe stiva de la dreapta la stanga
- Rezultatul implicit este returnat de catre functia sistem in EAX
- Registrii EAX, ECX, EDX pot fi folositi in interiorul functiei (isi pot modifica valoarea!)
- Atentie deci, daca doriti pastrarea valorilor initiale din EAX, ECX, EDX sa salvati aceste valori (in variabile de memorie, pe stiva sau in alti registrii) inainte de apelul functiei
- Functia nu va elibera argumentele de pe stiva. Este responsabilitatea programatorului sa faca acest lucru dupa apelul functiei
- Exemple: printf, scanf
Functii standard din msvcrt
Afisarea pe ecran
Pentru afisarea unui text pe ecran, ce respecta un anumit format, se foloseste functia printf.
Sintaxa functiei printf in limbaj de programare de nivel inalt este:
int printf(const char * format, variabila_1, constanta_2, ...);
Functia printf respecta conventia cdecl.
Primul argument al functiei este un sir de caractere ce contine formatul afisarii, urmat de un numar de argumente (valori constante sau nume de variabile) egal cu cel specificat in cadrul formatului.
Sirul de caractere transmis in parametrul format poate contine anumite marcaje de formatare, ce incep cu caracterul ’%’, care vor fi inlocuite de valorile specificate in urmatoarele argumente, formatate corespunzator.
Specificator | Ce se afiseaza | Exemplu | Dimensiune reprezentare valoare |
---|---|---|---|
c | Caracter | a | byte |
d sau i | Intreg zecimal cu semn | 392 | dword |
u | Intreg zecimal fara semn | 7235 | dword |
x | Numar in hexazecimal fara semn | 7fa | dword |
s | String (sir de caractere, terminat cu 0) | exemplu | sir de bytes terminat in 0 |
La intrarea in corpul functiei printf, in varful stivei se afla un dublucuvant cu Adresa de Revenire, apoi imediat sub el se afla alt dublucuvant care va contine offsetul stringului de formatare - argument al functiei printf. Sub acest dublucuvant se vor afla alte dublucuvinte corespunzatoare celorlalte argumente ale functiei printf. Descriptorii de afisare %d, %i, %c, %x, %u in cazul functiei printf vor fi aplicati totdeauna unui dublucuvant din stiva (chiar si in cazul lui %c care foloseste si el un dublucuvant de pe stiva, dar din acest dublucuvant considera doar octetul cel mai putin semnificativ). Astfel, primul descriptor de afisare se va aplica celui de-al treilea dublucuvant de pe stiva (numarat fata de varful stivei). Cel de-al doilea eventual descriptor se va aplica celui de-al patrulea dublucuvant de pe stiva (numarat fata de varful stivei), cel de-al treilea eventual descriptor din stringul de formatare se va aplica celui de-al cincilea dublucuvant de pe stiva (numarat fata de varful stivei) si tot asa.
Exemple:
Afisarea unui mesaj
- In limbaj de programare de nivel inalt:
printf("Ana are mere");
segment data use32 class=data
mesaj db "Ana are mere", 0 ; definim mesajul
segment code use32 class=code
; ...
push dword mesaj ; punem parametrul pe stiva
call [printf] ; apelam functia printf
add esp, 4 * 1 ; eliberam parametrii de pe stiva
; ...
Afisarea unui numar natural cu semn in baza 10
- In limbaj de programare de nivel inalt:
printf("%d", -17);
segment data use32 class=data
format db "%d", 0 ; definim formatul
segment code use32 class=code
; ...
push dword -17 ; punem parametrii pe stiva de la dreapta la stanga
push dword format
call [printf] ; apelam functia printf
add esp, 4 * 2 ; eliberam parametrii de pe stiva
; ...
Afisarea unui numar natural in baza 16
- In limbaj de programare de nivel inalt:
printf("%x", 0xAB);
segment data use32 class=data
format db "%x", 0 ; definim formatul
segment code use32 class=code
; ...
push dword 0xAB ; punem parametrii pe stiva de la dreapta la stanga
push dword format
call [printf] ; apelam functia printf
add esp, 4 * 2 ; eliberam parametrii de pe stiva
; ...
Afisarea unui mesaj care contine un numar natural in baza 10, stocat intr-o variabila n
- In limbaj de programare de nivel inalt:
printf("Ana are %d mere", n);
segment data use32 class=data
n dd 7
format db "Ana are %d mere", 0 ; definim formatul
segment code use32 class=code
; ...
push dword [n] ; punem pe stiva valoarea lui n
push dword format
call [printf] ; apelam functia printf
add esp, 4 * 2 ; eliberam parametrii de pe stiva
; ...
Afisarea unui mesaj care contine mai multe numere in baza 10.
- In limbaj de programare de nivel inalt:
printf("Ana are %d mere si %d pere", 7, 8);
segment data use32 class=data
format db "Ana are %d mere si %d pere", 0 ; definim formatul
segment code use32 class=code
; ...
push dword 8 ; punem parametrii pe stiva
push dword 7
push dword format
call [printf] ; apelam functia printf
add esp, 4 * 3 ; eliberam parametrii de pe stiva
; ...
Citirea de la tastatura
Pentru a citi date de la tastatura se foloseste functia scanf.
Sintaxa functiei scanf in limbaj de programare de nivel inalt este:
int scanf(const char * format, adresa_variabila_1, ...);
Sintaxa acestei functii este similara cu cea a functiei printf. Diferenta majora consta in faptul ca argumentele sale nu trebuie sa fie valori constante sau continuturi de variabile, ci numai adrese in memorie, unde se vor stoca valorile citite.
Exemplu:
Citirea unui numar natural in variabila n
- In limbaj de programare de nivel inalt:
scanf("%d", &n);
&n reprezinta adresa variabilei n in care functia scanf va completa valoarea citita de la tastatura
segment data use32 class=data
n dd 0 ; definim variabila n
format db "%d", 0 ; definim formatul
segment code use32 class=code
; ...
push dword n ; punem parametrii pe stiva de la dreapta la stanga
push dword format
call [scanf] ; apelam functia scanf pentru citire
add esp, 4 * 2 ; eliberam parametrii de pe stiva
; ...
Operatii cu fisiere text
Operatii cu fisiere text
- Deschiderea fisierului, care poate consta in:
- Deschiderea unui fisier existent
- Crearea unui fisier nou
- Efectuarea operatiilor de scriere si/sau citire
- Inchiderea fisierului.
Deschiderea unui fisier
Sintaxa functiei
fopen in limbaj de programare de nivel inalt este:FILE * fopen(const char* nume_fisier, const char * mod_acces)
Functia fopen respecta conventia cdecl si se gaseste in msvcrt.dll .
Argumentele functiei fopen:
Primul argument al functiei este adresa unui sir de caractere reprezentand numele fisierului: Al doilea argument este adresa unui sir de caractere, reprezentand modalitatea in care se va deschide fisierul.Mod | Semnificatie | Descriere |
r | citire (read) | - Deschide un fisier text pentru citire. Fisierul trebuie sa existe deja pe disc. |
w | scriere (write) | - Daca nu exista un fisier cu acel nume, creaza fisierul si il deschide pentru scriere. - Daca un fisier cu acel nume exista deja, deschide acel fisier pentru scriere. Continutul initial va fi sters. Scrierea se va face de la inceputul fisierului. |
a | adaugare (append) | - Daca nu exista un fisier cu acel nume, creaza fisierul si il deschide pentru scriere. - Daca un fisier cu acel nume exista deja, deschide acel fisier pentru scriere, dar scrierea se va face la sfarsitul fisierului, in continuarea continutului existent. Continutul initial al fisierului va fi pastrat. |
r+ | citire si scriere fisier existent | - Deschide un fisier text pentru citire si scriere. Fisierul trebuie sa existe deja pe disc. |
w+ | citire si scriere | - Daca nu exista un fisier cu acel nume, creaza fisierul si il deschide pentru citire si scriere. - Daca un fisier cu acel nume exista deja, deschide acel fisier pentru citire si scriere. Continutul initial va fi sters. Scrierea se va face de la inceputul fisierului. |
a+ | citire si adaugare | - Daca nu exista un fisier cu acel nume, creaza fisierul si il deschide pentru citire si scriere. - Daca un fisier cu acel nume exista deja, deschide acel fisier pentru citire si scriere. Continutul initial al fisierului va fi pastrat. Citirea se va face de la inceputul fisierului. Scrierea se va face in continuarea continutului existent. |
Observatii:
- Numele unui fisier trebuie sa includa si extensia (ex: nume.txt, exemplu.asm).
- Fisierele se vor crea sau deschide din directorul curent (in acelasi director in care se afla fisierul sursa asm). Important: pentru a putea deschide un fisier existent folosind numele acestuia, fisierul trebuie sa se afle in acelasi director cu fisierul sursa .asm, altfel acesta nu va fi gasit.
- Operatiile de scriere nu vor reusi pentru fisiere deschise doar cu drepturi de citire (ex: ”r”). Operatiile de citire nu vor reusi pentru fisiere deschise doar cu drepturi de scriere sau adaugare (ex: ”w”, ”a”)
- Ambele argumente ale functiei fopen reprezinta siruri de caractere care trebuie sa se termine cu valoarea 0 (asemenea formatului pentru functia printf).
Valoarea returnata de functia fopen:
Daca fisierul este deschis cu succes, functia fopen va completa in registrul EAX un identificator (descriptor de fisier) care va fi folosit in continuare pentru a lucra cu acel fisier (pentru operatii de scriere, citire, etc.). Altfel (in caz de eroare), functia fopen va completa in registrul EAX valoarea 0.Alte observatii:
Este important sa se verifice valoarea returnata de functie in EAX (daca nu a fost eroare), inainte de a efectua alte operatii cu acel fisier. Daca in cadrul unui program se deschid mai multe fisiere diferite folosind functia fopen, fiecare valoare returnata de functiei trebuie salvata separat, deoarece reprezinta o valoare distincta prin care este identificat un fisier. Dupa finalizarea lucrului cu un fisier deschis, este important sa se si inchida acel fisier (de obicei se face la finalul programului – inainte de exit). Pentru a inchide un fisier (deschis in prealabil de functia fopen) se foloseste functia fclose.Scrierea intr-un fisier
Sintaxa functiei
fprintf in limbaj de programare de nivel inalt este:int fprintf(FILE * stream, const char * format, <variabila_1>, <constanta_2>, <...>)
Functia fprintf respecta conventia cdecl si se gaseste in msvcrt.dll .
Sintaxa functiei fprintf este asemantoare cu sintaxa functiei printf (folosita pentru afisare in consola). Diferenta este faptul ca functia fprintf are ca prim parametru identificatorul fisierului in care se va scrie textul, in plus fata de parametrii functiei printf.
Argumentele functiei fprintf
Primul argument al functiei reprezinta descriptorul de fisier (identificatorul) returnat de apelul functiei fopen. Urmatorul argument al functiei este un sir de caractere ce contine formatul afisarii, urmat de un numar de argumente (valori constante sau nume de variabile) egal cu cel specificat in cadrul formatului. Asemenea functiei printf, sirul de caractere transmis in parametrul format poate contine anumite marcaje de formatare, ce incep cu caracterul ’%’, care vor fi inlocuite de valorile specificate in urmatoarele argumente, formatate corespunzator.Specificator | Ce se afiseaza | Exemplu | Dimensiune reprezentare valoare |
c | Caracter | a | byte |
d sau i | Intreg zecimal cu semn | 392 | dword |
u | Intreg zecimal fara semn | 7235 | dword |
x | Numar in hexazecimal fara semn | 7fa | dword |
s | String (sir de caractere, terminat cu 0) | exemplu | sir de bytes terminat in 0 |
Citirea dintr-un fisier
Sintaxa functiei
fread in limbaj de programare de nivel inalt este:int fread(void * str, int size, int count, FILE * stream)
Functia fread respecta conventia cdecl si se gaseste in msvcrt.dll .
Argumentele functiei fread
Primul argument al functiei fread reprezinta adresa unui sir de elemente in care se vor completa datele citite din fisier. Al doilea argument reprezinta dimensiunea unui element care va fi citit din fisier. Al treilea argument reprezinta numarul maxim de elemente care se vor citi din fisier. Ultimul argument al functiei reprezinta descriptorul de fisier (identificatorul) returnat de apelul functiei fopen. In cazul citirii fisierelor text, primul argument al functiei fread este un sir de bytes si al doilea argument este 1 (=dimensiunea unui byte). Al treilea argument este dimensiunea sirului de bytes (numarul de elemente).Valoarea returnata de functia fread:
Functia fread va completa in registrul EAX numarul de elemente citite. Daca acest numar este mai mic decat valoarea argumentului count, atunci fie apelul functiei fread a intampinat o eroare la citire, fie s-a ajuns la finalul fisierului.Observatii:
Fisierele text pot fi avea dimensiuni prea mari pentru putea citi continutul acestora cu un singur apel al functiei fread. In acest caz este nevoie de apeluri repetate ale functiei fread, pana cand intreg continutul fisierului este citit. In sectiunea „Exemple” vom prezenta un program care exemplifica acest scenariu. Pentru a verifica daca s-a ajuns la finalul fisierului cu operatia de citire se poate verifica daca valoarea returnata de fread este 0.Inchiderea unui fisier deschis
Sintaxa functiei
fclose in limbaj de programare de nivel inalt este:int fclose(FILE * descriptor)
Functia fclose respecta conventia cdecl si se gaseste in msvcrt.dll .