diff options
author | Indu Bhagat <indu.bhagat@oracle.com> | 2022-11-15 15:06:46 -0800 |
---|---|---|
committer | Indu Bhagat <indu.bhagat@oracle.com> | 2022-11-15 15:24:06 -0800 |
commit | b52c4ee46657eb5a70095d48cbc2938d024cc3b6 (patch) | |
tree | 10fb1afba608156a25ebe9732cfe5e3fe1d85833 /gas/config/tc-i386.c | |
parent | b07a29781610756a9b75a931c7c13735b7555d9f (diff) | |
download | binutils-gdb-b52c4ee46657eb5a70095d48cbc2938d024cc3b6.tar.gz |
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/tc-i386.c')
-rw-r--r-- | gas/config/tc-i386.c | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index a5ea9b16c9e..5bc3a56e4b2 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 |