[GHC] #6079: SEH exception handler not implemented on Win64
GHC
ghc-devs at haskell.org
Mon Jan 26 22:45:45 UTC 2015
#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
More information about the ghc-tickets
mailing list