diff --git a/gas/config/obj-coff-seh-aarch64.c b/gas/config/obj-coff-seh-aarch64.c
new file mode 100644
index 00000000000..6b5354f6544
--- /dev/null
+++ b/gas/config/obj-coff-seh-aarch64.c
@@ -0,0 +1,889 @@
+/* SEH .pdata/.xdata COFF object file format on AArch64
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GAS.
+
+   GAS 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.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#include "obj-coff-seh-aarch64.h"
+
+static struct seh_aarch64_context *seh_ctx_root = NULL;
+static bool in_seh_proc = false;
+
+struct aarch64_unwind_code_pack_info {
+  const char *directive;
+  unsigned offset_bits;
+  unsigned reg_bits;
+  unsigned code_bits;
+  unsigned code;
+  unsigned offset_right_shift;
+  unsigned offset;
+  unsigned reg_right_shift;
+  unsigned reg_offset;
+  unsigned size;
+};
+
+static const struct aarch64_unwind_code_pack_info
+aarch64_unwind_code_pack_data[] = {
+/* Unwind codes packing for AArch64 is described at
+   https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling?view=msvc-170#unwind-codes
+   and calculated in seh_aarch64_add_unwind_element function.  */
+  {
+    .directive = NULL, .offset_bits = 5, .reg_bits = 0,
+    .code_bits = 3, .code = AARCH64_UNOP_ALLOCS, .offset_right_shift = 4,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 0, .size = 1
+  },
+  {
+    .directive = NULL, .offset_bits = 11, .reg_bits = 0,
+    .code_bits = 5, .code = AARCH64_UNOP_ALLOCM, .offset_right_shift = 4,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 0, .size = 2
+  },
+  {
+    .directive = NULL, .offset_bits = 24, .reg_bits = 0,
+    .code_bits = 8, .code = AARCH64_UNOP_ALLOCL, .offset_right_shift = 4,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 0, .size = 4
+  },
+  {
+    .directive = ".seh_save_reg", .offset_bits = 6, .reg_bits = 4,
+    .code_bits = 6, .code = AARCH64_UNOP_SAVEREG, .offset_right_shift = 3,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 19, .size = 2
+  },
+  {
+    .directive = ".seh_save_reg_x", .offset_bits = 5, .reg_bits = 4,
+    .code_bits = 7, .code = AARCH64_UNOP_SAVEREGX, .offset_right_shift = 3,
+    .offset = 1, .reg_right_shift = 0, .reg_offset = 19, .size = 2
+  },
+  {
+    .directive = ".seh_save_regp", .offset_bits = 6, .reg_bits = 4,
+    .code_bits = 6, .code = AARCH64_UNOP_SAVEREGP, .offset_right_shift = 3,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 19, .size = 2
+  },
+  {
+    .directive = ".seh_save_regp_x", .offset_bits = 6, .reg_bits = 4,
+    .code_bits = 6, .code = AARCH64_UNOP_SAVEREGPX, .offset_right_shift = 3,
+    .offset = 1, .reg_right_shift = 0, .reg_offset = 19, .size = 2
+  },
+  {
+    .directive = ".seh_save_fregp", .offset_bits = 6, .reg_bits = 3,
+    .code_bits = 7, .code = AARCH64_UNOP_SAVEFREGP, .offset_right_shift = 3,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 8, .size = 2
+  },
+  {
+    .directive = ".seh_save_fregp_x", .offset_bits = 6, .reg_bits = 3,
+    .code_bits = 7, .code = AARCH64_UNOP_SAVEFREGPX, .offset_right_shift = 3,
+    .offset = 1, .reg_right_shift = 0, .reg_offset = 8, .size = 2
+  },
+  {
+    .directive = ".seh_save_freg", .offset_bits = 6, .reg_bits = 3,
+    .code_bits = 7, .code = AARCH64_UNOP_SAVEFREG, .offset_right_shift = 3,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 8, .size = 2
+  },
+  {
+    .directive = ".seh_save_freg_x", .offset_bits = 5, .reg_bits = 3,
+    .code_bits = 8, .code = AARCH64_UNOP_SAVEFREGX, .offset_right_shift = 3,
+    .offset = 1, .reg_right_shift = 0, .reg_offset = 8, .size = 2
+  },
+  {
+    .directive = ".seh_save_lrpair", .offset_bits = 6, .reg_bits = 3,
+    .code_bits = 7, .code = AARCH64_UNOP_SAVELRPAIR, .offset_right_shift = 3,
+    .offset = 0, .reg_right_shift = 1, .reg_offset = 19, .size = 2
+  },
+  {
+    .directive = ".seh_save_fplr", .offset_bits = 6, .reg_bits = 0,
+    .code_bits = 2, .code = AARCH64_UNOP_SAVEFPLR, .offset_right_shift = 3,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 0, .size = 1
+  },
+  {
+    .directive = ".seh_save_fplr_x", .offset_bits = 6, .reg_bits = 0,
+    .code_bits = 2, .code = AARCH64_UNOP_SAVEFPLRX, .offset_right_shift = 3,
+    .offset = 1, .reg_right_shift = 0, .reg_offset = 0, .size = 1
+  },
+  {
+    .directive = ".seh_save_r19r20_x", .offset_bits = 5, .reg_bits = 0,
+    .code_bits = 3, .code = AARCH64_UNOP_SAVER19R20X, .offset_right_shift = 3,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 0, .size = 1
+  },
+  {
+    .directive = ".seh_add_fp",	.offset_bits = 8, .reg_bits = 0,
+    .code_bits = 8, .code = AARCH64_UNOP_ADDFP,	.offset_right_shift = 0,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 0, .size = 2
+  },
+  {
+    .directive = ".seh_set_fp",	.offset_bits = 0, .reg_bits = 0,
+    .code_bits = 8, .code = AARCH64_UNOP_SETFP,	.offset_right_shift = 0,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 0, .size = 1
+  },
+  {
+    .directive = ".seh_save_next", .offset_bits = 0, .reg_bits = 0,
+    .code_bits = 8, .code = AARCH64_UNOP_SAVENEXT, .offset_right_shift = 0,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 0, .size = 1
+  },
+  {
+    .directive = ".seh_nop", .offset_bits = 0, .reg_bits = 0,
+    .code_bits = 8, .code = AARCH64_UNOP_NOP, .offset_right_shift = 0,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 0, .size = 1
+  },
+  {
+    .directive = ".seh_pac_sign_lr", .offset_bits = 0, .reg_bits = 0,
+    .code_bits = 8, .code = AARCH64_UNOP_PACSIGNLR, .offset_right_shift = 0,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 0, .size = 1
+  },
+  {
+    .directive = NULL, .offset_bits = 0, .reg_bits = 0,
+    .code_bits = 8, .code = AARCH64_UNOP_END, .offset_right_shift = 0,
+    .offset = 0, .reg_right_shift = 0, .reg_offset = 0, .size = 1
+  },
+};
+
+/* Set for current context the default handler.  */
+static void
+obj_coff_seh_handler (const int what ATTRIBUTE_UNUSED)
+{
+  char *symbol_name;
+  char name_end;
+
+  if (!verify_context (".seh_handler"))
+    return;
+
+  if (*input_line_pointer == 0 || *input_line_pointer == '\n')
+    as_bad (_(".seh_handler requires a handler"));
+
+  SKIP_WHITESPACE ();
+
+  if (*input_line_pointer == '@')
+    {
+      name_end = get_symbol_name (&symbol_name);
+
+      seh_ctx_cur->handler.X_op = O_constant;
+      seh_ctx_cur->handler.X_add_number = 0;
+
+      if (strcasecmp (symbol_name, "@0") == 0
+	  || strcasecmp (symbol_name, "@null") == 0)
+	;
+      else if (strcasecmp (symbol_name, "@1") == 0)
+	seh_ctx_cur->handler.X_add_number = 1;
+      else
+	as_bad (_("unknown constant value '%s' for handler"), symbol_name);
+
+      (void) restore_line_pointer (name_end);
+    }
+  else
+    expression (&seh_ctx_cur->handler);
+
+  seh_ctx_cur->handler_data.X_op = O_constant;
+  seh_ctx_cur->handler_data.X_add_number = 0;
+  seh_ctx_cur->xdata_header.x = 1;
+
+  while (skip_whitespace_and_comma (0))
+    {
+      name_end = get_symbol_name (&symbol_name);
+      (void) restore_line_pointer (name_end);
+    }
+}
+
+/* Switch to subsection for handler data for exception region.  */
+static void
+obj_coff_seh_handlerdata (const int what ATTRIBUTE_UNUSED)
+{
+  demand_empty_rest_of_line ();
+
+  switch_xdata (seh_ctx_cur->subsection + 1, seh_ctx_cur->code_seg);
+}
+
+/* Obtain available unwind element.  */
+static void
+seh_aarch64_add_unwind_element (const seh_aarch64_unwind_types unwind_type,
+				unsigned offset, unsigned reg)
+{
+  gas_assert (in_seh_proc);
+
+  const struct aarch64_unwind_code_pack_info *unwind_code_pack_info
+    = aarch64_unwind_code_pack_data + unwind_type;
+  unsigned value_offset_bits = 0;
+
+  if ((seh_ctx_cur->unwind_codes_byte_count
+      + unwind_code_pack_info->size) > AARCH64_MAX_UNWIND_CODES_SIZE)
+    as_bad (_("no unwind element available."));
+
+  seh_aarch64_unwind_code *aarch64_element;
+  aarch64_element = seh_ctx_cur->unwind_codes
+		    + seh_ctx_cur->unwind_codes_count++;
+  aarch64_element->value = 0;
+
+  if (unwind_code_pack_info->offset_bits)
+    {
+      offset = (offset >> unwind_code_pack_info->offset_right_shift)
+	       - unwind_code_pack_info->offset;
+      offset &= (1 << unwind_code_pack_info->offset_bits) - 1;
+      aarch64_element->value |= offset << value_offset_bits;
+      value_offset_bits += unwind_code_pack_info->offset_bits;
+    }
+
+  if (unwind_code_pack_info->reg_bits)
+    {
+      reg = (reg >> unwind_code_pack_info->reg_right_shift)
+	    - unwind_code_pack_info->reg_offset;
+      reg &= (1 << unwind_code_pack_info->reg_bits) - 1;
+      aarch64_element->value |= reg << value_offset_bits;
+      value_offset_bits += unwind_code_pack_info->reg_bits;
+    }
+
+  if (unwind_code_pack_info->code_bits)
+    {
+      unsigned code = unwind_code_pack_info->code;
+      code &= (1 << unwind_code_pack_info->code_bits) - 1;
+      aarch64_element->value |= code << value_offset_bits;
+    }
+
+  aarch64_element->type = unwind_type;
+  seh_ctx_cur->unwind_codes_byte_count += unwind_code_pack_info->size;
+}
+
+/* Mark begin of new context.  */
+static void
+obj_coff_seh_proc (const int what ATTRIBUTE_UNUSED)
+{
+  char *symbol_name;
+  char name_end;
+
+  if (in_seh_proc)
+    as_bad (_("previous SEH entry not closed (missing .seh_endproc)"));
+
+  if (*input_line_pointer == 0 || *input_line_pointer == '\n')
+    as_bad (_(".seh_proc requires function label name"));
+
+
+  if (!seh_ctx_root)
+  {
+    seh_ctx_root = XCNEW (seh_context);
+    seh_ctx_cur = seh_ctx_root;
+  }
+  else
+  {
+    seh_ctx_cur->next = XCNEW (seh_context);
+    seh_ctx_cur = seh_ctx_cur->next;
+  }
+
+  seh_ctx_cur->next = NULL;
+  seh_ctx_cur->code_seg = now_seg;
+
+  /* The current implementation always use a pair of .pdata and .xdata
+     records.  */
+  const bool use_xdata = true;
+
+  if (use_xdata)
+    {
+      x_segcur = seh_hash_find_or_make (seh_ctx_cur->code_seg, ".xdata");
+      seh_ctx_cur->subsection = x_segcur->subseg;
+      x_segcur->subseg += 2;
+
+      /* Initialize an empty .xdata record.  */
+      seh_ctx_cur->unwind_codes_count = 0;
+      seh_ctx_cur->unwind_codes_byte_count = 0;
+      seh_ctx_cur->epilogue_scopes_count = 0;
+      seh_ctx_cur->epilogue_scopes_capacity = 0;
+      seh_ctx_cur->epilogue_scopes = NULL;
+      seh_ctx_cur->xdata_header.x = 0;
+    }
+
+  SKIP_WHITESPACE ();
+
+  name_end = get_symbol_name (&symbol_name);
+  seh_ctx_cur->func_name = xstrdup (symbol_name);
+  (void) restore_line_pointer (name_end);
+
+  demand_empty_rest_of_line ();
+
+  seh_ctx_cur->start_addr = symbol_temp_new_now ();
+  in_seh_proc = true;
+}
+
+/* Mark end of prologue for current context.  */
+static void
+obj_coff_seh_endprologue (const int what ATTRIBUTE_UNUSED)
+{
+  if (!verify_context (".seh_endprologue")
+      || !seh_validate_seg (".seh_endprologue"))
+    return;
+  demand_empty_rest_of_line ();
+
+  if (seh_ctx_cur->endprologue_addr != NULL)
+    as_warn (_("duplicate .seh_endprologue in .seh_proc block"));
+  else
+    seh_ctx_cur->endprologue_addr = symbol_temp_new_now ();
+
+  /* Unwind codes need to be reversed.  */
+  for (unsigned i = 0, n = seh_ctx_cur->unwind_codes_count; i < n / 2; ++i)
+    {
+      seh_aarch64_unwind_code *unwind_codes = seh_ctx_cur->unwind_codes;
+      const seh_aarch64_unwind_code temp = unwind_codes[i];
+      unwind_codes[i] = unwind_codes[n-i-1];
+      unwind_codes[n-i-1] = temp;
+    }
+
+   seh_aarch64_add_unwind_element (unwind_end, 0, 0);
+}
+
+/* Mark end of current context.  */
+static void
+obj_coff_seh_endproc (const int what ATTRIBUTE_UNUSED)
+{
+  demand_empty_rest_of_line ();
+  if (!in_seh_proc)
+    as_bad (_(".seh_endproc used without .seh_proc"));
+
+  seh_validate_seg (".seh_endproc");
+
+  seh_ctx_cur->end_addr = symbol_temp_new_now ();
+  in_seh_proc = false;
+}
+
+static void
+obj_coff_seh_startepilogue (const int what ATTRIBUTE_UNUSED)
+{
+  if (!verify_context (".seh_startepilogue")
+      || !seh_validate_seg (".seh_startepilogue"))
+    return;
+  demand_empty_rest_of_line ();
+
+  const unsigned max_epilogue_scopes = AARCH64_MAX_EPILOGUE_SCOPES;
+  if (seh_ctx_cur->epilogue_scopes_count >= max_epilogue_scopes)
+    as_bad (_("no epilogue scopes available."));
+
+  symbolS *epilogue_start_addr = symbol_temp_new_now ();
+  expressionS exp;
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = epilogue_start_addr;
+  exp.X_op_symbol = seh_ctx_cur->start_addr;
+  exp.X_add_number = 0;
+
+  if (!resolve_expression (&exp) || exp.X_op != O_constant
+      || exp.X_add_number < 0)
+    as_bad (_(".seh_startepilog offset expression for %s "
+	    "does not evaluate to a non-negative constant"),
+	    S_GET_NAME (epilogue_start_addr));
+
+  if (seh_ctx_cur->epilogue_scopes_count
+      >= seh_ctx_cur->epilogue_scopes_capacity)
+    {
+      const unsigned initial_capacity = 32;
+      if (seh_ctx_cur->epilogue_scopes_capacity)
+	seh_ctx_cur->epilogue_scopes_capacity *= 2;
+      else
+	seh_ctx_cur->epilogue_scopes_capacity = initial_capacity;
+
+      seh_ctx_cur->epilogue_scopes
+	= XRESIZEVEC (seh_aarch64_epilogue_scope, seh_ctx_cur->epilogue_scopes,
+		     seh_ctx_cur->epilogue_scopes_capacity);
+    }
+
+  seh_aarch64_epilogue_scope *epilogue_scope = seh_ctx_cur->epilogue_scopes
+    + seh_ctx_cur->epilogue_scopes_count;
+  epilogue_scope->epilogue_start_offset = exp.X_add_number / 4;
+  epilogue_scope->reserved = 0;
+  epilogue_scope->epilogue_start_index = seh_ctx_cur->unwind_codes_byte_count;
+  seh_ctx_cur->epilogue_scopes_count++;
+}
+
+static void
+obj_coff_seh_endepilogue (const int what ATTRIBUTE_UNUSED)
+{
+  if (!verify_context (".seh_endepilogue")
+      || !seh_validate_seg (".seh_endepilogue"))
+    return;
+
+  demand_empty_rest_of_line ();
+
+  expressionS exp;
+  symbolS *epilogue_end_addr = symbol_temp_new_now ();
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = epilogue_end_addr;
+  exp.X_op_symbol = seh_ctx_cur->start_addr;
+  exp.X_add_number = 0;
+
+  if (!resolve_expression (&exp) || exp.X_op != O_constant
+      || exp.X_add_number < 0)
+    as_bad (_(".seh_endepilogue offset expression for %s "
+	    "does not evaluate to a non-negative constant"),
+	    S_GET_NAME (epilogue_end_addr));
+
+   seh_aarch64_epilogue_scope *epilogue_scope = seh_ctx_cur->epilogue_scopes
+     + seh_ctx_cur->epilogue_scopes_count - 1;
+
+   epilogue_scope->epilogue_end_offset = exp.X_add_number;
+
+  /* End code.  */
+  seh_aarch64_add_unwind_element (unwind_end, 0, 0);
+}
+
+/* End-of-file hook.  */
+static void
+free_seh_ctx (struct seh_aarch64_context *seh_ctx)
+{
+  free (seh_ctx->func_name);
+  const seh_aarch64_func_fragment *fragment = seh_ctx->func_fragment.next;
+  while (fragment)
+    {
+      const seh_aarch64_func_fragment *next = fragment->next;
+      XDELETE (fragment);
+      fragment = next;
+    }
+  XDELETEVEC (seh_ctx->epilogue_scopes);
+  free (seh_ctx);
+}
+
+static void
+obj_coff_seh_save_reg (const int type)
+{
+  gas_assert (type >= 0 && type <= unwind_last_type);
+
+  const struct aarch64_unwind_code_pack_info *unwind_code_pack_info
+    = aarch64_unwind_code_pack_data + type;
+
+  if (!unwind_code_pack_info->directive
+      || !seh_validate_seg (unwind_code_pack_info->directive))
+    return;
+
+  SKIP_WHITESPACE ();
+
+  char *symbol_name = NULL;
+  unsigned reg = -1;
+
+  if (unwind_code_pack_info->reg_bits)
+    {
+      char name_end = get_symbol_name (&symbol_name);
+      reg = atoi (symbol_name + 1);
+      (void) restore_line_pointer (name_end);
+
+      if (!skip_whitespace_and_comma (1))
+	return;
+
+      if (reg > 30)
+	as_bad (_("register number is out of range"));
+    }
+
+  offsetT off = -1;
+  if (unwind_code_pack_info->offset_bits)
+    {
+      off = get_absolute_expression ();
+
+      if (off < 0)
+	as_bad (_("offset is negative"));
+    }
+
+  demand_empty_rest_of_line ();
+
+  seh_aarch64_add_unwind_element (type, off, reg);
+}
+
+/* Add a stack-allocation token to current context.  */
+static void
+obj_coff_seh_stackalloc (const int what ATTRIBUTE_UNUSED)
+{
+  const offsetT off = get_absolute_expression ();
+  demand_empty_rest_of_line ();
+
+  /* aarch64 offset should be encoded in multiples of sixteen.  */
+  if ((off & 0xf) != 0)
+    as_bad (_(".seh_stackalloc offset < 16-byte stack alignment"));
+
+  if (off < 0x200)
+    seh_aarch64_add_unwind_element (unwind_alloc_s, off, 0);
+  else if (off < 0x8000)
+    seh_aarch64_add_unwind_element (unwind_alloc_m, off, 0);
+  else if (off < 0x10000000)
+    seh_aarch64_add_unwind_element (unwind_alloc_l, off, 0);
+  else
+    as_bad (_(".seh_stackalloc offset out of range"));
+}
+
+/* Data writing routines.  */
+static void
+seh_aarch64_emit_epilog_scopes (const seh_context *seh_ctx,
+				const uint64_t fragment_offset,
+				const unsigned prolog_size,
+				const unsigned first_fragment_scope,
+				const unsigned last_fragment_scope,
+				const bool has_phantom_prolog)
+{
+  unsigned start_index_offset = 0;
+  const seh_aarch64_epilogue_scope *scopes = seh_ctx->epilogue_scopes;
+  if (first_fragment_scope < seh_ctx->epilogue_scopes_count)
+    start_index_offset = scopes[first_fragment_scope].epilogue_start_index
+			 - prolog_size;
+  if (has_phantom_prolog)
+    {
+      if (start_index_offset == 0)
+	as_bad (_("start index offset for the epilogue cannot be 0 when "
+		"phantom prolog is used"));
+      --start_index_offset;
+    }
+
+  for (unsigned i = first_fragment_scope; i < last_fragment_scope; ++i)
+    {
+      seh_aarch64_epilogue_scope scope = seh_ctx->epilogue_scopes[i];
+      scope.epilogue_start_offset_reduced = (scope.epilogue_start_offset
+					    - fragment_offset) >> 2;
+      scope.epilogue_start_index -= start_index_offset;
+      uint32_t scope_code;
+      memcpy (&scope_code, &scope, sizeof (scope_code));
+      md_number_to_chars (frag_more (4), scope_code, 4);
+    }
+}
+
+static void
+seh_aarch64_emit_unwind_codes (const seh_context *seh_ctx,
+			       const unsigned prolog_size,
+			       const unsigned first_epilog_index,
+			       const unsigned last_epilog_index,
+			       const bool has_phantom_prolog)
+{
+  unsigned total_byte_count = 0;
+
+  if (has_phantom_prolog)
+    {
+      ++total_byte_count;
+      md_number_to_chars (frag_more (1), AARCH64_UNOP_ENDC, 1);
+    }
+
+  unsigned unwind_bytes_offset = 0;
+  for (unsigned i = 0; i < seh_ctx->unwind_codes_count; ++i)
+    {
+      const seh_aarch64_unwind_code *code = seh_ctx->unwind_codes
+					    + i;
+      const unsigned byte_count
+	= aarch64_unwind_code_pack_data[code->type].size;
+      unwind_bytes_offset += byte_count;
+
+      if (unwind_bytes_offset > last_epilog_index)
+	break;
+
+      if (unwind_bytes_offset > prolog_size
+	  && unwind_bytes_offset <= first_epilog_index)
+	continue;
+
+      /*  emit unwind code bytes in big endian.  */
+      number_to_chars_bigendian (frag_more (byte_count), code->value,
+				 byte_count);
+      total_byte_count += byte_count;
+    }
+
+    /* handle word alignment.  */
+    unsigned required_padding = (4 - total_byte_count % 4) % 4;
+    if (required_padding)
+      {
+	/* Use AARCH64_UNOP_NOP for alignment.  */
+	const uint32_t nop_chain = (AARCH64_UNOP_NOP << 24)
+				   | (AARCH64_UNOP_NOP << 16)
+				   | (AARCH64_UNOP_NOP << 8)
+				   | AARCH64_UNOP_NOP;
+
+	md_number_to_chars (frag_more (required_padding), nop_chain,
+			    required_padding);
+      }
+}
+
+static bool
+seh_function_size (const struct seh_aarch64_context *seh_ctx,
+		  uintptr_t *size)
+{
+  fragS *start_frag, *end_frag;
+  addressT start_offset, end_offset;
+  start_frag = symbol_get_frag_and_value (seh_ctx->start_addr, &start_offset);
+  end_frag = symbol_get_frag_and_value (seh_ctx->end_addr, &end_offset);
+
+  intptr_t func_size = end_frag->fr_address + end_offset
+		       - start_frag->fr_address - start_offset;
+  if (func_size < 0)
+    return false;
+
+  *size = func_size;
+  return true;
+}
+
+/* Write out the xdata information for one function.  */
+static void
+seh_aarch64_write_function_xdata (struct seh_aarch64_context *seh_ctx)
+{
+  if (!seh_ctx->unwind_codes_byte_count)
+    return;
+
+  const segT save_seg = now_seg;
+  const subsegT save_subseg = now_subseg;
+
+  switch_xdata (seh_ctx->subsection, seh_ctx->code_seg);
+
+  /* Set 4-byte alignment.  */
+  frag_align (2, 0, 0);
+
+  uintptr_t func_size = 0;
+  if (!seh_function_size (seh_ctx, &func_size))
+    {
+      as_bad (_("the function size for %s has not been evaluated"),
+	      seh_ctx->func_name);
+      return;
+    }
+
+  /* The large functions should be split into fragments smaller than 1MB with
+     4 bytes alignment.
+     https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling?view=msvc-170#large-functions.  */
+  const unsigned max_frag_size = (1 << 20) - 4;
+  const bool is_fragmented_function = func_size > max_frag_size;
+
+  /* [first_fragment_scope, last_fragment_scope).  */
+  unsigned prolog_insn_count = 0;
+  for (unsigned i = 0; i < seh_ctx->unwind_codes_count; ++i)
+    {
+      if (seh_ctx->unwind_codes[i].type == unwind_end)
+	{
+	  prolog_insn_count = i + 1;
+	  break;
+	}
+    }
+
+  unsigned prolog_size;
+  if (seh_ctx->epilogue_scopes_count)
+    prolog_size = seh_ctx->epilogue_scopes[0].epilogue_start_index;
+  else
+    prolog_size = seh_ctx->unwind_codes_byte_count;
+
+  seh_aarch64_func_fragment *fragment;
+  fragment = &seh_ctx->func_fragment;
+  uintptr_t fragment_offset = 0;
+  unsigned first_fragment_scope = 0;
+  unsigned last_fragment_scope = 0;
+  while (true)
+    {
+      fragment->xdata_addr = symbol_temp_new_now ();
+      fragment->offset = fragment_offset;
+      fragment->next = NULL;
+
+      uintptr_t frag_size = func_size - fragment_offset;
+      if (frag_size > max_frag_size)
+	frag_size = max_frag_size;
+
+      const bool is_first_frag = fragment_offset == 0;
+      const bool is_last_frag = (fragment_offset + frag_size) == func_size;
+
+      if (!is_fragmented_function)
+	last_fragment_scope = seh_ctx->epilogue_scopes_count;
+      else
+	{
+	  first_fragment_scope = last_fragment_scope;
+	  for (unsigned i = first_fragment_scope;
+	       i < seh_ctx->epilogue_scopes_count; ++i)
+	    {
+	      const seh_aarch64_epilogue_scope *scope
+		= seh_ctx->epilogue_scopes;
+	      scope += i;
+	      if (scope->epilogue_start_offset >= (fragment_offset + frag_size))
+		break;
+
+	      if (scope->epilogue_end_offset >= (fragment_offset + frag_size))
+		{
+		  frag_size = scope->epilogue_start_offset - fragment_offset;
+		  break;
+		}
+
+	      if (scope->epilogue_start_offset >= fragment_offset)
+		last_fragment_scope = i + 1;
+	    }
+	}
+
+      seh_aarch64_xdata_header *header = &seh_ctx->xdata_header;
+      const seh_aarch64_epilogue_scope *scopes = seh_ctx->epilogue_scopes;
+
+      const uint32_t func_length_encoded = frag_size >> 2;
+      header->func_length = func_length_encoded;
+      header->vers = 0;
+      header->e = 0;
+      header->code_words = 0;
+      header->epilogue_count = 0;
+
+      header->ext_code_words = 0;
+      header->ext_epilogue_count = last_fragment_scope
+				   - first_fragment_scope;
+      header->reserved = 0;
+
+      unsigned first_epilog_index = 0;
+      unsigned last_epilog_index = 0;
+      if (!header->ext_epilogue_count)
+	{
+	  first_epilog_index = prolog_size;
+	  last_epilog_index = prolog_size;
+	}
+      else
+	{
+	  const seh_aarch64_epilogue_scope *scope;
+	  scope = scopes + first_fragment_scope;
+	  first_epilog_index = scope->epilogue_start_index;
+	  if (last_fragment_scope == seh_ctx->epilogue_scopes_count)
+	    last_epilog_index = seh_ctx->unwind_codes_byte_count;
+	  else
+	    {
+	      scope = scopes + last_fragment_scope;
+	      last_epilog_index = scope->epilogue_start_index;
+	    }
+	}
+
+      unsigned unwind_bytes = 0;
+      if (is_first_frag || is_last_frag)
+	unwind_bytes += prolog_size;
+
+      if (header->ext_epilogue_count)
+	unwind_bytes += last_epilog_index - first_epilog_index;
+
+      const bool has_phantom_prolog = is_fragmented_function && is_last_frag;
+      if (has_phantom_prolog && unwind_bytes)
+	{
+	  /* One more epilogue scope and unwind code are emitted with phantom
+	     prolog.  */
+	  unwind_bytes += 1;
+	  ++header->ext_epilogue_count;
+	}
+
+      /* Calculate the number of code words with 4-byte alignment.  */
+      header->ext_code_words = (unwind_bytes + 3) / 4;
+
+      if ((header->ext_code_words == 0 && header->ext_epilogue_count == 0)
+	  || header->ext_code_words > 31
+	  || header->ext_epilogue_count > 31)
+	md_number_to_chars (frag_more (8),
+			   seh_ctx->xdata_header_value, 8);
+      else
+	{
+	  header->code_words = header->ext_code_words;
+	  header->epilogue_count = header->ext_epilogue_count;
+	  if (header->epilogue_count == 1)
+	    {
+	      header->e = 1;
+	      if (has_phantom_prolog)
+		header->ext_epilogue_count = 0;
+	      else
+		{
+		  const seh_aarch64_epilogue_scope *scope;
+		  scope = scopes + first_fragment_scope;
+		  header->ext_epilogue_count = scope->epilogue_start_index;
+		}
+	    }
+	  md_number_to_chars (frag_more (4),
+			      seh_ctx->xdata_header_value, 4);
+	}
+
+      if (header->ext_epilogue_count && !header->e)
+	{
+	  seh_aarch64_emit_epilog_scopes (seh_ctx,
+					 fragment_offset, prolog_size,
+					 first_fragment_scope,
+					 last_fragment_scope,
+					 has_phantom_prolog);
+	  if (has_phantom_prolog)
+	    {
+	      const uint32_t epilog_start_index_encoded = 1 << 22;
+	      const uint32_t epilog_start_offset_encoded
+		= (frag_size - prolog_insn_count * 4) >> 2;
+	      md_number_to_chars (frag_more (4),
+				  epilog_start_index_encoded
+				  | epilog_start_offset_encoded, 4);
+	    }
+	}
+
+      if (header->ext_code_words)
+	seh_aarch64_emit_unwind_codes (seh_ctx, prolog_size, first_epilog_index,
+				       last_epilog_index, has_phantom_prolog);
+
+      if (header->x == 1)
+	{
+	  if (seh_ctx->handler.X_op == O_symbol)
+	    seh_ctx->handler.X_op = O_symbol_rva;
+
+	  emit_expr (&seh_ctx->handler, 4);
+	}
+
+      fragment_offset += frag_size;
+      if (fragment_offset == func_size)
+	break;
+
+      fragment->next = XCNEW (seh_aarch64_func_fragment);
+      fragment = fragment->next;
+    }
+
+  subseg_set (save_seg, save_subseg);
+}
+
+/* Write out pdata for one function.  */
+static void
+seh_aarch64_write_function_pdata (const seh_context *seh_ctx)
+{
+  expressionS exp;
+  const segT save_seg = now_seg;
+  const subsegT save_subseg = now_subseg;
+  memset (&exp, 0, sizeof (expressionS));
+  switch_pdata (seh_ctx->code_seg);
+
+  if (seh_ctx->unwind_codes_byte_count)
+    {
+      const seh_aarch64_func_fragment *fragment = &seh_ctx->func_fragment;
+      while (fragment)
+	{
+	  exp.X_op = O_symbol_rva;
+	  exp.X_add_number = fragment->offset;
+	  exp.X_add_symbol = seh_ctx->start_addr;
+	  emit_expr (&exp, 4);
+
+	  exp.X_op = O_symbol_rva;
+	  /* TODO: Implementing packed unwind data.  */
+	  exp.X_add_number = 0;
+	  exp.X_add_symbol = fragment->xdata_addr;
+	  emit_expr (&exp, 4);
+	  fragment = fragment->next;
+	}
+    }
+
+  subseg_set (save_seg, save_subseg);
+}
+
+void
+seh_aarch64_write_data (void)
+{
+  if (in_seh_proc)
+    as_bad (_("open SEH entry at end of file (missing .seh_endproc)"));
+
+  if (!seh_ctx_root)
+    return;
+
+  struct seh_aarch64_context *seh_ctx = seh_ctx_root;
+  seh_ctx_root = NULL;
+
+  /* Relax the segment to be able to calculate the function sizes.  */
+  subsegs_finish_section (seh_ctx->code_seg);
+  const segment_info_type *seginfo = seg_info (seh_ctx->code_seg);
+  relax_segment (seginfo->frchainP->frch_root, seh_ctx->code_seg, 0);
+
+  while (seh_ctx)
+  {
+    seh_aarch64_write_function_xdata (seh_ctx);
+    seh_aarch64_write_function_pdata (seh_ctx);
+    struct seh_aarch64_context *next = seh_ctx->next;
+    free_seh_ctx (seh_ctx);
+    seh_ctx = next;
+  }
+}
+
+void
+obj_coff_seh_do_final (void)
+{
+}
diff --git a/gas/config/obj-coff-seh-aarch64.h b/gas/config/obj-coff-seh-aarch64.h
new file mode 100644
index 00000000000..bda7e00adc5
--- /dev/null
+++ b/gas/config/obj-coff-seh-aarch64.h
@@ -0,0 +1,265 @@
+/* SEH .pdata/.xdata COFF object file format on AArch64
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GAS.
+
+   GAS 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.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+/* SEH COFF AArch64 implementation partially intersects with the x64
+   version, however it has a different extension to the unwind codes.
+   It emits SEH data to pdata and xdata sections.  In some cases SEH
+   data could be emitted to a packed record in the pdata section
+   without the need for data in the xdata section.  However, the packed
+   pdata record is not implemented yet.  */
+
+#ifndef OBJ_COFF_SEH_AARCH64_H
+#define OBJ_COFF_SEH_AARCH64_H
+
+typedef enum seh_aarch64_unwind_types
+{
+  unwind_alloc_s,
+  unwind_alloc_m,
+  unwind_alloc_l,
+  unwind_save_reg,
+  unwind_save_reg_x,
+  unwind_save_regp,
+  unwind_save_regp_x,
+  unwind_save_fregp,
+  unwind_save_fregp_x,
+  unwind_save_freg,
+  unwind_save_freg_x,
+  unwind_save_lrpair,
+  unwind_save_fplr,
+  unwind_save_fplr_x,
+  unwind_save_r19r20_x,
+  unwind_add_fp,
+  unwind_set_fp,
+  unwind_save_next,
+  unwind_nop,
+  unwind_pac_sign_lr,
+  unwind_end,
+  unwind_end_c,
+  unwind_last_type = unwind_end_c
+} seh_aarch64_unwind_types;
+
+#define SEH_CMDS						      \
+  /* Start a function that contains SEH.  */			      \
+  {"seh_proc", obj_coff_seh_proc, 0},				      \
+								      \
+  /* End a function that contains SEH.  */			      \
+  {"seh_endproc", obj_coff_seh_endproc, 0},			      \
+								      \
+  /* End a SEH prolog with unwinding codes.  */			      \
+  {"seh_endprologue", obj_coff_seh_endprologue, 0},		      \
+								      \
+  /* Allocate stack.  */					      \
+  {"seh_stackalloc", obj_coff_seh_stackalloc, 0},		      \
+								      \
+  /* Set a SEH handler.  */					      \
+  {"seh_handler", obj_coff_seh_handler, 0},			      \
+								      \
+  /* Set a SEH handler data.  */				      \
+  {"seh_handlerdata", obj_coff_seh_handlerdata, 0},		      \
+								      \
+  /* Start a SEH epilogue.  */					      \
+  {"seh_startepilogue", obj_coff_seh_startepilogue, 0},		      \
+								      \
+  /* End a SEH epilogue.  */					      \
+  {"seh_endepilogue", obj_coff_seh_endepilogue, 0},		      \
+								      \
+  /* Save an 'x' register.  */					      \
+  {"seh_save_reg", obj_coff_seh_save_reg, unwind_save_reg},	      \
+								      \
+  /* Save an 'x' register with a pre-indexed offset.  */	      \
+  {"seh_save_reg_x", obj_coff_seh_save_reg, unwind_save_reg_x},	      \
+								      \
+  /* Save an 'x' register pair.  */				      \
+  {"seh_save_regp", obj_coff_seh_save_reg, unwind_save_regp},	      \
+								      \
+  /* Save an 'x' register pair with a pre-indexed offset.  */	      \
+  {"seh_save_regp_x", obj_coff_seh_save_reg, unwind_save_regp_x},     \
+								      \
+  /* Save an 'x' register and lr.  */				      \
+  {"seh_save_lrpair", obj_coff_seh_save_reg, unwind_save_lrpair},     \
+								      \
+  /* Save a 'd' register pair.  */				      \
+  {"seh_save_fregp", obj_coff_seh_save_reg, unwind_save_fregp},	      \
+								      \
+  /* Save a 'd' register pair with a pre-indexed offset.  */	      \
+  {"seh_save_fregp_x", obj_coff_seh_save_reg, unwind_save_fregp_x},   \
+								      \
+  /* Save a 'd' register.  */					      \
+  {"seh_save_freg", obj_coff_seh_save_reg, unwind_save_freg},	      \
+								      \
+  /* Save a 'd' register with a pre-indexed offset.  */		      \
+  {"seh_save_freg_x", obj_coff_seh_save_reg, unwind_save_freg_x},     \
+								      \
+  /* Save fp and lr registers.  */				      \
+  {"seh_save_fplr", obj_coff_seh_save_reg, unwind_save_fplr},	      \
+								      \
+  /* Save fp and lr registers with a pre-indexed offset.  */	      \
+  {"seh_save_fplr_x", obj_coff_seh_save_reg, unwind_save_fplr_x},     \
+								      \
+  /* Save x19 and x20 registers with a pre-indexed offset.  */	      \
+  {"seh_save_r19r20_x", obj_coff_seh_save_reg, unwind_save_r19r20_x}, \
+								      \
+  /* Set fp by sp + offset.  */					      \
+  {"seh_add_fp", obj_coff_seh_save_reg, unwind_add_fp},		      \
+								      \
+  /* Unwind operation is not required.  */			      \
+  {"seh_nop", obj_coff_seh_save_reg, unwind_nop},		      \
+								      \
+  /* Sign the return address in lr with pacibsp.  */		      \
+  {"seh_pac_sign_lr", obj_coff_seh_save_reg, unwind_pac_sign_lr},     \
+								      \
+  /* Set fp by sp.  */						      \
+  {"seh_set_fp", obj_coff_seh_save_reg, unwind_set_fp},		      \
+								      \
+  /* Save next register pair.  */				      \
+  {"seh_save_next", obj_coff_seh_save_reg, unwind_save_next},
+
+/* AArch64 exceptions handling and unwinding structures.
+   https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling#pdata-records.  */
+
+typedef struct seh_aarch64_unwind_code
+{
+  unsigned value;
+  seh_aarch64_unwind_types type;
+} seh_aarch64_unwind_code;
+
+typedef struct seh_aarch64_packed_unwind_data
+{
+  uint32_t flag : 2;
+  uint32_t func_length : 11;
+  uint32_t frame_size : 9;
+  uint32_t cr : 2;
+  uint32_t h : 1;
+  uint32_t regI : 4;
+  uint32_t regF : 3;
+} seh_aarch64_packed_unwind_data;
+
+typedef struct seh_aarch64_except_info
+{
+  uint32_t flag : 2;
+  uint32_t except_info_rva : 30;
+} seh_aarch64_except_info;
+
+typedef union seh_aarch64_unwind_info
+{
+  seh_aarch64_except_info except_info;
+  seh_aarch64_packed_unwind_data packed_unwind_data;
+} seh_aarch64_unwind_info;
+
+typedef struct seh_aarch64_xdata_header
+{
+  uint32_t func_length : 18;
+  uint32_t vers : 2;
+  uint32_t x : 1;
+  uint32_t e : 1;
+  uint32_t epilogue_count : 5;
+  uint32_t code_words : 5;
+  uint32_t ext_epilogue_count : 16;
+  uint32_t ext_code_words : 8;
+  uint32_t reserved : 8;
+} seh_aarch64_xdata_header;
+
+typedef struct seh_aarch64_epilogue_scope
+{
+  uint32_t epilogue_start_offset_reduced : 18;
+  uint32_t reserved : 4;
+  uint32_t epilogue_start_index : 10;
+  bfd_vma epilogue_start_offset;
+  bfd_vma epilogue_end_offset;
+} seh_aarch64_epilogue_scope;
+
+typedef struct seh_aarch64_func_fragment
+{
+  bfd_vma offset;
+  symbolS *xdata_addr;
+  struct seh_aarch64_func_fragment *next;
+} seh_aarch64_func_fragment;
+
+/* AARCH64_MAX_UNWIND_CODES is limited by
+   seh_aarch64_xdata_header::ext_code_words.  */
+#define AARCH64_MAX_UNWIND_CODES (255 * 4)
+#define AARCH64_MAX_UNWIND_CODES_SIZE (255 * 4)
+/* AARCH64_MAX_EPILOGUE_SCOPES is limited by
+   seh_aarch64_xdata_header::ext_epilogue_count.  */
+#define AARCH64_MAX_EPILOGUE_SCOPES 65535
+
+typedef struct seh_aarch64_context
+{
+  struct seh_aarch64_context *next;
+
+  /* Initial code-segment.  */
+  segT code_seg;
+  /* Function name.  */
+  char *func_name;
+  /* BeginAddress.  */
+  symbolS *start_addr;
+  /* EndAddress.  */
+  symbolS *end_addr;
+  /* PrologueEnd.  */
+  symbolS *endprologue_addr;
+  /* ExceptionHandler.  */
+  expressionS handler;
+  /* ExceptionHandlerData.  */
+  expressionS handler_data;
+
+  subsegT subsection;
+
+  union {
+    seh_aarch64_xdata_header xdata_header;
+    valueT xdata_header_value;
+  };
+  unsigned unwind_codes_count;
+  unsigned unwind_codes_byte_count;
+  seh_aarch64_unwind_code unwind_codes[AARCH64_MAX_UNWIND_CODES];
+  unsigned epilogue_scopes_count;
+  unsigned epilogue_scopes_capacity;
+  seh_aarch64_epilogue_scope *epilogue_scopes;
+  expressionS except_handler;
+  expressionS except_handler_data;
+  /* The function fragments.  */
+  seh_aarch64_func_fragment func_fragment;
+} seh_context;
+
+/* aarch64 unwind code prefixes.  */
+
+#define AARCH64_UNOP_ALLOCS	  0b000U
+#define AARCH64_UNOP_SAVER19R20X  0b001U
+#define AARCH64_UNOP_SAVEFPLR	  0b01U
+#define AARCH64_UNOP_SAVEFPLRX	  0b10U
+#define AARCH64_UNOP_ALLOCM	  0b11000U
+#define AARCH64_UNOP_SAVEREGP	  0b110010U
+#define AARCH64_UNOP_SAVEREGPX	  0b110011U
+#define AARCH64_UNOP_SAVEREG	  0b110100U
+#define AARCH64_UNOP_SAVEREGX	  0b1101010U
+#define AARCH64_UNOP_SAVELRPAIR	  0b1101011U
+#define AARCH64_UNOP_SAVEFREGP	  0b1101100U
+#define AARCH64_UNOP_SAVEFREGPX	  0b1101101U
+#define AARCH64_UNOP_SAVEFREG	  0b1101110U
+#define AARCH64_UNOP_SAVEFREGX	  0b11011110U
+#define AARCH64_UNOP_ALLOCL	  0b11100000U
+#define AARCH64_UNOP_SETFP	  0b11100001U
+#define AARCH64_UNOP_ADDFP	  0b11100010U
+#define AARCH64_UNOP_NOP	  0b11100011U
+#define AARCH64_UNOP_END	  0b11100100U
+#define AARCH64_UNOP_ENDC	  0b11100101U
+#define AARCH64_UNOP_SAVENEXT	  0b11100110U
+#define AARCH64_UNOP_PACSIGNLR	  0b11111100U
+
+#endif /* OBJ_COFF_SEH_AARCH64_H.  */
diff --git a/gas/config/obj-coff-seh-shared.c b/gas/config/obj-coff-seh-shared.c
index f3afd981aca..132470c70e6 100644
--- a/gas/config/obj-coff-seh-shared.c
+++ b/gas/config/obj-coff-seh-shared.c
@@ -19,8 +19,13 @@
    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
    02110-1301, USA.  */
 
+#if defined (COFFAARCH64)
+#include "obj-coff-seh-aarch64.h"
+typedef struct seh_aarch64_context seh_context_t;
+#else
 #include "obj-coff-seh.h"
 typedef struct seh_context seh_context_t;
+#endif
 
 /* Private segment collection list.  */
 struct seh_seg_list {
diff --git a/gas/config/obj-coff.c b/gas/config/obj-coff.c
index 7732c0af911..b08295019d8 100644
--- a/gas/config/obj-coff.c
+++ b/gas/config/obj-coff.c
@@ -55,7 +55,11 @@ static const char weak_altprefix[] = ".weak.";
 #endif /* TE_PE */
 
 #include "obj-coff-seh-shared.c"
+#if defined (COFFAARCH64)
+#include "obj-coff-seh-aarch64.c"
+#else
 #include "obj-coff-seh.c"
+#endif
 
 typedef struct
   {
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index cd76163488c..d9d3296a458 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -10375,6 +10375,16 @@ aarch64_cleanup (void)
     }
 }
 
+#if defined (OBJ_COFF)
+/* Called after all assembly has been done.  */
+
+void
+aarch64_md_finish (void)
+{
+  seh_aarch64_write_data();
+}
+#endif /* OBJ_COFF.  */
+
 #ifdef OBJ_ELF
 /* Remove any excess mapping symbols generated for alignment frags in
    SEC.  We may have created a mapping symbol before a zero byte
diff --git a/gas/config/tc-aarch64.h b/gas/config/tc-aarch64.h
index d1fb4c9058b..67f476a3dcc 100644
--- a/gas/config/tc-aarch64.h
+++ b/gas/config/tc-aarch64.h
@@ -82,6 +82,11 @@ struct aarch64_fix
 
 #define tc_frob_section(S) aarch64_frob_section (S)
 
+#if defined (OBJ_COFF)
+#define md_finish aarch64_md_finish
+extern void aarch64_md_finish (void);
+#endif
+
 /* The key used to sign a function's return address.  */
 enum pointer_auth_key {
   AARCH64_PAUTH_KEY_A,
@@ -363,6 +368,7 @@ extern void aarch64_handle_align (struct frag *);
 extern int tc_aarch64_regname_to_dw2regnum (char *regname);
 extern void tc_aarch64_frame_initial_instructions (void);
 extern bool aarch64_fix_adjustable (struct fix *);
+extern void seh_aarch64_write_data (void);
 
 #ifdef TE_PE
 
diff --git a/gas/write.c b/gas/write.c
index 9d0777051dd..903f858b4dc 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -1831,7 +1831,7 @@ set_symtab (void)
 #endif
 #endif
 
-static void
+void
 subsegs_finish_section (asection *s)
 {
   struct frchain *frchainP;
diff --git a/gas/write.h b/gas/write.h
index 7281930c2d6..0638e5958d6 100644
--- a/gas/write.h
+++ b/gas/write.h
@@ -188,5 +188,6 @@ extern fixS *fix_new_exp (fragS *, unsigned long, unsigned long,
 			  const expressionS *, int, bfd_reloc_code_real_type);
 extern void write_print_statistics (FILE *);
 extern void as_bad_subtract (fixS *);
+extern void subsegs_finish_section (asection *);
 
 #endif /* __write_h__ */
