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

VC++ 函數呼叫慣例深度解析:__cdecl vs __stdcall 組合語言層面對比

     編輯:關於VC++

兩大呼叫慣例核心差異

特性__cdecl (C/C++ 預設)__stdcall (WINAPI/CALLBACK/類別成員)
參數壓棧順序右到左右到左
棧平衡責任呼叫者被呼叫者
支援可變參數是否
名稱修飾前綴 `_`前綴 `_` + 後綴 `@n` (位元組數)

__cdecl 反組譯碼逐行解析


// void Input(int &m, int &n);
00401068  lea eax, [ebp-8]    ; 取 n 位址
0040106B  push eax            ; 壓棧第 2 參數
0040106C  lea ecx, [ebp-4]    ; 取 m 位址
0040106F  push ecx            ; 壓棧第 1 參數
00401070  call @ILT+5(Input)  ; 呼叫函數
00401075  add esp, 8          ; 呼叫者平衡棧 (2*4=8 位元組)

觀察記憶體:ebp-8 儲存 `n` 位址,ebp-4 儲存 `m` 位址,驗證「引用實為指標」且「右到左壓棧」。

__stdcall 反組譯碼對比


// void WINAPI Input(int &m, int &n);
; 呼叫端相同壓棧序列
00401068  lea eax, [ebp-8]
0040106B  push eax
0040106C  lea ecx, [ebp-4]
0040106F  push ecx
00401070  call @ILT+5(Input)
; 呼叫端無 add esp 指令!

; 函數內部結尾:
004011DE  mov esp, ebp
004011E0  pop ebp
004011E1  ret 8               ; 被呼叫者以 ret 8 平衡棧

關鍵差異:ret 8 直接在返回指令完成棧平衡,呼叫端無需額外指令。這也是為何 __stdcall 不支援可變參數——被呼叫者無法預知參數總大小。

實務應用場景

  • Windows API:全系採用 __stdcall (定義為 WINAPI/CALLBACK),確保二進位相容
  • DLL 匯出函數:建議統一 __stdcall,避免呼叫端語言差異導致棧損壞
  • 類別成員函數:MSVC 預設 __stdcall (thiscall 變體),this 指標通過 ECX 傳遞
  • 回調函數:必須與註冊端約定一致,否則棧不平衡導致崩潰

除錯技巧

  1. 檢視 Registers 視窗 確認 ESP/EBP 變化
  2. Memory 視窗 輸入 ebp-8、ebp-4 觀察實際參數內容
  3. 對比 call 後是否有 add esp, n 判斷呼叫慣例

範例環境:VC6.0 Debug 模式 Win32 Console 專案反組譯碼。理解呼叫慣例是混合語言開發、DLL 介面設計、逆向分析的基礎功夫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved