Supersedes r38084. Take three

modified   include/reactos/libs/pseh/pseh2.h
modified   lib/pseh/framebased-gcchack.c
modified   lib/pseh/i386/framebased-gcchack.S
   Disassemble trampolines in the library, instead of the macros. Results in better, smaller code. As a side effect, PSEH no longer requires a trampoline for nested functions - which results in even better, even smaller code in many common cases where the nested functions don't use any variables from the containing function
   Simulate a no-op setjmp so that GCC correctly handles variables in registers, instead of surprise-corrupting random variables in random conditions
   Save EBP and ESP every time a _SEH2_TRY/_SEH2_EXCEPT is entered, instead of only the first time. Probably not entirely correct yet
   Don't generate a nested function for a _SEH2_EXCEPT() filter expression if the value is a compile-time constant: convert the value to (void *)0, (void *)1 or (void *)-1, and set that as the filter, instead (like Visual C++ does, incidentally)
   If a _SEH2_EXCEPT() filter expression is a compile-time constant evaluating to EXCEPTION_CONTINUE_EXECUTION or EXCEPTION_CONTINUE_SEARCH, allow GCC to optimize out the body of the _SEH2_EXCEPT (because it'd be unreachable). This should really result in a compile-time warning, but #pragma message is unsupported in GCC 4.1.3
   Let _SEH2_EXCEPT() accept a comma expression as filter expression (e.g. _SEH2_EXCEPT(MessageBox(...), EXCEPTION_EXECUTE_HANDLER) instead of _SEH2_EXCEPT((MessageBox(...), EXCEPTION_EXECUTE_HANDLER)))
   Small optimizations in PSEH library
   Clean up GCC hacks
   Remove currently unused PSEH 3 hacks

svn path=/trunk/; revision=38197
This commit is contained in:
KJK::Hyperion 2008-12-20 13:05:57 +00:00
parent 5866c97424
commit e6f465bb78
3 changed files with 139 additions and 112 deletions

View file

@ -46,8 +46,7 @@ typedef struct __SEH2Frame
{ {
_SEH2Registration_t SF_Registration; _SEH2Registration_t SF_Registration;
volatile struct __SEH2TryLevel * volatile SF_TopTryLevel; volatile struct __SEH2TryLevel * volatile SF_TopTryLevel;
void * volatile SF_FramePointer; struct _EXCEPTION_POINTERS * volatile SF_ExceptionInformation;
void * volatile SF_StackPointer;
volatile unsigned long SF_Code; volatile unsigned long SF_Code;
} }
_SEH2Frame_t; _SEH2Frame_t;
@ -55,9 +54,10 @@ _SEH2Frame_t;
typedef struct __SEH2TryLevel typedef struct __SEH2TryLevel
{ {
volatile struct __SEH2TryLevel * ST_Next; volatile struct __SEH2TryLevel * ST_Next;
void * ST_FramePointer;
void * ST_Filter; void * ST_Filter;
void * ST_Body; void * ST_Body;
void * volatile ST_Ebp;
void * volatile ST_Esp;
} }
_SEH2TryLevel_t; _SEH2TryLevel_t;
@ -120,32 +120,40 @@ void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
#define __SEH_PRETEND_SIDE_EFFECT (void)0 #define __SEH_PRETEND_SIDE_EFFECT (void)0
/* Forces GCC to consider the specified label reachable */ /* Forces GCC to consider the specified label reachable */
#define __SEH_USE_LABEL(L_) __asm__ __volatile__("# %0\n" : : "i" (&&L_)) #define __SEH_USE_LABEL(L_) if(__SEH_VOLATILE_FALSE) goto L_;
/* Makes GCC pretend the specified label is reachable, to silence warnings */ /* Makes GCC pretend the specified label is reachable, to silence warnings */
#define __SEH_PRETEND_USE_LABEL(L_) (void)(&&L_) #define __SEH_PRETEND_USE_LABEL(L_) (void)(&&L_)
/* Forces GCC to emit the specified nested function as a function */
#define __SEH_USE_NESTED_FUNCTION(F_) (void)(&F_) /* __attribute__((noinline)) seems to do the trick */
/* Soft memory barrier */ /* Soft memory barrier */
#define __SEH_BARRIER __asm__ __volatile__("#":::"memory") #define __SEH_BARRIER __asm__ __volatile__("#":::"memory")
/* GCC doesn't know that this equals zero */ /* GCC doesn't know that this equals zero */
#define __SEH_ZERO ({ int zero = 0; __asm__ __volatile__("#" : "+g" (zero)); zero; }) #define __SEH_VOLATILE_ZERO ({ int zero = 0; __asm__ __volatile__("#" : "+g" (zero)); zero; })
#define __SEH_FALSE __builtin_expect(__SEH_ZERO, 0) /* GCC believes this is setjmp */
#define __SEH_TRUE __builtin_expect(!__SEH_ZERO, 1) #define __SEH_PRETEND_SETJMP() (_SEH2PretendSetjmp(), 0)
#define __SEH_VOLATILE_FALSE __builtin_expect(__SEH_VOLATILE_ZERO, 0)
#define __SEH_VOLATILE_TRUE __builtin_expect(!__SEH_VOLATILE_ZERO, 1)
#define ___SEH_STRINGIFY(X_) # X_
#define __SEH_STRINGIFY(X_) ___SEH_STRINGIFY(X_)
static
__inline__
__attribute__((returns_twice))
__attribute__((always_inline))
void _SEH2PretendSetjmp(void)
{
}
#define __SEH_FORCE_NEST \ #define __SEH_FORCE_NEST \
__asm__ __volatile__("#%0" : : "r" (&_SEHFrame)) __asm__ __volatile__("#%0" : : "r" (&_SEHFrame))
#define __SEH_NESTED_PROLOG \ #define __SEH_DECLARE_EXCEPT_PFN(NAME_) int (__cdecl * NAME_)(void)
__SEH_FORCE_NEST; #define __SEH_DECLARE_EXCEPT(NAME_) int __cdecl NAME_(void)
#define __SEH_DEFINE_EXCEPT(NAME_) int __cdecl NAME_(void)
#define __SEH_DECLARE_EXCEPT_PFN(NAME_) int (__cdecl * NAME_)(void *)
#define __SEH_DECLARE_EXCEPT(NAME_) int __cdecl NAME_(void *)
#define __SEH_DEFINE_EXCEPT(NAME_) int __cdecl NAME_(void * _SEHExceptionPointers)
#define __SEH_DECLARE_FINALLY_PFN(NAME_) void (__cdecl * NAME_)(void) #define __SEH_DECLARE_FINALLY_PFN(NAME_) void (__cdecl * NAME_)(void)
#define __SEH_DECLARE_FINALLY(NAME_) void __cdecl NAME_(void) #define __SEH_DECLARE_FINALLY(NAME_) void __cdecl NAME_(void)
@ -155,21 +163,19 @@ void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
#define __SEH_RETURN_FINALLY() return #define __SEH_RETURN_FINALLY() return
#define __SEH_BEGIN_TRY \ #define __SEH_BEGIN_TRY \
if(!__SEH_PRETEND_SETJMP()) \
{ \ { \
__label__ _SEHBeginTry; \
__label__ _SEHEndTry; \ __label__ _SEHEndTry; \
\ \
__SEH_USE_LABEL(_SEHBeginTry); \ __SEH_PRETEND_USE_LABEL(_SEHEndTry); \
__SEH_USE_LABEL(_SEHEndTry); \
\ \
_SEHBeginTry: __SEH_SIDE_EFFECT; \
{ \ { \
__SEH_BARRIER; __SEH_BARRIER;
#define __SEH_END_TRY \ #define __SEH_END_TRY \
__SEH_BARRIER; \ __SEH_BARRIER; \
} \ } \
_SEHEndTry: __SEH_SIDE_EFFECT; \ _SEHEndTry:; \
} }
#define __SEH_SET_TRYLEVEL(TRYLEVEL_) \ #define __SEH_SET_TRYLEVEL(TRYLEVEL_) \
@ -188,21 +194,14 @@ void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
#define __SEH_BEGIN_SCOPE \ #define __SEH_BEGIN_SCOPE \
for(;;) \ for(;;) \
{ \ { \
__label__ _SEHBeginScope; \
__label__ _SEHEndScope; \
\
_SEHBeginScope: __SEH_SIDE_EFFECT; \
\
const int _SEHTopTryLevel = (_SEH2ScopeKind != 0); \ const int _SEHTopTryLevel = (_SEH2ScopeKind != 0); \
_SEH2Frame_t * const _SEHCurFrameP = _SEH2FrameP; \ _SEH2Frame_t * const _SEHCurFrameP = _SEH2FrameP; \
volatile _SEH2TryLevel_t * const _SEHPrevTryLevelP = _SEH2TryLevelP; \ volatile _SEH2TryLevel_t * const _SEHPrevTryLevelP = _SEH2TryLevelP; \
__attribute__((unused)) int _SEHAbnormalTermination; \
\ \
(void)_SEHTopTryLevel; \ (void)_SEHTopTryLevel; \
(void)_SEHCurFrameP; \ (void)_SEHCurFrameP; \
(void)_SEHPrevTryLevelP; \ (void)_SEHPrevTryLevelP; \
\
__SEH_USE_LABEL(_SEHBeginScope); \
__SEH_USE_LABEL(_SEHEndScope); \
\ \
{ \ { \
__label__ _SEHBeforeTry; \ __label__ _SEHBeforeTry; \
@ -227,15 +226,10 @@ void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
__SEH_ENTER_TRYLEVEL(); \ __SEH_ENTER_TRYLEVEL(); \
\ \
if(_SEHTopTryLevel) \ if(_SEHTopTryLevel) \
{ \
__SEH_BARRIER; __asm__ __volatile__("mov %%ebp, %0\n#%1" : "=m" (_SEHFrame.SF_FramePointer) : "r" (__builtin_frame_address(0))); __SEH_BARRIER; \
_SEH2EnterFrame(&_SEHFrame); \ _SEH2EnterFrame(&_SEHFrame); \
} \
#define __SEH_END_SCOPE \ #define __SEH_END_SCOPE \
} \ } \
\
_SEHEndScope: __SEH_SIDE_EFFECT; \
\ \
break; \ break; \
} }
@ -244,7 +238,6 @@ void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
__label__ _SEHBeginExcept; \ __label__ _SEHBeginExcept; \
__label__ _SEHEndExcept; \ __label__ _SEHEndExcept; \
\ \
auto __SEH_DECLARE_EXCEPT(_SEHExcept); \
auto __SEH_DECLARE_FINALLY(_SEHFinally); auto __SEH_DECLARE_FINALLY(_SEHFinally);
#define _SEH2_TRY \ #define _SEH2_TRY \
@ -265,14 +258,15 @@ void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
__SEH_PRETEND_USE_LABEL(_SEHBeginExcept); \ __SEH_PRETEND_USE_LABEL(_SEHBeginExcept); \
__SEH_PRETEND_USE_LABEL(_SEHEndExcept); \ __SEH_PRETEND_USE_LABEL(_SEHEndExcept); \
\ \
__SEH_USE_NESTED_FUNCTION(_SEHFinally); \
\
_SEHTryLevel.ST_FramePointer = _SEHClosureFromTrampoline((_SEHTrampoline_t *)&_SEHFinally); \
_SEHTryLevel.ST_Filter = 0; \ _SEHTryLevel.ST_Filter = 0; \
_SEHTryLevel.ST_Body = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)&_SEHFinally); \ _SEHTryLevel.ST_Body = &_SEHFinally; \
\
_SEHAbnormalTermination = 1; \
\ \
goto _SEHDoTry; \ goto _SEHDoTry; \
_SEHAfterTry:; \ _SEHAfterTry:; \
\
_SEHAbnormalTermination = 0; \
\ \
if(_SEHTopTryLevel) \ if(_SEHTopTryLevel) \
_SEH2LeaveFrame(); \ _SEH2LeaveFrame(); \
@ -284,23 +278,20 @@ void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
_SEHFinally(); \ _SEHFinally(); \
goto _SEHEndExcept; \ goto _SEHEndExcept; \
\ \
_SEHBeginExcept: __SEH_PRETEND_SIDE_EFFECT; \ _SEHBeginExcept:; \
__attribute__((unused)) __SEH_DEFINE_EXCEPT(_SEHExcept) { __SEH_RETURN_EXCEPT(0); } \
\ \
__attribute__((noinline)) __attribute__((used)) __SEH_DEFINE_FINALLY(_SEHFinally) \ __attribute__((noinline)) __SEH_DEFINE_FINALLY(_SEHFinally) \
{ \ { \
__SEH_END_SCOPE_CHAIN; \ __SEH_END_SCOPE_CHAIN; \
\ \
(void)_SEH2ScopeKind; \ (void)_SEH2ScopeKind; \
(void)_SEH2FrameP; \ (void)_SEH2FrameP; \
(void)_SEH2TryLevelP; \ (void)_SEH2TryLevelP; \
\
__SEH_NESTED_PROLOG; \
\ \
for(;; ({ __SEH_RETURN_FINALLY(); })) \ for(;; ({ __SEH_RETURN_FINALLY(); })) \
{ {
#define _SEH2_EXCEPT(E_) \ #define _SEH2_EXCEPT(...) \
} \ } \
__SEH_END_TRY; \ __SEH_END_TRY; \
\ \
@ -308,23 +299,50 @@ void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
\ \
_SEHBeforeTry:; \ _SEHBeforeTry:; \
\ \
__SEH_USE_LABEL(_SEHBeginExcept); \ if(__builtin_constant_p((__VA_ARGS__))) \
__SEH_USE_LABEL(_SEHEndExcept); \ { \
\ if((__VA_ARGS__) > 0) \
__SEH_USE_NESTED_FUNCTION(_SEHExcept); \ { \
\ _SEHTryLevel.ST_Filter = (void *)1; \
_SEHTryLevel.ST_FramePointer = _SEHClosureFromTrampoline((_SEHTrampoline_t *)&_SEHExcept); \
_SEHTryLevel.ST_Filter = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)&_SEHExcept); \
_SEHTryLevel.ST_Body = &&_SEHBeginExcept; \ _SEHTryLevel.ST_Body = &&_SEHBeginExcept; \
__SEH_BARRIER; __asm__ __volatile__("mov %%esp, %0" : "=m" (_SEH2FrameP->SF_StackPointer)); __SEH_BARRIER; \ __SEH_USE_LABEL(_SEHBeginExcept); \
} \
else if((__VA_ARGS__) < 0) \
{ \
_SEHTryLevel.ST_Filter = (void *)-1; \
_SEHTryLevel.ST_Body = NULL; \
} \
else \
{ \
_SEHTryLevel.ST_Filter = (void *)0; \
_SEHTryLevel.ST_Body = NULL; \
} \
} \
else \
{ \
__SEH_DEFINE_EXCEPT(_SEHExcept) \
{ \
__SEH_RETURN_EXCEPT((__VA_ARGS__)); \
} \
\
_SEHTryLevel.ST_Filter = &_SEHExcept; \
_SEHTryLevel.ST_Body = &&_SEHBeginExcept; \
__SEH_USE_LABEL(_SEHBeginExcept); \
} \
\
__SEH_BARRIER; \
\
__asm__ __volatile__ \
( \
"mov %%ebp, %0\n" \
"mov %%esp, %1" : \
"=m" (_SEHTryLevel.ST_Ebp), \
"=m" (_SEHTryLevel.ST_Esp) \
); \
\
__SEH_BARRIER; \
\ \
goto _SEHDoTry; \ goto _SEHDoTry; \
\
__attribute__((noinline)) __attribute__((used)) __SEH_DEFINE_EXCEPT(_SEHExcept) \
{ \
__SEH_NESTED_PROLOG; \
__SEH_RETURN_EXCEPT(E_); \
} \
\ \
__attribute__((unused)) __SEH_DEFINE_FINALLY(_SEHFinally) { __SEH_RETURN_FINALLY(); } \ __attribute__((unused)) __SEH_DEFINE_FINALLY(_SEHFinally) { __SEH_RETURN_FINALLY(); } \
\ \
@ -336,12 +354,9 @@ void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
__SEH_LEAVE_TRYLEVEL(); \ __SEH_LEAVE_TRYLEVEL(); \
} \ } \
\ \
if(__SEH_FALSE) \
goto _SEHBeginExcept; \
else \
goto _SEHEndExcept; \ goto _SEHEndExcept; \
\ \
_SEHBeginExcept: __SEH_SIDE_EFFECT; \ _SEHBeginExcept:; \
{ \ { \
{ \ { \
_SEH2Frame_t * const _SEH2FrameP = _SEHTopTryLevel ? &_SEHFrame : _SEHCurFrameP; \ _SEH2Frame_t * const _SEH2FrameP = _SEHTopTryLevel ? &_SEHFrame : _SEHCurFrameP; \
@ -352,13 +367,14 @@ void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
__SEH_BARRIER; \ __SEH_BARRIER; \
} \ } \
} \ } \
_SEHEndExcept: __SEH_SIDE_EFFECT; \ \
_SEHEndExcept:; \
} \ } \
__SEH_END_SCOPE; __SEH_END_SCOPE;
#define _SEH2_GetExceptionInformation() ((struct _EXCEPTION_POINTERS *)_SEHExceptionPointers) #define _SEH2_GetExceptionInformation() ((_SEH2FrameP)->SF_ExceptionInformation)
#define _SEH2_GetExceptionCode() ((_SEH2FrameP)->SF_Code) #define _SEH2_GetExceptionCode() ((_SEH2FrameP)->SF_Code)
#define _SEH2_AbnormalTermination() (!!_SEH2_GetExceptionCode()) #define _SEH2_AbnormalTermination() (_SEHAbnormalTermination)
#define _SEH2_YIELD(STMT_) \ #define _SEH2_YIELD(STMT_) \
for(;;) \ for(;;) \
@ -379,7 +395,7 @@ __SEH_END_SCOPE_CHAIN;
#define _SEH2_TRY __try #define _SEH2_TRY __try
#define _SEH2_FINALLY __finally #define _SEH2_FINALLY __finally
#define _SEH2_EXCEPT(E_) __except((E_)) #define _SEH2_EXCEPT(...) __except(__VA_ARGS__)
#define _SEH2_END #define _SEH2_END
#define _SEH2_GetExceptionInformation() (GetExceptionInformation()) #define _SEH2_GetExceptionInformation() (GetExceptionInformation())

View file

@ -40,7 +40,7 @@
extern _SEH2Registration_t * __cdecl _SEH2CurrentRegistration(void); extern _SEH2Registration_t * __cdecl _SEH2CurrentRegistration(void);
extern void _SEH2GlobalUnwind(void *); extern void _SEH2GlobalUnwind(void *);
extern int __SEH2Except(void *, void *, void *); extern int __SEH2Except(void *, void *);
extern void __SEH2Finally(void *, void *); extern void __SEH2Finally(void *, void *);
extern DECLSPEC_NORETURN int __SEH2Handle(void *, void *, void *); extern DECLSPEC_NORETURN int __SEH2Handle(void *, void *, void *);
@ -51,18 +51,45 @@ extern int __cdecl __SEH2FrameHandler(struct _EXCEPTION_RECORD *, void *, struct
extern int __cdecl __SEH2NestedHandler(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *); extern int __cdecl __SEH2NestedHandler(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *);
FORCEINLINE FORCEINLINE
int _SEH2Except(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel, EXCEPTION_POINTERS * ep) int _SEH2Except(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel)
{ {
return __SEH2Except(trylevel->ST_Filter, trylevel->ST_FramePointer, ep); void * filter = trylevel->ST_Filter;
void * context = NULL;
if(filter == (void *)0)
return 0;
if(filter == (void *)1)
return 1;
if(filter == (void *)-1)
return -1;
if(_SEHIsTrampoline((_SEHTrampoline_t *)filter))
{
context = _SEHClosureFromTrampoline((_SEHTrampoline_t *)filter);
filter = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)filter);
} }
static return __SEH2Except(filter, context);
#if defined(__GNUC__) }
__attribute__((noinline))
#endif FORCEINLINE
void _SEH2Finally(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel) void _SEH2Finally(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel)
{ {
__SEH2Finally(trylevel->ST_Body, trylevel->ST_FramePointer); if(trylevel->ST_Filter == NULL && trylevel->ST_Body != NULL)
{
void * body = trylevel->ST_Body;
void * context = NULL;
if(_SEHIsTrampoline((_SEHTrampoline_t *)body))
{
context = _SEHClosureFromTrampoline((_SEHTrampoline_t *)body);
body = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)body);
}
__SEH2Finally(body, context);
}
} }
extern extern
@ -91,10 +118,7 @@ void _SEH2LocalUnwind(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * dsttrylev
__SEH2EnterFrame(&nestedframe); __SEH2EnterFrame(&nestedframe);
for(trylevel = frame->SF_TopTryLevel; trylevel && trylevel != dsttrylevel; trylevel = trylevel->ST_Next) for(trylevel = frame->SF_TopTryLevel; trylevel && trylevel != dsttrylevel; trylevel = trylevel->ST_Next)
{
if(!trylevel->ST_Filter)
_SEH2Finally(frame, trylevel); _SEH2Finally(frame, trylevel);
}
frame->SF_TopTryLevel = dsttrylevel; frame->SF_TopTryLevel = dsttrylevel;
@ -106,7 +130,7 @@ void _SEH2Handle(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel)
{ {
_SEH2GlobalUnwind(frame); _SEH2GlobalUnwind(frame);
_SEH2LocalUnwind(frame, trylevel); _SEH2LocalUnwind(frame, trylevel);
__SEH2Handle(trylevel->ST_Body, frame->SF_FramePointer, frame->SF_StackPointer); __SEH2Handle(trylevel->ST_Body, trylevel->ST_Ebp, trylevel->ST_Esp);
} }
extern extern
@ -132,19 +156,17 @@ int __cdecl _SEH2FrameHandler
{ {
int ret = 0; int ret = 0;
volatile _SEH2TryLevel_t * trylevel; volatile _SEH2TryLevel_t * trylevel;
frame->SF_Code = ExceptionRecord->ExceptionCode;
for(trylevel = frame->SF_TopTryLevel; trylevel != NULL; trylevel = trylevel->ST_Next)
{
if(trylevel->ST_Filter)
{
EXCEPTION_POINTERS ep; EXCEPTION_POINTERS ep;
ep.ExceptionRecord = ExceptionRecord; ep.ExceptionRecord = ExceptionRecord;
ep.ContextRecord = ContextRecord; ep.ContextRecord = ContextRecord;
ret = _SEH2Except(frame, trylevel, &ep); frame->SF_Code = ExceptionRecord->ExceptionCode;
frame->SF_ExceptionInformation = &ep;
for(trylevel = frame->SF_TopTryLevel; trylevel != NULL; trylevel = trylevel->ST_Next)
{
ret = _SEH2Except(frame, trylevel);
if(ret < 0) if(ret < 0)
return ExceptionContinueExecution; return ExceptionContinueExecution;
@ -152,7 +174,6 @@ int __cdecl _SEH2FrameHandler
_SEH2Handle(frame, trylevel); _SEH2Handle(frame, trylevel);
} }
} }
}
return ExceptionContinueSearch; return ExceptionContinueSearch;
} }

View file

@ -49,18 +49,8 @@ ___SEH2Handle:
jmp eax jmp eax
.globl ___SEH2Except .globl ___SEH2Except
___SEH2Except:
mov eax, [esp+4]
mov ecx, [esp+8]
push [esp+12]
call eax
pop ecx
ret
.globl ___SEH2Finally .globl ___SEH2Finally
___SEH2Except:
___SEH2Finally: ___SEH2Finally:
mov eax, [esp+4] mov eax, [esp+4]
mov ecx, [esp+8] mov ecx, [esp+8]