xref: /reactos/sdk/lib/pseh/i386/seh_prolog.s (revision 5100859e)
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