2009-12-21 51 views
26

忽略幀指針有什麼實質性的優化嗎? 如果我已經通過閱讀this頁正確理解,當我們想要避免保存,設置和恢復幀指針時,使用。什麼時候應該省略幀指針?

這是否僅對每個函數調用完成,如果是這樣,是否真的值得爲每個函數避免幾條指令? 是不是微不足道的優化。 除調試限制外,使用此選項的實際含義是什麼?

我整理了以下的C代碼使用和不使用此選項

int main(void) 
{ 
     int i; 

     i = myf(1, 2); 
} 

int myf(int a, int b) 
{ 
     return a + b; 
} 

# gcc -S -fomit-frame-pointer code.c -o withoutfp.s 
# gcc -S code.c -o withfp.s 

diff -u「荷蘭國際集團的兩個文件揭示了以下彙編代碼:


--- withfp.s 2009-12-22 00:03:59.000000000 +0000 
+++ withoutfp.s 2009-12-22 00:04:17.000000000 +0000 
@@ -7,17 +7,14 @@ 
     leal 4(%esp), %ecx 
     andl $-16, %esp 
     pushl -4(%ecx) 
-  pushl %ebp 
-  movl %esp, %ebp 
     pushl %ecx 
-  subl $36, %esp 
+  subl $24, %esp 
     movl $2, 4(%esp) 
     movl $1, (%esp) 
     call myf 
-  movl %eax, -8(%ebp) 
-  addl $36, %esp 
+  movl %eax, 20(%esp) 
+  addl $24, %esp 
     popl %ecx 
-  popl %ebp 
     leal -4(%ecx), %esp 
     ret 
     .size main, .-main 
@@ -25,11 +22,8 @@ 
.globl myf 
     .type myf, @function 
myf: 
-  pushl %ebp 
-  movl %esp, %ebp 
-  movl 12(%ebp), %eax 
-  addl 8(%ebp), %eax 
-  popl %ebp 
+  movl 8(%esp), %eax 
+  addl 4(%esp), %eax 
     ret 
     .size myf, .-myf 
     .ident "GCC: (GNU) 4.2.1 20070719 

可能有人請灑在上面的代碼中-fomit-frame-pointer的實際上確實賺差價的關鍵光點?

編輯:objdump的輸出與gcc -S取代的

+2

用-S編譯再次嘗試diff。比較彙編語言:它會更具可讀性。 –

+0

@理查德:完成!感謝您指出! – PetrosB

+0

相關,請參見[ARM:鏈接寄存器和幀指針](http://stackoverflow.com/q/15752188)。 – jww

回答

24

允許一個額外的寄存器可用於一般用途。我認爲這對32位x86來說真的只是一個大問題,這對於寄存器來說是有點匱乏的。*

有人會希望看到EBP不再保存和調整每個函數調用,並且可能還有一些額外的用途的正常代碼的EBP,並且在EBP被用作通用寄存器的情況下,堆棧操作更少。

你的代碼太簡單了,看不到這種優化的好處 - 你沒有使用足夠的寄存器。此外,您尚未打開優化程序,可能需要查看其中一些效果。

* ISA寄存器,而不是微架構寄存器。

+0

如果我必須明確設置其他優化選項,此選項的意義是分開的嗎?儘管你的觀點認爲我的代碼很簡單! – PetrosB

+0

此選項是獨立的,因爲它對調試有很大的缺點。 –

+0

它是獨立的,因爲它具有其他功能的含義,如在調試器中運行代碼或與其他代碼鏈接。我認爲即使優化器關閉,你也會看到註冊溢出的減少,但是由於我不確定我在對衝我的投注。 –

9

忽略它的唯一缺點是調試要困難得多。

主要優點是有一個額外的通用寄存器可以在性能上有很大的不同。顯然,這個額外的寄存器只在需要的時候使用(可能在你非常簡單的功能中它不是);在某些功能上,它比其他功能更有用。

+1

它不僅使調試更加低效。 Gnu docsonline說它使調試不可能 – PetrosB

+16

他們錯了。例如,printf()調試(** IS **仍在調試)是非常有可能的。 –

+8

無論使用何種編譯器選項,您仍然可以在指令(彙編語言)級別進行調試。並不像源代碼級調試那麼容易,但「不可能」絕對是錯誤的詞。 –

4

分析您的程序,看看是否有重大差異。

接下來,描述您的開發過程。調試更容易還是更困難?你花更多時間開發還是更少?

沒有分析的優化是浪費時間和金錢。

+0

我希望downvoters會留下一個解釋。 –

7

您可以經常使用-S參數輸出大會得到GCC更有意義的彙編代碼:

$ gcc code.c -S -o withfp.s 
$ gcc code.c -S -o withoutfp.s -fomit-frame-pointer 
$ diff -u withfp.s withoutfp.s 

GCC不關心的地址,所以我們可以比較直接產生的實際指令。爲了您的葉函數,這給:

myf: 
-  pushl %ebp 
-  movl %esp, %ebp 
-  movl 12(%ebp), %eax 
-  addl 8(%ebp), %eax 
-  popl %ebp 
+  movl 8(%esp), %eax 
+  addl 4(%esp), %eax 
    ret 

GCC不會產生代碼幀指針壓入棧,這改變了傳遞到堆棧上的函數參數的相對地址。

相關問題