结构化异常处理(seh) (转)

SEH异常之编译器原理探究 这里调用,然后调用入口程序相当于这里才是一个进程开始执行的地方这里有一个call调用,跟进去看看发现有修改fs:[0]的操作,这里就相当于编译器为我们注册了一个异常处理函数这里到里面的里面看一下,这里有一个注册SEH异常处理函数的操作//{int i = 1;return 0;return 0;可以发现线程也是从开始的然后跟进调用可以发现还是注册了一个异常处理函数还是去IDA里面看函数,发现也注册了一个SEH异常的函数。 阅读详情
结构化异常处理(seh)

  毕业的事情终于要搞定了,几个月前就答应要写这么一个文章,现在补上.
  结构化异常处理是一种操作系统提供的机制
,用来优化程序的结构,提供更加健壮的程序执行环境.试想想你写程序不用考虑哪里有个内存访问错误,哪里有个空指针等等一类的错误,一直按照程序的逻辑结构向下写,而不用去检查函数是否成功,这会是多么愉悦的事情(这个乃是seh的宣传词,不代表我的观点,这里完全是无责任应景之语).
  结构化异常处理---seh,是一个操作系统级的概念,操作系统为每个线程(windows平台线程是系统调度的基本单元)维护一个异常处理链表,当有异常发生的时候,控制权转移到操作系统手上,操作系统按照一定的方式遍历这个链表,寻找合适的处理函数,执行处理工作,并且进行堆栈的unwind.
  在user mode的线程运行的时候,操作系统让fs寄存器指向线程的环境块(teb),这个teb是一个user mode可访问的数据结构,在他的开头嵌入一个叫NT_TIB结构的tib(线程信息块),这个tib里面保存着seh要用到的链表.
  struct _TEB
  {
    NT_TIB NtTib;
    ......
  };

  struct NT_TIB
  {
    EXCEPTION_REGISTRATION_RECORD *ExceptionList;
    .....
  };

  struct EXCEPTION_REGISTRATION_RECORD
  {
    EXCEPTION_REGISTRATION_RECORD *Next;
    enum _EXCEPTION_DISPOSITION (*Handler)( _EXCEPTION_RECORD *ExceptionRecord,void * EstablisherFrame,_CONTEXT                              *ContextRecord,void * DispatcherContext);
  };

  在线程运行的时候fs段就指向的是TEB结构.这个能在下面的汇编代码里面看到.
  先具体的说说究竟异常发生的时候操作系统都作了什么吧.
  首先要明白什么是异常,顾名思意,异常就是不寻常的地方(-.-b),cpu在遇到异常的时候,会引发一个中断,操作系统会获取到控制权(具体的情况,我就不能在这里详细的描述了),在经过必要的保存现成等一系列动作以后,操作系统通过fs索引到TEB,也就是TIB,然后访问到ExceptionList,调用他里面的handler函数指针指向的函数,如果函数返回了,就检查函数的返回值,如果返回值表示他不能处理这个异常,那么就通过Next指针索引到下一个record,重复,到了链表的尽头了,还是没有人能处理,就自动的kill掉这个线程.
  
  那那个handler是从哪里来的呢?是应用程序在执行的时候给安装的,也许你已经知道了,那个handler一般都指向了一个叫_except_handler3 的函数,从上面已经看出来了,这个函数是整个seh的关键,下面会详细的介绍这个函数.

  在c语言里面,seh的语法是__try....__except....__finally这样构成的(具体的语法,这里也不详细说了),大家都知道,c语言是会转编译成机器语言,然后由cpu指向的,那这样的一个__try结构都会被转换成什么样子的机器语言呢?和他对等的汇编语言是什么样子的呢?因为seh涉及到太多的底层,特别是内存布局是非常重要的,所以这里必须要讲讲这个转换的过程.

  编译器遇到了一个__try结构,他就知道应该要进行seh代码生成了,也就是要完成上面的那个EXCEPTION_REGISTRATION_RECORD的链接,
  push _except_handler3    ;这个record构造在栈上面
  mov eax,fs:[0]      ;原来的record
  push eax
  mov fs:[0],esp

  这个代码执行完了,堆栈是什么样子的呢?(低地址在上,高地址在下)

  |原来的record指针| fs:[0]指向这里
  |现在的hanlder|   

  正好构成一个record结构,也正好和原来的list连接到了一起.正好满足操作系统的要求.

  看明白编译器怎么安排record以后,我们就要来看真正的handler了,相对的讲,每个handler都要作不同的事情,如果为每个try都生成一份处理的handler的话,会非常的麻烦,所以vc在实现的时候,让handler指向同一个函数,但是这样一来,handler本身的功能实现就复杂了,因为他必须要区分开究竟当前的异常是属于哪个try的,是属于哪个函数的,这就必须要建立适当的数据结构来让handler获取到这份信息,才能进行正确的处理.

  vc为每个函数维护一个叫scopetable的数据结构,他记载着函数里面使用的try的情况.

  typedef struct _SCOPETABLE
  {
    DWORD previousTryLevel;// 上一个try链表指针
    DWORD lpfnFilter;// __except后面的小括号里面的代码地址
    DWORD lpfnHandler;//__except下面的大括号里面的代码地址
  } SCOPETABLE, *PSCOPETABLE;

  vc在生成代码的时候,为每个函数都生成了一份scopetable数组,在建立seh record的时候把这个table的指针也放入到堆栈中,同时把当前的trylevel也放如到了堆栈里面,这样__except_handler3就能访问到这些数据,就能正确的处理异常.

  首先解释下什么是trylevel,trylevel是一个标识,他标记了当前代码执行的位置,他实际上指示了当前位于哪个try里面.
  int i = 0;// trylevel = -1
  __try
  {
    i = 1;//执行这个代码之前,让trylevel = 0
    __try
    {
      i = 2;//执行这个代码之前,让trylevel = 1
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
      i = 3;
    }
    __try
    {
      i = 4;//执行这个代码之前,让trylevel = 2
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
      i = 5;
    }
  }
  __except(EXCEPTION_EXECUTE_HANDLER)
  {
    i = 6;
  }
  请无视i这个变量,它完全是为了代码里面有内容而存在.

  trylevel这个就是用来标记当前代码位于哪个try里面,这个值会作为一个下标索引到scopetable里面,scopetable里面就记录了当前try对应的__except表达式,以及except的处理代码的地址.scopetable里面还有一个prevtrylevel成员,它把try block链接起来了,用于向上搜索处理句柄用,比如上面的代码,如果i=2的try里面发生了异常,首先查看的是它对应的__except,这个能从trylevel索引到scopetable得到,如果没有处理,就应该查看上一个try对应的except,也就是i=6的那个,但是怎么知道这个try所在的scopetable呢(因为处理函数和过滤函数地址都记录在table里面),这个就是prevtrylevel的用处了,刚刚的那个table里面的prevtrylevel = 0,这样就索引到了第一个try的scopetable,正是我们要找的.你马上就会想到,i=4对应的scopetable里面的prevtrylevel也是等于0的,yes,you are right.只要你明白了这个部分的道理,剩下的就容易多了.

  接下来看看真正的汇编代码是怎么生成的.在函数代码的开头,一般是这样的
  push ebp
  mov ebp,esp
  push 0ffffffffh ; 这里就是trylevel了
  push xxxx ;这个就是scopetable数组的指针了
  push __except_handler3
  push fs:[0]
  mov fs:[0],esp
  sub ebp,20h ;这里不一定是这个数字,它跟函数使用的局部变量有关系

  // 以后碰到try语句的话,就
  mov [ebp-4],1;也许是2,也许是3,你应该明白这里的值是干什么用的了吧

  可以看到,除了handler以外还设置了trylevel和scopetable的指针,因为这个要在handler里面使用.你也许要奇怪了,handler里面怎么获取到trylevel和scopetable的指针呢?这个得看看内存布局了.

  [ebp-0] = prev ebp
  [ebp-4] = trylevel
  [ebp-8] = scopetable pointer
  [ebp-0c] = handler
  [ebp-10] = prev registration record

  啊...如果我们有record的指针的话,向前访问就能访问到trylevel他们了呀,yes,record的指针会作为一个参数传递给你的,这个确实就是访问trylevel等等变量的方式.

  在说最后一个事情,然后就进入handler函数本体,你应该知道GetExceptionInformation()跟GetExceptionCode()函数吧,你也许很奇怪msdn里面提到说他们只能使用在某些地方,为什么呢?因为他们实现代码非常的奇怪

  GetExceptionInformation的实现代码
    mov eax,[ebp-14]
    ret
  你应该知道eax是保存函数的返回值的,也就是说这个函数只是返回了[ebp-14]的值,而且它并没有设置ebp的值(ebp是一个函数的frame pointer,你也应该知道,ebp-xx多少情况下是表示了一个函数的局部变量),也就是说它返回的是调用者的某个局部变量的值.呵呵,这里其实跟trylevel差不多的.vc在建立代码的时候保留了这样一个空间,而handler在执行的时候动态的设置了这个值,指向了合适的地址.

  ok,进入handler本体吧,先看它的几个参数,第一个不用说了,操作系统会帮你填充这个值,并且你能用GetExceptionInformation获取到这些信息,第二个是个void*参数,实际上,操作系统把当前的registeration record地址传递给了你,这个是一个很关键的指针,第三个也不用多说,它是一个跟体系结构有关系的context.最后一个参数有些时候其实也指向了scopetable,不过这个参数并没有使用到.

  下面给出handler的伪代码,在这之前,我们先看看handler都要作些什么.

  handler主要的任务就是要查找合适的__except语句,检查它的返回值,如果是EXCEPTION_EXECUTE_HANDLER(当然还有continue execute)的话就要执行except后面的代码,否则的转到上一个继续搜索,至于怎么转到上一个try,上面已经说得很清楚了.
  handler还要处理一种情况,就是进行unwind.操作系统会两次得调用你得handler函数,在第一个参数得某个成员里面告诉你要作的是查找处理还是进行unwind.

  // 对比上面的布局想想这个结构的由来
   struct _EXCEPTION_REGISTRATION
   {
    struct _EXCEPTION_REGISTRATION *prev;
    void (*handler)(PEXCEPTION_RECORD,PEXCEPTION_REGISTRATION,PCONTEXT,PEXCEPTION_RECORD);
    struct scopetable_entry *scopetable;
    int trylevel;
    int _ebp;
   };

  明白了handler的任务以后,看它实际的代码吧.
  int __except_handler3(_EXCEPTION_RECORD * pExceptionRecord,EXCEPTION_REGISTRATION * pRegistrationFrame,_CONTEXT     
              *pContextRecord,void * pDispatcherContext )
  {
    LONG filterFuncRet
    LONG trylevel
    EXCEPTION_POINTERS exceptPtrs
    PSCOPETABLE pScopeTable

    CLD // Clear the direction flag (make no assumptions!),这个是c语言编译器默认的操作方式

    // if neither the EXCEPTION_UNWINDING nor EXCEPTION_EXIT_UNWIND bit
    // is set... This is true the first time through the handler (the
    // non-unwinding case)

    // 检查是不是要进行unwind
    if ( ! (pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) )
    {
      // 设置[ebp-14]的值,记得上面说的[ebp-14]放的是什么么,这里的ExceptionRecord是在handler的堆栈里面的
      // 所以它的生存期是有限的,handler函数返回了,这个就不存在了,[ebp-14]这个指针也就指向了未知区域了,所以msdn里面限制
      // 了GetExceptionXXX函数的调用地点,明白了么?
      // Build the EXCEPTION_POINTERS structure on the stack
      exceptPtrs.ExceptionRecord = pExceptionRecord;
      exceptPtrs.ContextRecord = pContextRecord;

      // Put the pointer to the EXCEPTION_POINTERS 4 bytes below the
      // establisher frame. See ASM code for GetExceptionInformation
      // 想想看,-4指向了什么地方?
      *(PDWORD)((PBYTE)pRegistrationFrame - 4) = &exceptPtrs;

      // Get initial "trylevel" value,看看布局再看看上面那个结构的定义
      trylevel = pRegistrationFrame->trylevel

      // Get a pointer to the scopetable array
      scopeTable = pRegistrationFrame->scopetable;

search_for_handler:

      if ( pRegistrationFrame->trylevel != TRYLEVEL_NONE/*-1*/ )
      {
        // 如果是空,就表示这个是一个finally语句,finally是用来作unwind的
        if ( pRegistrationFrame->scopetable[trylevel].lpfnFilter )
        {
           PUSH EBP // Save this frame EBP

           // !!!Very Important!!! Switch to original EBP. This is
           // what allows all locals in the frame to have the same
           // value as before the exception occurred.
           // ebp是一个函数的frame pointer,对于一个函数的执行非常的重要,这里既然是要执行filter(except后面小括号
           // 里面的语句),就必须要恢复ebp的值,ebp是怎么恢复的呢?,上面的代码里面可以看到是一个mov ebp,esp,这个esp又
           // 是什么呢?对比下上面的内存布局,好好体会这句话的含义,看清楚前面有个取地址符.
           EBP = &pRegistrationFrame->_ebp

           // Call the filter function调用except小括号里面的语句,检查这个返回值
           filterFuncRet = scopetable[trylevel].lpfnFilter();

           POP EBP // Restore handler frame EBP

           if ( filterFuncRet != EXCEPTION_CONTINUE_SEARCH )
           {
             if ( filterFuncRet < 0 ) // EXCEPTION_CONTINUE_EXECUTION
               return ExceptionContinueExecution; // 依靠操作系统完成continue execution

             // If we get here, EXCEPTION_EXECUTE_HANDLER was specified
             scopetable == pRegistrationFrame->scopetable

             // Does the actual OS cleanup of registration frames
             // Causes this function to recurse
             // 进行unwind,操作系统会变量当前registration record以前的handler一一调用他们,然后断开这些record链表
             __global_unwind2( pRegistrationFrame );

             // Once we get here, everything is all cleaned up, except
             // for the last frame, where we'll continue execution
             EBP = &pRegistrationFrame->_ebp

             // 操作系统帮我们完成前面的unwind,当前record的unwind要自己来完成
             __local_unwind2( pRegistrationFrame, trylevel );

             // 这里是setjmp/longjmp支持代码
             // NLG == "non-local-goto" (setjmp/longjmp stuff)
             __NLG_Notify( 1 ); // EAX == scopetable->lpfnHandler

             // Set the current trylevel to whatever SCOPETABLE entry
             // was being used when a handler was found
             // 修改当前的trylevel为prevtrylevel,很显然,从当前的try block出来了自然就到了上一个try block
             pRegistrationFrame->trylevel = scopetable->previousTryLevel;

             // Call the _except {} block. Never returns.
             // goto except语句,这里并不返回,因为编译器并没有在except语句最后生成一个ret代码
             pRegistrationFrame->scopetable[trylevel].lpfnHandler();
           }
         }

         scopeTable = pRegistrationFrame->scopetable;
         trylevel = scopeTable->previousTryLevel

         goto search_for_handler;
       }
       else // trylevel == TRYLEVEL_NONE
       {
          retvalue == DISPOSITION_CONTINUE_SEARCH;
       }
     }
   }
   else // EXCEPTION_UNWINDING or EXCEPTION_EXIT_UNWIND flags are set
   {
     // 进行unwind(由__global_unwind2函数触发)
     PUSH EBP // Save EBP
     EBP = &pRegistrationFrame->_ebp // Set EBP for __local_unwind2

     __local_unwind2( pRegistrationFrame, TRYLEVEL_NONE )

     POP EBP // Restore EBP

     retvalue == DISPOSITION_CONTINUE_SEARCH;
   }
 }

  这里也不能不提到编译器为你生成代码的样子

  __try
  {
    i = 0;
  }
  __except(EXCEPTION_EXECUTE_HANDLER)
  {
    i = 1;
  }

  这里假设i放在 ebp-20的地方,同时省略fs:[0]的设置

