[V2 18/36] [SFrame-V3] gas: sframe: output new FDE type SFRAME_FDE_TYPE_FLEX
Indu Bhagat
indu.bhagat@oracle.com
Sat Jan 10 19:02:15 GMT 2026
On 1/10/26 11:00 AM, Indu Bhagat wrote:
> On 1/7/26 12:42 AM, Indu Bhagat wrote:
>> 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.
>>
>> For flex 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
>> flex FDE type, 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.
>>
>> TBD - gas/gen-sframe.c code can be improved ?
>>
>> gas/
>> * gen-sframe.c (get_udata_size_in_bytes): Get size of unsigned
>> int data in bytes.
>> (get_fre_num_offsets): Get number of offsets for
>> SFRAME_FDE_TYPE_FLEX 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 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_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 FDE type.
>> (struct sframe_xlate_ctx): Likewise.
>>
>> ---
>> [Changes in V1]
>> - Rename the FDE type to SFRAME_FDE_TYPE_FLEX. [Jens]
>> - Fix generation of RA offsets for flex FDE. In RFC, we were emitting
>> two offsets for flex FDE, irrespctive of whether RA tracking location
>> was REG/STACK or NONE. This is now changed to: emit RA padding
>> offset
>> - Bring proper implementation in now and remove FIXME in
>> output_sframe_row_entry_offsets [Jens].
>> - gas: sframe: must reset and init ra_reg appropriately.
>> - Allow reg to be any sized in the offset. In RFC, there was a limit
>> of 5-bits. Now its lifted. The calculation of the `size of offset`
>> is adjusted to account for the minimum necessary size, just like the
>> other offsets.
>> [End of changes in V1]
>>
>> [Changes in V2]
>> - Bring stub resetting ra_reg, ra_deref_p, fp_deref_p to the rightful
>> place (from previous commit) [Indu].
>> - Remove stale comments from output_sframe_row_entry_offsets () that
>> two offsets are emitted for RA irrespective of whether its tracked
>> or not [Indu].
>> - Other minor touch ups.
>> [End of changes in V2]
>> ---
>> gas/gen-sframe.c | 188 +++++++++++++++++++++++++++++++++++++++--------
>> gas/gen-sframe.h | 18 ++++-
>> 2 files changed, 175 insertions(+), 31 deletions(-)
>>
>> diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
>> index a21756c82b9..6a05492c939 100644
>> --- a/gas/gen-sframe.c
>> +++ b/gas/gen-sframe.c
>> @@ -233,6 +233,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 <= VALUE_8BIT + 1)
>> + size = 1;
>> + else if (value <= VALUE_16BIT + 1)
>> + 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. */
>> @@ -380,19 +396,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;
>> }
>> @@ -400,7 +433,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;
>> @@ -430,6 +464,32 @@ 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;
>> +
>> + reg_p = (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, reg_p);
>> + data_size = get_udata_size_in_bytes (data);
>> + if (data_size > max_offset_size)
>> + max_offset_size = data_size;
>> +
>
> The above 5 lines accounting for size of FP data need to be guarded with:
>
> if (sframe_fre->fp_loc != SFRAME_FRE_ELEM_LOC_REG)
>
I mean "if (sframe_fre->fp_loc != SFRAME_FRE_ELEM_LOC_NONE)
> Similarly for ra below.
>
>> + reg_p = (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, 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)
>> @@ -539,6 +599,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
>> @@ -588,39 +649,91 @@ 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_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;
>> +
>> + 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_data = SFRAME_V3_FLEX_FDE_REG_ENCODE (sframe_fre->ra_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_data = SFRAME_V3_FLEX_FDE_REG_ENCODE (sframe_fre->fp_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;
>> @@ -677,8 +790,10 @@ 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;
>> }
>> fre_info = sframe_set_fre_info (fre_base_reg, fre_num_offsets,
>> @@ -764,7 +879,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);
>> }
>> @@ -948,6 +1068,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;
>> @@ -974,6 +1095,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).
>> @@ -1030,10 +1152,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. */
>> @@ -1255,12 +1380,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;
>> };
>
More information about the Binutils
mailing list