aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorIndu Bhagat <indu.bhagat@oracle.com>2022-11-15 15:06:46 -0800
committerIndu Bhagat <indu.bhagat@oracle.com>2022-11-15 15:24:06 -0800
commitb52c4ee46657eb5a70095d48cbc2938d024cc3b6 (patch)
tree10fb1afba608156a25ebe9732cfe5e3fe1d85833 /gas/config
parentb07a29781610756a9b75a931c7c13735b7555d9f (diff)
downloadbinutils-b52c4ee46657eb5a70095d48cbc2938d024cc3b6.zip
binutils-b52c4ee46657eb5a70095d48cbc2938d024cc3b6.tar.gz
binutils-b52c4ee46657eb5a70095d48cbc2938d024cc3b6.tar.bz2
gas: generate .sframe from CFI directives
Currently supported for x86_64 and aarch64 only. [PS: Currently, the compiler has not been adapted to generate ".cfi_sections" with ".sframe" in it. The newly added command line option of --gsframe provides an easy way to try out .sframe support in the toolchain.] gas interprets the CFI directives to generate DWARF-based .eh_frame info. These internal DWARF structures are now consumed by gen-sframe.[ch] sub-system to, in turn, create the SFrame unwind information. These internal DWARF structures are read-only for the purpose of SFrame unwind info generation. SFrame unwind info generation does not impact .eh_frame unwind info generation. Both .eh_frame and .sframe can co-exist in an ELF file, if so desired by the user. Recall that SFrame unwind information only contains the minimal necessary information to generate backtraces and does not provide information to recover all callee-saved registers. The reason being that callee-saved registers other than FP are not needed for stack unwinding, and hence are not included in the .sframe section. Consequently, gen-sframe.[ch] only needs to interpret a subset of DWARF opcodes in gas. More details follow. [Set 1, Interpreted] The following opcodes are interpreted: - DW_CFA_advance_loc - DW_CFA_def_cfa - DW_CFA_def_cfa_register - DW_CFA_def_cfa_offset - DW_CFA_offset - DW_CFA_remember_state - DW_CFA_restore_state - DW_CFA_restore [Set 2, Bypassed] The following opcodes are acknowledged but are not necessary for generating SFrame unwind info: - DW_CFA_undefined - DW_CFA_same_value Anything else apart from the two above-mentioned sets is skipped altogether. This means that any function containing a CFI directive not in Set 1 or Set 2 above, will not have any SFrame unwind information generated for them. Holes in instructions covered by FREs of a single FDE are not representable in the SFrame unwind format. As few examples, following opcodes are not processed for .sframe generation, and are skipped: - .cfi_personality* - .cfi_*lsda - .cfi_escape - .cfi_negate_ra_state - ... Not processing .cfi_escape, .cfi_negate_ra_state will cause SFrame unwind information to be absent for SFrame FDEs that contain these CFI directives, hence affecting the asynchronicity. x86-64 and aarch64 backends need to have a few new definitions and functions for .sframe generation. These provide gas with architecture specific information like the SP/FP/RA register numbers and an SFrame-specific ABI marker. Lastly, the patch also implements an optimization for size, where specific fragments containing SFrame FRE start address and SFrame FDE function are fixed up. This is similar to other similar optimizations in gas, where fragments are sized and fixed up when the associated symbols can be resolved. This optimization is controlled by a #define SFRAME_FRE_TYPE_SELECTION_OPT and should be easy to turn off if needed. The optimization is on by default for both x86_64 and aarch64. ChangeLog: * gas/Makefile.am: Include gen-sframe.c and sframe-opt.c. * gas/Makefile.in: Regenerated. * gas/as.h (enum _relax_state): Add new state rs_sframe. (sframe_estimate_size_before_relax): New function. (sframe_relax_frag): Likewise. (sframe_convert_frag): Likewise. * gas/config/tc-aarch64.c (aarch64_support_sframe_p): New definition. (aarch64_sframe_ra_tracking_p): Likewise. (aarch64_sframe_cfa_ra_offset): Likewise. (aarch64_sframe_get_abi_arch): Likewise. (md_begin): Set values of sp/fp/ra registers. * gas/config/tc-aarch64.h (aarch64_support_sframe_p): New declaration. (support_sframe_p): Likewise. (SFRAME_CFA_SP_REG): Likewise. (SFRAME_CFA_FP_REG): Likewise. (SFRAME_CFA_RA_REG): Likewise. (aarch64_sframe_ra_tracking_p): Likewise. (sframe_ra_tracking_p): Likewise. (aarch64_sframe_cfa_ra_offset): Likewise. (sframe_cfa_ra_offset): Likewise. (aarch64_sframe_get_abi_arch): Likewise. (sframe_get_abi_arch): Likewise. * gas/config/tc-i386.c (x86_support_sframe_p): New definition. (x86_sframe_ra_tracking_p): Likewise. (x86_sframe_cfa_ra_offset): Likewise. (x86_sframe_get_abi_arch): Likewise. * gas/config/tc-i386.h (x86_support_sframe_p): New declaration. (support_sframe_p): Likewise. (SFRAME_CFA_SP_REG): Likewise. (SFRAME_CFA_FP_REG): Likewise. (x86_sframe_ra_tracking_p): Likewise. (sframe_ra_tracking_p): Likewise. (x86_sframe_cfa_ra_offset): Likewise. (sframe_cfa_ra_offset): Likewise. (x86_sframe_get_abi_arch): Likewise. (sframe_get_abi_arch): Likewise. * gas/config/tc-xtensa.c (unrelaxed_frag_max_size): Add case for rs_sframe. * gas/doc/as.texi: Add .sframe to the documentation for .cfi_sections. * gas/dw2gencfi.c (cfi_finish): Create a .sframe section. * gas/dw2gencfi.h (CFI_EMIT_sframe): New definition. * gas/write.c (cvt_frag_to_fill): Handle rs_sframe. (relax_segment): Likewise. * gas/gen-sframe.c: New file. * gas/gen-sframe.h: New file. * gas/sframe-opt.c: New file.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-aarch64.c58
-rw-r--r--gas/config/tc-aarch64.h29
-rw-r--r--gas/config/tc-i386.c50
-rw-r--r--gas/config/tc-i386.h26
-rw-r--r--gas/config/tc-xtensa.c1
5 files changed, 164 insertions, 0 deletions
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 165d927..c679d93 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -30,6 +30,9 @@
#ifdef OBJ_ELF
#include "elf/aarch64.h"
+#include "dw2gencfi.h"
+#include "sframe.h"
+#include "gen-sframe.h"
#endif
#include "dw2gencfi.h"
@@ -72,6 +75,11 @@ enum aarch64_abi_type
AARCH64_ABI_LLP64 = 3
};
+unsigned int aarch64_sframe_cfa_sp_reg;
+/* The other CFA base register for SFrame unwind info. */
+unsigned int aarch64_sframe_cfa_fp_reg;
+unsigned int aarch64_sframe_cfa_ra_reg;
+
#ifndef DEFAULT_ARCH
#define DEFAULT_ARCH "aarch64"
#endif
@@ -8403,6 +8411,50 @@ aarch64_init_frag (fragS * fragP, int max_chars)
break;
}
}
+
+/* Whether SFrame unwind info is supported. */
+
+bool
+aarch64_support_sframe_p (void)
+{
+ /* At this time, SFrame is supported for aarch64 only. */
+ return (aarch64_abi == AARCH64_ABI_LP64);
+}
+
+/* Specify if RA tracking is needed. */
+
+bool
+aarch64_sframe_ra_tracking_p (void)
+{
+ return true;
+}
+
+/* Specify the fixed offset to recover RA from CFA.
+ (useful only when RA tracking is not needed). */
+
+offsetT
+aarch64_sframe_cfa_ra_offset (void)
+{
+ return (offsetT) SFRAME_CFA_FIXED_RA_INVALID;
+}
+
+/* Get the abi/arch indentifier for SFrame. */
+
+unsigned char
+aarch64_sframe_get_abi_arch (void)
+{
+ unsigned char sframe_abi_arch = 0;
+
+ if (aarch64_support_sframe_p ())
+ {
+ sframe_abi_arch = target_big_endian
+ ? SFRAME_ABI_AARCH64_ENDIAN_BIG
+ : SFRAME_ABI_AARCH64_ENDIAN_LITTLE;
+ }
+
+ return sframe_abi_arch;
+}
+
#endif /* OBJ_ELF */
/* Initialize the DWARF-2 unwind information for this procedure. */
@@ -9688,6 +9740,12 @@ md_begin (void)
mach = bfd_mach_aarch64;
bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
+#ifdef OBJ_ELF
+ /* FIXME - is there a better way to do it ? */
+ aarch64_sframe_cfa_sp_reg = 31;
+ aarch64_sframe_cfa_fp_reg = 29; /* x29. */
+ aarch64_sframe_cfa_ra_reg = 30;
+#endif
}
/* Command line processing. */
diff --git a/gas/config/tc-aarch64.h b/gas/config/tc-aarch64.h
index 2d514ff..91412ce 100644
--- a/gas/config/tc-aarch64.h
+++ b/gas/config/tc-aarch64.h
@@ -239,6 +239,35 @@ struct aarch64_segment_info_type
/* We want .cfi_* pseudo-ops for generating unwind info. */
#define TARGET_USE_CFIPOP 1
+/* Whether SFrame unwind info is supported. */
+extern bool aarch64_support_sframe_p (void);
+#define support_sframe_p aarch64_support_sframe_p
+
+/* The stack-pointer register number for SFrame unwind info. */
+extern unsigned int aarch64_sframe_cfa_sp_reg;
+#define SFRAME_CFA_SP_REG aarch64_sframe_cfa_sp_reg
+
+/* The base-pointer register number for CFA unwind info. */
+extern unsigned int aarch64_sframe_cfa_fp_reg;
+#define SFRAME_CFA_FP_REG aarch64_sframe_cfa_fp_reg
+
+/* The return address register number for CFA unwind info. */
+extern unsigned int aarch64_sframe_cfa_ra_reg;
+#define SFRAME_CFA_RA_REG aarch64_sframe_cfa_ra_reg
+
+/* Specify if RA tracking is needed. */
+extern bool aarch64_sframe_ra_tracking_p (void);
+#define sframe_ra_tracking_p aarch64_sframe_ra_tracking_p
+
+/* Specify the fixed offset to recover RA from CFA.
+ (useful only when RA tracking is not needed). */
+extern offsetT aarch64_sframe_cfa_ra_offset (void);
+#define sframe_cfa_ra_offset aarch64_sframe_cfa_ra_offset
+
+/* The abi/arch indentifier for SFrame. */
+unsigned char aarch64_sframe_get_abi_arch (void);
+#define sframe_get_abi_arch aarch64_sframe_get_abi_arch
+
/* CFI hooks. */
#define tc_regname_to_dw2regnum tc_aarch64_regname_to_dw2regnum
#define tc_cfi_frame_initial_instructions tc_aarch64_frame_initial_instructions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index a5ea9b1..5bc3a56 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -30,6 +30,8 @@
#include "subsegs.h"
#include "dwarf2dbg.h"
#include "dw2gencfi.h"
+#include "gen-sframe.h"
+#include "sframe.h"
#include "elf/x86-64.h"
#include "opcodes/i386-init.h"
#include <limits.h>
@@ -591,6 +593,12 @@ static int use_big_obj = 0;
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
/* 1 if generating code for a shared library. */
static int shared = 0;
+
+unsigned int x86_sframe_cfa_sp_reg;
+/* The other CFA base register for SFrame unwind info. */
+unsigned int x86_sframe_cfa_fp_reg;
+unsigned int x86_sframe_cfa_ra_reg;
+
#endif
/* 1 for intel syntax,
@@ -3099,6 +3107,10 @@ md_begin (void)
x86_dwarf2_return_column = 16;
#endif
x86_cie_data_alignment = -8;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ x86_sframe_cfa_sp_reg = 7;
+ x86_sframe_cfa_fp_reg = 6;
+#endif
}
else
{
@@ -9131,6 +9143,44 @@ x86_cleanup (void)
if (seg && subseg)
subseg_set (seg, subseg);
}
+
+bool
+x86_support_sframe_p (void)
+{
+ /* At this time, SFrame unwind is supported for AMD64 ABI only. */
+ return (x86_elf_abi == X86_64_ABI);
+}
+
+bool
+x86_sframe_ra_tracking_p (void)
+{
+ /* In AMD64, return address is always stored on the stack at a fixed offset
+ from the CFA (provided via x86_sframe_cfa_ra_offset ()).
+ Do not track explicitly via an SFrame Frame Row Entry. */
+ return false;
+}
+
+offsetT
+x86_sframe_cfa_ra_offset (void)
+{
+ gas_assert (x86_elf_abi == X86_64_ABI);
+ return (offsetT) -8;
+}
+
+unsigned char
+x86_sframe_get_abi_arch (void)
+{
+ unsigned char sframe_abi_arch = 0;
+
+ if (x86_support_sframe_p ())
+ {
+ gas_assert (!target_big_endian);
+ sframe_abi_arch = SFRAME_ABI_AMD64_ENDIAN_LITTLE;
+ }
+
+ return sframe_abi_arch;
+}
+
#endif
static unsigned int
diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
index a6e096e..9003726 100644
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -362,6 +362,32 @@ extern bfd_vma x86_64_section_letter (int, const char **);
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
extern void x86_cleanup (void);
#define md_cleanup() x86_cleanup ()
+
+/* Whether SFrame unwind info is supported. */
+extern bool x86_support_sframe_p (void);
+#define support_sframe_p x86_support_sframe_p
+
+/* The stack-pointer register number for SFrame unwind info. */
+extern unsigned int x86_sframe_cfa_sp_reg;
+#define SFRAME_CFA_SP_REG x86_sframe_cfa_sp_reg
+
+/* The frame-pointer register number for CFA unwind info. */
+extern unsigned int x86_sframe_cfa_fp_reg;
+#define SFRAME_CFA_FP_REG x86_sframe_cfa_fp_reg
+
+/* Specify if RA tracking is needed. */
+extern bool x86_sframe_ra_tracking_p (void);
+#define sframe_ra_tracking_p x86_sframe_ra_tracking_p
+
+/* Specify the fixed offset to recover RA from CFA.
+ (useful only when RA tracking is not needed). */
+extern offsetT x86_sframe_cfa_ra_offset (void);
+#define sframe_cfa_ra_offset x86_sframe_cfa_ra_offset
+
+/* The abi/arch indentifier for SFrame. */
+extern unsigned char x86_sframe_get_abi_arch (void);
+#define sframe_get_abi_arch x86_sframe_get_abi_arch
+
#endif
#ifdef TE_PE
diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
index b7403ac..f7a28d3 100644
--- a/gas/config/tc-xtensa.c
+++ b/gas/config/tc-xtensa.c
@@ -8616,6 +8616,7 @@ unrelaxed_frag_max_size (fragS *fragP)
case rs_leb128:
case rs_cfa:
case rs_dwarf2dbg:
+ case rs_sframe:
/* No further adjustments needed. */
break;
case rs_machine_dependent: