1/* 2 * COPYRIGHT: GNU GPL, see COPYING in the top level directory 3 * PROJECT: ReactOS CRT 4 * FILE: lib/crt/misc/i386/seh_prolog.S 5 * PURPOSE: SEH Support for MSVC 6 * PROGRAMMERS: Timo Kreuzer 7 */ 8 9/* INCLUDES ******************************************************************/ 10 11#include <asm.inc> 12 13EXTERN __except_handler3:PROC 14 15/* The very first thing a function compiled with MSVC containing SEH 16 * will do is call __SEH_prolog like this: 17 * 18 * push <Number of stackbytes> 19 * push <Address of exception handler> 20 * call __SEH_prolog 21 * 22 * When entering the function the stack layout is like this: 23 * 24 * esp + 08: OLDFRAME.StackBytes 25 * esp + 04: OLDFRAME.SEHTable 26 * esp + 00: OLDFRAME.ReturnAddress 27 * 28 * __SEH_prolog will now setup the stack to the following layout: 29 * 30 * esp + N + 24: SEH_FRAME.OriginalEbp OLDFRAME.StackBytes 31 * esp + N + 20: SEH_FRAME.Disable OLDFRAME.SEHTable 32 * esp + N + 1C: SEH_FRAME.SEHTable OLDFRAME.ReturnAddress 33 * esp + N + 18: SEH_FRAME.Handler 34 * esp + N + 14: SEH_FRAME.PreviousRecord 35 * esp + N + 10: SEH_FRAME.unused 36 * esp + N + 0c: SEH_FRAME.NewEsp 37 * 38 * N bytes local variables 39 * ... 40 * esp + 08: SAFE_AREA.Ebx 41 * esp + 04: SAFE_AREA.Esi 42 * esp + 00: SAFE_AREA.Edi 43 * 44 * all this is documented here (with some minor errors): 45 * http://reactos-blog.blogspot.com/2009/08/inside-mind-of-reactos-developer.html 46 */ 47 48OLDFRAME_ReturnAddress = 0 /* 0x00 */ 49OLDFRAME_SEHTable = 4 /* 0x04 */ 50OLDFRAME_StackBytes = 8 /* 0x08 */ 51OLDFRAME_Size = 12 /* 0x0c */ 52 53SEH_FRAME_NewEsp = 0 /* 0x00 */ 54SEH_FRAME_unused = 4 /* 0x04 */ 55SEH_FRAME_PreviousRecord = 8 /* 0x08 */ 56SEH_FRAME_Handler = 12 /* 0x0c */ 57SEH_FRAME_SEHTable = 16 /* 0x10 */ 58SEH_FRAME_Disable = 20 /* 0x14 */ 59SEH_FRAME_OriginalEbp = 24 /* 0x18 */ 60SEH_FRAME_Size = 28 /* 0x1c */ 61 62SAFE_AREA_Edi = 0 /* 0x00 */ 63SAFE_AREA_Esi = 4 /* 0x04 */ 64SAFE_AREA_Ebx = 8 /* 0x08 */ 65SAFE_AREA_Size = 12 /* 0x0c */ 66 67 68.code 69 70PUBLIC __SEH_prolog 71__SEH_prolog: 72 73 /* Get the number of stack bytes to reserve */ 74 mov eax, [esp + OLDFRAME_StackBytes] 75 76 /* Push address of __except_handler3 on the stack */ 77 push offset __except_handler3 78 79 /* Push the old exception record on the stack */ 80 push dword ptr fs:0 81 82 /* Adjust stack allocation, add size of the stack frame minus 2 pushes */ 83 add eax, SEH_FRAME_Size + SAFE_AREA_Size - OLDFRAME_Size - 8 84 85 /* Save old ebp, overwriting OLDFRAME.StackBytes */ 86 mov [esp + 8 + OLDFRAME_StackBytes], ebp 87 88 /* Load new ebp, pointing to OLDFRAME.StackBytes */ 89 lea ebp, [esp + 8 + OLDFRAME_StackBytes] 90 91 /* Allocate stack space */ 92 sub esp, eax 93 94 /* Push the return address on the stack */ 95 push dword ptr [ebp - OLDFRAME_StackBytes + OLDFRAME_ReturnAddress] 96 97 /* Get address of the SEH table */ 98 mov eax, [ebp + OLDFRAME_SEHTable] 99 100 /* Save new esp */ 101 mov [ebp - SEH_FRAME_OriginalEbp + SEH_FRAME_NewEsp], esp 102 103 /* Safe SEH table, overwriting OLDFRAME.ReturnAddress */ 104 mov [ebp - SEH_FRAME_OriginalEbp + SEH_FRAME_SEHTable], eax 105 106 /* Safe the disable value, overwriting OLDFRAME.SEHTable */ 107 mov dword ptr [ebp - SEH_FRAME_OriginalEbp + SEH_FRAME_Disable], -1 108 109 /* Load the address of the new registration record */ 110 lea eax, [ebp - SEH_FRAME_OriginalEbp + SEH_FRAME_PreviousRecord] 111 112 /* Save registers */ 113 mov [esp + SAFE_AREA_Edi], edi 114 mov [esp + SAFE_AREA_Esi], esi 115 mov [esp + SAFE_AREA_Ebx], ebx 116 117 /* Enqueue the new record */ 118 mov fs:[0], eax 119 120 /* Return to the caller */ 121 ret 122 123 124PUBLIC __SEH_epilog 125__SEH_epilog: 126 127 /* Restore the previous exception registration record */ 128 mov ecx, [ebp - SEH_FRAME_OriginalEbp + SEH_FRAME_PreviousRecord] 129 mov fs:[0], ecx 130 131 /* Restore saved registers */ 132 mov edi, [esp + 4 + SAFE_AREA_Edi] 133 mov esi, [esp + 4 + SAFE_AREA_Esi] 134 mov ebx, [esp + 4 + SAFE_AREA_Ebx] 135 136 /* Get the return address */ 137 mov ecx, [esp] 138 139 /* Clean up stack */ 140 mov esp, ebp 141 142 /* Get previous ebp */ 143 mov ebp, [esp] 144 145 /* Save return address */ 146 mov [esp], ecx 147 148 /* Return to the caller */ 149 ret 150 151 152END 153