http://blog.chinaunix.net/uid-26606708-id-3073559.html
很不錯的代碼解析和棧分析:http://blog.csdn.net/iterzebra/article/details/6206420
棧的結構:http://www.cnblogs.com/bugman/archive/2011/09/29/2195879.html
關於棧的結構
棧結構(參數入棧順序跟調用方式有關,這裏以C語言默認的CDECL爲例(參數由右向左進入堆棧)):
| ....................| (棧底方向,高位地址)
| 參數3 |
| 參數2 |
| 參數1 |
| 返回地址 |
-| 上一層[EBP] |
| 局部變量2 |
| 局部變量1 |
|.....................| (棧頂方向,低位地址)
棧一直隨着函數調用的深入,一直想棧頂方向壓下去。每次調用函數時候,先壓函數參數(從右往左順序壓),再壓入函數調用下條指令的地址(由call完成)。接着進入調用函數體中先執行pushq %rbp; movq %rsp, %rbp(一般已經由編譯器加入到函數頭中了),接着就是吧函數體中的局部變量壓入棧中。再遇到函數的調用的嵌套則依此類推。(added
by smsong)
pushq %rbp; movq %rsp, %rbp這兩條指令實在大有深意:首先將rbp入棧,然後將棧頂指針rsp賦值給rbp。movq %rsp, %rbp這條指令表面上看是用rsp把原來rbp的值覆蓋了,其實不然——因爲給rbp賦值之前,原rbp值已被壓棧(位於棧頂),而新的rbp又恰恰指向棧頂
此時rbp寄存器就已處於一個很重要的地位,該寄存器中存儲着棧中的一個地址(原rbp入棧後的棧頂),從該地址爲基準,向上(棧底方向)能獲取返回地址、參數值,向下(棧頂方向)能獲取函數局部變量值,而該地址處又存儲着上一層函數調用時的rbp值!
進程的虛擬地址空間
| ....................|
| ....................|
|內核虛擬存儲器| (高位地址)
|用戶棧(運行時創建)|
|共享庫的存儲器的映射區域|
|運行時堆|
|讀/寫數據|
|只讀的代碼和數據|
|未用| (低位地址)
| ....................|
| ....................|