On 09.04.2025 12:36, Matthieu Longo wrote:
> --- 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:
Much like it is in existing code you modify (further down), case labels want
to align with the opening brace. I.e. here and below you will want to un-
indent what's inside the figure braces of switch() by one level.
> +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);
Hmm, I'm uncertain here - from the name DW_CFA_GNU_window_save isn't Sparc-
specific. Yet then I can see that gcc uses it only there.
In any event, much like you do further up, having blank lines between non-
fall-through case blocks would be nice.
> --- 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])
Hmm, here I'm again not sure: As this is unconditional, I'd have expected
the definition to come from Makefile.am instead. Question is whether we need
the extra #define in the first place: TC_* shouldn't be defined in subdirs
other than gas/. Then again dwarf2.def is shared with at least gcc, so
perhaps better to be on the safe side. However, as.h already defines GAS -
can't we key to that?
> --- 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 */
See comment further up (applicable also further down).
> --- 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
Does this really need doing with nested #if/#else? I think it would be easier
to follow if each DW_CFA_* appeared just once here. And whether ...
> +/* 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)
... this really needs to move I'm also unsure.
Jan
@@ -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));
}
}
@@ -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
@@ -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.
@@ -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
@@ -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:
{
@@ -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;
@@ -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. */