Re: [GHC] #6079: SEH exception handler not implemented on Win64

#6079: SEH exception handler not implemented on Win64 -------------------------------------+------------------------------------- Reporter: igloo | Owner: Phyx- Type: bug | Status: new Priority: normal | Milestone: 7.12.1 Component: Runtime System | Version: 7.5 Resolution: | Keywords: Operating System: Windows | Architecture: x86_64 Type of failure: None/Unknown | (amd64) Blocked By: | Test Case: derefnull, Related Tickets: | divbyzero | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- Comment (by Phyx-): Summary of what's changed and how It affects the GHC side of things: on x86 SEH handling was done via the stack. On a thread FS[0] would always point to the SEH linked list. It was also prone to buffer overflows and made it hard to share error handlers. on x64 it was cleaned up a bit and the EH information is now stored in the the PE headers in tables. instead of an EH covering an entire thread until popped, you know have to explicitly specify the rva (relative virtual address) of the region to which the EH should apply. Microsoft compilers calculate this information at compile time from the !__try, !__catch and !__except1 symbols and this information is statically added to the PE file. GCC's implementation works by dynamically manipulating the table (using '''RtlAddFunctionTable''' and related functions). It's implemented in MingW64 from version 4.6.2 (current version of msys2 ships with newer version so should be fine) and is based on GAS's implementation http://code.google.com/p/propgcc/source/browse/binutils/gas/config/obj- coff-seh.h The only way to use this is inline assembly in gcc: BEGIN_CATCH and END_CATCH theoretically become:
long CALLBACK !__hs_exception_handler(EXCEPTION_POINTERS *exception_data);
#define BEGIN_CATCH asm (".l_start:\n" \ "\t.seh_handler !__C_specific_handler, @except\n" \ "\t.seh_handlerdata\n" \ "\t.long 1\n" \ "\t.rva .l_start, .l_end, !__hs_exception_handler, .l_end\n" \ "\t.text" \ );
#define END_CATCH asm ("nop\n" \ "\t.l_end:\n" \ "\tnop\n" \ );
everything between the .l_start and .l_end label is covered by the function !__hs_exception_handler. {{{ The interesting part here is the line "\t.rva .l_startw, .l_endw, _gnu_exception_handler ,.l_endw\n". The first rva is the start-address of the first instruction within try-block, the next is the end-address of the try-block (be aware that it needs to +1 after end of last instruction in try-block). The third rva is the handler to be called, and the fourth is the address of the finally-block. }}} (NOTE: the \t are only for indenting if viewing the dissassembly generated from gcc with -S) --- Implementation wise, a few things make it difficult: 1) the function real_main() in RtsMain is decorated with !__noreturn!__, this makes GCC perform dead code elimination and remove the END_CATCH, the linker will then refuse to link as the .l_end label will be missing. Instead moving the BEGIN_CATCH and END_CATCH blocks inside the real_main to appropriate positions allows it all to work. --- I have the changes implemented but the handler is not being called for some reason. I will figure out what's wrong and create a patch. I'm concerned that when linking, the .l_end label is put in a position that does not cover the user code, in which case this implementation would probably get more complex -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/6079#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC