亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如題,請問except的參數是什么,求詳解!

如題,請問except的參數是什么,求詳解!

C++ C
慕村225694 2022-02-19 03:02:35
VC++中 __try,____except( EXCEPTION_EXECUTE_HANDLER ) 結構
查看完整描述

2 回答

?
森林海

TA貢獻2011條經驗 獲得超2個贊

SEH:結構化異常處理

結構化異常處理機制提供了一個操作系統,用于優化結構的方案,為客戶提供更強大的程序執行環境。試想一下,你寫程序不用考慮內存訪問錯誤,那里是空指針錯誤,一直在按照程序的邏輯結構來寫,而無需檢查功能是否成功,那將是怎樣愉快的事情(但SEH宣傳的字,并不意味著我的角度來看,這里是沒有義務的語言之際)。

結構化異常處理--- SEH是一個操作系統級別,操作系統(windows平臺為每個線程的基本單元,系統調度線程),以維持一個鏈表異常處理,異常發生時,控制權轉移到手中的操作系統,操作系統根據一定的方式遍歷列表中找到相應的處理函數,進行處理,堆棧展開

用戶模式的線程中運行的操作系統FS寄存器指向線程環境塊(TEB),TEB是一個用戶模式訪問的數據結構,的所謂NT_TIB結構嵌入TIB(線程信息塊)在開幕式上,這的TIB里面保存SEH使用鏈表。

struct_TEB

{

NT_TIBNtTib的;

......

}

structNT_TIB

{

EXCEPTION_REGISTRATION_RECORD * ExceptionList中;

.....

}

structEXCEPTION_REGISTRATION_RECORD

