bpftool wraps the C dump in a clang attribute pragma that applies preserve_access_index to every struct and union, so field accesses through vmlinux.h types get CO-RE relocations. GCC-BPF supports the attribute but not the pragma, so it gets no CO-RE from the header. Jose proposed replacing the Clang pragmas with per-record attributes in May 2024 [1]. The declaration attribute support in btf_dump [2] now provides the per-type control discussed in that thread. Apply the attribute to each struct and union definition instead, as kflagged decl tags rendered by btf_dump. Add the tags to the split BTF that bpftool dumps through. The tags use the __bpf_relocatable macro, which by default expands to __attribute__((preserve_access_index)) if the compiler supports it. Programs built with Clang are unchanged. GCC-BPF programs can now get CO-RE relocations from vmlinux.h. The selftests GCC-BPF build defines BPF_NO_PRESERVE_ACCESS_INDEX, so it is not affected yet. [1]: https://lore.kernel.org/bpf/20240503111836.25275-1-jose.marchesi@oracle.com/ [2]: https://lore.kernel.org/bpf/20260929234608.48503-1-ihor.solodrai@linux.dev/ Signed-off-by: Ihor Solodrai --- tools/bpf/bpftool/btf.c | 34 +++++++++++++++---- .../bpf/bpftool_btf_dump_sorted.expected | 16 ++++----- .../bpf/bpftool_btf_dump_unsorted.expected | 16 ++++----- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c index b4516361a3fe..aa4290d5cabc 100644 --- a/tools/bpf/bpftool/btf.c +++ b/tools/bpf/bpftool/btf.c @@ -1131,6 +1131,24 @@ static int btf_c_annotate_type_tags(struct btf *btf) return 0; } +static int btf_c_annotate_records(struct btf *btf) +{ + __u32 i, cnt = btf__type_cnt(btf); + int err; + + for (i = 1; i < cnt; i++) { + const struct btf_type *t = btf__type_by_id(btf, i); + + if (!btf_is_composite(t)) + continue; + err = btf__add_decl_attr(btf, "__bpf_relocatable", i, -1); + if (err < 0) + return err; + } + + return 0; +} + static int dump_btf_c(struct btf *btf, __u32 *root_type_ids, int root_type_cnt, bool sort_dump) { @@ -1153,6 +1171,10 @@ static int dump_btf_c(struct btf *btf, if (err) goto done; + err = btf_c_annotate_records(split); + if (err) + goto done; + d = btf_dump__new(split, btf_dump_printf, NULL, NULL); if (!d) { err = -errno; @@ -1162,8 +1184,12 @@ static int dump_btf_c(struct btf *btf, printf("#ifndef __VMLINUX_H__\n"); printf("#define __VMLINUX_H__\n"); printf("\n"); - printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n"); - printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n"); + printf("#ifndef __bpf_relocatable\n"); + printf("#if !defined(BPF_NO_PRESERVE_ACCESS_INDEX) && __has_attribute(preserve_access_index)\n"); + printf("#define __bpf_relocatable __attribute__((preserve_access_index))\n"); + printf("#else\n"); + printf("#define __bpf_relocatable\n"); + printf("#endif\n"); printf("#endif\n\n"); printf("#ifndef __ksym\n"); printf("#define __ksym __attribute__((section(\".ksyms\")))\n"); @@ -1207,10 +1233,6 @@ static int dump_btf_c(struct btf *btf, goto done; } - printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n"); - printf("#pragma clang attribute pop\n"); - printf("#endif\n"); - printf("\n"); printf("#endif /* __VMLINUX_H__ */\n"); done: diff --git a/tools/testing/selftests/bpf/bpftool_btf_dump_sorted.expected b/tools/testing/selftests/bpf/bpftool_btf_dump_sorted.expected index 5470b2b43229..f2389e3dceed 100644 --- a/tools/testing/selftests/bpf/bpftool_btf_dump_sorted.expected +++ b/tools/testing/selftests/bpf/bpftool_btf_dump_sorted.expected @@ -1,8 +1,12 @@ #ifndef __VMLINUX_H__ #define __VMLINUX_H__ -#ifndef BPF_NO_PRESERVE_ACCESS_INDEX -#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record) +#ifndef __bpf_relocatable +#if !defined(BPF_NO_PRESERVE_ACCESS_INDEX) && __has_attribute(preserve_access_index) +#define __bpf_relocatable __attribute__((preserve_access_index)) +#else +#define __bpf_relocatable +#endif #endif #ifndef __ksym @@ -30,19 +34,15 @@ struct holey { long: 32; long: 32; int tail; -}; +} __bpf_relocatable; struct s { int f; -}; +} __bpf_relocatable; /* BPF kfuncs */ #ifndef BPF_NO_KFUNC_PROTOTYPES #endif -#ifndef BPF_NO_PRESERVE_ACCESS_INDEX -#pragma clang attribute pop -#endif - #endif /* __VMLINUX_H__ */ diff --git a/tools/testing/selftests/bpf/bpftool_btf_dump_unsorted.expected b/tools/testing/selftests/bpf/bpftool_btf_dump_unsorted.expected index 4310adc2ed51..549045677a45 100644 --- a/tools/testing/selftests/bpf/bpftool_btf_dump_unsorted.expected +++ b/tools/testing/selftests/bpf/bpftool_btf_dump_unsorted.expected @@ -1,8 +1,12 @@ #ifndef __VMLINUX_H__ #define __VMLINUX_H__ -#ifndef BPF_NO_PRESERVE_ACCESS_INDEX -#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record) +#ifndef __bpf_relocatable +#if !defined(BPF_NO_PRESERVE_ACCESS_INDEX) && __has_attribute(preserve_access_index) +#define __bpf_relocatable __attribute__((preserve_access_index)) +#else +#define __bpf_relocatable +#endif #endif #ifndef __ksym @@ -26,7 +30,7 @@ struct holey { long: 32; long: 32; int tail; -}; +} __bpf_relocatable; enum { E0 = 1, @@ -34,15 +38,11 @@ enum { struct s { int f; -}; +} __bpf_relocatable; /* BPF kfuncs */ #ifndef BPF_NO_KFUNC_PROTOTYPES #endif -#ifndef BPF_NO_PRESERVE_ACCESS_INDEX -#pragma clang attribute pop -#endif - #endif /* __VMLINUX_H__ */ -- 2.56.0