]> www.infradead.org Git - linux.git/commitdiff
bpf: Remove 'may_goto 0' instruction in opt_remove_nops()
authorYonghong Song <yonghong.song@linux.dev>
Sat, 18 Jan 2025 19:20:29 +0000 (11:20 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Mon, 20 Jan 2025 17:46:10 +0000 (09:46 -0800)
Since 'may_goto 0' insns are actually no-op, let us remove them.
Otherwise, verifier will generate code like
   /* r10 - 8 stores the implicit loop count */
   r11 = *(u64 *)(r10 -8)
   if r11 == 0x0 goto pc+2
   r11 -= 1
   *(u64 *)(r10 -8) = r11

which is the pure overhead.

The following code patterns (from the previous commit) are also
handled:
   may_goto 2
   may_goto 1
   may_goto 0

With this commit, the above three 'may_goto' insns are all
eliminated.

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/r/20250118192029.2124584-1-yonghong.song@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index 963dfda81c0612d49651651a1aceb1fdee95748b..74525392714e220857126b0572ff78721055b17c 100644 (file)
@@ -20184,23 +20184,28 @@ static int opt_remove_dead_code(struct bpf_verifier_env *env)
 }
 
 static const struct bpf_insn NOP = BPF_JMP_IMM(BPF_JA, 0, 0, 0);
+static const struct bpf_insn MAY_GOTO_0 = BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 0, 0);
 
 static int opt_remove_nops(struct bpf_verifier_env *env)
 {
-       const struct bpf_insn ja = NOP;
        struct bpf_insn *insn = env->prog->insnsi;
        int insn_cnt = env->prog->len;
+       bool is_may_goto_0, is_ja;
        int i, err;
 
        for (i = 0; i < insn_cnt; i++) {
-               if (memcmp(&insn[i], &ja, sizeof(ja)))
+               is_may_goto_0 = !memcmp(&insn[i], &MAY_GOTO_0, sizeof(MAY_GOTO_0));
+               is_ja = !memcmp(&insn[i], &NOP, sizeof(NOP));
+
+               if (!is_may_goto_0 && !is_ja)
                        continue;
 
                err = verifier_remove_insns(env, i, 1);
                if (err)
                        return err;
                insn_cnt--;
-               i--;
+               /* Go back one insn to catch may_goto +1; may_goto +0 sequence */
+               i -= (is_may_goto_0 && i > 0) ? 2 : 1;
        }
 
        return 0;