__try:
  mov [ebp-4],0 ; trylevel = 0
  mov [ebp-18h],esp ; 保存esp
  mov [ebp-20h],0 ; 执行i = 0
  jmp __finish ; 跳出try语句
__except_filter:
  mov eax,EXCEPTION_EXECUTE_HANDLER ; 返回
  ret
__except_body:
  mov esp,[ebp-18h] ; 首先恢复esp值,也就是回复运行栈
  mov [ebp-20h],1 ; 执行 i = 1;
__finish:
  mov [ebp-4],0ffffffffh ; trylevel = -1

  到这里差不多我要讲的就结束了,更为详细的可以参考我多次提到的msj里面的那个文章.
  http://www.microsoft.com/msj/0197/exception/exception.aspx
  如果你对vc生成的代码更加的感兴趣,你可以使用ida+softice动态静态跟踪看看.
深入研究Win32结构化异常处理(SEH总结篇) 深入研究Win32结构化异常处理(SEH总结篇) 本文假设你熟悉WIN32,C/C++。引言: 本文是在《Win32 结构化异常处理(SEH)探秘》基础上做的更新总结。探索MS C/C++编译器和MS核心DLL在操作系统SEH上的不同扩展,逐个分析其内部采用的数据结构及处理流程。 摘要:     Win32 结构化异常处理其核心是操作系统提供的服务,特定的编 阅读详情

相关推荐

深入解析结构化异常处理(SEH)

尽管以前写过一篇SEH相关的文章《关于SEH的简单总结》, 但那真的只是皮毛,一直对Windows异常处理的原理似懂非懂, 看了下面的文章 ,一切都豁然开朗.  1997年文章,Windows技术的根一直没变: http://www.microsoft.com/msj/0197/exception/exception.aspx Matt Pietrek 著   董岩 译   在Win32操作系统...

CherishPrecious的博客 673

SEH及逆向调试

SEH 文章目录SEH1. 异常处理方法正常运行的异常处理调试运行的异常处理2. 常见异常EXCEPTION_ACCESS_VIOLATIONEXCEPTION_BREAKPOINTEXCEPTION_ILLEGAL_INSTRUCTIONEXCEPTION_INT_DIVIDE_BY_ZEROEXCEPTION_SINGLE_STEP3. SEH详细说明回调函数ExceptionRecordEs...

Starr 3465

IDA_ARM_Unwind:IDA插件,调试手臂时展开堆栈跟踪

IDA ARM Unwind Plugin 功能 使用 IDA 调试 arm 调试时,打印实时的栈回溯。 IDA 的菜单栏有一处功能:Debugger -> Debugger windows -> Stack trace (Ctrl + Alt + S),在调试 x86、x64、arm64 的程序时它的功能是正常的,在调试 arm 程序时它的功能是不正常的,表现出来栈回溯缺失和栈回溯错误。本质上因为 arm 使用的是自己搞的一套 arm exception handler abi,由 .arm.exidx 和 .arm.extab 描述;而其他 cpu 使用的是 dwarf,由 .eh_frame 描述,IDA 没有针对它做处理。本文使用 idapython 实现这个缺失的功能。 用法 1. 安装 pyelftools >= 0.27 当前最新版是0.26,该版本暂不提供 arm ehab

破解笔记1——SEH

     对于SEH(Structured Exception Handling)结构化异常处理的初步理解:是在CPU指令层次上给程序设计者提供异常处理,C++中的_try{}_except{}结构不过是在高层对SEH的包装。从总体上来说SEH是一个异常处理回调函数的链表,以线程基本单位,每个线程拥有自己的SEH处理链,出现异常时可以顺着SEH链依次调用异常处理函数,直到找到适合的处理函数

haungrui的专栏,水底深呼吸 1803

STC8H8K64U ADC采样实战:从蜂鸣器控制到电压测量(附完整代码)

本文以STC8H8K64U单片机为核心,通过两个实战案例详细讲解ADC采样的应用。首先介绍如何利用ADC采样值动态控制蜂鸣器响度,实现模拟PWM效果;其次深入探讨高精度外部电压测量的方法,包括硬件连接、两点校准技巧以及软件滤波,旨在帮助开发者从理论到实践全面掌握ADC功能。

weixin_29159441的博客 558

STM32G474 FDCAN滤波器配置与多ID接收实战

本文详细介绍了STM32G474 FDCAN滤波器配置与多ID接收实战,重点解析了掩码过滤和范围过滤两种模式的工作原理及配置步骤。通过实际项目案例展示了如何高效配置多个滤波器实现多ID报文接收,并提供了接收FIFO配置与中断处理的优化策略,帮助开发者提升CAN通信系统的稳定性和实时性。

