[RFC 19/28] [SFrame-V3] sframe: gas: translate specific CFI directives for SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME

Indu Bhagat indu.bhagat@oracle.com
Tue Dec 16 06:14:53 GMT 2025
On 12/15/25 4:54 AM, Jens Remus wrote:
> On 12/9/2025 10:07 AM, Indu Bhagat wrote:
>> This patch updates the SFrame generation in GAS to translate specific CFI
>> directives into the new SFrame V3 FDE type: SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME.
>>
>> The primary goal is to support code patterns where:
>>    - the Canonical Frame Address (CFA) is not defined by a simple offset
>>      from the Stack Pointer (SP) or Frame Pointer (FP), or where the CFA
>>      rule involves a dereference. Such patterns are generated by compilers
>>      for stack realignment (e.g., DRAP on x86_64, or when mixing legacy
>>      codes that keep 4-byte stack alignment with modern codes that keep
>>      16-byte stack alignment for SSE compatibility).
>>    - the Frame Pointer is not defined by a simple offset from the CFA,
>>      but may even involve another register and/or dereferencing.
>>    - the Return Address is not defined by a simple offset from the CFA,
>>      but may even involve another register and/or dereferencing.
>>
>> Support for non-SP/FP based CFA: Update sframe_xlate_do_def_cfa () and
>> sframe_xlate_do_def_cfa_register () to detect when a non-SP/FP register
>> is used for the CFA.
>>
>> Support for CFA expressions: A vital part of supporting the
>> above-mentioned cases on AMD64 is support for CFA expressions.  Add
>> sframe_xlate_do_escape_cfa_expr () to parse simple
>> DW_CFA_def_cfa_expression sequence in .cfi_escape.
>>
>> Support for FP expressions: Update sframe_xlate_do_escape_expr () to
>> handle DW_CFA_expression involving `DW_OP_breg6` (rbp) on AMD64,
>> allowing for tracking of the Frame Pointer when it is saved with a
>> dereference rule in the DRAP pattern.
>>
>> The "support" for both CFA expressions and FP expressions is quite
>> minimal, and is tailored to the most commonly seen occurences generated
> 
> Nit: occurrences
> 

OK

>> by GCC.
>>
>> Add a helper sframe_fre_reg_encodable_p () to verify if a DWARF register
>> number can be encoded in the limited bits (5 bits) available in the
>> SFrame format.
>>
>> This functionality is currently implemented only for the
>> SFRAME_ABI_AMD64_ENDIAN_LITTLE ABI.  Support for other ABIs may be added
>> without format version bump, as the necessary specification changes will
>> already be in place.
> 
> Why did you limit it to AMD64?
> 

Only for design and coding related ease.  I also needed some reviews of 
the overall direction etc..  We can enable flexible frames for s390x too.

>> diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
> 
>> @@ -1189,30 +1204,46 @@ sframe_xlate_do_def_cfa (struct sframe_xlate_ctx *xlate_ctx,
>>       sframe_fre_set_begin_addr (cur_fre,
>>   			       get_dw_fde_start_addrS (xlate_ctx->dw_fde));
>>     }
>> -  /* Define the current CFA rule to use the provided register and
>> -     offset.  However, if the register is not FP/SP, skip creating
>> -     SFrame stack trace info for the function.  */
>> -  if (cfi_insn->u.ri.reg != SFRAME_CFA_SP_REG
>> -      && cfi_insn->u.ri.reg != SFRAME_CFA_FP_REG)
>> -    {
>> -      as_warn (_("no SFrame FDE emitted; "
>> -		 "non-SP/FP register %u in .cfi_def_cfa"),
>> -	       cfi_insn->u.ri.reg);
>> -      return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
>> -    }
>> -  else if (sframe_fre_stack_offset_bound_p (cfi_insn->u.ri.offset, true))
>> -    {
>> -      sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
>> -      sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.ri.offset);
>> -      cur_fre->merge_candidate = false;
>> -    }
>> -  else
>> +
>> +  offsetT offset = cfi_insn->u.ri.offset;
>> +  bool bound_p = sframe_fre_stack_offset_bound_p (offset, true);
>> +  if (!bound_p)
>>       {
>>         as_warn (_("no SFrame FDE emitted; "
>>   		 ".cfi_def_cfa with unsupported offset value"));
>>         return SFRAME_XLATE_ERR_NOTREPRESENTED;
>>       }
>>   
>> +  /* Define the current CFA rule to use the provided register and
>> +     offset.  Typically, the CFA rule uses SP/FP based CFA.  However, with
>> +     SFrame V3 specification, if the CFA register is not FP/SP, SFrame FDE type
>> +     SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME type may be used.
>> +
>> +     ATM however, GAS implements non-SP/FP based CFA only for AMD64, where such
>> +     a CFA pattern may be seen (e.g., DRAP, stack alignment).  On s390x, this
>> +     may be seen for (GCC) generated code for static stack clash protection.
>> +     This remains sufficiently rare and is currently unimplemented for s390x.
>> +     */
>> +  if (cfi_insn->u.ri.reg != SFRAME_CFA_SP_REG
>> +      && cfi_insn->u.ri.reg != SFRAME_CFA_FP_REG)
>> +    {
>> +      if (sframe_get_abi_arch () != SFRAME_ABI_AMD64_ENDIAN_LITTLE
>> +	  || !sframe_fre_reg_encodable_p (cfi_insn->u.ri.reg))
> 
> Maybe use an architecture-configurable knob instead?  For example:
> 
> /* Whether to support SFrame FLEX_TOPMOST_FRAME.  */
> extern bool x86_sframe_flex_topmost_frame_p (void);
> #define sframe_flex_topmost_frame_p x86_sframe_flex_topmost_frame_p
> 
> And then change above as follows:
> 
> if (!sframe_flex_topmost_frame_p () || !sframe_fre_reg_encodable_p (cfi_insn->u.ri.reg))
> 
> 

Yeah, there is some clutter because of those (sframe_get_abi_arch () != 
SFRAME_ABI_AMD64_ENDIAN_LITTLE) checks.  Perhaps 
sframe_flex_topmost_frame_p () will help there too.

>> +	{
>> +	  as_warn (_("no SFrame FDE emitted; "
>> +		     "non-SP/FP register %u in .cfi_def_cfa"),
>> +		   cfi_insn->u.ri.reg);
>> +	  return SFRAME_XLATE_ERR_NOTREPRESENTED;
>> +	}
>> +      else
>> +	xlate_ctx->flex_topmost_p = true;
>> +    }
>> +
>> +  sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
>> +  sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.ri.offset);
>> +  cur_fre->merge_candidate = false;
>> +  cur_fre->cfa_deref_p = false;
>> +
>>     return SFRAME_XLATE_OK;
>>   }
>>   
>> @@ -1234,14 +1265,23 @@ sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx *xlate_ctx,
>>     if (cfi_insn->u.r != SFRAME_CFA_SP_REG
>>         && cfi_insn->u.r != SFRAME_CFA_FP_REG)
>>       {
>> -      as_warn (_("no SFrame FDE emitted; "
>> -		 "non-SP/FP register %u in .cfi_def_cfa_register"),
>> -	       cfi_insn->u.r);
>> -      return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
>> +      if (sframe_get_abi_arch () != SFRAME_ABI_AMD64_ENDIAN_LITTLE)
> 
> Likewise:
> 
> if (!sframe_flex_topmost_frame_p ())
> 

OK.

>> +	{
>> +	  as_warn (_("no SFrame FDE emitted; "
>> +		     "non-SP/FP register %u in .cfi_def_cfa_register"),
>> +		   cfi_insn->u.ri.reg);
>> +	  return SFRAME_XLATE_ERR_NOTREPRESENTED;
>> +	}
>> +      else
>> +	/* Currently, SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME is generated for AMD64
>> +	   only.  */
>> +	xlate_ctx->flex_topmost_p = true;
>>       }
>> +
>>     sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.r);
>>     if (last_fre)
>>       sframe_fre_set_cfa_offset (cur_fre, sframe_fre_get_cfa_offset (last_fre));
>> +  cur_fre->cfa_deref_p = false;
>>   
>>     cur_fre->merge_candidate = false;
>>   
>> @@ -1574,6 +1614,98 @@ sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
>>     return SFRAME_XLATE_ERR_NOTREPRESENTED;  /* Not represented.  */
>>   }
> Thanks and regards,
> Jens



More information about the Binutils mailing list