// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ #include #include #include "bpf_misc.h" #ifdef __SIZEOF_INT128__ typedef unsigned __int128 u128; #endif 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 = 1;" "r2 = 0x10;" /* p.lo */ "r3 = 0x20;" /* p.hi */ "r4 = 2;" "call %[global_arg_pair];" "exit;" : : __imm(global_arg_pair) : __clobber_all); } SEC("tc") __failure __msg("R2 type=fp expected=scalar") __naked int aggregate_arg_pair_ptr_fail(void) { asm volatile ( "r1 = 1;" "r2 = r10;" /* a stack pointer where p.lo belongs */ "r3 = 0x20;" "r4 = 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 = 0;" "r2 = 0;" "r3 = 0;" "call %[global_arg_too_big];" "r0 = 0;" "exit;" : : __imm(global_arg_too_big) : __clobber_all); } #if defined(__BPF_FEATURE_STACK_ARGUMENT) /* * One slot per parameter, so the slot count is settled before the parameters * are walked. The cases below reach the same count only once they have been. */ __noinline __u64 global_arg_six_scalars(int a, int b, int c, int d, int e, int f) { return (__u64)a + b + c + d + e + f; } SEC("tc") __failure __msg("global function global_arg_six_scalars() needs 6 > 5 argument slots") __naked int aggregate_arg_six_scalars_fail(void) { asm volatile ( "r1 = 0;" "r2 = 0;" "r3 = 0;" "r4 = 0;" "r5 = 0;" "call %[global_arg_six_scalars];" "r0 = 0;" "exit;" : : __imm(global_arg_six_scalars) : __clobber_all); } __noinline __u64 global_arg_split(int a, int b, int c, int d, struct pair 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 = 0;" "r2 = 0;" "r3 = 0;" "r4 = 0;" "r5 = 0;" "call %[global_arg_split];" "r0 = 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 argument slots") __naked int aggregate_arg_past_regs_fail(void) { asm volatile ( "r1 = 0;" "r2 = 0;" "r3 = 0;" "r4 = 0;" "r5 = 0;" "call %[global_arg_past_regs];" "r0 = 0;" "exit;" : : __imm(global_arg_past_regs) : __clobber_all); } #ifdef __SIZEOF_INT128__ __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 argument slots") __naked int aggregate_arg_i128_slots_fail(void) { asm volatile ( "r1 = 0;" "r2 = 0;" "r3 = 0;" "r4 = 0;" "r5 = 0;" "call %[global_arg_i128_slots];" "r0 = 0;" "exit;" : : __imm(global_arg_i128_slots) : __clobber_all); } #endif /* __SIZEOF_INT128__ */ #endif char _license[] SEC("license") = "GPL";