[CMAKE]
[reactos.git] / reactos / lib / sdk / crt / except / i386 / seh_prolog.s
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
13 EXTERN __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
48 OLDFRAME_ReturnAddress = 0 /* 0x00 */
49 OLDFRAME_SEHTable = 4 /* 0x04 */
50 OLDFRAME_StackBytes = 8 /* 0x08 */
51 OLDFRAME_Size = 12 /* 0x0c */
52
53 SEH_FRAME_NewEsp = 0 /* 0x00 */
54 SEH_FRAME_unused = 4 /* 0x04 */
55 SEH_FRAME_PreviousRecord = 8 /* 0x08 */
56 SEH_FRAME_Handler = 12 /* 0x0c */
57 SEH_FRAME_SEHTable = 16 /* 0x10 */
58 SEH_FRAME_Disable = 20 /* 0x14 */
59 SEH_FRAME_OriginalEbp = 24 /* 0x18 */
60 SEH_FRAME_Size = 28 /* 0x1c */
61
62 SAFE_AREA_Edi = 0 /* 0x00 */
63 SAFE_AREA_Esi = 4 /* 0x04 */
64 SAFE_AREA_Ebx = 8 /* 0x08 */
65 SAFE_AREA_Size = 12 /* 0x0c */
66
67
68 .code
69
70 PUBLIC __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
124 PUBLIC __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
152 END