Mostly style comments; was also able to build a cross compiler with host and build aarch64-linux-gnu and target aarch64-w64-mingw32 using your bintuils SEH patch [v12,1/1] aarch64: Implement Structured Exception Handling (SEH) on AArch64 - Patchwork <https://patchwork.sourceware.org/project/binutils/patch/[email protected]/>

Would it be possible for you to add a `dg-run` test that could exercise the exception throw and catch facilities?

On 7/8/2026 4:43 PM, Evgeny Karpov wrote:

This patch reuses the existing SEH, stack unwinding and C++ exceptions
from ix86 and implements the required unwinding for AArch64.

Co-authored-by: Zac Walker <[email protected]>
Signed-off-by: Evgeny Karpov <[email protected]>

gcc/ChangeLog:

        * common/config/aarch64/aarch64-common.cc (aarch64_except_unwind_info):
        Add unwinding for AArch64.
        * config/aarch64/aarch64-abi-ms-protos.h (aarch64_pe_seh_unwind_emit):
        Likewise.
        * config/aarch64/aarch64-abi-ms.cc (aarch64_seh_cfa_adjust_cfa):
        Likewise.
        (aarch64_seh_emit_save): Likewise.
        (aarch64_seh_emit_save_pair): Likewise.
        (aarch64_seh_pattern_emit): Likewise.
        (aarch64_pe_seh_unwind_emit): Likewise.
        * config/aarch64/aarch64-abi-ms.h (CALLEE_SAVED_REG_NUMBER):
        Define callee saved registers.
        * config/aarch64/aarch64.cc (TARGET_SEH): Add unwinding for AArch64.
        (aarch64_get_separate_components): Likewise.
        (aarch64_frame_pointer_required): Likewise.
        (aarch64_override_options_internal): Likewise.
        (aarch64_declare_function_name): Likewise.
        * config/aarch64/cygming.h (SYMBOL_REF_STUBVAR_P): Likewise.
        (TARGET_SEH): Likewise.
        (SEH_MAX_FRAME_SIZE): Likewise.
        (TARGET_ASM_UNWIND_EMIT): Likewise.
        (TARGET_ASM_UNWIND_EMIT_BEFORE_INSN): Likewise.
        (TARGET_ASM_FUNCTION_END_PROLOGUE): Likewise.
        (TARGET_ASM_EMIT_EXCEPT_PERSONALITY): Likewise.
        (TARGET_ASM_INIT_SECTIONS): Likewise.
        (TARGET_EXCEPT_UNWIND_INFO): Likewise.
        (SUBTARGET_ASM_UNWIND_INIT): Likewise.
        (ASM_DECLARE_FUNCTION_SIZE): Likewise.
        (ASM_DECLARE_COLD_FUNCTION_SIZE): Likewise.
        (ASM_DECLARE_COLD_FUNCTION_NAME): Likewise.

libgcc/ChangeLog:

        * unwind-seh.c (defined): Update SEH handler for AArch64.
        (_Unwind_Backtrace): Add unwinding for AArch64.

libstdc++-v3/ChangeLog:

        * libsupc++/eh_personality.cc (defined): Add unwinding for AArch64.
---
  gcc/common/config/aarch64/aarch64-common.cc |  23 ++
  gcc/config/aarch64/aarch64-abi-ms-protos.h  |   2 +
  gcc/config/aarch64/aarch64-abi-ms.cc        | 310 ++++++++++++++++++++
  gcc/config/aarch64/aarch64-abi-ms.h         |   4 +
  gcc/config/aarch64/aarch64.cc               |  17 +-
  gcc/config/aarch64/cygming.h                |  40 ++-
  libgcc/unwind-seh.c                         |  41 ++-
  libstdc++-v3/libsupc++/eh_personality.cc    |  16 +
  8 files changed, 439 insertions(+), 14 deletions(-)

diff --git a/gcc/common/config/aarch64/aarch64-common.cc 
b/gcc/common/config/aarch64/aarch64-common.cc
index fc7e84ae966..e11f70ea8f9 100644
--- a/gcc/common/config/aarch64/aarch64-common.cc
+++ b/gcc/common/config/aarch64/aarch64-common.cc
@@ -842,6 +842,29 @@ is_host_cpu_not_armv8_base (int argc, const char **argv)
    return "";
  }