happy2的博客 875

Exploit writing tutorial part 7 : Unicode – from 0×00410041 to calc

Finally … after spending a couple of weeks working on unicode and unicode exploits, I’m glad and happy to be able to release this next article in my basic exploit writing series : writing exploits for

I'm a hack---- 3534

因果推断--PSM的原理和应用(二)

上一篇介绍了DID,本文介绍和DID可一起搭配使用的一种因果推断方法PSM。在正式介绍PSM之前,先来简单回顾一下为什么需要因果推断以及如何做因果推断。我们都知道相关非因果,比起相关我们更希望知道两个事件之间的因果关系,有了确切的因果关系,才能知道对A如何操作才能引起B的变化。解决因果推断问题,目前主要有两种框架,Rubin虚拟事实模型和Pearl因果图模型。站在数据分析的角度上,Rubin虚拟事实模型更容易理解,其核心思想是寻找恰当的对照组。

baidu_26137595的博客 1万+

深入解析结构化异常处理(SEH) - by Matt Pietrek

深入解析结构化异常处理(SEH) - by Matt Pietrek

dvlinker的技术专栏 5万+

麒麟系统下PaddleOCR的离线部署实战:从环境搭建到模型优化

本文详细介绍了在国产麒麟操作系统上离线部署百度PaddleOCR的完整实战流程。从系统环境准备、Conda虚拟环境搭建,到PaddlePaddle框架和PaddleOCR的离线安装,再到预训练模型的本地部署与优化技巧,提供了全面的文字识别解决方案。重点解决了离线环境下依赖包管理、模型量化加速等核心问题,并附带了批量处理与内存监控的进阶代码,适用于对数据安全有严格要求的政务、金融等场景。

