基于孟寧老師的Linux內核分析
1 int g(int x){ 2 int y = x + 3;3 return y;4 }5 6 int f(int x){7 int z = x + 10;8 return g(z);9 }10 11 int main(){12 int a = f(8) + 1;13 return 0;14 }
對于上述源代碼,我們嘗試對其進行分析,先編譯gcc -g -o lab1 lab1.c
(注意計算機系統是32位Linux)。
堆棧能夠干什么
對于C語言來說,32位下,堆棧都能干什么?
- 函數調用,使用call的時候,保存當前EIP的值,然后函數指向完,ret再返回來。
call指令,能夠讓EIP入棧,ret指令讓EIP出棧 - 保存函數局部變量,函數內的局部變量,就是保存在當前函數的棧空間中。
- 傳遞函數參數,參數先被放入棧空間中,然后再執行call指令調用函數(對于32位系統,從右到左依次壓棧),因此來說,函數參數一定是被調用的函數的棧空間上面的(高地址)
另外,函數的返回值,會被保存到EAX中,可能是值,也可能是地址(如果是地址,地址對應的空間就不能是會被銷毀的棧空間,需要是堆空間,或者是暫時不會被銷毀的棧空間)。
指針和引用也可以傳遞返回值,他們是作為參數傳過來的,修改指針指向地址的值,就相當于是傳參了。
關于棧空間的構建與撤銷,其實就兩個重要節點
- 棧底保存EBP的值,ESP作為棧頂,就是棧空間的創建
- 棧空間創建后,隨著函數對ESP的使用,棧空間會各種改變,但是可以一鍵還原會創建棧空間前的狀態,因為EBP一直指向棧底之上的一個位置,先把ESP = EBP,然后把原來的EBP出棧,就達到了復原,這樣一來,這個函數從棧空間來看,就像沒有執行過一樣。而棧空間也會被回收,不能再使用。
存儲2個局部變量: