[PATCH v1 3/4] LoongArch: BPF: Refactor jump offset calculation in tail call
From: Tiezhu Yang
Date: Mon Jun 29 2026 - 22:29:18 EST
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".
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.
Signed-off-by: Tiezhu Yang <yangtiezhu@xxxxxxxxxxx>
---
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..b30132f44541 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->offset[insn + 1] - ctx->idx;
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->offset[insn + 1] - ctx->idx;
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->offset[insn + 1] - ctx->idx;
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