!c++异常的实现_zh

上传人:第*** 文档编号:32801531 上传时间:2018-02-12 格式:DOC 页数:7 大小:46KB
返回 下载 相关 举报
!c++异常的实现_zh_第1页
第1页 / 共7页
!c++异常的实现_zh_第2页
第2页 / 共7页
!c++异常的实现_zh_第3页
第3页 / 共7页
!c++异常的实现_zh_第4页
第4页 / 共7页
!c++异常的实现_zh_第5页
第5页 / 共7页
点击查看更多>>
资源描述

《!c++异常的实现_zh》由会员分享,可在线阅读,更多相关《!c++异常的实现_zh(7页珍藏版)》请在金锄头文库上搜索。

1、http:/ a c+ compiler implements exception handling有人应该知道有这么一个同名的文章介绍 vc 6 怎么实现 c+异常的文章.在这里小弟不才.借用下这个名字,介绍 2003 怎么实现这个技术. 先说这些代码的由来,首先呢 ,你得写一个 c+得程序, 然后选择静态链接,然后用 ida 反汇编就 ok,用 vc 本身作调试器就 ok,softice 这种家伙, 也没有用得必要了 . 当然你也许能发现 eh.obj 这样的文件, 其实代码就在那几个 obj 里面. 要想继续看下去,你得了解 windows 得 seh 技术, 得熟练掌握 32 位汇编

2、,因为这里并没有什么源代码给你看,全部是反汇编得结果 .自然对 c+异常的语法 ,以及 c+异常规范,你必须要有足够的了解才行. 因为我 ida 反汇编以后加上注释的那几个 idb 文件已经不见了, 只是剩下了自己用汇编写的代码,所以这里出现的代码都是 nasm 格式的汇编代码, 同时搭配使用 c32.mac 这个文件,这个文件我有修改增加其宏的功能,名字都很简单明了, 希望那些宏不会对大家的阅读产生障碍. 然后呢,要说说一些基本的概念 . 你应该要知道_stdcall,_cdecl,_thiscall 这些的调用与被调用规则,应该要知道在一个 c函数里面哪些寄存器的值是要保护的,哪些寄存器是

3、不用保护的. 应该要明白 mov fs:0,eax是在干什么,你要明白 windows 的 seh 是怎么完成的. 有了足够的准备以后往下看吧. seh 是 windows 平台上的一种异常处理方式,通过预先安装一个处理函数,到发生异常的时候跳转到处理函数里面的方式完成异常处理,这里不要把_try,_except 等同到 seh,他们只是一种简单的处理模型,并不代表了 seh 本身,seh 本身只是在异常发生的时候跳转到一个函数而已. 当我们写下 throw 0;这样的语句的时候,编译器会为我们产生下面的这些代码 mov ebp-10,0 lea eax,ebp-10 push _TI1H p

4、ush eax call _CxxThrowException8 上面这些代码调用了一个叫_CxxThrowException8 的函数 看它的名字就知道它应该是一个使用 stdcall 调用法则,有两个参数的函数 .它的原型 void _stdcall _CxxThrowException(void *pObject,_s_ThrowInfo const* pThrowInfo) 第一个参数就是 throw 后面的那个 object 的地址, 第二个参数是一个叫 throwInfo 的结构,它的定义如下(能在 vc 的 watch 窗口里面看到,你输入(_s_ThrowInfo*)0 就能看

5、到它的成员定义了) ; throw info struc _s_ThrowInfo .attributes : resd 1 ; properites .pmfnUnwind : resd 1 ; destructor for thrown object .pForwardCompat : resd 1 ; compat handler address .pCatchableTypeArray : resd 1 ; catchable type array endstruc 这个结构定义是使用 nasm 的语法,resd 表示它是 dword 大小的,后面的 1 表示一个 dword. 上面看

6、到的那个_TI1H 就是这个结构. 关于它的几个成员.我后面都有注释 ,唯一要说的就是最后一个成员 ,它表示这个 throw 出来的 object 它能转换成哪些其他的 object 以便被 catch 语句捕获,你应该要知道 catch 语句捕获的原则. _CxxThrowException 函数是一个外部的函数, 它应该由 c+的 lib 提供,它在设置好一些工作以后应该调用 os 提供的 RaiseException 的函数,然后 os 取得控制权, 交到应用程序安装的 seh handler 上面, 那么 vc 为我们安装的那个函数是什么呢? 它会是一个诸如_ehhandler$_ma

7、in:这样的函数 它简单的 mov eax,_TI1H+48h 然后 jmp 到一个叫_CxxFrameHandler 的函数 这个函数原型如下 int _CxxFrameHandler(struct EHExceptionRecord * pExcept,struct EHRegistrationNode * pRN, ; struct _CONTEXT * pContext,void * pDC) 这个函数使用什么样子的调用法则是无关紧要的,因为它要么不返回, 要么 os 会另外的设置esp,所以你使用 cdcel 还是 stdcall 都没有关系,唯一要保证的就是它的名字, 它也应该要由

