簡體   English   中英

函數聲明 __declspec(naked) 如何存儲局部變量?

[英]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.

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