Win32结构化异常处理(SEH)探秘(下)
HandlerForException来完成这个工作。根据RtlpExecuteHandlerForException的执行情况,RtlDispatchException或者继续遍历异常帧,或者引发另一个异常。这第二次的异常表明异常处理程序内部出现了错误,这样就不能继续执行下去了。
RtlpExecuteHandlerForException的代码与RtlpExecuteHandlerForUnwind的代码极其相似。你可能会回忆起来在前面讨论展开时我提到过它。这两个“函数”都只是简单地给EDX寄存器加载一个不同的值然后就调用ExecuteHandler函数。也就是说,RtlpExecuteHandlerForException和RtlpExecuteHandlerForUnwind都是 ExecuteHanlder这个公共函数的前端。 ExecuteHandler查找EXCEPTION_REGISTRATION结构的handler域的值并调用它。令人奇怪的是,对异常处理回调函数的调用本身也被一个结构化异常处理程序封装着。在SEH自身中使用SEH看起来有点奇怪,但你思索一会儿就会理解其中的含义。如果在异常回调过程中引发了另外一个异常,操作系统需要知道这个情况。根据异常发生在最初的回调阶段还是展开回调阶段,ExecuteHandler或者返回DISPOSITION_NESTED_EXCEPTION,或者返回DISPOSITION_COLLIDED_UNWIND。这两者都是“红色警报!现在把一切都关掉!”类型的代码。 如果你像我一样,那不仅理解所有与SEH有关的函数非常困难,而且记住它们之间的调用关系也非常困难。为了帮助我自己记忆,我画了一个调用关系图(图十五)。 图十五 在SEH中是谁调用了谁
现在要问:在调用ExecuteHandler之前设置EDX寄存器的值有什么用呢?这非常简单。如果ExecuteHandler在调用用户安装的异常处理程序的过程中出现了什么错误,它就把EDX指向的代码作为原始的异常处理程序。它把EDX寄存器的值压入堆栈作为原始的 EXCEPTION_REGISTRATION结构的handler域。这基本上与我在MYSEH和MYSEH2中对原始的结构化异常处理的使用情况一样。 结论 结构化异常处理是Win32一个非常好的特性。多亏有了像Visual C++之类的编译器的支持层对它的封装,一般的程序员才能付出比较小的学习代价就能利用SEH所提供的便利。但是在操作系统层面上,事情远比Win32文档说的复杂。 不幸的是,由于人人都认为系统层面的SEH是一个非常困难的问题,因此至今这方面的资料都不多。在本文中,我已经向你指出了系统层面的SEH就是围绕着简单的回调在打转。如果你理解了回调的本质,在此基础上分层理解,系统层面的结构化异常处理也不是那么难掌握。 附录:关于 “prolog 和 epilog ” 在 Visual C++ 文档中,微软对 prolog 和 epilog 的解释是:“保护现场和恢复现场” 此附录摘自微软 MSDN 库,详细信息参见:
每个分配堆栈空间、调用其他函数、保存非易失寄存器或使用异常处理的函数必须具有 Prolog,Prolog 的地址限制在与各自的函数表项关联的展开数据中予以说明(请参见异常处理 (x64))。Prolog 将执行以下操作:必要时将参数寄存器保存在其内部地址中;将非易失寄存器推入堆栈;为局部变量和临时变量分配堆栈的固定部分;(可选)建立帧指针。关联的展开数据必须描述 Prolog 的操作,必须提供撤消 Prolog 代码的影响所需的信息。 如果堆栈中的固定分配超过一页(即大 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |