2012-11-06 45 views
4

我無法理解下面的代碼如何工作。這是一段簡單的代碼,它使用遞歸函數來查找數字的階乘。在這種情況下,4*3*2*1 = 24爲什麼此組件產量爲24而不是4?

.section .data 
.section .text 
.globl _start 
._start: 

pushl $4 
call factorial 
addl $4, %esp 

movl %eax, %ebx 
movl $1, %eax 
int $0x80 

.type factorial, @function 
factorial: 
pushl %ebp 
movl %esp, %ebp 
movl 8(%ebp), %eax 

cmpl $1, %eax 
je end_factorial 
decl %eax 
pushl %eax 
call factorial 
movl 8(%ebp), %ebx 
imull %ebx, %eax 

end_factorial: 
movl %ebp, %esp 
popl %ebp 
ret 

我明白關於代碼的一切,除非我不明白爲什麼執行此部分(25/26行)。

movl 8(%ebp), %ebx 
imull %ebx, %eax 

我的理解(這顯然是錯誤的),是該函數將保持自稱直到%eax值爲1。在這一點上它將乘以%eax這是一個「4」。這將給出4的值,這對於4的階乘是完全錯誤的。然而,當我運行這個時,它確實提供了24的正確輸出。我認爲每次函數都應該執行乘法指令執行,而不是在函數完成調用之後。

有人可以通過代碼並向我解釋爲什麼代碼實際上給出了24的正確答案,而不是我認爲它應該給(4)。

而且每次在函數內部調用該函數時,ebp都會被壓入堆棧,並且會被更改爲esp。 (pushl%ebp Movl%esb,%ebp)。如果是的話,我們如何才能將esp,ebp值恢復到函數末尾的初始值。 (據我所知,pop在end_function中是做的,我們已經多次調用了這個函數,這已經推動了ebp,return,eax等幾次堆棧)。這真是令人困惑,我的組裝邏輯崩潰了。請有人解釋一下它是什麼意思,並說明什麼是堆棧,並在每個點上註冊。

+0

你應該學會使用調試器。這些將允許您逐步瀏覽代碼並觀察發生的情況,並通過指令進行指導。從大多數代碼中剔除它。 –

回答

3

記住,函數的返回值總是進入%eax

的組件,功能經過並調用階乘,由1每次遞減%eax,將其推入堆棧。當%eax是一個時,它最終返回。當%eax爲2時,這將使您回到call factorial的遞歸調用中,該值被存儲在8(%ebp)(回想它被推送)。所以現在你有2 * 1 = 2 = %eax。現在它完成並返回並重復該過程,直到它返回到首先調用factorial的函數。

相關問題