All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vineet Gupta <vineet.gupta@linux.dev>
To: bpf@vger.kernel.org, andrii@kernel.org, ast@kernel.org,
	daniel@iogearbox.net
Cc: eddyz87@gmail.com, memxor@gmail.com, martin.lau@linux.dev,
	song@kernel.org, yonghong.song@linux.dev, jolsa@kernel.org,
	emil@etsalapatis.com, ihor.solodrai@linux.dev,
	linux-kernel@vger.kernel.org,
	Vineet Gupta <vineet.gupta@linux.dev>
Subject: [PATCH bpf-next v2] selftests/bpf: Fix linked_externs with bpf-gcc
Date: Mon, 28 Sep 2026 16:14:41 -0700	[thread overview]
Message-ID: <20260928231441.4037097-1-vineet.gupta@linux.dev> (raw)

test_progs-bpf_gcc fails to build:

  prog_tests/linked_externs.c:17:23: error: 'struct linked_arena' has no
      member named 'arena'

Several problems, all from bpf-gcc not supporting address_space(1).

First, the arena variables are declared with __arena, but that macro is
for pointers -- it marks the pointee address space. The one that carries
placement is __arena_global:

  #if defined(__BPF_FEATURE_ADDR_SPACE_CAST) && !defined(BPF_ARENA_FORCE_ASM)
  #define __arena        __attribute__((address_space(1))) __attribute__((btf_type_tag("arena")))
  #define __arena_global __attribute__((address_space(1)))
  #else
  #define __arena        __attribute__((btf_type_tag("arena")))
  #define __arena_global SEC(".addr_space.1")
  #endif

__BPF_FEATURE_ADDR_SPACE_CAST is a clang predefine. Under clang the two
are interchangeable here, since address_space(1) both places the
variable and is what btf_type_tag would have described. Under bpf-gcc
__arena is only a BTF type tag, so the definitions land in .data, the
arena map gets no initial value, and is_skel_data() in bpftool does not
emit the typed arena member -- hence the build error. Note this is
distinct from skel->maps.arena, which comes from SEC(".maps") and is
always present.

The extern declarations need __arena_global too. Without a section, gcc
does not place an extern in any DATASEC, so it stays a free-floating
extern VAR rather than an entry of .addr_space.1. test_relink() only
walks that DATASEC:

    id = btf__find_by_name_kind(btf, sec_name, BTF_KIND_DATASEC);
    ...
        ASSERT_NEQ(btf_var(t)->linkage, BTF_VAR_GLOBAL_EXTERN, "var_resolved");

so relink_arena would report OK under bpf-gcc whether or not the linker
resolved anything -- it would not be testing the allocated-section path
this test exists for.

Second, placement alone is not enough to run the test. Dereferencing an
arena global needs an addr_space_cast, which only clang emits:

  clang:                                  bpf-gcc:
    r1 = 0x0 ll                             r1 = 0x0 ll
    r1 = addr_space_cast(r1, 0x0, 0x1)      r2 = *(u64 *)(r1 + 0x0)
    r1 = *(u64 *)(r1 + 0x0)

so the verifier sees a scalar and rejects the program:

  4: (79) r2 = *(u64 *)(r1 +0)
  R1 invalid mem access 'scalar'

Guard the program bodies and skip the skeleton subtest, as
arena_atomics.c already does. The variables stay unconditional so the
arena is still populated and the skeleton still has its member. The
fallback bodies reference the externs without dereferencing them:
'used' is ignored on an extern, so an unreferenced one is dropped and
.addr_space.1 loses it again.

With this, bpf-gcc reports:

  #217/1   linked_externs/skel_arena:SKIP
  #217/2   linked_externs/relink_arena:OK
  #217/3   linked_externs/relink_maps:OK

with b_val present in .addr_space.1 as linkage=extern, same as clang, so
relink_arena covers the same path in both. clang still passes all three.

Fixes: 34354db1b148 ("selftests/bpf: Add linked_externs test for externs in allocated sections")
Signed-off-by: Vineet Gupta <vineet.gupta@linux.dev>
---

v2:
- Declare the externs with __arena_global too. Without a section gcc
  keeps them out of the .addr_space.1 DATASEC, which is the only thing
  test_relink() inspects, so relink_arena could not fail under bpf-gcc
  regardless of the linker (bpf-ci).
