diff mbox

[RFC] Win64 SEH support

Message ID 4CC1CE9A.3090904@redhat.com
State New
Headers show

Commit Message

Richard Henderson Oct. 22, 2010, 5:49 p.m. UTC
This is a consolidated patch for the work I've been doing
on a (git) branch for SEH support.  I've been intending to
mash the branch patches together and separate them back
out into logical units.  To some extent I've already begun
that with some of the patches that have already been applied
to mainline, however, I realize that I'm running out of time
to officially submit this before the end of stage1.

Logically, there are 3 different portions in this patch:

(1) SEH unwind info generation,

(2) Changes to prologue/epilogue generation forced
    by limitations in unwind info representation,

(3) SEH unwind runtime, and the symbol name changes
    and preprocessor defines within the compiler to
    support that.

I think the only real question that's open is if we should
have a configure switch a-la --enable-sjlj-exceptions in
order to switch between dwarf2 and seh based exceptions.

I personally don't think that's very useful.  The main
reason to want to use the x64 seh unwind info is that it
is supported by the object format and the system similar
to how PT_GNU_FRAME is supported under ELF -- one no longer
has to register and de-register eh_frame data during
shared library load and unload.

Comments?


r~



 gcc/ada/raise-gcc.c                                    |   15
 gcc/config/i386/cygming.h                              |   40 +
 gcc/config/i386/i386-protos.h                          |   11
 gcc/config/i386/i386.c                                 |  197 ++++++
 gcc/config/i386/i386.h                                 |    9
 gcc/config/i386/i386.md                                |  115 +---
 gcc/config/i386/libgcc-cygming.ver                     |   28
 gcc/config/i386/t-cygming                              |    3
 gcc/config/i386/t-mingw-w64                            |    5
 gcc/config/i386/winnt.c                                |  460 ++++++++++++++++
 gcc/coretypes.h                                        |    3
 gcc/dwarf2out.c                                        |   10
 gcc/expr.c                                             |    3
 gcc/opts.c                                             |    6
 gcc/testsuite/g++.dg/torture/stackalign/stackalign.exp |   12
 gcc/testsuite/gcc.dg/torture/stackalign/stackalign.exp |   11
 gcc/testsuite/lib/target-supports.exp                  |   11
 gcc/unwind-c.c                                         |   15
 gcc/unwind-seh.c                                       |  483 +++++++++++++++++
 gcc/unwind-seh.h                                       |  258 +++++++++
 libjava/exception.cc                                   |   20
 libjava/libgcj.ver                                     |    1
 libobjc/exception.c                                    |   15
 libstdc++-v3/config/abi/pre/gnu.ver                    |    1
 libstdc++-v3/libsupc++/eh_personality.cc               |   20
 25 files changed, 1612 insertions(+), 140 deletions(-)

Comments

Arnaud Charlet Oct. 22, 2010, 5:52 p.m. UTC | #1
> diff --git a/gcc/ada/raise-gcc.c b/gcc/ada/raise-gcc.c
> index 512ff36..d23ecf5 100644
> --- a/gcc/ada/raise-gcc.c
> +++ b/gcc/ada/raise-gcc.c
> @@ -1029,6 +1029,8 @@ extern void __gnat_notify_unhandled_exception
> (void);
>  
>  #ifdef __USING_SJLJ_EXCEPTIONS__
>  #define PERSONALITY_FUNCTION    __gnat_personality_sj0
> +#elif defined(__SEH__)
> +#define PERSONALITY_FUNCTION    __gnat_personality_imp

Shouldn't that be __gnat_personality_seh0 instead?

> +#ifdef __SEH__
> +EXCEPTION_DISPOSITION
> +__gnat_personality_seh0 (PEXCEPTION_RECORD ms_exc, void
> *this_frame,
> +			 PCONTEXT ms_orig_context,
> +			 PDISPATCHER_CONTEXT ms_disp)
> +{
> +  return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
> +				ms_disp, __gnat_personality_imp);
> +}
> +#endif /* SEH */
>  #else
>  /* ! IN_RTS  */
Richard Henderson Oct. 22, 2010, 6:03 p.m. UTC | #2
On 10/22/2010 10:52 AM, Arnaud Charlet wrote:
>> diff --git a/gcc/ada/raise-gcc.c b/gcc/ada/raise-gcc.c
>> index 512ff36..d23ecf5 100644
>> --- a/gcc/ada/raise-gcc.c
>> +++ b/gcc/ada/raise-gcc.c
>> @@ -1029,6 +1029,8 @@ extern void __gnat_notify_unhandled_exception
>> (void);
>>  
>>  #ifdef __USING_SJLJ_EXCEPTIONS__
>>  #define PERSONALITY_FUNCTION    __gnat_personality_sj0
>> +#elif defined(__SEH__)
>> +#define PERSONALITY_FUNCTION    __gnat_personality_imp
> 
> Shouldn't that be __gnat_personality_seh0 instead?
> 
>> +#ifdef __SEH__
>> +EXCEPTION_DISPOSITION
>> +__gnat_personality_seh0 (PEXCEPTION_RECORD ms_exc, void
>> *this_frame,
>> +			 PCONTEXT ms_orig_context,
>> +			 PDISPATCHER_CONTEXT ms_disp)
>> +{
>> +  return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
>> +				ms_disp, __gnat_personality_imp);
>> +}

No, look closer.  The _imp function is passed via argument to
the generic _GCC_specific_handler function which does the 
conversion between "GCC exceptions" and "SEH exceptions".

Would it be clearer if that penultimate line were written
using the PERSONALITY_FUNCTION macro?

r~
Kai Tietz Oct. 22, 2010, 6:12 p.m. UTC | #3
2010/10/22 Richard Henderson <rth@redhat.com>:
> This is a consolidated patch for the work I've been doing
> on a (git) branch for SEH support.  I've been intending to
> mash the branch patches together and separate them back
> out into logical units.  To some extent I've already begun
> that with some of the patches that have already been applied
> to mainline, however, I realize that I'm running out of time
> to officially submit this before the end of stage1.

Thank you for posting them now.

> I think the only real question that's open is if we should
> have a configure switch a-la --enable-sjlj-exceptions in
> order to switch between dwarf2 and seh based exceptions.
>
> I personally don't think that's very useful.  The main
> reason to want to use the x64 seh unwind info is that it
> is supported by the object format and the system similar
> to how PT_GNU_FRAME is supported under ELF -- one no longer
> has to register and de-register eh_frame data during
> shared library load and unload.
>
> Comments?

I know that I were initially voting for having here a configure option
to switch between SjLj and the new SEH unwinding. As I am testing this
patch already for I while, I admit that I came also to the point that
it isn't essential (and maybe even problematic in some points) to have
this fallback option to support here SjLj. So my vote is for not
supporting SjLj by configure for this target anymore.


Regards,
Kai
Richard Henderson Oct. 22, 2010, 6:33 p.m. UTC | #4
On 10/22/2010 11:53 AM, Dave Korn wrote:
> On 22/10/2010 18:49, Richard Henderson wrote:
> 
>> +# In order to work around the very problems that force us to now generally
>> +# create a libgcc.so, glibc reexported a number of routines from libgcc.a.
>> +# By now choosing the same version tags for these specific routines, we
>> +# maintain enough binary compatibility to allow future versions of glibc
>> +# to defer implementation of these routines to libgcc.so via DT_AUXILIARY.
> 
>   This comment seems odd to me.  None of the cygming platforms support glibc.
>  (Or DT_AUXILIARY for that matter).  We use the version script just to filter
> what symbols get dllexported from the libgcc DLL.

Heh.  Too much copy/paste.  I'll kill that bit.


r~
Arnaud Charlet Oct. 22, 2010, 6:52 p.m. UTC | #5
> >> +++ b/gcc/ada/raise-gcc.c
> >> @@ -1029,6 +1029,8 @@ extern void __gnat_notify_unhandled_exception
> >> (void);
> >>  
> >>  #ifdef __USING_SJLJ_EXCEPTIONS__
> >>  #define PERSONALITY_FUNCTION    __gnat_personality_sj0
> >> +#elif defined(__SEH__)
> >> +#define PERSONALITY_FUNCTION    __gnat_personality_imp
> > 
> > Shouldn't that be __gnat_personality_seh0 instead?
> > 
> >> +#ifdef __SEH__
> >> +EXCEPTION_DISPOSITION
> >> +__gnat_personality_seh0 (PEXCEPTION_RECORD ms_exc, void
> >> *this_frame,
> >> +			 PCONTEXT ms_orig_context,
> >> +			 PDISPATCHER_CONTEXT ms_disp)
> >> +{
> >> +  return _GCC_specific_handler (ms_exc, this_frame,
> >> ms_orig_context,
> >> +				ms_disp, __gnat_personality_imp);
> >> +}
> 
> No, look closer.  The _imp function is passed via argument to
> the generic _GCC_specific_handler function which does the 
> conversion between "GCC exceptions" and "SEH exceptions".

OK, I see now. Thanks.

> Would it be clearer if that penultimate line were written
> using the PERSONALITY_FUNCTION macro?

Possibly yes. Olivier, what you think?

Arno
Dave Korn Oct. 22, 2010, 6:53 p.m. UTC | #6
On 22/10/2010 18:49, Richard Henderson wrote:

> +# In order to work around the very problems that force us to now generally
> +# create a libgcc.so, glibc reexported a number of routines from libgcc.a.
> +# By now choosing the same version tags for these specific routines, we
> +# maintain enough binary compatibility to allow future versions of glibc
> +# to defer implementation of these routines to libgcc.so via DT_AUXILIARY.

  This comment seems odd to me.  None of the cygming platforms support glibc.
 (Or DT_AUXILIARY for that matter).  We use the version script just to filter
what symbols get dllexported from the libgcc DLL.

    cheers,
      DaveK
Mike Stump Oct. 22, 2010, 7:52 p.m. UTC | #7
On Oct 22, 2010, at 10:49 AM, Richard Henderson wrote:
> I think the only real question that's open is if we should
> have a configure switch a-la --enable-sjlj-exceptions in
> order to switch between dwarf2 and seh based exceptions.

No.  I look at the configure switch (and even the runtime flag) as a way of doing A/B comparisons to compare behavior between the two to make EH bring-up/diagnosis easier.  Users that might use such flags, are probably doing it to work around bugs that would be better addressed by actually fixing any bugs in the code.  I'd almost go the other way, and see if we can't rip out the existing flags (that are exposed to the users).
Dave Korn Oct. 23, 2010, 12:11 a.m. UTC | #8
On 22/10/2010 20:52, Mike Stump wrote:
> On Oct 22, 2010, at 10:49 AM, Richard Henderson wrote:
>> I think the only real question that's open is if we should have a
>> configure switch a-la --enable-sjlj-exceptions in order to switch between
>> dwarf2 and seh based exceptions.
> 
> No.  I look at the configure switch (and even the runtime flag) as a way of
> doing A/B comparisons to compare behavior between the two to make EH
> bring-up/diagnosis easier.  Users that might use such flags, are probably
> doing it to work around bugs that would be better addressed by actually
> fixing any bugs in the code. 

  Or they want to interoperate with old code.  This is a major ABI break.

> I'd almost go the other way, and see if we
> can't rip out the existing flags (that are exposed to the users).

  I'm not so sure about that.  I think it might be better to have such a
switch, at least for the first two or three release series after adding a
feature like this.

    cheers,
      DaveK
Chris Lattner Oct. 23, 2010, 1:16 p.m. UTC | #9
Hi Richard,

Out of curiosity, how does this avoid the well-known SEH patents by borland and Microsoft?

-Chris

On Oct 22, 2010, at 7:49 PM, Richard Henderson <rth@redhat.com> wrote:

> This is a consolidated patch for the work I've been doing
> on a (git) branch for SEH support.  I've been intending to
> mash the branch patches together and separate them back
> out into logical units.  To some extent I've already begun
> that with some of the patches that have already been applied
> to mainline, however, I realize that I'm running out of time
> to officially submit this before the end of stage1.
> 
> Logically, there are 3 different portions in this patch:
> 
> (1) SEH unwind info generation,
> 
> (2) Changes to prologue/epilogue generation forced
>    by limitations in unwind info representation,
> 
> (3) SEH unwind runtime, and the symbol name changes
>    and preprocessor defines within the compiler to
>    support that.
> 
> I think the only real question that's open is if we should
> have a configure switch a-la --enable-sjlj-exceptions in
> order to switch between dwarf2 and seh based exceptions.
> 
> I personally don't think that's very useful.  The main
> reason to want to use the x64 seh unwind info is that it
> is supported by the object format and the system similar
> to how PT_GNU_FRAME is supported under ELF -- one no longer
> has to register and de-register eh_frame data during
> shared library load and unload.
> 
> Comments?
> 
> 
> r~
> 
> 
> 
> gcc/ada/raise-gcc.c                                    |   15
> gcc/config/i386/cygming.h                              |   40 +
> gcc/config/i386/i386-protos.h                          |   11
> gcc/config/i386/i386.c                                 |  197 ++++++
> gcc/config/i386/i386.h                                 |    9
> gcc/config/i386/i386.md                                |  115 +---
> gcc/config/i386/libgcc-cygming.ver                     |   28
> gcc/config/i386/t-cygming                              |    3
> gcc/config/i386/t-mingw-w64                            |    5
> gcc/config/i386/winnt.c                                |  460 ++++++++++++++++
> gcc/coretypes.h                                        |    3
> gcc/dwarf2out.c                                        |   10
> gcc/expr.c                                             |    3
> gcc/opts.c                                             |    6
> gcc/testsuite/g++.dg/torture/stackalign/stackalign.exp |   12
> gcc/testsuite/gcc.dg/torture/stackalign/stackalign.exp |   11
> gcc/testsuite/lib/target-supports.exp                  |   11
> gcc/unwind-c.c                                         |   15
> gcc/unwind-seh.c                                       |  483 +++++++++++++++++
> gcc/unwind-seh.h                                       |  258 +++++++++
> libjava/exception.cc                                   |   20
> libjava/libgcj.ver                                     |    1
> libobjc/exception.c                                    |   15
> libstdc++-v3/config/abi/pre/gnu.ver                    |    1
> libstdc++-v3/libsupc++/eh_personality.cc               |   20
> 25 files changed, 1612 insertions(+), 140 deletions(-)
> 
> <d-seh-1>
Richard Henderson Oct. 23, 2010, 3:20 p.m. UTC | #10
On 10/23/2010 06:16 AM, Chris Lattner wrote:
> Out of curiosity, how does this avoid the well-known SEH patents by borland and Microsoft?

I have no idea what you're talking about.

I assume we're not violating any patents simply because
we're using the published interfaces provided by Windows,
not re-implementing them.


r~
Chris Lattner Oct. 23, 2010, 7:37 p.m. UTC | #11
Ok, I don't know much about SEH and don't really care, it was just my understanding that patents were why gcc didn't already support it. *shrug*

-Chris

On Oct 23, 2010, at 5:20 PM, Richard Henderson <rth@redhat.com> wrote:

> On 10/23/2010 06:16 AM, Chris Lattner wrote:
>> Out of curiosity, how does this avoid the well-known SEH patents by borland and Microsoft?
> 
> I have no idea what you're talking about.
> 
> I assume we're not violating any patents simply because
> we're using the published interfaces provided by Windows,
> not re-implementing them.
> 
> 
> r~
Charles Wilson Oct. 23, 2010, 8:10 p.m. UTC | #12
On 10/23/2010 3:37 PM, Chris Lattner wrote:
> Ok, I don't know much about SEH and don't really care, it was just my understanding that patents were why gcc didn't already support it. *shrug*
> 
> On Oct 23, 2010, at 5:20 PM, Richard Henderson wrote:
>> I have no idea what you're talking about.
>>
>> I assume we're not violating any patents simply because
>> we're using the published interfaces provided by Windows,
>> not re-implementing them.

From the GCC Wiki
http://gcc.gnu.org/wiki/WindowsGCCImprovements

"Unfortunately, GCC does not support SEH yet. Casper Hornstrup had
created an initial implementation, but it was never merged into mainline
GCC. Some people have expressed concerns over a Borland patent on SEH
[1], but Borland seems to dismiss these concerns [2] as balderdash."

[1] http://wiki.ffii.org/Wine05En
[2] http://blogs.borland.com/dcc/archive/2005/05/12/4294.aspx Dead link,
but wayback machine has:
http://web.archive.org/web/20070818053531/blogs.codegear.com/dcc/archive/2005/05/12/4294.aspx

--
Chuck
Florian Weimer Oct. 24, 2010, 10:57 a.m. UTC | #13
* Chris Lattner:

> Out of curiosity, how does this avoid the well-known SEH patents by
> borland and Microsoft?

AFAIK, SEH on Win64 does not use a control value on the stack, but
tables in the style of DWARF exception handling.

Win32 is different, and allegedly affected by the Borland patent
(whoever controls that nowadays).  I don't know if the previous
reluctance was based on valid IP concerns or on general disregard of
the Windows platform.
Olivier Hainque Oct. 25, 2010, 9:03 a.m. UTC | #14
Arnaud Charlet wrote:
> >  +#ifdef __SEH__
> >  +EXCEPTION_DISPOSITION
> >  +__gnat_personality_seh0 (PEXCEPTION_RECORD ms_exc, void  *this_frame,
> >  +			 PCONTEXT ms_orig_context,
> >  +			 PDISPATCHER_CONTEXT ms_disp)
> >  +{
> >  +  return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
> >  +				ms_disp, __gnat_personality_imp);
> >  +}

> > The _imp function is passed via argument to the generic
> > _GCC_specific_handler function which does the conversion between
> > "GCC exceptions" and "SEH exceptions".

> > Would it be clearer if that penultimate line were written
> > using the PERSONALITY_FUNCTION macro?
> 
> Possibly yes. Olivier, what you think?

 I think it would clarify a bit, yes.

 My understanding is that we have two functions named "personality"
 with different conceptual roles in the processing chain; very roughly:
 interfacing with the unwinding engine, via indirect call through pointer
 in the unwind info for a frame, vs decoding the gcc exception tables to
 decide for a given context.

 PERSONALITY_FUNCTION denotes a specific one of those roles (the latter),
 and everything that can be done to make the relationships explicit seems
 useful to me. In many cases, the same function plays the two roles so
 there's no ambiguity.

 Thanks Richard for this very nice piece of work :)

 Olivier
diff mbox

Patch

diff --git a/gcc/ada/raise-gcc.c b/gcc/ada/raise-gcc.c
index 512ff36..d23ecf5 100644
--- a/gcc/ada/raise-gcc.c
+++ b/gcc/ada/raise-gcc.c
@@ -1029,6 +1029,8 @@  extern void __gnat_notify_unhandled_exception (void);
 
 #ifdef __USING_SJLJ_EXCEPTIONS__
 #define PERSONALITY_FUNCTION    __gnat_personality_sj0
+#elif defined(__SEH__)
+#define PERSONALITY_FUNCTION    __gnat_personality_imp
 #else
 #define PERSONALITY_FUNCTION    __gnat_personality_v0
 #endif
@@ -1064,6 +1066,9 @@  typedef int version_arg_t;
 typedef _Unwind_Action phases_arg_t;
 #endif
 
+#ifdef __SEH__
+static
+#endif
 _Unwind_Reason_Code
 PERSONALITY_FUNCTION (version_arg_t version_arg,
                       phases_arg_t phases_arg,
@@ -1211,6 +1216,16 @@  __gnat_Unwind_ForcedUnwind (_Unwind_Exception *e,
 
 #endif /* __USING_SJLJ_EXCEPTIONS__ */
 
+#ifdef __SEH__
+EXCEPTION_DISPOSITION
+__gnat_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
+			 PCONTEXT ms_orig_context,
+			 PDISPATCHER_CONTEXT ms_disp)
+{
+  return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
+				ms_disp, __gnat_personality_imp);
+}
+#endif /* SEH */
 #else
 /* ! IN_RTS  */
 
diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h
index bb1a420..ed6b459 100644
--- a/gcc/config/i386/cygming.h
+++ b/gcc/config/i386/cygming.h
@@ -33,6 +33,29 @@  along with GCC; see the file COPYING3.  If not see
 #define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
 #endif
 
+#undef TARGET_SEH
+#define TARGET_SEH  TARGET_64BIT_MS_ABI
+
+/* Win64 with SEH cannot represent DRAP stack frames.  Disable its use.
+   Force the use of different mechanisms to allocate aligned local data.  */
+#undef MAX_STACK_ALIGNMENT
+#define MAX_STACK_ALIGNMENT  (TARGET_SEH ? 128 : MAX_OFILE_ALIGNMENT)
+
+/* Support hooks for SEH.  */
+#undef  TARGET_EXCEPT_UNWIND_INFO
+#define TARGET_EXCEPT_UNWIND_INFO  i386_pe_seh_unwind_info
+#undef  TARGET_ASM_UNWIND_EMIT
+#define TARGET_ASM_UNWIND_EMIT  i386_pe_seh_unwind_emit
+#undef  TARGET_ASM_UNWIND_EMIT_BEFORE_INSN
+#define TARGET_ASM_UNWIND_EMIT_BEFORE_INSN  false
+#undef  TARGET_ASM_FUNCTION_END_PROLOGUE
+#define TARGET_ASM_FUNCTION_END_PROLOGUE  i386_pe_seh_end_prologue
+#undef  TARGET_ASM_EMIT_EXCEPT_PERSONALITY
+#define TARGET_ASM_EMIT_EXCEPT_PERSONALITY i386_pe_seh_emit_except_personality
+#undef  TARGET_ASM_INIT_SECTIONS
+#define TARGET_ASM_INIT_SECTIONS  i386_pe_seh_init_sections
+#define SUBTARGET_ASM_UNWIND_INIT  i386_pe_seh_init
+
 #undef DEFAULT_ABI
 #define DEFAULT_ABI (TARGET_64BIT ? MS_ABI : SYSV_ABI)
 
@@ -104,6 +127,8 @@  along with GCC; see the file COPYING3.  If not see
     {									\
 	if (!TARGET_64BIT)						\
 	  builtin_define ("_X86_=1");					\
+	if (TARGET_SEH)							\
+	  builtin_define ("__SEH__");				\
 	builtin_assert ("system=winnt");				\
 	builtin_define ("__stdcall=__attribute__((__stdcall__))");	\
 	builtin_define ("__fastcall=__attribute__((__fastcall__))");	\
@@ -281,15 +306,12 @@  do {						\
    properly.  If we are generating SDB debugging information, this
    will happen automatically, so we only need to handle other cases.  */
 #undef ASM_DECLARE_FUNCTION_NAME
-#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)			\
-  do									\
-    {									\
-      i386_pe_maybe_record_exported_symbol (DECL, NAME, 0);		\
-      if (write_symbols != SDB_DEBUG)					\
-	i386_pe_declare_function_type (FILE, NAME, TREE_PUBLIC (DECL));	\
-      ASM_OUTPUT_FUNCTION_LABEL (FILE, NAME, DECL);			\
-    }									\
-  while (0)
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
+  i386_pe_start_function (FILE, NAME, DECL)
+
+#undef ASM_DECLARE_FUNCTION_SIZE
+#define ASM_DECLARE_FUNCTION_SIZE(FILE,NAME,DECL) \
+  i386_pe_end_function (FILE, NAME, DECL)
 
 /* Add an external function to the list of functions to be declared at
    the end of the file.  */
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 9c10103..b2f4e63 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -225,8 +225,17 @@  extern void i386_pe_asm_output_aligned_decl_common (FILE *, tree,
 						    HOST_WIDE_INT,
 						    HOST_WIDE_INT);
 extern void i386_pe_file_end (void);
+extern void i386_pe_start_function (FILE *, const char *, tree);
+extern void i386_pe_end_function (FILE *, const char *, tree);
 extern tree i386_pe_mangle_decl_assembler_name (tree, tree);
 
+extern void i386_pe_seh_init (FILE *);
+extern void i386_pe_seh_end_prologue (FILE *);
+extern void i386_pe_seh_unwind_emit (FILE *, rtx);
+extern void i386_pe_seh_emit_except_personality (rtx);
+extern void i386_pe_seh_init_sections (void);
+extern enum unwind_info_type i386_pe_seh_unwind_info (void);
+
 /* In winnt-cxx.c and winnt-stubs.c  */
 extern void i386_pe_adjust_class_at_definition (tree);
 extern bool i386_pe_type_dllimport_p (tree);
@@ -263,3 +272,5 @@  extern int asm_preferred_eh_data_format (int, int);
 #ifdef HAVE_ATTR_cpu
 extern enum attr_cpu ix86_schedule;
 #endif
+
+extern const char * ix86_output_call_insn (rtx insn, rtx call_op, int addr_op);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 6668a62..a327b65 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -56,6 +56,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "debug.h"
 #include "dwarf2out.h"
 #include "sched-int.h"
+
 static rtx legitimize_dllimport_symbol (rtx, bool);
 
 #ifndef CHECK_STACK_LIMIT
@@ -1864,6 +1865,7 @@  struct ix86_frame
   HOST_WIDE_INT frame_pointer_offset;
   HOST_WIDE_INT hard_frame_pointer_offset;
   HOST_WIDE_INT stack_pointer_offset;
+  HOST_WIDE_INT hfp_save_offset;
   HOST_WIDE_INT reg_save_offset;
   HOST_WIDE_INT sse_reg_save_offset;
 
@@ -3489,10 +3491,19 @@  ix86_option_override_internal (bool main_args_p)
   ix86_preferred_stack_boundary = PREFERRED_STACK_BOUNDARY_DEFAULT;
   if (ix86_preferred_stack_boundary_string)
     {
+      int min = (TARGET_64BIT ? 4 : 2);
+      int max = (TARGET_SEH ? 4 : 12);
+
       i = atoi (ix86_preferred_stack_boundary_string);
-      if (i < (TARGET_64BIT ? 4 : 2) || i > 12)
-	error ("%spreferred-stack-boundary=%d%s is not between %d and 12",
-	       prefix, i, suffix, TARGET_64BIT ? 4 : 2);
+      if (i < min || i > max)
+	{
+	  if (min == max)
+	    error ("%spreferred-stack-boundary%s is not supported "
+		   "for this target", prefix, suffix);
+	  else
+	    error ("%spreferred-stack-boundary=%d%s is not between %d and %d",
+		   prefix, i, suffix, min, max);
+	}
       else
 	ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT;
     }
@@ -3699,7 +3710,13 @@  ix86_option_override_internal (bool main_args_p)
         sorry ("-mfentry isn't supported for 32-bit in combination with -fpic");
       flag_fentry = 0;
     }
-  if (flag_fentry < 0)
+  else if (TARGET_SEH)
+    {
+      if (flag_fentry == 0)
+	sorry ("-mno-fentry isn't compatible with SEH");
+      flag_fentry = 1;
+    }
+  else if (flag_fentry < 0)
    {
 #if defined(PROFILE_BEFORE_PROLOGUE)
      flag_fentry = 1;
@@ -5188,6 +5205,10 @@  ix86_asm_output_function_label (FILE *asm_out_file, const char *fname,
         fprintf (asm_out_file, ASM_LONG " %#x\n", filler_cc);
     }
 
+#ifdef SUBTARGET_ASM_UNWIND_INIT
+  SUBTARGET_ASM_UNWIND_INIT (asm_out_file);
+#endif
+
   ASM_OUTPUT_LABEL (asm_out_file, fname);
 
   /* Output magic byte marker, if hot-patch attribute is set.  */
@@ -8436,17 +8457,25 @@  ix86_compute_frame_layout (struct ix86_frame *frame)
   gcc_assert (preferred_alignment >= STACK_BOUNDARY / BITS_PER_UNIT);
   gcc_assert (preferred_alignment <= stack_alignment_needed);
 
+  /* For SEH we have to limit the amount of code movement into the prologue.
+     At present we do this via a BLOCKAGE, at which point there's very little
+     scheduling that can be done, which means that there's very little point
+     in doing anything except PUSHs.  */
+  if (TARGET_SEH)
+    cfun->machine->use_fast_prologue_epilogue = false;
+
   /* During reload iteration the amount of registers saved can change.
      Recompute the value as needed.  Do not recompute when amount of registers
      didn't change as reload does multiple calls to the function and does not
      expect the decision to change within single iteration.  */
-  if (!optimize_function_for_size_p (cfun)
-      && cfun->machine->use_fast_prologue_epilogue_nregs != frame->nregs)
+  else if (!optimize_function_for_size_p (cfun)
+           && cfun->machine->use_fast_prologue_epilogue_nregs != frame->nregs)
     {
       int count = frame->nregs;
       struct cgraph_node *node = cgraph_node (current_function_decl);
 
       cfun->machine->use_fast_prologue_epilogue_nregs = count;
+
       /* The fast prologue uses move instead of push to save registers.  This
          is significantly longer, but also executes faster as modern hardware
          can execute the moves in parallel, but can't do that for push/pop.
@@ -8488,7 +8517,9 @@  ix86_compute_frame_layout (struct ix86_frame *frame)
   /* Skip saved base pointer.  */
   if (frame_pointer_needed)
     offset += UNITS_PER_WORD;
+  frame->hfp_save_offset = offset;
 
+  /* The traditional frame pointer location is at the top of the frame.  */
   frame->hard_frame_pointer_offset = offset;
 
   /* Register save area */
@@ -8571,6 +8602,27 @@  ix86_compute_frame_layout (struct ix86_frame *frame)
   else
     frame->red_zone_size = 0;
   frame->stack_pointer_offset -= frame->red_zone_size;
+
+  /* The SEH frame pointer location is near the bottom of the frame.
+     This is enforced by the fact that the difference between the
+     stack pointer and the frame pointer is limited to 240 bytes in
+     the unwind data structure.  */
+  if (TARGET_SEH)
+    {
+      HOST_WIDE_INT diff;
+
+      /* If we can leave the frame pointer where it is, do so.  */
+      diff = frame->stack_pointer_offset - frame->hard_frame_pointer_offset;
+      if (diff > 240 || (diff & 15) != 0)
+	{
+	  /* Ideally we'd determine what portion of the local stack frame
+	     (within the constraint of the lowest 240) is most heavily used.
+	     But without that complication, simply bias the frame pointer
+	     by 128 bytes so as to maximize the amount of the local stack
+	     frame that is addressable with 8-bit offsets.  */
+	  frame->hard_frame_pointer_offset = frame->stack_pointer_offset - 128;
+	}
+    }
 }
 
 /* This is semi-inlined memory_address_length, but simplified
@@ -9503,7 +9555,8 @@  ix86_expand_prologue (void)
       /* Check if profiling is active and we shall use profiling before
          prologue variant. If so sorry.  */
       if (crtl->profile && flag_fentry != 0)
-        sorry ("ms_hook_prologue attribute isn't compatible with -mfentry for 32-bit");
+        sorry ("ms_hook_prologue attribute isn't compatible "
+	       "with -mfentry for 32-bit");
 
       /* In ix86_asm_output_function_label we emitted:
 	 8b ff     movl.s %edi,%edi
@@ -9632,14 +9685,16 @@  ix86_expand_prologue (void)
       insn = emit_insn (gen_push (hard_frame_pointer_rtx));
       RTX_FRAME_RELATED_P (insn) = 1;
 
-      insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
-      RTX_FRAME_RELATED_P (insn) = 1;
+      if (m->fs.sp_offset == frame.hard_frame_pointer_offset)
+	{
+	  insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
+	  RTX_FRAME_RELATED_P (insn) = 1;
 
-      if (m->fs.cfa_reg == stack_pointer_rtx)
-        m->fs.cfa_reg = hard_frame_pointer_rtx;
-      gcc_assert (m->fs.sp_offset == frame.hard_frame_pointer_offset);
-      m->fs.fp_offset = m->fs.sp_offset;
-      m->fs.fp_valid = true;
+	  if (m->fs.cfa_reg == stack_pointer_rtx)
+	    m->fs.cfa_reg = hard_frame_pointer_rtx;
+	  m->fs.fp_offset = m->fs.sp_offset;
+	  m->fs.fp_valid = true;
+	}
     }
 
   int_registers_saved = (frame.nregs == 0);
@@ -9792,12 +9847,15 @@  ix86_expand_prologue (void)
       insn = emit_insn (adjust_stack_insn (stack_pointer_rtx,
 					   stack_pointer_rtx, eax));
 
-      if (m->fs.cfa_reg == stack_pointer_rtx)
+      /* Note that SEH directives need to continue tracking the stack
+	 pointer even after the frame pointer has been set up.  */
+      if (m->fs.cfa_reg == stack_pointer_rtx || TARGET_SEH)
 	{
-	  m->fs.cfa_offset += allocate;
+	  if (m->fs.cfa_reg == stack_pointer_rtx)
+	    m->fs.cfa_offset += allocate;
 
 	  RTX_FRAME_RELATED_P (insn) = 1;
-	  add_reg_note (insn, REG_CFA_ADJUST_CFA,
+	  add_reg_note (insn, REG_FRAME_RELATED_EXPR,
 			gen_rtx_SET (VOIDmode, stack_pointer_rtx,
 				     plus_constant (stack_pointer_rtx,
 						    -allocate)));
@@ -9819,6 +9877,22 @@  ix86_expand_prologue (void)
     }
   gcc_assert (m->fs.sp_offset == frame.stack_pointer_offset);
 
+  /* If we havn't already set up the frame pointer, do so now.  */
+  if (frame_pointer_needed && !m->fs.fp_valid)
+    {
+      insn = ix86_gen_add3 (hard_frame_pointer_rtx, stack_pointer_rtx,
+			    GEN_INT (frame.stack_pointer_offset
+				     - frame.hard_frame_pointer_offset));
+      insn = emit_insn (insn);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      add_reg_note (insn, REG_CFA_ADJUST_CFA, NULL);
+
+      if (m->fs.cfa_reg == stack_pointer_rtx)
+	m->fs.cfa_reg = hard_frame_pointer_rtx;
+      m->fs.fp_offset = frame.hard_frame_pointer_offset;
+      m->fs.fp_valid = true;
+    }
+
   if (!int_registers_saved)
     ix86_emit_save_regs_using_mov (frame.reg_save_offset);
   if (frame.nsseregs)
@@ -9888,6 +9962,11 @@  ix86_expand_prologue (void)
   /* Emit cld instruction if stringops are used in the function.  */
   if (TARGET_CLD && ix86_current_function_needs_cld)
     emit_insn (gen_cld ());
+
+  /* SEH requires that the prologue end within 256 bytes of the start of
+     the function.  Prevent instruction schedules that would extend that.  */
+  if (TARGET_SEH)
+    emit_insn (gen_blockage ());
 }
 
 /* Emit code to restore REG using a POP insn.  */
@@ -10112,13 +10191,16 @@  ix86_expand_epilogue (int style)
   if (crtl->calls_eh_return && style != 2)
     frame.reg_save_offset -= 2 * UNITS_PER_WORD;
 
+  /* EH_RETURN requires the use of moves to function properly.  */
+  if (crtl->calls_eh_return)
+    restore_regs_via_mov = true;
+  /* SEH requires the use of pops to identify the epilogue.  */
+  else if (TARGET_SEH)
+    restore_regs_via_mov = false;
   /* If we're only restoring one register and sp is not valid then
      using a move instruction to restore the register since it's
      less work than reloading sp and popping the register.  */
-  if (!m->fs.sp_valid && frame.nregs <= 1)
-    restore_regs_via_mov = true;
-  /* EH_RETURN requires the use of moves to function properly.  */
-  else if (crtl->calls_eh_return)
+  else if (!m->fs.sp_valid && frame.nregs <= 1)
     restore_regs_via_mov = true;
   else if (TARGET_EPILOGUE_USING_MOVE
 	   && cfun->machine->use_fast_prologue_epilogue
@@ -10230,6 +10312,23 @@  ix86_expand_epilogue (int style)
     }
   else
     {
+      /* SEH requires that the function end with (1) a stack adjustment
+	 if necessary, (2) a sequence of pops, and (3) a return or
+	 jump instruction.  Prevent insns from the function body from
+	 being scheduled into this sequence.  */
+      if (TARGET_SEH)
+	{
+	  /* Prevent a catch region from being adjacent to the standard
+	     epilogue sequence.  Unfortuantely crtl->uses_eh_lsda nor
+	     several other flags that would be interesting to test are
+	     not yet set up.  If we want to elide the nop when it isn't
+	     strictly needed, we'll have to do it in the output template.  */
+	  if (flag_exceptions)
+	    emit_insn (gen_epilogue_nop ());
+	  else
+	    emit_insn (gen_blockage ());
+	}
+
       /* First step is to deallocate the stack frame so that we can
 	 pop the registers.  */
       if (!m->fs.sp_valid)
@@ -10257,7 +10356,7 @@  ix86_expand_epilogue (int style)
     {
       /* If the stack pointer is valid and pointing at the frame
 	 pointer store address, then we only need a pop.  */
-      if (m->fs.sp_valid && m->fs.sp_offset == frame.hard_frame_pointer_offset)
+      if (m->fs.sp_valid && m->fs.sp_offset == frame.hfp_save_offset)
 	ix86_emit_restore_reg_using_pop (hard_frame_pointer_rtx);
       /* Leave results in shorter dependency chains on CPUs that are
 	 able to grok it fast.  */
@@ -14987,6 +15086,13 @@  ix86_expand_binary_operator (enum rtx_code code, enum machine_mode mode,
       gcc_assert (code == PLUS);
       emit_insn (op);
     }
+  else if (reload_completed
+	   && code == PLUS
+	   && !rtx_equal_p (dst, src1))
+    {
+      /* This is going to be an LEA; avoid splitting it later.  */
+      emit_insn (op);
+    }
   else
     {
       clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
@@ -20891,6 +20997,53 @@  ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
   return call;
 }
 
+/* Output the assembly for a call instruction.  */
+
+const char *
+ix86_output_call_insn (rtx insn, rtx call_op, int addr_op)
+{
+  bool direct_p = constant_call_address_operand (call_op, Pmode);
+  bool seh_nop_p = false;
+
+  gcc_assert (addr_op == 0 || addr_op == 1);
+
+  if (SIBLING_CALL_P (insn))
+    {
+      if (direct_p)
+	return addr_op ? "jmp\t%P1" : "jmp\t%P0";
+      /* SEH epilogue detection requires the indirect branch case
+	 to include REX.W.  */
+      else if (TARGET_SEH)
+	return addr_op ? "rex.W jmp %A1" : "rex.W jmp %A0";
+      else
+	return addr_op ? "jmp\t%A1" : "jmp\t%A0";
+    }
+
+  /* SEH unwinding can require an extra nop to be emitted in several
+     circumstances.  Determine if we have one of those.  */
+  if (TARGET_SEH)
+    {
+      if (find_reg_note (insn, REG_NORETURN, NULL_RTX))
+	seh_nop_p = true;
+
+      /* else if epilogue follows */
+    }
+
+  if (direct_p)
+    {
+      if (seh_nop_p)
+	return addr_op ? "call\t%P1\n\tnop" : "call\t%P0\n\tnop";
+      else
+	return addr_op ? "call\t%P1" : "call\t%P0";
+    }
+  else
+    {
+      if (seh_nop_p)
+	return addr_op ? "call\t%A1\n\tnop" : "call\t%A0\n\tnop";
+      else
+	return addr_op ? "call\t%A1" : "call\t%A0";
+    }
+}
 
 /* Clear stack slot assignments remembered from previous functions.
    This is called from INIT_EXPANDERS once before RTL is emitted for each
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 25463a5..30062a7 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -490,6 +490,9 @@  extern tree x86_mfence;
 /* For the Windows 64-bit ABI.  */
 #define TARGET_64BIT_MS_ABI (TARGET_64BIT && ix86_cfun_abi () == MS_ABI)
 
+/* This is re-defined by cygming.h.  */
+#define TARGET_SEH 0
+
 /* Available call abi.  */
 enum calling_abi
 {
@@ -2242,6 +2245,9 @@  struct GTY(()) machine_frame_state
   BOOL_BITFIELD realigned : 1;
 };
 
+/* Private to winnt.c.  */
+struct seh_frame_state;
+
 struct GTY(()) machine_function {
   struct stack_local_entry *stack_locals;
   const char *some_ld_name;
@@ -2292,6 +2298,9 @@  struct GTY(()) machine_function {
   /* During prologue/epilogue generation, the current frame state.
      Otherwise, the frame state at the end of the prologue.  */
   struct machine_frame_state fs;
+
+  /* During SEH output, this is non-null.  */
+  struct seh_frame_state * GTY((skip(""))) seh;
 };
 #endif
 
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index ae52746..9f10ba5 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -245,6 +245,7 @@ 
   UNSPECV_XCHG
   UNSPECV_LOCK
   UNSPECV_PROLOGUE_USE
+  UNSPECV_EPILOGUE_NOP
   UNSPECV_CLD
   UNSPECV_NOPS
   UNSPECV_VZEROALL
@@ -11275,32 +11276,21 @@ 
   [(call (mem:QI (match_operand 0 "constant_call_address_operand" ""))
 	 (match_operand 1 "" ""))]
   ""
-{
-  if (SIBLING_CALL_P (insn))
-    return "jmp\t%P0";
-  else
-    return "call\t%P0";
-}
+  { return ix86_output_call_insn (insn, operands[0], 0); }
   [(set_attr "type" "call")])
 
 (define_insn "*call_1"
   [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lsm"))
 	 (match_operand 1 "" ""))]
   "!TARGET_64BIT && !SIBLING_CALL_P (insn)"
-{
-  if (constant_call_address_operand (operands[0], Pmode))
-    return "call\t%P0";
-  return "call\t%A0";
-}
+  { return ix86_output_call_insn (insn, operands[0], 0); }
   [(set_attr "type" "call")])
 
 (define_insn "*sibcall_1"
   [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "s,U"))
 	 (match_operand 1 "" ""))]
   "!TARGET_64BIT && SIBLING_CALL_P (insn)"
-  "@
-   jmp\t%P0
-   jmp\t%A0"
+  { return ix86_output_call_insn (insn, operands[0], 0); }
   [(set_attr "type" "call")])
 
 (define_insn "*call_1_rex64"
@@ -11308,11 +11298,7 @@ 
 	 (match_operand 1 "" ""))]
   "TARGET_64BIT && !SIBLING_CALL_P (insn)
    && ix86_cmodel != CM_LARGE && ix86_cmodel != CM_LARGE_PIC"
