Laborator 11 - Exemple
Programare multi-modul (asm+asm)
Exemple
Se va scrie un program care calculeaza factorialul unui numar.
"Programul principal" este main.asm, iar funcția factorial este definită în modul.asm.
Pentru a putea asambla și edita legaturi este nevoie de linia de comandă.
Mai jos este prezentat procesul de asamblare, editare de legături ce duce la un program executabil:
- Fie directorul asc pe discul D, în acest director se găsesc sursele programului (main.asm și modul.asm);
- Este necesar ca în directorul asc să se copieze și nasm.exe și alink.exe (programe disponibile în directorul nasm din setul de instrumente);
- Pentru a usura navigarea în linia de comandă către locația pe disc unde se află sursele se poate folosi programul Total Commander, se navighează vizual până în directorul asc și se lansează linia de comandă (a se vedea figura de mai jos)
- dacă nu se vrea utilizarea programului Total Commander, se lansează cmd.exe și cu urmatoarea secvență de comenzi se poate naviga în directorul asc
> d:
> cd asc
- indiferent de varianta aleasă rezultatul trebuie să fie cel din figura de mai jos
- comanda dir listează conținutul directorului curent, se verifică dacă directorul în care s-a navigat conține sursele .asm și programele alink.exe și nasm.exe (a se vedea figura de mai jos)
- se asamblează cele două surse folosind secvența de comenzi
> nasm -fobj modul.asm
> nasm -fobj main.asm
- rezultatul este cel din figura de mai jos, două fișiere .obj
- folosind alink.exe (editor de legături), din cele două fișiere .obj se creează programul executabil, numele fișierului .exe rezultat este identic cu primul fișier .obj dat ca și parametru editorului de legături, în acest caz main. Programul poate fi rulat, în acest caz main.exe afișează pe ecran 6! = 720 (a se vedea figura de mai jos)
- pentru a depana, codul din ollydbg, File->Open si se deschide fisierul executabil, în acest caz main.exe
Programe sursa
Exemplul 1:
Exemplul 2:
Exemplul 3:
Factorial recursiv - Exemplu propus de studentul Molnar Radu, grupa 215, 2017-2018
bits 32 ; assembling for the 32 bits architecture
; declare the EntryPoint (a label defining the very first instruction of the program)
global start
; declare external functions needed by our program
extern exit,printf,scanf; adaugam functile externe de care avem nevoie
import exit msvcrt.dll
import printf msvcrt.dll
import scanf msvcrt.dll
; our data is declared here (the variables needed by our program)
segment data use32 class=data
; ...
text db "introduceti un n=",0
final db "n!=%d",0
format db "%d",0
a resd 1 ; variabila a va contine numarul n citit de la tastatura
; our code starts here
segment code use32 class=code
factor:
;pentru a implementa problema recursiv trebuie sa o despartim in cazuri
;la calcularea factorialului recursiv exista doua cazuri:
;n!=n*(n-1)! - iteratia curenta
;0!=1 - conditia de oprire
;subprogramul se va reapela pana in momentul in care se ajunge la ecx=0 moment in care se atribuie eax = 1 si ne intoarcem la pasul anterior
mov ecx, [esp+4] ;mutam in ecx numarul de pasi pe care ii mai avem de facut
jecxz sf ;daca ecx ajunge sa fie 0 sarim la eticheta sf pentru a putea incepe sa calculam factorialul
;daca am trecut de compararea cu 0 atunci ajungem la primul caz al recursivitatii
;formula lui fiind n!=n*(n-1)!
dec ecx; decrementam ecx pentru a putea sa reapelam functia pentru pasul urmator
push ecx; depunem pe stiva valoarea n curenta de calcul a factorialului
call factor; apelam functia cu parametrul curent valoarea de pe stiva
mul dword [esp+8]; inmultim cu valoarea coresp. pasului actual
add esp,4; eliberam stiva de parametrul utilizat pentru a ajunge la adresa de revenire a pasului anterior
jmp return; salt la eticheta return pentru a putea invoca revenirea din subprogram
sf:
mov eax,1;cum recursivitatea noastra are doua cazuri am ajuns in cazul in care ecx e 0 si returnam 1 – conditia de oprire
;0!=1
return:
ret ;ne intoarcem la pasul anterior sau in programul principal
start:
; ...
;tiparirea mesajului
push dword text
call [printf]
add esp,4
;citirea lui n de la tastatura
push dword a
push dword format
call [scanf]
add esp,4*2
mov ecx,0
mov eax,0;pregatim registrii pentru apelare
push dword [a] ;salvam pe stiva numarul n
call factor ;apelam functia
;afisarea rezultatului
push eax
push final
call [printf]
; exit(0)
push dword 0; push the parameter for exit onto the stack
call [exit]; call exit to terminate the program