MASM32的结构化异常(SEH)宏

这个是以前做的,发在了MASM32论坛上。现在转回到自己的博客上来。。适合32位windows。

这些宏的实现是利用了“函数嵌套函数”方式。在我知道的所有语言里,只有汇编语言里可以实现函数嵌套函数。

另外Linux也有类似的SEH方式,是通过sigsetjmp方式,先把我的旧文章发了再提下。。

==========================================

Hope these macors will help you.
Use these SEH macros,you can use C++ like syntax to catch and handling the exceptions.The syntax like this:

__try exceptionid
	;code snippet which may cause exceptions
__catch exceptionid
	;code snippet will execute when the exception is caught
__finally exceptionid
	;end the exception caught

the exceptionid is programmer defined string and a __try-__catch-__finally block must use the same exceptionid.
The macros will use the exceptionid to define global labels,so different __try-__catch__finally block must use different exception ids.
The __try-__catch-__finally block can be nested like this:

__try e1
	;your code
__catch e1
	__try e2
		;your code
	__catch e2
		;your code
	__finally e2
__finally e1

if you want to throw an exception,the easiest way is read or write null pointer

———————————–SEH macros—————————————-

;SEH macros for masm32

;by hoverlees       2009

;email: me[at]hoverlees.com


comment ~

Hope these macors will help you.

Use these SEH macros,you can use C++ like syntax to catch and handling the exceptions.The syntax like this:

********************************************************************************

__try exceptionid

	;code snippet which may cause exceptions

__catch exceptionid

	;code snippet will execute when the exception is caught

__finally exceptionid 

;end the exception caught

********************************************************************************

the exceptionid is programmer defined string and a __try-__catch-__finally block must use the same exceptionid.

The macros will use the exceptionid to define global labels,so different __try-__catch__finally block must use different exception ids.

The __try-__catch-__finally block can be nested like this:

********************************************************************************

__try e1

	;your code

__catch e1

	__try e2

		;your code

	__catch e2

		;your code

	__finally e2

__finally e1

********************************************************************************

~



IFNDEF IN_HOVERLEES_SEH

IN_HOVERLEES_SEH	equ	1

IFNDEF SEH

SEH struct

	PrevLink			dd ?

	CurrentHandler	dd ?

	SafeOffset		dd ?

	PrevEsp			dd ?

	PrevEbp			dd ?

SEH ends

ENDIF



__try macro exceptionid

		assume fs:nothing

		push fs:[0]

		mov eax,esp

		push fs:[0]

		push ebp

		push eax

		push __finally_&exceptionid

		push __exception_&exceptionid

		push eax

		mov fs:[0],esp

		assume fs:ERROR

endm



__catch macro exceptionid

		add esp,sizeof SEH+4

		jmp __finally_&exceptionid

		__exception_&exceptionid:

		push ebp

		mov ebp,esp

		mov edx,[ebp][12]

		assume edx:ptr SEH

		mov eax,[ebp][16]

		assume eax:ptr CONTEXT

		push [edx].SafeOffset

		pop [eax].regEip

		push [edx].PrevEsp

		pop [eax].regEsp

		push [edx].PrevEbp

		pop [eax].regEbp

endm



__finally macro exceptionid

		mov eax,ExceptionContinueExecution

		pop ebp

		retn 16+sizeof SEH

		__finally_&exceptionid:

		assume fs:nothing

		pop fs:[0]

		assume fs:error

endm

ENDIF

———————————————————————————————

===========================================

linux的SEH例子如下(C语言):

#include <stdio.h>
#include <setjmp.h>
#include <signal.h>

static sigjmp_buf jmpbuf;

void sig_fpe(int signo){
	siglongjmp(jmpbuf,1);
}

int main(int argc, char *argv[]){
	signal(SIGFPE, sig_fpe);
	if (sigsetjmp(jmpbuf,1) == 0){
		int s=1/0;
	}
	else{
		printf("catch exception\n");
	}
}

linux这种方式也是差不多的,按我的理解,signal注册回调函数那儿应该是维护一张全局表,sigsetjmp应该是按下面的步骤走的:

sigsetjmp{

1.保存CPU各寄存器状态,然后把第3步的程序起始地址到jmpbuf中。

2.返回0

3.恢复CPU寄存器状态

4.返回1

}

当CPU出现异常中断时,我们跳到jumpbuf指向的程序地址,恰好又回到了sigsetjump的第三步,然后我们恢复了寄存器状态后就返回1,所以会跳到else段里执行。

我觉得应该是这样,至少同样的接口让我来实现的话,我会设计成这样。呵呵。

if you want to throw an exception,the easiest way is read or write null pointer

Leave a comment

Your email address will not be published. Required fields are marked *