c语言的setjmp和longjmp


    在移植jpglib后,发现当jpeg文件遭到破坏后,解码器内部就会调用默认的错误处理函数,但此函数实际上并    没有真正处理错误,而只简单地做了资源释放,然后调用exit()函数.此函数对于windows的application来说,就是
简单的结束进程.可是对于嵌入式设备来说根本没有exit()函数.

METHODDEF(int)
error_exit (j_common_ptr cinfo)
{
    /* Always display the message */
    (*cinfo->err->output_message) (cinfo);

    /* Let the memory manager delete any temp files before we die */
    jpeg_destroy(cinfo);
    exit(EXIT_FAILURE);
}


    假设简单地注释掉exit(),那么错误没有得到处理,程序继续解码,会出现更多不可预知的错误.如果把error_exit
函数返回某个错误代码,其调用函数检测这个代码,然后一级返回,那要改的地方太多,而且测试很复杂.有没有更
干净利落的方法呢?
    后来想到一个办法,在调用解码器之前,把当前的context保存好,包括堆栈指针,pc值等.在遇到错误的时候,
也就是在error_exit函数中,恢复原来的context,直接返回调用点.但这时程序已经知道产生了错误,可以返回错
误代码给调用者,以告知用户.
    方法很简单,但着手做却遇到不少问题.
    当前的环境是ucos vc版,其中每个task都是windows的一个线程,于是使用GetThreadContext得到当前的环境,
然后在出错的地方SetThreadContext,可是这样做就是不行,在调用SetThreadContext的时候产生无效指针.
    无奈之下看x86 asm,想用内联汇编实现上下文的保存和恢复,由于x86 asm早忘得差不多了,这个过程真可谓复杂,
首先是不知如何取得EIP寄存器的值,找了很久发现似乎EIP是不能直接存取的,只能通过JMP,CALL等跳转方式去改变...
    后来问一网友,他告知标准c有setjmp和longjmp函数可调用,就是实现此功能的.于是急忙去看msdn,真的很简单
   
#include ".h"
jmp_buf contex;
int is_error;

METHODDEF(int)
error_exit (j_common_ptr cinfo)
{
    /* Always display the message */
    (*cinfo->err->output_message) (cinfo);

    /* Let the memory manager delete any temp files before we die */
    jpeg_destroy(cinfo);
    _jpeg_err_ret();
   
   
}

void _jpeg_err_ret(void)
{
    is_error = 1;            //标记错误已发生
    longjmp(contex, -1);    //恢复错误前的context,直接跳到main的setjmp()返回处
}

int main()
{
    is_error = 0;
    setjmp(contex);    //假设其返回一定成功
longjmp_retptr:            // longjmp to here!
    if(is_error)
    {
        //释放资源
        printf("error!/n");
        return 1;
    }
   
    decode_jpeg();
    return 0;
}


    问题已解决了,再来看看setjmp和longjmp是如何实现的,

