我一直在試圖深入理解編譯器如何生成機器代碼,更具體地說,GCC如何處理堆棧。在這樣做的過程中,我一直在編寫簡單的C程序,將它們編譯成彙編語言,並盡我所能瞭解結果。這裏有一個簡單的程序,並輸出它產生:堆棧分配,填充和對齊
asmtest.c
:
void main() {
char buffer[5];
}
asmtest.s
:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
leave
ret
什麼是令人費解的我就是24個字節被分配爲堆棧。我知道,由於處理器如何處理內存,堆棧必須以4爲增量進行分配,但如果是這種情況,我們應該只將堆棧指針移動8個字節,而不是24個。作爲參考,緩衝區爲17字節產生一個移動了40個字節的堆棧指針,並且根本沒有緩衝區移動堆棧指針8.一個包含1到16個字節的緩衝區移動了12個字節。
現在假設8個字節是一個必要的常量(它需要什麼?),這意味着我們以16個字節的塊分配。爲什麼編譯器會以這種方式對齊?我使用的是x86_64處理器,但即使是64位字也只需要8字節對齊。爲何差異?
僅供參考我正在使用gcc 4.0.1運行10.5的Mac上進行編譯,並且未啓用優化。
做了「push%ebp」使esp減少了8個字節嗎?加上ret的8個字節,應該已經與16字節對齊。爲什麼劑量編譯器需要額外的8個字節? – 2013-07-12 07:52:00
哦,我明白了。這是一個32位的機器。抱歉。它應該是ret 4字節+ ebp 4字節+對齊8字節+緩衝區16 – 2013-07-12 13:05:40
當前版本的i386和x86-64 System V ABI需要16B堆棧對齊(在「調用」指令之前),因此函數允許假設那。歷史上,i386 ABI只需要4B對齊。 (有關ABI文檔的鏈接,請參閱https://stackoverflow.com/tags/x86/info)。即使在葉函數(不調用其他函數)時,GCC也會保持'%esp`對齊,當它必須保留任何空間時,這就是發生了什麼。 – 2017-09-07 19:31:02