Win32结构化异常处理(SEH)探秘(上)
什么我要在堆栈上建立这个 EXCEPTION_REGISTRATION 结构,而不是使用全局变量,有一个很好的理由。当你使用编译器的 _try/_except 时,编译器也会在堆栈上建立 EXCEPTION_REGISTRATION 结构。我只是向你简要地揭示你使用 _try/_except 时编译器所做的事情。让我们回到 main 函数,下一个 __asm 块是通过把 EAX 寄存器清零(MOV EAX,0),然后把此寄存器的值作为内存地址让下一条指令(MOV [EAX],1)向此地址写入数据而故意引发一个错误。最后一个 __asm 块是清除这个简单的异常处理例程:首先它恢复以前的 FS:[0] 内容,然后它将 EXCEPTION_REGISTRATION 结构记录从堆栈中弹出(ADD ESP,8)。
现在,假设你正在运行 MYSEH.EXE 并会看到所发生的事情。当 MOV [EAX],1 指令执行时,它导致一个数据访问违例。系统察看 TIB 中的 FS:[0] 并找到 EXCEPTION_REGISTRATION 结构指针。此结构中则有一个指向 MYSEH.CPP 中 _except_handler 函数的指针。系统则将四个必须的参数(我在前面描述过这四个参数)压入堆栈并调用 _except_handler 函数。 一旦进入 _except_handler,代码首先通过 printf 指示“哈!这里是我干的!”。接着,_except_handler 修复导致出错的问题。即 EAX 寄存器指向某个不能写入的内存地址(地址 0)。修复方法是在改变 CONTEXT 结构中的 EAX 的值,以便它指向某个允许进行写入操作的位置。在这个简单的程序中,DWORD 变量(scratch)是故意为此而设计的。_except_handler 函数最后一个动作时返回 ExceptionContinueExecution 值,它在标准的 EXCPT.H 文件中定义。 当操作系统看到返回值为 ExceptionContinueExecution。它就认为你已经修复了问题,并且引起错误的指令应该被重新执行。因为我的 _except_handler 函数强制 EAX 寄存器指向合法内存,MOV EAX,1 指令再次执行,函数 main 一切正常。看,这并不复杂,不是吗? 进一步深入 有了前面的最简单的例子,让我们再回过头去填补一些空白。虽然这个异常回调机制很棒,但它并不是一个完美的解决方案。对于稍微复杂一些的应用程序来说,仅用一个函数就能处理程序中任何地方都可能发生的异常是相当困难的。一个更实用的方案应该是有多个异常处理例程,每个例程针对程序的特定部分。不知你是否知道,实际上,操作系统提供的正是这个功能。 还记得系统用来查找异常回调函数的 EXCEPTION_REGISTRATION 结构吗?这个结构的第一个成员,称为 prev,前面我们曾把它忽略掉了。它实际上是一个指向另外一个 EXCEPTION_REGISTRATION 结构的指针。这第二个 EXCEPTION_REGISTRATION 结构可以有一个完全不同的处理函数。然后呢,它的 prev 域可以指向第三个 EXCEPTION_REGISTRATION 结构,依次类推。简单地说,就是有一个 EXCEPTION_REGISTRATION 结构链表。线程信息块的第一个 DWORD(在基于 Intel CPU 的机器上是 FS:[0])总是指向这个链表的头部。 操作系统要这个 EXCEPTION_REGISTRATION 结构链表做什么呢?原来,当异常发生时,系统遍历这个链表以便查找其中的一个EXCEPTION_REGISTRATION 结构,其例程回调(异常处理程序)同意处理该异常。在 MYSEH.CPP 的例子中,异常处理程序通过返回ExceptionContinueExecution 表示它同意处理这个异常。异常回调函数也可以拒绝处理这个异常。在这种情况下,系统移向链表的下一个EXCEPTION_REGISTRATION 结构并询问它的异常回调函数,看它是否愿意处理这个异常。图四显示了这个过程: 图四 查找处理异常的 EXCEPTION_REGISTRATION 结构 一旦系统找到一个处理该异常的某个回调函数,它就停止遍历结构链表。 下面的代码 MYSEH2.CPP 就是一个异常处理函数不处理某个异常的例子。为了使代码尽量简单,我使用了编译器层面的异 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |