Exception Handler Bug
Posted: Mon Oct 20, 2008 6:54 pm
Hi,
When trying to test my exception handling routines, I had a stack problem and realized that it is a bug current in all the exception handling examples in the tutorials.
Here is an explanation and a solution to it.
When an interrupt fires, the stack looks like this:
...
EFlags
CS
EIP <-- esp points here
[Error] <---+ or here depending on the exception
...
However, given a function in C++ such as:
This is compiled expecting the stack to look like:
...
eflags
cs
eip
retn addr
prev ebp <-- ebp points here
local vars ...
The parameters are referenced using
Therefore, the code that the C++ compiler and linker generates has a 4 byte offset because there is no return address for an interrupt handler. This causes all the parameters to index the wrong elements on the stack.
A workaround for this exists by subtracting 4 bytes from ebp so all the parameter references become correct. This has the side effect that any local variables will be 4 bytes lower in memory than expected but this will only have any effect if you try using inline assembly to reference them. One final point to say is that, because this isn't a naked function, the stack must be restored before the iret instruction.
Therefore, here is a function that works properly:
~Andrew
When trying to test my exception handling routines, I had a stack problem and realized that it is a bug current in all the exception handling examples in the tutorials.
Here is an explanation and a solution to it.
When an interrupt fires, the stack looks like this:
...
EFlags
CS
EIP <-- esp points here
[Error] <---+ or here depending on the exception
...
However, given a function in C++ such as:
Code: Select all
void Div0(unsigned int eip,unsigned int cs,unsigned int eflags)
{
...
}
...
eflags
cs
eip
retn addr
prev ebp <-- ebp points here
local vars ...
The parameters are referenced using
Code: Select all
dword ptr [ebp +- num]
A workaround for this exists by subtracting 4 bytes from ebp so all the parameter references become correct. This has the side effect that any local variables will be 4 bytes lower in memory than expected but this will only have any effect if you try using inline assembly to reference them. One final point to say is that, because this isn't a naked function, the stack must be restored before the iret instruction.
Therefore, here is a function that works properly:
Code: Select all
void Div0(unsigned int eip,unsigned int cs,unsigned int eflags)
{
__asm sub ebp,4
//deal with Div0
__asm{
pop ebp
iretd
}
}