[V2 18/36] [SFrame-V3] gas: sframe: output new FDE type SFRAME_FDE_TYPE_FLEX
Indu Bhagat
indu.bhagat@oracle.com
Tue Jan 13 02:06:04 GMT 2026
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 ?
> 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);
> 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) {
> UNSAFE_GET_USER_INC(ra_reg, cur, offset_size, Efault);
> offset_count--;
> if (ra_reg) {
> if (!offset_count) <-- additional test required
> return -EFAULT;
> 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) */
> }
> }
>
(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...)
> [... 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.
> 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.
>
> 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).
More information about the Binutils
mailing list