C++編譯器怎麼實現異常處理2

看了C++編譯器怎麼實現異常處理1    sdssly(翻譯)<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

http://www.csdn.net/Develop/article/15%5C15051.shtm

沒有下文,於是自己去看原文,也翻譯了一部分,只是還是沒有到關鍵部分

函數和堆棧

堆棧是一塊連續的內存,用來保存函數的局部對象。更明確的說,每一個函數都有關聯的棧幀(譯註:stack frame,在調用函數時,進入函數以後第一句應該是push ebp,然後mov ebp,esp,所以ebp一般都指向當前函數進入時的棧頂,而且指向的內容是上一層調用函數進入時棧頂,如此向外,最後找到0,就是系統的入口,這樣一個函數使用的那些棧應該就是一幀)來保存所有的函數局部對象和函數表達式產生的臨時對象(譯註:1.C++裏對象的意義很廣泛,不只是class, 結構,簡單類型也是對象2.臨時對象,學過編譯原理的話應該很清楚,舉個例子,比如有一個函數是int myfun();你在函數中這樣寫int ret = myfun();這樣myfun()返回的結果就放到了ret裏,如果你寫成myfun();而不理它的返回值,你雖然不理它,但是仍然會有它返回值存放的地方,這就是一個臨時的對象,在vc的調試環境了,看auto變量的頁面就可以看到臨時的變量)。請注意上面描述只是很典型的情況。而實際上,編譯器可能會儲存所有或部分的變量到寄存器裏,以便獲得更快的執行速度(譯註:編譯器優化)。堆棧是一個處理器(CPU)級就支持的概念(譯註:之所以這麼說,因爲彙編代碼裏就有push和pop ).處理器提供內部的寄存器和特殊的指令來實現堆棧處理

圖 2 顯示了一個典型的棧,這是當函數foo調用函數bar,然後bar 調用函數widget以後的棧的內容。請注意棧是向下增長的(譯註:平時我在紙上畫棧都是低地址在上,所以作者的這個圖看起來感覺有點怪,但是看懂應該沒有問題),這意味着下一個將要入棧的元素所在的地址將比前一個元素的地址更小(低)。 figure2.gif

編譯器用ESP 寄存器來鑑別當前的棧幀,在上圖所示的情況下,widget時正在執行的函數, EBP寄存器指向了widget的棧幀(就是函數進入時,push了ebp以後的棧頂位置)。函數訪問局部變量都是用局部變量所在的位置相對於幀頂的偏移量。編譯器在編譯的時候就把所有的局部變量從名字變成固定的相對於幀頂的偏移,例如,widget函數訪問它的一個局部變量就用ebp-24來指明它的位置

上圖也顯示了ESP寄存器,在圖示的情況下,它指向了堆棧的最後一項,也就是處於widget幀的尾部,下一幀將從這個位置開始

處理器支持兩種棧操作:push 和 pop:

pop EAX

意味着從esp所在的位置讀4個字節到eax中,然後把esp增加4(32位的處理器下)。同樣的,

push EBP

 

意味着把esp減4,然後把ebp的內容寫到esp指向的地方。

當編譯器編譯一個函數, 它在函數頭部添加一些創建和初始化函數棧幀的代碼,同樣,在函數結尾加上從堆棧裏彈出棧幀的代碼。

典型的,編譯器在函數頭部生成

Push EBP      ; save current frame pointer on stack

Mov EBP, ESP  ; Activate the new frame

Sub ESP, 10   ; Subtract. Set ESP at the end of the frame

 第一句保存當前的幀指針ebp到堆棧裏,第二句通過設置ebp到當前的esp來激活當前的函數幀,.第三句設置esp寄存器到當前幀的尾部,就是把esp減去本函數內的局部對象的總長度。編譯器在編譯的時候就知道有多少的局部對象和每個對象的長度,所以能夠清楚地知道一個函數的幀的確切長度

在函數結束時把當前幀從堆棧中彈出

Mov ESP, EBP   

Pop EBP         ; activate caller's frame

Ret             ; return to the caller

恢復ESP和EBP,然後執行RET

當處理器執行RET指令時,實際上類似執行了一條pop eip,把棧裏保存的EIP彈出,然後跳到EIP處開始執行。相反,call指令執行的時候先把當前的EIP推入堆棧,然後jmp到相應的地址,

3 顯示了運行時堆棧的更多詳細信息。如圖所示,函數參數也是函數幀的一部分,調用函數者把參數推入堆棧,然後函數返回否執行

Add ESP, args_size

或者,採用另一種RET指令,如下

Ret 24

相當於返回後,執行了 ADD ESP , 24

注意沒有進程裏的每隔線程都有它自己的棧

figure3.gif

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章