From: Indu Bhagat Date: Fri, 16 Jan 2026 00:42:32 +0000 (-0800) Subject: [SFrame-V3] gas: sframe: output new FDE type SFRAME_FDE_TYPE_FLEX X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d75441d503f620575913a25d7c428ee19491144f;p=thirdparty%2Fbinutils-gdb.git [SFrame-V3] gas: sframe: output new FDE type SFRAME_FDE_TYPE_FLEX This patch updates the routines for emission of the new FDE type SFRAME_FDE_TYPE_FLEX in the SFrame output section. The support for generating these flex FDEs themselves is added in a subsequent commit. Update struct sframe_row_entry to track additional state for CFA, FP, and RA. Modify output_sframe_row_entry_offsets () to emit metadata/offset pairs for flexible FDEs or padding where applicable, ensuring the usual ordering (CFA, RA, FP). The padding data, a.k.a. SFRAME_FRE_RA_OFFSET_INVALID is emitted in flexible FDEs when RA is untracked but FP offsets follow. Trailing padding offsets should not occur. Add a new function get_udata_size_in_bytes () to account for sizing of unsigned register metadata. gas/ * gen-sframe.c (get_udata_size_in_bytes): Get size of unsigned int data in bytes. (get_fre_num_offsets): Handle SFRAME_FDE_TYPE_FLEX. (sframe_get_fre_offset_size): Account for register metadata in flexible FDEs. (output_sframe_row_entry_offsets): Add logic for flexible FDE offset pairs. (output_sframe_row_entry): Reset base register for flex FDEs. (output_sframe_funcdesc): Emit FDE type in func_info2. (sframe_xlate_ctx_init): Initialize flex_p. (sframe_xlate_ctx_finalize): Finalize flex_p status. (sframe_row_entry_initialize): Copy new deref tracking bits. (sframe_xlate_do_offset): Set deref bits during translation. * gen-sframe.h (struct sframe_row_entry): Add cfa_deref_p, fp_deref_p, and ra_deref_p. (struct sframe_func_entry): Add fde_flex_p. (struct sframe_xlate_ctx): Add flex_p. --- diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c index 58028ef7a38..8da9de33ad9 100644 --- a/gas/gen-sframe.c +++ b/gas/gen-sframe.c @@ -223,6 +223,22 @@ get_offset_size_in_bytes (offsetT value) return size; } +/* Given an unsigned item, return the size in bytes needed to represent it. */ + +static unsigned int +get_udata_size_in_bytes (unsigned int value) +{ + unsigned int size = 0; + + if (value <= UINT8_MAX) + size = 1; + else if (value <= UINT16_MAX) + size = 2; + else + size = 4; + + return size; +} #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B 0 /* SFRAME_FRE_OFFSET_1B. */ #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B 1 /* SFRAME_FRE_OFFSET_2B. */ #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B 2 /* SFRAME_FRE_OFFSET_4B. */ @@ -370,19 +386,36 @@ 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_p) { - /* Atleast 1 must always be present (to recover CFA). */ - unsigned int fre_num_offsets = 1; + /* For SFRAME_FDE_TYPE_FLEX FDE type, each entity (CFA, FP, RA) may carry up + to two offsets. */ + unsigned int count = flex_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_p) must always be present. */ + unsigned int fre_num_offsets = count; + + /* For flexible frames encoding, there will be two offsets for RA (if RA is + being tracked). 1 padding offset otherwise. */ + if (flex_p) + { + if (sframe_fre->ra_loc != SFRAME_FRE_ELEM_LOC_NONE) + fre_num_offsets += count; + else if (sframe_fre->fp_loc != SFRAME_FRE_ELEM_LOC_NONE) + fre_num_offsets += 1; + } + else if (sframe_ra_tracking_p () + && (sframe_fre->ra_loc != SFRAME_FRE_ELEM_LOC_NONE + /* 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_NONE))) fre_num_offsets++; + + if (sframe_fre->fp_loc != SFRAME_FRE_ELEM_LOC_NONE) + fre_num_offsets += count; + return fre_num_offsets; } @@ -390,7 +423,8 @@ get_fre_num_offsets (const struct sframe_row_entry *sframe_fre) SFrame frame row entry. */ static unsigned int -sframe_get_fre_offset_size (const struct sframe_row_entry *sframe_fre) +sframe_get_fre_offset_size (const struct sframe_row_entry *sframe_fre, + bool flex_p) { unsigned int max_offset_size = 0; unsigned int cfa_offset_size = 0; @@ -420,6 +454,38 @@ sframe_get_fre_offset_size (const struct sframe_row_entry *sframe_fre) if (ra_offset_size > max_offset_size) max_offset_size = ra_offset_size; + /* If flex FDE, account for reg data too. */ + if (flex_p) + { + bool reg_p = (sframe_fre->cfa_base_reg != SFRAME_FRE_REG_INVALID); + unsigned int data + = SFRAME_V3_FLEX_FDE_REG_ENCODE (sframe_fre->cfa_base_reg, + sframe_fre->cfa_deref_p, reg_p); + unsigned int data_size = get_udata_size_in_bytes (data); + if (data_size > max_offset_size) + max_offset_size = data_size; + + if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_REG) + { + data = SFRAME_V3_FLEX_FDE_REG_ENCODE (sframe_fre->ra_reg, + sframe_fre->ra_deref_p, + 1 /* reg_p. */); + data_size = get_udata_size_in_bytes (data); + if (data_size > max_offset_size) + max_offset_size = data_size; + } + + if (sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_REG) + { + data = SFRAME_V3_FLEX_FDE_REG_ENCODE (sframe_fre->fp_reg, + sframe_fre->fp_deref_p, + 1 /* reg_p. */); + data_size = get_udata_size_in_bytes (data); + if (data_size > max_offset_size) + max_offset_size = data_size; + } + } + gas_assert (max_offset_size); switch (max_offset_size) @@ -529,6 +595,7 @@ sframe_row_entry_new (void) valid register for a supported arch. */ fre->cfa_base_reg = SFRAME_FRE_REG_INVALID; fre->fp_reg = SFRAME_FRE_REG_INVALID; + fre->ra_reg = SFRAME_FRE_REG_INVALID; fre->merge_candidate = true; /* Reset the mangled RA status bit to zero by default. We will initialize it in sframe_row_entry_initialize () with the sticky @@ -578,39 +645,93 @@ 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_p) { - if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK) + /* SFrame FDE of type SFRAME_FDE_TYPE_FLEX. */ + /* Output CFA related FRE offsets. */ + uint32_t reg = sframe_fre->cfa_base_reg; + uint32_t reg_data + = SFRAME_V3_FLEX_FDE_REG_ENCODE (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; + + bool reg_p = false; + if (sframe_fre->ra_loc != SFRAME_FRE_ELEM_LOC_NONE) { - fre_offset_func_map[idx].out_func (sframe_fre->ra_offset); - fre_write_offsets++; + /* Output RA related FRE offsets. */ + reg_p = sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_REG; + reg = reg_p ? sframe_fre->ra_reg : 0; + reg_data = SFRAME_V3_FLEX_FDE_REG_ENCODE (reg, + sframe_fre->ra_deref_p, + reg_p); + offset_data = sframe_fre->ra_offset; + fre_offset_func_map[idx].out_func (reg_data); + fre_offset_func_map[idx].out_func (offset_data); + fre_write_offsets += 2; } - /* 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) + else if (sframe_fre->fp_loc != SFRAME_FRE_ELEM_LOC_NONE) { + /* If RA is not in REG/STACK, emit RA padding if there are more + offsets to follow. Note that, emitting + SFRAME_FRE_RA_OFFSET_INVALID is equivalent to emitting + SFRAME_V3_FLEX_FDE_REG_ENCODE (0, 0, 0). */ fre_offset_func_map[idx].out_func (SFRAME_FRE_RA_OFFSET_INVALID); - fre_write_offsets++; + fre_write_offsets += 1; + } + + if (sframe_fre->fp_loc != SFRAME_FRE_ELEM_LOC_NONE) + { + /* Output FP related FRE offsets. */ + reg_p = sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_REG; + reg = reg_p ? sframe_fre->fp_reg : 0; + reg_data = SFRAME_V3_FLEX_FDE_REG_ENCODE (reg, + sframe_fre->fp_deref_p, + 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_DEFAULT. */ + /* 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; @@ -667,10 +788,17 @@ 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_offset_size = sframe_get_fre_offset_size (sframe_fre); + fre_num_offsets = get_fre_num_offsets (sframe_fre, + sframe_fde->fde_flex_p); + fre_offset_size = sframe_get_fre_offset_size (sframe_fre, + sframe_fde->fde_flex_p); fre_mangled_ra_p = sframe_fre->mangled_ra_p; } + + /* Unused for flex FDE. Set to zero. */ + if (sframe_fde->fde_flex_p) + fre_base_reg = 0; + fre_info = sframe_set_fre_info (fre_base_reg, fre_num_offsets, fre_offset_size, fre_mangled_ra_p); out_one (fre_info); @@ -754,7 +882,12 @@ output_sframe_funcdesc (symbolS *start_of_fre_section, } else out_one (func_info); - out_one (0); + + uint8_t finfo2 = 0; + if (sframe_fde->fde_flex_p) + finfo2 = SFRAME_V3_SET_FDE_TYPE (finfo2, SFRAME_FDE_TYPE_FLEX); + out_one (finfo2); + out_one (0); } @@ -938,6 +1071,7 @@ static void sframe_xlate_ctx_init (struct sframe_xlate_ctx *xlate_ctx) { xlate_ctx->dw_fde = NULL; + xlate_ctx->flex_p = false; xlate_ctx->first_fre = NULL; xlate_ctx->last_fre = NULL; xlate_ctx->cur_fre = NULL; @@ -964,6 +1098,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_p = xlate_ctx->flex_p; sframe_fde->sframe_fres = xlate_ctx->first_fre; sframe_fde->num_fres = xlate_ctx->num_xlate_fres; /* remember_fre is cloned copy of the applicable fre (where necessary). @@ -1020,10 +1155,13 @@ 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_reg = prev_fre->ra_reg; cur_fre->ra_offset = prev_fre->ra_offset; /* Treat RA mangling as a sticky bit. It retains its value until another .cfi_negate_ra_state is seen. */ @@ -1245,12 +1383,15 @@ sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx, { sframe_fre_set_fp_track (cur_fre, cfi_insn->u.ri.offset); cur_fre->fp_reg = SFRAME_FRE_REG_INVALID; + cur_fre->fp_deref_p = true; cur_fre->merge_candidate = false; } else if (sframe_ra_tracking_p () && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG) { sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset); + cur_fre->ra_reg = SFRAME_FRE_REG_INVALID; + cur_fre->ra_deref_p = true; cur_fre->merge_candidate = false; } /* This is used to track changes to non-rsp registers, skip all others diff --git a/gas/gen-sframe.h b/gas/gen-sframe.h index fe7f3961fc9..1a1f887d508 100644 --- a/gas/gen-sframe.h +++ b/gas/gen-sframe.h @@ -79,17 +79,27 @@ 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 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; + unsigned int fp_reg; /* 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 FDE type. */ + bool fp_deref_p; /* Track RA location. Specify whether it is in register or memory. */ unsigned int ra_loc; + unsigned int ra_reg; /* If RA is stashed on stack, note the offset. */ offsetT ra_offset; + /* Whether RA recovery needs dereferencing. This is tracked for FDE type + SFRAME_FDE_TYPE_FLEX. */ + bool ra_deref_p; }; /* SFrame Function Description Entry. */ @@ -103,6 +113,8 @@ 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 representation. */ + bool fde_flex_p; /* Reference to the first FRE for this function. */ struct sframe_row_entry *sframe_fres; @@ -133,6 +145,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 frame encoding, hence + needing SFRAME_FDE_TYPE_FLEX FDE type. */ + bool flex_p; + unsigned num_xlate_fres; };