Outcome:
1. How does __except_handler3 call the __except block without returning back?
Before entering __except block, the compiler always generates the following statement:
mov esp,dword ptr [ebp-18h]
It will restore the esp register to the value of before executing any code.
2. Since the __except bock will restore the esp to the value of before executing any code, how does it use the local variables?
Since the local variables are accessed through the offset of ebp, although the esp does not point to the stack top anymore, compiler can still use ebp offset to use them. Take the local variables, "dw" and "str" for example, see below:
char *str="this is a local string";
0041338B mov dword ptr [ebp-20h],424E70h
int dw=3;
004133A6 mov dword ptr [ebp-2Ch],3
the __except block will use them like this:
0041340A mov esp,dword ptr [ebp-18h]
{
printf("We handled this exception %d, %s\n", dw, str);
0041340D mov eax,dword ptr [ebp-20h]
00413410 push eax
00413411 mov ecx,dword ptr [ebp-2Ch]
00413414 push ecx
Additionally, based on my test, once the SEH is used in the function, the VC optimizer will not omit Frame Pointer register(ebp) anyway, it will always save the ebp for offset usage.
3. 2 points of code in __except_handler3.
Before calling the __except code block, the __except_handler3 sets the ebp register to the original saved ebp value in the extended EXCEPTION_REGISTRATION so that when the __except block is executed, the ebp register can be used to lookup the function local variables that contains __except block.
Also, before calling the __except code block, the __except_handler3 sets the trylevel field in the EXCEPTION_REGISTRATION to the parent __try block trylevel value, so that it can handle any nested exception generated in __except code block.