[V2 18/36] [SFrame-V3] gas: sframe: output new FDE type SFRAME_FDE_TYPE_FLEX
Jens Remus
jremus@linux.ibm.com
Tue Jan 13 08:31:30 GMT 2026
On 1/13/2026 3:06 AM, Indu Bhagat wrote:
> On 1/12/26 2:28 AM, Jens Remus wrote:
>> Hello Indu, Jose, Steven, et al.,
>>
>> On 1/7/2026 9:42 AM, Indu Bhagat wrote:
>>> This patch updates the routines for emission of the new FDE type
>>> SFRAME_FDE_TYPE_FLEX in the SFrame output section. The support for
>>> generating these flex FDEs themselves is added in a subsequent commit.
>>>
>>> For flex FDE type, output_sframe_row_entry_offsets () emits two
>>> offsets for RA tracking, irrespective of the ABI/arch, i.e.,
>>> irrespecitve of whether RA-tracking is enabled. This is because, for
>>
>> Please mention that only a single FP/RA padding "offset" is used when
>> FP location info without RA location info is encoded.
>>
>>> flex FDE type, RA is allowed "non-standard" recovery rules,
>>> e.g., RA = REG or RA = *(REG+offset). In a follow-up patch, when
>>> handling for .cfi_register RA, REG is added, emission code will be
>>> patched up accodingly.
>>
>> TL;DR: Recap of why a single padding offset of zero is acceptable.
>> Skip to stack tracer implications below.
>>
>> Regarding whether a single RA padding offset of zero (instead of two) is
>> sufficient to represent FP without RA saved:
>>
>> reg_data = SFRAME_V3_FLEX_FDE_REG_ENCODE (0 /* regnum */, 0 /* deref_p */, 0 /* reg_p */)
>> = SFRAME_FRE_RA_OFFSET_INVALID
>> = 0
>>
>> We established that this encoding rules out to represent the CFI
>> directive .cfi_val_offset RA, <offset> (means RA = CFA + <offset>) in
>> SFrame V3 without any additional flag in reg_data.
>>
>> This would not be an issue for RA, as .cfi_val_offset specifies an
>> address on the stack (as long as CFA points somewhere to the stack),
>> which should never be valid for the return address.
>> For FP this should not be useful either, as the FP value at entry
>> should not be known and thus not be representable related to CFA.
>> For SP, if SFrame would ever be extended to track SP, the only
>> sensible rule should be the one from the CFA definition
>> (e.g. CFA = SP at call site or CFA = SP at call site + 160 on s390x),
>> which would not need to be explicitly encoded, as it is already
>> implicitly assumed to unwind SP.
>>
>> If the need to represent .cfi_val_offset {SP|FP|RA} would still arise,
>> the spare unused bit in reg_data could possibly be used. It may be
>> required after all, as .cfi_val_offset {SP|FP|RA}, <offset> encodes as:
>>
>> reg_data = 0;
>> offset_data = <offset>;
>>
>
> Currently, .cfi_val_offset {SP|FP|RA} is not handled for SFrame.
>
> Your understanding is correct that: for enabling (generation) representation
> of of .cfi_val_offset {SP|FP|RA}, <offset> in future, we can use the
> indicated unused bit.
>
> The thinking was what we could _set_ that unused bit to 1 when wanting to
> indicate the semantics of .cfi_val_offset.
>
> That is,
>
> reg_data = SFRAME_V3_FLEX_FDE_REG_ENCODE (0,1,0,0);
> offset_data = <offset>
>
> would indicate the semantics of .cfi_val_offset in future.
>
> However, I now realise that for the above then, we will have to have
> (in future):
>
> #define SFRAME_V3_FLEX_FDE_REG_ENCODE(reg, not_invalid_p, deref_p, reg_p) \
> ((((reg) << 0x3) | (((not_invalid_p) & 0x1) << 0x2) | (((deref_p) & 0x1) << 0x1) | ((reg_p) & 0x1)))
>
> Perhaps its my general lack of skills in naming things appropriately,
> but I cannot think of an alternative to "not_invalid_p". That choice
> of name will be generally confusing.
>
> [The PADDING or invalid reg_data will need to be always be defined as zero.]
>
> Perhaps its better to define that unused bit now to adopt the semantics
> of valid_p. IOW, we start to generate reg_data as:
>
> reg_data = SFRAME_V3_FLEX_FDE_REG_ENCODE (reg,1,deref_p,reg_p);
> offset_data = <offset>
>
> Thoughts ?
I would then use the LSB for valid_p, but that is only my personal
preference:
((reg) << 3) | (deref_p << 3) | (reg_p << 2) | (valid_p)
It would leave no spare bit for any future use. Currently I can't see why
.cfi_val_offset {SP|FP|RA} would be important.
>> An offset value of zero (on architectures such as s390x that do not use
>> zero as default), would need explicit indication in reg_data to be
>> differentiated from two padding offsets of zero.
>>
>>
>>
>> Stack tracer implications of using single padding offsets in flexible
>> SFrame FDEs (at the example of WIP Linux Kernel unwind user sframe):
>>
>> TL;DR: Disallowing trailing padding offsets would slightly simplify the
>> flex FDE FRE offset decoding logic, as it allows to test for
>> (offset_count >= 2) once instead of (offset_count > 0) twice.
>>
>> A) Flex FDE FRE offset decoding logic when using two padding offsets:
>>
>> /* offset_count >= 2, as it is neither zero nor odd */
>> UNSAFE_GET_USER_INC(cfa_reg, cur, offset_size, Efault);
>> UNSAFE_GET_USER_INC(cfa_off, cur, offset_size, Efault);
>> offset_count -= 2;
>> cfa_off = sframe_cfa_offset_decode(cfa_off);
>>
>> ra_off = sec->fp_off;
>> ra_reg = ra_off ? 2 : 0; /* deref_p=(ra_off != 0) */
>> if (offset_count >= 2) {
>> UNSAFE_GET_USER_INC(ra_reg, cur, offset_size, Efault); <-- unconditionally read two offsets
>> UNSAFE_GET_USER_INC(ra_off, cur, offset_size, Efault);
>> offset_count -= 2;
>> if (!ra_reg && !ra_off) {
>> /* Padding RA location info */
>> ra_off = sec->ra_off;
>> if (ra_off)
>> ra_reg = 2; /* deref_p=(ra_off != 0) */
>> }
>> }
>>
>> [... likewise for FP ...]
>>
>> if (offset_count)
>> return -EFAULT;
>>
>> B) Flex FDE FRE offset decoding logic when using single padding offset
>> and disallowing trailing padding offsets:
>>
>> if (offset_count < 2)
>> return -EFAULT;
>> UNSAFE_GET_USER_INC(cfa_reg, cur, offset_size, Efault);
>> UNSAFE_GET_USER_INC(cfa_off, cur, offset_size, Efault);
>> offset_count -= 2;
>> cfa_off = sframe_cfa_offset_decode(cfa_off);
>>
>> ra_off = sec->fp_off;
>> ra_reg = ra_off ? 2 : 0; /* deref_p=(ra_off != 0) */
>> if (offset_count >= 2) { <-- either [ra_reg_data, ra_offset] or [SFRAME_FRE_RA_OFFSET_INVALID, fp_reg_data]
>> UNSAFE_GET_USER_INC(ra_reg, cur, offset_size, Efault);
>> offset_count--;
>> if (ra_reg) {
>> UNSAFE_GET_USER_INC(ra_off, cur, offset_size, Efault);
>> offset_count--;
>> } else {
>> /* Padding RA location info */
>> ra_off = sec->ra_off;
>> if (ra_off)
>> ra_reg = 2; /* deref_p=(ra_off != 0) */
>> }
>> }
>>
>> [... likewise for FP ...]
>>
>> if (offset_count)
>> return -EFAULT;
>>
>> C) Flex FDE FRE offset decoding logic when using single padding offset
>> but allowing trailing padding offsets:
>>
>> if (offset_count < 2)
>> return -EFAULT;
>> UNSAFE_GET_USER_INC(cfa_reg, cur, offset_size, Efault);
>> UNSAFE_GET_USER_INC(cfa_off, cur, offset_size, Efault);
Above reads CFA control data and offset into cfa_reg and cfa_off.
>> offset_count -= 2;
>> cfa_off = sframe_cfa_offset_decode(cfa_off);
>>
>> ra_off = sec->fp_off;
>> ra_reg = ra_off ? 2 : 0; /* deref_p=(ra_off != 0) */
Above initializes RA offset in ra_off to fixed RA offset and deduces
RA control data in ra_reg to have deref_p set if the RA offset is not
SFRAME_CFA_FIXED_RA_INVALID (= zero).
>> if (offset_count) {
>> UNSAFE_GET_USER_INC(ra_reg, cur, offset_size, Efault);
Above reads RA contol data into ra_reg.
>> offset_count--;
>> if (ra_reg) {
>> if (!offset_count) <-- additional test required
>> return -EFAULT;
>> UNSAFE_GET_USER_INC(ra_off, cur, offset_size, Efault);
Above reads RA offset into ra_off.
>> offset_count--;
>> } else {
>> /* Padding RA location info */
>> ra_off = sec->ra_off;
>> if (ra_off)
>> ra_reg = 2; /* deref_p=(ra_off != 0) */
Above sets RA offset to fixed RA offset and deduces RA control data.
I realized that setting ra_off is not required as it was not touched
since initialization to the fixed RA offset. Only the RA control
data needs to be re-deduced, as it got overwritten with the padding
"offset".
>> }
>> }
>>
>
> (I assume the comments /* deref_p=(ra_off != 0) */ are merely some
> stub/testing comment. We do need to get
> SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P (ra_reg) for deref_p...)
No, they are not. Whenever the fixed default RA/FP offset is used
the control data in ra_reg needs to be deduced, specifically deref_p
from whether the offset not SFRAME_CFA_FIXED_{FP|RA}_INVALID (= zero).
reg_p is always cleared when a fixed FP/RA offset is used.
Whenever control data is read from the FDE location data that is used
of course.
regnum, deref_p, and reg_p for CFA/FP/RA are later extracted from
cfa_reg/cfa_off, ra_reg/ra_off, and fp_reg/fp_off.
>
>> [... likewise for FP ...]
>>
>> if (offset_count) <-- TODO: test for additional padding offsets?
>> return -EFAULT;
>>
>>
>
> If the kernel implements this check of additional offsets as error path
> now, and suppose a future backward-compatible errata of the format uses
> more data (say for SP), other changes in the sframe stack tracer will be
> necessary anyway.
>
> So implementing this as error path now at least ensures safety as it is
> essentially a sanity check.
Makes sense.
>> What are your thoughts regarding the single padding offsets and whether
>> to allow for trailing padding offsets? Why would they be useful?
>>
>
> So far in GAS, we do not emit trailing padding offsets. As far as I can
> reason, I do not see a use to emitting trailing padding offsets.
>
> If there is agreement, I'd say its better to add this expectation (Trailing
> padding offsets should not exist) in the specification.
>
> So B) looks preferable to me:
> - Compared to A), B is compact in terms of section size.
> - Compared to C), I dont see the advantage in allowing trailing offsets ATM.
I very much agree. Somehow I was mislead that you preferred to allow
trailing padding offsets.
>> If I find some time besides getting the Kernel unwind user sframe
>> series into shape for review, I plan to do some SFrame size comparison
>> on s390x of the following:
>>
>> SFrame V2
>> SFrame V3, flex FDE disabled, use SFrame V2 register as offset encoding
>> SFrame V3, flex FDE disabled, use SFrame V3 register as offset encoding
>> SFrame V3, flex FDE enabled only for .cfi_register
>> SFrame V3, flex FDE fully enabled (this patch series)
>>
>
> In SFrame V3, we have one additional function info byte per FDE. Just a
> reminder that a size increase proportional to the number of FDEs is
> expected (when comparing V3 over V2).
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