+#if TARGET_AARCH64_MS_ABI
+/* Implement TARGET_EXCEPT_UNWIND_INFO.  */
+
+static enum unwind_info_type
+aarch64_except_unwind_info (struct gcc_options *opts)
+{
+  /* Honor the --enable-sjlj-exceptions configure switch.  */
+#ifdef CONFIG_SJLJ_EXCEPTIONS
+  if (CONFIG_SJLJ_EXCEPTIONS)
+    return UI_SJLJ;
+#endif
+
+  /* Prefer SEH exceptions over anything else.  */
+  if (opts->x_flag_unwind_tables)
+    return UI_SEH;
+
+  if (DWARF2_UNWIND_INFO)
+    return UI_DWARF2;
+
+  return UI_SJLJ;
Nit: Would it be useful to add comments over the if branch of DWARF2_UNWIND_INFO and the default UI_SJLJ like you did for others? That would also help readers understand why is UI_SJLJ default, for example.
+}
+#endif
+
  struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
#undef AARCH64_CPU_NAME_LENGTH
diff --git a/gcc/config/aarch64/aarch64-abi-ms-protos.h 
b/gcc/config/aarch64/aarch64-abi-ms-protos.h
index f08ea29d0c2..29e82ae392e 100644
--- a/gcc/config/aarch64/aarch64-abi-ms-protos.h
+++ b/gcc/config/aarch64/aarch64-abi-ms-protos.h
@@ -28,6 +28,8 @@ extern tree aarch64_ms_variadic_abi_fn_abi_va_list (tree 
fndecl);
extern tree aarch64_ms_variadic_abi_canonical_va_list_type (tree type); +extern void aarch64_pe_seh_unwind_emit (FILE *, rtx_insn *);
+
  extern int aarch64_arg_partial_bytes (cumulative_args_t,
                                      const function_arg_info &);
diff --git a/gcc/config/aarch64/aarch64-abi-ms.cc b/gcc/config/aarch64/aarch64-abi-ms.cc
index 1eaab4246d3..781a50ef6fd 100644
--- a/gcc/config/aarch64/aarch64-abi-ms.cc
+++ b/gcc/config/aarch64/aarch64-abi-ms.cc
@@ -32,6 +32,7 @@
  #include "regs.h"
  #include "function-abi.h"
  #include "builtins.h"
+#include "diagnostic-core.h"
  #include "aarch64-abi-ms-protos.h"
