[ros-kernel] Macro SEH support, version 2 (Help needed: translating to AT&T assembler syntax)

Steven Edwards steven_ed4153 at yahoo.com
Mon Oct 27 10:57:15 CST 2003


Hello Skywing,
I have forwarded your request to wine-devel also in the event your SEH
implementation might help them.

Thanks
Steven

--- Skywing <skywing at valhallalegends.com> wrote:
> I've done a significant amount of reworking on the macro SEH support
> that I
> introduced on the mailinglist some time ago.  It now passes every
> test I can
> throw at it with flying colors, including interoperating with
> VC-style SEH.
> This includes unwinding and nested exception handlers.  This release
> fixes a
> number of bugs with the original implementation.
> 
> Request for help:  I don't know AT&T assembler, so somebody needs to
> port
> this if it's to be used with MinGW (which is the primary purpose for
> me
> writing it).  Unless somebody is willing to lend a hand with
> GNU-ASM'ing it,
> this will probably not benefit the ReactOS project much.
> 
> I've tried to code this as defensively as possible, so that any code
> in the
> handler or filter areas will properly run without any special
> knowledge
> about the values of the stack/other registers while in an exception
> handler.
> I'm pretty sure that the macros are virtually bulletproof against the
> compiler generating code that doesn't work inside of them, provided
> you
> follow these rules: Enable frame pointer generation.  This is
> absolutely
> crucial to any SEH implementation; without frame pointers, the macros
> will
> fall over and die. Preferably, exit the SEH exception handler with
> fallthrough.  If you must exit it otherwise, you can try using the
> ExceptCleanup() macro before leaving the handler with a return or
> similar
> statement.  Exiting the SEH handler inside the filter expression is
> probably
> a Bad Idea and may not work, as the "panic stack" will be used
> through the
> remainder of the function.
> 
> Additionally, GetExceptionCode() and GetExceptionPointers() should be
> available at the proper scopes.  You ought to get an undefined
> identifier
> error if you try to use them elsewhere.
> 
> The macros work with "heap-based" SEH in order to work around the
> Borland
> patent.  There are some limitations with using this with regular
> Microsoft
> Windows (see below), but it should be no problem to modify ReactOS to
> work
> with this scheme if necessary.
> 
> The semantics for using the macros are as follows:
> TRY
> {
>   try-protected-code;
> }
> EXCEPT(( filter-expression )) /* Note that double parens are needed
> */ {
> handler-code; } EXCEPT_END();
> 
> Issues with "heap-based" SEH:
> The default Microsoft RtlUnwind implementation will not call an
> exception
> handler if the exception registration is not within the threads stack
> limits.  It would be a good idea to ensure that the ReactOS RtlUnwind
> implementation does not have this limitation if we wish to use
> "heap-based"
> SEH and not "stack-based" SEH.
> 
> Issues with the macros and MSVC++:
> The VC compiler crashes if you use if(0) { code; } or goto label; {
> code; }
> label: instead of __asm jmp label; { code; } label; to prevent the
> exception
> handler from being executed by fallthrough.  I think that this is
> because
> the optimizer decides that the exception handler is unreachable and
> removes
> it, despite an existing reference to code in the handler (the label
> for the
> start of the OS-invoked SEH handler function itself).  Later this
> causes the
> compiler to crash, hence my workaround with __asm jmp
> EXCEPT_EndOfExcept.
> 


__________________________________
Do you Yahoo!?
Exclusive Video Premiere - Britney Spears
http://launch.yahoo.com/promos/britneyspears/
-------------- next part --------------
#define ExceptCleanup() { \
	ExFreePool(EXCEPT_ExceptionPointers); \
	__asm { \
	__asm push		eax \
	__asm mov		eax, dword ptr fs:[0x00000000] \
	__asm mov		eax, dword ptr [eax] \
	__asm mov		dword ptr fs:[0x00000000], eax \
	__asm pop		eax \
	} \
}
#define GetExceptionCode() ((DWORD)(EXCEPT_ExceptionCode))
#define GetExceptionPointers()
((PEXCEPTION_POINTERS)(&EXCEPT_ExceptionPointers))

#define EH_NONCONTINUABLE	0x00000001
#define EH_UNWINDING		0x00000002
#define EH_EXIT_UNWIND		0x00000004
#define EH_STACK_INVALID	0x00000008
#define EH_NESTED_CALL		0x00000010
#define EH_UNWIND_CONTEXT	EH_UNWINDING | EH_EXIT_UNWIND

#define _TRY_SAVED_EBP		0x08
#define _TRY_SAVED_EBX		0x0c
#define _TRY_SAVED_ESI		0x10
#define _TRY_SAVED_EDI		0x14
#define _TRY_SAVED_ESP		0x18

#if 0 // Enable if you don't have these in scope
typedef enum {
	ExceptionContinueExecution,
	ExceptionContinueSearch,
	ExceptionNestedException,
	ExceptionCollidedUnwind
} EXCEPTION_DISPOSITION;
#endif

#define TRY { \
	PVOID TRY_ExceptionRegistration = ExAllocatePoolWithTag(PagedPool,
28, ' HES'); \
	volatile DWORD EXCEPT_ExceptionCode; \
	__asm { \
		__asm push		eax \
		__asm push		ecx \
		__asm mov		eax, TRY_ExceptionRegistration \
		__asm mov		ecx, dword ptr fs:[0] \
		__asm mov		dword ptr [eax+0x00], ecx \
		__asm mov		dword ptr fs:[0], eax \
		__asm lea		ecx, EXCEPT_Handler \
		__asm mov		dword ptr [eax+0x04], ecx \
		__asm mov		dword ptr [eax+_TRY_SAVED_EBP], ebp
\
		__asm mov		dword ptr [eax+_TRY_SAVED_EBX], ebx
\
		__asm mov		dword ptr [eax+_TRY_SAVED_ESI], esi
\
		__asm mov		dword ptr [eax+_TRY_SAVED_EDI], edi
\
		__asm mov		dword ptr [eax+_TRY_SAVED_ESP], esp
\
		__asm add		dword ptr [eax+_TRY_SAVED_ESP], 0x08
\
		__asm pop		ecx \
		__asm pop		eax \
	}

#define EXCEPT_LOCALS TYPE CONTEXT + 20
#define EXCEPT_CONTEXT_OFFSET 0
#define EXCEPT_POINTERS_OFFSET TYPE CONTEXT


#ifdef _MSC_VER
#pragma comment(linker, "/INCLUDE:_RtlUnwind at 16")
#endif

#if 0 // Enable if not in scope
// RtlUnwind unwinds procedure call stack frames.
extern "C"
NTSYSAPI
VOID
NTAPI
RtlUnwind(
	IN OUT PVOID TargetFrame OPTIONAL,
	IN PVOID TargetIp OPTIONAL,
	IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
	IN PVOID ReturnValue
	);
#endif

#define EXCEPT(Expression) { __asm { jmp EXCEPT_EndOfExcept} \
	volatile EXCEPTION_POINTERS EXCEPT_ExceptionPointers; \
	EXCEPT_Handler: /* EXCEPTION_DISPOSITION __cdecl
handler(EXCEPTION_RECORD* ExceptionRecord, void* EstablisherFrame, 
CONTEXT*
ContextRecord, void* DispatcherContext) */ \
	__asm { \
		__asm mov		eax, dword ptr [esp+0x04] \
		__asm test		dword ptr
[eax]EXCEPTION_RECORD.ExceptionFlags, EH_UNWIND_CONTEXT | 
EH_NESTED_CALL \
		__asm je		EXCEPT_DoHandler \
\
		__asm xor		eax, eax \
		__asm or		eax, ExceptionContinueSearch \
		__asm ret \
	} \
	EXCEPT_DoHandler: /* Can't define this in inline asm macro + __asm{}
block, or compiler complains. */ \
	__asm { \
		__asm sub		esp, EXCEPT_LOCALS \
		__asm mov		[esp]CONTEXT.Ebp, ebp \
		__asm mov		[esp]CONTEXT.Ebx, ebx \
		__asm mov		[esp]CONTEXT.Edi, edi \
		__asm mov		[esp]CONTEXT.Esi, esi \
		__asm pushfd \
		__asm pop		ecx \
		__asm mov		[esp]CONTEXT.EFlags, ecx \
		__asm mov		ebp, dword ptr
[esp+0x08+EXCEPT_LOCALS] \
		__asm mov		ebp, dword ptr [ebp+0x08] \
		__asm lea		edx, EXCEPT_ExceptionPointers \
		__asm mov		ecx, dword ptr
[esp+0x04+EXCEPT_LOCALS] \
		__asm mov
[edx]EXCEPTION_POINTERS.ExceptionRecord, ecx \
		__asm mov		ecx, dword ptr
[esp+0x0c+EXCEPT_LOCALS] \
		__asm mov
[edx]EXCEPTION_POINTERS.ContextRecord, ecx \
		__asm mov		edx,
[edx]EXCEPTION_POINTERS.ExceptionRecord \
		__asm mov		edx,
[edx]EXCEPTION_RECORD.ExceptionCode \
		__asm mov		EXCEPT_ExceptionCode, edx \
		__asm mov		ebp, dword ptr
[esp+0x0c+EXCEPT_LOCALS] \
		__asm mov		eax, [ebp]CONTEXT.EFlags \
		__asm push		eax \
		__asm popfd	\
		__asm mov		ebp, dword ptr
[esp+0x08+EXCEPT_LOCALS] \
		__asm mov		ebx, dword ptr [ebp+_TRY_SAVED_EBX]
\
		__asm mov		esi, dword ptr [ebp+_TRY_SAVED_ESI]
\
		__asm mov		edi, dword ptr [ebp+_TRY_SAVED_EDI]
\
		__asm mov		ebp, dword ptr [ebp+_TRY_SAVED_EBP]
\
		__asm cld \
	} \