-{
-  if (constant_call_address_operand (operands[0], Pmode))
-    return "call\t%P0";
-  return "call\t%A0";
-}
+  { return ix86_output_call_insn (insn, operands[0], 0); }
   [(set_attr "type" "call")])
 
 (define_insn "*call_1_rex64_ms_sysv"
@@ -11332,27 +11318,21 @@ 
    (clobber (reg:DI SI_REG))
    (clobber (reg:DI DI_REG))]
   "TARGET_64BIT && !SIBLING_CALL_P (insn)"
-{
-  if (constant_call_address_operand (operands[0], Pmode))
-    return "call\t%P0";
-  return "call\t%A0";
-}
+  { return ix86_output_call_insn (insn, operands[0], 0); }
   [(set_attr "type" "call")])
 
 (define_insn "*call_1_rex64_large"
   [(call (mem:QI (match_operand:DI 0 "call_insn_operand" "rm"))
 	 (match_operand 1 "" ""))]
   "TARGET_64BIT && !SIBLING_CALL_P (insn)"
-  "call\t%A0"
+  { return ix86_output_call_insn (insn, operands[0], 0); }
   [(set_attr "type" "call")])
 
 (define_insn "*sibcall_1_rex64"
   [(call (mem:QI (match_operand:DI 0 "sibcall_insn_operand" "s,U"))
 	 (match_operand 1 "" ""))]
   "TARGET_64BIT && SIBLING_CALL_P (insn)"
-  "@
-   jmp\t%P0
-   jmp\t%A0"
+  { return ix86_output_call_insn (insn, operands[0], 0); }
   [(set_attr "type" "call")])
 
 ;; Call subroutine, returning value in operand 0
@@ -11478,6 +11458,19 @@ 
   ""
   [(set_attr "length" "0")])
 
+;; For SEH, if a call to a function that throws immediately preceeds
+;; the epilogue, the system unwinder will assume the caller is *in*
+;; the epilogue and therefore not run the catch handlers.  Therefore
+;; if the current function has catch handlers we may need to force a
+;; nop in between the body of the function and the epilogue.  
+(define_insn "epilogue_nop"
+  [(unspec_volatile [(const_int 0)] UNSPECV_EPILOGUE_NOP)]
+  "TARGET_SEH"
+  ; TODO: actually look back in the insn stream to see if the previous
+  ; real insn is in fact a call.  For now be lazy and waste a byte.
+  "nop"
+  [(set_attr "length" "1")])
+
 ;; Insn emitted into the body of a function to return from a function.
 ;; This is only done if the function's epilogue is known to be simple.
 ;; See comments for ix86_can_use_return_insn_p in i386.c.
@@ -17099,12 +17092,7 @@ 
 	(plus:SI (reg:SI SP_REG)
 		 (match_operand:SI 3 "immediate_operand" "")))]
   "!TARGET_64BIT"
-{
-  if (SIBLING_CALL_P (insn))
-    return "jmp\t%P1";
-  else
-    return "call\t%P1";
-}
+  { return ix86_output_call_insn (insn, operands[1], 1); }
   [(set_attr "type" "callv")])
 
 (define_insn "*call_value_pop_1"
@@ -17115,11 +17103,7 @@ 
 	(plus:SI (reg:SI SP_REG)
 		 (match_operand:SI 3 "immediate_operand" "i")))]
   "!TARGET_64BIT && !SIBLING_CALL_P (insn)"
-{
-  if (constant_call_address_operand (operands[1], Pmode))
-    return "call\t%P1";
-  return "call\t%A1";
-}
+  { return ix86_output_call_insn (insn, operands[1], 1); }
   [(set_attr "type" "callv")])
 
 (define_insn "*sibcall_value_pop_1"
@@ -17130,9 +17114,7 @@ 
 	(plus:SI (reg:SI SP_REG)
 		 (match_operand:SI 3 "immediate_operand" "i,i")))]
   "!TARGET_64BIT && SIBLING_CALL_P (insn)"
-  "@
-   jmp\t%P1
-   jmp\t%A1"
+  { return ix86_output_call_insn (insn, operands[1], 1); }
   [(set_attr "type" "callv")])
 
 (define_insn "*call_value_0"
@@ -17140,12 +17122,7 @@ 
 	(call (mem:QI (match_operand:SI 1 "constant_call_address_operand" ""))
 	      (match_operand:SI 2 "" "")))]
   "!TARGET_64BIT"
-{
-  if (SIBLING_CALL_P (insn))
-    return "jmp\t%P1";
-  else
-    return "call\t%P1";
-}
+  { return ix86_output_call_insn (insn, operands[1], 1); }
   [(set_attr "type" "callv")])
 
 (define_insn "*call_value_0_rex64"
@@ -17153,12 +17130,7 @@ 
 	(call (mem:QI (match_operand:DI 1 "constant_call_address_operand" ""))
 	      (match_operand:DI 2 "const_int_operand" "")))]
   "TARGET_64BIT"
-{
-  if (SIBLING_CALL_P (insn))
-    return "jmp\t%P1";
-  else
-    return "call\t%P1";
-}
+  { return ix86_output_call_insn (insn, operands[1], 1); }
   [(set_attr "type" "callv")])
 
 (define_insn "*call_value_0_rex64_ms_sysv"
@@ -17179,12 +17151,7 @@ 
    (clobber (reg:DI SI_REG))
    (clobber (reg:DI DI_REG))]
   "TARGET_64BIT && !SIBLING_CALL_P (insn)"
-{
-  if (SIBLING_CALL_P (insn))
-    return "jmp\t%P1";
-  else
-    return "call\t%P1";
-}
+  { return ix86_output_call_insn (insn, operands[1], 1); }
   [(set_attr "type" "callv")])
 
 (define_insn "*call_value_1"
@@ -17192,11 +17159,7 @@ 
 	(call (mem:QI (match_operand:SI 1 "call_insn_operand" "lsm"))
 	      (match_operand:SI 2 "" "")))]
   "!TARGET_64BIT && !SIBLING_CALL_P (insn)"
-{
-  if (constant_call_address_operand (operands[1], Pmode))
-    return "call\t%P1";
-  return "call\t%A1";
-}
+  { return ix86_output_call_insn (insn, operands[1], 1); }
   [(set_attr "type" "callv")])
 
 (define_insn "*sibcall_value_1"
@@ -17204,9 +17167,7 @@ 
 	(call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "s,U"))
 	      (match_operand:SI 2 "" "")))]
   "!TARGET_64BIT && SIBLING_CALL_P (insn)"
-  "@
-   jmp\t%P1
-   jmp\t%A1"
+  { return ix86_output_call_insn (insn, operands[1], 1); }
   [(set_attr "type" "callv")])
 
 (define_insn "*call_value_1_rex64"
@@ -17215,11 +17176,7 @@ 
 	      (match_operand:DI 2 "" "")))]
   "TARGET_64BIT && !SIBLING_CALL_P (insn)
    && ix86_cmodel != CM_LARGE && ix86_cmodel != CM_LARGE_PIC"
-{
-  if (constant_call_address_operand (operands[1], Pmode))
-    return "call\t%P1";
-  return "call\t%A1";
-}
+  { return ix86_output_call_insn (insn, operands[1], 1); }
   [(set_attr "type" "callv")])
 
 (define_insn "*call_value_1_rex64_ms_sysv"
@@ -17240,11 +17197,7 @@ 
    (clobber (reg:DI SI_REG))
    (clobber (reg:DI DI_REG))]
   "TARGET_64BIT && !SIBLING_CALL_P (insn)"
-{
-  if (constant_call_address_operand (operands[1], Pmode))
-    return "call\t%P1";
-  return "call\t%A1";
-}
+  { return ix86_output_call_insn (insn, operands[1], 1); }
   [(set_attr "type" "callv")])
 
 (define_insn "*call_value_1_rex64_large"
@@ -17252,7 +17205,7 @@ 
 	(call (mem:QI (match_operand:DI 1 "call_insn_operand" "rm"))
 	      (match_operand:DI 2 "" "")))]
   "TARGET_64BIT && !SIBLING_CALL_P (insn)"
-  "call\t%A1"
+  { return ix86_output_call_insn (insn, operands[1], 1); }
   [(set_attr "type" "callv")])
 
 (define_insn "*sibcall_value_1_rex64"
@@ -17260,9 +17213,7 @@ 
 	(call (mem:QI (match_operand:DI 1 "sibcall_insn_operand" "s,U"))
 	      (match_operand:DI 2 "" "")))]
   "TARGET_64BIT && SIBLING_CALL_P (insn)"
-  "@
-   jmp\t%P1
-   jmp\t%A1"
+  { return ix86_output_call_insn (insn, operands[1], 1); }
   [(set_attr "type" "callv")])
 
 ;; We used to use "int $5", in honor of #BR which maps to interrupt vector 5.
diff --git a/gcc/config/i386/libgcc-cygming.ver b/gcc/config/i386/libgcc-cygming.ver
new file mode 100644
index 0000000..399e52c
--- /dev/null
+++ b/gcc/config/i386/libgcc-cygming.ver
@@ -0,0 +1,28 @@ 
+# Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# In order to work around the very problems that force us to now generally
+# create a libgcc.so, glibc reexported a number of routines from libgcc.a.
+# By now choosing the same version tags for these specific routines, we
+# maintain enough binary compatibility to allow future versions of glibc
+# to defer implementation of these routines to libgcc.so via DT_AUXILIARY.
+
+GCC_4.6 {
+  _GCC_specific_handler
+  __gcc_personality_seh0
+}
diff --git a/gcc/config/i386/t-cygming b/gcc/config/i386/t-cygming
index 183e545..2669935 100644
--- a/gcc/config/i386/t-cygming
+++ b/gcc/config/i386/t-cygming
@@ -100,4 +100,5 @@  SHLIB_MKMAP = $(srcdir)/mkmap-flat.awk
 # We'd like to use SHLIB_SONAME here too, but shlib_base_name
 # does not get substituted before mkmap-flat.awk is run.
 SHLIB_MKMAP_OPTS = -v pe_dll=libgcc_s_$(EH_MODEL)-$(SHLIB_SOVERSION)$(SHLIB_EXT)
-SHLIB_MAPFILES = $(srcdir)/libgcc-std.ver
+SHLIB_MAPFILES = $(srcdir)/libgcc-std.ver \
+		 $(srcdir)/config/i386/libgcc-cygming.ver
diff --git a/gcc/config/i386/t-mingw-w64 b/gcc/config/i386/t-mingw-w64
index d5b2d0e..18357b1 100644
--- a/gcc/config/i386/t-mingw-w64
+++ b/gcc/config/i386/t-mingw-w64
@@ -10,3 +10,8 @@  SHLIB_LC = -lmingw32 -lmingwex -lmoldname -lmsvcrt -ladvapi32 -lshell32 -luser32
 
 LIBGCC = stmp-multilib
 INSTALL_LIBGCC = install-multilib
+
+# Use SEH exception handling.
+LIB2ADDEH = $(srcdir)/unwind-seh.c $(srcdir)/unwind-sjlj.c \
+	$(srcdir)/unwind-c.c $(srcdir)/gthr-gnat.c
+UNWIND_H = $(srcdir)/unwind-seh.h
diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c
index 60a8b79..f117b41 100644
--- a/gcc/config/i386/winnt.c
+++ b/gcc/config/i386/winnt.c
@@ -36,6 +36,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "ggc.h"
 #include "target.h"
+#include "except.h"
 #include "lto-streamer.h"
 
 /* i386/PE specific attribute support.
@@ -730,4 +731,463 @@  i386_pe_file_end (void)
     }
 }
 
+
+/* x64 Structured Exception Handling unwind info.  */
+
+struct seh_frame_state
+{
+  /* SEH records saves relative to the "current" stack pointer, whether
+     or not there's a frame pointer in place.  This tracks the current
+     stack pointer offset from the CFA.  */
+  HOST_WIDE_INT sp_offset;
+
+  /* The CFA is located at CFA_REG + CFA_OFFSET.  */
+  HOST_WIDE_INT cfa_offset;
+  rtx cfa_reg;
+
+  /* True if .seh_setframe has been emitted.  */
+  bool have_setframe;
+};
+
+static void seh_force_setframe (FILE *f, struct seh_frame_state *seh);
+
+/* Set up data structures beginning output for SEH.  */
+
+void
+i386_pe_seh_init (FILE *f)
+{
+  struct seh_frame_state *seh;
+
+  if (!TARGET_SEH)
+    return;
+  if (cfun->is_thunk)
+    return;
+
+  /* We cannot support DRAP with SEH.  We turned off support for it by
+     re-defining MAX_STACK_ALIGNMENT when SEH is enabled.  */
+  gcc_assert (!stack_realign_drap);
+
+  seh = XCNEW (struct seh_frame_state);
+  cfun->machine->seh = seh;
+
+  seh->sp_offset = INCOMING_FRAME_SP_OFFSET;
+  seh->cfa_offset = INCOMING_FRAME_SP_OFFSET;
+  seh->cfa_reg = stack_pointer_rtx;
+  seh->have_setframe = false;
+
+  fputs ("\t.seh_proc\t", f);
+  assemble_name (f, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (cfun->decl)));
+  fputc ('\n', f);
+}
+
+void
+i386_pe_seh_end_prologue (FILE *f)
+{
+  if (!TARGET_SEH)
+    return;
+  if (cfun->is_thunk)
+    return;
+
+  /* If nothing else has forced it, emit setframe last.  */
+  seh_force_setframe (f, cfun->machine->seh);
+
+  XDELETE (cfun->machine->seh);
+  cfun->machine->seh = NULL;
+
+  fputs ("\t.seh_endprologue\n", f);
+}
+
+static void
+i386_pe_seh_fini (FILE *f)
+{
+  if (!TARGET_SEH)
+    return;
+  if (cfun->is_thunk)
+    return;
+  fputs ("\t.seh_endproc\n", f);
+}
+
+/* Emit an assembler directive to save REG via a PUSH.  */
+
+static void
+seh_emit_push (FILE *f, struct seh_frame_state *seh, rtx reg)
+{
+  unsigned int regno = REGNO (reg);
+
+  gcc_checking_assert (GENERAL_REGNO_P (regno));
+
+  seh->sp_offset += UNITS_PER_WORD;
+  if (seh->cfa_reg == stack_pointer_rtx)
+    seh->cfa_offset += UNITS_PER_WORD;
+
+  fputs ("\t.seh_pushreg\t", f);
+  print_reg (reg, 0, f);
+  fputc ('\n', f);
+}
+
+/* Emit an assembler directive to save REG at CFA - CFA_OFFSET.  */
+
+static void
+seh_emit_save (FILE *f, struct seh_frame_state *seh,
+	       rtx reg, HOST_WIDE_INT cfa_offset)
+{
+  unsigned int regno = REGNO (reg);
+  HOST_WIDE_INT offset;
+
+  /* Negative save offsets are of course not supported, since that
+     would be a store below the stack pointer and thus clobberable.  */
+  gcc_assert (seh->sp_offset >= cfa_offset);
+  offset = seh->sp_offset - cfa_offset;
+
+  fputs ((SSE_REGNO_P (regno) ? "\t.seh_savexmm\t"
+	 : GENERAL_REGNO_P (regno) ?  "\t.seh_savereg\t"
+	 : (gcc_unreachable (), "")), f);
+  print_reg (reg, 0, f);
+  fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
+}
+
+/* Emit an assembler directive to set up the frame pointer.  */
+
+static void
+seh_emit_setframe (FILE *f, struct seh_frame_state *seh,
+		   rtx reg, HOST_WIDE_INT offset)
+{
+  gcc_assert ((offset & 15) == 0);
+  gcc_assert (IN_RANGE (offset, 0, 240));
+  gcc_assert (!seh->have_setframe);
+  seh->have_setframe = true;
+
+  fputs ("\t.seh_setframe\t", f);
+  print_reg (reg, 0, f);
+  fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
+}
+
+/* Force a setframe to be done if it needs doing.  */
+
+static void
+seh_force_setframe (FILE *f, struct seh_frame_state *seh)
+{
+  if (!seh->have_setframe && seh->cfa_reg != stack_pointer_rtx)
+    seh_emit_setframe (f, seh, seh->cfa_reg, seh->sp_offset - seh->cfa_offset);
+}
+
+/* Emit an assembler directive to adjust RSP by OFFSET.  */
+
+static void
+seh_emit_stackalloc (FILE *f, struct seh_frame_state *seh,
+		     HOST_WIDE_INT offset)
+{
+  /* We're only concerned with prologue stack allocations, which all
+     are subtractions from the stack pointer.  */
+  gcc_assert (offset < 0);
+  offset = -offset;
+
+  if (seh->cfa_reg == stack_pointer_rtx)
+    seh->cfa_offset += offset;
+  seh->sp_offset += offset;
+
+  fprintf (f, "\t.seh_stackalloc\t" HOST_WIDE_INT_PRINT_DEC "\n", offset);
+}
+
+/* Process REG_CFA_ADJUST_CFA for SEH.  */
+
+static void
+seh_cfa_adjust_cfa (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+  rtx dest, src;
+  HOST_WIDE_INT reg_offset = 0;
+  unsigned int dest_regno;
+
+  dest = SET_DEST (pat);
+  src = SET_SRC (pat);
+
+  if (GET_CODE (src) == PLUS)
+    {
+      reg_offset = INTVAL (XEXP (src, 1));
+      src = XEXP (src, 0);
+    }
+  else if (GET_CODE (src) == MINUS)
+    {
+      reg_offset = -INTVAL (XEXP (src, 1));
+      src = XEXP (src, 0);
+    }
+  gcc_assert (src == stack_pointer_rtx);
+  gcc_assert (seh->cfa_reg == stack_pointer_rtx);
+  dest_regno = REGNO (dest);
+
+  if (dest_regno == STACK_POINTER_REGNUM)
+    seh_emit_stackalloc (f, seh, reg_offset);
+  else if (dest_regno == HARD_FRAME_POINTER_REGNUM)
+    {
+      gcc_assert (!seh->have_setframe);
+      seh->cfa_reg = dest;
+      seh->cfa_offset -= reg_offset;
+    }
+  else
+    gcc_unreachable ();
+}
+
+/* Process REG_CFA_OFFSET for SEH.  */
+
+static void
+seh_cfa_offset (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+  rtx dest, src;
+  HOST_WIDE_INT reg_offset;
+
+  dest = SET_DEST (pat);
+  src = SET_SRC (pat);
+
+  gcc_assert (MEM_P (dest));
+  dest = XEXP (dest, 0);
+  if (REG_P (dest))
+    reg_offset = 0;
+  else
+    {
+      gcc_assert (GET_CODE (dest) == PLUS);
+      reg_offset = INTVAL (XEXP (dest, 1));
+      dest = XEXP (dest, 0);
+    }
+  gcc_assert (dest == seh->cfa_reg);
+
+  seh_emit_save (f, seh, src, seh->cfa_offset - reg_offset);
+}
+
+/* Process a FRAME_RELATED_EXPR for SEH.  */
+
+static void
+seh_frame_related_expr (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+  rtx dest, src;
+  HOST_WIDE_INT addend;
+
+  /* See the full loop in dwarf2out_frame_debug_expr.  */
+  if (GET_CODE (pat) == PARALLEL || GET_CODE (pat) == SEQUENCE)
+    {
+      int i, n = XVECLEN (pat, 0), pass, npass;
+
+      npass = (GET_CODE (pat) == PARALLEL ? 2 : 1);
+      for (pass = 0; pass < npass; ++pass)
+	for (i = 0; i < n; ++i)
+	  {
+	    rtx ele = XVECEXP (pat, 0, i);
+
+	    if (GET_CODE (ele) != SET)
+	      continue;
+	    dest = SET_DEST (ele);
+
+	    /* Process each member of the PARALLEL independently.  The first
+	       member is always processed; others only if they are marked.  */
+	    if (i == 0 || RTX_FRAME_RELATED_P (ele))
+	      {
+		/* Evaluate all register saves in the first pass and all
+		   register updates in the second pass.  */
+		if ((MEM_P (dest) ^ pass) || npass == 1)
+		  seh_frame_related_expr (f, seh, ele);
+	      }
+	  }
+      return;
+    }
+
+  dest = SET_DEST (pat);
+  src = SET_SRC (pat);
+
+  switch (GET_CODE (dest))
+    {
+    case REG:
+      switch (GET_CODE (src))
+	{
+	case REG:
+	  /* REG = REG: This should be establishing a frame pointer.  */
+	  gcc_assert (src == stack_pointer_rtx);
+	  gcc_assert (dest == hard_frame_pointer_rtx);
+	  seh_cfa_adjust_cfa (f, seh, pat);
+	  break;
+
+	case PLUS:
+	  addend = INTVAL (XEXP (src, 1));
+	  src = XEXP (src, 0);
+	  if (dest == hard_frame_pointer_rtx)
+	    seh_cfa_adjust_cfa (f, seh, pat);
+	  else if (dest == stack_pointer_rtx)
+	    {
+	      gcc_assert (src == stack_pointer_rtx);
+	      seh_emit_stackalloc (f, seh, addend);
+	    }
+	  else
+	    gcc_unreachable ();
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+      break;
+
+    case MEM:
+      /* A save of some kind.  */
+      dest = XEXP (dest, 0);
+      if (GET_CODE (dest) == PRE_DEC)
+	{
+	  gcc_checking_assert (GET_MODE (src) == Pmode);
+	  gcc_checking_assert (REG_P (src));
+	  seh_emit_push (f, seh, src);
+	}
+      else
+	seh_cfa_offset (f, seh, pat);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* This function looks at a single insn and emits any SEH directives
+   required for unwind of this insn.  */
+
+void
+i386_pe_seh_unwind_emit (FILE *asm_out_file, rtx insn)
+{
+  rtx note, pat;
+  bool handled_one = false;
+  struct seh_frame_state *seh;
+
+  if (!TARGET_SEH)
+    return;
+
+  /* We free the SEH data once done with the prologue.  Ignore those
+     RTX_FRAME_RELATED_P insns that are associated with the epilogue.  */
+  seh = cfun->machine->seh;
+  if (seh == NULL)
+    return;
+
+  if (NOTE_P (insn) || !RTX_FRAME_RELATED_P (insn))
+    return;
+
+  for (note = REG_NOTES (insn); note ; note = XEXP (note, 1))
+    {
+      pat = XEXP (note, 0);
+      switch (REG_NOTE_KIND (note))
+	{
+	case REG_FRAME_RELATED_EXPR:
+	  goto found;
+
+	case REG_CFA_DEF_CFA:
+	case REG_CFA_EXPRESSION:
+	  /* Only emitted with DRAP, which we disable.  */
+	  gcc_unreachable ();
+	  break;
+
+	case REG_CFA_REGISTER:
+	  /* Only emitted in epilogues, which we skip.  */
+	  gcc_unreachable ();
+
+	case REG_CFA_ADJUST_CFA:
+	  if (pat == NULL)
+	    {
+	      pat = PATTERN (insn);
+	      if (GET_CODE (pat) == PARALLEL)
+		pat = XVECEXP (pat, 0, 0);
+	    }
+	  seh_cfa_adjust_cfa (asm_out_file, seh, pat);
+	  handled_one = true;
+	  break;
+
+	case REG_CFA_OFFSET:
+	  if (pat == NULL)
+	    pat = single_set (insn);
+	  seh_cfa_offset (asm_out_file, seh, pat);
+	  handled_one = true;
+	  break;
+
+	default:
+	  break;
+	}
+    }
+  if (handled_one)
+    return;
+  pat = PATTERN (insn);
+ found:
+  seh_frame_related_expr (asm_out_file, seh, pat);
+}
+
+void
+i386_pe_seh_emit_except_personality (rtx personality)
+{
+  int flags = 0;
+
+  if (!TARGET_SEH)
+    return;
+
+  fputs ("\t.seh_handler\t", asm_out_file);
+  output_addr_const (asm_out_file, personality);
+
+#if 0
+  /* ??? The current implementation of _GCC_specific_handler requires
+     both except and unwind handling, regardless of which sorts the
+     user-level function requires.  */
+  eh_region r;
+  FOR_ALL_EH_REGION(r)
+    {
+      if (r->type == ERT_CLEANUP)
+	flags |= 1;
+      else
+	flags |= 2;
+    }
+#else
+  flags = 3;
+#endif
+
+  if (flags & 1)
+    fputs (", @unwind", asm_out_file);
+  if (flags & 2)
+    fputs (", @except", asm_out_file);
+  fputc ('\n', asm_out_file);
+}
+
+void
+i386_pe_seh_init_sections (void)
+{
+  if (TARGET_SEH)
+    exception_section = get_unnamed_section (0, output_section_asm_op,
+					     "\t.seh_handlerdata");
+}
+
+/* Implement TARGET_EXCEPT_UNWIND_INFO.  */
+
+enum unwind_info_type
+i386_pe_seh_unwind_info (void)
+{
+  /* Honor the --enable-sjlj-exceptions configure switch.  */
+#ifdef CONFIG_UNWIND_EXCEPTIONS
+  if (CONFIG_UNWIND_EXCEPTIONS)
+    return UI_SJLJ;
+#endif
+
+  /* Prefer SEH exceptions over anything else.  */
+  if (TARGET_SEH)
+    return UI_SEH;
+
+  if (DWARF2_UNWIND_INFO)
+    return UI_DWARF2;
+
+  return UI_SJLJ;
+}
+
+void
+i386_pe_start_function (FILE *f, const char *name, tree decl)
+{
+  i386_pe_maybe_record_exported_symbol (decl, name, 0);
+  if (write_symbols != SDB_DEBUG)
+    i386_pe_declare_function_type (f, name, TREE_PUBLIC (decl));
+  ASM_OUTPUT_FUNCTION_LABEL (f, name, decl);
+}
+
+void
+i386_pe_end_function (FILE *f, const char *name ATTRIBUTE_UNUSED,
+		      tree decl ATTRIBUTE_UNUSED)
+{
+  i386_pe_seh_fini (f);
+}
+
+
 #include "gt-winnt.h"
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 3c63684..38f37a2 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -118,7 +118,8 @@  enum unwind_info_type
   UI_NONE,
   UI_SJLJ,
   UI_DWARF2,
-  UI_TARGET
+  UI_TARGET,
+  UI_SEH
 };
 
 struct edge_def;
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index d19a5cd..0821d3c 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2552,7 +2552,9 @@  dwarf2out_frame_debug_expr (rtx expr, const char *label)
 
 	    regno = REGNO (XEXP (XEXP (dest, 0), 0));
 
-	    if (cfa_store.reg == (unsigned) regno)
+	    if (cfa.reg == (unsigned) regno)
+	      offset -= cfa.offset;
+	    else if (cfa_store.reg == (unsigned) regno)
 	      offset -= cfa_store.offset;
 	    else
 	      {
@@ -2568,7 +2570,9 @@  dwarf2out_frame_debug_expr (rtx expr, const char *label)
 	  {
 	    int regno = REGNO (XEXP (dest, 0));
 
-	    if (cfa_store.reg == (unsigned) regno)
+	    if (cfa.reg == (unsigned) regno)
+	      offset = -cfa.offset;
+	    else if (cfa_store.reg == (unsigned) regno)
 	      offset = -cfa_store.offset;
 	    else
 	      {
@@ -3985,7 +3989,7 @@  dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
      call-site information.  We must emit this label if it might be used.  */
   if (!do_frame
       && (!flag_exceptions
-	  || targetm.except_unwind_info () != UI_TARGET))
+	  || targetm.except_unwind_info () == UI_SJLJ))
     return;
 
   fnsec = function_section (current_function_decl);
diff --git a/gcc/expr.c b/gcc/expr.c
index 0050518..6ae55c7 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -10275,6 +10275,9 @@  build_personality_function (const char *lang)
     case UI_TARGET:
       unwind_and_version = "_v0";
       break;
+    case UI_SEH:
+      unwind_and_version = "_seh0";
+      break;
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/opts.c b/gcc/opts.c
index 52f8c6d..3dc0347 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1066,7 +1066,7 @@  finish_options (struct gcc_options *opts, struct gcc_options *opts_set)
 
   if (flag_exceptions
       && flag_reorder_blocks_and_partition
-      && (ui_except == UI_SJLJ || ui_except == UI_TARGET))
+      && (ui_except == UI_SJLJ || ui_except >= UI_TARGET))
     {
       inform (input_location,
 	      "-freorder-blocks-and-partition does not work "
@@ -1081,7 +1081,7 @@  finish_options (struct gcc_options *opts, struct gcc_options *opts_set)
   if (flag_unwind_tables
       && !targetm.unwind_tables_default
       && flag_reorder_blocks_and_partition
-      && (ui_except == UI_SJLJ || ui_except == UI_TARGET))
+      && (ui_except == UI_SJLJ || ui_except >= UI_TARGET))
     {
       inform (input_location,
 	      "-freorder-blocks-and-partition does not support "
@@ -1098,7 +1098,7 @@  finish_options (struct gcc_options *opts, struct gcc_options *opts_set)
       && (!targetm.have_named_sections
 	  || (flag_unwind_tables
 	      && targetm.unwind_tables_default
-	      && (ui_except == UI_SJLJ || ui_except == UI_TARGET))))
+	      && (ui_except == UI_SJLJ || ui_except >= UI_TARGET))))
     {
       inform (input_location,
 	      "-freorder-blocks-and-partition does not work "
diff --git a/gcc/testsuite/g++.dg/torture/stackalign/stackalign.exp b/gcc/testsuite/g++.dg/torture/stackalign/stackalign.exp
index bfa413e..e68337d 100644
--- a/gcc/testsuite/g++.dg/torture/stackalign/stackalign.exp
+++ b/gcc/testsuite/g++.dg/torture/stackalign/stackalign.exp
@@ -18,19 +18,15 @@ 
 # This harness is for tests that should be run at all optimisation levels.
 
 load_lib g++-dg.exp
-
-# Only run on targets which support automatic stack alignment.
-if { ![check_effective_target_automatic_stack_alignment] } then {
-    return
-}
-
+dg-init
 set additional_flags ""
-if { [istarget i?86*-*-*] || [istarget x86_64-*-*] } then {
+
+# If automatic stack alignment is supported, force it on.
+if { [check_effective_target_automatic_stack_alignment] } then {
     lappend additional_flags "-mstackrealign"
     lappend additional_flags "-mpreferred-stack-boundary=5"
 }
 
-dg-init
 gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.C]] $additional_flags
 if { [check_effective_target_fpic] } then {
     lappend additional_flags "-fpic"
diff --git a/gcc/testsuite/gcc.dg/torture/stackalign/stackalign.exp b/gcc/testsuite/gcc.dg/torture/stackalign/stackalign.exp
index ef45dbe..83c6239 100644
--- a/gcc/testsuite/gcc.dg/torture/stackalign/stackalign.exp
+++ b/gcc/testsuite/gcc.dg/torture/stackalign/stackalign.exp
@@ -19,15 +19,12 @@ 
 
 load_lib gcc-dg.exp
 
-# Only run on targets which support automatic stack alignment.
-if { ![check_effective_target_automatic_stack_alignment] } then {
-    return
-}
-
 set additional_flags ""
-if { [istarget i?86*-*-*] || [istarget x86_64-*-*] } then {
+if { [check_effective_target_automatic_stack_alignment] } then {
     lappend additional_flags "-mstackrealign"
     lappend additional_flags "-mpreferred-stack-boundary=5"
+}
+if { [istarget i?86*-*-*] || [istarget x86_64-*-*] } then {
     lappend additional_flags "-mno-mmx"
 }
 
@@ -40,7 +37,7 @@  if { [check_effective_target_fpic] } then {
     gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] $pic_additional_flags
 }
 
-if { [istarget i?86*-*-*] || [istarget x86_64-*-*] } then {
+if { [check_effective_target_automatic_stack_alignment] } then {
     lappend additional_flags "-mforce-drap"
     gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] $additional_flags
     if { [check_effective_target_fpic] } then {
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 0ae003a..87b234d 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -3551,8 +3551,15 @@  proc check_effective_target_4byte_wchar_t { } {
 # Return 1 if the target supports automatic stack alignment.
 
 proc check_effective_target_automatic_stack_alignment  { } {
-    # Not "stack alignment" per se, but proper stack alignment of decls.
-    return 1;
+    # Ordinarily x86 supports automatic stack alignment ...
+    if { [istarget i?86*-*-*] || [istarget x86_64-*-*] } then {
+        if { [istarget *-*-mingw*] || [istarget *-*-cygwin*] } {
+	    # ... except Win64 SEH doesn't.  Succeed for Win32 though.
+	    return [check_effective_target_ilp32];
+	}
+	return 1;
+    }
+    return 0;
 }
 
 # Return 1 if avx instructions can be compiled.
diff --git a/gcc/unwind-c.c b/gcc/unwind-c.c
index 86b9f55..32ff0e6 100644
--- a/gcc/unwind-c.c
+++ b/gcc/unwind-c.c
@@ -93,6 +93,8 @@  parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
 #ifdef __USING_SJLJ_EXCEPTIONS__
 #define PERSONALITY_FUNCTION    __gcc_personality_sj0
 #define __builtin_eh_return_data_regno(x) x
+#elif defined(__SEH__)
+#define PERSONALITY_FUNCTION	__gcc_personality_imp
 #else
 #define PERSONALITY_FUNCTION    __gcc_personality_v0
 #endif
@@ -107,6 +109,9 @@  PERSONALITY_FUNCTION (_Unwind_State state,
 		      struct _Unwind_Exception * ue_header,
 		      struct _Unwind_Context * context)
 #else
+#ifdef __SEH__
+static
+#endif
 _Unwind_Reason_Code
 PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
 		      struct _Unwind_Exception *, struct _Unwind_Context *);
@@ -227,3 +232,13 @@  PERSONALITY_FUNCTION (int version,
   _Unwind_SetIP (context, landing_pad);
   return _URC_INSTALL_CONTEXT;
 }
+
+#ifdef __SEH__
+EXCEPTION_DISPOSITION
+__gcc_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
+			PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
+{
+  return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
+				ms_disp, __gcc_personality_imp);
+}
+#endif /* SEH */
diff --git a/gcc/unwind-seh.c b/gcc/unwind-seh.c
new file mode 100644
index 0000000..67bcd90
--- /dev/null
+++ b/gcc/unwind-seh.c
@@ -0,0 +1,483 @@ 
+/* Structured Exception Handling (SEH) runtime interface routines.
+   Copyright (C) 2010  Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "unwind.h"
+#include "gthr.h"
+
+#ifdef __SEH__
+
+/* At the moment everything is written for x64, but in theory this could
+   also be used for i386, arm, mips and other extant embedded Windows.  */
+#ifndef __x86_64__
+#error "Unsupported architecture."
+#endif
+
+/* Define GCC's exception codes.  See
+     http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx
+   In particular, MS defines bits:
+     [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
+     [29]    = 1 (user-defined)
+     [28]    = 0 (reserved)
+   We define bits:
+     [24:27] = type
+     [0:23]  = magic
+   We set "magic" to "GCC", which is similar to MVC++ which uses "msc"
+   as the low 3 bytes of its user-defined codes for C++ exceptions.
+
+   We define the ExceptionInformation entries as follows:
+     [0] = _Unwind_Exception pointer
+     [1] = target frame
+     [2] = target ip
+     [3] = target rdx
+*/
+
+#define STATUS_USER_DEFINED		(1U << 29)
+
+#define GCC_MAGIC			(('G' << 16) | ('C' << 8) | 'C')
+#define GCC_EXCEPTION(TYPE)		\
+       (STATUS_USER_DEFINED | ((TYPE) << 24) | GCC_MAGIC)
+
+#define STATUS_GCC_THROW		GCC_EXCEPTION (0)
+#define STATUS_GCC_UNWIND		GCC_EXCEPTION (1)
+#define STATUS_GCC_FORCED		GCC_EXCEPTION (2)
+
+
+struct _Unwind_Context
+{
+  _Unwind_Word cfa;
+  _Unwind_Word ra;
+  _Unwind_Word reg[2];
+  PDISPATCHER_CONTEXT disp;
+};
+
+/* Get the value of register INDEX as saved in CONTEXT.  */
+
+_Unwind_Word
+_Unwind_GetGR (struct _Unwind_Context *c, int index)
+{
+  if (index < 0 || index > 2)
+    abort ();
+  return c->reg[index];
+}
+
+/* Overwrite the saved value for register INDEX in CONTEXT with VAL.  */
+
+void
+_Unwind_SetGR (struct _Unwind_Context *c, int index, _Unwind_Word val)
+{
+  if (index < 0 || index > 2)
+    abort ();
+  c->reg[index] = val;
+}
+
+/* Get the value of the CFA as saved in CONTEXT.  */
+
+_Unwind_Word
+_Unwind_GetCFA (struct _Unwind_Context *c)
+{
+  return c->cfa;
+}
+
+/* Retrieve the return address for CONTEXT.  */
+
+_Unwind_Ptr
+_Unwind_GetIP (struct _Unwind_Context *c)
+{
+  return c->ra;
+}
+
+/* Retrieve the return address and flag whether that IP is before
+   or after first not yet fully executed instruction.  */
+
+_Unwind_Ptr
+_Unwind_GetIPInfo (struct _Unwind_Context *c, int *ip_before_insn)
+{
+  /* ??? Is there a concept of a signal context properly?  There's
+     obviously an UNWP_PUSH_MACHFRAME opcode, but the runtime might
+     have arranged for that not to matter, really.  */
+  *ip_before_insn = 0;
+  return c->ra;
+}
+
+/* Overwrite the return address for CONTEXT with VAL.  */
+
+inline void
+_Unwind_SetIP (struct _Unwind_Context *c, _Unwind_Ptr val)
+{
+  c->ra = val;
+}
+
+void *
+_Unwind_GetLanguageSpecificData (struct _Unwind_Context *c)
+{
+  return c->disp->HandlerData;
+}
+
+_Unwind_Ptr
+_Unwind_GetRegionStart (struct _Unwind_Context *c)
+{
+  return c->disp->FunctionEntry->BeginAddress + c->disp->ImageBase;
+}
+
+void *
+_Unwind_FindEnclosingFunction (void *pc)
+{
+  PRUNTIME_FUNCTION entry;
+  ULONG64 ImageBase;
+
+  entry = RtlLookupFunctionEntry ((ULONG64)pc, &ImageBase, NULL);
+
+  return (entry ? (void *)(entry->BeginAddress + ImageBase) : NULL);
+}
+
+_Unwind_Ptr
+_Unwind_GetDataRelBase (struct _Unwind_Context *c ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+_Unwind_Ptr
+_Unwind_GetTextRelBase (struct _Unwind_Context *c)
+{
+  return c->disp->ImageBase;
+}
+
+
+/* The two-phase unwind process that GCC uses is ordered differently
+   from the two-phase unwind process that SEH uses.  The mechansism
+   that GCC uses is to have the filter return _URC_HANDER_FOUND; the
+   mechanism that SEH uses is for the filter function call back into
+   the unwinder.
+
+   An Ideal port to SEH would have GCC emit handler functions that
+   can be called, given a pointer to the "EstablisherFrame" (i.e.
+   the frame pointer base of the user-level function) can manipulate
+   the user-level variables within the user-level function's stack
+   frame.  Once done manipulating the variables, it would return
+   a ExceptionContinueSearch, and the unwind process would continue.
+
+   GCC has always done things a bit differently.  We continue to
+   transfer control back into the user-level function which, once
+   done manipulating the user-level variables, re-throws the exception.  */
+
+/* The "real" language-specific personality handler forwards to here
+   where we handle the MS SEH state and transforms it into the GCC
+   unwind state as per GCC's <unwind.h>, at which point we defer to
+   the regular language-specfic exception handler, which is passed in.  */
+
+EXCEPTION_DISPOSITION
+_GCC_specific_handler (PEXCEPTION_RECORD ms_exc, void *this_frame,
+		       PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp,
+		       _Unwind_Personality_Fn gcc_per)
+{
+  DWORD ms_flags = ms_exc->ExceptionFlags;
+  DWORD ms_code = ms_exc->ExceptionCode;
+  void *ms_data = ms_disp->HandlerData;
+
+  struct _Unwind_Exception *gcc_exc
+    = (struct _Unwind_Exception *) ms_exc->ExceptionInformation[0];
+  struct _Unwind_Context gcc_context;
+  _Unwind_Action gcc_action;
+  _Unwind_Reason_Code gcc_reason;
+
+  if (ms_flags & EXCEPTION_TARGET_UNWIND)
+    {
+      /* This frame is known to be the target frame.  We've already
+         "installed" the target_ip and RAX value via the arguments
+         to RtlUnwindEx.  All that's left is to set the RDX value
+         and "continue" to have the context installed.  */
+      ms_disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3];
+      return ExceptionContinueSearch;
+    }
+
+  if (ms_code == STATUS_GCC_UNWIND)
+    {
+      /* This is a colliding exception that we threw so that we could
+         cancel the already in-flight exception and stop in a frame
+	 that wanted to perform some unwind action.  The only relevant
+	 test is that we're the target frame.  */
+      if (ms_exc->ExceptionInformation[1] == (_Unwind_Ptr) this_frame)
+	{
+	  RtlUnwindEx (this_frame, ms_exc->ExceptionInformation[2],
+		       ms_exc, gcc_exc, ms_orig_context,
+		       ms_disp->HistoryTable);
+	  abort ();
+	}
+      return ExceptionContinueSearch;
+    }
+
+  gcc_context.cfa = ms_disp->ContextRecord->Rsp;
+  gcc_context.ra = ms_disp->ControlPc;
+  gcc_context.reg[0] = 0xdeadbeef;	/* These are write-only.  */
+  gcc_context.reg[1] = 0xdeadbeef;
+  gcc_context.disp = ms_disp;
+
+  if (ms_code == STATUS_GCC_FORCED)
+    {
+       _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) gcc_exc->private_[0];
+       void *stop_argument = (void *) gcc_exc->private_[4];
+ 
+       gcc_action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE;
+ 
+       stop (1, gcc_action, gcc_exc->exception_class, gcc_exc,
+             &gcc_context, stop_argument);
+
+       goto phase2;
+    }
+
+  /* ??? TODO: handling non-gcc user-defined exceptions as foreign.  */
+  if (ms_code != STATUS_GCC_THROW)
+    return ExceptionContinueSearch;
+
+  if (ms_flags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND))
+    {
+      /* This is Phase 2.  */
+      /* We know this isn't the target frame because we've already tested
+	 EXCEPTION_TARGET_UNWIND.  The remaining possibility is that the
+	 gcc personality has unwind code to run.  */
+
+      gcc_action = _UA_CLEANUP_PHASE;
+    phase2:
+      gcc_reason = gcc_per(1, gcc_action, gcc_exc->exception_class,
+			   gcc_exc, &gcc_context);
+
+      if (gcc_reason == _URC_CONTINUE_UNWIND)
+	return ExceptionContinueSearch;
+
+      if (gcc_reason == _URC_INSTALL_CONTEXT)
+	{
+	  /* Scratch space for the bits for the unwind catch.  */
+	  ms_exc->ExceptionInformation[1] = (_Unwind_Ptr) this_frame;
+	  ms_exc->ExceptionInformation[2] = gcc_context.ra;
+	  ms_exc->ExceptionInformation[3] = gcc_context.reg[1];
+
+	  /* Cancel the current exception by raising another.  */
+	  RaiseException (STATUS_GCC_UNWIND, EXCEPTION_NONCONTINUABLE,
+			  4, ms_exc->ExceptionInformation);
+
+	  /* Is RaiseException declared noreturn?  */
+	}
+
+      /* In _Unwind_RaiseException_Phase2 we return _URC_FATAL_PHASE2_ERROR. */
+    }
+  else
+    {
+      /* This is Phase 1.  */
+      gcc_reason = gcc_per(1, _UA_SEARCH_PHASE, gcc_exc->exception_class,
+			   gcc_exc, &gcc_context);
+
+      if (gcc_reason == _URC_CONTINUE_UNWIND)
+	return ExceptionContinueSearch;
+
+      if (gcc_reason == _URC_HANDLER_FOUND)
+	{
+	  /* We really need some of the information that GCC's personality
+	     routines compute during phase 2 right now, like the target IP.
+	     Go ahead and ask for it now, and cache it.  */
+	  gcc_reason = gcc_per(1, _UA_CLEANUP_PHASE | _UA_HANDLER_FRAME,
+			       gcc_exc->exception_class, gcc_exc,
+			       &gcc_context);
+	  if (gcc_reason != _URC_INSTALL_CONTEXT)
+	    abort ();
+
+	  gcc_exc->private_[1] = (_Unwind_Ptr) this_frame;
+	  gcc_exc->private_[2] = gcc_context.ra;
+	  gcc_exc->private_[3] = gcc_context.reg[1];
+
+	  ms_exc->NumberParameters = 4;
+	  ms_exc->ExceptionInformation[1] = (_Unwind_Ptr) this_frame;
+	  ms_exc->ExceptionInformation[2] = gcc_context.ra;
+	  ms_exc->ExceptionInformation[3] = gcc_context.reg[1];
+
+	  /* Begin phase 2.  Perform the unwinding.  */
+	  RtlUnwindEx (this_frame, gcc_context.ra, ms_exc, gcc_exc,
+		       ms_orig_context, ms_disp->HistoryTable);
+	}
+
+      /* In _Unwind_RaiseException we return _URC_FATAL_PHASE1_ERROR.  */
+    }
+  abort ();
+}
+
+/* Raise an exception, passing along the given exception object.  */
+
+_Unwind_Reason_Code
+_Unwind_RaiseException(struct _Unwind_Exception *exc)
+{
+  memset (exc->private_, 0, sizeof (exc->private_));
+
+  RaiseException (STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exc);
+
+  /* The exception handler installed in crt0 will continue any GCC
+     exception that reaches there (and isn't marked non-continuable).
+     Returning allows the C++ runtime to call std::terminate.  */
+  return _URC_END_OF_STACK;
+}
+
+/* Resume propagation of an existing exception.  This is used after
+   e.g. executing cleanup code, and not to implement rethrowing.  */
+
+void
+_Unwind_Resume (struct _Unwind_Exception *gcc_exc)
+{
+  UNWIND_HISTORY_TABLE ms_history;
+  EXCEPTION_RECORD ms_exc;
+  CONTEXT ms_context;
+
+  memset (&ms_exc, 0, sizeof(ms_exc));
+  memset (&ms_history, 0, sizeof(ms_history));
+
+  /* ??? Not 100% perfect, since we aren't passing on the *original*
+     exception context, but should be good enough.  */
+  ms_exc.ExceptionCode = STATUS_GCC_THROW;
+  ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
+  ms_exc.NumberParameters = 4;
+  ms_exc.ExceptionInformation[0] = (ULONG_PTR) gcc_exc;
+  ms_exc.ExceptionInformation[1] = gcc_exc->private_[1];
+  ms_exc.ExceptionInformation[2] = gcc_exc->private_[2];
+  ms_exc.ExceptionInformation[3] = gcc_exc->private_[3];
+
+  ms_context.ContextFlags = CONTEXT_ALL;
+  RtlCaptureContext (&ms_context);
+
+  RtlUnwindEx((void *) gcc_exc->private_[1], gcc_exc->private_[2],
+	      &ms_exc, gcc_exc, &ms_context, &ms_history);
+
+  /* Is RtlUnwindEx declared noreturn?  */
+  abort ();
+}
+
+static _Unwind_Reason_Code
+_Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc)
+{
+  _Unwind_Stop_Fn stop;
+  void * stop_argument;
+
+  RaiseException (STATUS_GCC_FORCED, 0, 1, (ULONG_PTR *)&exc);
+
+  /* If we get here, we got to top-of-stack.  */
+  /* ??? We no longer have a context pointer to pass in.  */
+
+  stop = (_Unwind_Stop_Fn) exc->private_[0];
+  stop_argument = (void *) exc->private_[4];
+  stop (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK,
+	exc->exception_class, exc, NULL, stop_argument);
+
+  return _UA_END_OF_STACK;
+}
+
+_Unwind_Reason_Code
+_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc)
+{
+  if (exc->private_[0] == 0)
+    _Unwind_RaiseException (exc);
+  else
+    _Unwind_ForcedUnwind_Phase2 (exc);
+  abort ();
+}
+
+/* Raise an exception for forced unwinding.  */
+
+_Unwind_Reason_Code
+_Unwind_ForcedUnwind (struct _Unwind_Exception *exc,
+		      _Unwind_Stop_Fn stop, void * stop_argument)
+{
+  /* ??? This is a hack that only works with _GCC_specific_handler.
+     There's no way to invoke STOP within frames that use a different
+     exception handler.  This is essentially just good enough to run
+     the code within the gcc testsuite.  */
+
+  memset (exc->private_, 0, sizeof (exc->private_));
+  exc->private_[0] = (_Unwind_Ptr) stop;
+  exc->private_[4] = (_Unwind_Ptr) stop_argument;
+
+  return _Unwind_ForcedUnwind_Phase2 (exc);
+}
+
+/* A convenience function that calls the exception_cleanup field.  */
+
+void
+_Unwind_DeleteException (struct _Unwind_Exception *exc)
+{
+  if (exc->exception_cleanup)
+    (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
+}
+
+/* Perform stack backtrace through unwind data.  */
+
+_Unwind_Reason_Code
+_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument)
+{
+#if 0
+  UNWIND_HISTORY_TABLE ms_history;
+  CONTEXT ms_context;
+  struct _Unwind_Context gcc_context;
+
+  memset (&ms_history, 0, sizeof(ms_history));
+  memset (&gcc_context, 0, sizeof(gcc_context));
+
+  ms_context.ContextFlags = CONTEXT_ALL;
+  RtlCaptureContext (&ms_context);
+
+  gcc_context.disp.ContextRecord = &ms_context;
+  gcc_context.disp.HistoryTable = &ms_history;
+
+  while (1)
+    {
+      gcc_context.disp.ControlPc = ms_context.Rip;
+      gcc_context.disp.FunctionEntry
+	= RtlLookupFunctionEntry (ms_context.Rip, &gcc_context.disp.ImageBase,
+				  &ms_history);
+
+      if (gcc_context.disp.FunctionEntry)
+	{
+	  gcc_context.disp.LanguageHandler
+	    = RtlVirtualUnwind (0, gcc_context.disp.ImageBase, ms_context.Rip,
+				gcc_context.disp.FunctionEntry, &ms_context,
+				&gcc_context.disp.HandlerData,
+				&gcc_context.disp.EstablisherFrame, NULL);
+	}
+      else
+	{
+	  ms_context.Rip = *(ULONG_PTR *)ms_context.Rsp;
+	  ms_context.Rsp += 8;
+	}
+
+      /* Call trace function.  */
+      if (trace (&gcc_context, trace_argument) != _URC_NO_REASON)
+	return _URC_FATAL_PHASE1_ERROR;
+
+      /* ??? Check for invalid stack pointer.  */
+      if (ms_context.Rip == 0)
+	return _URC_END_OF_STACK;
+    }
+#else
+  return _URC_END_OF_STACK;
+#endif
+}
+#endif /* __SEH__ */
diff --git a/gcc/unwind-seh.h b/gcc/unwind-seh.h
new file mode 100644
index 0000000..4caf785
--- /dev/null
+++ b/gcc/unwind-seh.h
@@ -0,0 +1,258 @@ 
+/* Exception handling and frame unwind runtime interface routines.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This is derived from the C++ ABI for IA-64.  Where we diverge
+   for cross-architecture compatibility are noted with "@@@".  */
+
+#ifndef _UNWIND_H
+#define _UNWIND_H
+
+#ifdef __SEH__
+#include <windows.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Level 1: Base ABI  */
+
+/* @@@ The IA-64 ABI uses uint64 throughout.  Most places this is
+   inefficient for 32-bit and smaller machines.  */
+typedef unsigned _Unwind_Word __attribute__((__mode__(__unwind_word__)));
+typedef signed _Unwind_Sword __attribute__((__mode__(__unwind_word__)));
+typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
+typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__)));
+
+/* @@@ The IA-64 ABI uses a 64-bit word to identify the producer and
+   consumer of an exception.  We'll go along with this for now even on
+   32-bit machines.  We'll need to provide some other option for
+   16-bit machines and for machines with > 8 bits per byte.  */
+typedef unsigned _Unwind_Exception_Class __attribute__((__mode__(__DI__)));
+
+/* The unwind interface uses reason codes in several contexts to
+   identify the reasons for failures or other actions.  */
+typedef enum
+{
+  _URC_NO_REASON = 0,
+  _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+  _URC_FATAL_PHASE2_ERROR = 2,
+  _URC_FATAL_PHASE1_ERROR = 3,
+  _URC_NORMAL_STOP = 4,
+  _URC_END_OF_STACK = 5,
+  _URC_HANDLER_FOUND = 6,
+  _URC_INSTALL_CONTEXT = 7,
+  _URC_CONTINUE_UNWIND = 8
+} _Unwind_Reason_Code;
+
+
+/* The unwind interface uses a pointer to an exception header object
+   as its representation of an exception being thrown. In general, the
+   full representation of an exception object is language- and
+   implementation-specific, but it will be prefixed by a header
+   understood by the unwind interface.  */
+
+struct _Unwind_Exception;
+
+typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code,
+					      struct _Unwind_Exception *);
+
+struct _Unwind_Exception
+{
+  _Unwind_Exception_Class exception_class;
+  _Unwind_Exception_Cleanup_Fn exception_cleanup;
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+  _Unwind_Word private_1;
+  _Unwind_Word private_2;
+#else
+  _Unwind_Word private_[6];
+#endif
+
+  /* @@@ The IA-64 ABI says that this structure must be double-word aligned.
+     Taking that literally does not make much sense generically.  Instead we
+     provide the maximum alignment required by any type for the machine.  */
+} __attribute__((__aligned__));
+
+
+/* The ACTIONS argument to the personality routine is a bitwise OR of one
+   or more of the following constants.  */
+typedef int _Unwind_Action;
+
+#define _UA_SEARCH_PHASE	1
+#define _UA_CLEANUP_PHASE	2
+#define _UA_HANDLER_FRAME	4
+#define _UA_FORCE_UNWIND	8
+#define _UA_END_OF_STACK	16
+
+/* The target can override this macro to define any back-end-specific
+   attributes required for the lowest-level stack frame.  */
+#ifndef LIBGCC2_UNWIND_ATTRIBUTE
+#define LIBGCC2_UNWIND_ATTRIBUTE
+#endif
+
+/* This is an opaque type used to refer to a system-specific data
+   structure used by the system unwinder. This context is created and
+   destroyed by the system, and passed to the personality routine
+   during unwinding.  */
+struct _Unwind_Context;
+
+/* Raise an exception, passing along the given exception object.  */
+extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE
+_Unwind_RaiseException (struct _Unwind_Exception *);
+
+/* Raise an exception for forced unwinding.  */
+
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+     (int, _Unwind_Action, _Unwind_Exception_Class,
+      struct _Unwind_Exception *, struct _Unwind_Context *, void *);
+
+extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE
+_Unwind_ForcedUnwind (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
+
+/* Helper to invoke the exception_cleanup routine.  */
+extern void _Unwind_DeleteException (struct _Unwind_Exception *);
+
+/* Resume propagation of an existing exception.  This is used after
+   e.g. executing cleanup code, and not to implement rethrowing.  */
+extern void LIBGCC2_UNWIND_ATTRIBUTE
+_Unwind_Resume (struct _Unwind_Exception *);
+
+/* @@@ Resume propagation of a FORCE_UNWIND exception, or to rethrow
+   a normal exception that was handled.  */
+extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE
+_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *);
+
+/* @@@ Use unwind data to perform a stack backtrace.  The trace callback
+   is called for every stack frame in the call chain, but no cleanup
+   actions are performed.  */
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)
+     (struct _Unwind_Context *, void *);
+
+extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE
+_Unwind_Backtrace (_Unwind_Trace_Fn, void *);
+
+/* These functions are used for communicating information about the unwind
+   context (i.e. the unwind descriptors and the user register state) between
+   the unwind library and the personality routine and landing pad.  Only
+   selected registers may be manipulated.  */
+
+extern _Unwind_Word _Unwind_GetGR (struct _Unwind_Context *, int);
+extern void _Unwind_SetGR (struct _Unwind_Context *, int, _Unwind_Word);
+
+extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
+extern _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *);
+extern void _Unwind_SetIP (struct _Unwind_Context *, _Unwind_Ptr);
+
+/* @@@ Retrieve the CFA of the given context.  */
+extern _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *);
+
+extern void *_Unwind_GetLanguageSpecificData (struct _Unwind_Context *);
+
+extern _Unwind_Ptr _Unwind_GetRegionStart (struct _Unwind_Context *);
+
+
+/* The personality routine is the function in the C++ (or other language)
+   runtime library which serves as an interface between the system unwind
+   library and language-specific exception handling semantics.  It is
+   specific to the code fragment described by an unwind info block, and
+   it is always referenced via the pointer in the unwind info block, and
+   hence it has no ABI-specified name.
+
+   Note that this implies that two different C++ implementations can
+   use different names, and have different contents in the language
+   specific data area.  Moreover, that the language specific data
+   area contains no version info because name of the function invoked
+   provides more effective versioning by detecting at link time the
+   lack of code to handle the different data format.  */
+
+typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)
+     (int, _Unwind_Action, _Unwind_Exception_Class,
+      struct _Unwind_Exception *, struct _Unwind_Context *);
+
+/* @@@ The following alternate entry points are for setjmp/longjmp
+   based unwinding.  */
+
+struct SjLj_Function_Context;
+extern void _Unwind_SjLj_Register (struct SjLj_Function_Context *);
+extern void _Unwind_SjLj_Unregister (struct SjLj_Function_Context *);
+
+extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE
+_Unwind_SjLj_RaiseException (struct _Unwind_Exception *);
+extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE
+_Unwind_SjLj_ForcedUnwind (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
+extern void LIBGCC2_UNWIND_ATTRIBUTE
+_Unwind_SjLj_Resume (struct _Unwind_Exception *);
+extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE
+_Unwind_SjLj_Resume_or_Rethrow (struct _Unwind_Exception *);
+
+/* @@@ The following provide access to the base addresses for text
+   and data-relative addressing in the LDSA.  In order to stay link
+   compatible with the standard ABI for IA-64, we inline these.  */
+
+extern _Unwind_Ptr _Unwind_GetDataRelBase (struct _Unwind_Context *);
+extern _Unwind_Ptr _Unwind_GetTextRelBase (struct _Unwind_Context *);
+
+/* @@@ Given an address, return the entry point of the function that
+   contains it.  */
+extern void * _Unwind_FindEnclosingFunction (void *pc);
+
+#ifndef __SIZEOF_LONG__
+  #error "__SIZEOF_LONG__ macro not defined"
+#endif
+
+#ifndef __SIZEOF_POINTER__
+  #error "__SIZEOF_POINTER__ macro not defined"
+#endif
+
+/* leb128 type numbers have a potentially unlimited size.
+   The target of the following definitions of _sleb128_t and _uleb128_t
+   is to have efficient data types large enough to hold the leb128 type
+   numbers used in the unwind code.
+   Mostly these types will simply be defined to long and unsigned long
+   except when a unsigned long data type on the target machine is not
+   capable of storing a pointer.  */
+
+#if __SIZEOF_LONG__ >= __SIZEOF_POINTER__
+  typedef long _sleb128_t;
+  typedef unsigned long _uleb128_t;
+#elif __SIZEOF_LONG_LONG__ >= __SIZEOF_POINTER__
+  typedef long long _sleb128_t;
+  typedef unsigned long long _uleb128_t;
+#else
+# error "What type shall we use for _sleb128_t?"
+#endif
+
+#ifdef __SEH__
+/* Handles the mapping from SEH to GCC interfaces.  */
+EXCEPTION_DISPOSITION _GCC_specific_handler (PEXCEPTION_RECORD, void *,
+					     PCONTEXT, PDISPATCHER_CONTEXT,
+					     _Unwind_Personality_Fn);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* unwind.h */
diff --git a/libjava/exception.cc b/libjava/exception.cc
index 76f1451..d356f35 100644
--- a/libjava/exception.cc
+++ b/libjava/exception.cc
@@ -208,6 +208,8 @@  get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
 #ifdef SJLJ_EXCEPTIONS
 #define PERSONALITY_FUNCTION	__gcj_personality_sj0
 #define __builtin_eh_return_data_regno(x) x
+#elif defined (__SEH__)
+#define PERSONALITY_FUNCTION	__gcj_personality_imp
 #else
 #define PERSONALITY_FUNCTION	__gcj_personality_v0
 #endif
@@ -231,7 +233,12 @@  PERSONALITY_FUNCTION (_Unwind_State state,
 
 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
 
-extern "C" _Unwind_Reason_Code
+#ifdef __SEH__
+static
+#else
+extern "C"
+#endif
+_Unwind_Reason_Code
 PERSONALITY_FUNCTION (int version,
 		      _Unwind_Action actions,
 		      _Unwind_Exception_Class exception_class,
@@ -495,3 +502,14 @@  PERSONALITY_FUNCTION (int version,
 #endif
   return _URC_INSTALL_CONTEXT;
 }
+
+#ifdef __SEH__
+extern "C"
+EXCEPTION_DISPOSITION
+__gcj_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
+			PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
+{
+  return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
+				ms_disp, __gcj_personality_imp);
+}
+#endif /* SEH */
diff --git a/libjava/libgcj.ver b/libjava/libgcj.ver
index 4e90d9d..142c6fb 100644
--- a/libjava/libgcj.ver
+++ b/libjava/libgcj.ver
@@ -7,6 +7,7 @@ 
     _Jv_*;
     __gcj_personality_v0;
     __gcj_personality_sj0;
+    __gcj_personality_seh0;
     _Z*;
   local:
     *;
diff --git a/libobjc/exception.c b/libobjc/exception.c
index 4883448..ef80c23 100644
--- a/libobjc/exception.c
+++ b/libobjc/exception.c
@@ -226,6 +226,8 @@  get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i)
 #ifdef SJLJ_EXCEPTIONS
 #define PERSONALITY_FUNCTION	__gnu_objc_personality_sj0
 #define __builtin_eh_return_data_regno(x) x
+#elif defined(__SEH__)
+#define PERSONALITY_FUNCTION	__gnu_objc_personality_imp
 #else
 #define PERSONALITY_FUNCTION	__gnu_objc_personality_v0
 #endif
@@ -249,6 +251,9 @@  PERSONALITY_FUNCTION (_Unwind_State state,
 
 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
 
+#ifdef __SEH__
+static
+#endif
 _Unwind_Reason_Code
 PERSONALITY_FUNCTION (int version,
 		      _Unwind_Action actions,
@@ -549,3 +554,13 @@  objc_exception_throw (id exception)
   abort ();
 }
 
+#ifdef __SEH__
+EXCEPTION_DISPOSITION
+__gnu_objc_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
+			     PCONTEXT ms_orig_context,
+			     PDISPATCHER_CONTEXT ms_disp)
+{
+  return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
+				ms_disp, __gnu_objc_personality_imp);
+}
+#endif /* SEH */
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 4981ca9..f2762b4 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -1225,6 +1225,7 @@  CXXABI_1.3 {
     __cxa_vec_new;
     __gxx_personality_v0;
     __gxx_personality_sj0;
+    __gxx_personality_seh0;
     __dynamic_cast;
 
     # *_type_info classes, ctor and dtor
diff --git a/libstdc++-v3/libsupc++/eh_personality.cc b/libstdc++-v3/libsupc++/eh_personality.cc
index 2b194f2..2cd2152 100644
--- a/libstdc++-v3/libsupc++/eh_personality.cc
+++ b/libstdc++-v3/libsupc++/eh_personality.cc
@@ -342,11 +342,18 @@  namespace __cxxabiv1
 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
 #define PERSONALITY_FUNCTION	__gxx_personality_sj0
 #define __builtin_eh_return_data_regno(x) x
+#elif defined(__SEH__)
+#define PERSONALITY_FUNCTION	__gxx_personality_imp
 #else
 #define PERSONALITY_FUNCTION	__gxx_personality_v0
 #endif
 
-extern "C" _Unwind_Reason_Code
+#ifdef __SEH__
+static
+#else
+extern "C"
+#endif
+_Unwind_Reason_Code
 #ifdef __ARM_EABI_UNWINDER__
 PERSONALITY_FUNCTION (_Unwind_State state,
 		      struct _Unwind_Exception* ue_header,
@@ -785,4 +792,15 @@  __cxa_call_unexpected (void *exc_obj_in)
 }
 #endif
 
+#ifdef __SEH__
+extern "C"
+EXCEPTION_DISPOSITION
+__gxx_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
+			PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
+{
+  return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
+				ms_disp, __gxx_personality_imp);
+}
+#endif /* SEH */
+
 } // namespace __cxxabiv1