[V2 26/36] [SFrame-V3] gas: sframe: testsuite: handle .cfi_offset for RA

Jens Remus jremus@linux.ibm.com
Wed Jan 7 15:20:30 GMT 2026


On 1/7/2026 9:42 AM, Indu Bhagat wrote:
> With the introduction of flex FDE type, handling .cfi_offset for
> RA needs adjustment.
> 
> On architectures like x86_64, the return address (RA) is typically saved
> at a fixed offset from the CFA. Previous versions of the SFrame format
> assumed this fixed offset was invariant for the entire function on such
> architectures. Consequently, GAS would warn and suppress SFrame
> generation if it encountered a .cfi_offset directive for the RA
> register that deviated from this fixed default.
> 
> SFrame V3 introduces "Flex FDEs" which allows tracking the RA location
> explicitly even on architectures where it is usually fixed.
> 
> This patch updates sframe_xlate_do_offset () to leverage Flex FDEs. When
> processing a .cfi_offset for the RA register:
>   - The check for non-representable RA offsets is relaxed. If the ABI
>     supports Flex FDEs (SFrame V3), GAS proceeds instead of issuing a
>     warning.
>   - For ABIs without explicit RA tracking (like AMD64), if the RA
>     offset differs from the default fixed offset, the FDE is marked as a
>     Flex FDE, and the new stack location is recorded.
>   - Logic is added to detect when the RA is restored to its standard
>     fixed offset. In this case, the tracking state is reset (ra_loc set
>     to SFRAME_FRE_ELEM_LOC_NONE), deferring to the ABI's default fixed RA
>     offset behavior.
> 
> gas/
> 	* gen-sframe.c (sframe_xlate_do_offset): Support .cfi_offset for RA
> 	by switching to Flex FDEs when necessary.
> gas/testsuite/
> 	* gas/cfi-sframe/cfi-sframe-x86_64-6.d: New test.
> 	* gas/cfi-sframe/cfi-sframe-x86_64-6.s: New test to check
> 	transition of location of REG_RA from register to CFA-8 (default
> 	location on AMD64).  Flex FDE in effect.
> 	* gas/cfi-sframe/cfi-sframe.exp: Add new test.

Reviewed-by: Jens Remus <jremus@linux.ibm.com>

> diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c

> @@ -1390,8 +1390,10 @@ sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx,
>  
>    /* For ABIs not tracking RA, the return address is expected to be in a
>       specific location.  Explicit manourvering to a different offset (than the
> -     default offset) is non-representable in SFrame.  */
> -  if (!sframe_ra_tracking_p () && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG
> +     default offset) is non-representable in SFrame, unless flex FDE generation
> +     is supported for the ABI.  */
> +  if (!sframe_support_flex_fde_p () && !sframe_ra_tracking_p ()
> +      && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG
>        && cfi_insn->u.ri.offset != sframe_cfa_ra_offset ())
>      {
>        as_warn (_("no SFrame FDE emitted; %s register %u in .cfi_offset"),
> @@ -1409,13 +1411,42 @@ sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx,
>        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)
> +  /* Either the ABI has enabled RA tracking, in which case we must process the
> +     DW_CFA_offset opcode for REG_RA like usual.  Or if the ABI has not enabled
> +     RA tracking, but flex FDE generation is supported, dintinguish between

Nit: s/dintinguish/distinguish/

> +     whether its time to reset the ra tracking state or not.  */

Nit: s/ra/RA/

> +  else if (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;
> +      if (!sframe_ra_tracking_p ())
> +	{
> +	  /* RA is restored to its standard fixed offset.  */

Maybe: s/RA/RA tracking info/

The comment is kind of confusing as what it states is not performed
unconditionally.  Maybe change as follows:

	  /* Reset RA tracking info, if fixed offset.  */

> +	  if (cfi_insn->u.ri.offset == sframe_cfa_ra_offset ())
> +	    {
> +	      cur_fre->ra_reg = SFRAME_FRE_REG_INVALID;
> +	      cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_NONE;
> +	      cur_fre->ra_deref_p = false;
> +	      cur_fre->merge_candidate = false;
> +	    }
> +	  /* If flex FDE is supported, update the ra tracking info.  */

Nit: s/ra/RA/

> +	  else if (sframe_support_flex_fde_p ())
> +	    {
> +	      sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
> +	      cur_fre->ra_reg = SFRAME_FRE_REG_INVALID;
> +	      cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_STACK;
> +	      cur_fre->ra_deref_p = true;
> +	      cur_fre->merge_candidate = false;
> +
> +	      xlate_ctx->flex_p = true;
> +	    }
> +	}
> +      else if (sframe_ra_tracking_p ())

Can't this be simplified to:

      else
or
      else /* sframe_ra_tracking_p ()  */

If the sframe_ra_tracking_p () case is handled first then the else
would be close to the if condition:

      if (!sframe_ra_tracking_p ())
	{
	  sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
	  cur_fre->ra_reg = SFRAME_FRE_REG_INVALID;
	  cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_STACK;
	  cur_fre->ra_deref_p = true;
	  cur_fre->merge_candidate = false;
	}
      else
	{
...
	}

> +	{
> +	  sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
> +	  cur_fre->ra_reg = SFRAME_FRE_REG_INVALID;
> +	  cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_STACK;

If I am not mistaken this was not part of the old implementation.  Why
is that required?

> +	  cur_fre->ra_deref_p = true;
> +	  cur_fre->merge_candidate = false;
> +	}
>      }
>    /* This is used to track changes to non-rsp registers, skip all others

Unrelated to this patch: What are non-rsp registers?

>       except FP / RA for now.  */
Maybe the SFRAME_CFA_RA_REG case can be simplified as follows:

  else if (cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG)
    {
      if (!sframe_ra_tracking_p ()
          && cfi_insn->u.ri.offset == sframe_cfa_ra_offset ())
        {
          /* Reset RA tracking info to fixed offset.  */
          cur_fre->ra_reg = SFRAME_FRE_REG_INVALID;
          cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_NONE;
          cur_fre->ra_deref_p = false;
          cur_fre->merge_candidate = false;
        }
      else
        {
          sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
          cur_fre->ra_reg = SFRAME_FRE_REG_INVALID;
          cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_STACK;
          cur_fre->ra_deref_p = true;
          cur_fre->merge_candidate = false;

          if (!sframe_ra_tracking_p () && sframe_support_flex_fde_p ())
            xlate_ctx->flex_p = true;
        }
    }

The following common statements could be moved from the inner to the
outer clause.  I left them duplicated as I found that more readable.

  cur_fre->ra_reg = SFRAME_FRE_REG_INVALID;
  cur_fre->merge_candidate = false;

Regards,
Jens
-- 
Jens Remus
Linux on Z Development (D3303)
jremus@de.ibm.com / jremus@linux.ibm.com

IBM Deutschland Research & Development GmbH; Vorsitzender des Aufsichtsrats: Wolfgang Wendt; Geschäftsführung: David Faller; Sitz der Gesellschaft: Ehningen; Registergericht: Amtsgericht Stuttgart, HRB 243294
IBM Data Privacy Statement: https://www.ibm.com/privacy/



More information about the Binutils mailing list