diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c
index 78b3ecb5a7d..cd2b5f03346 100644
--- a/bfd/elf-eh-frame.c
+++ b/bfd/elf-eh-frame.c
@@ -338,12 +338,79 @@ next_cie_fde_offset (const struct eh_cie_fde *ent,
   return sec->size;
 }
 
+static bool
+skip_cfa_op_aarch64 (bfd_byte op,
+		     bfd_byte **iter ATTRIBUTE_UNUSED,
+		     bfd_byte *end ATTRIBUTE_UNUSED)
+{
+  switch (op)
+    {
+      case DW_CFA_AARCH64_negate_ra_state:
+      case DW_CFA_AARCH64_negate_ra_state_with_pc:
+	/* No arguments.  */
+	return true;
+
+      default:
+	return false;
+    }
+}
+
+static bool
+skip_cfa_op_mips (bfd_byte op,
+		  bfd_byte **iter,
+		  bfd_byte *end)
+{
+  switch (op)
+    {
+      case DW_CFA_MIPS_advance_loc8:
+	return skip_bytes (iter, end, 8);
+
+      default:
+	return false;
+    }
+}
+
+static bool
+skip_cfa_op_sparc (bfd_byte op,
+		   bfd_byte **iter ATTRIBUTE_UNUSED,
+		   bfd_byte *end ATTRIBUTE_UNUSED)
+{
+  switch (op)
+    {
+      case DW_CFA_GNU_window_save:
+	/* No arguments.  */
+	return true;
+
+      default:
+	return false;
+    }
+}
+
+static bool
+skip_cfa_op_arch_specific (enum bfd_architecture arch,
+			   bfd_byte **iter, bfd_byte *end,
+			   bfd_byte op)
+{
+  switch (arch)
+    {
+      case bfd_arch_aarch64:
+	return skip_cfa_op_aarch64 (op, iter, end);
+      case bfd_arch_mips:
+	return skip_cfa_op_mips (op, iter, end);
+      case bfd_arch_sparc:
+	return skip_cfa_op_sparc (op, iter, end);
+      default:
+	return false;
+    }
+}
+
 /* Assume that the bytes between *ITER and END are CFA instructions.
    Try to move *ITER past the first instruction and return true on
    success.  ENCODED_PTR_WIDTH gives the width of pointer entries.  */
 
 static bool
-skip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width)
+skip_cfa_op (enum bfd_architecture arch, bfd_byte **iter, bfd_byte *end,
+	     unsigned int encoded_ptr_width)
 {
   bfd_byte op = 0;
   bfd_vma length;
@@ -351,15 +418,14 @@ skip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width)
   if (!read_byte (iter, end, &op))
     return false;
 
-  switch (op & 0xc0 ? op & 0xc0 : op)
+  op = op & 0xc0 ? op & 0xc0 : op;
+  switch (op)
     {
     case DW_CFA_nop:
     case DW_CFA_advance_loc:
     case DW_CFA_restore:
     case DW_CFA_remember_state:
     case DW_CFA_restore_state:
-    case DW_CFA_GNU_window_save:
-    case DW_CFA_AARCH64_negate_ra_state_with_pc:
       /* No arguments.  */
       return true;
 
@@ -410,10 +476,9 @@ skip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width)
     case DW_CFA_advance_loc4:
       return skip_bytes (iter, end, 4);
 
-    case DW_CFA_MIPS_advance_loc8:
-      return skip_bytes (iter, end, 8);
-
     default:
+      if (op >= DW_CFA_lo_user && op <= DW_CFA_hi_user)
+	return skip_cfa_op_arch_specific (arch, iter, end, op);
       return false;
     }
 }
@@ -424,8 +489,8 @@ skip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width)
    ENCODED_PTR_WIDTH is as for skip_cfa_op.  */
 
 static bfd_byte *
-skip_non_nops (bfd_byte *buf, bfd_byte *end, unsigned int encoded_ptr_width,
-	       unsigned int *set_loc_count)
+skip_non_nops (enum bfd_architecture arch, bfd_byte *buf, bfd_byte *end,
+	       unsigned int encoded_ptr_width, unsigned int *set_loc_count)
 {
   bfd_byte *last;
 
@@ -437,7 +502,7 @@ skip_non_nops (bfd_byte *buf, bfd_byte *end, unsigned int encoded_ptr_width,
       {
 	if (*buf == DW_CFA_set_loc)
 	  ++*set_loc_count;
-	if (!skip_cfa_op (&buf, end, encoded_ptr_width))
+	if (!skip_cfa_op (arch, &buf, end, encoded_ptr_width))
 	  return 0;
 	last = buf;
       }
@@ -994,7 +1059,8 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
 	 include the padding.  */
       length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
       set_loc_count = 0;
-      insns_end = skip_non_nops (insns, end, length, &set_loc_count);
+      insns_end = skip_non_nops (bfd_get_arch (abfd), insns, end, length,
+				 &set_loc_count);
       /* If we don't understand the CFA instructions, we can't know
 	 what needs to be adjusted there.  */
       if (insns_end == NULL
@@ -1025,7 +1091,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
 	    {
 	      if (*p == DW_CFA_set_loc)
 		this_inf->set_loc[++cnt] = p + 1 - start;
-	      REQUIRE (skip_cfa_op (&p, end, length));
+	      REQUIRE (skip_cfa_op (bfd_get_arch (abfd), &p, end, length));
 	    }
 	}
 
diff --git a/gas/config.in b/gas/config.in
index bb896244640..4f58c40d35b 100644
--- a/gas/config.in
+++ b/gas/config.in
@@ -173,6 +173,9 @@
 /* Choose a default ABI for MIPS targets. */
 #undef MIPS_DEFAULT_ABI
 
+/* Building gas module */
+#undef MODULE_GAS
+
 /* Define value for nds32_arch_name */
 #undef NDS32_DEFAULT_ARCH_NAME
 
diff --git a/gas/configure b/gas/configure
index 16a8937f53a..b4fbc7922e4 100755
--- a/gas/configure
+++ b/gas/configure
@@ -12993,6 +12993,10 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+
+$as_echo "#define MODULE_GAS 1" >>confdefs.h
+
+
 for ac_prog in 'bison -y' byacc
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
diff --git a/gas/configure.ac b/gas/configure.ac
index e97ec598b6f..d81746542e8 100644
--- a/gas/configure.ac
+++ b/gas/configure.ac
@@ -937,6 +937,8 @@ AC_DEFINE_UNQUOTED(TARGET_CPU,		"${target_cpu}",   [Target CPU.])
 AC_DEFINE_UNQUOTED(TARGET_VENDOR,	"${target_vendor}", [Target vendor.])
 AC_DEFINE_UNQUOTED(TARGET_OS,		"${target_os}",    [Target OS.])
 
+AC_DEFINE(MODULE_GAS, 1, [Building gas module])
+
 AC_PROG_YACC
 AM_PROG_LEX
 
diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c
index a21ae322488..d025da35676 100644
--- a/gas/dw2gencfi.c
+++ b/gas/dw2gencfi.c
@@ -720,9 +720,16 @@ const pseudo_typeS cfi_pseudo_table[] =
     { "cfi_same_value", dot_cfi, DW_CFA_same_value },
     { "cfi_remember_state", dot_cfi, DW_CFA_remember_state },
     { "cfi_restore_state", dot_cfi, DW_CFA_restore_state },
-    { "cfi_window_save", dot_cfi, DW_CFA_GNU_window_save },
+#if TC_AARCH64
+    /* cfi_window_save is an alias of cfi_negate_ra_state which is kept for
+       backward-compatibility concerns.  */
+    { "cfi_window_save", dot_cfi, DW_CFA_AARCH64_negate_ra_state },
     { "cfi_negate_ra_state", dot_cfi, DW_CFA_AARCH64_negate_ra_state },
     { "cfi_negate_ra_state_with_pc", dot_cfi, DW_CFA_AARCH64_negate_ra_state_with_pc },
+#endif /* TC_AARCH64 */
+#if TC_SPARC
+    { "cfi_window_save", dot_cfi, DW_CFA_GNU_window_save },
+#endif /* TC_SPARC */
     { "cfi_escape", dot_cfi_escape, 0 },
     { "cfi_signal_frame", dot_cfi, CFI_signal_frame },
     { "cfi_personality", dot_cfi_personality, 0 },
@@ -919,13 +926,21 @@ dot_cfi (int arg)
       cfi_add_CFA_restore_state ();
       break;
 
-    case DW_CFA_GNU_window_save:
-      cfi_add_CFA_insn (DW_CFA_GNU_window_save);
+#if TC_AARCH64
+    case DW_CFA_AARCH64_negate_ra_state:
+      cfi_add_CFA_insn (DW_CFA_AARCH64_negate_ra_state);
       break;
 
     case DW_CFA_AARCH64_negate_ra_state_with_pc:
       cfi_add_CFA_insn (DW_CFA_AARCH64_negate_ra_state_with_pc);
       break;
+#endif /* TC_AARCH64 */
+
+#if TC_SPARC
+    case DW_CFA_GNU_window_save:
+      cfi_add_CFA_insn (DW_CFA_GNU_window_save);
+      break;
+#endif /* TC_SPARC */
 
     case CFI_signal_frame:
       frchain_now->frch_cfi_data->cur_fde_data->signal_frame = 1;
@@ -1824,13 +1839,21 @@ output_cfi_insn (struct cfi_insn_data *insn)
       out_one (insn->insn);
       break;
 
-    case DW_CFA_GNU_window_save:
-      out_one (DW_CFA_GNU_window_save);
+#if TC_AARCH64
+    case DW_CFA_AARCH64_negate_ra_state:
+      out_one (DW_CFA_AARCH64_negate_ra_state);
       break;
 
     case DW_CFA_AARCH64_negate_ra_state_with_pc:
       out_one (DW_CFA_AARCH64_negate_ra_state_with_pc);
       break;
+#endif /* TC_AARCH64 */
+
+#if TC_SPARC
+    case DW_CFA_GNU_window_save:
+      out_one (DW_CFA_GNU_window_save);
+      break;
+#endif /* TC_SPARC */
 
     case CFI_escape:
       {
diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
index 5b5e7b14b3a..3a5ecda47de 100644
--- a/gas/gen-sframe.c
+++ b/gas/gen-sframe.c
@@ -1257,6 +1257,8 @@ sframe_xlate_do_restore (struct sframe_xlate_ctx *xlate_ctx,
   return SFRAME_XLATE_OK;
 }
 
+#if TC_AARCH64
+
 /* Translate DW_CFA_AARCH64_negate_ra_state into SFrame context.
    Return SFRAME_XLATE_OK if success.  */
 
@@ -1287,30 +1289,7 @@ sframe_xlate_do_aarch64_negate_ra_state_with_pc (struct sframe_xlate_ctx *xlate_
   return SFRAME_XLATE_ERR_NOTREPRESENTED;  /* Not represented.  */
 }
 
-/* Translate DW_CFA_GNU_window_save into SFrame context.
-   DW_CFA_GNU_window_save is a DWARF Sparc extension, but is multiplexed with a
-   directive of DWARF AArch64 extension: DW_CFA_AARCH64_negate_ra_state.
-   The AArch64 backend of GCC 14 and older versions was emitting mistakenly the
-   Sparc CFI directive (.cfi_window_save).  From GCC 15, the AArch64 backend
-   only emits .cfi_negate_ra_state.  For backward compatibility, the handler for
-   .cfi_window_save needs to check whether the directive was used in a AArch64
-   ABI context or not.
-   Return SFRAME_XLATE_OK if success.  */
-
-static int
-sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
-				 struct cfi_insn_data *cfi_insn)
-{
-  unsigned char abi_arch = sframe_get_abi_arch ();
-
-  /* Translate DW_CFA_AARCH64_negate_ra_state into SFrame context.  */
-  if (abi_arch == SFRAME_ABI_AARCH64_ENDIAN_BIG
-      || abi_arch == SFRAME_ABI_AARCH64_ENDIAN_LITTLE)
-    return sframe_xlate_do_aarch64_negate_ra_state (xlate_ctx, cfi_insn);
-
-  as_warn (_("skipping SFrame FDE; .cfi_window_save"));
-  return SFRAME_XLATE_ERR_NOTREPRESENTED;  /* Not represented.  */
-}
+#endif /* TC_AARCH64 */
 
 /* Handle DW_CFA_expression in .cfi_escape.
 
@@ -1622,14 +1601,14 @@ sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
     case DW_CFA_restore:
       err = sframe_xlate_do_restore (xlate_ctx, cfi_insn);
       break;
-    /* DW_CFA_AARCH64_negate_ra_state is multiplexed with
-       DW_CFA_GNU_window_save.  */
-    case DW_CFA_GNU_window_save:
-      err = sframe_xlate_do_gnu_window_save (xlate_ctx, cfi_insn);
+#if TC_AARCH64
+    case DW_CFA_AARCH64_negate_ra_state:
+      err = sframe_xlate_do_aarch64_negate_ra_state (xlate_ctx, cfi_insn);
       break;
     case DW_CFA_AARCH64_negate_ra_state_with_pc:
       err = sframe_xlate_do_aarch64_negate_ra_state_with_pc (xlate_ctx, cfi_insn);
       break;
+#endif /* TC_AARCH64 */
     case DW_CFA_register:
       err = sframe_xlate_do_register (xlate_ctx, cfi_insn);
       break;
diff --git a/include/dwarf2.def b/include/dwarf2.def
index 6d6c0e0cc39..c9dd3e4aae3 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -780,20 +780,46 @@ DW_CFA (DW_CFA_val_offset, 0x14)
 DW_CFA (DW_CFA_val_offset_sf, 0x15)
 DW_CFA (DW_CFA_val_expression, 0x16)
 
+/* Users extensions.
+   Note: DW_CFA_lo_user and DW_CFA_hi_user can be aliased to used as extension.
+   This is a closed interval.  */
 DW_CFA (DW_CFA_lo_user, 0x1c)
-DW_CFA (DW_CFA_hi_user, 0x3f)
 
-/* SGI/MIPS specific.  */
+/* For gas, we disable the extensions according to the target architecture.  */
+#ifdef MODULE_GAS
+/* SGI/MIPS specific extensions.  */
+#ifdef TC_MIPS
 DW_CFA (DW_CFA_MIPS_advance_loc8, 0x1d)
-/* AArch64 extensions.  */
+#endif /* TC_MIPS */
+
+/* AArch64 specific extensions.  */
+#ifdef TC_AARCH64
 DW_CFA (DW_CFA_AARCH64_negate_ra_state_with_pc, 0x2c)
-/* GNU extensions.
-   NOTE: DW_CFA_GNU_window_save is multiplexed on Sparc and AArch64.  */
+DW_CFA (DW_CFA_AARCH64_negate_ra_state, 0x2d)
+/* NOTE: DW_CFA_GNU_window_save is multiplexed on Sparc and AArch64.  */
+DW_CFA_DUP (DW_CFA_GNU_window_save, 0x2d)
+#endif /* TC_AARCH64 */
+
+/* Sparc specific extensions.  */
+#ifdef TC_SPARC
 DW_CFA (DW_CFA_GNU_window_save, 0x2d)
-DW_CFA_DUP (DW_CFA_AARCH64_negate_ra_state, 0x2d)
+#endif /* TC_SPARC */
+#else
+/* SGI/MIPS specific extensions.  */
+DW_CFA (DW_CFA_MIPS_advance_loc8, 0x1d)
+/* AArch64 specific extensions.  */
+DW_CFA (DW_CFA_AARCH64_negate_ra_state_with_pc, 0x2c)
+DW_CFA (DW_CFA_AARCH64_negate_ra_state, 0x2d)
+/* NOTE: DW_CFA_GNU_window_save is multiplexed on Sparc and AArch64.  */
+DW_CFA_DUP (DW_CFA_GNU_window_save, 0x2d)
+#endif
+
+/* GNU extensions.  */
 DW_CFA (DW_CFA_GNU_args_size, 0x2e)
 DW_CFA (DW_CFA_GNU_negative_offset_extended, 0x2f)
 
+DW_CFA (DW_CFA_hi_user, 0x3f)
+
 DW_END_CFA
 
 /* Index attributes in the Abbreviations Table.  */
