On Fri, Apr 11, 2025 at 10:32:10PM +0200, Alexis Lothoré (eBPF Foundation) wrote: > In order to properly JIT the trampolines needed to attach BPF programs > to functions, some architectures like ARM64 need to know about the > alignment needed for the function arguments. Such alignment can > generally be deduced from the argument size, but that's not completely > true for composite types. In the specific case of ARM64, the AAPCS64 ABI > defines that a composite type which needs to be passed through stack > must be aligned on the maximum between 8 and the largest alignment > constraint of its first-level members. So the JIT compiler needs more > information about the arguments to make sure to generate code that > respects those alignment constraints. > > For struct arguments, add information about the size of the largest > first-level member in the struct btf_func_model to allow the JIT > compiler to guess the needed alignment. The information is quite > specific, but it allows to keep arch-specific concerns (ie: guessing the > final needed alignment for an argument) isolated in each JIT compiler. > > Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.loth...@bootlin.com> > --- > include/linux/bpf.h | 1 + > kernel/bpf/btf.c | 25 +++++++++++++++++++++++++ > 2 files changed, 26 insertions(+) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index > 3f0cc89c0622cb1a097999afb78c17102593b6bb..8b34dcf60a0ce09228ff761b962ab67b6a3e2263 > 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -1106,6 +1106,7 @@ struct btf_func_model { > u8 nr_args; > u8 arg_size[MAX_BPF_FUNC_ARGS]; > u8 arg_flags[MAX_BPF_FUNC_ARGS]; > + u8 arg_largest_member_size[MAX_BPF_FUNC_ARGS]; > }; > > /* Restore arguments before returning from trampoline to let original > function > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c > index > 16ba36f34dfab7531babf5753cab9f368cddefa3..5d40911ec90210086a6175d569abb6e52d75ad17 > 100644 > --- a/kernel/bpf/btf.c > +++ b/kernel/bpf/btf.c > @@ -7318,6 +7318,29 @@ static int __get_type_size(struct btf *btf, u32 btf_id, > return -EINVAL; > } > > +static u8 __get_largest_member_size(struct btf *btf, const struct btf_type > *t) > +{ > + const struct btf_member *member; > + const struct btf_type *mtype; > + u8 largest_member_size = 0; > + int i; > + > + if (!__btf_type_is_struct(t)) > + return largest_member_size; > + > + for_each_member(i, t, member) { > + mtype = btf_type_by_id(btf, member->type); > + while (mtype && btf_type_is_modifier(mtype)) > + mtype = btf_type_by_id(btf, mtype->type); > + if (!mtype) > + return -EINVAL;
should we use __get_type_size for member->type instead ? jirka > + if (mtype->size > largest_member_size) > + largest_member_size = mtype->size; > + } > + > + return largest_member_size; > +} > + > static u8 __get_type_fmodel_flags(const struct btf_type *t) > { > u8 flags = 0; > @@ -7396,6 +7419,8 @@ int btf_distill_func_proto(struct bpf_verifier_log *log, > } > m->arg_size[i] = ret; > m->arg_flags[i] = __get_type_fmodel_flags(t); > + m->arg_largest_member_size[i] = > + __get_largest_member_size(btf, t); > } > m->nr_args = nargs; > return 0; > > -- > 2.49.0 >