2014-10-01 47 views
1

我已經學習了一會兒的程序集,現在我已經開始掌握它了,但是我似乎無法理解的一件事就是爲什麼我們需要遞減堆棧指針離開漫遊本地變量,來看看下面的代碼:在這個小程序(64位GNU編譯器編譯代碼,AT & T語法)爲什麼我們需要在調用函數時遞減堆棧指針

pushq %rbp 

movq %rsp, %rbp 

subq $48, %rsp 

call __main 
movl $0, -4(%rbp) 
movl $4, -8(%rbp) 
movl -8(%rbp), %edx 
movl -4(%rbp), %eax 
addl %edx, %eax 
movl %eax, -12(%rbp) 
movl -4(%rbp), %edx 
movl -12(%rbp), %eax 
addl %eax, %edx 
movl -8(%rbp), %eax 
addl %edx, %eax 
movl %eax, -16(%rbp) 
addq $48, %rsp 
popq %rbp 
ret 

我可以想象做所有這些,而不需要減少48。我可以使用基指針來將值從堆棧中移出,並且只需要指向相同的位置以準備好彈出ebp並返回。 有人可以澄清爲什麼有必要爲局部變量留下「空間」。 謝謝!! 如果這看起來像一個愚蠢的問題,我很抱歉

回答

2

你想讓你的函數調用的每個函數都必須知道你已經把變量放在堆棧上的位置嗎?

大量的函數調用等功能 - 遞減堆棧指針是你的函數說:「我使用的堆棧此位」的方式


「葉子」的方法 - 即不調用方法其他函數 - 確實可以按照您所建議的樣式編寫 - 因爲沒有其他代碼會自行使用堆棧。

+0

好吧,所以遞減堆棧指針的全部意義在於,當我們調用另一個函數時總是保持遞減ebp,從而爲我們節省了執行如下操作的麻煩:'mov「返回地址」,-52($ ebp)'我們爲新函數插入一個局部變量,並且保持跟蹤每幀的beginig和end(通過推送ebp和遞減esp),是嗎? – user3769877 2014-10-01 07:22:44

-2

它用於記憶功能,它在遞歸函數調用中非常有用。

+2

這不能再模糊或不完整。 – 2014-10-01 07:53:24

0

從堆棧指針中減去一個常量是如何爲局部變量分配空間。編譯器或彙編程序員將知道這些變量的位置,或者是來自rbp的負偏移量,或者是來自rsp的正偏移量(或零偏移量)。你顯示的例子有點奇怪,因爲它執行了多次添加,將結果存儲在堆棧中的局部變量數據中,然後將一個常量返回到堆棧指針,從而有效地釋放了所有這些局部變量(它在eax中留下了一筆款項)。同樣看例子,使用的「最低」地址是rbp-16的4個字節的數據,所以從esp中減去20就足夠了(在這種情況下)。

如果使用類似_alloca()的函數,它會變得更加複雜,因爲它會從堆棧中分配可變數量的內存。

此外,使用rbp是可選的。它在示例代碼中被用作「幀指針」,但是一些編譯器可以選擇禁用幀指針,在這種情況下,編譯器僅使用rsp(或者在32位模式下使用esp)來跟蹤局部變量,釋放使用rbp(或ebp)作爲通用寄存器。

2

如果發生中斷,地址小於RSP的任何事情都是公平的遊戲 - 操作系統會在不詢問您的情況下將其擦除(即替換爲自己的數據)。中斷始終發生。 Ergo - 你必須在RSP或以下保留所有你關心的東西。

此外,調用其他函數推送返回地址。除非RSP上方有空白區域,否則會覆蓋您的數據。

相關問題