mirror of
https://github.com/torvalds/linux.git
synced 2026-11-10 17:11:02 +01:00
selftests/bpf: Add linked_externs test for externs in allocated sections
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> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20260926000243.2830819-2-andrii@kernel.org
This commit is contained in:
parent
d07d3efd01
commit
34354db1b1
|
|
@ -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
|
||||
|
|
|
|||
109
tools/testing/selftests/bpf/prog_tests/linked_externs.c
Normal file
109
tools/testing/selftests/bpf/prog_tests/linked_externs.c
Normal file
|
|
@ -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");
|
||||
}
|
||||
22
tools/testing/selftests/bpf/progs/linked_arena1.c
Normal file
22
tools/testing/selftests/bpf/progs/linked_arena1.c
Normal file
|
|
@ -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";
|
||||
18
tools/testing/selftests/bpf/progs/linked_arena2.c
Normal file
18
tools/testing/selftests/bpf/progs/linked_arena2.c
Normal file
|
|
@ -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";
|
||||
Loading…
Reference in New Issue
Block a user