在 x86 架構下,函數調用的棧幀管理離不開三個關鍵寄存器:**EIP(指令指針)**、**EBP(基址指針/棧底)**、**ESP(棧頂指針)**。理解它們的交互過程,是掌握調試技術、棧溢出原理、逆向分析的基石。
void fun(void) { printf("hello world"); }
void main(void) { fun(); printf("函數調用結束"); }
fun() 之前(調用者視角)call fun 指令的下一條指令(即 printf("函數調用結束") 的地址) —— 這是返回地址。main)的棧幀基址。fun() 後(被調用者視角)fun:
push ebp ; 保存調用者 EBP
mov ebp, esp ; 建立新棧幀:EBP = 當前 ESP
sub esp, N ; 分配局部變量空間(N 字節)
... ; 函數體執行
fun 棧幀的固定錨點(棧底),用 [ebp+offset] 訪問參數,[ebp-offset] 訪問局部變量。fun 內部指令。
mov esp, ebp ; 恢復棧頂(丟棄局部變量空間)
pop ebp ; 恢復調用者 EBP
ret ; 彈出返回地址到 EIP,跳轉回調用者
main 中 call fun 之後的指令。cdecl 由調用者 add esp, 4)。高地址 +------------------+ | 調用者局部變量 | ← 舊 EBP 指向這裡 +------------------+ | 保存的 EBP | ← 新 EBP 指向這裡 (fun 入口 push ebp 後) +------------------+ | 返回地址 (EIP) | ← call 指令壓入 +------------------+ | 參數 (如有) | +------------------+ | fun 局部變量 | ← ESP 在此區域動態移動 +------------------+ 低地址
bt 回溯棧幀依賴 EBP 鏈;info registers 觀察三寄存器狀態。-fomit-frame-pointer 會省略 EBP,導致棧回溯困難,調試構建建議保留幀指針。EIP 指引「去哪裡」,EBP 定位「在哪裡」,ESP 管理「用多少」。 三者協同構成了函數調用的時空坐標系,是軟件運行時基礎設施的核心組件。