Code:
push %ebp
movl %esp, %ebp
movl 8(%ebp), %ebx
u ebx ti ide argument koji se predaje funkciji :)
Code:
andl %ebx, %ebx #provera da li je n=0
jz fakt_nula
Kao sto i sam komentar kaze (cesce se koristi or i test nego and), ali kod radi svoj posao i proverava da li je argument predat funkciji = 0.
Code:
push %ebx #čuvanje vrednosti n na steku
decl %ebx #n-1
push %ebx #rekurzija
call faktorijel
add $4, %esp
Dakle cuvas vrednost ebx-a pre ulaska u drugi poziv iste funkcije, zatim umanjujes ebx za 1 i predajes ga kao parametar funkciji faktorijal.
Naime add $4, %esp ce ukloniti sa stacka parametar koji si gurnuo na stack. Zbog lepote koda ja koristim ret 4 (pa u tom slucaju add $4, %esp nepotrebno)
to je u sustini razlika izmedju __cdecl(ne cisti stack znaci samo retn) i __stdcall(cisti stack znaci ret broj_parametra * 4)
Code:
pop %ebx #vraćanje vrednosti n sa steka
mull %ebx #n*(n-1)! -> eax
jmp fakt_kraj
Sad posto si poravnao stack odnosno ukloni sa njega parametar koji si predao funkciji vracas u ebx ono sto si ranije pushnuo (ono #cuvanje vrednosti n na stacku) i mnozis sadrzaj eax registra sa ebx (mull %ebx) i izlazis iz te funkcije...
Da sumiramo ovako ->
Ovaj kod ce se pozivati i vrteti sve dok argument predat funkciji != 0, odnosno dok ebx != 0
Code:
faktorijel:
push %ebp
movl %esp, %ebp
movl 8(%ebp), %ebx
andl %ebx, %ebx #provera da li je n=0
jz fakt_nula
push %ebx #čuvanje vrednosti n na steku (ovo je bitan momenat)
decl %ebx #n-1
push %ebx #rekurzija
call faktorijel
Kad ebx bude = 0 u eax ce se staviti broj 1 i izaci ce se iz poslednje funkcije kad ta funkcija izadje ovaj deo koda ce se vrteti do kraja pri cemu ce se eax uvek mnoziti sa sacuvanim ebx-om sa stacka :)
Code:
add $4, %esp
pop %ebx #vraćanje vrednosti n sa steka
mull %ebx #n*(n-1)! -> eax
jmp fakt_kraj
fakt_nula:
movl $1, %eax #slučaj n=0
fakt_kraj:
movl %ebp, %esp
pop %ebp
ret
Stek ce ti ovako izgledati (ebx prvo cuvanje ebx pre decl %ebx, arg1 ebx koji se predaje kao argument)
[ebx][arg1][eip][ebp][ebx][arg1][eip][ebp][ebx][arg1][eip][ebp]
Kad funkcija dodje do
mov ebp, esp
pop ebp
sa steka ce se ocistiti ebp
[ebx][arg1][eip][ebp][ebx][arg1][eip][ebp][ebx][arg1][eip]
ret ce pokupiti sacuvan EIP i stack ce izgledati ovako:
[ebx][arg1][eip][ebp][ebx][arg1][eip][ebp][ebx][arg1]
add esp, 4 ce ocistiti [arg1] sa stacka i mozes slobodno da popnes sacuvani ebx
dakle:
[ebx][arg1][eip][ebp][ebx][arg1][eip][ebp][ebx]
pop ebx cisti sacuvani ebx i onda imas sitciju kakvu si i imao malopre :
[ebx][arg1][eip][ebp][ebx][arg1][eip][ebp]
i na kraju kad poslednji izlaz iz funkcije pokupi EIP u izaci ces i iz ove duge rekurzije :)
Nadam se da sam donekle pomogao :)