/* Iterate through the target-specific builtin types for va_list.
@@ -104,3 +105,312 @@ aarch64_arg_partial_bytes (cumulative_args_t pcum_v,
return 0;
  }
+
+/* Emit SEH directive to adjust the stack pointer by offset.  */
+
+static void
+aarch64_seh_cfa_adjust_cfa (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+  rtx src = SET_SRC (pat);
+  if (GET_CODE (src) != PLUS)
+    gcc_unreachable ();
+
+  const HOST_WIDE_INT reg_offset = INTVAL (XEXP (src, 1));
+  src = XEXP (src, 0);
+
+  gcc_assert (src == stack_pointer_rtx);
+  gcc_assert (seh->cfa_reg == stack_pointer_rtx);
Should we fold these two asserts into a single assert separated by &&? If you agree to this, might be useful to flip the order of both equality asserts so that stack_pointer_rtx comes first. That would then read "stack_pointer_rtx equals this and stack_pointer_rtx equals that".
+
+  rtx dest = SET_DEST (pat);
+  if (REGNO (dest) != STACK_POINTER_REGNUM)
+    gcc_unreachable ();
+
+  mingw_pe_seh_emit_stackalloc (f, seh, reg_offset);
+}
+
+/* Emit SEH directive to save a REG.  */
+
+static void
+aarch64_seh_emit_save (FILE *f, rtx reg, HOST_WIDE_INT cfa_offset)
+{
+  const unsigned int regno = REGNO (reg);
+  fputs ((FP_REGNUM_P (regno) ? " \t.seh_save_freg\t"
+        : GP_REGNUM_P (regno) ?  " \t.seh_save_reg\t"
+        : (gcc_unreachable (), "")), f);
+  if (REGNO (reg) >= V0_REGNUM)
+    fprintf (f, "d%d", REGNO (reg) - V0_REGNUM);
+  else
+    fprintf (f, "x%d", REGNO (reg));
+  fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC " \n", abs (cfa_offset));
+  return;
+}
+
+/* Emit SEH directive to save REG or REG pair.  */
+
+static void
+aarch64_seh_emit_save_pair (FILE *f, HOST_WIDE_INT regno[2],
+                           HOST_WIDE_INT offset)
+{
+  const char *unwind_code_prefix = ".seh_save_";
+  const char *unwind_code_infix = "";
+  bool negative_offset = offset < 0;
+  const char *unwind_code_suffix = negative_offset ? "_x": "";
+  offset = abs (offset);
+
+  if (regno[0] == FP_REGNUM && regno[1] == LR_REGNUM)
+  {
+    unwind_code_infix = "fplr";
+    fprintf (f, "\t%s%s%s\t%ld\n",
+            unwind_code_prefix,
+            unwind_code_infix,
+            unwind_code_suffix,
+            offset);
+    return;
+  }
+
+  const unsigned save_r19r20_x_max_offset = 248;

Can you add a comment about this max_offset please?

Thanks,

Saurabh

+  if (regno[0] == R19_REGNUM && regno[1] == R20_REGNUM && negative_offset
+      && offset <= save_r19r20_x_max_offset)
+  {
+    unwind_code_infix = "r19r20";
+    fprintf (f, "\t%s%s%s\t%ld\n",
+            unwind_code_prefix,
+            unwind_code_infix,
+            unwind_code_suffix,
+            offset);
+    return;
+  }
+
+  bool callee_save_reg1 = CALLEE_SAVED_REG_NUMBER (regno[0]);
+  bool callee_save_reg2 = CALLEE_SAVED_REG_NUMBER (regno[1]);
+
+  if (!callee_save_reg1 && !callee_save_reg2)
+    return;
+
+  bool emit_single_register = false;
+  unsigned reg_count = 1;
+  if (callee_save_reg1 && callee_save_reg2)
+  {
+    emit_single_register = (regno[1] - regno[0]) != 1;
+    reg_count += emit_single_register ? 1: 0;
+  }
+  else
+  {
+    emit_single_register = true;
+    if (!callee_save_reg1)
+      regno[0] = regno[1];
+  }
+
+  unwind_code_infix = emit_single_register ? "reg": "regp";
+  char reg_prefix = 'x';
+  unsigned regno_offset = 0;
+  HOST_WIDE_INT offset_increment = 8;
+
+  if (FP_REGNUM_P (regno[0]))
+  {
+    unwind_code_prefix = ".seh_save_f";
+    reg_prefix = 'd';
+    regno_offset = V0_REGNUM;
+  }
+
+  for (unsigned i = 0; i < reg_count; ++i)
+    fprintf (f, "\t%s%s%s\t%c%ld, %ld\n",
+            unwind_code_prefix,
+            unwind_code_infix,
+            unwind_code_suffix,
+            reg_prefix,
+            regno[i] - regno_offset,
+            offset + i * offset_increment);
+}
+
+/* Emit SEH directive if the pattern is recognized.  */
+
+static void
+aarch64_seh_pattern_emit (FILE *f, struct seh_frame_state *seh, const rtx pat)
+{
+  rtx dest, src;
+
+  if (GET_CODE (pat) == PARALLEL)
+    {
+      HOST_WIDE_INT regno[2];
+      HOST_WIDE_INT offsets[2];
+      unsigned reg_count = 0;
+
+      for (unsigned i = 0, n = XVECLEN (pat, 0); i < n; ++i)
+       {
+         rtx ele = XVECEXP (pat, 0, i);
+
+         if (GET_CODE (ele) != SET)
+           continue;
+
+         src = SET_SRC (ele);
+         dest = SET_DEST (ele);
+         if (GET_CODE (src) != REG || GET_CODE (dest) != MEM)
+           continue;
+
+         dest = XEXP (dest, 0);
+         if (dest == stack_pointer_rtx)
+           offsets[reg_count] = 0;
+         else if (GET_CODE (dest) == PLUS
+                 && XEXP (dest, 0) == stack_pointer_rtx)
+           {
+             if (GET_CODE (XEXP (dest, 1)) != CONST_INT)
+               {
+                 sorry ("unexpected offset type");
+                 return;
+               }
+             offsets[reg_count] = INTVAL (XEXP (dest, 1));
+           }
+         else
+           continue;
+
+
+         if (reg_count == 2)
+           gcc_unreachable ();
+         regno[reg_count] = REGNO (src);
+
+         if (CALLEE_SAVED_REG_NUMBER (regno[reg_count]))
+           ++reg_count;
+       }
+
+      if (reg_count == 1)
+       gcc_unreachable ();
+
+      if (reg_count == 2)
+       {
+         if (offsets[0] > offsets[1])
+           {
+             std::swap (offsets[0], offsets[1]);
+             std::swap (regno[0], regno[1]);
+           }
+         if (offsets[1]- offsets[0] != UNITS_PER_WORD)
+           gcc_unreachable ();
+
+         aarch64_seh_emit_save_pair (f, regno, offsets[0]);
+       }
+
+      return;
+    }
+
+  if (GET_CODE (pat) != SET)
+    return;
+
+  src = SET_SRC (pat);
+  dest = SET_DEST (pat);
+  switch (GET_CODE (dest))
+    {
+    case REG:
+      switch (GET_CODE (src))
+       {
+       case REG:
+         if (dest == hard_frame_pointer_rtx && src == stack_pointer_rtx)
+           fprintf (f, "\t.seh_set_fp\n");
+         break;
+
+       case PLUS:
+         if (dest == stack_pointer_rtx)
+           {
+             if (GET_CODE (XEXP (src, 1)) != CONST_INT)
+               {
+                 sorry ("unexpected offset type");
+                 return;
+               }
+             const HOST_WIDE_INT offset = abs (INTVAL (XEXP (src, 1)));
+             mingw_pe_seh_emit_stackalloc (f, seh, -offset);
+           }
+         break;
+
+       case MEM:
+         src = XEXP (src, 0);
+         if (GET_CODE (src) == PLUS
+             && XEXP (src, 0) == stack_pointer_rtx
+             && CALLEE_SAVED_REG_NUMBER (REGNO (dest)))
+           {
+             if (GET_CODE (XEXP (src, 1)) != CONST_INT)
+               {
+                 sorry ("unexpected offset type");
+                 return;
+               }
+             aarch64_seh_emit_save (f, dest, INTVAL (XEXP (src, 1)));
+           }
+         break;
+
+       default:
+         break;
+       }
+      break;
+
+    case MEM:
+      dest = XEXP (dest, 0);
+
+      if (GET_CODE (dest) == PLUS && XEXP (dest, 0) == stack_pointer_rtx
+         && GET_CODE (src) == REG && CALLEE_SAVED_REG_NUMBER (REGNO (src)))
+       {
+         if (GET_CODE (XEXP (dest, 1)) != CONST_INT)
+           {
+             sorry ("unexpected offset type");
+             return;
+           }
+
+         aarch64_seh_emit_save (f, src, INTVAL (XEXP (dest, 1)));
+       }
+      else if (GET_CODE (dest) == PLUS
+              && XEXP (dest, 0) == hard_frame_pointer_rtx
+              && GET_CODE (src) == UNSPEC
+              && XINT (src, 1) == UNSPEC_STP)
+       {
+         if (GET_CODE (XEXP (dest, 1)) != CONST_INT)
+           {
+             sorry ("unexpected offset type");
+             return;
+           }
+
+         HOST_WIDE_INT offset = INTVAL (XEXP (dest, 1));
+         rtvec vec = XVEC (src, 0);
+         HOST_WIDE_INT regno[2] = { REGNO (RTVEC_ELT (vec, 0)),
+                                    REGNO (RTVEC_ELT (vec, 1))};
+         aarch64_seh_emit_save_pair (f, regno, offset);
+       }
+      break;
+
+    default:
+      break;
+    }
+}
+
+/* This function looks at a single insn and emits any SEH directives
+   required to unwind of this insn.  */
+
+void
+aarch64_pe_seh_unwind_emit (FILE *out_file, rtx_insn *insn)
+{
+  if (!TARGET_SEH || NOTE_P (insn) || !RTX_FRAME_RELATED_P (insn))
+    return;
+
+  struct seh_frame_state *seh = cfun->machine->seh;
+  if (!seh || seh->after_prologue)
+    return;
+
+  rtx pat = PATTERN (insn);
+  for (rtx note = REG_NOTES (insn); note ; note = XEXP (note, 1))
+    {
+      switch (REG_NOTE_KIND (note))
+       {
+       case REG_FRAME_RELATED_EXPR:
+         pat = XEXP (note, 0);
+         break;
+
+       case REG_CFA_ADJUST_CFA:
+         if (XEXP (note, 0))
+           pat = XEXP (note, 0);
+         if (GET_CODE (pat) == PARALLEL)
+           pat = XVECEXP (pat, 0, 0);
+         aarch64_seh_cfa_adjust_cfa (out_file, seh, pat);
+         return;
+       default:
+         break;
+       }
+    }
+
+  aarch64_seh_pattern_emit (out_file, seh, pat);
+}
diff --git a/gcc/config/aarch64/aarch64-abi-ms.h 
b/gcc/config/aarch64/aarch64-abi-ms.h
index 1e1fb3fa400..f25e476b3a8 100644
--- a/gcc/config/aarch64/aarch64-abi-ms.h
+++ b/gcc/config/aarch64/aarch64-abi-ms.h
@@ -31,6 +31,10 @@ along with GCC; see the file COPYING3.  If not see
  #undef  STATIC_CHAIN_REGNUM
  #define STATIC_CHAIN_REGNUM R17_REGNUM
