[PATCH v3 04/11] s390: Represent FP/RA saved in register in SFrame
Jens Remus
jremus@linux.ibm.com
Mon Jul 7 14:36:27 GMT 2025
Hello Indu,
thank you for the review and feedback!
On 06.07.2025 01:03, Indu Bhagat via Binutils wrote:
> On 6/27/25 4:08 AM, Jens Remus wrote:
>> GCC on s390x, when in a leaf function, can be observed to save the
>> frame pointer (FP) and/or return address (RA) register in a floating-
>> point registers (FPR) instead of on the stack. This is declared using
>> the following CFI directive:
>>
>> .cfi_register <fp/ra-regnum>, <fpr-regnum>
>>
>> SFrame cannot represent the FP and/or RA being saved in another
>> register. It does only track the CFA base register (SP/FP), CFA offset
>> from CFA base register, and FP and RA save area offsets from CFA.
>>
>> On s390x the FP and/or RA are only saved in another FPR when in a leaf
>> function. That is a function that does not call any other function.
>> Therefore it can ever only be the topmost function in a call chain.
>> An unwinder by default has access to all registers of the function that
>> is the topmost on the call stack. Therefore no further information
>> is required to restore FP/RA from the FPR.
>>
>> Represent FP/RA saved in another register on s390x, by encoding the
>> DWARF register number shifted by one to the left with the least-
>> significant bit set in the offset as follows:
>>
>> offset = (regnum << 1) | 1
>>
>> The use of the least-significant bit of the offset as indication is
>> possible, as the stack pointer (SP), the CFA, and any register save
>> area slots are 8-byte aligned according to the s390x ELF ABI:
>> - The stack pointer (SP) "shall maintain an 8-byte alignment". [1]
>> - The CFA is defined as SP at call site +160. [2]
>> - Pointers and 8-byte integers, such as general register values, must
>> be 8-byte aligned. [3]
>> SFrame FP and RA stack offsets must therefore always be a multiple of
>> 8 on s390x. Note that for the same reason the DWARF data alignment
>> factor is -8 on s390x (see DWARF2_CIE_DATA_ALIGNMENT).
>>
>> Add s390x-specific SFrame (error) tests for FP/RA saved in FPRs in leaf
>> function.
>>
>> [1]: s390x ELF ABI, sections "Register Roles" and "Stack Frame
>> Allocation", https://github.com/IBM/s390x-abi/releases
>> [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"),
>> https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88
>> [3]: s390x ELF ABI, section "Fundamental Types", table "Scalar types",
>> https://github.com/IBM/s390x-abi/releases
>>
>> include/
>> * sframe.h (SFRAME_S390X_OFFSET_IS_REGNUM): New s390x-specific
>> macro to test whether an SFrame FP/RA offset is a DWARF register
>> number.
>> (SFRAME_S390X_OFFSET_ENCODE_REGNUM): New s390x-specific macro to
>> encode a DWARF register number into an SFrame FP/RA offset.
>> (SFRAME_S390X_OFFSET_DECODE_REGNUM): New s390x-specific macro to
>> decode an SFrame FP/RA offset into a DWARF register number.
>> * sframe-api.h (sframe_fre_get_fp_offset,
>> sframe_fre_get_fp_offset): Add comment that for s390x the offset
>> may be an encoded register number.
>>
>> gas/
>> * gen-sframe.c (s390_sframe_xlate_do_register): New S390-
>> specific function. Uses SFRAME_S390X_OFFSET_ENCODE_REGNUM to
>> represent FP/RA saved in another register on s390x.
>> (sframe_xlate_do_register): Invoke s390_sframe_xlate_do_register
>> on s390x.
>>
>> libsframe/
>> * sframe.c (sframe_fre_get_fp_offset, sframe_fre_get_fp_offset):
>> Add comment that for s390x the offset may be an encoded register
>> number.
>> * sframe-dump.c (is_sframe_abi_arch_s390x): New helper to test
>> whether ABI/arch is s390x.
>> (dump_sframe_func_with_fres): Use SFRAME_S390X_OFFSET_IS_REGNUM
>> and SFRAME_S390X_OFFSET_DECODE_REGNUM to dump FP/RA saved in
>> another register on s390x.
>> * doc/sframe-spec.texi (s390x): Document s390x-specific
>> representation of FP/RA saved in another register.
>>
>> gas/testsuite/
>> * gas/cfi-sframe/cfi-sframe.exp: Update s390x-specific SFrame
>> (error) tests.
>> * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s: Rename
>> to ...
>> * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d:
>> Likewise.
>> * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-1.s: This. Test
>> no longer triggers a warning, as SFrame can represent FP and RA
>> saved in registers.
>> * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-1.d: Likewise.
>> * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: Test
>> now triggers a different warning, as SFrame can represent FP and
>> RA saved in registers, but not FP without RA saved in register.
>>
>> Signed-off-by: Jens Remus <jremus@linux.ibm.com>
>
> Few nits below.
>
> Otherwise, LGTM.
> Reviewed-by: Indu Bhagat <indu.bhagat@oracle.com>
>> diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
>> @@ -1126,6 +1126,37 @@ sframe_xlate_do_val_offset (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_U
>> return SFRAME_XLATE_OK;
>> }
>> +/* S390-specific translate DW_CFA_register into SFrame context.
>> + Return SFRAME_XLATE_OK if success. */
>> +
>> +static int
>> +s390_sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx,
>> + struct cfi_insn_data *cfi_insn)
>> +{
>> + /* The scratchpad FRE currently being updated with each cfi_insn
>> + being interpreted. This FRE eventually gets linked in into the
>> + list of FREs for the specific function. */
>> + struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
>> +
>> + gas_assert (cur_fre);
>> +
>> + /* Change the rule for the register indicated by the register number to
>> + be the specified register. Encode the register number as offset by
>> + shifting it to the left by one and setting the least-significant bit
>> + (LSB). The LSB can be used to differentiate offsets from register
>> + numbers, as offsets from CFA are always a multiple of -8 on s390x. */
>> + if (cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG)
>> + sframe_fre_set_bp_track (cur_fre,
>> + SFRAME_S390X_OFFSET_ENCODE_REGNUM (cfi_insn->u.rr.reg2));
>> + else if (sframe_ra_tracking_p ()
>> + && cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG)
>> + sframe_fre_set_ra_track (cur_fre,
>> + SFRAME_S390X_OFFSET_ENCODE_REGNUM (cfi_insn->u.rr.reg2));
>> +
>> + /* Safe to skip. */
>> + return SFRAME_XLATE_OK;
>
> Remove comment "Safe to skip."
Makes sense.
>> +}
>> diff --git a/include/sframe.h b/include/sframe.h
>> @@ -347,6 +347,19 @@ typedef struct sframe_frame_row_entry_addr4
>> SP value offset from CFA is -160. */
>> #define SFRAME_S390X_SP_VAL_OFFSET (-160)
>> +/* On s390x, the FP and RA registers can be saved either on the stack or,
>> + in case of leaf functions, in registers. Store DWARF register numbers
>> + encoded as offset by using the least-significant bit (LSB) as indicator:
>> + - LSB=0: Stack offset. The s390x ELF ABI mandates that stack register
>> + slots must be 8-byte aligned.
>> + - LSB=1: DWARF register number shifted to the left by one. */
>> +#define SFRAME_S390X_OFFSET_IS_REGNUM(offset) \
>> + ((offset) & 1)
>> +#define SFRAME_S390X_OFFSET_ENCODE_REGNUM(regnum) \
>> + (((regnum) << 1) | 1)
>> +#define SFRAME_S390X_OFFSET_DECODE_REGNUM(offset) \
>> + ((offset) >> 1)
>> +
>
> Perhaps it wont hurt to also use "SFRAME_V2" as prefix in the names:
> - SFRAME_V2_S390X_OFFSET_IS_REGNUM
> - SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM
> - SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM
>
> This also aligns well with the choice made in the rest of the series
> (SFRAME_V2_FRE_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_FRE_S390X_CFA_OFFSET_DECODE).
Ok.
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