From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-179.mta0.migadu.com (out-179.mta0.migadu.com [91.218.175.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AFD2F15B55D for ; Thu, 15 Aug 2024 21:32:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.179 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723757580; cv=none; b=lCAKBcR8W9jcJCBrzeRofjUsEmkPFAy003kctbXF87RbUyicCVMXJK35viVLaFOsTT2h2tvvqCT3dwS+PctHib5dMOxR2FxK3d67Ag36UtnEeulw7+X4WyLa13TzimFlU3ODYgOO/rHG+aqBAqFtYpcVnGXSjcERFFbAiY1zTao= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723757580; c=relaxed/simple; bh=veqtI9XIoQQZa+koou8EyEtA59JLykRBvxpTM2g7ODo=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=M2Fl0RhLME+y3MW6e/WAiv2zooZXaDgEkSIo7AHjWZUlhztbthH3qgeJ7BCR3IxuA6UIo64jvJCdGO/z2qd3CF779HYNuFQxIt2/U8Vt4ZAKWvj8gsgDcH985Ab2Y21G+CkMMS2KNr+/ujq/hqJp+lI5X+0UoXeSHfGOmNAom4M= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=pwznHgoS; arc=none smtp.client-ip=91.218.175.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="pwznHgoS" Message-ID: <78d7872d-4644-4a9a-9ef2-f4823fd7944f@linux.dev> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1723757575; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=gE1yyIJMApJqsEGk97mapkxBa1K03kk2fttv4FaX9VM=; b=pwznHgoSFw8zY+86QW502xMKr8xVGv2WVL6rf8Nqr+GhoJKkyVr3/2z2b23Ea6ab8mhcng V72F+/DKnT/Bw7lVDcfuZwlvt5xqPiw8Q4BBlnHrMinnaO1HUOgucb6rf0v49XJydVgcoF muuA3wgWWQxIQNZqdQR+XYH59zWXZn8= Date: Thu, 15 Aug 2024 14:32:48 -0700 Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Subject: Re: [PATCH bpf-next 4/4] selftests/bpf: validate jit behaviour for tail calls Content-Language: en-GB To: Eduard Zingerman , bpf@vger.kernel.org, ast@kernel.org Cc: andrii@kernel.org, daniel@iogearbox.net, martin.lau@linux.dev, kernel-team@fb.com, hffilwlqm@gmail.com References: <20240809010518.1137758-1-eddyz87@gmail.com> <20240809010518.1137758-5-eddyz87@gmail.com> X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. From: Yonghong Song In-Reply-To: <20240809010518.1137758-5-eddyz87@gmail.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Migadu-Flow: FLOW_OUT On 8/8/24 6:05 PM, Eduard Zingerman wrote: > A program calling sub-program which does a tail call. > The idea is to verify instructions generated by jit for tail calls: > - in program and sub-program prologues; > - for subprogram call instruction; > - for tail call itself. > > Signed-off-by: Eduard Zingerman > --- > .../selftests/bpf/prog_tests/verifier.c | 2 + > .../bpf/progs/verifier_tailcall_jit.c | 103 ++++++++++++++++++ > 2 files changed, 105 insertions(+) > create mode 100644 tools/testing/selftests/bpf/progs/verifier_tailcall_jit.c > > diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c > index f8f546eba488..cf3662dbd24f 100644 > --- a/tools/testing/selftests/bpf/prog_tests/verifier.c > +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c > @@ -75,6 +75,7 @@ > #include "verifier_stack_ptr.skel.h" > #include "verifier_subprog_precision.skel.h" > #include "verifier_subreg.skel.h" > +#include "verifier_tailcall_jit.skel.h" > #include "verifier_typedef.skel.h" > #include "verifier_uninit.skel.h" > #include "verifier_unpriv.skel.h" > @@ -198,6 +199,7 @@ void test_verifier_spin_lock(void) { RUN(verifier_spin_lock); } > void test_verifier_stack_ptr(void) { RUN(verifier_stack_ptr); } > void test_verifier_subprog_precision(void) { RUN(verifier_subprog_precision); } > void test_verifier_subreg(void) { RUN(verifier_subreg); } > +void test_verifier_tailcall_jit(void) { RUN(verifier_tailcall_jit); } > void test_verifier_typedef(void) { RUN(verifier_typedef); } > void test_verifier_uninit(void) { RUN(verifier_uninit); } > void test_verifier_unpriv(void) { RUN(verifier_unpriv); } > diff --git a/tools/testing/selftests/bpf/progs/verifier_tailcall_jit.c b/tools/testing/selftests/bpf/progs/verifier_tailcall_jit.c > new file mode 100644 > index 000000000000..1a09c76d7be0 > --- /dev/null > +++ b/tools/testing/selftests/bpf/progs/verifier_tailcall_jit.c > @@ -0,0 +1,103 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include "bpf_misc.h" > + > +int main(void); > + > +struct { > + __uint(type, BPF_MAP_TYPE_PROG_ARRAY); > + __uint(max_entries, 1); > + __uint(key_size, sizeof(__u32)); > + __array(values, void (void)); > +} jmp_table SEC(".maps") = { > + .values = { > + [0] = (void *) &main, > + }, > +}; > + > +__noinline __auxiliary > +static __naked int sub(void) > +{ > + asm volatile ( > + "r2 = %[jmp_table] ll;" > + "r3 = 0;" > + "call 12;" > + "exit;" > + : > + : __imm_addr(jmp_table) > + : __clobber_all); > +} > + > +__success > +/* program entry for main(), regular function prologue */ > +__jit_x86(" endbr64") > +__jit_x86(" nopl (%rax,%rax)") > +__jit_x86(" xorq %rax, %rax") > +__jit_x86(" pushq %rbp") > +__jit_x86(" movq %rsp, %rbp") How do we hanble multi architectures (x86, arm64, riscv64)? Do we support the following? __jit_x86(...) __jit_x86(...) ... __jit_arm64(...) __jit_arm64(...) ... __jit_riscv64(...) __jit_riscv64(...) ... Or we can use macro like #ifdef __TARGET_ARCH_x86 __jit(...) ... #elif defined(__TARGET_ARCH_arm64) __jit(...) ... #elif defined(...) Or we can have __arch_x86_64 __jit(...) // code for x86 ... __arch_arm64 __jit(...) // code for arm64 ... __arch_riscv __jit(...) // code for riscv ... For xlated, different archs could share the same code. Bot for jited code, different arch has different encoding, so we need to figure out a format suitable for multiple archs. > +/* tail call prologue for program: > + * - establish memory location for tail call counter at &rbp[-8]; > + * - spill tail_call_cnt_ptr at &rbp[-16]; > + * - expect tail call counter to be passed in rax; > + * - for entry program rax is a raw counter, value < 33; > + * - for tail called program rax is tail_call_cnt_ptr (value > 33). > + */ > +__jit_x86(" endbr64") > +__jit_x86(" cmpq $0x21, %rax") > +__jit_x86(" ja L0") > +__jit_x86(" pushq %rax") > +__jit_x86(" movq %rsp, %rax") > +__jit_x86(" jmp L1") > +__jit_x86("L0: pushq %rax") /* rbp[-8] = rax */ > +__jit_x86("L1: pushq %rax") /* rbp[-16] = rax */ > +/* on subprogram call restore rax to be tail_call_cnt_ptr from rbp[-16] > + * (cause original rax might be clobbered by this point) > + */ [...]