+#define CALLEE_SAVED_REG_NUMBER(r) \
+  (((r) >= R19_REGNUM && (r) <= R30_REGNUM)      \
+   || ((r) >= V8_REGNUM && (r) <= V15_REGNUM))
+
  #define ASM_COMMENT_START "//"
/* ASM_OUTPUT_TYPE_DIRECTIVE is not yet supported by binutils for the
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 5c018d92986..1687b377e83 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -124,6 +124,11 @@
  #define TARGET_AARCH64_MS_ABI 0
  #endif
+/* Not on SEH unless explicitly set. */
+#ifndef TARGET_SEH
+#define TARGET_SEH 0
+#endif
+
  /* Flags that describe how a function shares certain architectural state
     with its callers.
@@ -9915,6 +9920,9 @@ offset_12bit_unsigned_scaled_p (machine_mode mode, poly_int64 offset)
  static sbitmap
  aarch64_get_separate_components (void)
  {
+  if (TARGET_SEH)
+     return NULL;
+
    aarch64_frame &frame = cfun->machine->frame;
    sbitmap components = sbitmap_alloc (LAST_SAVED_REGNUM + 1);
    bitmap_clear (components);
@@ -14036,7 +14044,7 @@ aarch64_frame_pointer_required ()
  {
    /* If the function needs to record the incoming value of PSTATE.SM,
       make sure that the slot is accessible from the frame pointer.  */
-  return aarch64_need_old_pstate_sm ();
+  return TARGET_SEH || aarch64_need_old_pstate_sm ();
  }
static bool
@@ -20127,6 +20135,10 @@ aarch64_override_options_internal (struct gcc_options 
*opts,
                         aarch64_autovec_preference,
                         opts->x_autovec_preference);
+ /* Enable unwind tables for MS ABI. */
+  if (TARGET_AARCH64_MS_ABI)
+    SET_OPTION_IF_UNSET (opts, &global_options_set, flag_unwind_tables, 1);
+
    aarch64_override_options_after_change_1 (opts);
  }
@@ -26766,6 +26778,9 @@ aarch64_declare_function_name (FILE *stream, const char* name, /* Don't forget the type directive for ELF. */
    ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function");
+#ifdef SUBTARGET_ASM_UNWIND_INIT
+  SUBTARGET_ASM_UNWIND_INIT (stream);
+#endif
    ASM_OUTPUT_FUNCTION_LABEL (stream, name, fndecl);
cfun->machine->label_is_assembled = true;
diff --git a/gcc/config/aarch64/cygming.h b/gcc/config/aarch64/cygming.h
index bb3c750df69..4ade1fd2085 100644
--- a/gcc/config/aarch64/cygming.h
+++ b/gcc/config/aarch64/cygming.h
@@ -45,14 +45,29 @@ along with GCC; see the file COPYING3.  If not see
  #define SYMBOL_REF_STUBVAR_P(X) \
        ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_STUBVAR) != 0)
-/* Disable SEH and declare the required SEH-related macros that are
-still needed for compilation.  */
  #undef TARGET_SEH
-#define TARGET_SEH 0
+#define TARGET_SEH 1
#define SSE_REGNO_P(N) (gcc_unreachable (), 0)
  #define GENERAL_REGNO_P(N) (gcc_unreachable (), 0)
-#define SEH_MAX_FRAME_SIZE (gcc_unreachable (), 0)
+
+/* Support hooks for SEH.  */
+#undef  TARGET_ASM_UNWIND_EMIT
+#define TARGET_ASM_UNWIND_EMIT  aarch64_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  mingw_pe_seh_end_prologue
+#undef  TARGET_ASM_EMIT_EXCEPT_PERSONALITY
+#define TARGET_ASM_EMIT_EXCEPT_PERSONALITY mingw_pe_seh_emit_except_personality
+#undef  TARGET_ASM_INIT_SECTIONS
+#define TARGET_ASM_INIT_SECTIONS  mingw_pe_seh_init_sections
+#undef  TARGET_EXCEPT_UNWIND_INFO
+#define TARGET_EXCEPT_UNWIND_INFO  aarch64_except_unwind_info
+#undef  SUBTARGET_ASM_UNWIND_INIT
+#define SUBTARGET_ASM_UNWIND_INIT  mingw_pe_seh_init
+
+#define SEH_MAX_FRAME_SIZE (1 << 28)
#undef TARGET_PECOFF
  #define TARGET_PECOFF 1
@@ -118,6 +133,7 @@ still needed for compilation.  */
        builtin_define ("__MSVCRT__");                                        \
        builtin_define ("__MINGW32__");                                       \
        builtin_define ("_WIN32");                                    \
+      builtin_define ("__SEH__");                                    \
        builtin_define_std ("WIN32");                                 \
        builtin_define_std ("WINNT");                                 \
        builtin_define_with_int_value ("_INTEGRAL_MAX_BITS",          \
@@ -203,6 +219,14 @@ still needed for compilation.  */
      flag_stack_check = STATIC_BUILTIN_STACK_CHECK;    \
    } while (0)
+#undef ASM_DECLARE_FUNCTION_SIZE
+#define ASM_DECLARE_FUNCTION_SIZE(FILE,NAME,DECL) \
+  mingw_pe_end_function (FILE, NAME, DECL)
+
+#undef ASM_DECLARE_COLD_FUNCTION_SIZE
+#define ASM_DECLARE_COLD_FUNCTION_SIZE(FILE,NAME,DECL) \
+  mingw_pe_end_cold_function (FILE, NAME, DECL)
+
  #define SUBTARGET_ATTRIBUTE_TABLE \
    { "selectany", 0, 0, true, false, false, false, \
      mingw_handle_selectany_attribute, NULL },     \
@@ -231,6 +255,14 @@ still needed for compilation.  */
      aarch64_declare_function_name (STREAM, NAME, DECL);                       
\
    } while (0)
+#define ASM_DECLARE_COLD_FUNCTION_NAME(FILE, NAME, DECL) \
+  do                                                           \
+    {                                                          \
+      mingw_pe_declare_type (FILE, NAME, 0, 1);                \
+      mingw_pe_seh_init (FILE);                        \
+      ASM_OUTPUT_LABEL (FILE, NAME);                           \
+    }                                                          \
+  while (0)
/* Define this to be nonzero if static stack checking is supported. */
  #define STACK_CHECK_STATIC_BUILTIN 1
diff --git a/libgcc/unwind-seh.c b/libgcc/unwind-seh.c
index 3bd0c8a4e03..36da236a9ea 100644
--- a/libgcc/unwind-seh.c
+++ b/libgcc/unwind-seh.c
@@ -30,9 +30,9 @@
#if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__) -/* 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__
+/* At the moment everything is written for x64 and aarch64, but in theory this
+   could also be used for i386, arm, mips and other extant embedded Windows.  
*/
+#if !defined (__x86_64__) && !defined (__aarch64__)
  #error "Unsupported architecture."
  #endif
  
@@ -209,7 +209,12 @@ _GCC_specific_handler (PEXCEPTION_RECORD ms_exc, void 
*this_frame,
           "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.  */
+#ifdef __x86_64__
        ms_disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3];
+#elif defined (__aarch64__)
+      ms_disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3];
+#endif
+
        return ExceptionContinueSearch;
      }
@@ -229,7 +234,11 @@ _GCC_specific_handler (PEXCEPTION_RECORD ms_exc, void *this_frame,
        return ExceptionContinueSearch;
      }
+#ifdef __x86_64__
    gcc_context.cfa = ms_disp->ContextRecord->Rsp;
+#elif defined (__aarch64__)
+  gcc_context.cfa = ms_disp->ContextRecord->Sp;
+#endif
    gcc_context.ra = ms_disp->ControlPc;
    gcc_context.reg[0] = 0xdeadbeef;    /* These are write-only.  */
    gcc_context.reg[1] = 0xdeadbeef;
@@ -438,6 +447,8 @@ _Unwind_Backtrace(_Unwind_Trace_Fn trace,
    CONTEXT ms_context;
    struct _Unwind_Context gcc_context;
    DISPATCHER_CONTEXT disp_context;
+  ULONG64 ip;
+  ULONG64 sp;
memset (&ms_history, 0, sizeof(ms_history));
    memset (&gcc_context, 0, sizeof(gcc_context));
@@ -452,31 +463,43 @@ _Unwind_Backtrace(_Unwind_Trace_Fn trace,
while (1)
      {
-      gcc_context.disp->ControlPc = ms_context.Rip;
+#ifdef __x86_64__
+      ip = ms_context.Rip;
+#elif defined (__aarch64__)
+      ip = ms_context.Pc;
+#endif
+      gcc_context.disp->ControlPc = ip;
        gcc_context.disp->FunctionEntry
-       = RtlLookupFunctionEntry (ms_context.Rip, &gcc_context.disp->ImageBase,
+       = RtlLookupFunctionEntry (ip, &gcc_context.disp->ImageBase,
                                  &ms_history);
if (!gcc_context.disp->FunctionEntry)
        return _URC_END_OF_STACK;
gcc_context.disp->LanguageHandler
-       = RtlVirtualUnwind (0, gcc_context.disp->ImageBase, ms_context.Rip,
+       = RtlVirtualUnwind (0, gcc_context.disp->ImageBase, ip,
                            gcc_context.disp->FunctionEntry, &ms_context,
                            &gcc_context.disp->HandlerData,
                            &gcc_context.disp->EstablisherFrame, NULL);
/* Set values that the callback can inspect via _Unwind_GetIP
         * and _Unwind_GetCFA. */
-      gcc_context.ra = ms_context.Rip;
-      gcc_context.cfa = ms_context.Rsp;
+#ifdef __x86_64__
+      ip = ms_context.Rip;
+      sp = ms_context.Rsp;
+#elif defined (__aarch64__)
+      ip = ms_context.Pc;
+      sp = ms_context.Sp;
+#endif
+      gcc_context.ra = ip;
+      gcc_context.cfa = sp;
/* 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)
+      if (ip == 0)
        return _URC_END_OF_STACK;
      }
  }
diff --git a/libstdc++-v3/libsupc++/eh_personality.cc 
b/libstdc++-v3/libsupc++/eh_personality.cc
index 10458318f88..3eab8ec2f29 100644
--- a/libstdc++-v3/libsupc++/eh_personality.cc
+++ b/libstdc++-v3/libsupc++/eh_personality.cc
@@ -23,6 +23,7 @@
  // <http://www.gnu.org/licenses/>.
#include <bits/c++config.h>
+#include <cstdint>
  #include <cstdlib>
  #include <bits/exception_defines.h>
  #include <cxxabi.h>
@@ -54,6 +55,21 @@ parse_lsda_header (_Unwind_Context *context, const unsigned 
char *p,
info->Start = (context ? _Unwind_GetRegionStart (context) : 0); +#if defined (__SEH__) && defined (__aarch64__)
+  /* On AArch64, a single function may be split into multiple function
+    fragments, each with it's own .pdata and (if required) .xdata records.
+    The language-specific exception handler data in .xdata records used by GCC
+    consists of two values:
+    - The offset of the fragment within the full function;
+    - The RVA of a .seh_handlerdata record, which is shared by all
+      fragments of the function.  */
+  uint32_t fragment_offset = *(uint32_t *) p;
+  p += sizeof (uint32_t);
+  info->Start -= fragment_offset;
+  uint32_t handler_data_rva = *(uint32_t *) p;
+  p = (unsigned char *) _Unwind_GetTextRelBase (context) + handler_data_rva;
+#endif
+
    // Find @LPStart, the base to which landing pad offsets are relative.
    lpstart_encoding = *p++;
    if (lpstart_encoding != DW_EH_PE_omit)

Reply via email to