在移植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