- Link to v1: https://lore.kernel.org/bpf/20260928215110.3966357-1-vineet.gupta@linux.dev/
 .../selftests/bpf/prog_tests/linked_externs.c | 15 ++++++++++--
 .../selftests/bpf/progs/linked_arena1.c       | 24 +++++++++++++++++--
 .../selftests/bpf/progs/linked_arena2.c       |  8 +++++--
 3 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/linked_externs.c b/tools/testing/selftests/bpf/prog_tests/linked_externs.c
index 29358c82dc35..ff568f5cfc42 100644
--- a/tools/testing/selftests/bpf/prog_tests/linked_externs.c
+++ b/tools/testing/selftests/bpf/prog_tests/linked_externs.c
@@ -10,10 +10,20 @@ static void test_skel(void)
 	struct linked_arena *skel;
 	int err;
 
-	skel = linked_arena__open_and_load();
-	if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
+	skel = linked_arena__open();
+	if (!ASSERT_OK_PTR(skel, "skel_open"))
 		return;
 
+	if (skel->data->skip_tests) {
+		printf("%s:SKIP: no addr_space_cast support in the BPF compiler\n", __func__);
+		test__skip();
+		goto cleanup;
+	}
+
+	err = linked_arena__load(skel);
+	if (!ASSERT_OK(err, "skel_load"))
+		goto cleanup;
+
 	ASSERT_EQ(skel->arena->a_val, 1, "a_val_init");
 	ASSERT_EQ(skel->arena->b_val, 2, "b_val_init");
 
@@ -28,6 +38,7 @@ static void test_skel(void)
 	ASSERT_EQ(skel->arena->a_val, 11, "a_val");
 	ASSERT_EQ(skel->arena->b_val, 22, "b_val");
 
+cleanup:
 	linked_arena__destroy(skel);
 }
 
diff --git a/tools/testing/selftests/bpf/progs/linked_arena1.c b/tools/testing/selftests/bpf/progs/linked_arena1.c
index 3e8788dec1d9..5027b4ac2887 100644
--- a/tools/testing/selftests/bpf/progs/linked_arena1.c
+++ b/tools/testing/selftests/bpf/progs/linked_arena1.c
@@ -10,13 +10,33 @@ struct {
 	__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 */
+/*
+ * Dereferencing an arena global needs the compiler to emit an
+ * addr_space_cast, which only clang does. Keep the variables so the arena
+ * is still populated and the skeleton still has its arena member, but skip
+ * the test elsewhere.
+ */
+#ifdef __BPF_FEATURE_ADDR_SPACE_CAST
+bool skip_tests __attribute((__section__(".data"))) = false;
+#else
+bool skip_tests = true;
+#endif
+
+long __arena_global a_val = 1;
+extern long __arena_global b_val; /* defined in linked_arena2.c */
 
 SEC("syscall")
 int sum1(void *ctx)
 {
+#ifdef __BPF_FEATURE_ADDR_SPACE_CAST
 	return a_val + b_val;
+#else
+	/*
+	 * Reference the extern without dereferencing it, so that the relink
+	 * test still has an extern to resolve.
+	 */
+	return (long)&b_val;
+#endif
 }
 
 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
index d0bcdf18a4b6..db37198854a3 100644
--- a/tools/testing/selftests/bpf/progs/linked_arena2.c
+++ b/tools/testing/selftests/bpf/progs/linked_arena2.c
@@ -4,15 +4,19 @@
 #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 */
+long __arena_global b_val = 2;
+extern long __arena_global a_val; /* defined in linked_arena1.c */
 
 SEC("syscall")
 int bump2(void *ctx)
 {
+#ifdef __BPF_FEATURE_ADDR_SPACE_CAST
 	a_val += 10;
 	b_val += 20;
 	return a_val + b_val;
+#else /* see linked_arena1.c */
+	return (long)&a_val;
+#endif
 }
 
 char _license[] SEC("license") = "GPL";
-- 
2.53.0-Meta


             reply	other threads:[~2026-09-28 23:14 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-28 23:14 Vineet Gupta [this message]
2026-09-29  0:01 ` [PATCH bpf-next v2] selftests/bpf: Fix linked_externs with bpf-gcc Ihor Solodrai
2026-09-29  0:26   ` Andrii Nakryiko
2026-09-29  0:30 ` patchwork-bot+netdevbpf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260928231441.4037097-1-vineet.gupta@linux.dev \
    --to=vineet.gupta@linux.dev \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=emil@etsalapatis.com \
    --cc=ihor.solodrai@linux.dev \
    --cc=jolsa@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=memxor@gmail.com \
    --cc=song@kernel.org \
    --cc=yonghong.song@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.