首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C函數調用與棧幀分析:從匯編視角看入棧、出棧與參數傳遞

     編輯:關於C

棧幀基礎:EBP 與 ESP 角色

  • EBP(幀基址指針):固定指向當前棧幀底部,用於相對偏移訪問參數與區域變量
  • ESP(棧頂指針):隨 push/pop/call/ret 動態移動,始終指向棧頂
  • 棧向低位址生長,EBP > ESP

函數調用完整流程(Caller → Callee)

  1. Caller:參數從右至左入棧
  2. Caller:call 指令隱含 push eip(返回地址)
  3. Callee 序言:
    push ebp        ; 保存舊幀基址
    mov  ebp, esp     ; 建立新幀基址
    sub  esp, N       ; 分配區域變量空間(N 為對齊後大小)
  4. Callee 體執行:透過 [ebp+offset] 訪問參數,[ebp-offset] 訪問區域變量
  5. Callee 尾聲:
    mov  esp, ebp     ; 恢復棧頂(釋放區域變量)
    pop  ebp          ; 恢復舊幀基址
    ret               ; 彈出返回地址跳轉
    等價於 leave; ret
  6. Caller:add esp, param_bytes 清理參數(__cdecl 呼叫約定)

實戰:GDB 觀察 swap 調用棧變化


// main.c
void swap(int *a, int *b) { int c = *a; *a = *b; *b = c; }
int main() { int a=16, b=64; swap(&a, &b); return a-b; }

編譯:gcc -g -O0 -fno-omit-frame-pointer -o main main.c

GDB 關鍵斷點與觀察:

(gdb) break main
(gdb) break swap
(gdb) run
(gdb) info frame        // 顯示當前棧幀詳情
(gdb) x/20x $esp        // 檢查棧內容
(gdb) next              // 單步觀察 EBP/ESP 變化

棧幀佈局圖解(swap 被調用時)

高位址
+------------------+
| main 區域變量    |  ← EBP_main
+------------------+
| 返回地址         |  ← call 指令壓入
+------------------+
| swap 參數 b (64) |  ← [EBP_swap+12]
| swap 參數 a (16) |  ← [EBP_swap+8]
+------------------+
| 舊 EBP (main)    |  ← [EBP_swap+0]  ← EBP_swap
+------------------+
| swap 區域變量 c  |  ← [EBP_swap-4]
| ... 對齊填充 ... |
+------------------+  ← ESP_swap
低位址

呼叫約定差異速查

約定參數入棧順序棧清理者典型場景
__cdecl右→左CallerC/C++ 預設,支援可變參數
__stdcall右→左CalleeWindows API
__fastcall前兩參數用寄存器Callee高效能需求

優化對棧幀的影響

  • -fomit-frame-pointer:省略 EBP,ESP 直接偏移訪問,除錯困難
  • -O2 內聯小函數,消除棧幀開銷
  • 尾呼叫優化:重用當前棧幀,避免棧增長
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved