[PATCH v4 08/11] s390: Store SFrame CFA offset adjusted

Jens Remus jremus@linux.ibm.com
Thu Jul 10 12:07:53 GMT 2025


Hello Indu,

one final (tm) question for change (see also below), before I commit the
series to mainline for 2.45 (provided Nick confirms that your and
Andreas' approval is sufficient):

Ok to remove the infix "FRE" from
SFRAME_V2_FRE_S390X_CFA_OFFSET_{ENCODE|DECODE}?

On 07.07.2025 18:21, Jens Remus wrote:
> In SFrame V2 the size of the offsets following an SFrame FRE can be
> either signed 8-bit, 16-bit, or 32-bit integer, with the largest offset
> determining their size:
>   1. CFA offset from CFA base register
>   2. RA (stack save slot) offset from CFA, usually -48 on s390x if saved
>   3. FP (stack save slot) offset from CFA, usually -72 on s390x if saved
> The FP and RA offsets from CFA, when FP/RA saved on the stack, usually
> have fixed values that fit into signed 8-bit SFrame offsets.  Likewise
> the DWARF register numbers on s390x of general registers (GR; 0-15) and
> floating-point registers (FPR; 16-31), when FP/RA saved in registers.
> With that the CFA offset from CFA base register has the greatest impact
> on the signed SFrame offset size.
> 
> The s390x ELF ABI [1] defines the CFA as stack pointer (SP) at call
> site +160. [2]  Therefore the minimum CFA offset from CFA base register
> on s390x is 160.  This does not fit into a signed 8-bit integer and
> therefore effectively prevents any use of signed 8-bit SFrame offsets
> on s390x.
> 
> For s390x store the CFA offset from CFA base register adjusted by -160
> to enable the use of signed 8-bit SFrame offsets.
> 
> [1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases
> [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"),
>      https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88
> 
> include/
> 	* sframe.h (SFRAME_S390X_CFA_OFFSET_ADJUSTMENT): Define
> 	s390x-specific CFA offset adjustment.
> 	(SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE,
> 	SFRAME_V2_FRE_S390X_CFA_OFFSET_DECODE): New s390x-specific
> 	macros.  Use SFRAME_S390X_CFA_OFFSET_ADJUSTMENT to en-/decode
> 	CFA offset.
> 
> bfd/
> 	* elf64-s390.c (elf_s390x_sframe_plt_fre): Use
> 	SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE on CFA offset to store it
> 	adjusted and switch to 8-bit offsets.
> 
> gas/
> 	* gen-sframe.c (sframe_fre_set_cfa_offset): For s390x use
> 	SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE on CFA offset to store it
> 	adjusted.
> 	(__sframe_fre_get_cfa_offset): New helper.  For s390x use
> 	SFRAME_V2_FRE_S390X_CFA_OFFSET_DECODE on CFA offset to undo its
> 	adjustment.
> 	(sframe_xlate_do_def_cfa_register): Use new helper
> 	__sframe_fre_get_cfa_offset.
> 
> libsframe/
> 	* sframe.c (sframe_fre_get_cfa_offset): For s390x use
> 	SFRAME_V2_FRE_S390X_CFA_OFFSET_DECODE on CFA offset to undo its
> 	adjustment.
> 	* doc/sframe-spec.texi (s390x,
> 	SFRAME_S390X_CFA_OFFSET_ADJUSTMENT,
> 	SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE,
> 	SFRAME_V2_FRE_S390X_CFA_OFFSET_DECODE): Document s390x-specific
> 	adjustment of CFA offset.
> 
> libsframe/testsuite/
> 	* libsframe.find/plt-findfre-2.c (add_plt0_fde, add_pltn_fde):
> 	Use SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE to enable use of
> 	1-byte SFrame offsets.
> 
> Suggested-by: Indu Bhagat <indu.bhagat@oracle.com>
> Signed-off-by: Jens Remus <jremus@linux.ibm.com>
> ---
> 
> Notes (jremus):
>     Changes in V4:
>     - Prefix internal helper sframe_fre_get_cfa_offset with "__" to resolve
>       clash with external SFrame API function.  Issue surfaced, due to
>       recent fix of relocatable SFrame links including "sframe-api.h".

Thanks to your latest path I will undo this ugly workaround.

>     - Indent list of s390x-specific changes in SFrame spec.
>     - Fix typo in commit message ("with"). (Indu)
>     - Use comma after "i.e." in SFrame spec. (Indu)
>     - Use "revert" instead of "unapply" in SFrame spec. (Indu)
>     
>     Changes in V3:
>     - Update "Changes from Version 1 to Version 2" in SFrame spec. (Indu)
>     - Regenerate statistics in patch notes below.  Differences to V2 due
>       to change in min/max N-bit offset accounting (was unusual in V1/V2)
>       and use in newer GCC.
>     
>     Changes in V2:
>     - Reword commit message (s390 to s390x, offsets, FDE to FRE). (Indu)
>     - Rename s390x-specific macros from *_S390_* to *_S390X_*. (Indu)
>     - Use "s390x" instead of "S390" in comments and SFrame spec. (Indu)
>     - Change order of CFA restore instructions in SFrame spec. (Indu)
>     - Update new libsframe test plt-findfre-2.
>     
>     A test build of Glibc tag 2.41 on s390x libc.so shows a ~8.8% reduction in
>     .sframe section size due to storing the SFrame CFA offsets adjusted by
>     -160.
>     
>     Statistics for libc.so - base (no CFA offset adjustment):
>     
>       .sframe size: 169,697 bytes
>     
>       VALUE        TOTAL      MIN        MAX        AVG
>       FDEs:        3651       -          -          -
>       FREs/FDE:    15237      1          20         4
>       Offsets/FDE: 29795      1          38         8
>          8-bit:    0          0          0          0
>         16-bit:    29795      1          38         8
>         32-bit:    0          0          0          0
>       Offsets/FRE: 29795      1          3          1
>          8-bit:    -          0          0          0
>         16-bit:    -          1          3          1
>         32-bit:    -          0          0          0
>       O_Padd/FDE:  345        -          -          0
>          8-bit:    0
>         16-bit:    345
>         32-bit:    0
>     
>     Statistics for libc.so - CFA offset adjustment:
>     
>       .sframe size: 154,698 bytes
>     
>       VALUE        TOTAL      MIN        MAX        AVG
>       FDEs:        3651       -          -          -
>       FREs/FDE:    15237      1          20         4
>       Offsets/FDE: 29795      1          38         8
>          8-bit:    14999      1          38         4
>         16-bit:    14796      0          21         4
>         32-bit:    0          0          0          0
>       Offsets/FRE: 29795      1          3          1
>          8-bit:    -          1          3          0
>         16-bit:    -          1          3          0
>         32-bit:    -          0          0          0
>       O_Padd/FDE:  345        -          -          0
>          8-bit:    286
>         16-bit:    59
>         32-bit:    0
> 
>  bfd/elf64-s390.c                               |  4 ++--
>  gas/gen-sframe.c                               | 18 +++++++++++++++++-
>  include/sframe.h                               |  8 ++++++++
>  libsframe/doc/sframe-spec.texi                 | 16 +++++++++++++++-
>  libsframe/sframe.c                             | 10 ++++++++--
>  .../testsuite/libsframe.find/plt-findfre-2.c   |  8 ++++----
>  6 files changed, 54 insertions(+), 10 deletions(-)
> 
> diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c
> index 491070da803b..eb850e932c9e 100644
> --- a/bfd/elf64-s390.c
> +++ b/bfd/elf64-s390.c
> @@ -621,8 +621,8 @@ struct elf_s390x_sframe_plt
>  static const sframe_frame_row_entry elf_s390x_sframe_plt_fre =
>  {
>    0, /* SFrame FRE start address.  */
> -  {0, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 12 bytes.  */
> -  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_2B) /* FRE info.  */
> +  { SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE (160), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* Offset bytes.  */
> +  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B) /* FRE info.  */
>  };
>  
>  /* SFrame helper object for PLT.  */
> diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
> index ab1dfcb49dd1..034dd2680b67 100644
> --- a/gas/gen-sframe.c
> +++ b/gas/gen-sframe.c
> @@ -135,10 +135,26 @@ sframe_fre_set_cfa_base_reg (struct sframe_row_entry *fre,
>    fre->merge_candidate = false;
>  }
>  
> +static offsetT
> +__sframe_fre_get_cfa_offset (const struct sframe_row_entry * fre)
> +{
> +  offsetT offset = fre->cfa_offset;
> +
> +  /* For s390x undo adjustment of CFA offset (to enable 8-bit offsets).  */
> +  if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG)
> +    offset = SFRAME_V2_FRE_S390X_CFA_OFFSET_DECODE (offset);
> +
> +  return offset;
> +}
> +
>  static void
>  sframe_fre_set_cfa_offset (struct sframe_row_entry *fre,
>  			   offsetT cfa_offset)
>  {
> +  /* For s390x adjust CFA offset to enable 8-bit offsets.  */
> +  if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG)
> +    cfa_offset = SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE (cfa_offset);
> +
>    fre->cfa_offset = cfa_offset;
>    fre->merge_candidate = false;
>  }
> @@ -1043,7 +1059,7 @@ sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx *xlate_ctx,
>      }
>    sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.r);
>    if (last_fre)
> -    sframe_fre_set_cfa_offset (cur_fre, last_fre->cfa_offset);
> +    sframe_fre_set_cfa_offset (cur_fre, __sframe_fre_get_cfa_offset (last_fre));
>  
>    cur_fre->merge_candidate = false;
>  
> diff --git a/include/sframe.h b/include/sframe.h
> index 28b625b3258f..db137393532e 100644
> --- a/include/sframe.h
> +++ b/include/sframe.h
> @@ -376,6 +376,14 @@ typedef struct sframe_frame_row_entry_addr4
>  #define SFRAME_FRE_TYPE_ADDR4_LIMIT   \
>    (1ULL << ((SFRAME_FRE_TYPE_ADDR4 * 2) * 8))
>  
> +/* On s390x, the CFA offset from CFA base register is by definition a minimum
> +   of 160.  Store it adjusted by -160 to enable use of 8-bit SFrame offsets.  */
> +#define SFRAME_S390X_CFA_OFFSET_ADJUSTMENT		SFRAME_S390X_SP_VAL_OFFSET
> +#define SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE(offset) \
> +  ((offset) + SFRAME_S390X_CFA_OFFSET_ADJUSTMENT)
> +#define SFRAME_V2_FRE_S390X_CFA_OFFSET_DECODE(offset) \
> +  ((offset) - SFRAME_S390X_CFA_OFFSET_ADJUSTMENT)
> +

