bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 bpf-next 1/2] libbpf: Fix static linking of externs placed in allocated sections
@ 2026-09-26  0:02 Andrii Nakryiko
  2026-09-26  0:02 ` [PATCH v2 bpf-next 2/2] selftests/bpf: Add linked_externs test for externs " Andrii Nakryiko
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Andrii Nakryiko @ 2026-09-26  0:02 UTC (permalink / raw)
  To: bpf; +Cc: andrii, kernel-team

Clang puts an extern variable that ends up with a section, an extern
map in .maps or an arena global in .addr_space.<N>, into the BTF
DATASEC of that section, next to the object's own definitions and
with offset 0. Unlike .kconfig and .ksyms, that section is a real
allocated ELF section whenever the same object also defines a
variable in it. The static linker handles such externs incorrectly in
two ways.

The output symbol of an unresolved extern gets the destination
section's index and offset instead of staying SHN_UNDEF with a zero
value. For ephemeral sections both are 0, so this only shows up for
allocated sections, where the extern turns into a size-zero NOTYPE
definition. Linking the output again then fails with "conflicting
non-weak symbol" against a strong definition of that variable, or,
against a weak one, keeps the bogus symbol and resolves every
reference to offset 0 of the section. And if the section of the
object with the extern doesn't start at offset 0 of the output
section, the output symbol fails linker_sanity_check_elf_symtab() on
the next link with "invalid extern symbol" before any of that.

When the extern is resolved by a later object in the same link, the
DATASEC entry appended for the extern keeps its placeholder offset,
as linker_append_btf() only updates the size of an existing entry.
The ELF symbol and the BTF secinfo then disagree and skeleton
generation fails with:

  Error: Something is wrong for .addr_space.1's variable #1: need offset 0, already at 8.

Keep unresolved externs SHN_UNDEF with a zero value in the output
symbol table, and once an extern is resolved take the offset of its
DATASEC entry from the ELF symbol, which already accounts for weak
vs. strong resolution.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 tools/lib/bpf/linker.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/tools/lib/bpf/linker.c b/tools/lib/bpf/linker.c
index 53f64a1a1f25..f3f71c452f00 100644
--- a/tools/lib/bpf/linker.c
+++ b/tools/lib/bpf/linker.c
@@ -2159,8 +2159,13 @@ static int linker_append_elf_sym(struct bpf_linker *linker, struct src_obj *obj,
 	dst_sym->st_name = name_off;
 	dst_sym->st_info = sym->st_info;
 	dst_sym->st_other = sym->st_other;
-	dst_sym->st_shndx = dst_sec ? dst_sec->sec_idx : sym->st_shndx;
-	dst_sym->st_value = (src_sec ? src_sec->dst_off : 0) + sym->st_value;
+	if (sym_is_extern) {
+		dst_sym->st_shndx = SHN_UNDEF;
+		dst_sym->st_value = 0;
+	} else {
+		dst_sym->st_shndx = dst_sec ? dst_sec->sec_idx : sym->st_shndx;
+		dst_sym->st_value = (src_sec ? src_sec->dst_off : 0) + sym->st_value;
+	}
 	dst_sym->st_size = sym->st_size;
 
 	obj->sym_map[src_sym_idx] = dst_sym_idx;
@@ -2592,6 +2597,10 @@ static int linker_append_btf(struct bpf_linker *linker, struct src_obj *obj)
 					continue;
 
 				dst_var = &dst_sec->sec_vars[glob_sym->var_idx];
+				if (!glob_sym->is_extern) {
+					Elf64_Sym *sym = get_sym_by_idx(linker, glob_sym->sym_idx);
+					dst_var->offset = sym->st_value;
+				}
 				/* Because underlying BTF type might have
 				 * changed, so might its size have changed, so
 				 * re-calculate and update it in sec_var.
-- 
2.53.0-Meta


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 bpf-next 2/2] selftests/bpf: Add linked_externs test for externs in allocated sections
  2026-09-26  0:02 [PATCH v2 bpf-next 1/2] libbpf: Fix static linking of externs placed in allocated sections Andrii Nakryiko
@ 2026-09-26  0:02 ` Andrii Nakryiko
  2026-09-26  0:08   ` sashiko-bot
                     ` (2 more replies)
  2026-09-26  0:50 ` [PATCH v2 bpf-next 1/2] libbpf: Fix static linking of externs placed " bot+bpf-ci
  2026-09-26  8:51 ` Alexei Starovoitov
  2 siblings, 3 replies; 8+ messages in thread
From: Andrii Nakryiko @ 2026-09-26  0:02 UTC (permalink / raw)
  To: bpf; +Cc: andrii, kernel-team

Add two objects that define an arena global each and declare the
other one's as extern, linked into a single skeleton with the
extern-declaring object first.

The skeleton build relinks the linked object twice more, which fixes
up DATASEC offsets from the ELF symbol table, so the test also drives
the libbpf linker directly: it links linked_arena1.bpf.o on its own,
links the result with linked_arena2.bpf.o, checks that no variable in
the .addr_space.1 DATASEC is left extern, and loads the object. The
same is done with linked_maps1/2.bpf.o, which have an extern map in
.maps.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 tools/testing/selftests/bpf/Makefile.skel     |   3 +-
 .../selftests/bpf/prog_tests/linked_externs.c | 109 ++++++++++++++++++
 .../selftests/bpf/progs/linked_arena1.c       |  22 ++++
 .../selftests/bpf/progs/linked_arena2.c       |  18 +++
 4 files changed, 151 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/linked_externs.c
 create mode 100644 tools/testing/selftests/bpf/progs/linked_arena1.c
 create mode 100644 tools/testing/selftests/bpf/progs/linked_arena2.c

