From: Indu Bhagat Date: Wed, 19 Nov 2025 17:26:47 +0000 (-0800) Subject: [SFrame-V3] gas: sframe: output new FDE type SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=757afde36afa6915d0ce364a547df4bc7b1f52e0;p=thirdparty%2Fbinutils-gdb.git [SFrame-V3] gas: sframe: output new FDE type SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME This patch updates the routines for emission of the new FDE type SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME in the SFrame output section. The support for generating the flex-topmost-frame FDEs themselves is added in a subsequent commit. For flex topmost FDE type, output_sframe_row_entry_offsets () emits two offsets for RA tracking, irrespective of the ABI/arch, i.e., irrespecitve of whether RA-tracking is enabled. This is because, for flexible topmost frames, RA is allowed "non-standard" recovery rules, e.g., RA = REG or RA = *(REG+offset). In a follow-up patch, when handling for .cfi_register RA, REG is added, emission code will be patched up accodingly. gas/ * gen-sframe.c (get_fre_num_offsets): Get number of offsets for SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME fde type as well (new argument). (output_sframe_row_entry_offsets): Output the SFrame FREs for two different cases (fde type SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME or the default). (output_sframe_row_entry): Update caller. (output_sframe_funcdesc): Emit func type in func_info2 field. (sframe_xlate_ctx_init): Initialize flex_topmost_p in translation context object. (sframe_xlate_ctx_finalize): Likewise. (sframe_row_entry_initialize): Copy over new data members too. * gen-sframe.h (struct sframe_row_entry): Add tracking for CFA dereferencing, frame pointer dereferencing. (struct sframe_func_entry): Add tracking for flexible topmost frame. (struct sframe_xlate_ctx): Likewise. --- diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c index e2c3d1fafd8..073a8374a4f 100644 --- a/gas/gen-sframe.c +++ b/gas/gen-sframe.c @@ -380,19 +380,31 @@ get_fre_base_reg_id (const struct sframe_row_entry *sframe_fre) /* Get number of offsets necessary for the SFrame Frame Row Entry. */ static unsigned int -get_fre_num_offsets (const struct sframe_row_entry *sframe_fre) +get_fre_num_offsets (const struct sframe_row_entry *sframe_fre, + bool flex_topmost_p) { - /* Atleast 1 must always be present (to recover CFA). */ - unsigned int fre_num_offsets = 1; + /* For SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME FDE type, each entity (CFA, FP, RA) + may carry up to two offsets. */ + unsigned int count = flex_topmost_p ? 2 : 1; - if (sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_STACK) - fre_num_offsets++; - if (sframe_ra_tracking_p () - && (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK - /* For s390x account padding RA offset, if FP without RA saved. */ - || (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG - && sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_STACK))) + /* CFA offset (or offsets when flex_topmost_p) must always be present. */ + unsigned int fre_num_offsets = count; + + /* For flexible topmost frames encoding, there will be two offsets for RA + (irrespective of whether RA tracking is enabled or not). */ + if (flex_topmost_p) + fre_num_offsets += count; + else if (sframe_ra_tracking_p () + && (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK + /* For s390x account padding RA offset, if FP without RA + saved. */ + || (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG + && sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_STACK))) fre_num_offsets++; + + if (sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_STACK) + fre_num_offsets += count; + return fre_num_offsets; } @@ -587,39 +599,84 @@ sframe_fde_free (struct sframe_func_entry *sframe_fde) size FRE_OFFSET_SIZE. Write out the offsets in order - CFA, RA, FP. */ static unsigned int -output_sframe_row_entry_offsets (const struct sframe_func_entry *sframe_fde ATTRIBUTE_UNUSED, +output_sframe_row_entry_offsets (const struct sframe_func_entry *sframe_fde, const struct sframe_row_entry *sframe_fre, unsigned int fre_offset_size) - { unsigned int fre_write_offsets = 0; unsigned int idx = sframe_fre_offset_func_map_index (fre_offset_size); gas_assert (idx < SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX); - /* Write out the offsets in order - cfa, fp, ra. */ - fre_offset_func_map[idx].out_func (sframe_fre->cfa_offset); - fre_write_offsets++; - - if (sframe_ra_tracking_p ()) + if (sframe_fde->fde_flex_topmost_p) { - if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK) + /* SFrame FDE of type SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME. */ + /* Output CFA related FRE offsets. */ + uint8_t reg_data + = SFRAME_V3_FLEX_FDE_REG_ENCODE (sframe_fre->cfa_base_reg, + sframe_fre->cfa_deref_p, + 1 /* reg_p. */); + offsetT offset_data = sframe_fre->cfa_offset; + fre_offset_func_map[idx].out_func (reg_data); + fre_offset_func_map[idx].out_func (offset_data); + fre_write_offsets += 2; + + /* Not expected. Flexible Topmost Frame FDEs are not implemented ATM + for ABIs other than SFRAME_ABI_AMD64_ENDIAN_LITTLE. If need arises, + the implementation may be added later as it will be backwards + compatible to add a new FDE type for those ABIs. */ + if (sframe_ra_tracking_p ()) + gas_assert (false); + + /* RA tracking enabled or not, emit two offsets for RA. + Aside, emitting SFRAME_FRE_RA_OFFSET_INVALID is equivalent to emitting + SFRAME_V3_FLEX_FDE_REG_ENCODE (0, 0, 0). + FIXME - This may change later when we implement handling .cfi_register + RA, reg. Emit two 0 offsets for now. */ + fre_offset_func_map[idx].out_func (SFRAME_FRE_RA_OFFSET_INVALID); + /* FIXME Offset 0 for now. */ + fre_offset_func_map[idx].out_func (0); + fre_write_offsets += 2; + + if (sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_STACK) { - fre_offset_func_map[idx].out_func (sframe_fre->ra_offset); - fre_write_offsets++; - } - /* For s390x write padding RA offset, if FP without RA saved. */ - else if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG - && sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_STACK) - { - fre_offset_func_map[idx].out_func (SFRAME_FRE_RA_OFFSET_INVALID); - fre_write_offsets++; + /* Output FP related FRE offsets. */ + reg_data = SFRAME_V3_FLEX_FDE_REG_ENCODE (sframe_fre->fp_reg, + sframe_fre->fp_deref_p, + 1 /* reg_p. */); + offset_data = sframe_fre->fp_offset; + fre_offset_func_map[idx].out_func (reg_data); + fre_offset_func_map[idx].out_func (offset_data); + fre_write_offsets += 2; } } - if (sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_STACK) + else { - fre_offset_func_map[idx].out_func (sframe_fre->fp_offset); + /* SFrame FDE of type SFRAME_FDE_TYPE_PCINC. */ + /* Output CFA related FRE offsets. */ + fre_offset_func_map[idx].out_func (sframe_fre->cfa_offset); fre_write_offsets++; + + if (sframe_ra_tracking_p ()) + { + if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK) + { + fre_offset_func_map[idx].out_func (sframe_fre->ra_offset); + fre_write_offsets++; + } + /* For s390x write padding RA offset, if FP without RA saved. */ + else if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG + && sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_STACK) + { + fre_offset_func_map[idx].out_func (SFRAME_FRE_RA_OFFSET_INVALID); + fre_write_offsets++; + } + } + if (sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_STACK) + { + fre_offset_func_map[idx].out_func (sframe_fre->fp_offset); + fre_write_offsets++; + } } return fre_write_offsets; @@ -676,7 +733,8 @@ output_sframe_row_entry (const struct sframe_func_entry *sframe_fde, else { fre_base_reg = get_fre_base_reg_id (sframe_fre); - fre_num_offsets = get_fre_num_offsets (sframe_fre); + fre_num_offsets = get_fre_num_offsets (sframe_fre, + sframe_fde->fde_flex_topmost_p); fre_offset_size = sframe_get_fre_offset_size (sframe_fre); fre_mangled_ra_p = sframe_fre->mangled_ra_p; } @@ -763,7 +821,19 @@ output_sframe_funcdesc (symbolS *start_of_fre_section, } else out_one (func_info); - out_one (0); + + if (sframe_fde->fde_flex_topmost_p) + { + uint8_t finfo2 = 0; + if (sframe_fde->fde_flex_topmost_p) + { + uint8_t fde_type = SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME; + finfo2 = SFRAME_V3_FUNC_INFO2_SET_FDE_TYPE (finfo2, fde_type); + } + } + else + out_one (0); + out_one (0); } @@ -947,6 +1017,7 @@ static void sframe_xlate_ctx_init (struct sframe_xlate_ctx *xlate_ctx) { xlate_ctx->dw_fde = NULL; + xlate_ctx->flex_topmost_p = false; xlate_ctx->first_fre = NULL; xlate_ctx->last_fre = NULL; xlate_ctx->cur_fre = NULL; @@ -971,6 +1042,7 @@ sframe_xlate_ctx_finalize (struct sframe_xlate_ctx *xlate_ctx, struct sframe_func_entry *sframe_fde) { sframe_fde->dw_fde = xlate_ctx->dw_fde; + sframe_fde->fde_flex_topmost_p = xlate_ctx->flex_topmost_p; sframe_fde->sframe_fres = xlate_ctx->first_fre; sframe_fde->num_fres = xlate_ctx->num_xlate_fres; } @@ -1023,8 +1095,11 @@ sframe_row_entry_initialize (struct sframe_row_entry *cur_fre, gas_assert (prev_fre); cur_fre->cfa_base_reg = prev_fre->cfa_base_reg; cur_fre->cfa_offset = prev_fre->cfa_offset; + cur_fre->cfa_deref_p = prev_fre->cfa_deref_p; cur_fre->fp_loc = prev_fre->fp_loc; + cur_fre->fp_reg = prev_fre->fp_reg; cur_fre->fp_offset = prev_fre->fp_offset; + cur_fre->fp_deref_p = prev_fre->fp_deref_p; cur_fre->ra_loc = prev_fre->ra_loc; cur_fre->ra_offset = prev_fre->ra_offset; /* Treat RA mangling as a sticky bit. It retains its value until another diff --git a/gas/gen-sframe.h b/gas/gen-sframe.h index c4d621b0173..4921e796a10 100644 --- a/gas/gen-sframe.h +++ b/gas/gen-sframe.h @@ -73,12 +73,18 @@ struct sframe_row_entry unsigned int cfa_base_reg; /* Offset from the CFA base register for recovering CFA. */ offsetT cfa_offset; + /* Whether CFA recovery needs dereferencing. This is tracked for + SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME SFrame FDE type. */ + bool cfa_deref_p; /* Track FP location. Specify whether it is in register or memory. */ unsigned int fp_reg; unsigned int fp_loc; /* If the FP is stashed on stack, note the offset. */ offsetT fp_offset; + /* Whether FP recovery needs dereferencing. This is tracked for + SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME SFrame FDE type. */ + bool fp_deref_p; /* Track RA location. Specify whether it is in register or memory. */ unsigned int ra_loc; @@ -97,6 +103,9 @@ struct sframe_func_entry like the start_address and the segment is made available via this member. */ const struct fde_entry *dw_fde; + /* Whether the current FDE will use SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME + representation. */ + bool fde_flex_topmost_p; /* Reference to the first FRE for this function. */ struct sframe_row_entry *sframe_fres; @@ -127,6 +136,10 @@ struct sframe_xlate_ctx /* Remember FRE for an eventual restore. */ struct sframe_row_entry *remember_fre; + /* Whether the current FRE requires a more flexible topmost frame, hence + needing SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME SFrame FDE type. */ + bool flex_topmost_p; + unsigned num_xlate_fres; };