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