棧增長方向:高地址 → 低地址(與手動實現的棧相反)。
關鍵寄存器:
ESP(Stack Pointer):棧頂指針,指向當前棧頂EBP(Base Pointer):棧幀基址,固定於函數棧幀內,用於定位參數/局部變量示例代碼:
int foo1(int m, int n) { int p = m*n; return p; }
int foo(int a, int b) {
int c = a+1, d = b+1, e = foo1(c, d);
return e;
}
int main() { int result = foo(3,4); return 0; }
調用約定 __cdecl:參數從右向左壓入。foo(3,4) 先壓 4,再壓 3。
call foo 指令將下一條指令地址(EIP)壓棧,實現函數返回跳轉。
push ebp ; 保存調用者 EBP
mov ebp, esp ; 新 EBP = 當前 ESP
此時棧佈局:
[高地址] ... caller 的棧幀 參數 b (EBP+12) 參數 a (EBP+8) 返回地址 (EBP+4) 舊 EBP (EBP+0) ← 當前 EBP 指向這裡 [低地址]
sub esp, 0xE4 ; 向低地址擴展,一次性預留空間
Debug 模式下編譯器會過度分配並填充 0xCC,變量間隔 8 字節便於調試。
a:[EBP+8]c:[EBP-4](視具體偏移)EBP 鏈向上遍歷mov esp, ebp ; 恢復 ESP
pop ebp ; 恢復舊 EBP
ret ; 彈出返回地址跳轉
__cdecl 由調用者清理參數(add esp, 8)。
x86 棧幀機制以 EBP 為錨點,實現參數/局部變量定址、調用鏈追蹤、上下文保存恢復。理解此過程對調試、逆向、性能分析至關重要。