{

EXCEPTION_REGISTRATION_RECORD *下一步;

enum_EXCEPTION_DISPOSITION(*處理器)(_EXCEPTION_RECORD * ExceptionRecord,無效* EstablisherFrame,_context * ContextRecord無效* DispatcherContext);

FS段線程運行點TEB結構可以看出,在下面的匯編代碼里面。

是否發生異常時特定的操作系統,他們做了什么,先說說。 首先,你要了解什么是異常,這個名字以為意,異常是不尋常的地方( - ),CPU遇到異常,將觸發一個中斷,操作系統將取得的(控制具體的,我不能在這里詳細說明),經過一系列必要的措施,以節省現成的,現成的操作系統通過FS指數TEB,工商局之間在ExceptionList然后訪問,處理函數指針,給他打電話的功能,如果函數的返回,檢查函數的返回值,返回值意味著他不能處理這個異常,那么對指數下指針到下一條記錄,重復,鏈表結束,還是沒有人可以處理自動殺這個線程。

處理程序是在哪里呢?在執行的時候安裝的應用程序,你可能已經知道,通常指向一個處理程序稱為功能_except_handler3,從上面看到,這個功能是整個SEH的關鍵,下面詳細介紹此功能。

里面的c語言,其語法是__嘗試SEH ... 。 __except .... __finally構造(具體語法,這里就不詳細介紹),大家都知道,c語言編譯成機器語言,然后由CPU點__嘗試,這樣的結構將被改造成什么樣子像機器語言?和他同行匯編語言是它看起來像它? SEH的,它涉及到地面太多,尤其是內存的布局是非常重要的,所以在這里談論這個轉換的過程。

編譯器遇到__試著結構,他應該知道SEH代碼生成,是EXCEPTION_REGISTRATION_RECORD完成上面的鏈接,

push_except_handler3;這個紀錄

moveax堆棧結構以上,FS:[0];原始記錄

pusheax /> movfs的:[0],ESP

此代碼執行完畢,堆棧又算得了什么呢? (低地址旁邊的地址)

原來的記錄指針| FS:[0]點這里

|現在hanlder |

只是構成了一個記錄結構,也發生被連接到一起的原始清單只是為了滿足操作系統的要求。

了解編譯器如何安排記錄,我們來看看真正的處理程序,相對來說,每個處理程序,做不同的事情,每次嘗試生成的加工處理程序,這將是很麻煩,VC + +實現的,因此該處理程序點相同的功能,但是這一次,處理程序本身設有一個復雜的領域,因為他必須分開當前異常的嘗試,功能,必須建立相應的數據結構去該信息處理程序正確處理。

VC保持一個叫每個函數的數據結構SCOPETABLE的,他記錄功能里面一試。

typedefstruct_SCOPETABLE

{

DWORDpreviousTryLevel ;/ /嘗試列表指針

DWORDlpfnFilter ;/ / __除括號內的代碼地址后立即

DWORDlpfnHandler的;/ / __除外,以下括號內的代碼地址

} SCOPETABLE的,PSCOPETABLE的;

VC在生成的代碼為每個函數生成一個數組的SCOPETABLE,建立sehrecord此表指針也添加到堆棧中,而當前trylevel的也把這樣的,這里面__except_handler3的疊加將能夠訪問這些數據,就能夠妥善處理異常。

首先解釋一下什么是trylevel trylevel標志,標記當前代碼執行的位置,他居然表示嘗試里面。此/>英地= 0 ;/ / trylevel = -1。

__嘗試

{

= 1 ;/ /此代碼,讓trylevel = 0

__嘗試

{

= 2 ;/ /此代碼,讓trylevel = 1

}

__惟(EXCEPTION_EXECUTE_HANDLER)

{

= 3;}

__嘗試

{

I = 4 ;/ /執行這段代碼,讓trylevel = 2

}

__除外(EXCEPTION_EXECUTE_HANDLER)

{

= 5;

}

}

__除外(EXCEPTION_EXECUTE_HANDLER)

{

= 6;

}

請忽略變量i,它是內容存在的代碼里面。

trylevel這是用來標記當前代碼的嘗試里面,這個值作為下標的索引里面SCOPETABLE,SCOPETABLE里面記錄的電流對應的try __除表達,除了處理代碼地址。 SCOPETABLE有prevtrylevel成員,它tryblock聯系起來的搜索進程句柄,如上面的代碼,如果i = 2里面的異常,一試的第一個視圖對應的__除了這trylevel的索引,如果SCOPETABLE不處理,你應該嘗試以外的對應,那就是,I = 6,檢查,但你怎么知道其中嘗試SCOPETABLE的(因為處理函數和過濾函數地址都記錄在表里面)表只是里面的prevtrylevel的的prevtrylevel使用= 0,指數第一嘗試SCOPETABLE,正是我們正在尋找你馬上會想到I = 4對應也等于0里面prevtrylevel的的SCOPETABLE,是的,youareright只要你明白這個事實的一部分,其余的要容易得多。

接下來看看如何實際生成的匯編代碼在功能代碼的開頭這樣

pushebp

movebp的ESP

push0ffffffffh;這里是trylevel了

pushxxxx是,這是SCOPETABLE數組指針

pushfs:[0] /> movfs的:[0],ESP

subebp,20H,這里是不一定圖中,使用的局部變量的函數關系

/ / try語句后相遇,

MOV [EBP-4],1,也許兩個,也許是三個,你應該明白的地方該值是用來做什么的

正如你可以看到,在除了以外的集trylevel SCOPETABLE指針的處理,因為這應該是用于內部處理程序。你可能要怪的處理程序里面如何獲取指針trylevel SCOPETABLE?要看看在內存布局。

[EBP-0] = prevebp

[EBP-4] = trylevel

[EBP-8] = scopetablepointer

[EBP-0C] =處理程序 [EBP-10] = prevregistrationrecord

啊......如果我們有記錄指針向前的訪問將是能夠訪問它們trylevel啊,是的,記錄指針作為參數傳遞給你,這確實是訪問變量的trylevel等方式。

最后一件事,然后進入處理函數的主體,你應該知道GetExceptionInformation GetExceptionCode()函數,你可能會奇怪,MSDN中,他提到,他們只能用在某些的地方,為什么呢?因為他們的代碼實現,很奇怪的實施

的GetExceptionInformation代碼

moveax,[EBP-14]

RET

你應該知道eax中保存的返回函數值,這意味著這個函數只是返回值[EBP-14],它不設置EBP(EBP是函數framepointer的價值,你應該知道EBP-XX多少的情況下是一個函數的局部變量),這意味著它返回一個局部變量的值,調用者。 VC建筑幾乎trylevel的代碼保留這樣的空間,事實上,實行動態中的處理程序將此值設置為指向相應的地址。

ok了,該處理的身體,看看它的幾個參數,首先不用說,操作系統將幫助您填寫的價值觀,你可以使用GetExceptionInformation獲取此信息,第二個是一個void *的參數,其實時,操作系統通過當前registerationrecord地址的話,這是一個非常關鍵的指針的第三不用說,它是一種架構的上下文中的關系。事實上,有時指向SCOPETABLE最后一個參數,但這個參數沒有使用。

這里都是偽代碼的處理程序,在此之前,讓我們看看在處理程序應

處理程序的主要任務是找到合適的__ except語句,檢查它的返回值是HANDLER EXCEPTION_EXECUTE_。 (和當然continueexecute的)要執行除了后面的代碼,否則在繼續搜索,如何去上一試,上面已經很清楚

處理程序處理的情況,開展放松操作系統的處理函數被調用兩次,在第一個參數是一個成員,在里面告訴你這樣做是要找到治療或放松

/ /對比上述布局的起源想想這種結構

struct_EXCEPTION_REGISTRATION

{,

struct_EXCEPTION_REGISTRATION *上一頁;,

無效的(處理器)(PEXCEPTION_RECORD,PEXCEPTION_REGISTRATION,IMessageSource接口16.3.1。 PEXCEPTION_RECORD);

structscopetable_entry * SCOPETABLE;

inttrylevel的;

int_ebp;

明白任務的處理程序,請參閱是實際的代碼。

int__except_handler3(_EXCEPTION_RECORD * pExceptionRecord,EXCEPTION_REGISTRATION * pRegistrationFrame _context

* pContextRecord,無效* pDispatcherContext)

{

LONGtrylevel LONGfilterFuncRet

EXCEPTION_POINTERSexceptPtrs

PSCOPETABLEpScopeTable

CLD / / Clearthedirectionflag的(makenoassumptions!),這是C語言編譯器的默認操作方式

/ / ifneithertheEXCEPTION_UNWINDINGnorEXCEPTION_EXIT_UNWINDbit。

/ /使用isset ... Thisistruethefirsttimethroughthehandler(

/ /非unwindingcase)

/ /檢查是不是要放松

如果(!(pExceptionRecord ExceptionFlags(EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND))) BR /> {

/ /套[EBP-14]的值,記住上面所說的,[EBP-14]把它,這里ExceptionRecord的內部處理程序堆棧 / /所以它的壽命是有限的,處理函數返回時,此不存在,[EBP-14],指針會指向一個未知的領域,MSDN里面限制

/ /功能調用GetExceptionXXX的位置,明白了嗎?

/ / BuildtheEXCEPTION_POINTERSstructureonthestack的,

exceptPtrs.ExceptionRecord = pExceptionRecord;,

exceptPtrs.ContextRecord = pContextRecord;

/ / PutthepointertotheEXCEPTION_POINTERS4bytesbelowthe / / establisherframe.SeeASMcodeforGetExceptionInformation的

/ /想想吧,-4點,到了什么地方?

*(PDWORD),的((PBYTE),的pRegistrationFrame-4)= &exceptPtrs;

/ / Getinitial“trylevel”的價值,看布局,然后看看該結構定義
> trylevel = pRegistrationFrame> trylevel

/ / Getapointertothescopetablearray,

SCOPETABLE = pRegistrationFrame - > SCOPETABLE;

search_for_handler:

( != / TRYLEVEL_NONE * -1 pRegistrationFrame> trylevel * /)

{

/ /如果它是空的,這意味著這是一個finally語句終于用于放松

(pRegistrationFrame的, -> SCOPETABLE [trylevel] lpfnFilter)

{。

PUSHEBP / / SavethisframeEBP

/ /! veryimportant! SwitchtooriginalEBP.Thisis

/ / whatallowsalllocalsintheframetohavethesame。的

/ / valueasbeforetheexceptionoccurred的的

/ / EBP是一個函數,對于執行該功能是非常重要的,在這里是來執行濾鏡(后面括號 / /里面的語句),你必須恢復EBP EBP的值是如何恢復的?上面的代碼可以看到一個movebp,ESP,ESP

/ /這是什么?根據上述的內存布局,一個很好的經驗句話的含義相反,看看在前面的地址字符。

EBP。 =&pRegistrationFrame> _ebp

/ / Callthefilterfunction的聲明,除括號內的檢查返回值被稱為

filterFuncRet的= SCOPETABLE [trylevel]。 ;
POPEBP / / RestorehandlerframeEBP的

(filterFuncRet! = EXCEPTION_CONTINUE_SEARCH)

{

(filterFuncRet <0)/ / EXCEPTION_CONTINUE_EXECUTION
> returnExceptionContinueExecution,;/ /依靠經營系統完整的continueexecution的

/ / Ifwegethere。,EXCEPTION_EXECUTE_HANDLERwasspecified

SCOPETABLE的== pRegistrationFrame - > SCOPETABLE

/ / DoestheactualOScleanupofregistrationframes
> / / Causesthisfunctiontorecurse的

/ /進行放松,操作系統將是以前的處理程序可變registrationrecord的逐一,然后斷開這些記錄鏈

__ global_unwind2 pRegistrationFrame;

BR /> / / Oncewegethere。everythingisallcleanedup,除了

/ / forthelastframe,wherewe'llcontinueexecution

EBP =&pRegistrationFrame> _ebp

/ /操作系統來幫助我們完成以前放松,目前戰績放松做<br / __ local_unwind2的的(pRegistrationFrame trylevel);

/ /調用setjmp / longjmp的支持的代碼

/ /前起落架==“非本地轉到(setjmp的/ longjmpstuff)

__ NLG_Notify(1);/ / EAX == SCOPETABLE的 - > lpfnHandler

/> / / SetthecurrenttryleveltowhateverSCOPETABLEentry的

/ / wasbeingusedwhenahandlerwasfound中的

/ /當前trylevel prevtrylevel顯然,從目前tryblock出自然的。上tryblock是

pRegistrationFrame> trylevel = SCOPETABLE-> previousTryLevel

/ / Callthe_except。的{} block.Neverreturns,的。 BR /> / / gotoexcept聲明,不返回,因為編譯器不產生一個RET代碼

pRegistrationFrame> SCOPETABLE的[trylevel] except語句的最后lpfnHandler();

}

}

SCOPETABLE = pRegistrationFrame> SCOPETABLE的;

trylevel = SCOPETABLE-> previousTryLevel

gotosearch_for_handler;

}

其他/ / trylevel的== {TRYLEVEL_NONE

retvalue == DISPOSITION_CONTINUE_SEARCH;

}

}

}

其他/ / EXCEPTION_UNWINDINGorEXCEPTION_EXIT_UNWINDflagsareset。

{

/ /進行出放松(觸發由__ global_unwind2功能)

PUSHEBP / / SaveEBP的

EBP =與pRegistrationFrame-_ebp / /
__ local_unwind2(pRegistrationFrame TRYLEVEL_NONE)

BR /> POPEBP / / RestoreEBP。

retvalue的== DISPOSITION_CONTINUE_SEARCH;

}

}

在這里不能不提到的編譯器來生成你的代碼看起來

__嘗試

{

= 0;

}

__除外(EXCEPTION_EXECUTE_HANDLER) { BR /> = 1;

}

據推測,在省略EBP-20的地方FS:[0]設置

__嘗試: MOV [EBP -4],0; trylevel = 0

MOV [EBP-18H],ESP ESP保存

MOV [EBP-20H],0;執行i = 0
> jmp__finish; try語句

__ except_filter:

moveax EXCEPTION_EXECUTE_HANDLER返回,

RET

__ except_body:

movesp,[EBP-18H];第一恢復ESP的值,它是一個運行時堆棧

MOV [EBP-20H],1;執行i = 1;

__完成:

MOV [EBP-4] 0FFFFFFFFH trylevel = -1






查看完整回答
反對 回復 2022-02-21
?
繁華開滿天機

TA貢獻1816條經驗 獲得超4個贊

在__excep后面的()中是一個表達式,值可以是:
EXCEPTION_CONTINUE_EXECUTION (–1) 異常被忽略,控制流將在異常出現的點之后,繼續恢復運行。
EXCEPTION_CONTINUE_SEARCH (0) 異常不被識別,也即當前的這個__except模塊不是這個異常錯誤所對應的正確的異常處理模塊。系統將繼續到上一層的try-except域中繼續查找一個恰當的__except模塊。
EXCEPTION_EXECUTE_HANDLER (1) 異常已經被識別,也即當前的這個異常錯誤,系統已經找到了并能夠確認,這個__except模塊就是正確的異常處理模塊??刂屏鲗⑦M入到__except模塊中。

查看完整回答
反對 回復 2022-02-21
  • 2 回答
  • 0 關注
  • 231 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號