Laborator

Apeluri de functii

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
 

Exemple:

Afisarea unui mesaj
  • In limbaj de programare de nivel inalt:
  • 
    	printf("Ana are mere");
    	
  • Echivalentul in limbaj de asamblare:
  • 
    	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);
    	
  • Echivalentul in limbaj de asamblare:
  • 
    	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);
    	
  • Echivalentul in limbaj de asamblare:
  • 
    	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);
    	
  • Echivalentul in limbaj de asamblare:
  • 
    	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);
    	
  • Echivalentul in limbaj de asamblare:
  • 
    	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
    	
  • Echivalentul in limbaj de asamblare:
  • 
    	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
    		; ...