bpf, x86: detect/optimize loading 0 immediates
authorDaniel Borkmann <daniel@iogearbox.net>
Thu, 17 Dec 2015 22:51:56 +0000 (23:51 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 18 Dec 2015 21:04:51 +0000 (16:04 -0500)
When sometimes structs or variables need to be initialized/'memset' to 0 in
an eBPF C program, the x86 BPF JIT converts this to use immediates. We can
however save a couple of bytes (f.e. even up to 7 bytes on a single emmission
of BPF_LD | BPF_IMM | BPF_DW) in the image by detecting such case and use xor
on the dst register instead.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
arch/x86/net/bpf_jit_comp.c

index c080e812ce85afb4988ba2226c669b9c8f5e98ba..4286f3618bd07c32bba605874c4f9915be47820e 100644 (file)
@@ -459,6 +459,18 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
                        }
 
                case BPF_ALU | BPF_MOV | BPF_K:
+                       /* optimization: if imm32 is zero, use 'xor <dst>,<dst>'
+                        * to save 3 bytes.
+                        */
+                       if (imm32 == 0) {
+                               if (is_ereg(dst_reg))
+                                       EMIT1(add_2mod(0x40, dst_reg, dst_reg));
+                               b2 = 0x31; /* xor */
+                               b3 = 0xC0;
+                               EMIT2(b2, add_2reg(b3, dst_reg, dst_reg));
+                               break;
+                       }
+
                        /* mov %eax, imm32 */
                        if (is_ereg(dst_reg))
                                EMIT1(add_1mod(0x40, dst_reg));
@@ -473,6 +485,20 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
                                return -EINVAL;
                        }
 
+                       /* optimization: if imm64 is zero, use 'xor <dst>,<dst>'
+                        * to save 7 bytes.
+                        */
+                       if (insn[0].imm == 0 && insn[1].imm == 0) {
+                               b1 = add_2mod(0x48, dst_reg, dst_reg);
+                               b2 = 0x31; /* xor */
+                               b3 = 0xC0;
+                               EMIT3(b1, b2, add_2reg(b3, dst_reg, dst_reg));
+
+                               insn++;
+                               i++;
+                               break;
+                       }
+
                        /* movabsq %rax, imm64 */
                        EMIT2(add_1mod(0x48, dst_reg), add_1reg(0xB8, dst_reg));
                        EMIT(insn[0].imm, 4);