April 14th, 2013, 07:22 AM
A few questions about exception handling
I have a few questions about exception handling in assembly language, Ive been reading up on the subject but have not been able to successfully implement my own handler yet.
First off, I would like to understand stack unwinding better. As I understand it, the PROC macro does something in order for the call stack to be walked in the event of an exception. Im my routines, when an exception occurs, the call stack is only usable to me about 1/2 the time. In every case, the call stack will be clean to the point of a managed to native transition, after that point sometimes the call stack will show the native functions that were traveled through to reach the point of error, other times it doesnt. When an exception is encountered it allways shows me the code that caused the exception, if the call stack is clean (shows the path through the native code), I can usually travel back up to the managed code and inspect the variables and such, if the call stack isnt clean, then usually when I bounce back to the managed code all the variables say something along the lines of them not being defined. My question is, what exactly does it take to set up a function in assembly language for proper unwinding?
All of my functions start off the same, I push all the registers the function uses (except the registers used for passing arguments), then it adjusts the stack frame pointer and calculates the offset to use when calling other functions. The offset is calculated only once at the beggining because in order for everything to work the stack pointer needs to be aligned to 16 bytes, once this offset is calculated I dont use push or pop, if I want to use the stack I use mov instructions. Anyways, the beggining of all functions looks something like this:
My other question is about implementing exception handling in a 64 bit windows system. Everything Ive read so far is based on 32 bit windows and Ive not been able to get it working. To this point for a limited exception handling, Ive been testing for conditions that may cause an exception before it reaches the code that could cause an exception, if my code caught it my code creates an array of 3 qwords with the first two values being 0, 0 and the third value represents a code Ive assigned myself to tell whatever function is getting this returned to it what was caught. This works fine for my code here because in all but a few functions I am returning an array of qwords, and the first element of the array contains the element count of that array (so even if the array represents zero, the first element will contain a 1 and the second will contain a zero), even though this works Im thinking if I didnt have to test for these conditions the functions would execute quicker and still be able to respond to the exceptions in the event one happens.
AsmFactorial64 PROC _val:PTR qword
mov rax, rbp ;save the current base pointer
sub rsp, 128 ;make enough room for local vals
mov rbp, rsp ;move the stack pointer into the base pointer (the base pointer will be used in place of pushes and pops)
mov qword ptr[rbp+8], rax ;save the base pointer on the stack to make it easy to restore
mov qword ptr[rbp+16], rcx ;save the passed in argument
;calculate the offset
mov rax, rsp ;move the stack pointer into rax before the following push so it doesnt count it
push rdx ;save the rdx register
sub rax, 28h ;this is the basic offset for calling functions, room must be made for 4 variables even if they arent used
xor rdx, rdx ;clear the rdx register before doing the division
div _sixteen ;divide the value in rax by 16
cmp rdx, 0 ;rdx will contain either 0 or 8 at this point,
cmove rax, _eight ;we want it to contain 8 because when we call a function the return address will be pushed onto the stack thereby aligning
cmovne rax, _zero ;the stack to 16 bytes
add rax, 28h ;we add the 28h to whatever we stored in rax to give us the total offset to use when calling functions
pop rdx ;restore the contents of the rdx register
mov qword ptr[rbp], rax ;mov _totalsub, rax
;a basic call to a function
mov rcx, _val1
mov rdx, _val2
sub rsp, qword ptr[rbp]
add rsp, qword ptr[rbp]
mov _returnval, rax
;at the end of each function we restore the frame pointer, stack pointer, and pop our saved registers
mov rdx, qword ptr[rbp+8] ;move the original value of rbp into rdx
mov rsp, rbp ;move the value into rsp
add rsp, 128 ;adjust rsp by 128 bytes that we saved for our variables
mov rbp, rdx ;restore rbp to its original value
mov rax, _returnval ;put our return value in rax
Also from what Ive been reading, exception handling is thread based, so I would have to setup the exception handlers for each thread? Is there a way to have the handlers installed on thread creation outside of the assembly code? Do I have to make the assembly code thread aware to check if my handlers are installed?
Thanks in advance
Click Here to Expand Forum to Full Width
This is a CodeGuru survey question.