[英]How function declared __declspec(naked) stores local variables?
__declspec(naked) void printfive() {
int i = 5;
printf("%i\n", i);
}
出於某種原因,這段代碼有效,但我不明白i
存儲在哪里? 在調用函數的框架中? 它成為全局變量? 如果它存儲在調用者的幀中,那么編譯器如何知道位移,因為您可以從具有不同幀大小和局部變量的不同函數調用printfive()
。 如果它是全局的,或者像static
東西,我試圖遞歸,我可以看到變量沒有改變,它確實不是真正的局部變量。 但這很明顯,沒有入口代碼(序言)。 好的,我明白了,沒有序言,沒有框架,沒有寄存器更改,但這是值,但是范圍會發生什么? 此說明符的行為是否在任何參考中定義? 這是否是 C++ 標准的一部分? 如果您主要在其中使用asm {}
,這類函數非常棒(或使用 asm 調用它們並希望確保該函數沒有過度優化),但您可以與 C++ 混合使用。 但這有點腦筋急轉彎。
我知道這個話題已經有好幾年了,這是我自己的答案。
由於沒有參考與此主題相關的 Microsoft 文檔,對於那些想了解更多關於 Keltar 所述需要或不需要什么的人, 這里是 Microsoft 文檔,其中解釋了 Keltar 未在此處解釋的大部分內容。
根據 Microsoft 文檔,應該避免使用。
以下規則和限制適用於裸函數:
- 不允許使用 return 語句。
- 不允許使用結構化異常處理和 C++ 異常處理構造,因為它們必須在堆棧幀中展開。
- 出於同樣的原因,禁止任何形式的 setjmp
- 禁止使用 _alloca 函數。
- 為確保在 prolog 序列之前沒有局部變量的初始化代碼出現,函數范圍內不允許初始化局部變量。 特別是C++的聲明
函數范圍內不允許使用對象。 但是,嵌套范圍中可能存在初始化數據。- 不推薦幀指針優化(/Oy 編譯器選項),但它會自動抑制裸函數。
- 您不能在函數詞法范圍內聲明 C++ 類對象。 但是,您可以在嵌套塊中聲明對象。
從 gcc 手冊:
使用此屬性 ... 來指示指定的函數不需要編譯器生成的序言/尾聲序列。 由程序員提供這些序列。 唯一可以安全地包含在裸函數中的語句是沒有操作數的 asm 語句。 應避免使用所有其他語句,包括局部變量的聲明、if 語句等。 裸函數應該用於實現匯編函數的主體,同時允許編譯器為匯編器構造必要的函數聲明。
它不是標准的(以及任何__declspec
或__attribute__
)
當進入或退出一個函數時,編譯器會添加代碼來幫助傳遞或參數。 當一個函數被裸聲明時,會生成非參數變量賦值代碼,如果你想獲取任何一個參數,你將需要直接訪問相關的寄存器或堆棧(取決於ABI定義的調用約定)。
在您的情況下,您沒有將參數傳遞給函數,因此即使函數是裸聲明的,您的代碼也能工作。 如果您想看到差異,請查看反匯編程序。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.