函數調用時,指令指針(EIP)指向函數地址,棧指針(ESP)和基址指針(EBP)如何變化?函數返回時如何恢復現場?EIP 是否等於 ESP?
CALL func:push ebp ; 保存調用者的 EBP
mov ebp, esp ; 建立新棧幀基址
sub esp, N ; 分配局部變量空間(N 字節)
此時:EBP 指向棧幀基址,ESP 指向棧頂(局部變量區),EIP 指向函數代碼區(不在棧中)。明顯 EIP ≠ ESP,二者分屬代碼段與棧段。
[ebp + offset] 訪問參數(正偏移)。[ebp - offset] 訪問局部變量(負偏移)。mov esp, ebp ; 恢復 ESP(釋放局部變量空間)
pop ebp ; 恢復調用者 EBP
ret ; 彈出返回地址到 EIP,跳轉回調用者下一條指令
| 階段 | EIP | EBP | ESP | 棧內容(從高到低) |
|---|---|---|---|---|
| 調用前 | 調用點 | 調用者基址 | 棧頂 | 參數N...參數1 |
| CALL 後 | 函數入口 | 調用者基址 | 返回地址 | 返回地址、參數N...參數1 |
| 序言後 | 函數代碼 | 新棧幀基址 | 局部變量區頂 | 舊EBP、返回地址、參數...、局部變量 |
| 返回後 | 調用點下一條 | 調用者基址 | 調用前棧頂 | 參數N...參數1(由調用者清理) |