diff --git a/tools/testing/selftests/bpf/Makefile.skel b/tools/testing/selftests/bpf/Makefile.skel
index 3d92cdca62ed..2e22bb901bf3 100644
--- a/tools/testing/selftests/bpf/Makefile.skel
+++ b/tools/testing/selftests/bpf/Makefile.skel
@@ -23,7 +23,7 @@ BPF_OBJS := $(patsubst %.c,$(RDIR)/%.bpf.o,$(BPF_SRCS))
 SKEL_BLACKLIST := btf__% test_pinning_invalid.c test_sk_assign.c
 
 LINKED_SKELS := test_static_linked.skel.h linked_funcs.skel.h		\
-		linked_vars.skel.h linked_maps.skel.h 			\
+		linked_vars.skel.h linked_maps.skel.h linked_arena.skel.h \
 		test_subskeleton.skel.h test_subskeleton_lib.skel.h	\
 		test_usdt.skel.h tracing_multi.skel.h			\
 		tracing_multi_module.skel.h				\
@@ -46,6 +46,7 @@ test_static_linked.skel.h-deps := test_static_linked1.bpf.o test_static_linked2.
 linked_funcs.skel.h-deps := linked_funcs1.bpf.o linked_funcs2.bpf.o
 linked_vars.skel.h-deps := linked_vars1.bpf.o linked_vars2.bpf.o
 linked_maps.skel.h-deps := linked_maps1.bpf.o linked_maps2.bpf.o
+linked_arena.skel.h-deps := linked_arena1.bpf.o linked_arena2.bpf.o
 # In the subskeleton case, we want the test_subskeleton_lib.subskel.h file
 # but that's created as a side-effect of the skel.h generation.
 test_subskeleton.skel.h-deps := test_subskeleton_lib2.bpf.o test_subskeleton_lib.bpf.o test_subskeleton.bpf.o
diff --git a/tools/testing/selftests/bpf/prog_tests/linked_externs.c b/tools/testing/selftests/bpf/prog_tests/linked_externs.c
new file mode 100644
index 000000000000..29358c82dc35
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/linked_externs.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
+#include <test_progs.h>
+#include <bpf/btf.h>
+#include "linked_arena.skel.h"
+
+static void test_skel(void)
+{
+	LIBBPF_OPTS(bpf_test_run_opts, opts);
+	struct linked_arena *skel;
+	int err;
+
+	skel = linked_arena__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
+		return;
+
+	ASSERT_EQ(skel->arena->a_val, 1, "a_val_init");
+	ASSERT_EQ(skel->arena->b_val, 2, "b_val_init");
+
+	err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.sum1), &opts);
+	ASSERT_OK(err, "sum1_run");
+	ASSERT_EQ(opts.retval, 1 + 2, "sum1_retval");
+
+	err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.bump2), &opts);
+	ASSERT_OK(err, "bump2_run");
+	ASSERT_EQ(opts.retval, 11 + 22, "bump2_retval");
+
+	ASSERT_EQ(skel->arena->a_val, 11, "a_val");
+	ASSERT_EQ(skel->arena->b_val, 22, "b_val");
+
+	linked_arena__destroy(skel);
+}
+
+static int link_objs(const char *out, const char *in1, const char *in2)
+{
+	struct bpf_linker *linker;
+	int err;
+
+	linker = bpf_linker__new(out, NULL);
+	if (!ASSERT_OK_PTR(linker, "linker_new"))
+		return -EINVAL;
+
+	err = bpf_linker__add_file(linker, in1, NULL);
+	if (!ASSERT_OK(err, in1))
+		goto cleanup;
+	if (in2) {
+		err = bpf_linker__add_file(linker, in2, NULL);
+		if (!ASSERT_OK(err, in2))
+			goto cleanup;
+	}
+	err = bpf_linker__finalize(linker);
+	ASSERT_OK(err, "finalize");
+
+cleanup:
+	bpf_linker__free(linker);
+	return err;
+}
+
+/* link in1 on its own first, then link the result with in2 */
+static void test_relink(const char *in1, const char *in2, const char *sec_name)
+{
+	char out1[] = "/tmp/linked_externs.XXXXXX", out2[] = "/tmp/linked_externs.XXXXXX";
+	const struct btf_var_secinfo *vi;
+	struct bpf_object *obj = NULL;
+	const struct btf_type *t;
+	struct btf *btf;
+	int i, id, n;
+
+	close(mkstemp(out1));
+	close(mkstemp(out2));
+
+	if (!ASSERT_OK(link_objs(out1, in1, NULL), "link_stage1") ||
+	    !ASSERT_OK(link_objs(out2, out1, in2), "link_stage2"))
+		goto cleanup;
+
+	obj = bpf_object__open_file(out2, NULL);
+	if (!ASSERT_OK_PTR(obj, "obj_open"))
+		goto cleanup;
+
+	btf = bpf_object__btf(obj);
+	id = btf__find_by_name_kind(btf, sec_name, BTF_KIND_DATASEC);
+	if (!ASSERT_GT(id, 0, "find_datasec"))
+		goto cleanup;
+
+	t = btf__type_by_id(btf, id);
+	vi = btf_var_secinfos(t);
+	n = btf_vlen(t);
+	for (i = 0; i < n; i++) {
+		t = btf__type_by_id(btf, vi[i].type);
+		ASSERT_NEQ(btf_var(t)->linkage, BTF_VAR_GLOBAL_EXTERN, "var_resolved");
+	}
+
+	ASSERT_OK(bpf_object__load(obj), "obj_load");
+
+cleanup:
+	bpf_object__close(obj);
+	unlink(out1);
+	unlink(out2);
+}
+
+void test_linked_externs(void)
+{
+	if (test__start_subtest("skel_arena"))
+		test_skel();
+	if (test__start_subtest("relink_arena"))
+		test_relink("linked_arena1.bpf.o", "linked_arena2.bpf.o", ".addr_space.1");
+	if (test__start_subtest("relink_maps"))
+		test_relink("linked_maps1.bpf.o", "linked_maps2.bpf.o", ".maps");
+}
diff --git a/tools/testing/selftests/bpf/progs/linked_arena1.c b/tools/testing/selftests/bpf/progs/linked_arena1.c
new file mode 100644
index 000000000000..3e8788dec1d9
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/linked_arena1.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_arena_common.h"
+
+struct {
+	__uint(type, BPF_MAP_TYPE_ARENA);
+	__uint(map_flags, BPF_F_MMAPABLE);
+	__uint(max_entries, 1); /* number of pages */
+} arena SEC(".maps");
+
+long __arena a_val = 1;
+extern long __arena b_val; /* defined in linked_arena2.c */
+
+SEC("syscall")
+int sum1(void *ctx)
+{
+	return a_val + b_val;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/linked_arena2.c b/tools/testing/selftests/bpf/progs/linked_arena2.c
new file mode 100644
index 000000000000..d0bcdf18a4b6
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/linked_arena2.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_arena_common.h"
+
+long __arena b_val = 2;
+extern long __arena a_val; /* defined in linked_arena1.c */
+
+SEC("syscall")
+int bump2(void *ctx)
+{
+	a_val += 10;
+	b_val += 20;
+	return a_val + b_val;
+}
+
+char _license[] SEC("license") = "GPL";
-- 
2.53.0-Meta


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 bpf-next 2/2] selftests/bpf: Add linked_externs test for externs in allocated sections
  2026-09-26  0:02 ` [PATCH v2 bpf-next 2/2] selftests/bpf: Add linked_externs test for externs " Andrii Nakryiko
@ 2026-09-26  0:08   ` sashiko-bot
  2026-09-26  0:50   ` bot+bpf-ci
  2026-09-28 21:52   ` Vineet Gupta
  2 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-09-26  0:08 UTC (permalink / raw)
  To: Andrii Nakryiko; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] selftests/bpf: unhandled mkstemp() failure in test_relink()
--

commit e2fcaeeb4be58f57f9657902a9e400bc15e30412
Author: Andrii Nakryiko <andrii@kernel.org>

selftests/bpf: Add linked_externs test for externs in allocated sections

This commit adds a selftest to verify that the BPF linker correctly handles
extern variables in allocated sections (like arena and maps). It tests the
behavior both via the BPF skeleton and by directly driving the libbpf linker
API.

> diff --git a/tools/testing/selftests/bpf/prog_tests/linked_externs.c b/tools/testing/selftests/bpf/prog_tests/linked_externs.c
> new file mode 100644
> index 0000000000000..29358c82dc356
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/linked_externs.c
[ ... ]
> +/* link in1 on its own first, then link the result with in2 */
> +static void test_relink(const char *in1, const char *in2, const char *sec_name)
> +{
> +	char out1[] = "/tmp/linked_externs.XXXXXX", out2[] = "/tmp/linked_externs.XXXXXX";
> +	const struct btf_var_secinfo *vi;
> +	struct bpf_object *obj = NULL;
> +	const struct btf_type *t;
> +	struct btf *btf;
> +	int i, id, n;
> +
> +	close(mkstemp(out1));
> +	close(mkstemp(out2));

[Severity: Medium]
What happens if mkstemp() fails here?

If it returns -1, it will be passed directly to close() which will just fail,
but the template strings will remain undefined (typically unmodified). The
test would then continue using the predictable string
"/tmp/linked_externs.XXXXXX" for file operations.

Could this cause collisions with other concurrent test runs or leave leftover
predictable files in /tmp?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260926000243.2830819-1-andrii@kernel.org?part=2

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 bpf-next 2/2] selftests/bpf: Add linked_externs test for externs in allocated sections
  2026-09-26  0:02 ` [PATCH v2 bpf-next 2/2] selftests/bpf: Add linked_externs test for externs " Andrii Nakryiko
  2026-09-26  0:08   ` sashiko-bot
@ 2026-09-26  0:50   ` bot+bpf-ci
  2026-09-28 21:52   ` Vineet Gupta
  2 siblings, 0 replies; 8+ messages in thread
From: bot+bpf-ci @ 2026-09-26  0:50 UTC (permalink / raw)
  To: andrii, bpf
  Cc: andrii, kernel-team, ast, andrii, daniel, martin.lau, eddyz87,
	yonghong.song, mason, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 3571 bytes --]

> diff --git a/tools/testing/selftests/bpf/prog_tests/linked_externs.c b/tools/testing/selftests/bpf/prog_tests/linked_externs.c
> new file mode 100644
> index 000000000000..29358c82dc35
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/linked_externs.c
> @@ -0,0 +1,109 @@

[ ... ]

> +/* link in1 on its own first, then link the result with in2 */
> +static void test_relink(const char *in1, const char *in2, const char *sec_name)
> +{
> +	char out1[] = "/tmp/linked_externs.XXXXXX", out2[] = "/tmp/linked_externs.XXXXXX";
> +	const struct btf_var_secinfo *vi;
> +	struct bpf_object *obj = NULL;
> +	const struct btf_type *t;
> +	struct btf *btf;
> +	int i, id, n;
> +
> +	close(mkstemp(out1));
> +	close(mkstemp(out2));
> +
> +	if (!ASSERT_OK(link_objs(out1, in1, NULL), "link_stage1") ||
> +	    !ASSERT_OK(link_objs(out2, out1, in2), "link_stage2"))
> +		goto cleanup;
> +
> +	obj = bpf_object__open_file(out2, NULL);
> +	if (!ASSERT_OK_PTR(obj, "obj_open"))
> +		goto cleanup;
> +
> +	btf = bpf_object__btf(obj);
> +	id = btf__find_by_name_kind(btf, sec_name, BTF_KIND_DATASEC);
> +	if (!ASSERT_GT(id, 0, "find_datasec"))
> +		goto cleanup;
> +
> +	t = btf__type_by_id(btf, id);
> +	vi = btf_var_secinfos(t);
> +	n = btf_vlen(t);
> +	for (i = 0; i < n; i++) {
> +		t = btf__type_by_id(btf, vi[i].type);
> +		ASSERT_NEQ(btf_var(t)->linkage, BTF_VAR_GLOBAL_EXTERN, "var_resolved");
> +	}
> +
> +	ASSERT_OK(bpf_object__load(obj), "obj_load");

Does the relink_arena subtest detect a regression of the second libbpf hunk
in de5494287bf5, the one that sets dst_var->offset = sym->st_value in
linker_append_btf?

If that hunk were reverted, a_val and b_val in .addr_space.1 would both keep
BTF offset 0 in the stage2 output. Both vars are already
BTF_VAR_GLOBAL_ALLOCATED (complete_extern_btf_info updates the linkage), so
the var_resolved assertion passes.

bpf_object__open_file() does not repair the offsets, because
btf_fixup_datasec() only recomputes them when t->size == 0:

tools/lib/bpf/libbpf.c:btf_fixup_datasec() {
    for (i = 0, vsi = btf_var_secinfos(t); i < vlen; i++, vsi++) {
        ...
        if (t->size)
            continue;
        ...
        vsi->offset = ((__u32)sym.st_value) - start;
    }
}

At load time the kernel rejects the BTF in btf_datasec_check_meta() with
Invalid offset. This object has no struct_ops, though, so libbpf treats BTF
as optional, logs BTF is optional, ignoring, and bpf_object__load() still
returns 0:

tools/lib/bpf/libbpf.c:bpf_object_load() {
    err = bpf_object_init_prog_arrays(obj);
    if (err)
        return libbpf_err(err);

    err = bpf_object_load_prog(obj, prog, ...);
    ...
}

Arena relocations use ELF symbols and section data, not BTF offsets, so
obj_load still passes.

The skel_arena subtest does not catch it either, because gen_bpf_skel.sh
relinks through linker_fixup_btf, which recomputes the offsets from the ELF
symbols. The commit message says the direct linker test exists because the
skeleton path hides the problem, but only relink_maps (through map
sec_offset matching) would expose the offset bug. relink_arena would not.

Could the test also check that the DATASEC var offsets are distinct, or that
they match the ELF symbol values?

> +
> +cleanup:
> +	bpf_object__close(obj);
> +	unlink(out1);
> +	unlink(out2);
> +}

[ ... ]


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/36204104252

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 bpf-next 1/2] libbpf: Fix static linking of externs placed in allocated sections
  2026-09-26  0:02 [PATCH v2 bpf-next 1/2] libbpf: Fix static linking of externs placed in allocated sections Andrii Nakryiko
  2026-09-26  0:02 ` [PATCH v2 bpf-next 2/2] selftests/bpf: Add linked_externs test for externs " Andrii Nakryiko
@ 2026-09-26  0:50 ` bot+bpf-ci
  2026-09-26  8:51 ` Alexei Starovoitov
  2 siblings, 0 replies; 8+ messages in thread
From: bot+bpf-ci @ 2026-09-26  0:50 UTC (permalink / raw)
  To: andrii, bpf
  Cc: andrii, kernel-team, ast, andrii, daniel, martin.lau, eddyz87,
	yonghong.song, mason, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 2631 bytes --]

> diff --git a/tools/lib/bpf/linker.c b/tools/lib/bpf/linker.c
> index 53f64a1a1f25..f3f71c452f00 100644
> --- a/tools/lib/bpf/linker.c
> +++ b/tools/lib/bpf/linker.c

[ ... ]

> @@ -2592,6 +2597,10 @@ static int linker_append_btf(struct bpf_linker *linker, struct src_obj *obj)
>  					continue;
>
>  				dst_var = &dst_sec->sec_vars[glob_sym->var_idx];
> +				if (!glob_sym->is_extern) {
> +					Elf64_Sym *sym = get_sym_by_idx(linker, glob_sym->sym_idx);
> +					dst_var->offset = sym->st_value;
> +				}

The new offset update assumes glob_sym->var_idx is an index into the
current dst_sec->sec_vars. Does that hold when the resolving definition
is in a different section than the one where the DATASEC entry was first
created?

glob_sym->var_idx is recorded when the glob_sym first gets a DATASEC
entry. If a later strong definition wins, linker_append_elf_sym() moves
the symbol to the new section:

  dst_sym->st_shndx = dst_sec->sec_idx;
  dst_sym->st_value = src_sec->dst_off + sym->st_value;
  ...
  glob_sym->sec_id = dst_sec->id;
  glob_sym->is_extern = false;

The section mismatch check at the top of the DATASEC loop in
linker_append_btf() compares against this updated sec_id, so it passes.
The stale var_idx is then used to index the other section's sec_vars.

For example, if A.c has `int y = 1;` in .data and `int x __weak;` in
.bss, and B.c has `int x = 5;` in .data, linking A then B:

  After A: y is .data sec_vars[0]; x is .bss sec_vars[0] with var_idx 0
  B's .data DATASEC: strong x resolves weak one, sec_id becomes .data,
                     dst_var = &.data->sec_vars[0], which is y's entry

Before this patch only dst_var->size was rewritten there, and y's size
is 4 either way. With this patch y's offset is also set to x's st_value.
The output BTF then has y and x at the same offset in .data.

The same happens for an extern whose DATASEC entry sits in one allocated
section when the definition that resolves it is in a different section.
If the new section's sec_vars is shorter than var_idx, or still NULL,
the write lands out of bounds or through a NULL-based pointer.

Could the var_idx path be skipped, or the resolution rejected, when the
resolving section differs from the one var_idx refers to?

>  				/* Because underlying BTF type might have
>  				 * changed, so might its size have changed, so
>  				 * re-calculate and update it in sec_var.


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/36204104252

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 bpf-next 1/2] libbpf: Fix static linking of externs placed in allocated sections
  2026-09-26  0:02 [PATCH v2 bpf-next 1/2] libbpf: Fix static linking of externs placed in allocated sections Andrii Nakryiko
  2026-09-26  0:02 ` [PATCH v2 bpf-next 2/2] selftests/bpf: Add linked_externs test for externs " Andrii Nakryiko
  2026-09-26  0:50 ` [PATCH v2 bpf-next 1/2] libbpf: Fix static linking of externs placed " bot+bpf-ci
@ 2026-09-26  8:51 ` Alexei Starovoitov
  2 siblings, 0 replies; 8+ messages in thread
From: Alexei Starovoitov @ 2026-09-26  8:51 UTC (permalink / raw)
  To: Andrii Nakryiko; +Cc: bpf, Kernel Team

On Fri, Sep 25, 2026 at 5:04 PM Andrii Nakryiko <andrii@kernel.org> wrote:

it was applied. bot is asleep.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 bpf-next 2/2] selftests/bpf: Add linked_externs test for externs in allocated sections
  2026-09-26  0:02 ` [PATCH v2 bpf-next 2/2] selftests/bpf: Add linked_externs test for externs " Andrii Nakryiko
  2026-09-26  0:08   ` sashiko-bot
  2026-09-26  0:50   ` bot+bpf-ci
@ 2026-09-28 21:52   ` Vineet Gupta
  2026-09-28 21:52     ` Vineet Gupta
  2 siblings, 1 reply; 8+ messages in thread
From: Vineet Gupta @ 2026-09-28 21:52 UTC (permalink / raw)
  To: Andrii Nakryiko, bpf; +Cc: kernel-team, Ihor Solodrai

Hi Andrii,

On 9/25/26 5:02 PM, Andrii Nakryiko wrote:
> Add two objects that define an arena global each and declare the
> other one's as extern, linked into a single skeleton with the
> extern-declaring object first.
> 
> The skeleton build relinks the linked object twice more, which fixes
> up DATASEC offsets from the ELF symbol table, so the test also drives
> the libbpf linker directly: it links linked_arena1.bpf.o on its own,
> links the result with linked_arena2.bpf.o, checks that no variable in
> the .addr_space.1 DATASEC is left extern, and loads the object. The
> same is done with linked_maps1/2.bpf.o, which have an extern map in
> .maps.
> 
> Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
> ---
>   tools/testing/selftests/bpf/Makefile.skel     |   3 +-
>   .../selftests/bpf/prog_tests/linked_externs.c | 109 ++++++++++++++++++
>   .../selftests/bpf/progs/linked_arena1.c       |  22 ++++
>   .../selftests/bpf/progs/linked_arena2.c       |  18 +++
>   4 files changed, 151 insertions(+), 1 deletion(-)
>   create mode 100644 tools/testing/selftests/bpf/prog_tests/linked_externs.c
>   create mode 100644 tools/testing/selftests/bpf/progs/linked_arena1.c
>   create mode 100644 tools/testing/selftests/bpf/progs/linked_arena2.c

This is tripping up CI, fails with BPF_GCC [1] and some more (sched-ext)
Fix for gcc build failure is posted here [2]

[1] https://github.com/kernel-patches/bpf/actions/runs/36243003457
[2] 
https://lore.kernel.org/bpf/20260928215110.3966357-1-vineet.gupta@linux.dev/T/#u

Thx,
-Vineet

> 
> diff --git a/tools/testing/selftests/bpf/Makefile.skel b/tools/testing/selftests/bpf/Makefile.skel
> index 3d92cdca62ed..2e22bb901bf3 100644
> --- a/tools/testing/selftests/bpf/Makefile.skel
> +++ b/tools/testing/selftests/bpf/Makefile.skel
> @@ -23,7 +23,7 @@ BPF_OBJS := $(patsubst %.c,$(RDIR)/%.bpf.o,$(BPF_SRCS))
>   SKEL_BLACKLIST := btf__% test_pinning_invalid.c test_sk_assign.c
>   
>   LINKED_SKELS := test_static_linked.skel.h linked_funcs.skel.h		\
> -		linked_vars.skel.h linked_maps.skel.h 			\
> +		linked_vars.skel.h linked_maps.skel.h linked_arena.skel.h \
>   		test_subskeleton.skel.h test_subskeleton_lib.skel.h	\
>   		test_usdt.skel.h tracing_multi.skel.h			\
>   		tracing_multi_module.skel.h				\
> @@ -46,6 +46,7 @@ test_static_linked.skel.h-deps := test_static_linked1.bpf.o test_static_linked2.
>   linked_funcs.skel.h-deps := linked_funcs1.bpf.o linked_funcs2.bpf.o
>   linked_vars.skel.h-deps := linked_vars1.bpf.o linked_vars2.bpf.o
>   linked_maps.skel.h-deps := linked_maps1.bpf.o linked_maps2.bpf.o
> +linked_arena.skel.h-deps := linked_arena1.bpf.o linked_arena2.bpf.o
>   # In the subskeleton case, we want the test_subskeleton_lib.subskel.h file
>   # but that's created as a side-effect of the skel.h generation.
>   test_subskeleton.skel.h-deps := test_subskeleton_lib2.bpf.o test_subskeleton_lib.bpf.o test_subskeleton.bpf.o
> diff --git a/tools/testing/selftests/bpf/prog_tests/linked_externs.c b/tools/testing/selftests/bpf/prog_tests/linked_externs.c
> new file mode 100644
> index 000000000000..29358c82dc35
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/linked_externs.c
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
> +#include <test_progs.h>
> +#include <bpf/btf.h>
> +#include "linked_arena.skel.h"
> +
> +static void test_skel(void)
> +{
> +	LIBBPF_OPTS(bpf_test_run_opts, opts);
> +	struct linked_arena *skel;
> +	int err;
> +
> +	skel = linked_arena__open_and_load();
> +	if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
> +		return;
> +
> +	ASSERT_EQ(skel->arena->a_val, 1, "a_val_init");
> +	ASSERT_EQ(skel->arena->b_val, 2, "b_val_init");
> +
> +	err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.sum1), &opts);
> +	ASSERT_OK(err, "sum1_run");
> +	ASSERT_EQ(opts.retval, 1 + 2, "sum1_retval");
> +
> +	err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.bump2), &opts);
> +	ASSERT_OK(err, "bump2_run");
> +	ASSERT_EQ(opts.retval, 11 + 22, "bump2_retval");
> +
> +	ASSERT_EQ(skel->arena->a_val, 11, "a_val");
> +	ASSERT_EQ(skel->arena->b_val, 22, "b_val");
> +
> +	linked_arena__destroy(skel);
> +}
> +
> +static int link_objs(const char *out, const char *in1, const char *in2)
> +{
> +	struct bpf_linker *linker;
> +	int err;
> +
> +	linker = bpf_linker__new(out, NULL);
> +	if (!ASSERT_OK_PTR(linker, "linker_new"))
> +		return -EINVAL;
> +
> +	err = bpf_linker__add_file(linker, in1, NULL);
> +	if (!ASSERT_OK(err, in1))
> +		goto cleanup;
> +	if (in2) {
> +		err = bpf_linker__add_file(linker, in2, NULL);
> +		if (!ASSERT_OK(err, in2))
> +			goto cleanup;
> +	}
> +	err = bpf_linker__finalize(linker);
> +	ASSERT_OK(err, "finalize");
> +
> +cleanup:
> +	bpf_linker__free(linker);
> +	return err;
> +}
> +
> +/* link in1 on its own first, then link the result with in2 */
> +static void test_relink(const char *in1, const char *in2, const char *sec_name)
> +{
> +	char out1[] = "/tmp/linked_externs.XXXXXX", out2[] = "/tmp/linked_externs.XXXXXX";
> +	const struct btf_var_secinfo *vi;
> +	struct bpf_object *obj = NULL;
> +	const struct btf_type *t;
> +	struct btf *btf;
> +	int i, id, n;
> +
> +	close(mkstemp(out1));
> +	close(mkstemp(out2));
> +
> +	if (!ASSERT_OK(link_objs(out1, in1, NULL), "link_stage1") ||
> +	    !ASSERT_OK(link_objs(out2, out1, in2), "link_stage2"))
> +		goto cleanup;
> +
> +	obj = bpf_object__open_file(out2, NULL);
> +	if (!ASSERT_OK_PTR(obj, "obj_open"))
> +		goto cleanup;
> +
> +	btf = bpf_object__btf(obj);
> +	id = btf__find_by_name_kind(btf, sec_name, BTF_KIND_DATASEC);
> +	if (!ASSERT_GT(id, 0, "find_datasec"))
> +		goto cleanup;
> +
> +	t = btf__type_by_id(btf, id);
> +	vi = btf_var_secinfos(t);
> +	n = btf_vlen(t);
> +	for (i = 0; i < n; i++) {
> +		t = btf__type_by_id(btf, vi[i].type);
> +		ASSERT_NEQ(btf_var(t)->linkage, BTF_VAR_GLOBAL_EXTERN, "var_resolved");
> +	}
> +
> +	ASSERT_OK(bpf_object__load(obj), "obj_load");
> +
> +cleanup:
> +	bpf_object__close(obj);
> +	unlink(out1);
> +	unlink(out2);
> +}
> +
> +void test_linked_externs(void)
> +{
> +	if (test__start_subtest("skel_arena"))
> +		test_skel();
> +	if (test__start_subtest("relink_arena"))
> +		test_relink("linked_arena1.bpf.o", "linked_arena2.bpf.o", ".addr_space.1");
> +	if (test__start_subtest("relink_maps"))
> +		test_relink("linked_maps1.bpf.o", "linked_maps2.bpf.o", ".maps");
> +}
> diff --git a/tools/testing/selftests/bpf/progs/linked_arena1.c b/tools/testing/selftests/bpf/progs/linked_arena1.c
> new file mode 100644
> index 000000000000..3e8788dec1d9
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/linked_arena1.c
> @@ -0,0 +1,22 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
> +#include <vmlinux.h>
> +#include <bpf/bpf_helpers.h>
> +#include "bpf_arena_common.h"
> +
> +struct {
> +	__uint(type, BPF_MAP_TYPE_ARENA);
> +	__uint(map_flags, BPF_F_MMAPABLE);
> +	__uint(max_entries, 1); /* number of pages */
> +} arena SEC(".maps");
> +
> +long __arena a_val = 1;
> +extern long __arena b_val; /* defined in linked_arena2.c */
> +
> +SEC("syscall")
> +int sum1(void *ctx)
> +{
> +	return a_val + b_val;
> +}
> +
> +char _license[] SEC("license") = "GPL";
> diff --git a/tools/testing/selftests/bpf/progs/linked_arena2.c b/tools/testing/selftests/bpf/progs/linked_arena2.c
> new file mode 100644
> index 000000000000..d0bcdf18a4b6
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/linked_arena2.c
> @@ -0,0 +1,18 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
> +#include <vmlinux.h>
> +#include <bpf/bpf_helpers.h>
> +#include "bpf_arena_common.h"
> +
> +long __arena b_val = 2;
> +extern long __arena a_val; /* defined in linked_arena1.c */
> +
> +SEC("syscall")
> +int bump2(void *ctx)
> +{
> +	a_val += 10;
> +	b_val += 20;
> +	return a_val + b_val;
> +}
> +
> +char _license[] SEC("license") = "GPL";


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 bpf-next 2/2] selftests/bpf: Add linked_externs test for externs in allocated sections
  2026-09-28 21:52   ` Vineet Gupta