docker7nomad的博客 963

电子产品的老化测试有哪些类型?

因此,越来越多的人在寻找“已知合格的测试连接器”,即经过测试具有可靠性和有效性的测试连接器,可以在老化测试中制定优化方法。例如对于芯片来说,不同的封装有不同的老化测试座,QFP老化测试座,QFN老化测试座等。老化测试时,专用老化电路板上的元件将承受等于或高于其额定工作条件的压力,以消除任何在额定寿命之前过早失效的元件。静态老化:在此类系统中,将测试设备安装到老化板上的插座中,然后放入老化箱中,其中每隔12至24小时施加电源和高温。动态老化:在动态老化系统中,设备以老化速度设定的最大速率进行测试。

软件技术的专栏 1839

SEH结构化异常处理

Matt Pietrek 著董岩 译Victor 转载自 Xfocus 并整理在所有 Win32 操作系统提供的机制中,使用最广泛的未公开的机制恐怕就要数结构化异常处理(structured exception handling,SEH)了。一提到结构化异常处理,可能就会令人想起 _try、_finally 和 _except 之类的词儿。在任何一本不错的 Win32 书中都会有对 SEH 详

hackwaly的专栏 5209

从URDF到Gazebo:一个完整的ROS2机械臂仿真与运动控制实战指南

本文提供了一个完整的ROS2机械臂仿真与运动控制实战指南。详细讲解了从URDF建模、ROS2 Control配置到Gazebo物理仿真的全流程,重点介绍了如何利用MoveIt2快速搭建高级运动规划系统,并解决实际部署中的常见问题,帮助开发者高效、安全地进行机器人算法验证与开发。

red88的博客 573

结构化异常处理SEH

