[PATCH bpf-next 1/2] bpftool: Skip non-autoload programs when generating light skeletons
From: Thiébaud Weksteen
Date: Tue Sep 08 2026 - 03:02:53 EST
When generating a light skeleton (bpftool gen skeleton -L),
bpf_object__load() skips loading programs marked as non-autoload (e.g.
SEC("?...")), so the generated loader program only records and populates
file descriptors for autoloaded programs.
Previously, bpftool emitted struct bpf_prog_desc fields, link fields,
and attach/detach/destroy functions for all programs in the BPF object,
causing the loader program to store subsequent program FDs into
incorrect skeleton struct fields when non-autoload programs were
present.
Skip programs with !bpf_program__autoload(prog) when counting programs
and generating progs/links struct fields as well as attach, detach, and
destroy functions for light skeletons.
Fixes: d510296d331a ("bpftool: Use syscall/loader program in "prog load" and "gen skeleton" command.")
Signed-off-by: Thiébaud Weksteen <tweek@xxxxxxxxxx>
---
tools/bpf/bpftool/Documentation/bpftool-gen.rst | 4 +++-
tools/bpf/bpftool/gen.c | 15 +++++++++++++++
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/tools/bpf/bpftool/Documentation/bpftool-gen.rst b/tools/bpf/bpftool/Documentation/bpftool-gen.rst
index d0a36f442db7..1cdecf3e4fa5 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-gen.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-gen.rst
@@ -184,7 +184,9 @@ OPTIONS
-L, --use-loader
For skeletons, generate a "light" skeleton (also known as "loader"
skeleton). A light skeleton contains a loader eBPF program. It does not use
- the majority of the libbpf infrastructure, and does not need libelf.
+ the majority of the libbpf infrastructure, and does not need libelf. BPF
+ programs marked as non-autoload (e.g., via **SEC("?...")**) are skipped and
+ not included in the generated skeleton.
-S, --sign
For skeletons, generate a signed skeleton. This option must be used with
diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index a50540ef6521..0fcfe20ff515 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -583,6 +583,9 @@ static void codegen_attach_detach(struct bpf_object *obj, const char *obj_name)
bpf_object__for_each_program(prog, obj) {
const char *tp_name;
+ if (!bpf_program__autoload(prog))
+ continue;
+
codegen("\
\n\
\n\
@@ -629,6 +632,8 @@ static void codegen_attach_detach(struct bpf_object *obj, const char *obj_name)
", obj_name);
bpf_object__for_each_program(prog, obj) {
+ if (!bpf_program__autoload(prog))
+ continue;
codegen("\
\n\
ret = ret < 0 ? ret : %1$s__%2$s__attach(skel); \n\
@@ -646,6 +651,8 @@ static void codegen_attach_detach(struct bpf_object *obj, const char *obj_name)
", obj_name);
bpf_object__for_each_program(prog, obj) {
+ if (!bpf_program__autoload(prog))
+ continue;
codegen("\
\n\
skel_closenz(skel->links.%1$s_fd); \n\
@@ -676,6 +683,8 @@ static void codegen_destroy(struct bpf_object *obj, const char *obj_name)
obj_name);
bpf_object__for_each_program(prog, obj) {
+ if (!bpf_program__autoload(prog))
+ continue;
codegen("\
\n\
skel_closenz(skel->progs.%1$s.prog_fd); \n\
@@ -1339,6 +1348,8 @@ static int do_skeleton(int argc, char **argv)
map_cnt++;
}
bpf_object__for_each_program(prog, obj) {
+ if (use_loader && !bpf_program__autoload(prog))
+ continue;
prog_cnt++;
}
@@ -1402,6 +1413,8 @@ static int do_skeleton(int argc, char **argv)
if (prog_cnt) {
printf("\tstruct {\n");
bpf_object__for_each_program(prog, obj) {
+ if (use_loader && !bpf_program__autoload(prog))
+ continue;
if (use_loader)
printf("\t\tstruct bpf_prog_desc %s;\n",
bpf_program__name(prog));
@@ -1415,6 +1428,8 @@ static int do_skeleton(int argc, char **argv)
if (prog_cnt + attach_map_cnt) {
printf("\tstruct {\n");
bpf_object__for_each_program(prog, obj) {
+ if (use_loader && !bpf_program__autoload(prog))
+ continue;
if (use_loader)
printf("\t\tint %s_fd;\n",
bpf_program__name(prog));
--
2.55.0.979.g7e5102b832-goog