簡體   English   中英

堆棧分配、填充和對齊

[英]Stack allocation, padding, and alignment

我一直試圖更深入地了解編譯器如何生成機器代碼,更具體地說是 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 bytes 產生一個移動了 40 個字節的堆棧指針,並且根本沒有緩沖區移動堆棧指針 8。1 到 16 個字節之間的緩沖區移動ESP 24 個字節。

現在假設 8 個字節是一個必要的常量(它需要什么?),這意味着我們以 16 個字節的塊進行分配。 為什么編譯器會以這種方式對齊? 我使用的是 x86_64 處理器,但即使是 64 位字也只需要 8 字節對齊。 為什么會出現差異?

作為參考,我在運行 10.5 和 gcc 4.0.1 且未啟用優化的 Mac 上編譯它。

這是由-mpreferred-stack-boundary=n控制的 gcc 功能,其中編譯器嘗試將堆棧上的項目與2^n對齊。 如果將n更改為2 ,它只會在堆棧上分配 8 個字節。 n的默認值是4即它會嘗試與 16 字節邊界對齊。

為什么有“默認”的 8 個字節然后 24=8+16 個字節是因為堆棧已經包含了 8 個用於leaveret字節,所以編譯后的代碼必須首先將堆棧調整 8 個字節以使其與 2^4= 對齊16.

SSEx 系列指令要求將 128 位向量打包成 16 字節對齊 - 否則您會在嘗試加載/存儲它們時遇到段錯誤。 即,如果您想安全地傳遞 16 字節向量以在堆棧上與 SSE 一起使用,則堆棧需要始終保持與 16 對齊。默認情況下,GCC 會考慮到這一點。

我找到了這個站點,它在頁面底部有一些關於為什么堆棧可能更大的不錯的解釋。 將這個概念擴展到 64 位機器,它可能會解釋你所看到的。

LWN 有一篇關於內存對齊的文章,你可能會覺得有趣。

Mac OS X / Darwin x86 ABI 需要 16 字節的堆棧對齊。 這在 Linux、Win32、FreeBSD 等其他 x86 平台上並非如此……

有 8 個字節是因為第一條指令將 %ebp 的起始值壓入堆棧(假設為 64 位)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM