Skip to content

Commit 44cee8d

Browse files
author
Alexei Starovoitov
committed
Merge branch 'bpf-arm64-stack-argument-fixes'
Puranjay Mohan says: ==================== bpf, arm64: Stack argument fixes Patch 1 fixes a redundant MOV in the arm64 JIT's emit_stack_arg_store_imm() and clarifies the stack layout comments. This is not a bug fix but an improvement. Patch 2 bumps the stack argument tests from 6-8 args to at least 10 so they actually exercise the native stack on arm64, where x0-x7 cover the first 8 arguments. ==================== Link: https://patch.msgid.link/20260528161750.1900674-1-puranjay@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2 parents 41300d0 + 157317b commit 44cee8d

6 files changed

Lines changed: 115 additions & 77 deletions

File tree

arch/arm64/net/bpf_jit_comp.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,8 @@ static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
546546
* low
547547
*
548548
* Stack args 6-8 are passed in x5-x7, args 9+ at [SP].
549-
* Incoming args 9+ are at [FP + 16], [FP + 24], ...
549+
* Incoming args 9+ are at [A64_FP + 16], [A64_FP + 24], ...
550+
* (above the saved FP/LR pair pushed in the callee prologue).
550551
*/
551552

552553
emit_kcfi(is_main_prog ? cfi_bpf_hash : cfi_bpf_subprog_hash, ctx);
@@ -1235,11 +1236,12 @@ static void emit_stack_arg_store_imm(s32 imm, s16 bpf_off, const u8 tmp, struct
12351236
{
12361237
int idx = -bpf_off / sizeof(u64) - 1;
12371238

1238-
emit_a64_mov_i(1, tmp, imm, ctx);
1239-
if (idx < NR_STACK_ARG_REGS)
1240-
emit(A64_MOV(1, stack_arg_reg[idx], tmp), ctx);
1241-
else
1239+
if (idx < NR_STACK_ARG_REGS) {
1240+
emit_a64_mov_i(1, stack_arg_reg[idx], imm, ctx);
1241+
} else {
1242+
emit_a64_mov_i(1, tmp, imm, ctx);
12421243
emit(A64_STR64I(tmp, A64_SP, (idx - NR_STACK_ARG_REGS) * sizeof(u64)), ctx);
1244+
}
12431245
}
12441246

12451247
/* JITs an eBPF instruction.

tools/testing/selftests/bpf/prog_tests/stack_arg.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ static void test_global_many(void)
3737
if (!ASSERT_OK(stack_arg__load(skel), "load"))
3838
goto out;
3939

40-
run_subtest(skel->progs.test_global_many_args, 36);
40+
run_subtest(skel->progs.test_global_many_args, 55);
4141

4242
out:
4343
stack_arg__destroy(skel);
@@ -62,10 +62,10 @@ static void test_async_cb_many(void)
6262
run_subtest(skel->progs.test_async_cb_many_args, 0);
6363

6464
/* Wait for the timer callback to fire and verify the result.
65-
* 10+20+30+40+50+60+70+80 = 360
65+
* 10+20+30+40+50+60+70+80+90+100 = 550
6666
*/
6767
usleep(50);
68-
ASSERT_EQ(skel->bss->timer_result, 360, "timer_result");
68+
ASSERT_EQ(skel->bss->timer_result, 550, "timer_result");
6969

7070
out:
7171
stack_arg__destroy(skel);
@@ -87,11 +87,11 @@ static void test_bpf2bpf(void)
8787
if (!ASSERT_OK(stack_arg__load(skel), "load"))
8888
goto out;
8989

90-
run_subtest(skel->progs.test_bpf2bpf_ptr_stack_arg, 45);
91-
run_subtest(skel->progs.test_bpf2bpf_mix_stack_args, 51);
92-
run_subtest(skel->progs.test_bpf2bpf_nesting_stack_arg, 50);
93-
run_subtest(skel->progs.test_bpf2bpf_dynptr_stack_arg, 69);
94-
run_subtest(skel->progs.test_two_callees, 91);
90+
run_subtest(skel->progs.test_bpf2bpf_ptr_stack_arg, 75);
91+
run_subtest(skel->progs.test_bpf2bpf_mix_stack_args, 66);
92+
run_subtest(skel->progs.test_bpf2bpf_nesting_stack_arg, 84);
93+
run_subtest(skel->progs.test_bpf2bpf_dynptr_stack_arg, 99);
94+
run_subtest(skel->progs.test_two_callees, 133);
9595

9696
out:
9797
stack_arg__destroy(skel);
@@ -113,14 +113,14 @@ static void test_kfunc(void)
113113
if (!ASSERT_OK(stack_arg_kfunc__load(skel), "load"))
114114
goto out;
115115

116-
run_subtest(skel->progs.test_stack_arg_scalar, 36);
117-
run_subtest(skel->progs.test_stack_arg_ptr, 45);
118-
run_subtest(skel->progs.test_stack_arg_mix, 51);
119-
run_subtest(skel->progs.test_stack_arg_dynptr, 69);
116+
run_subtest(skel->progs.test_stack_arg_scalar, 55);
117+
run_subtest(skel->progs.test_stack_arg_ptr, 75);
118+
run_subtest(skel->progs.test_stack_arg_mix, 66);
119+
run_subtest(skel->progs.test_stack_arg_dynptr, 99);
120120
run_subtest(skel->progs.test_stack_arg_mem, 151);
121-
run_subtest(skel->progs.test_stack_arg_iter, 115);
122-
run_subtest(skel->progs.test_stack_arg_const_str, 15);
123-
run_subtest(skel->progs.test_stack_arg_timer, 15);
121+
run_subtest(skel->progs.test_stack_arg_iter, 145);
122+
run_subtest(skel->progs.test_stack_arg_const_str, 45);
123+
run_subtest(skel->progs.test_stack_arg_timer, 45);
124124

125125
out:
126126
stack_arg_kfunc__destroy(skel);

tools/testing/selftests/bpf/progs/stack_arg.c

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,16 @@ int timer_result;
2727
const volatile bool has_stack_arg = true;
2828

2929
__noinline static int static_func_many_args(int a, int b, int c, int d,
30-
int e, int f, int g, int h)
30+
int e, int f, int g, int h,
31+
int i, int j)
3132
{
32-
return a + b + c + d + e + f + g + h;
33+
return a + b + c + d + e + f + g + h + i + j;
3334
}
3435

3536
__noinline int global_calls_many_args(int a, int b, int c)
3637
{
37-
return static_func_many_args(a, b, c, 4, 5, 6, 7, 8);
38+
return static_func_many_args(a, b, c, a + 3, a + 4, a + 5, a + 6,
39+
a + 7, a + 8, a + 9);
3840
}
3941

4042
SEC("tc")
@@ -48,18 +50,20 @@ struct test_data {
4850
long y;
4951
};
5052

51-
/* 1 + 2 + 3 + 4 + 5 + 10 + 20 = 45 */
53+
/* 1+2+3+4+5+6+7+8+9+10+20 = 75 */
5254
__noinline static long func_with_ptr_stack_arg(long a, long b, long c, long d,
53-
long e, struct test_data *p)
55+
long e, long f, long g, long h,
56+
long i, struct test_data *p)
5457
{
55-
return a + b + c + d + e + p->x + p->y;
58+
return a + b + c + d + e + f + g + h + i + p->x + p->y;
5659
}
5760

5861
__noinline long global_ptr_stack_arg(long a, long b, long c, long d, long e)
5962
{
6063
struct test_data data = { .x = 10, .y = 20 };
6164

62-
return func_with_ptr_stack_arg(a, b, c, d, e, &data);
65+
return func_with_ptr_stack_arg(a, b, c, d, e, a + 5, a + 6, a + 7,
66+
a + 8, &data);
6367
}
6468

6569
SEC("tc")
@@ -68,20 +72,22 @@ int test_bpf2bpf_ptr_stack_arg(void)
6872
return global_ptr_stack_arg(1, 2, 3, 4, 5);
6973
}
7074

71-
/* 1 + 2 + 3 + 4 + 5 + 10 + 6 + 20 = 51 */
75+
/* 1+2+3+4+5+6+7+10+8+20 = 66 */
7276
__noinline static long func_with_mix_stack_args(long a, long b, long c, long d,
73-
long e, struct test_data *p,
74-
long f, struct test_data *q)
77+
long e, long f, long g,
78+
struct test_data *p,
79+
long h, struct test_data *q)
7580
{
76-
return a + b + c + d + e + p->x + f + q->y;
81+
return a + b + c + d + e + f + g + p->x + h + q->y;
7782
}
7883

7984
__noinline long global_mix_stack_args(long a, long b, long c, long d, long e)
8085
{
8186
struct test_data p = { .x = 10 };
8287
struct test_data q = { .y = 20 };
8388

84-
return func_with_mix_stack_args(a, b, c, d, e, &p, e + 1, &q);
89+
return func_with_mix_stack_args(a, b, c, d, e, e + 1, e + 2, &p,
90+
e + 3, &q);
8591
}
8692

8793
SEC("tc")
@@ -94,26 +100,30 @@ int test_bpf2bpf_mix_stack_args(void)
94100
* Nesting test: func_outer calls func_inner, both with struct pointer
95101
* as stack arg.
96102
*
97-
* func_inner: (a+1) + (b+1) + (c+1) + (d+1) + (e+1) + p->x + p->y
98-
* = 2 + 3 + 4 + 5 + 6 + 10 + 20 = 50
103+
* func_inner: (a+1)+...+(i+1) + p->x + p->y
104+
* = 2+3+4+5+6+7+8+9+10+10+20 = 84
99105
*/
100106
__noinline static long func_inner_ptr(long a, long b, long c, long d,
101-
long e, struct test_data *p)
107+
long e, long f, long g, long h,
108+
long i, struct test_data *p)
102109
{
103-
return a + b + c + d + e + p->x + p->y;
110+
return a + b + c + d + e + f + g + h + i + p->x + p->y;
104111
}
105112

106113
__noinline static long func_outer_ptr(long a, long b, long c, long d,
107-
long e, struct test_data *p)
114+
long e, long f, long g, long h,
115+
long i, struct test_data *p)
108116
{
109-
return func_inner_ptr(a + 1, b + 1, c + 1, d + 1, e + 1, p);
117+
return func_inner_ptr(a + 1, b + 1, c + 1, d + 1, e + 1,
118+
f + 1, g + 1, h + 1, i + 1, p);
110119
}
111120

112121
__noinline long global_nesting_ptr(long a, long b, long c, long d, long e)
113122
{
114123
struct test_data data = { .x = 10, .y = 20 };
115124

116-
return func_outer_ptr(a, b, c, d, e, &data);
125+
return func_outer_ptr(a, b, c, d, e, a + 5, a + 6, a + 7, a + 8,
126+
&data);
117127
}
118128

119129
SEC("tc")
@@ -122,11 +132,12 @@ int test_bpf2bpf_nesting_stack_arg(void)
122132
return global_nesting_ptr(1, 2, 3, 4, 5);
123133
}
124134

125-
/* 1 + 2 + 3 + 4 + 5 + sizeof(pkt_v4) = 15 + 54 = 69 */
135+
/* 1+2+3+4+5+6+7+8+9+sizeof(pkt_v4) = 45+54 = 99 */
126136
__noinline static long func_with_dynptr(long a, long b, long c, long d,
127-
long e, struct bpf_dynptr *ptr)
137+
long e, long f, long g, long h,
138+
long i, struct bpf_dynptr *ptr)
128139
{
129-
return a + b + c + d + e + bpf_dynptr_size(ptr);
140+
return a + b + c + d + e + f + g + h + i + bpf_dynptr_size(ptr);
130141
}
131142

132143
__noinline long global_dynptr_stack_arg(void *ctx __arg_ctx, long a, long b,
@@ -135,7 +146,8 @@ __noinline long global_dynptr_stack_arg(void *ctx __arg_ctx, long a, long b,
135146
struct bpf_dynptr ptr;
136147

137148
bpf_dynptr_from_skb(ctx, 0, &ptr);
138-
return func_with_dynptr(a, b, c, d, d + 1, &ptr);
149+
return func_with_dynptr(a, b, c, d, d + 1, d + 2, d + 3, d + 4,
150+
d + 5, &ptr);
139151
}
140152

141153
SEC("tc")
@@ -144,33 +156,35 @@ int test_bpf2bpf_dynptr_stack_arg(struct __sk_buff *skb)
144156
return global_dynptr_stack_arg(skb, 1, 2, 3, 4);
145157
}
146158

147-
/* foo1: a+b+c+d+e+f+g+h */
148-
__noinline static int foo1(int a, int b, int c, int d,
149-
int e, int f, int g, int h)
159+
/* foo1: a+b+c+d+e+f+g+h+i+j */
160+
__noinline static int foo1(int a, int b, int c, int d, int e,
161+
int f, int g, int h, int i, int j)
150162
{
151-
return a + b + c + d + e + f + g + h;
163+
return a + b + c + d + e + f + g + h + i + j;
152164
}
153165

154-
/* foo2: a+b+c+d+e+f+g+h+i+j */
166+
/* foo2: a+b+c+d+e+f+g+h+i+j+k+l */
155167
__noinline static int foo2(int a, int b, int c, int d, int e,
156-
int f, int g, int h, int i, int j)
168+
int f, int g, int h, int i, int j,
169+
int k, int l)
157170
{
158-
return a + b + c + d + e + f + g + h + i + j;
171+
return a + b + c + d + e + f + g + h + i + j + k + l;
159172
}
160173

161-
/* global_two_callees calls foo1 (3 stack args) and foo2 (5 stack args).
174+
/* global_two_callees calls foo1 (5 stack args) and foo2 (7 stack args).
162175
* The outgoing stack arg area is sized for foo2 (the larger callee).
163176
* Stores for foo1 are a subset of the area used by foo2.
164-
* Result: foo1(1,2,3,4,5,6,7,8) + foo2(1,2,3,4,5,6,7,8,9,10) = 36 + 55 = 91
177+
* Result: foo1(1..10) + foo2(1..12) = 55 + 78 = 133
165178
*
166179
* Pass a-e through so the compiler can't constant-fold the stack args away.
167180
*/
168181
__noinline int global_two_callees(int a, int b, int c, int d, int e)
169182
{
170183
int ret;
171184

172-
ret = foo1(a, b, c, d, e, a + 5, a + 6, a + 7);
173-
ret += foo2(a, b, c, d, e, a + 5, a + 6, a + 7, a + 8, a + 9);
185+
ret = foo1(a, b, c, d, e, a + 5, a + 6, a + 7, a + 8, a + 9);
186+
ret += foo2(a, b, c, d, e, a + 5, a + 6, a + 7, a + 8, a + 9,
187+
a + 10, a + 11);
174188
return ret;
175189
}
176190

@@ -180,9 +194,15 @@ int test_two_callees(void)
180194
return global_two_callees(1, 2, 3, 4, 5);
181195
}
182196

197+
const volatile int timer_base = 10;
198+
183199
static int timer_cb_many_args(void *map, int *key, struct bpf_timer *timer)
184200
{
185-
timer_result = static_func_many_args(10, 20, 30, 40, 50, 60, 70, 80);
201+
int v = timer_base;
202+
203+
timer_result = static_func_many_args(v, v * 2, v * 3, v * 4, v * 5,
204+
v * 6, v * 7, v * 8, v * 9,
205+
v * 10);
186206
return 0;
187207
}
188208

