From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from 66-220-144-179.mail-mxout.facebook.com (66-220-144-179.mail-mxout.facebook.com [66.220.144.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A9E352EC09B for ; Wed, 9 Sep 2026 06:26:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=66.220.144.179 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788935186; cv=none; b=QUOMqm4GYx3hbrUMSZ/MGq4k9RwIhfxLCPOGim+t/gaN8L5mcGPHaAduLTIpATQP3e2Ditp7CLczun4YczjBlcGSq5PjizFo4twMDQBCle4YKQC0Nzt/FhyVmhy/ZWzpiO0YUV9IJsEQJ8diDMJGAFJWB+1fXdfbZSrDuuXomYE= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788935186; c=relaxed/simple; bh=1Q0EcthOAram9Mjgjv+8A85Z/4DljIYTjAYOG2DhyfY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jhxpeWfApIdkl6QXSDLpB3TceATai/kt92P2c9/fOjZJ+2CLui58yrjhey+ucu78CJ/xfrRp762aKZi7wWycAKAWqpYmab8yB/u3hIP/lnGNlyVYJkErP8w8VsagHIRsltvE+sjz7sjwI2WnDY6hvHOQ8w0g2ExkTP2ReUYiB9s= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.dev; spf=fail smtp.mailfrom=linux.dev; arc=none smtp.client-ip=66.220.144.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=linux.dev Received: by devvm16039.vll0.facebook.com (Postfix, from userid 128203) id 2A037299489727; Tue, 8 Sep 2026 23:26:21 -0700 (PDT) From: Yonghong Song To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Eduard Zingerman , kernel-team@fb.com Subject: [PATCH bpf-next v2 11/12] selftests/bpf: Add inline-asm tests for by-value arguments Date: Tue, 8 Sep 2026 23:26:21 -0700 Message-ID: <20260909062621.4009625-1-yonghong.song@linux.dev> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260909062522.4001896-1-yonghong.song@linux.dev> References: <20260909062522.4001896-1-yonghong.song@linux.dev> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable The tests cover a struct passed in a register pair, a pointer in one half of it refused at the call site, a struct too large to pass by value, and three placements a global function cannot have: a struct split between th= e last argument register and the stack, one wholly past the registers, and an __int128 whose two slots push the last parameter out. GCC passes an aggregate by invisible reference, so a callee it compiles expects a pointer where BTF says the halves of the struct are, and those tests are left to clang. Signed-off-by: Yonghong Song --- .../selftests/bpf/prog_tests/aggregate_arg.c | 9 + .../selftests/bpf/progs/aggregate_arg_func.c | 155 ++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/aggregate_arg.= c create mode 100644 tools/testing/selftests/bpf/progs/aggregate_arg_func.= c diff --git a/tools/testing/selftests/bpf/prog_tests/aggregate_arg.c b/too= ls/testing/selftests/bpf/prog_tests/aggregate_arg.c new file mode 100644 index 000000000000..b230f3bd3b2a --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/aggregate_arg.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ +#include +#include "aggregate_arg_func.skel.h" + +void test_aggregate_arg(void) +{ + RUN_TESTS(aggregate_arg_func); +} diff --git a/tools/testing/selftests/bpf/progs/aggregate_arg_func.c b/too= ls/testing/selftests/bpf/progs/aggregate_arg_func.c new file mode 100644 index 000000000000..61dd5f86c3a4 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/aggregate_arg_func.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ +#include +#include +#include "bpf_misc.h" + +typedef unsigned __int128 u128; + +struct pair { + __u64 lo; + __u64 hi; +}; + +struct too_big { + __u64 a; + __u64 b; + __u64 c; +}; + +#if defined(__clang__) + +__noinline __u64 global_arg_pair(int a, struct pair p, int c) +{ + return (__u64)a + p.lo + p.hi + c; +} + +SEC("tc") +__success __retval(0x33) +__naked int aggregate_arg_pair_asm(void) +{ + asm volatile ( + "r1 =3D 1;" + "r2 =3D 0x10;" /* p.lo */ + "r3 =3D 0x20;" /* p.hi */ + "r4 =3D 2;" + "call %[global_arg_pair];" + "exit;" + : + : __imm(global_arg_pair) + : __clobber_all); +} + +SEC("tc") +__failure __msg("R2 is not a scalar") +__naked int aggregate_arg_pair_ptr_fail(void) +{ + asm volatile ( + "r1 =3D 1;" + "r2 =3D r10;" /* a stack pointer where p.lo belongs */ + "r3 =3D 0x20;" + "r4 =3D 2;" + "call %[global_arg_pair];" + "exit;" + : + : __imm(global_arg_pair) + : __clobber_all); +} + +#endif + +__noinline __u64 global_arg_too_big(struct too_big s) +{ + return s.a + s.b + s.c; +} + +SEC("tc") +__failure __msg("in global_arg_too_big() has size 24, only 1 to 16 bytes= can be passed by value") +__naked int aggregate_arg_too_big_fail(void) +{ + asm volatile ( + "r1 =3D 0;" + "r2 =3D 0;" + "r3 =3D 0;" + "call %[global_arg_too_big];" + "r0 =3D 0;" + "exit;" + : + : __imm(global_arg_too_big) + : __clobber_all); +} + +#if defined(__BPF_FEATURE_STACK_ARGUMENT) + +__noinline __u64 global_arg_split(int a, int b, int c, int d, struct pai= r p) +{ + return (__u64)a + b + c + d + p.lo + p.hi; +} + +SEC("tc") +__failure __msg("global function global_arg_split() needs 6 > 5 argument= slots") +__naked int aggregate_arg_split_fail(void) +{ + asm volatile ( + "r1 =3D 0;" + "r2 =3D 0;" + "r3 =3D 0;" + "r4 =3D 0;" + "r5 =3D 0;" + "call %[global_arg_split];" + "r0 =3D 0;" + "exit;" + : + : __imm(global_arg_split) + : __clobber_all); +} + +__noinline __u64 global_arg_past_regs(struct pair p, struct pair q, int = a, struct pair r) +{ + return p.lo + p.hi + q.lo + q.hi + a + r.lo + r.hi; +} + +SEC("tc") +__failure __msg("global function global_arg_past_regs() needs 7 > 5 argu= ment slots") +__naked int aggregate_arg_past_regs_fail(void) +{ + asm volatile ( + "r1 =3D 0;" + "r2 =3D 0;" + "r3 =3D 0;" + "r4 =3D 0;" + "r5 =3D 0;" + "call %[global_arg_past_regs];" + "r0 =3D 0;" + "exit;" + : + : __imm(global_arg_past_regs) + : __clobber_all); +} + +__noinline __u64 global_arg_i128_slots(u128 v, int a, int b, int c, int = d) +{ + return (__u64)v + a + b + c + d; +} + +SEC("tc") +__failure __msg("global function global_arg_i128_slots() needs 6 > 5 arg= ument slots") +__naked int aggregate_arg_i128_slots_fail(void) +{ + asm volatile ( + "r1 =3D 0;" + "r2 =3D 0;" + "r3 =3D 0;" + "r4 =3D 0;" + "r5 =3D 0;" + "call %[global_arg_i128_slots];" + "r0 =3D 0;" + "exit;" + : + : __imm(global_arg_i128_slots) + : __clobber_all); +} + +#endif + +char _license[] SEC("license") =3D "GPL"; --=20 2.53.0-Meta