@ 2026-09-28 21:52     ` Vineet Gupta
  0 siblings, 0 replies; 8+ messages in thread
From: Vineet Gupta @ 2026-09-28 21:52 UTC (permalink / raw)
  To: bpf; +Cc: kernel-team, Ihor Solodrai

Hi Andrii,

On 9/25/26 5:02 PM, Andrii Nakryiko wrote:
> Add two objects that define an arena global each and declare the
> other one's as extern, linked into a single skeleton with the
> extern-declaring object first.
> 
> The skeleton build relinks the linked object twice more, which fixes
> up DATASEC offsets from the ELF symbol table, so the test also drives
> the libbpf linker directly: it links linked_arena1.bpf.o on its own,
> links the result with linked_arena2.bpf.o, checks that no variable in
> the .addr_space.1 DATASEC is left extern, and loads the object. The
> same is done with linked_maps1/2.bpf.o, which have an extern map in
> .maps.
> 
> Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
> ---
>   tools/testing/selftests/bpf/Makefile.skel     |   3 +-
>   .../selftests/bpf/prog_tests/linked_externs.c | 109 ++++++++++++++++++
>   .../selftests/bpf/progs/linked_arena1.c       |  22 ++++
>   .../selftests/bpf/progs/linked_arena2.c       |  18 +++
>   4 files changed, 151 insertions(+), 1 deletion(-)
>   create mode 100644 tools/testing/selftests/bpf/prog_tests/linked_externs.c
>   create mode 100644 tools/testing/selftests/bpf/progs/linked_arena1.c
>   create mode 100644 tools/testing/selftests/bpf/progs/linked_arena2.c

This is tripping up CI, fails with BPF_GCC [1] and some more (sched-ext)
Fix for gcc build failure is posted here [2]

[1] https://github.com/kernel-patches/bpf/actions/runs/36243003457
[2] 
https://lore.kernel.org/bpf/20260928215110.3966357-1-vineet.gupta@linux.dev/T/#u

Thx,
-Vineet

> 
> diff --git a/tools/testing/selftests/bpf/Makefile.skel b/tools/testing/selftests/bpf/Makefile.skel
> index 3d92cdca62ed..2e22bb901bf3 100644
> --- a/tools/testing/selftests/bpf/Makefile.skel
> +++ b/tools/testing/selftests/bpf/Makefile.skel
> @@ -23,7 +23,7 @@ BPF_OBJS := $(patsubst %.c,$(RDIR)/%.bpf.o,$(BPF_SRCS))
>   SKEL_BLACKLIST := btf__% test_pinning_invalid.c test_sk_assign.c
>   
>   LINKED_SKELS := test_static_linked.skel.h linked_funcs.skel.h		\
> -		linked_vars.skel.h linked_maps.skel.h 			\
> +		linked_vars.skel.h linked_maps.skel.h linked_arena.skel.h \
>   		test_subskeleton.skel.h test_subskeleton_lib.skel.h	\
>   		test_usdt.skel.h tracing_multi.skel.h			\
>   		tracing_multi_module.skel.h				\
> @@ -46,6 +46,7 @@ test_static_linked.skel.h-deps := test_static_linked1.bpf.o test_static_linked2.
>   linked_funcs.skel.h-deps := linked_funcs1.bpf.o linked_funcs2.bpf.o
>   linked_vars.skel.h-deps := linked_vars1.bpf.o linked_vars2.bpf.o
>   linked_maps.skel.h-deps := linked_maps1.bpf.o linked_maps2.bpf.o
> +linked_arena.skel.h-deps := linked_arena1.bpf.o linked_arena2.bpf.o
>   # In the subskeleton case, we want the test_subskeleton_lib.subskel.h file
>   # but that's created as a side-effect of the skel.h generation.
>   test_subskeleton.skel.h-deps := test_subskeleton_lib2.bpf.o test_subskeleton_lib.bpf.o test_subskeleton.bpf.o
> diff --git a/tools/testing/selftests/bpf/prog_tests/linked_externs.c b/tools/testing/selftests/bpf/prog_tests/linked_externs.c
> new file mode 100644
> index 000000000000..29358c82dc35
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/linked_externs.c
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
> +#include <test_progs.h>
> +#include <bpf/btf.h>
> +#include "linked_arena.skel.h"
> +
> +static void test_skel(void)
> +{
> +	LIBBPF_OPTS(bpf_test_run_opts, opts);
> +	struct linked_arena *skel;
> +	int err;
> +
> +	skel = linked_arena__open_and_load();
> +	if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
> +		return;
> +
> +	ASSERT_EQ(skel->arena->a_val, 1, "a_val_init");
> +	ASSERT_EQ(skel->arena->b_val, 2, "b_val_init");
> +
> +	err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.sum1), &opts);
> +	ASSERT_OK(err, "sum1_run");
> +	ASSERT_EQ(opts.retval, 1 + 2, "sum1_retval");
> +
> +	err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.bump2), &opts);
> +	ASSERT_OK(err, "bump2_run");
> +	ASSERT_EQ(opts.retval, 11 + 22, "bump2_retval");
> +
> +	ASSERT_EQ(skel->arena->a_val, 11, "a_val");
> +	ASSERT_EQ(skel->arena->b_val, 22, "b_val");
> +
> +	linked_arena__destroy(skel);
> +}
> +
> +static int link_objs(const char *out, const char *in1, const char *in2)
> +{
> +	struct bpf_linker *linker;
> +	int err;
> +
> +	linker = bpf_linker__new(out, NULL);
> +	if (!ASSERT_OK_PTR(linker, "linker_new"))
> +		return -EINVAL;
> +
> +	err = bpf_linker__add_file(linker, in1, NULL);
> +	if (!ASSERT_OK(err, in1))
> +		goto cleanup;
> +	if (in2) {
> +		err = bpf_linker__add_file(linker, in2, NULL);
> +		if (!ASSERT_OK(err, in2))
> +			goto cleanup;
> +	}
> +	err = bpf_linker__finalize(linker);
> +	ASSERT_OK(err, "finalize");
> +
> +cleanup:
> +	bpf_linker__free(linker);
> +	return err;
> +}
> +
> +/* link in1 on its own first, then link the result with in2 */
> +static void test_relink(const char *in1, const char *in2, const char *sec_name)
> +{
> +	char out1[] = "/tmp/linked_externs.XXXXXX", out2[] = "/tmp/linked_externs.XXXXXX";
> +	const struct btf_var_secinfo *vi;
> +	struct bpf_object *obj = NULL;
> +	const struct btf_type *t;
> +	struct btf *btf;
> +	int i, id, n;
> +
> +	close(mkstemp(out1));
> +	close(mkstemp(out2));
> +
> +	if (!ASSERT_OK(link_objs(out1, in1, NULL), "link_stage1") ||
> +	    !ASSERT_OK(link_objs(out2, out1, in2), "link_stage2"))
> +		goto cleanup;
> +
> +	obj = bpf_object__open_file(out2, NULL);
> +	if (!ASSERT_OK_PTR(obj, "obj_open"))
> +		goto cleanup;
> +
> +	btf = bpf_object__btf(obj);
> +	id = btf__find_by_name_kind(btf, sec_name, BTF_KIND_DATASEC);
> +	if (!ASSERT_GT(id, 0, "find_datasec"))
> +		goto cleanup;
> +
> +	t = btf__type_by_id(btf, id);
> +	vi = btf_var_secinfos(t);
> +	n = btf_vlen(t);
> +	for (i = 0; i < n; i++) {
> +		t = btf__type_by_id(btf, vi[i].type);
> +		ASSERT_NEQ(btf_var(t)->linkage, BTF_VAR_GLOBAL_EXTERN, "var_resolved");
> +	}
> +
> +	ASSERT_OK(bpf_object__load(obj), "obj_load");
> +
> +cleanup:
> +	bpf_object__close(obj);
> +	unlink(out1);
> +	unlink(out2);
> +}
> +
> +void test_linked_externs(void)
> +{
> +	if (test__start_subtest("skel_arena"))
> +		test_skel();
> +	if (test__start_subtest("relink_arena"))
> +		test_relink("linked_arena1.bpf.o", "linked_arena2.bpf.o", ".addr_space.1");
> +	if (test__start_subtest("relink_maps"))
> +		test_relink("linked_maps1.bpf.o", "linked_maps2.bpf.o", ".maps");
> +}
> diff --git a/tools/testing/selftests/bpf/progs/linked_arena1.c b/tools/testing/selftests/bpf/progs/linked_arena1.c
> new file mode 100644
> index 000000000000..3e8788dec1d9
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/linked_arena1.c
> @@ -0,0 +1,22 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
> +#include <vmlinux.h>
> +#include <bpf/bpf_helpers.h>
> +#include "bpf_arena_common.h"
> +
> +struct {
> +	__uint(type, BPF_MAP_TYPE_ARENA);
> +	__uint(map_flags, BPF_F_MMAPABLE);
> +	__uint(max_entries, 1); /* number of pages */
> +} arena SEC(".maps");
> +
> +long __arena a_val = 1;
> +extern long __arena b_val; /* defined in linked_arena2.c */
> +
> +SEC("syscall")
> +int sum1(void *ctx)
> +{
> +	return a_val + b_val;
> +}
> +
> +char _license[] SEC("license") = "GPL";
> diff --git a/tools/testing/selftests/bpf/progs/linked_arena2.c b/tools/testing/selftests/bpf/progs/linked_arena2.c
> new file mode 100644
> index 000000000000..d0bcdf18a4b6
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/linked_arena2.c
> @@ -0,0 +1,18 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
> +#include <vmlinux.h>
> +#include <bpf/bpf_helpers.h>
> +#include "bpf_arena_common.h"
> +
> +long __arena b_val = 2;
> +extern long __arena a_val; /* defined in linked_arena1.c */
> +
> +SEC("syscall")
> +int bump2(void *ctx)
> +{
> +	a_val += 10;
> +	b_val += 20;
> +	return a_val + b_val;
> +}
> +
> +char _license[] SEC("license") = "GPL";



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-09-28 21:53 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-26  0:02 [PATCH v2 bpf-next 1/2] libbpf: Fix static linking of externs placed in allocated sections Andrii Nakryiko
2026-09-26  0:02 ` [PATCH v2 bpf-next 2/2] selftests/bpf: Add linked_externs test for externs " Andrii Nakryiko
2026-09-26  0:08   ` sashiko-bot
2026-09-26  0:50   ` bot+bpf-ci
2026-09-28 21:52   ` Vineet Gupta
2026-09-28 21:52     ` Vineet Gupta
2026-09-26  0:50 ` [PATCH v2 bpf-next 1/2] libbpf: Fix static linking of externs placed " bot+bpf-ci
2026-09-26  8:51 ` Alexei Starovoitov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).