tools/testing/selftests/bpf/progs/stack_arg_kfunc.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ struct {
3333
SEC("tc")
3434
int test_stack_arg_scalar(struct __sk_buff *skb)
3535
{
36-
return bpf_kfunc_call_stack_arg(1, 2, 3, 4, 5, 6, 7, 8);
36+
return bpf_kfunc_call_stack_arg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
3737
}
3838

3939
SEC("tc")
4040
int test_stack_arg_ptr(struct __sk_buff *skb)
4141
{
4242
struct prog_test_pass1 p = { .x0 = 10, .x1 = 20 };
4343

44-
return bpf_kfunc_call_stack_arg_ptr(1, 2, 3, 4, 5, &p);
44+
return bpf_kfunc_call_stack_arg_ptr(1, 2, 3, 4, 5, 6, 7, 8, 9, &p);
4545
}
4646

4747
SEC("tc")
@@ -50,17 +50,17 @@ int test_stack_arg_mix(struct __sk_buff *skb)
5050
struct prog_test_pass1 p = { .x0 = 10 };
5151
struct prog_test_pass1 q = { .x1 = 20 };
5252

53-
return bpf_kfunc_call_stack_arg_mix(1, 2, 3, 4, 5, &p, 6, &q);
53+
return bpf_kfunc_call_stack_arg_mix(1, 2, 3, 4, 5, 6, 7, &p, 8, &q);
5454
}
5555

56-
/* 1 + 2 + 3 + 4 + 5 + sizeof(pkt_v4) = 15 + 54 = 69 */
56+
/* 1+2+3+4+5+6+7+8+9+sizeof(pkt_v4) = 45+54 = 99 */
5757
SEC("tc")
5858
int test_stack_arg_dynptr(struct __sk_buff *skb)
5959
{
6060
struct bpf_dynptr ptr;
6161

6262
bpf_dynptr_from_skb(skb, 0, &ptr);
63-
return bpf_kfunc_call_stack_arg_dynptr(1, 2, 3, 4, 5, &ptr);
63+
return bpf_kfunc_call_stack_arg_dynptr(1, 2, 3, 4, 5, 6, 7, 8, 9, &ptr);
6464
}
6565

6666
/* 1 + 2 + 3 + 4 + 5 + (1 + 2 + ... + 16) = 15 + 136 = 151 */
@@ -72,29 +72,30 @@ int test_stack_arg_mem(struct __sk_buff *skb)
7272
return bpf_kfunc_call_stack_arg_mem(1, 2, 3, 4, 5, buf, sizeof(buf));
7373
}
7474

75-
/* 1 + 2 + 3 + 4 + 5 + 100 = 115 */
75+
/* 1+2+3+4+5+6+7+8+9+100 = 145 */
7676
SEC("tc")
7777
int test_stack_arg_iter(struct __sk_buff *skb)
7878
{
7979
struct bpf_iter_testmod_seq it;
8080
u64 ret;
8181

8282
bpf_iter_testmod_seq_new(&it, 100, 10);
83-
ret = bpf_kfunc_call_stack_arg_iter(1, 2, 3, 4, 5, &it);
83+
ret = bpf_kfunc_call_stack_arg_iter(1, 2, 3, 4, 5, 6, 7, 8, 9, &it);
8484
bpf_iter_testmod_seq_destroy(&it);
8585
return ret;
8686
}
8787

8888
const char cstr[] = "hello";
8989

90-
/* 1 + 2 + 3 + 4 + 5 = 15 */
90+
/* 1+2+3+4+5+6+7+8+9 = 45 */
9191
SEC("tc")
9292
int test_stack_arg_const_str(struct __sk_buff *skb)
9393
{
94-
return bpf_kfunc_call_stack_arg_const_str(1, 2, 3, 4, 5, cstr);
94+
return bpf_kfunc_call_stack_arg_const_str(1, 2, 3, 4, 5, 6, 7, 8, 9,
95+
cstr);
9596
}
9697

97-
/* 1 + 2 + 3 + 4 + 5 = 15 */
98+
/* 1+2+3+4+5+6+7+8+9 = 45 */
9899
SEC("tc")
99100
int test_stack_arg_timer(struct __sk_buff *skb)
100101
{
@@ -104,7 +105,8 @@ int test_stack_arg_timer(struct __sk_buff *skb)
104105
val = bpf_map_lookup_elem(&kfunc_timer_map, &key);
105106
if (!val)
106107
return 0;
107-
return bpf_kfunc_call_stack_arg_timer(1, 2, 3, 4, 5, &val->timer);
108+
return bpf_kfunc_call_stack_arg_timer(1, 2, 3, 4, 5, 6, 7, 8, 9,
109+
&val->timer);
108110
}
109111

110112
#else

0 commit comments

Comments
 (0)