使用上一篇文章的资料,就可以使用汇编实现异常处理了。下面来看一个例子。
这是一个汇编实现的函数,计算一个数字厨艺另一个数字得到的结果和余数。如果发生了除零错的话,使用异常处理将结果和余数都设置为0。
1 CONSTANT
2 VARIABLE
3 CODE
4
5 //struct{int Quotient;int Remainder;}
6 //__stdcall
7 //divmod(
8 // int Num1,
9 // int Num2)
10 @DIVMOD:
11 PUSH EBP //EBP->[EBP][EIP][Num1][Num2]
12 MOV EBP, ESP
13 PUSH ECX //ESP->[ECX] EBP->
14 SUB ESP, int32 8 //ESP->[Remainder][Quotient][ECX] EBP->
15 @DIVMOD_BEGIN_TRY:
16 PUSH EBP
17 PUSH int32 0
18 PUSH int32 @DIVMOD_END_TRY
19 PUSH int32 @DIVMOD_CATCH
20 PUSH int32 #EXCEPTION_HANDLER
21 FS PUSH int32 [0]
22 FS MOV int32 [0], ESP //FS:[0]->ESP->[Prev][Handler][Catch][EndTry][Unwind][EBP][Remainder][Quotient][ECX] EBP->
23 XOR EDX, EDX
24 MOV EAX, int32 [EBP+8]
25 IDIV int32 [EBP+12]
26 MOV int32 [EBP-12], EDX
27 MOV int32 [EBP-8], EAX
28 @DIVMOD_END_TRY:
29 MOV ECX, int32 [ESP]
30 FS MOV int32 [0], ECX //FS:[0]->Previous Handler
31 ADD ESP, int32 24 //ESP->[Remainder][Quotient][ECX] EBP->
32 JMP @DIVMOD_FINISH_TRY_CATCH
33 @DIVMOD_CATCH:
34 PUSH EBP
35 MOV EBP, ECX
36 XOR EAX, EAX
37 MOV int32 [EBP-12], EAX
38 MOV int32 [EBP-8], EAX
39 MOV EAX, int32 1
40 POP EBP
41 RET
42 @DIVMOD_FINISH_TRY_CATCH:
43 POP EDX //EDX=Remainder
44 POP EAX //EAX=Quotient
45 POP ECX
46 MOV ESP, EBP
47 POP EBP
48 RET int16 8
注释除标明了函数的原型。这个函数接受两个DWORD参数,返回一个包含两个DWORD的struct,使用__stdcall调用方法。上面的函数在进行除法之前向FS:[0]处写入了一个异常处理节点。执行到第22行的时候,可以看到FS:[0]和ESP两个指针指向的数据的内容。于是运行到第25行的IDIV指令。如果正确的话将撤销FS:[0],错误的话不仅要撤销,还要在堆栈预留的地方([Remainder][Quotient],见第14行)写入两个0。
函数执行结束之后,向[Remainder][Quotient]索取内容依次放入EDX和EAX,用第43、44行的两个POP实现。最后结束函数。至于异常处理函数的内容是什么呢?由于过于复杂,我使用C++实现:
1 DWORD RunCatch(void * EstablisherFrame)
2 {
3 typedef DWORD (__fastcall * CatchHandler)(DWORD EBP);
4 CatchHandler Catch=(CatchHandler)((VInt*)EstablisherFrame)[2];
5 return Catch(((VInt*)EstablisherFrame)[5]);
6 }
7
8 DWORD RunUnwind(void * EstablisherFrame)
9 {
10 typedef DWORD (__fastcall * UnwindHandler)(DWORD EBP);
11 UnwindHandler Unwind=(UnwindHandler)((VInt*)EstablisherFrame)[4];
12 if(Unwind)
13 {
14 return Unwind(((VInt*)EstablisherFrame)[5]);
15 }
16 else
17 {
18 return 0;
19 }
20 }
21
22 EXCEPTION_DISPOSITION __cdecl EXCEPTION_HANDLER
23 (
24 struct _EXCEPTION_RECORD *ExceptionRecord,
25 void * EstablisherFrame,
26 struct _CONTEXT *ContextRecord,
27 void * DispatcherContext
28 )
29 {
30 //FS:[0] -> [Prev][Handler][Catch][EndTry][Unwind][EBP]
31 // 0 1 2 3 4 5
32 if(ExceptionRecord->ExceptionFlags==0)
33 {
34 if(RunCatch(EstablisherFrame))
35 {
36 RunUnwind(EstablisherFrame);
37 ContextRecord->Eip=((VInt*)EstablisherFrame)[3];
38 ContextRecord->Ebp=((VInt*)EstablisherFrame)[5];
39 ContextRecord->Esp=(DWORD)EstablisherFrame;
40 return ExceptionContinueExecution;
41 }
42 else
43 {
44 return ExceptionContinueSearch;
45 }
46 }
47 else if(ExceptionRecord->ExceptionFlags & 2)
48 {
49 RunUnwind(EstablisherFrame);
50 return ExceptionContinueSearch;
51 }
52 else
53 {
54 return ExceptionContinueSearch;
55 }
56 }
于是我们分别用10/3和10/0两组数字调用该函数:
1 struct ASM_RESULT
2 {
3 VInt Quotient;
4 VInt Remainder;
5 };
6
7 typedef ASM_RESULT(__stdcall*ASM_DIVMOD)(VInt Num1 , VInt Num2);
8
9 void RunExecutable(VL_AsmProgram* Program , VL_AsmCompiled* Compiled , VL_AsmExecutable* Executable)
10 {
11 VInt Offset=(VInt)Compiled->LabelOffsets[Program->LabelNames.IndexOf(L"@DIVMOD")];
12 ASM_DIVMOD Summer=(ASM_DIVMOD)((VInt)Executable->GetInstruction()+Offset);
13 {
14 ASM_RESULT Result=Summer(10,3);
15 GetConsole()->Write(L"Quotient = "+VUnicodeString(Result.Quotient)+L"\r\n");
16 GetConsole()->Write(L"Remainder = "+VUnicodeString(Result.Remainder)+L"\r\n");
17 }
18 {
19 ASM_RESULT Result=Summer(10,0);
20 GetConsole()->Write(L"Quotient = "+VUnicodeString(Result.Quotient)+L"\r\n");
21 GetConsole()->Write(L"Remainder = "+VUnicodeString(Result.Remainder)+L"\r\n");
22 }
23 }
得到如下结果:
大功告成!
posted on 2009-03-03 00:20
陈梓瀚(vczh) 阅读(2319)
评论(1) 编辑 收藏 引用 所属分类:
JIT