Share via


x64 堆疊使用方式

RSP 目前位址以外的所有記憶體都會被視為揮發性:OS 或偵錯工具可能會在使用者偵錯會話或中斷處理常式期間覆寫此記憶體。 因此,必須先設定 RSP,才能嘗試讀取或寫入堆疊框架的值。

本節討論區域變數和 alloca 內建函式的堆疊空間配置。

堆疊配置

函式的初構負責配置區域變數的堆疊空間、儲存的暫存器、堆疊參數和暫存器參數。

參數區域一律位於堆疊底部(即使 alloca 已使用),因此在任何函式呼叫期間,它一律會與傳回位址相鄰。 它至少包含四個專案,但一律有足夠的空間來保存任何可能呼叫的函式所需的所有參數。 請注意,即使參數本身從未回到堆疊,也一律會為暫存器參數配置空間;被呼叫者保證已為其所有參數配置空間。 暫存器引數需要住家位址,因此當呼叫的函式需要取得引數清單位址(va_list)或個別引數時,可以使用連續區域。 此區域也提供方便的位置,可在 Thunk 執行期間儲存暫存器引數,並做為偵錯選項(例如,如果引數儲存在初構程式碼中的主位址,在偵錯期間很容易找到這些引數)。 即使呼叫的函式少於 4 個參數,這些 4 個堆疊位置仍由呼叫的函式有效擁有,而且除了儲存參數暫存器值之外,呼叫的函式也可以用於其他用途。 因此,呼叫端可能不會在函式呼叫的堆疊區域中儲存資訊。

如果在函式中動態配置空間 ( alloca ),則必須使用非volatiatile 暫存器做為框架指標,以標記堆疊固定部分的基底,而且該暫存器必須在初構中儲存和初始化。 請注意,使用 時 alloca ,來自相同呼叫端的相同被呼叫端的呼叫可能會有不同的住家位址,以取得其暫存器參數。

堆疊一律會保持 16 位元組的對齊,除了在 prolog 內以外(例如,在推送傳回位址之後),以及特定框架函式類別的函式函式的函式類型 中所 指出的位置除外。

以下是堆疊配置範例,其中函式 A 會呼叫非分葉函式 B。函式 A 的初構已為 B 在堆疊底部所需的所有暫存器和堆疊參數配置空間。 呼叫會推送傳回位址,而 B 的初構會為其區域變數、非揮發暫存器配置空間,以及呼叫函式所需的空間。 如果 B 使用 alloca ,則會在區域變數/非volatile 暫存器儲存區域與參數堆疊區域之間配置空間。

Diagram of the stack layout for the x64 conversion example.

當函式 B 呼叫另一個函式時,傳回位址會推送到 RCX 的主位址下方。

動態參數堆疊區域建構

如果使用框架指標,則選項會以動態方式建立參數堆疊區域。 這目前在 x64 編譯器中尚未完成。

函數類型

基本上有兩種類型的函式。 需要堆疊框架的函式稱為 框架函式 。 不需要堆疊框架的函式稱為 分葉函式

框架函式是配置堆疊空間、呼叫其他函式、儲存非大量暫存器或使用例外狀況處理的函式。 它也需要函式資料表專案。 框架函式需要初構和表結。 框架函式可以動態配置堆疊空間,並採用框架指標。 框架函式具有此呼叫標準的完整功能。

如果框架函式未呼叫另一個函式,則不需要對齊堆疊(在區段 堆疊配置 中參考)。

分葉函式是不需要函式資料表專案的函式。 它無法變更任何非揮發性暫存器,包括 RSP,這表示它無法呼叫任何函式或配置堆疊空間。 允許在堆疊執行時保持未對齊。

malloc 對齊

malloc 保證會傳回適當對齊的記憶體,以儲存任何具有基本對齊且可能符合所配置記憶體數量的物件。 基本對齊 方式是一種對齊方式,小於或等於實作所支援的最大對齊方式,而不需要對齊規格。 (在 Visual C++ 中,這是 或 8 個位元組所需的 double 對齊方式。在以 64 位平臺為目標的程式碼中,它是 16 個位元組。例如,四位元組配置會在支援任何四位元組或更小物件的界限上對齊。

Visual C++ 允許具有 延伸對齊 的類型,也稱為 過度對齊 的類型。 例如,SSE 型 別__m128 __m256 ,以及使用 __declspec(align( n )) where n 大於 8 宣告的型別已擴充對齊方式。 不保證 malloc 界限上的記憶體對齊方式適用于需要延伸對齊的物件。 若要配置過度對齊類型的記憶體,請使用 _aligned_malloc 和相關函式。

alloca

_alloca必須對齊 16 位元組,而且需要另外才能使用框架指標。

如堆疊配置 中所述 ,所配置的堆疊必須包含後續呼叫函式之參數之後的空間。

另請參閱

x64 軟體慣例
align
__declspec