Author: tkreuzer
Date: Sun Mar 9 13:55:26 2014
New Revision: 62466
URL:
http://svn.reactos.org/svn/reactos?rev=62466&view=rev
Log:
[PSEH3]
- Add AllocaFrame field to the exception registration record. It is required for Clang and
C++ handlers.
- Fix the way how "nested functions" are emulated on Clang and C++, respecting
the fact that the compiler can and will use a temporary esp-based stack frame below any
alloca-allocations for function invocation. This uses the AllocaFrame field to calculate
and setup a new temp stack frame for the "nested functions".
- Make use of the HandlerType field in the exception registration record to use different
methods for invoking filters / finally functions.
- Write @_SEH3$_CallRtlUnwind@4 in raw asm instead of inline, because Clang cannot deal
with stdcall decorations in inline asm (see
http://llvm.org/bugs/show_bug.cgi?id=19027)
- Make sure ExceptionPointers are properly initialized in _SEH3$_except_handler
Modified:
trunk/reactos/include/reactos/libs/pseh/pseh3.h
trunk/reactos/lib/pseh/i386/pseh3.c
trunk/reactos/lib/pseh/i386/pseh3_asmdef.h
trunk/reactos/lib/pseh/i386/pseh3_i386.S
Modified: trunk/reactos/include/reactos/libs/pseh/pseh3.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/libs/pseh/…
==============================================================================
--- trunk/reactos/include/reactos/libs/pseh/pseh3.h [iso-8859-1] (original)
+++ trunk/reactos/include/reactos/libs/pseh/pseh3.h [iso-8859-1] Sun Mar 9 13:55:26 2014
@@ -67,6 +67,8 @@
/* Registers that we need to save */
unsigned long Esp;
unsigned long Ebp;
+
+ char* AllocaFrame;
#ifdef _SEH3$_FRAME_ALL_NONVOLATILES
unsigned long Ebx;
unsigned long Esi;
@@ -101,10 +103,12 @@
_SEH3$_TryLevel = 0,
};
+#ifndef __clang__
/* These are global dummy definitions, that get overwritten in the local context of
__finally / __except blocks */
int __cdecl __attribute__((error ("Can only be used inside a __finally
block."))) _abnormal_termination(void);
unsigned long __cdecl __attribute__((error("Can only be used inside an exception
filter or __except block."))) _exception_code(void);
void * __cdecl __attribute__((error("Can only be used inside an exception
filter."))) _exception_info(void);
+#endif
/* This attribute allows automatic cleanup of the registered frames */
#define _SEH3$_AUTO_CLEANUP __attribute__((cleanup(_SEH3$_Unregister)))
@@ -119,15 +123,16 @@
#define _SEH3$_ASM_GOTO(_Label, ...)
int
-__attribute__((regparm(2)))
+__attribute__((regparm(3)))
__attribute__((returns_twice))
_SEH3$_RegisterFrameWithNonVolatiles(
volatile SEH3$_REGISTRATION_FRAME* RegistrationFrame,
- const SEH3$_SCOPE_TABLE* ScopeTable);
+ const SEH3$_SCOPE_TABLE* ScopeTable,
+ void* AllocaFrame);
#define _SEH3$_RegisterFrame_(_TrylevelFrame, _DataTable) \
do { \
- int result = _SEH3$_RegisterFrameWithNonVolatiles(_TrylevelFrame, _DataTable); \
+ int result = _SEH3$_RegisterFrameWithNonVolatiles(_TrylevelFrame, _DataTable,
__builtin_alloca(0)); \
if (__builtin_expect(result != 0, 0)) \
{ \
if (result == 1) goto _SEH3$_l_FilterOrFinally; \
@@ -137,15 +142,16 @@
} while(0)
int
-__attribute__((regparm(2)))
+__attribute__((regparm(3)))
__attribute__((returns_twice))
_SEH3$_RegisterTryLevelWithNonVolatiles(
volatile SEH3$_REGISTRATION_FRAME* RegistrationFrame,
- const SEH3$_SCOPE_TABLE* ScopeTable);
+ const SEH3$_SCOPE_TABLE* ScopeTable,
+ void* AllocaFrame);
#define _SEH3$_RegisterTryLevel_(_TrylevelFrame, _DataTable) \
do { \
- int result = _SEH3$_RegisterTryLevelWithNonVolatiles(_TrylevelFrame, _DataTable);
\
+ int result = _SEH3$_RegisterTryLevelWithNonVolatiles(_TrylevelFrame, _DataTable,
__builtin_alloca(0)); \
if (__builtin_expect(result != 0, 0)) \
{ \
if (result == 1) goto _SEH3$_l_FilterOrFinally; \
@@ -163,25 +169,34 @@
#define _SEH3$_ASM_GOTO(_Label, ...) asm goto ("#\n" : : : "memory",
## __VA_ARGS__ : _Label)
+#ifdef __cplusplus
+#define _SEH3$_CALL_WRAPPER(_Function, _TrylevelFrame, _DataTable) \
+ asm goto ("leal %0, %%eax\n" \
+ "leal %1, %%edx\n" \
+ "call " #_Function "WithStackLayout\n" \
+ : \
+ : "m" (*(_TrylevelFrame)), "m" (*(_DataTable)),
"c"(__builtin_alloca(0)) \
+ : "eax", "edx", "memory" \
+ : _SEH3$_l_HandlerTarget, _SEH3$_l_FilterOrFinally)
+
+#else
+#define _SEH3$_CALL_WRAPPER(_Function, _TrylevelFrame, _DataTable) \
+ asm goto ("leal %0, %%eax\n" \
+ "leal %1, %%edx\n" \
+ "call " #_Function "\n" \
+ : \
+ : "m" (*(_TrylevelFrame)), "m" (*(_DataTable)) \
+ : "eax", "edx", "ecx", "memory" \
+ : _SEH3$_l_HandlerTarget)
+#endif
+
/* This is an asm wrapper around _SEH3$_RegisterFrame */
#define _SEH3$_RegisterFrame_(_TrylevelFrame, _DataTable) \
- asm goto ("leal %0, %%eax\n" \
- "leal %1, %%edx\n" \
- "call __SEH3$_RegisterFrame\n" \
- : \
- : "m" (*(_TrylevelFrame)), "m" (*(_DataTable)) \
- : "ecx", "edx", "memory" \
- : _SEH3$_l_HandlerTarget)
+ _SEH3$_CALL_WRAPPER(__SEH3$_RegisterFrame, _TrylevelFrame, _DataTable)
/* This is an asm wrapper around _SEH3$_RegisterTryLevel */
#define _SEH3$_RegisterTryLevel_(_TrylevelFrame, _DataTable) \
- asm goto ("leal %0, %%eax\n" \
- "leal %1, %%edx\n" \
- "call __SEH3$_RegisterTryLevel\n" \
- : \
- : "m" (*(_TrylevelFrame)), "m" (*(_DataTable)) \
- : "ecx", "edx", "memory" \
- : _SEH3$_l_HandlerTarget)
+ _SEH3$_CALL_WRAPPER(__SEH3$_RegisterTryLevel, _TrylevelFrame, _DataTable)
/* This construct scares GCC so much, that it will stop moving code
around into places that are never executed. */
@@ -214,15 +229,17 @@
/* The "nested" functions are a piece of code with a ret instruction at the end
*/
#define _SEH3$_NESTED_FUNC_OPEN() \
{ \
- int SavedEsp, result = 0; \
-\
- /* Save esp */ \
- asm volatile ("movl %%esp, %[SavedEsp]\n" : :
[SavedEsp]"m"(SavedEsp));
+ int _SEH3$_Result = 0; \
+
+/* On invocation, the AllocaFrame field is loaded with the return esp value */
+#define _SEH3$_NESTED_FUNC_RETURN() \
+ /* Restore esp and return to the caller */ \
+ asm volatile ("movl %[FixedEsp], %%esp\nret\n" \
+ : : "a"(_SEH3$_Result),
[FixedEsp]"m"(_SEH3$_TrylevelFrame.AllocaFrame) : "memory")
#define _SEH3$_NESTED_FUNC_CLOSE() \
- /* Restore esp and return to the caller */ \
- asm volatile ("movl %[SavedEsp], %%esp\nret\n" \
- : : "a"(result), [SavedEsp]"irm"(SavedEsp)); \
+ /* Return to the caller */ \
+ _SEH3$_NESTED_FUNC_RETURN(); \
}
/* The filter function */
@@ -230,7 +247,7 @@
_SEH3$_NESTED_FUNC_OPEN() \
{ \
/* Evaluate the filter expression */ \
- result = (expression); \
+ _SEH3$_Result = (expression); \
} \
_SEH3$_NESTED_FUNC_CLOSE()
@@ -238,11 +255,10 @@
_SEH3$_NESTED_FUNC_OPEN() \
/* This construct makes sure that the finally function returns */ \
/* a proper value at the end */ \
- for (; ; (void)({asm volatile ("movl %[SavedEsp], %%esp\nret\n" \
- : : "a"(result), [SavedEsp]"irm"(SavedEsp)); 0;}))
+ for (; ; (void)({_SEH3$_NESTED_FUNC_RETURN(); 0;}))
#define _SEH3$_FILTER(_Filter, _FilterExpression) (&&_SEH3$_l_FilterOrFinally)
-#define _SEH3$_FINALLY(_Finally) 0
+#define _SEH3$_FINALLY(_Finally) (&&_SEH3$_l_FilterOrFinally)
#define _SEH3$_DECLARE_EXCEPT_INTRINSICS()
@@ -336,6 +352,7 @@
__label__ _SEH3$_l_OnException; \
__label__ _SEH3$_l_BeforeFilterOrFinally; \
__label__ _SEH3$_l_FilterOrFinally; \
+ (void)&&_SEH3$_l_OnException; \
(void)&&_SEH3$_l_BeforeFilterOrFinally; \
(void)&&_SEH3$_l_FilterOrFinally; \
\
@@ -419,7 +436,7 @@
_SEH3$_DECLARE_FILTER_FUNC(_SEH3$_FinallyFunction); \
\
/* Create a static data table that contains the finally function */ \
- static const SEH3$_SCOPE_TABLE _SEH3$_ScopeTable = { 0,
_SEH3$_FINALLY(&_SEH3$_FinallyFunction) }; \
+ static const SEH3$_SCOPE_TABLE _SEH3$_ScopeTable = { 0,
_SEH3$_FINALLY(&_SEH3$_FinallyFunction), _SEH3$_TryLevel, _SEH3$_HANDLER_TYPE }; \
\
/* Register the registration record. */ \
if (_SEH3$_TryLevel == 1) _SEH3$_RegisterFrame_(&_SEH3$_TrylevelFrame,
&_SEH3$_ScopeTable); \
@@ -431,6 +448,7 @@
_SEH3$_EnforceFramePointer(); \
\
_SEH3$_l_BeforeFilterOrFinally: (void)0; \
+ _SEH3$_EnforceFramePointer(); \
_SEH3$_l_FilterOrFinally: (void)0; \
_SEH3$_FINALLY_FUNC_OPEN(_SEH3$_FinallyFunction)
Modified: trunk/reactos/lib/pseh/i386/pseh3.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/pseh/i386/pseh3.c?rev=…
==============================================================================
--- trunk/reactos/lib/pseh/i386/pseh3.c [iso-8859-1] (original)
+++ trunk/reactos/lib/pseh/i386/pseh3.c [iso-8859-1] Sun Mar 9 13:55:26 2014
@@ -63,8 +63,8 @@
static inline
LONG
-_SEH3$_InvokeFilter(
- PVOID Record,
+_SEH3$_InvokeNestedFunctionFilter(
+ PSEH3$_REGISTRATION_FRAME RegistrationFrame,
PVOID Filter)
{
LONG FilterResult;
@@ -78,14 +78,54 @@
/* The result is the frame base address that we passed in (0) plus the
offset to the registration record. */
"negl %%eax\n\t"
- "addl %[Record], %%eax\n\t"
+ "addl %[RegistrationFrame], %%eax\n\t"
/* Second call to get the filter result */
"mov $1, %%ecx\n\t"
"call *%[Filter]\n\t"
: "=a"(FilterResult)
- : [Record] "m" (Record), [Filter] "m" (Filter)
+ : [RegistrationFrame] "m" (RegistrationFrame), [Filter] "m"
(Filter)
: "ecx", "edx");
+
+ return FilterResult;
+}
+
+long
+__attribute__((regparm(1)))
+_SEH3$_InvokeEmbeddedFilter(
+ PSEH3$_REGISTRATION_FRAME RegistrationFrame);
+
+long
+__attribute__((regparm(1)))
+_SEH3$_InvokeEmbeddedFilterFromRegistration(
+ PSEH3$_REGISTRATION_FRAME RegistrationFrame);
+
+static inline
+LONG
+_SEH3$_InvokeFilter(
+ PSEH3$_REGISTRATION_FRAME RegistrationFrame,
+ PVOID Filter)
+{
+ LONG FilterResult;
+
+ if (RegistrationFrame->ScopeTable->HandlerType == _SEH3$_NESTED_HANDLER)
+ {
+ return _SEH3$_InvokeNestedFunctionFilter(RegistrationFrame, Filter);
+ }
+ else if (RegistrationFrame->ScopeTable->HandlerType == _SEH3$_CPP_HANDLER)
+ {
+ /* Call the embedded filter function */
+ return _SEH3$_InvokeEmbeddedFilter(RegistrationFrame);
+ }
+ else if (RegistrationFrame->ScopeTable->HandlerType == _SEH3$_CLANG_HANDLER)
+ {
+ return _SEH3$_InvokeEmbeddedFilterFromRegistration(RegistrationFrame);
+ }
+ else
+ {
+ /* Should not happen! Skip this handler */
+ FilterResult = EXCEPTION_CONTINUE_SEARCH;
+ }
return FilterResult;
}
@@ -136,45 +176,51 @@
_SEH3$_JumpToTarget(
PSEH3$_REGISTRATION_FRAME RegistrationFrame)
{
- asm volatile (
- /* Load the registers */
- "movl 20(%%ecx), %%esp\n"
- "movl 24(%%ecx), %%ebp\n"
-
- /* Stack pointer is 4 off from the call to __SEH3$_RegisterFrame */
- "addl $4, %%esp\n"
-
- /* Jump into the exception handler */
- "jmp *%[Target]\n"
- : :
- "c" (RegistrationFrame),
- "a" (RegistrationFrame->ScopeTable),
- [Target] "m" (RegistrationFrame->ScopeTable->Target)
- );
+ if (RegistrationFrame->ScopeTable->HandlerType == _SEH3$_CLANG_HANDLER)
+ {
+ asm volatile (
+ /* Load the registers */
+ "movl 20(%%ecx), %%esp\n"
+ "movl 24(%%ecx), %%ebp\n"
+
+ /* Stack pointer is 4 off from the call to __SEH3$_RegisterFrame */
+ "addl $4, %%esp\n"
+
+ /* Jump into the exception handler */
+ "jmp *%[Target]\n"
+ : :
+ "c" (RegistrationFrame),
+ "a" (RegistrationFrame->ScopeTable),
+ [Target] "m" (RegistrationFrame->ScopeTable->Target)
+ );
+ }
+ else
+ {
+ asm volatile (
+ /* Load the registers */
+ "movl 20(%%ecx), %%esp\n"
+ "movl 24(%%ecx), %%ebp\n"
+
+ /* Stack pointer is 4 off from the call to __SEH3$_RegisterFrame */
+ "addl $4, %%esp\n"
+
+ /* Jump into the exception handler */
+ "jmp *%[Target]\n"
+ : :
+ "c" (RegistrationFrame),
+ "a" (RegistrationFrame->ScopeTable),
+ [Target] "m" (RegistrationFrame->ScopeTable->Target)
+ );
+ }
__builtin_unreachable();
}
-static inline
void
+__fastcall
_SEH3$_CallRtlUnwind(
- PSEH3$_REGISTRATION_FRAME RegistrationFrame)
-{
- LONG ClobberedEax;
-
- asm volatile(
- "push %%ebp\n"
- "push $0\n"
- "push $0\n"
- "push $0\n"
- "push %[TargetFrame]\n"
- "call _RtlUnwind@16\n"
- "pop %%ebp\n"
- : "=a" (ClobberedEax)
- : [TargetFrame] "a" (RegistrationFrame)
- : "ebx", "ecx", "edx", "esi",
- "edi", "flags", "memory");
-}
+ PSEH3$_REGISTRATION_FRAME RegistrationFrame);
+
EXCEPTION_DISPOSITION
__cdecl
@@ -192,6 +238,10 @@
/* Clear the direction flag. */
asm volatile ("cld\n" : : : "memory");
+ /* Save the exception pointers on the stack */
+ ExceptionPointers.ExceptionRecord = ExceptionRecord;
+ ExceptionPointers.ContextRecord = ContextRecord;
+
/* Check if this is an unwind */
if (ExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING)
{
@@ -200,10 +250,6 @@
}
else
{
- /* Save the exception pointers on the stack */
- ExceptionPointers.ExceptionRecord = ExceptionRecord;
- ExceptionPointers.ContextRecord = ContextRecord;
-
/* Loop all frames for this registration */
CurrentFrame = EstablisherFrame->EndOfChain;
for (;;)
Modified: trunk/reactos/lib/pseh/i386/pseh3_asmdef.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/pseh/i386/pseh3_asmdef…
==============================================================================
--- trunk/reactos/lib/pseh/i386/pseh3_asmdef.h [iso-8859-1] (original)
+++ trunk/reactos/lib/pseh/i386/pseh3_asmdef.h [iso-8859-1] Sun Mar 9 13:55:26 2014
@@ -7,9 +7,10 @@
#define SEH3_REGISTRATION_FRAME_ExceptionPointers 16
#define SEH3_REGISTRATION_FRAME_Esp 20
#define SEH3_REGISTRATION_FRAME_Ebp 24
-#define SEH3_REGISTRATION_FRAME_Ebx 28
-#define SEH3_REGISTRATION_FRAME_Esi 32
-#define SEH3_REGISTRATION_FRAME_Edi 36
+#define SEH3_REGISTRATION_FRAME_AllocaFrame 28
+#define SEH3_REGISTRATION_FRAME_Ebx 32
+#define SEH3_REGISTRATION_FRAME_Esi 36
+#define SEH3_REGISTRATION_FRAME_Edi 40
#define SEH3_SCOPE_TABLE_Target 0
#define SEH3_SCOPE_TABLE_Filter 4
Modified: trunk/reactos/lib/pseh/i386/pseh3_i386.S
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/pseh/i386/pseh3_i386.S…
==============================================================================
--- trunk/reactos/lib/pseh/i386/pseh3_i386.S [iso-8859-1] (original)
+++ trunk/reactos/lib/pseh/i386/pseh3_i386.S [iso-8859-1] Sun Mar 9 13:55:26 2014
@@ -15,11 +15,12 @@
/*
* void
- * __attribute__((regparm(2)))
+ * __attribute__((regparm(3)))
* __attribute__((returns_twice))
* _SEH3$_RegisterFrame[WithNonVolatiles](
* PSEH3$_REGISTRATION_FRAME RegistrationFrame<eax>,
- * PSEH3$_SCOPE_TABLE ScopeTable<edx>);
+ * PSEH3$_SCOPE_TABLE ScopeTable<edx>,
+ * PVOID AllocaFrame);
*/
.global __SEH3$_RegisterFrameWithNonVolatiles
__SEH3$_RegisterFrameWithNonVolatiles:
@@ -29,6 +30,12 @@
mov [eax + SEH3_REGISTRATION_FRAME_Esi], esi
mov [eax + SEH3_REGISTRATION_FRAME_Edi], edi
+.global __SEH3$_RegisterFrameWithStackLayout
+__SEH3$_RegisterFrameWithStackLayout:
+
+ /* Save the pointer to the alloca frame */
+ mov [eax + SEH3_REGISTRATION_FRAME_AllocaFrame], ecx
+
.global __SEH3$_RegisterFrame
__SEH3$_RegisterFrame:
@@ -57,11 +64,12 @@
/*
* void
- * __attribute__((regparm(2)))
+ * __attribute__((regparm(3)))
* __attribute__((returns_twice))
* _SEH3$_RegisterTryLevel[WithNonVolatiles](
* PSEH3$_REGISTRATION_FRAME RegistrationFrame<edx>,
- * PSEH3$_SCOPE_TABLE ScopeTable<eax>);
+ * PSEH3$_SCOPE_TABLE ScopeTable<eax>,
+ * PVOID AllocaFrame);
*/
.global __SEH3$_RegisterTryLevelWithNonVolatiles
__SEH3$_RegisterTryLevelWithNonVolatiles:
@@ -71,6 +79,12 @@
mov [eax + SEH3_REGISTRATION_FRAME_Esi], esi
mov [eax + SEH3_REGISTRATION_FRAME_Edi], edi
+.global __SEH3$_RegisterTryLevelWithStackLayout
+__SEH3$_RegisterTryLevelWithStackLayout:
+
+ /* Save the pointer to the alloca frame */
+ mov [eax + SEH3_REGISTRATION_FRAME_AllocaFrame], ecx
+
.global __SEH3$_RegisterTryLevel
__SEH3$_RegisterTryLevel:
@@ -98,3 +112,105 @@
xor eax, eax
ret
+
+.global __SEH3$_InvokeEmbeddedFilterFromRegistration
+__SEH3$_InvokeEmbeddedFilterFromRegistration:
+
+ /* Safe the current non-volatiles */
+ push ebp
+ push ebx
+ push esi
+ push edi
+
+ /* Load the non-volatiles from the registration invocation */
+ mov ebx, [eax + SEH3_REGISTRATION_FRAME_Ebx]
+ mov esi, [eax + SEH3_REGISTRATION_FRAME_Esi]
+ mov edi, [eax + SEH3_REGISTRATION_FRAME_Edi]
+ mov ebp, [eax + SEH3_REGISTRATION_FRAME_Ebp]
+
+ /* Get the saved stack pointer */
+ mov edx, [eax + SEH3_REGISTRATION_FRAME_Esp]
+
+ xor eax, eax
+ inc eax
+ call [edx]
+
+ /* Restore the current non-volatiles */
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+
+ ret
+
+
+.global __SEH3$_InvokeEmbeddedFilter
+__SEH3$_InvokeEmbeddedFilter:
+
+ /* Safe the current non-volatiles */
+ push ebp
+ push ebx
+ push esi
+ push edi
+
+ /* Load ebp from the registration invocation */
+ mov ebp, [eax + SEH3_REGISTRATION_FRAME_Ebp]
+
+ /* Calculate the size of the temp stack frame region */
+ mov ecx, [eax + SEH3_REGISTRATION_FRAME_AllocaFrame]
+ sub ecx, [eax + SEH3_REGISTRATION_FRAME_Esp]
+
+ /* Put the return address on the stack */
+ push offset __SEH3$_InvokeEmbeddedFilterReturn
+
+ /* Save the current stack pointer in the AllocaFrame member */
+ mov [eax + SEH3_REGISTRATION_FRAME_AllocaFrame], esp
+
+ /* Allocate enough temp stack space on the stack */
+ sub esp, ecx
+
+ /* Get the scope table */
+ mov edx, [eax + SEH3_REGISTRATION_FRAME_ScopeTable]
+
+ /* Jump into the filter or finally function */
+ jmp [edx + SEH3_SCOPE_TABLE_Filter]
+
+ /* We return to this label with a cleaned up stack */
+__SEH3$_InvokeEmbeddedFilterReturn:
+
+ /* Restore the current non-volatiles */
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+
+ ret
+
+/*
+ * void
+ * __fastcall
+ * _SEH3$_CallRtlUnwind(
+ * PSEH3$_REGISTRATION_FRAME RegistrationFrame<ecx>)
+ */
+.global @_SEH3$_CallRtlUnwind@4
+@_SEH3$_CallRtlUnwind@4:
+
+ push ebp
+ mov ebp, esp
+
+ push edi
+ push esi
+ push ebx
+
+ push 0 /* ReturnValue */
+ push 0 /* ExceptionRecord */
+ push 0 /* TargetIp */
+ push ecx /* TargetFrame */
+ call _RtlUnwind@16
+
+ pop ebx
+ pop esi
+ pop edi
+ pop ebp
+ ret
+