\
	switch( (Expression) ) { \
\
	case EXCEPTION_CONTINUE_SEARCH: \
		ExFreePool(TRY_ExceptionRegistration); \
		__asm { \
			__asm mov		ebp, [esp]CONTEXT.Ebp \
			__asm mov		ebx, [esp]CONTEXT.Ebx \
			__asm mov		edi, [esp]CONTEXT.Edi \
			__asm mov		esi, [esp]CONTEXT.Esi \
			__asm add		esp, EXCEPT_LOCALS \
			__asm xor		eax, eax \
			__asm or		eax, ExceptionContinueSearch
\
			__asm ret \
		} \
\
	case EXCEPTION_CONTINUE_EXECUTION: \
		ExFreePool(TRY_ExceptionRegistration); \
		__asm { \
			__asm mov		eax, dword ptr
[esp+0x08+EXCEPT_LOCALS] \
			__asm push		0 \
			__asm push		0 \
			__asm push
__ret_label_CONTINUE_EXECUTION \
			__asm push		eax \
			__asm call		dword ptr [RtlUnwind] \
		} \
		__ret_label_CONTINUE_EXECUTION: \
		__asm { \
			__asm mov		ebp, [esp]CONTEXT.Ebp \
			__asm mov		ebx, [esp]CONTEXT.Ebx \
			__asm mov		edi, [esp]CONTEXT.Edi \
			__asm mov		esi, [esp]CONTEXT.Esi \
			__asm add		esp, EXCEPT_LOCALS \
			__asm xor		eax, eax \
			__asm or		eax,
ExceptionContinueExecution \
			__asm ret \
		} \
\
	case EXCEPTION_EXECUTE_HANDLER: \
		__asm { \
			__asm pushad \
			__asm pushfd \
			__asm mov		eax, dword ptr
[esp+0x08+0x04+0x20+EXCEPT_LOCALS] \
			__asm push		0 \
			__asm push		0 \
			__asm push		__ret_label_EXECUTE_HANDLER
\
			__asm push		eax \
			__asm call		dword ptr [RtlUnwind] \
		} \
		__ret_label_EXECUTE_HANDLER: \
		 __asm { \
			__asm popfd \
			__asm popad \
		} \
		break; \
\
	default: \
		DPRINT("SEH: Invalid disposition returned from filter
expression!\n"); \
		RtlRaiseStatus(STATUS_INVALID_DISPOSITION); \
\
	} \
\
	__asm { \
		__asm mov		ebp, dword ptr
[esp+0x08+EXCEPT_LOCALS] \
		__asm mov		ebx, dword ptr [ebp+_TRY_SAVED_EBX]
\
		__asm mov		esi, dword ptr [ebp+_TRY_SAVED_ESI]
\
		__asm mov		edi, dword ptr [ebp+_TRY_SAVED_EDI]
\
		__asm mov		esp, dword ptr [ebp+_TRY_SAVED_ESP]
\
		__asm mov		ebp, dword ptr [ebp+0x08] \
	} }



More information about the wine-devel mailing list