mirror of
https://github.com/reactos/reactos.git
synced 2025-01-10 08:10:18 +00:00
[CMAKE]
On MSVC builds, compile native SEH support into PSEH library. This should be part of the crt, but our crt is too disorganized to handle that. The empty C file is for cmake to get the library right. svn path=/branches/cmake-bringup/; revision=50486
This commit is contained in:
parent
0c480c0cb2
commit
45cb5eb141
4 changed files with 605 additions and 0 deletions
|
@ -16,4 +16,14 @@ if(NOT MSVC)
|
|||
add_library(pseh ${SOURCE})
|
||||
add_dependencies(pseh psdk)
|
||||
|
||||
else()
|
||||
|
||||
list(APPEND SOURCE
|
||||
dummy.c
|
||||
i386/seh.s
|
||||
i386/seh_prolog.s)
|
||||
|
||||
add_library(pseh ${SOURCE})
|
||||
add_dependencies(pseh asm)
|
||||
|
||||
endif()
|
||||
|
|
2
lib/pseh/dummy.c
Normal file
2
lib/pseh/dummy.c
Normal file
|
@ -0,0 +1,2 @@
|
|||
/* intentionally empty file */
|
||||
|
441
lib/pseh/i386/seh.s
Normal file
441
lib/pseh/i386/seh.s
Normal file
|
@ -0,0 +1,441 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS CRT
|
||||
* FILE: lib/crt/misc/i386/seh.S
|
||||
* PURPOSE: SEH Support for the CRT
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <asm.inc>
|
||||
|
||||
#define DISPOSITION_DISMISS 0
|
||||
#define DISPOSITION_CONTINUE_SEARCH 1
|
||||
#define DISPOSITION_COLLIDED_UNWIND 3
|
||||
|
||||
#define EXCEPTION_EXIT_UNWIND 4
|
||||
#define EXCEPTION_UNWINDING 2
|
||||
|
||||
|
||||
EXTERN _RtlUnwind@16:PROC
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
PUBLIC __global_unwind2
|
||||
PUBLIC __local_unwind2
|
||||
PUBLIC __abnormal_termination
|
||||
PUBLIC __except_handler2
|
||||
PUBLIC __except_handler3
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
.code
|
||||
_unwind_handler:
|
||||
|
||||
/* Check if we were unwinding and continue search if not */
|
||||
mov ecx, [esp+4]
|
||||
test dword ptr [ecx+4], EXCEPTION_EXIT_UNWIND + EXCEPTION_UNWINDING
|
||||
mov eax, DISPOSITION_CONTINUE_SEARCH
|
||||
jz unwind_handler_return
|
||||
|
||||
/* We have a collision, do a local unwind */
|
||||
mov eax, [esp+20]
|
||||
push ebp
|
||||
mov ebp, [eax+16]
|
||||
mov edx, [eax+40]
|
||||
push edx
|
||||
mov edx, [eax+36]
|
||||
push edx
|
||||
call __local_unwind2
|
||||
add esp, 8
|
||||
pop ebp
|
||||
|
||||
/* Set new try level */
|
||||
mov eax, [esp+8]
|
||||
mov edx, [esp+16]
|
||||
mov [edx], eax
|
||||
|
||||
/* Return collided unwind */
|
||||
mov eax, DISPOSITION_COLLIDED_UNWIND
|
||||
|
||||
unwind_handler_return:
|
||||
ret
|
||||
|
||||
|
||||
__global_unwind2:
|
||||
|
||||
/* Create stack and save all registers */
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
push ebp
|
||||
|
||||
/* Call unwind */
|
||||
push 0
|
||||
push 0
|
||||
push glu_return
|
||||
push [ebp+8]
|
||||
call _RtlUnwind@16
|
||||
|
||||
glu_return:
|
||||
/* Restore registers and return */
|
||||
pop ebp
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
__abnormal_termination:
|
||||
|
||||
/* Assume false */
|
||||
xor eax, eax
|
||||
|
||||
/* Check if the handler is the unwind handler */
|
||||
mov ecx, fs:0
|
||||
cmp dword ptr [ecx+4], offset _unwind_handler
|
||||
jne short ab_return
|
||||
|
||||
/* Get the try level */
|
||||
mov edx, [ecx+12]
|
||||
mov edx, [edx+12]
|
||||
|
||||
/* Compare it */
|
||||
cmp [ecx+8], edx
|
||||
jne ab_return
|
||||
|
||||
/* Return true */
|
||||
mov eax, 1
|
||||
|
||||
/* Return */
|
||||
ab_return:
|
||||
ret
|
||||
|
||||
|
||||
__local_unwind2:
|
||||
|
||||
/* Save volatiles */
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
|
||||
/* Get the exception registration */
|
||||
mov eax, [esp+16]
|
||||
|
||||
/* Setup SEH to protect the unwind */
|
||||
push ebp
|
||||
push eax
|
||||
push -2
|
||||
push offset _unwind_handler
|
||||
push fs:0
|
||||
mov fs:0, esp
|
||||
|
||||
unwind_loop:
|
||||
/* Get the exception registration and try level */
|
||||
mov eax, [esp+36]
|
||||
mov ebx, [eax+8]
|
||||
mov esi, [eax+12]
|
||||
|
||||
/* Validate the unwind */
|
||||
cmp esi, -1
|
||||
je unwind_return
|
||||
cmp dword ptr [esp+40], -1
|
||||
je unwind_ok
|
||||
cmp esi, [esp+40]
|
||||
jbe unwind_return
|
||||
|
||||
unwind_ok:
|
||||
/* Get the new enclosing level and save it */
|
||||
lea esi, [esi+esi*2]
|
||||
mov ecx, [ebx+esi*4]
|
||||
mov [esp+8], ecx
|
||||
mov [eax+12], ecx
|
||||
|
||||
/* Check the filter type */
|
||||
cmp dword ptr [ebx+esi*4+4], 0
|
||||
jnz __NLG_Return2
|
||||
|
||||
/* FIXME: NLG Notification */
|
||||
|
||||
/* Call the handler */
|
||||
call dword ptr [ebx+esi*4+8]
|
||||
|
||||
__NLG_Return2:
|
||||
/* Unwind again */
|
||||
jmp unwind_loop
|
||||
|
||||
unwind_return:
|
||||
/* Cleanup SEH */
|
||||
pop fs:0
|
||||
add esp, 16
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
|
||||
__except_handler2:
|
||||
|
||||
/* Setup stack and save volatiles */
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
sub esp, 8
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
push ebp
|
||||
|
||||
/* Clear direction flag */
|
||||
cld
|
||||
|
||||
/* Get exception registration and record */
|
||||
mov ebx, [ebp+12]
|
||||
mov eax, [ebp+8]
|
||||
|
||||
/* Check if this is an unwind */
|
||||
test dword ptr [eax+4], EXCEPTION_EXIT_UNWIND + EXCEPTION_UNWINDING
|
||||
jnz except_unwind2
|
||||
|
||||
/* Save exception pointers structure */
|
||||
mov [ebp-8], eax
|
||||
mov eax, [ebp+16]
|
||||
mov [ebp-4], eax
|
||||
lea eax, [ebp-8]
|
||||
mov [ebx+20], eax
|
||||
|
||||
/* Get the try level and scope table */
|
||||
mov esi, [ebx+12]
|
||||
mov edi, [ebx+8]
|
||||
|
||||
except_loop2:
|
||||
/* Validate try level */
|
||||
cmp esi, -1
|
||||
je except_search2
|
||||
|
||||
/* Check if this is the termination handler */
|
||||
lea ecx, [esi+esi*2]
|
||||
cmp dword ptr [edi+ecx*4+4], 0
|
||||
jz except_continue2
|
||||
|
||||
/* Save registers and call filter, then restore them */
|
||||
push esi
|
||||
push ebp
|
||||
mov ebp, [ebx+16]
|
||||
call dword ptr [edi+ecx*4+4]
|
||||
pop ebp
|
||||
pop esi
|
||||
|
||||
/* Restore ebx and check the result */
|
||||
mov ebx, [ebp+12]
|
||||
or eax, eax
|
||||
jz except_continue2
|
||||
js except_dismiss2
|
||||
|
||||
/* So this is an accept, call the termination handlers */
|
||||
mov edi, [ebx+8]
|
||||
push ebx
|
||||
call __global_unwind2
|
||||
add esp, 4
|
||||
|
||||
/* Restore ebp */
|
||||
mov ebp, [ebx+16]
|
||||
|
||||
/* Do local unwind */
|
||||
push esi
|
||||
push ebx
|
||||
call __local_unwind2
|
||||
add esp, 8
|
||||
|
||||
/* Set new try level */
|
||||
lea ecx, [esi+esi*2]
|
||||
mov eax, [edi+ecx*4]
|
||||
mov [ebx+12], eax
|
||||
|
||||
/* Call except handler */
|
||||
call dword ptr [edi+ecx*4+8]
|
||||
|
||||
except_continue2:
|
||||
/* Reload try level and except again */
|
||||
mov edi, [ebx+8]
|
||||
lea ecx, [esi+esi*2]
|
||||
mov esi, [edi+ecx*4]
|
||||
jmp except_loop2
|
||||
|
||||
except_dismiss2:
|
||||
/* Dismiss it */
|
||||
mov eax, DISPOSITION_DISMISS
|
||||
jmp except_return2
|
||||
|
||||
except_search2:
|
||||
/* Continue searching */
|
||||
mov eax, DISPOSITION_CONTINUE_SEARCH
|
||||
jmp except_return2
|
||||
|
||||
/* Do local unwind */
|
||||
except_unwind2:
|
||||
push ebp
|
||||
mov ebp, [ebx+16]
|
||||
push -1
|
||||
push ebx
|
||||
call __local_unwind2
|
||||
add esp, 8
|
||||
|
||||
/* Retore EBP and set return disposition */
|
||||
pop ebp
|
||||
mov eax, DISPOSITION_CONTINUE_SEARCH
|
||||
|
||||
except_return2:
|
||||
/* Restore registers and stack */
|
||||
pop ebp
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
__except_handler3:
|
||||
|
||||
/* Setup stack and save volatiles */
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
sub esp, 8
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
push ebp
|
||||
|
||||
/* Clear direction flag */
|
||||
cld
|
||||
|
||||
/* Get exception registration and record */
|
||||
mov ebx, [ebp+12]
|
||||
mov eax, [ebp+8]
|
||||
|
||||
/* Check if this is an unwind */
|
||||
test dword ptr [eax+4], EXCEPTION_EXIT_UNWIND + EXCEPTION_UNWINDING
|
||||
jnz except_unwind3
|
||||
|
||||
/* Save exception pointers structure */
|
||||
mov [ebp-8], eax
|
||||
mov eax, [ebp+16]
|
||||
mov [ebp-4], eax
|
||||
lea eax, [ebp-8]
|
||||
mov [ebx-4], eax
|
||||
|
||||
/* Get the try level and scope table */
|
||||
mov esi, [ebx+12]
|
||||
mov edi, [ebx+8]
|
||||
|
||||
/* FIXME: Validate the SEH exception */
|
||||
|
||||
except_loop3:
|
||||
/* Validate try level */
|
||||
cmp esi, -1
|
||||
je except_search3
|
||||
|
||||
/* Check if this is the termination handler */
|
||||
lea ecx, [esi+esi*2]
|
||||
mov eax, [edi+ecx*4+4]
|
||||
or eax, eax
|
||||
jz except_continue3
|
||||
|
||||
/* Save registers clear them all */
|
||||
push esi
|
||||
push ebp
|
||||
lea ebp, [ebx+16]
|
||||
xor ebx, ebx
|
||||
xor ecx, ecx
|
||||
xor edx, edx
|
||||
xor esi, esi
|
||||
xor edi, edi
|
||||
|
||||
/* Call the filter and restore our registers */
|
||||
call eax
|
||||
pop ebp
|
||||
pop esi
|
||||
|
||||
/* Restore ebx and check the result */
|
||||
mov ebx, [ebp+12]
|
||||
or eax, eax
|
||||
jz except_continue3
|
||||
js except_dismiss3
|
||||
|
||||
/* So this is an accept, call the termination handlers */
|
||||
mov edi, [ebx+8]
|
||||
push ebx
|
||||
call __global_unwind2
|
||||
add esp, 4
|
||||
|
||||
/* Restore ebp */
|
||||
lea ebp, [ebx+16]
|
||||
|
||||
/* Do local unwind */
|
||||
push esi
|
||||
push ebx
|
||||
call __local_unwind2
|
||||
add esp, 8
|
||||
|
||||
/* FIXME: Do NLG Notification */
|
||||
|
||||
/* Set new try level */
|
||||
lea ecx, [esi+esi*2]
|
||||
mov eax, [edi+ecx*4]
|
||||
mov [ebx+12], eax
|
||||
|
||||
/* Clear registers and call except handler */
|
||||
mov eax, [edi+ecx*4+8]
|
||||
xor ebx, ebx
|
||||
xor ecx, ecx
|
||||
xor edx, edx
|
||||
xor esi, esi
|
||||
xor edi, edi
|
||||
call eax
|
||||
|
||||
except_continue3:
|
||||
/* Reload try level and except again */
|
||||
mov edi, [ebx+8]
|
||||
lea ecx, [esi+esi*2]
|
||||
mov esi, [edi+ecx*4]
|
||||
jmp except_loop3
|
||||
|
||||
except_dismiss3:
|
||||
/* Dismiss it */
|
||||
mov eax, DISPOSITION_DISMISS
|
||||
jmp except_return3
|
||||
|
||||
except_search3:
|
||||
/* Continue searching */
|
||||
mov eax, DISPOSITION_CONTINUE_SEARCH
|
||||
jmp except_return3
|
||||
|
||||
/* Do local unwind */
|
||||
except_unwind3:
|
||||
push ebp
|
||||
mov ebp, [ebx+16]
|
||||
push -1
|
||||
push ebx
|
||||
call __local_unwind2
|
||||
add esp, 8
|
||||
|
||||
/* Retore EBP and set return disposition */
|
||||
pop ebp
|
||||
mov eax, DISPOSITION_CONTINUE_SEARCH
|
||||
|
||||
except_return3:
|
||||
/* Restore registers and stack */
|
||||
pop ebp
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
END
|
152
lib/pseh/i386/seh_prolog.s
Normal file
152
lib/pseh/i386/seh_prolog.s
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* COPYRIGHT: GNU GPL, see COPYING in the top level directory
|
||||
* PROJECT: ReactOS CRT
|
||||
* FILE: lib/crt/misc/i386/seh_prolog.S
|
||||
* PURPOSE: SEH Support for MSVC
|
||||
* PROGRAMMERS: Timo Kreuzer
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <asm.inc>
|
||||
|
||||
EXTERN __except_handler3:PROC
|
||||
|
||||
/* The very first thing a function compiled with MSVC containing SEH
|
||||
* will do is call __SEH_prolog like this:
|
||||
*
|
||||
* push <Number of stackbytes>
|
||||
* push <Address of exception handler>
|
||||
* call __SEH_prolog
|
||||
*
|
||||
* When entering the function the stack layout is like this:
|
||||
*
|
||||
* esp + 08: OLDFRAME.StackBytes
|
||||
* esp + 04: OLDFRAME.SEHTable
|
||||
* esp + 00: OLDFRAME.ReturnAddress
|
||||
*
|
||||
* __SEH_prolog will now setup the stack to the following layout:
|
||||
*
|
||||
* esp + N + 24: SEH_FRAME.OriginalEbp OLDFRAME.StackBytes
|
||||
* esp + N + 20: SEH_FRAME.Disable OLDFRAME.SEHTable
|
||||
* esp + N + 1C: SEH_FRAME.SEHTable OLDFRAME.ReturnAddress
|
||||
* esp + N + 18: SEH_FRAME.Handler
|
||||
* esp + N + 14: SEH_FRAME.PreviousRecord
|
||||
* esp + N + 10: SEH_FRAME.unused
|
||||
* esp + N + 0c: SEH_FRAME.NewEsp
|
||||
*
|
||||
* N bytes local variables
|
||||
* ...
|
||||
* esp + 08: SAFE_AREA.Ebx
|
||||
* esp + 04: SAFE_AREA.Esi
|
||||
* esp + 00: SAFE_AREA.Edi
|
||||
*
|
||||
* all this is documented here (with some minor errors):
|
||||
* http://reactos-blog.blogspot.com/2009/08/inside-mind-of-reactos-developer.html
|
||||
*/
|
||||
|
||||
OLDFRAME_ReturnAddress = 0 /* 0x00 */
|
||||
OLDFRAME_SEHTable = 4 /* 0x04 */
|
||||
OLDFRAME_StackBytes = 8 /* 0x08 */
|
||||
OLDFRAME_Size = 12 /* 0x0c */
|
||||
|
||||
SEH_FRAME_NewEsp = 0 /* 0x00 */
|
||||
SEH_FRAME_unused = 4 /* 0x04 */
|
||||
SEH_FRAME_PreviousRecord = 8 /* 0x08 */
|
||||
SEH_FRAME_Handler = 12 /* 0x0c */
|
||||
SEH_FRAME_SEHTable = 16 /* 0x10 */
|
||||
SEH_FRAME_Disable = 20 /* 0x14 */
|
||||
SEH_FRAME_OriginalEbp = 24 /* 0x18 */
|
||||
SEH_FRAME_Size = 28 /* 0x1c */
|
||||
|
||||
SAFE_AREA_Edi = 0 /* 0x00 */
|
||||
SAFE_AREA_Esi = 4 /* 0x04 */
|
||||
SAFE_AREA_Ebx = 8 /* 0x08 */
|
||||
SAFE_AREA_Size = 12 /* 0x0c */
|
||||
|
||||
|
||||
.code
|
||||
|
||||
PUBLIC __SEH_prolog
|
||||
__SEH_prolog:
|
||||
|
||||
/* Get the number of stack bytes to reserve */
|
||||
mov eax, [esp + OLDFRAME_StackBytes]
|
||||
|
||||
/* Push address of __except_handler3 on the stack */
|
||||
push offset __except_handler3
|
||||
|
||||
/* Push the old exception record on the stack */
|
||||
push dword ptr fs:0
|
||||
|
||||
/* Adjust stack allocation, add size of the stack frame minus 2 pushes */
|
||||
add eax, SEH_FRAME_Size + SAFE_AREA_Size - OLDFRAME_Size - 8
|
||||
|
||||
/* Save old ebp, overwriting OLDFRAME.StackBytes */
|
||||
mov [esp + 8 + OLDFRAME_StackBytes], ebp
|
||||
|
||||
/* Load new ebp, pointing to OLDFRAME.StackBytes */
|
||||
lea ebp, [esp + 8 + OLDFRAME_StackBytes]
|
||||
|
||||
/* Allocate stack space */
|
||||
sub esp, eax
|
||||
|
||||
/* Push the return address on the stack */
|
||||
push dword ptr [ebp - OLDFRAME_StackBytes + OLDFRAME_ReturnAddress]
|
||||
|
||||
/* Get address of the SEH table */
|
||||
mov eax, [ebp + OLDFRAME_SEHTable]
|
||||
|
||||
/* Save new esp */
|
||||
mov [ebp - SEH_FRAME_OriginalEbp + SEH_FRAME_NewEsp], esp
|
||||
|
||||
/* Safe SEH table, overwriting OLDFRAME.ReturnAddress */
|
||||
mov [ebp - SEH_FRAME_OriginalEbp + SEH_FRAME_SEHTable], eax
|
||||
|
||||
/* Safe the disable value, overwriting OLDFRAME.SEHTable */
|
||||
mov dword ptr [ebp - SEH_FRAME_OriginalEbp + SEH_FRAME_Disable], -1
|
||||
|
||||
/* Load the address of the new registration record */
|
||||
lea eax, [ebp - SEH_FRAME_OriginalEbp + SEH_FRAME_PreviousRecord]
|
||||
|
||||
/* Save registers */
|
||||
mov [esp + SAFE_AREA_Edi], edi
|
||||
mov [esp + SAFE_AREA_Esi], esi
|
||||
mov [esp + SAFE_AREA_Ebx], ebx
|
||||
|
||||
/* Enqueue the new record */
|
||||
mov fs:[0], eax
|
||||
|
||||
/* Return to the caller */
|
||||
ret
|
||||
|
||||
|
||||
PUBLIC __SEH_epilog
|
||||
__SEH_epilog:
|
||||
|
||||
/* Restore the previous exception registration record */
|
||||
mov ecx, [ebp - SEH_FRAME_OriginalEbp + SEH_FRAME_PreviousRecord]
|
||||
mov fs:[0], ecx
|
||||
|
||||
/* Restore saved registers */
|
||||
mov edi, [esp + 4 + SAFE_AREA_Edi]
|
||||
mov esi, [esp + 4 + SAFE_AREA_Esi]
|
||||
mov ebx, [esp + 4 + SAFE_AREA_Ebx]
|
||||
|
||||
/* Get the return address */
|
||||
mov ecx, [esp]
|
||||
|
||||
/* Clean up stack */
|
||||
mov esp, ebp
|
||||
|
||||
/* Get previous ebp */
|
||||
mov ebp, [esp]
|
||||
|
||||
/* Save return address */
|
||||
mov [esp], ecx
|
||||
|
||||
/* Return to the caller */
|
||||
ret
|
||||
|
||||
|
||||
END
|
Loading…
Reference in a new issue