Uninformed: Informative Information for the Uninformed

Vol 4» 2006.Jun

Exception Handling on x64

On x86, exception handling is accomplished through the adding and removing of exception registration records on a per-thread basis. When a function is entered that makes use of an exception handler, it constructs an exception registration record on the stack that is composed of an exception handler (a function pointer), and a pointer to the next element in the exception handler list. This list of exception registration records is stored relative to fs:[0]. When an exception occurs, the exception dispatcher walks the list of exception handlers and calls each one, checking to see if they are capable of handling the exception that occurred. While this approach works perfectly fine, Microsoft realized that there were better ways to go about it. First of all, the adding and removing of exception registration records that are static in the context of an execution path adds needless execution overhead. Secondly, the security implications of storing a function pointer on the stack have been made very obvious, especially in the case where that function pointer can be called after an exception is generated (such as an access violation). Finally, the process of unwinding call frames is muddled with limitations, thus making it a more complicated process than it might otherwise need to be[6].

With these things in mind, Microsoft completely revamped the way exception handling is accomplished on x64. The major changes center around the approaches Microsoft has taken to solve the three major deficiencies found on x86. First, Microsoft solved the execution time overhead issue of adding and removing exception handlers by moving all of the static exception handling information into a static location in the binary. This location, known as the .pdata section, is described by the PE32+'s Exception Directory. The structure of this section will be described in the exception directory subsection. By eliminating the need to add and remove exception handlers on the fly, Microsoft has also eliminated the security issue found on x86 with regard to overwriting the function pointer of an exception handler. Perhaps most importantly, the process involved in unwinding call frames has been drastically improved through the formalization of the frame unwinding process. This will be discussed in the subsection on unwind information.