[英]Why does the x86-64 GCC function prologue allocate less stack than the local variables?
[英]Why does GCC on x86-64 insert a NOP inside of a function?
給定以下C函數:
void go(char *data) {
char name[64];
strcpy(name, data);
}
x86-64上的GCC 5和6編譯(普通gcc -c -g -o
后跟objdump
)這個:
0000000000000000 <go>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 50 sub $0x50,%rsp
8: 48 89 7d b8 mov %rdi,-0x48(%rbp)
c: 48 8b 55 b8 mov -0x48(%rbp),%rdx
10: 48 8d 45 c0 lea -0x40(%rbp),%rax
14: 48 89 d6 mov %rdx,%rsi
17: 48 89 c7 mov %rax,%rdi
1a: e8 00 00 00 00 callq 1f <go+0x1f>
1f: 90 nop
20: c9 leaveq
21: c3 retq
GCC是否有任何理由在1f
處插入90
/ nop
,或者只是在未啟用優化時可能發生的副作用?
注意:這個問題與大多數其他問題不同,因為它詢問函數體內的nop
,而不是外部填充。
測試的編譯器版本:GCC Debian 5.3.1-14(5.3.1)和Debian 6-20160313-1(6.0.0)
這很奇怪,我從來沒有注意過-O0
之前的asm輸出中的雜散nop
。 (可能是因為我不浪費時間查看未優化的編譯器輸出)。
通常nop
的內部函數是對齊分支目標,包括像Brian鏈接的問題中的函數入口點。 (另請參閱gcc文檔中的 -falign-loops
,默認情況下在-Os
之外的優化級別處啟用)。
在這種情況下, nop
是裸空函數的編譯器噪聲的一部分:
void go(void) {
//char name[64];
//strcpy(name, data);
}
push rbp
mov rbp, rsp
nop # only present for gcc5, not gcc 4.9.3
pop rbp
ret
在Godbolt Compiler Explorer中查看該代碼,以便您可以檢查asm是否有其他編譯器版本和編譯選項。
(技術上不是噪聲,但-O0
啟用-fno-omit-frame-pointer
,並且-O0甚至空函數設置並拆除堆棧幀。)
當然,該nop
不存在於任何非零優化級別。 問題中的代碼中的nop
沒有調試或性能優勢。 (請參閱x86標記wiki中的性能指南鏈接,尤其是Agner Fog的微體系結構指南 ,了解在當前CPU上使代碼快速運行的原因。)
我的猜測是它純粹是gcc內部的神器 。 這nop
是有作為nop
在gcc -S
ASM輸出,而不是作為一個.p2align
指令。 gcc本身不計算機器代碼字節,它只是在某些點使用對齊指令來對齊重要的分支目標。 只有匯編程序知道實際需要多大的nop
才能達到給定的對齊。
默認的-O0
告訴gcc你希望它快速編譯而不是編寫好的代碼。 這意味着asm輸出會告訴您更多關於gcc內部的信息,而不是其他-O
級別,而關於如何優化或其他任何內容的信息很少。
如果您正在嘗試學習asm,那么查看-Og
處的代碼會更有趣(例如,針對調試進行優化)。
如果您正在嘗試查看gcc或clang在編寫代碼時的表現,那么您應該查看-O3 -march=native
(或-O2 -mtune=intel
,或者您構建項目的任何設置)。 然而,在-O3
進行的優化令人費解是學習一些asm技巧的好方法。 -fno-tree-vectorize
如果你想要看到除此之外完全優化的非矢量化版本,那么它很方便。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.