setjmp()
004E8CA4   mov         edx,dword ptr [esp+4]        //edx 指向参数context
004E8CA8   mov         dword ptr [edx],ebp            // save ebp
004E8CAA   mov         dword ptr [edx+4],ebx        // save ebx
004E8CAD   mov         dword ptr [edx+8],edi        // save edi
004E8CB0   mov         dword ptr [edx+0Ch],esi        // save esi
004E8CB3   mov         dword ptr [edx+10h],esp        // save esp(栈)
004E8CB6   mov         eax,dword ptr [esp]            // 取出返回地址,即上文的longjmp_retptr
004E8CB9   mov         dword ptr [edx+14h],eax
004E8CBC   mov         dword ptr [edx+20h],56433230h
004E8CC3   mov         dword ptr [edx+24h],0
004E8CCA   mov         eax,fs:[00000000]
004E8CD0   mov         dword ptr [edx+18h],eax        //
004E8CD3   cmp         eax,0FFh
004E8CD6   jne         __setjmp3+3Dh (004e8ce1)
004E8CD8   mov         dword ptr [edx+1Ch],0FFFFFFFFh
004E8CDF   jmp         __setjmp3+78h (004e8d1c)
004E8CE1   mov         ecx,dword ptr [esp+8]
004E8CE5   or          ecx,ecx
004E8CE7   je          __setjmp3+4Fh (004e8cf3)
004E8CE9   mov         eax,dword ptr [esp+0Ch]
004E8CED   mov         dword ptr [edx+24h],eax
004E8CF0   dec         ecx
004E8CF1   jne         __setjmp3+57h (004e8cfb)
004E8CF3   mov         eax,dword ptr [eax+0Ch]
004E8CF6   mov         dword ptr [edx+1Ch],eax
004E8CF9   jmp         __setjmp3+78h (004e8d1c)
004E8CFB   mov         eax,dword ptr [esp+10h]
004E8CFF   mov         dword ptr [edx+1Ch],eax
004E8D02   dec         ecx
004E8D03   je          __setjmp3+78h (004e8d1c)
004E8D05   push        esi
004E8D06   push        edi
004E8D07   lea         esi,[esp+1Ch]
004E8D0B   lea         edi,[edx+28h]
004E8D0E   cmp         ecx,6
004E8D11   jbe         __setjmp3+74h (004e8d18)
004E8D13   mov         ecx,6
004E8D18   rep movs    dword ptr [edi],dword ptr [esi]
004E8D1A   pop         edi
004E8D1B   pop         esi
004E8D1C   sub         eax,eax
004E8D1E   ret
004E8D1F   int         3

_longjmp:
004E8B88   mov         ebx,dword ptr [esp+4]        //取出参数context
004E8B8C   mov         ebp,dword ptr [ebx]            //resume ebp
004E8B8E   mov         esi,dword ptr [ebx+18h]        //resume esi
004E8B91   cmp         esi,dword ptr fs:[0]            //
004E8B98   je          _longjmp+1Bh (004e8ba3)
004E8B9A   push        esi
004E8B9B   call        __global_unwind2 (004eafc4)        //-???????????
004E8BA0   add         esp,4
004E8BA3   cmp         esi,0
004E8BA6   je          _longjmp+50h (004e8bd8)
004E8BA8   lea         eax,[ebx+20h]
004E8BAB   push        eax
004E8BAC   call        __rt_probe_read4@4 (004eb0b2)    //-???????????
004E8BB1   or          eax,eax
004E8BB3   je          _longjmp+43h (004e8bcb)
004E8BB5   mov         eax,dword ptr [ebx+20h]
004E8BB8   cmp         eax,56433230h
004E8BBD   jne         _longjmp+43h (004e8bcb)
004E8BBF   mov         eax,dword ptr [ebx+24h]
004E8BC2   or          eax,eax
004E8BC4   je          _longjmp+50h (004e8bd8)
004E8BC6   push        ebx
004E8BC7   call        eax                                //-???????????
004E8BC9   jmp         _longjmp+50h (004e8bd8)
004E8BCB   mov         eax,dword ptr [ebx+1Ch]
004E8BCE   push        eax
004E8BCF   push        esi
004E8BD0   call        __local_unwind2 (004eb006)        //-???????????
004E8BD5   add         esp,8
004E8BD8   push        0
004E8BDA   mov         eax,dword ptr [ebx+14h]
004E8BDD   call        __NLG_Notify (004eb09a)            //-???????????
004E8BE2   mov         edx,ebx
004E8BE4   mov         ebx,dword ptr [edx+4]
004E8BE7   mov         edi,dword ptr [edx+8]
004E8BEA   mov         esi,dword ptr [edx+0Ch]
004E8BED   mov         eax,dword ptr [esp+8]
004E8BF1   cmp         eax,1
004E8BF4   adc         eax,0
004E8BF7   mov         esp,dword ptr [edx+10h]
004E8BFA   add         esp,4
004E8BFD   jmp         dword ptr [edx+14h]
004E8C00   ret
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值