结构化异常处理(seh)(Z)毕业的事情终于要搞定了,几个月前就答应要写这么一个文章,现在补上.结构化异常处理是一种操作系统提供的机制, 用来优化程序的结构,提供更加健壮的程序执行环境.试想想你写程序不用考虑哪里有个内存访问错误,哪里有个空指针等等一类的错误,一直按照程序的逻辑结构 向下写,而不用去检查函数是否成功,这会是多么愉悦的事情(这个乃是seh的宣传词,不代表我的观点,这里

rageliu的专栏 1294

从理论到实践:基于Zemax的高分辨率生物显微镜光学系统仿真与优化指南

本文详细介绍了基于Zemax的高分辨率生物显微镜光学系统仿真与优化全流程。从阿贝分辨率公式、柯勒照明等理论基础出发,逐步讲解Zemax建模、像差优化、制造可行性分析等核心步骤,并提供常见问题解决方案。通过实际案例展示如何将理论设计转化为可制造的优化方案,帮助工程师掌握从仿真到实际应用的关键技术。

weixin_29229989的博客 481

第二天 原来Labview语言结构也挺自然(2.1 顺序结构)

新建项目文件StructureTest.lvproj,新建四个子VI(FlatSequence.vi、CaseStructure.vi、LoopStructure.vi、EventStructure.vi),具体新建流程可以参考1.2节。

weixin_38637405的博客 1004

SEH(结构化异常处理)

内容回顾: 当用户异常产生后,内核函数KiDispatchException并不是像处理内核异常那样在0环直接处理,而是修正3环EIP为KiUSerExceptionDispatcher函数后就结束了。 这样,当线程再次回到3环时,将会从KiUserExceptionDispatcher函数开始执行。 KiUserExceptionDispatcher会调用RtlDispatchException函数来查找并调用异常处理函数,查找的顺序: 先查全局链表:VEH 再查句柄链表:SEH 它是与线程有关的,

寻梦&之璐 6019

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

SEH异常处理

 SEH异常处理学习总结 - ToBeroOTer的专栏 - 优快云Blog 收藏 导读: 前一段时间,在看异常处理一章内容的时候,发现这一部分还真的挺有尿水:)所以上网搜了一下有关内容,呦嗬,还挺丰富的。当然有些自己还是看不懂,现在就将这些宝贝拿出来跟大家共享一下。首先我们看一下使用异常处理的几种情况:A. 用来处理非致命的错误B. 对API函数的参数合法性的检验(假设参数都是合法的,只有

liwei8703的专栏 2913

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

对于结构化异常处理(SEH)的进一步探索

导读:对于结构化异常处理(SEH)的进一步探索 本文关键字:SEH, _except_handler3, Windows, VisualC

xu的blog 2460

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

5.SEH(结构化异常处理)

当用户异常产生后,内核函数KiDispatchException并不是像处理内核异常那样在0环直接进行处理,而是修正3环EIP为KiUserExceptionDispatcher函数后就结束了。 这样,当线程再次回到3环时,将会从KiUserExceptionDispatcher函数开始执行。 KiUserExceptionDispatcher会调用RtIDispatchException函数来查...

My classmates 1402

SEH——Structured Exception Handling(结构化异常处理)

SEH是windows操作系统处理程序错误或异常的技术。SEH是一种系统体制,与具体的程序设计语言无关,但是windows下的编译器多使用SEH实现异常处理。     系统级别的SEH比较好理解,利用fs:[0]处保存的异常处理回到函数链表对异常进行处理。从这里也可以看出异常是和线程相关的。因为fs:[0]指向的位置是TEB而TEB所包含的的TIB的第一个成员是EXCEPTION_REGISTR

dayenglish的专栏 1917

什么是 c++的结构化异常处理 SEH

SEH是Windows平台上处理系统级异常的有效工具,适合处理硬件异常和系统错误。尽管功能强大,但使用时需注意其平台依赖性和性能影响。

抟土成人祖,炼石补青天。眼中览银河,手可摘星辰。 687

Win32 结构化异常处理(SEH)探秘

<br /><br /><br />Win32 结构化异常处理(SEH)探秘<br />原著:Matt Pietrek<br /><br /><br />原文出处:A Crash Course on the Depths of Win32? Structured Exception Handling<br />下载源代码<br />本文假设你熟悉 C++,Win32 <br />摘要 <br />  Win32 结构化异常处理其核心是操作系统提供的服务,你能找到的关于 SEH 的所有文档都是描述一个特定的编

Never fall behind 761
上一篇: 利用seh进行错误处理(转)
下一篇: c++对象内存布局(转)
evers
博客等级 码龄24年 7粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值