In emit_bpf_tail_call(), the macro-based jmp_offset calculation relies on a fragile prediction equation: "tc_ninsn - (ctx->idx - idx0)". This calculation model utilizes tc_ninsn from the previous pass to estimate the remaining stride of the active tail call code block. Given that the macro relies on stale layout data from a prior pass to compute the active relative stride, the conditional branches end up encoding wrong immediate offsets under extra JIT passes. Consequently, the execution flow leaps into misaligned instruction boundaries, triggering soft lockups or early loop collapse. To fix this issue, drop the pass-dependent macro and the intermediate variable entirely. Instead, explicitly calculate "jmp_offset" using an absolute target reference anchor: "ctx->offset[insn + 1] - ctx->idx". However, during the initial size-estimation pass, the target address "ctx->offset[insn + 1]" is not yet populated and will evaluate to 0, resulting in "jmp_offset = -ctx->idx". For large eBPF programs, this inflated negative offset would overflow the 16-bit signed immediate limit of LoongArch conditional branch instructions, causing the range validation inside emit_tailcall_jmp() to abort the JIT compilation prematurely. To bypass this initialization bottleneck cleanly without changing any function signatures, leverage the "ctx->image" pointer to safely detect the initial pass. Since conditional branch instructions on LoongArch maintain a fixed 4-byte width regardless of the target displacement, injecting a safe dummy offset (0) when "ctx->image == NULL" preserves accurate size estimation while preventing 16-bit range check failures. Within this new deterministic arithmetic model: 1) "ctx->offset[insn + 1]" maps directly to the absolute instruction index of the immediate next eBPF business instruction, serving as a rock-solid target label. 2) "ctx->idx" tracks the real-time instruction index of the conditional branch currently being emitted. This guarantees the generated immediate offsets always land precisely on the next instruction boundary under all multi-pass compilation paths and all code size dimensions. Signed-off-by: Tiezhu Yang --- arch/loongarch/net/bpf_jit.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index 95e3b372a44f..45364a15ae5e 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -290,17 +290,13 @@ bool bpf_jit_supports_far_kfunc_call(void) static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn) { - int off, tc_ninsn = 0; + int off, jmp_offset; int tcc_ptr_off = BPF_TAIL_CALL_CNT_PTR_STACK_OFF(ctx->stack_size); u8 a1 = LOONGARCH_GPR_A1; u8 a2 = LOONGARCH_GPR_A2; u8 t1 = LOONGARCH_GPR_T1; u8 t2 = LOONGARCH_GPR_T2; u8 t3 = LOONGARCH_GPR_T3; - const int idx0 = ctx->idx; - -#define cur_offset (ctx->idx - idx0) -#define jmp_offset (tc_ninsn - (cur_offset)) /* * a0: &ctx @@ -310,12 +306,12 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn) * if (index >= array->map.max_entries) * goto out; */ - tc_ninsn = insn ? ctx->offset[insn+1] - ctx->offset[insn] : ctx->offset[0]; emit_zext_32(ctx, a2, true); off = offsetof(struct bpf_array, map.max_entries); emit_insn(ctx, ldwu, t1, a1, off); /* bgeu $a2, $t1, jmp_offset */ + jmp_offset = ctx->image ? (ctx->offset[insn + 1] - ctx->idx) : 0; if (emit_tailcall_jmp(ctx, BPF_JGE, a2, t1, jmp_offset) < 0) goto toofar; @@ -326,6 +322,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn) emit_insn(ctx, ldd, REG_TCC, LOONGARCH_GPR_SP, tcc_ptr_off); emit_insn(ctx, ldd, t3, REG_TCC, 0); emit_insn(ctx, addid, t2, LOONGARCH_GPR_ZERO, MAX_TAIL_CALL_CNT); + jmp_offset = ctx->image ? (ctx->offset[insn + 1] - ctx->idx) : 0; if (emit_tailcall_jmp(ctx, BPF_JSGE, t3, t2, jmp_offset) < 0) goto toofar; @@ -340,6 +337,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn) off = offsetof(struct bpf_array, ptrs); emit_insn(ctx, ldd, t2, t2, off); /* beq $t2, $zero, jmp_offset */ + jmp_offset = ctx->image ? (ctx->offset[insn + 1] - ctx->idx) : 0; if (emit_tailcall_jmp(ctx, BPF_JEQ, t2, LOONGARCH_GPR_ZERO, jmp_offset) < 0) goto toofar; @@ -355,8 +353,6 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn) toofar: pr_info_once("tail_call: jump too far\n"); return -1; -#undef cur_offset -#undef jmp_offset } static void emit_store_stack_imm64(struct jit_ctx *ctx, int reg, int stack_off, u64 imm64) -- 2.42.0