int g(int x) { return x + 3; }
int f(int x) { return g(x); }
int main() { return f(8) + 1; }
程序加載後從 main 開始執行。關鍵節點分析:
call f 時,EIP 指向下一條指令地址(圖中 23)push EIP)f 的入口地址(相當於 mov EIP, f)f 函數體極簡單,直接調用 g 並透傳參數。編譯器可能優化為尾調用,但未優化時會建立獨立棧幀。
g 計算 x + 3,結果放入 EAX(x86 調用約定:返回值在 EAX)leave 指令(等價於 mov esp, ebp; pop ebp),恢復棧幀ret 彈出返回地址跳轉回 ff 同樣將結果傳遞給 main,main 加 1 後返回給操作系統。
| 指令 | 含義 | 棧操作 |
|---|---|---|
call func | 調用函數 | 壓入返回地址,跳轉 |
push ebp | 保存舊棧幀基址 | 棧增長 |
mov ebp, esp | 建立新棧幀基址 | — |
sub esp, N | 分配局部變量空間 | 棧增長 |
leave | 銷毀棧幀 | mov esp, ebp; pop ebp |
ret | 函數返回 | 彈出返回地址到 EIP |
gcc -S 生成匯編代碼(.s 文件)objdump -d 反匯編可執行文件disassemble 查看運行時指令流ebp/esp 變化與參數傳遞位置理解函數調用的棧幀機制,是掌握緩衝區溢出、ROP 攻擊、調試優化代碼等進階技能的基石。