Ok to remove the infix "FRE" from the above (and all references in this
patch)?  This would align better with the following and shorten their
names:

SFRAME_V2_S390X_CFA_OFFSET_ENCODE(offset)
SFRAME_V2_S390X_CFA_OFFSET_DECODE(offset)

SFRAME_V2_S390X_OFFSET_IS_REGNUM(offset)
SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM(regnum)
SFRAME_V2_S390X_OFFSET_DECODE_REGNUM(offset)

>  /* On s390x, the CFA is defined as SP at call site + 160.  Therefore the
>     SP value offset from CFA is -160.  */
>  #define SFRAME_S390X_SP_VAL_OFFSET			(-160)
> diff --git a/libsframe/doc/sframe-spec.texi b/libsframe/doc/sframe-spec.texi
> index 6ba6c131edb6..9814c975147d 100644
> --- a/libsframe/doc/sframe-spec.texi
> +++ b/libsframe/doc/sframe-spec.texi
> @@ -155,6 +155,12 @@ an FP/RA offset.
>    @item SFRAME_FRE_RA_OFFSET_INVALID: Invalid RA offset value (like
>  SFRAME_CFA_FIXED_RA_INVALID).  Used on s390x as padding offset to represent
>  FP without RA saved.
> +  @item SFRAME_S390X_CFA_OFFSET_ADJUSTMENT: CFA offset (from CFA base register)
> +adjustment value.  Used to enable use of 8-bit SFrame offsets on s390x.
> +  @item SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE: Encode CFA offset (i.e., apply
> +CFA offset adjustment).
> +  @item SFRAME_V2_FRE_S390X_CFA_OFFSET_DECODE: Decode CFA offset (i.e., revert
> +CFA offset adjustment).
>   @end itemize
>  @end itemize
>  
> @@ -885,7 +891,15 @@ case in the topmost stack frame of the callchain.  For FP this may be the case
>  in any stack frame.
>  
>  Irrespective of the ABI, the first stack offset is always used to locate the
> -CFA, by interpreting it as: CFA = @code{BASE_REG} + offset1.
> +CFA.  On s390x the value of the offset is stored adjusted by the s390x-specific
> +@code{SFRAME_S390X_CFA_OFFSET_ADJUSTMENT} to enable the use of signed 8-bit
> +offsets on s390x.
> +s390x-specific helpers @code{SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE} and
> +@code{SFRAME_V2_FRE_S390X_CFA_OFFSET_DECODE} are provided to perform and undo
> +the adjustment.  The CFA offset can therefore be interpreted as:
> +CFA = @code{BASE_REG} + @code{SFRAME_V2_FRE_S390X_CFA_OFFSET_DECODE(offset1)}
> +or
> +CFA = @code{BASE_REG} + offset1 - @code{SFRAME_S390X_CFA_OFFSET_ADJUSTMENT}.
>  The identification of the @code{BASE_REG} is done by using the
>  @code{fre_cfa_base_reg_id} field in the SFrame FRE info word.
>  
> diff --git a/libsframe/sframe.c b/libsframe/sframe.c
> index d8d370da90dd..cedfd0d59580 100644
> --- a/libsframe/sframe.c
> +++ b/libsframe/sframe.c
> @@ -695,10 +695,16 @@ sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre, int *errp)
>  /* Get the CFA offset from the FRE.  If the offset is invalid, sets errp.  */
>  
>  int32_t
> -sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
> +sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx,
>  			   sframe_frame_row_entry *fre, int *errp)
>  {
> -  return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp);
> +  int32_t offset = sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp);
> +
> +  /* For s390x undo adjustment of CFA offset (to enable 8-bit offsets).  */
> +  if (sframe_decoder_get_abi_arch (dctx) == SFRAME_ABI_S390X_ENDIAN_BIG)
> +    offset = SFRAME_V2_FRE_S390X_CFA_OFFSET_DECODE (offset);
> +
> +  return offset;
>  }
>  
>  /* Get the FP offset from the FRE.  If the offset is invalid, sets errp.
> diff --git a/libsframe/testsuite/libsframe.find/plt-findfre-2.c b/libsframe/testsuite/libsframe.find/plt-findfre-2.c
> index 3ccc259a4d1c..5049e221ca5d 100644
> --- a/libsframe/testsuite/libsframe.find/plt-findfre-2.c
> +++ b/libsframe/testsuite/libsframe.find/plt-findfre-2.c
> @@ -43,8 +43,8 @@ add_plt0_fde (sframe_encoder_ctx *ectx, uint32_t plt_vaddr,
>    /* 1 single FRE.  */
>    sframe_frame_row_entry fre
>      = { 0x0,
> -	{ 0, 160 + PLT0_CFA_OFFSET_MAGIC },
> -	SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_2B) };
> +	{ SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE (160 + PLT0_CFA_OFFSET_MAGIC) },
> +	SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B) };
>  
>    unsigned char finfo = sframe_fde_create_func_info (SFRAME_FRE_TYPE_ADDR1,
>  						     SFRAME_FDE_TYPE_PCINC);
> @@ -72,8 +72,8 @@ add_pltn_fde (sframe_encoder_ctx *ectx, uint32_t plt_vaddr,
>    /* 1 single FRE.  */
>    sframe_frame_row_entry fre
>      = { 0x0,
> -	{ 0, 160 + PLTN_CFA_OFFSET_MAGIC },
> -	SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_2B) };
> +	{ SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE (160 + PLTN_CFA_OFFSET_MAGIC) },
> +	SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B) };
>  
>    unsigned char finfo = sframe_fde_create_func_info (SFRAME_FRE_TYPE_ADDR1,
>  						     SFRAME_FDE_TYPE_PCMASK);

Thanks and regards,
Jens
-- 
Jens Remus
Linux on Z Development (D3303)
+49-7031-16-1128 Office
jremus@de.ibm.com

IBM

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



More information about the Binutils mailing list