[ Zevs85 @ 29.03.2005. 19:53 ] @
Pozdrav...


Da li bi bili ljubazni da mi objasnite princip rada rekurzivnih funkcija preko steka....
Konkretno vezano za faktorijel i Fibonacijeve brojeve.

Unapred zahvalan
[ Vojislav Milunovic @ 29.03.2005. 20:53 ] @
Pa kao i u C i u asm je isto.
Pozivas istu funkciju iz te funkcije :)

recimo:
Code:

proba    proc ja :DWORD
    ;sta god oces
    call proba, eax
    ;sta vec oces
proba endp

[ Zevs85 @ 30.03.2005. 12:25 ] @
:-)
Hvala,ali mene zanima struktura steka pri pozivanju rekurzivne funkcije...
[ Vojislav Milunovic @ 30.03.2005. 14:56 ] @
Pa ako mislis na redosled podataka na steku onda to izgleda slikovito ovako:
U zavisnosti da li koristis EBP da pristupas podacima na steku ili ides diektno preko esp registra imas razliciti prikaz steka: (cita se sa desna na levo jer me mrzi da pisem u vise linija)
1. poziv sa 1 argumentom (bez frame pointera aka ebp)
[arg1][eip]
2. poziv
[arg1][eip][arg1][eip]
3.poziv
[arg1][eip][arg1][eip][arg1][eip]

sa EBP:
1. poziv
[arg1][eip][ebp]
2. poziv
[arg1][eip][ebp][arg1][eip][ebp]
3. poziv
[arg1][eip][ebp][arg1][eip][ebp][arg1][eip][ebp]


itd iitd, ako si na ovo mislio :)
Ako nisi na ovo mislio, onda moras detaljnije da objasnis sta te konkretno zanima :)
[ Zevs85 @ 30.03.2005. 18:47 ] @
Da, to sam pitao, ali i dalje mi neke stvari nisu jasne...

Konkretno problem je: <PODPROGRAM>

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
decl %ebx #n-1
push %ebx #rekurzija
call faktorijel
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


ne razumem neke delove koda, nisam siguran ni da li radi... Studiram racunarstvo i automatiku na FTN-u i to se nalazi u njihovom praktikumu iz arhitekture, a oni (asistenti) kazu da tu sve "sljaka" kako treba!

Nisam razumeo konkretno deo koda posle prvog poziva labela faktorijel... Kad on izlazi iz petlje, jel prolazi kroz naredn redove koda posle poziva...?

Ne znam, ako imas strpljenja da mi iskucas u cemu je fazon....

Unapred u svakom slucaju VELIKO HVALA, i prethodni odgovor mi je znacio....
[ Vojislav Milunovic @ 30.03.2005. 20:52 ] @
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 :)
[ Zevs85 @ 30.03.2005. 23:08 ] @
HVALA TI MNOGO...
Nemam reci, najjaci si....
Pozdrav!
[ Vojislav Milunovic @ 31.03.2005. 12:40 ] @
Nema frke :)