[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