1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
// 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";
|