【C++&彙編】try-catch異常處理機制的彙編實現

C++中支持使用try-catch的語法處理異常,防止程序崩潰。那麼編譯器是如何實現的呢?html

有以下測試代碼:cookie

int main(int argc,char** argv){

	try{
		throw "error";
	}
	catch (char* err){
		err = nullptr;
	}

	return 0;
}

這裏直接在try中拋出異常,程序捕獲這個異常將錯誤信息傳給err,爲了使catch塊不被編譯器忽略,這裏隨便附一個值,順便看看這個nullptr是什麼。函數

編譯出的彙編代碼以下:測試

int main(int argc,char** argv){
//ebp用於定位函數局部變量,先保存ebp,而後移動到棧頂
00A91410  push        ebp  
00A91411  mov         ebp,esp  
//數0xFFFFFFFF和地址0A94EF0壓棧,這個實際上是一個函數的地址(後面有說明)
00A91413  push        0FFFFFFFFh  
00A91415  push        0A94EF0h  
//這裏出現了一個fs寄存器,取fs的0偏移,即獲得「指向SEH鏈指針」(後面說明)
//SEH鏈指針壓棧,ecx壓棧
00A9141A  mov         eax,dword ptr fs:[00000000h]  
00A91420  push        eax  
00A91421  push        ecx  
//分配棧空間
00A91422  sub         esp,0D8h  
//保護現場
00A91428  push        ebx  
00A91429  push        esi  
00A9142A  push        edi  
00A9142B  lea         edi,[ebp-0E8h]  
//清理棧
00A91431  mov         ecx,36h  
00A91436  mov         eax,0CCCCCCCCh  
00A9143B  rep stos    dword ptr es:[edi]  
//這裏把ds:0xA99000(0x6DAAB763,應該是某dword型的標誌)的數據和ebp(棧頂)作異或,將結果保存
00A9143D  mov         eax,dword ptr ds:[00A99000h]  
00A91442  xor         eax,ebp  
00A91444  push        eax  
//這裏ebp-0c顯然是一個SEH鏈指針,由於它被保存到fs:0
00A91445  lea         eax,[ebp-0Ch]  
00A91448  mov         dword ptr fs:[00000000h],eax  
//保存esp是爲了什麼?
00A9144E  mov         dword ptr [ebp-10h],esp  

	try{
//ebp-4這個變量的值很關鍵,進入try就被清0
00A91451  mov         dword ptr [ebp-4],0  
		throw "error";
//直接一個地址0A96858是靜態存儲區"error"字符串的首地址,保存到棧空間,臨時變量無疑
00A91458  mov         dword ptr [ebp-0E4h],0A96858h  
//參數 0A98078 -- 第二個參數比較奇怪
00A91462  push        0A98078h  
//參數 &"error"
00A91467  lea         eax,[ebp-0E4h]  
00A9146D  push        eax  
//調用函數 至關於 __CxxThrowException("error",0x0A98078);
//該函數從名字上能夠略知一二,因爲屢次調用比較複雜,因此就不分析裏面了
00A9146E  call        __CxxThrowException@8 (0A910FAh)  
	}
	catch (char* err){
		err = nullptr;
//能夠看到nullptr就是0
00A91473  mov         dword ptr [ebp-18h],0  
	}
//標籤$LN7位置的指令地址作返回值,返回處理後可能會再次跳到$LN7,而將ebp-4這個變量取反
//可能意味着出現錯誤
00A9147A  mov         eax,0A91489h  
00A9147F  ret  
00A91480  mov         dword ptr [ebp-4],0FFFFFFFFh  
//去return
00A91487  jmp         $LN7+7h (0A91490h)  
$LN7:
00A91489  mov         dword ptr [ebp-4],0FFFFFFFFh  

	return 0;
00A91490  xor         eax,eax

這裏省略最後一個括弧的編譯結果,把重點放在try-catch塊。spa

下面對上面的一些地方進行詳細說明:.net

  1. 地址0A94EF0線程

__ehhandler$_main:
00A94EF0  mov         edx,dword ptr [esp+8]  
00A94EF4  lea         eax,[edx+0Ch]  
00A94EF7  mov         ecx,dword ptr [edx-0ECh]  
00A94EFD  xor         ecx,eax  
00A94EFF  call        @__security_check_cookie@4 (0A9101Eh)  
00A94F04  mov         eax,0A9804Ch  
00A94F09  jmp         ___CxxFrameHandler3 (0A91190h)  
00A94F0E  int         3  
00A94F0F  int         3  
00A94F10  int         3

2. fs寄存器和SEH鏈指針

關於fs寄存器的做用引用一個博客裏面的:code

FS寄存器指向當前活動線程的TEB結構(線程結構)htm

偏移   說明 

000   指向SEH鏈指針 

004   線程堆棧頂部 

008   線程堆棧底部 

00C   SubSystemTib 

010   FiberData 

014   ArbitraryUserPointer 

018   FS段寄存器在內存中的鏡像地址 

020   進程PID 

024   線程ID 

02C   指向線程局部存儲指針 

030   PEB結構地址(進程結構) 

034   上個錯誤號

http://blog.sina.com.cn/s/blog_a5ece79401016os9.html

SEH鏈:

(structured exception handling) 是一種處理程序異常的機制,當程序異常 (例如除零異常,非法存取異常,等等) 發生的時候,系統便會把執行位置切換到thread 的 exception handler。

更多關於SEH機制能夠參考:

http://blog.csdn.net/pofante/article/details/7044028

相關文章
相關標籤/搜索