s390: Store SFrame CFA offset adjusted

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_S390X_CFA_OFFSET_ENCODE,
	SFRAME_V2_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_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_S390X_CFA_OFFSET_ENCODE on CFA offset to store it
	adjusted.
	(sframe_fre_get_cfa_offset): New helper.  For s390x use
	SFRAME_V2_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_S390X_CFA_OFFSET_DECODE on CFA offset to undo its
	adjustment.
	* doc/sframe-spec.texi (s390x,
	SFRAME_S390X_CFA_OFFSET_ADJUSTMENT,
	SFRAME_V2_S390X_CFA_OFFSET_ENCODE,
	SFRAME_V2_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_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>
This commit is contained in:
Jens Remus
2025-07-11 10:29:40 +02:00
parent 0d4d5a2633
commit c1056133a3
6 changed files with 54 additions and 10 deletions

View File

@@ -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_S390X_CFA_OFFSET_ENCODE: Encode CFA offset (i.e., apply
CFA offset adjustment).
@item SFRAME_V2_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_S390X_CFA_OFFSET_ENCODE} and
@code{SFRAME_V2_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_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.

View File

@@ -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_S390X_CFA_OFFSET_DECODE (offset);
return offset;
}
/* Get the FP offset from the FRE. If the offset is invalid, sets errp.

View File

@@ -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_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_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);