xref: /linux/tools/testing/selftests/bpf/progs/verifier_stack_arg.c (revision b2128290c29902315e632ea59e0504d6bc9e9b42)
100c3ac42SYonghong Song // SPDX-License-Identifier: GPL-2.0
200c3ac42SYonghong Song /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
300c3ac42SYonghong Song 
400c3ac42SYonghong Song #include <linux/bpf.h>
500c3ac42SYonghong Song #include <bpf/bpf_helpers.h>
600c3ac42SYonghong Song #include "bpf_misc.h"
700c3ac42SYonghong Song 
800c3ac42SYonghong Song struct {
900c3ac42SYonghong Song 	__uint(type, BPF_MAP_TYPE_HASH);
1000c3ac42SYonghong Song 	__uint(max_entries, 1);
1100c3ac42SYonghong Song 	__type(key, long long);
1200c3ac42SYonghong Song 	__type(value, long long);
1300c3ac42SYonghong Song } map_hash_8b SEC(".maps");
1400c3ac42SYonghong Song 
1590e43f1bSPuranjay Mohan #if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64)) && \
1690e43f1bSPuranjay Mohan 	defined(__BPF_FEATURE_STACK_ARGUMENT)
1700c3ac42SYonghong Song 
1800c3ac42SYonghong Song __noinline __used
1900c3ac42SYonghong Song static int subprog_6args(int a, int b, int c, int d, int e, int f)
2000c3ac42SYonghong Song {
2100c3ac42SYonghong Song 	return a + b + c + d + e + f;
2200c3ac42SYonghong Song }
2300c3ac42SYonghong Song 
2400c3ac42SYonghong Song __noinline __used
2500c3ac42SYonghong Song static int subprog_7args(int a, int b, int c, int d, int e, int f, int g)
2600c3ac42SYonghong Song {
2700c3ac42SYonghong Song 	return a + b + c + d + e + f + g;
2800c3ac42SYonghong Song }
2900c3ac42SYonghong Song 
3000c3ac42SYonghong Song __noinline __used
3100c3ac42SYonghong Song static long subprog_deref_arg6(long a, long b, long c, long d, long e, long *f)
3200c3ac42SYonghong Song {
3300c3ac42SYonghong Song 	return *f;
3400c3ac42SYonghong Song }
3500c3ac42SYonghong Song 
3600c3ac42SYonghong Song SEC("tc")
3700c3ac42SYonghong Song __description("stack_arg: subprog with 6 args")
3800c3ac42SYonghong Song __success __retval(21)
3900c3ac42SYonghong Song __naked void stack_arg_6args(void)
4000c3ac42SYonghong Song {
4100c3ac42SYonghong Song 	asm volatile (
4200c3ac42SYonghong Song 		"r1 = 1;"
4300c3ac42SYonghong Song 		"r2 = 2;"
4400c3ac42SYonghong Song 		"r3 = 3;"
4500c3ac42SYonghong Song 		"r4 = 4;"
4600c3ac42SYonghong Song 		"r5 = 5;"
4700c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = 6;"
4800c3ac42SYonghong Song 		"call subprog_6args;"
4900c3ac42SYonghong Song 		"exit;"
5000c3ac42SYonghong Song 		::: __clobber_all
5100c3ac42SYonghong Song 	);
5200c3ac42SYonghong Song }
5300c3ac42SYonghong Song 
5400c3ac42SYonghong Song SEC("tc")
5500c3ac42SYonghong Song __description("stack_arg: two subprogs with >5 args")
5600c3ac42SYonghong Song __success __retval(90)
5700c3ac42SYonghong Song __naked void stack_arg_two_subprogs(void)
5800c3ac42SYonghong Song {
5900c3ac42SYonghong Song 	asm volatile (
6000c3ac42SYonghong Song 		"r1 = 1;"
6100c3ac42SYonghong Song 		"r2 = 2;"
6200c3ac42SYonghong Song 		"r3 = 3;"
6300c3ac42SYonghong Song 		"r4 = 4;"
6400c3ac42SYonghong Song 		"r5 = 5;"
6500c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = 10;"
6600c3ac42SYonghong Song 		"call subprog_6args;"
6700c3ac42SYonghong Song 		"r6 = r0;"
6800c3ac42SYonghong Song 		"r1 = 1;"
6900c3ac42SYonghong Song 		"r2 = 2;"
7000c3ac42SYonghong Song 		"r3 = 3;"
7100c3ac42SYonghong Song 		"r4 = 4;"
7200c3ac42SYonghong Song 		"r5 = 5;"
7300c3ac42SYonghong Song 		"*(u64 *)(r11 - 16) = 30;"
7400c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = 20;"
7500c3ac42SYonghong Song 		"call subprog_7args;"
7600c3ac42SYonghong Song 		"r0 += r6;"
7700c3ac42SYonghong Song 		"exit;"
7800c3ac42SYonghong Song 		::: __clobber_all
7900c3ac42SYonghong Song 	);
8000c3ac42SYonghong Song }
8100c3ac42SYonghong Song 
8200c3ac42SYonghong Song SEC("tc")
8300c3ac42SYonghong Song __description("stack_arg: read from uninitialized stack arg slot")
8400c3ac42SYonghong Song __failure
8500c3ac42SYonghong Song __msg("invalid read from stack arg off 8 depth 0")
8600c3ac42SYonghong Song __naked void stack_arg_read_uninitialized(void)
8700c3ac42SYonghong Song {
8800c3ac42SYonghong Song 	asm volatile (
8900c3ac42SYonghong Song 		"r0 = *(u64 *)(r11 + 8);"
9000c3ac42SYonghong Song 		"r0 = 0;"
9100c3ac42SYonghong Song 		"exit;"
9200c3ac42SYonghong Song 		::: __clobber_all
9300c3ac42SYonghong Song 	);
9400c3ac42SYonghong Song }
9500c3ac42SYonghong Song 
9600c3ac42SYonghong Song SEC("tc")
9700c3ac42SYonghong Song __description("stack_arg: gap at offset -8, only wrote -16")
9800c3ac42SYonghong Song __failure
9900c3ac42SYonghong Song __msg("callee expects 7 args, stack arg1 is not initialized")
10000c3ac42SYonghong Song __naked void stack_arg_gap_at_minus8(void)
10100c3ac42SYonghong Song {
10200c3ac42SYonghong Song 	asm volatile (
10300c3ac42SYonghong Song 		"r1 = 1;"
10400c3ac42SYonghong Song 		"r2 = 2;"
10500c3ac42SYonghong Song 		"r3 = 3;"
10600c3ac42SYonghong Song 		"r4 = 4;"
10700c3ac42SYonghong Song 		"r5 = 5;"
10800c3ac42SYonghong Song 		"*(u64 *)(r11 - 16) = 30;"
10900c3ac42SYonghong Song 		"call subprog_7args;"
11000c3ac42SYonghong Song 		"exit;"
11100c3ac42SYonghong Song 		::: __clobber_all
11200c3ac42SYonghong Song 	);
11300c3ac42SYonghong Song }
11400c3ac42SYonghong Song 
11500c3ac42SYonghong Song SEC("tc")
11600c3ac42SYonghong Song __description("stack_arg: pruning with different stack arg types")
1170e264779SYonghong Song __failure __log_level(2)
11800c3ac42SYonghong Song __flag(BPF_F_TEST_STATE_FREQ)
1190e264779SYonghong Song __msg("arg JOIN insn 9 -> 10 r1: fp0-8 + _ => fp0-8|fp0+0")
120*d1dbe443SYonghong Song __msg("arg JOIN insn 9 -> 10 sa0: fp0-8 + _ => fp0-8|fp0+0")
12100c3ac42SYonghong Song __msg("R{{[0-9]}} invalid mem access 'scalar'")
12200c3ac42SYonghong Song __naked void stack_arg_pruning_type_mismatch(void)
12300c3ac42SYonghong Song {
12400c3ac42SYonghong Song 	asm volatile (
12500c3ac42SYonghong Song 		"call %[bpf_get_prandom_u32];"
12600c3ac42SYonghong Song 		"r6 = r0;"
12700c3ac42SYonghong Song 		/* local = 0 on program stack */
12800c3ac42SYonghong Song 		"r7 = 0;"
12900c3ac42SYonghong Song 		"*(u64 *)(r10 - 8) = r7;"
13000c3ac42SYonghong Song 		/* Branch based on random value */
13100c3ac42SYonghong Song 		"if r6 s> 3 goto l0_%=;"
13200c3ac42SYonghong Song 		/* Path 1: store stack pointer to outgoing arg6 */
13300c3ac42SYonghong Song 		"r1 = r10;"
13400c3ac42SYonghong Song 		"r1 += -8;"
13500c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = r1;"
13600c3ac42SYonghong Song 		"goto l1_%=;"
13700c3ac42SYonghong Song 	"l0_%=:"
13800c3ac42SYonghong Song 		/* Path 2: store scalar to outgoing arg6 */
13900c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = 42;"
14000c3ac42SYonghong Song 	"l1_%=:"
14100c3ac42SYonghong Song 		/* Call subprog that dereferences arg6 */
14200c3ac42SYonghong Song 		"r1 = r6;"
14300c3ac42SYonghong Song 		"r2 = 0;"
14400c3ac42SYonghong Song 		"r3 = 0;"
14500c3ac42SYonghong Song 		"r4 = 0;"
14600c3ac42SYonghong Song 		"r5 = 0;"
14700c3ac42SYonghong Song 		"call subprog_deref_arg6;"
14800c3ac42SYonghong Song 		"exit;"
14900c3ac42SYonghong Song 		:: __imm(bpf_get_prandom_u32)
15000c3ac42SYonghong Song 		: __clobber_all
15100c3ac42SYonghong Song 	);
15200c3ac42SYonghong Song }
15300c3ac42SYonghong Song 
15400c3ac42SYonghong Song SEC("tc")
15500c3ac42SYonghong Song __description("stack_arg: release_reference invalidates stack arg slot")
15600c3ac42SYonghong Song __failure
157ef1b54e0SYonghong Song __msg("callee expects 6 args, stack arg1 is not initialized")
15800c3ac42SYonghong Song __naked void stack_arg_release_ref(void)
15900c3ac42SYonghong Song {
16000c3ac42SYonghong Song 	asm volatile (
16100c3ac42SYonghong Song 		"r6 = r1;"
16200c3ac42SYonghong Song 		/* struct bpf_sock_tuple tuple = {} */
16300c3ac42SYonghong Song 		"r2 = 0;"
16400c3ac42SYonghong Song 		"*(u32 *)(r10 - 8) = r2;"
16500c3ac42SYonghong Song 		"*(u64 *)(r10 - 16) = r2;"
16600c3ac42SYonghong Song 		"*(u64 *)(r10 - 24) = r2;"
16700c3ac42SYonghong Song 		"*(u64 *)(r10 - 32) = r2;"
16800c3ac42SYonghong Song 		"*(u64 *)(r10 - 40) = r2;"
16900c3ac42SYonghong Song 		"*(u64 *)(r10 - 48) = r2;"
17000c3ac42SYonghong Song 		/* sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof(tuple), 0, 0) */
17100c3ac42SYonghong Song 		"r1 = r6;"
17200c3ac42SYonghong Song 		"r2 = r10;"
17300c3ac42SYonghong Song 		"r2 += -48;"
17400c3ac42SYonghong Song 		"r3 = %[sizeof_bpf_sock_tuple];"
17500c3ac42SYonghong Song 		"r4 = 0;"
17600c3ac42SYonghong Song 		"r5 = 0;"
17700c3ac42SYonghong Song 		"call %[bpf_sk_lookup_tcp];"
17800c3ac42SYonghong Song 		/* r0 = sk (PTR_TO_SOCK_OR_NULL) */
17900c3ac42SYonghong Song 		"if r0 == 0 goto l0_%=;"
18000c3ac42SYonghong Song 		/* Store sock ref to outgoing arg6 slot */
18100c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = r0;"
18200c3ac42SYonghong Song 		/* Release the reference — invalidates the stack arg slot */
18300c3ac42SYonghong Song 		"r1 = r0;"
18400c3ac42SYonghong Song 		"call %[bpf_sk_release];"
18500c3ac42SYonghong Song 		/* Call subprog that dereferences arg6 — should fail */
18600c3ac42SYonghong Song 		"r1 = 1;"
18700c3ac42SYonghong Song 		"r2 = 2;"
18800c3ac42SYonghong Song 		"r3 = 3;"
18900c3ac42SYonghong Song 		"r4 = 4;"
19000c3ac42SYonghong Song 		"r5 = 5;"
19100c3ac42SYonghong Song 		"call subprog_deref_arg6;"
19200c3ac42SYonghong Song 	"l0_%=:"
19300c3ac42SYonghong Song 		"r0 = 0;"
19400c3ac42SYonghong Song 		"exit;"
19500c3ac42SYonghong Song 		:
19600c3ac42SYonghong Song 		: __imm(bpf_sk_lookup_tcp),
19700c3ac42SYonghong Song 		  __imm(bpf_sk_release),
19800c3ac42SYonghong Song 		  __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
19900c3ac42SYonghong Song 		: __clobber_all
20000c3ac42SYonghong Song 	);
20100c3ac42SYonghong Song }
20200c3ac42SYonghong Song 
20300c3ac42SYonghong Song SEC("tc")
20400c3ac42SYonghong Song __description("stack_arg: pkt pointer in stack arg slot invalidated after pull_data")
20500c3ac42SYonghong Song __failure
206ef1b54e0SYonghong Song __msg("callee expects 6 args, stack arg1 is not initialized")
20700c3ac42SYonghong Song __naked void stack_arg_stale_pkt_ptr(void)
20800c3ac42SYonghong Song {
20900c3ac42SYonghong Song 	asm volatile (
21000c3ac42SYonghong Song 		"r6 = r1;"
21100c3ac42SYonghong Song 		"r7 = *(u32 *)(r6 + %[__sk_buff_data]);"
21200c3ac42SYonghong Song 		"r8 = *(u32 *)(r6 + %[__sk_buff_data_end]);"
21300c3ac42SYonghong Song 		/* check pkt has at least 1 byte */
21400c3ac42SYonghong Song 		"r0 = r7;"
21500c3ac42SYonghong Song 		"r0 += 8;"
21600c3ac42SYonghong Song 		"if r0 > r8 goto l0_%=;"
21700c3ac42SYonghong Song 		/* Store valid pkt pointer to outgoing arg6 slot */
21800c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = r7;"
21900c3ac42SYonghong Song 		/* bpf_skb_pull_data invalidates all pkt pointers */
22000c3ac42SYonghong Song 		"r1 = r6;"
22100c3ac42SYonghong Song 		"r2 = 0;"
22200c3ac42SYonghong Song 		"call %[bpf_skb_pull_data];"
22300c3ac42SYonghong Song 		/* Call subprog that dereferences arg6 — should fail */
22400c3ac42SYonghong Song 		"r1 = 1;"
22500c3ac42SYonghong Song 		"r2 = 2;"
22600c3ac42SYonghong Song 		"r3 = 3;"
22700c3ac42SYonghong Song 		"r4 = 4;"
22800c3ac42SYonghong Song 		"r5 = 5;"
22900c3ac42SYonghong Song 		"call subprog_deref_arg6;"
23000c3ac42SYonghong Song 	"l0_%=:"
23100c3ac42SYonghong Song 		"r0 = 0;"
23200c3ac42SYonghong Song 		"exit;"
23300c3ac42SYonghong Song 		:
23400c3ac42SYonghong Song 		: __imm(bpf_skb_pull_data),
23500c3ac42SYonghong Song 		  __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
23600c3ac42SYonghong Song 		  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
23700c3ac42SYonghong Song 		: __clobber_all
23800c3ac42SYonghong Song 	);
23900c3ac42SYonghong Song }
24000c3ac42SYonghong Song 
24100c3ac42SYonghong Song SEC("tc")
24200c3ac42SYonghong Song __description("stack_arg: null propagation rejects deref on null branch")
24300c3ac42SYonghong Song __failure
24400c3ac42SYonghong Song __msg("R{{[0-9]}} invalid mem access 'scalar'")
24500c3ac42SYonghong Song __naked void stack_arg_null_propagation_fail(void)
24600c3ac42SYonghong Song {
24700c3ac42SYonghong Song 	asm volatile (
24800c3ac42SYonghong Song 		"r1 = 0;"
24900c3ac42SYonghong Song 		"*(u64 *)(r10 - 8) = r1;"
25000c3ac42SYonghong Song 		/* r0 = bpf_map_lookup_elem(&map_hash_8b, &key) */
25100c3ac42SYonghong Song 		"r2 = r10;"
25200c3ac42SYonghong Song 		"r2 += -8;"
25300c3ac42SYonghong Song 		"r1 = %[map_hash_8b] ll;"
25400c3ac42SYonghong Song 		"call %[bpf_map_lookup_elem];"
25500c3ac42SYonghong Song 		/* Store PTR_TO_MAP_VALUE_OR_NULL to outgoing arg6 slot */
25600c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = r0;"
25700c3ac42SYonghong Song 		/* null check on r0 */
25800c3ac42SYonghong Song 		"if r0 != 0 goto l0_%=;"
25900c3ac42SYonghong Song 		/*
26000c3ac42SYonghong Song 		 * On null branch, outgoing slot is SCALAR(0).
26100c3ac42SYonghong Song 		 * Call subprog that dereferences arg6 — should fail.
26200c3ac42SYonghong Song 		 */
26300c3ac42SYonghong Song 		"r1 = 0;"
26400c3ac42SYonghong Song 		"r2 = 0;"
26500c3ac42SYonghong Song 		"r3 = 0;"
26600c3ac42SYonghong Song 		"r4 = 0;"
26700c3ac42SYonghong Song 		"r5 = 0;"
26800c3ac42SYonghong Song 		"call subprog_deref_arg6;"
26900c3ac42SYonghong Song 	"l0_%=:"
27000c3ac42SYonghong Song 		"r0 = 0;"
27100c3ac42SYonghong Song 		"exit;"
27200c3ac42SYonghong Song 		:
27300c3ac42SYonghong Song 		: __imm(bpf_map_lookup_elem),
27400c3ac42SYonghong Song 		  __imm_addr(map_hash_8b)
27500c3ac42SYonghong Song 		: __clobber_all
27600c3ac42SYonghong Song 	);
27700c3ac42SYonghong Song }
27800c3ac42SYonghong Song 
27900c3ac42SYonghong Song SEC("tc")
28000c3ac42SYonghong Song __description("stack_arg: missing store on one branch")
28100c3ac42SYonghong Song __failure
28200c3ac42SYonghong Song __msg("callee expects 7 args, stack arg1 is not initialized")
28300c3ac42SYonghong Song __naked void stack_arg_missing_store_one_branch(void)
28400c3ac42SYonghong Song {
28500c3ac42SYonghong Song 	asm volatile (
28600c3ac42SYonghong Song 		"call %[bpf_get_prandom_u32];"
28700c3ac42SYonghong Song 		"r1 = 1;"
28800c3ac42SYonghong Song 		"r2 = 2;"
28900c3ac42SYonghong Song 		"r3 = 3;"
29000c3ac42SYonghong Song 		"r4 = 4;"
29100c3ac42SYonghong Song 		"r5 = 5;"
29200c3ac42SYonghong Song 		/* Write arg7 (r11-16) before branch */
29300c3ac42SYonghong Song 		"*(u64 *)(r11 - 16) = 20;"
29400c3ac42SYonghong Song 		"if r0 > 0 goto l0_%=;"
29500c3ac42SYonghong Song 		/* Path 1: write arg6 and call */
29600c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = 10;"
29700c3ac42SYonghong Song 		"r1 = 1;"
29800c3ac42SYonghong Song 		"r2 = 2;"
29900c3ac42SYonghong Song 		"r3 = 3;"
30000c3ac42SYonghong Song 		"r4 = 4;"
30100c3ac42SYonghong Song 		"r5 = 5;"
30200c3ac42SYonghong Song 		"call subprog_7args;"
30300c3ac42SYonghong Song 		"goto l1_%=;"
30400c3ac42SYonghong Song 	"l0_%=:"
30500c3ac42SYonghong Song 		/* Path 2: missing arg6 store, call should fail */
30600c3ac42SYonghong Song 		"r1 = 1;"
30700c3ac42SYonghong Song 		"r2 = 2;"
30800c3ac42SYonghong Song 		"r3 = 3;"
30900c3ac42SYonghong Song 		"r4 = 4;"
31000c3ac42SYonghong Song 		"r5 = 5;"
31100c3ac42SYonghong Song 		"call subprog_7args;"
31200c3ac42SYonghong Song 	"l1_%=:"
31300c3ac42SYonghong Song 		"r0 = 0;"
31400c3ac42SYonghong Song 		"exit;"
31500c3ac42SYonghong Song 		:: __imm(bpf_get_prandom_u32)
31600c3ac42SYonghong Song 		: __clobber_all
31700c3ac42SYonghong Song 	);
31800c3ac42SYonghong Song }
31900c3ac42SYonghong Song 
32000c3ac42SYonghong Song SEC("tc")
32100c3ac42SYonghong Song __description("stack_arg: share a store for both branches")
32200c3ac42SYonghong Song __success __retval(0)
32300c3ac42SYonghong Song __naked void stack_arg_shared_store(void)
32400c3ac42SYonghong Song {
32500c3ac42SYonghong Song 	asm volatile (
32600c3ac42SYonghong Song 		"call %[bpf_get_prandom_u32];"
32700c3ac42SYonghong Song 		"r1 = 1;"
32800c3ac42SYonghong Song 		"r2 = 2;"
32900c3ac42SYonghong Song 		"r3 = 3;"
33000c3ac42SYonghong Song 		"r4 = 4;"
33100c3ac42SYonghong Song 		"r5 = 5;"
33200c3ac42SYonghong Song 		/* Write arg7 (r11-16) before branch */
33300c3ac42SYonghong Song 		"*(u64 *)(r11 - 16) = 20;"
33400c3ac42SYonghong Song 		"if r0 > 0 goto l0_%=;"
33500c3ac42SYonghong Song 		/* Path 1: write arg6 and call */
33600c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = 10;"
33700c3ac42SYonghong Song 		"r1 = 1;"
33800c3ac42SYonghong Song 		"r2 = 2;"
33900c3ac42SYonghong Song 		"r3 = 3;"
34000c3ac42SYonghong Song 		"r4 = 4;"
34100c3ac42SYonghong Song 		"r5 = 5;"
34200c3ac42SYonghong Song 		"call subprog_7args;"
34300c3ac42SYonghong Song 		"goto l1_%=;"
34400c3ac42SYonghong Song 	"l0_%=:"
34500c3ac42SYonghong Song 		/* Path 2: also write arg6 and call */
34600c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = 30;"
34700c3ac42SYonghong Song 		"r1 = 1;"
34800c3ac42SYonghong Song 		"r2 = 2;"
34900c3ac42SYonghong Song 		"r3 = 3;"
35000c3ac42SYonghong Song 		"r4 = 4;"
35100c3ac42SYonghong Song 		"r5 = 5;"
35200c3ac42SYonghong Song 		"call subprog_7args;"
35300c3ac42SYonghong Song 	"l1_%=:"
35400c3ac42SYonghong Song 		"r0 = 0;"
35500c3ac42SYonghong Song 		"exit;"
35600c3ac42SYonghong Song 		:: __imm(bpf_get_prandom_u32)
35700c3ac42SYonghong Song 		: __clobber_all
35800c3ac42SYonghong Song 	);
35900c3ac42SYonghong Song }
36000c3ac42SYonghong Song 
36100c3ac42SYonghong Song SEC("tc")
36200c3ac42SYonghong Song __description("stack_arg: write beyond max outgoing depth")
36300c3ac42SYonghong Song __failure
36400c3ac42SYonghong Song __msg("stack arg write offset -80 exceeds max 7 stack args")
36500c3ac42SYonghong Song __naked void stack_arg_write_beyond_max(void)
36600c3ac42SYonghong Song {
36700c3ac42SYonghong Song 	asm volatile (
36800c3ac42SYonghong Song 		"r1 = 1;"
36900c3ac42SYonghong Song 		"r2 = 2;"
37000c3ac42SYonghong Song 		"r3 = 3;"
37100c3ac42SYonghong Song 		"r4 = 4;"
37200c3ac42SYonghong Song 		"r5 = 5;"
37300c3ac42SYonghong Song 		/* Write to offset -80, way beyond any callee's needs */
37400c3ac42SYonghong Song 		"*(u64 *)(r11 - 80) = 99;"
37500c3ac42SYonghong Song 		"*(u64 *)(r11 - 16) = 20;"
37600c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = 10;"
37700c3ac42SYonghong Song 		"call subprog_7args;"
37800c3ac42SYonghong Song 		"r0 = 0;"
37900c3ac42SYonghong Song 		"exit;"
38000c3ac42SYonghong Song 		::: __clobber_all
38100c3ac42SYonghong Song 	);
38200c3ac42SYonghong Song }
38300c3ac42SYonghong Song 
38400c3ac42SYonghong Song SEC("tc")
38500c3ac42SYonghong Song __description("stack_arg: write unused stack arg slot")
38600c3ac42SYonghong Song __failure
38700c3ac42SYonghong Song __msg("func#0 writes 5 stack arg slots, but calls only require 2")
38800c3ac42SYonghong Song __naked void stack_arg_write_unused_slot(void)
38900c3ac42SYonghong Song {
39000c3ac42SYonghong Song 	asm volatile (
39100c3ac42SYonghong Song 		"r1 = 1;"
39200c3ac42SYonghong Song 		"r2 = 2;"
39300c3ac42SYonghong Song 		"r3 = 3;"
39400c3ac42SYonghong Song 		"r4 = 4;"
39500c3ac42SYonghong Song 		"r5 = 5;"
39600c3ac42SYonghong Song 		/* Write to offset -40, unused for the callee */
39700c3ac42SYonghong Song 		"*(u64 *)(r11 - 40) = 99;"
39800c3ac42SYonghong Song 		"*(u64 *)(r11 - 16) = 20;"
39900c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = 10;"
40000c3ac42SYonghong Song 		"call subprog_7args;"
40100c3ac42SYonghong Song 		"r0 = 0;"
40200c3ac42SYonghong Song 		"exit;"
40300c3ac42SYonghong Song 		::: __clobber_all
40400c3ac42SYonghong Song 	);
40500c3ac42SYonghong Song }
40600c3ac42SYonghong Song 
40700c3ac42SYonghong Song SEC("tc")
40800c3ac42SYonghong Song __description("stack_arg: sequential calls reuse slots")
40900c3ac42SYonghong Song __failure
41000c3ac42SYonghong Song __msg("callee expects 7 args, stack arg1 is not initialized")
41100c3ac42SYonghong Song __naked void stack_arg_sequential_calls(void)
41200c3ac42SYonghong Song {
41300c3ac42SYonghong Song 	asm volatile (
41400c3ac42SYonghong Song 		"r1 = 1;"
41500c3ac42SYonghong Song 		"r2 = 2;"
41600c3ac42SYonghong Song 		"r3 = 3;"
41700c3ac42SYonghong Song 		"r4 = 4;"
41800c3ac42SYonghong Song 		"r5 = 5;"
41900c3ac42SYonghong Song 		"*(u64 *)(r11 - 8) = 6;"
42000c3ac42SYonghong Song 		"*(u64 *)(r11 - 16) = 7;"
42100c3ac42SYonghong Song 		"call subprog_7args;"
42200c3ac42SYonghong Song 		"r6 = r0;"
42300c3ac42SYonghong Song 		"r1 = 1;"
42400c3ac42SYonghong Song 		"r2 = 2;"
42500c3ac42SYonghong Song 		"r3 = 3;"
42600c3ac42SYonghong Song 		"r4 = 4;"
42700c3ac42SYonghong Song 		"r5 = 5;"
42800c3ac42SYonghong Song 		"call subprog_7args;"
42900c3ac42SYonghong Song 		"r0 += r6;"
43000c3ac42SYonghong Song 		"exit;"
43100c3ac42SYonghong Song 		::: __clobber_all
43200c3ac42SYonghong Song 	);
43300c3ac42SYonghong Song }
43400c3ac42SYonghong Song 
43500c3ac42SYonghong Song #else
43600c3ac42SYonghong Song 
43700c3ac42SYonghong Song SEC("socket")
43800c3ac42SYonghong Song __description("stack_arg is not supported by compiler or jit, use a dummy test")
43900c3ac42SYonghong Song __success
44000c3ac42SYonghong Song int dummy_test(void)
44100c3ac42SYonghong Song {
44200c3ac42SYonghong Song 	return 0;
44300c3ac42SYonghong Song }
44400c3ac42SYonghong Song 
44500c3ac42SYonghong Song #endif
44600c3ac42SYonghong Song 
44700c3ac42SYonghong Song char _license[] SEC("license") = "GPL";
448