blob: 2132b926a8f086c7cfdcc016fcb50811483956c0 [file] [edit]
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#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";