8、 c+的 lib 提供( 当然我假定你是这个 lib 的提供者). 它使用的几个参数,首先是 eax,它是一个_s_FuncInfo 的指针,然后是一个 EEHExceptionRecord 的指针 ,它其实跟 seh 使用的 ExceptionRecord 差不多,只是 vc 在它里面加入了些其他的成员,剩下的参数也同它一样 ,你应该要知道这些大都是 seh 传递给你的参数,你也应该要知道,他们会在你调用 RaiseException 的时候设置好. 先给出这些结构的定义. ;exception record struc EHExceptionRecord .ExceptionCode :

9、resd 1 ; exception code .ExceptionFlags : resd 1 ; exception flags .ExceptionRecord : resd 1 ; exception record .ExceptionAddress : resd 1 ; exception address .NumberParameters : resd 1 ; number of param .magicNumber : resd 1 ; magic number .pExceptionObject : resd 1 ; exception object pointer .pThr

10、owInfo : resd 1 ; throw info pointer endstruc ;function info struc _s_FuncInfo .magicNumber : resd 1 ; magic number .maxState : resd 1 ; max state in the function .pUnwindMap : resd 1 ; unwind function list .nTryBlocks : resd 1 ; how many try blocks .pTryBlockMap : resd 1 ; try block list endstruc ;

11、registration node struc EHRegistrationNode .pNext : resd 1 ; prev exception registration node .frameHandler : resd 1 ; this frame handler .state : resd 1 ; current state endstruc 上面的几个结构呢.首先要说的是 ExceptionRecord,你应该要知道它里面由一个 Parameters 的数组,vc 使用了里面的 3 个成员, 分别赋予了不同的意思.这个很容易理解. 然后是 RegisterationNode,vc

12、 多加入了一个叫 state 的域,如果你对_try,_except 很熟悉的话,你会会心一笑,他其实跟 tryLevel 差不多,用来表示抛出这个异常时, 程序运行到什么地方了. 至于 function info,他表示的是你当前处于的这个函数的信息,他收集了发生异常的时候必须要完成的操作所需要的信息. 我希望你看到这里的时候还没有头晕,我选择先把这些东西一古老全抖出来然后再解释他的机制的方式,希望你还挺得住 . 到这里,我要描述具体得实现思路了 . vc 实现得 c+异常是一种编译时行为, 并不能归结到运行时行为,他通过编译器收集足够的信息来完成异常处理. 对于每个函数,vc 收集一份他里

13、面的 try 语句的位置信息,catch 语句能 catch 住的 object type 信息,以及每个可能发生异常的情况下要完成的 object destructor 调用的信息,这些信息共同的构成了上面的 function info. 同时 vc 在 throw 语句执行的时候,抓取到(也是在编译时完成的)那个 object 的地址, 收集到这个 obj 能转换的类型(catch 判断的时候有用),然后移交控制权 ,同时 vc 还在运行时候记录当前执行到的语句的位置,这个数据会用来得到当前语句属于哪个 try,当前这个地方要调用哪些 destructor. 看个具体的例子 假设我有定义

14、A,B 两个 class code void test() / 这里设置当前位置为-1,表示不处于任何一个 try 语句里面 try / 这里设置当前位置 0,表示进入了第一个 try 里面 A testA; / 这里设置当前位置 1,表示如果在这里出现了问题, 要调用类 A 的 destructor MayThrowException1; try / 这里设置当前位置 2,表示进入第二个 try B testB; / 这里设置为 3,要调用 B 的 destructor MayThrowException2; /这里会插入 B 类的 ddestructor 调用, 同时设置当前位置为 1,表

15、示退出了第二个 try catch(.) / 这里也会有修改到当前位置的操作,因为在 catch 里面也会定义 c+对象 / 这里同样插入 A 的 destructor 调用,设置当前位置-1 catch(.) /code 这个例子程序非常的简单,大家可以体会下这个当前位置的值的变换情况, 他不仅仅是要表示 try 的位置,也要表示你必须要调用的 destructor 的信息.你也许要问这个当前位置保存到什么地方的?就在那个 EHRegisterationNode 里面,state 就是用来保存这个的, 你应该要知道他的位置就是ebp-4, 这个部分你要熟悉 seh 才能明白为什么是ebp-4

16、 假想这么一个情况,上面的函数发生了一个 c+异常,进入到异常处理函数里面 ,函数通过查看 EHRegisterationNode-state 的值, 得到了当前程序运行的位置,先通过 function info 得到了当前所在的 try block,这个是通过 function info 里面的 try block list 完成的, 他其实是一个数组,每个成员又是一个结构定义如下 ;try block entry struc _s_TryBlockMapEntry .tryLow : resd 1 ; begin state .tryHi : resd 1 ; end state .catchHi : resd 1 ; catch end state .nCa

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 建筑/环境 > 工程造价

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号