2 * Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy)
3 * Copyright (C) 2005-2008 Jung-uk Kim <jkim@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Politecnico di Torino nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/socket.h>
41 #include <sys/malloc.h>
47 #include <sys/types.h>
50 #include <net/bpf_jitter.h>
52 #include <i386/i386/bpf_jit_machdep.h>
54 bpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, int *);
57 * emit routine to update the jump table
60 emit_length(bpf_bin_stream *stream, __unused u_int value, u_int len)
63 (stream->refs)[stream->bpf_pc] += len;
64 stream->cur_ip += len;
68 * emit routine to output the actual binary code
71 emit_code(bpf_bin_stream *stream, u_int value, u_int len)
76 stream->ibuf[stream->cur_ip] = (u_char)value;
81 *((u_short *)(stream->ibuf + stream->cur_ip)) = (u_short)value;
86 *((u_int *)(stream->ibuf + stream->cur_ip)) = value;
95 * Function that does the real stuff
98 bpf_jit_compile(struct bpf_insn *prog, u_int nins, int *mem)
100 struct bpf_insn *ins;
102 bpf_bin_stream stream;
105 * NOTE: do not modify the name of this variable, as it's used by
106 * the macros to emit code.
110 /* Allocate the reference table for the jumps */
112 stream.refs = (u_int *)malloc((nins + 1) * sizeof(u_int),
115 stream.refs = (u_int *)malloc((nins + 1) * sizeof(u_int));
117 if (stream.refs == NULL)
120 /* Reset the reference table */
121 for (i = 0; i < nins + 1; i++)
128 * the first pass will emit the lengths of the instructions
129 * to create the reference table
137 /* create the procedure header */
144 MOVodd(16, EBP, EDI);
146 for (i = 0; i < nins; i++) {
172 case BPF_LD|BPF_W|BPF_ABS:
178 CMPid(sizeof(int32_t), ECX);
185 MOVobd(EBX, ESI, EAX);
189 case BPF_LD|BPF_H|BPF_ABS:
196 CMPid(sizeof(int16_t), ECX);
202 MOVobw(EBX, ESI, AX);
206 case BPF_LD|BPF_B|BPF_ABS:
215 MOVobb(EBX, ESI, AL);
218 case BPF_LD|BPF_W|BPF_LEN:
219 MOVodd(12, EBP, EAX);
222 case BPF_LDX|BPF_W|BPF_LEN:
223 MOVodd(12, EBP, EDX);
226 case BPF_LD|BPF_W|BPF_IND:
237 CMPid(sizeof(int32_t), ECX);
244 MOVobd(EBX, ESI, EAX);
248 case BPF_LD|BPF_H|BPF_IND:
260 CMPid(sizeof(int16_t), ECX);
266 MOVobw(EBX, ESI, AX);
270 case BPF_LD|BPF_B|BPF_IND:
284 MOVobb(EBX, ESI, AL);
287 case BPF_LDX|BPF_MSH|BPF_B:
297 MOVobb(EBX, ESI, DL);
306 case BPF_LDX|BPF_IMM:
311 MOVid((uintptr_t)mem, ECX);
312 MOVid(ins->k * 4, ESI);
313 MOVobd(ECX, ESI, EAX);
316 case BPF_LDX|BPF_MEM:
317 MOVid((uintptr_t)mem, ECX);
318 MOVid(ins->k * 4, ESI);
319 MOVobd(ECX, ESI, EDX);
324 * XXX this command and the following could
325 * be optimized if the previous instruction
326 * was already of this type
328 MOVid((uintptr_t)mem, ECX);
329 MOVid(ins->k * 4, ESI);
330 MOVomd(EAX, ECX, ESI);
334 MOVid((uintptr_t)mem, ECX);
335 MOVid(ins->k * 4, ESI);
336 MOVomd(EDX, ECX, ESI);
340 JMP(stream.refs[stream.bpf_pc + ins->k] -
341 stream.refs[stream.bpf_pc]);
344 case BPF_JMP|BPF_JGT|BPF_K:
345 if (ins->jt == 0 && ins->jf == 0)
351 case BPF_JMP|BPF_JGE|BPF_K:
352 if (ins->jt == 0 && ins->jf == 0)
358 case BPF_JMP|BPF_JEQ|BPF_K:
359 if (ins->jt == 0 && ins->jf == 0)
365 case BPF_JMP|BPF_JSET|BPF_K:
366 if (ins->jt == 0 && ins->jf == 0)
372 case BPF_JMP|BPF_JGT|BPF_X:
373 if (ins->jt == 0 && ins->jf == 0)
379 case BPF_JMP|BPF_JGE|BPF_X:
380 if (ins->jt == 0 && ins->jf == 0)
386 case BPF_JMP|BPF_JEQ|BPF_X:
387 if (ins->jt == 0 && ins->jf == 0)
393 case BPF_JMP|BPF_JSET|BPF_X:
394 if (ins->jt == 0 && ins->jf == 0)
400 case BPF_ALU|BPF_ADD|BPF_X:
404 case BPF_ALU|BPF_SUB|BPF_X:
408 case BPF_ALU|BPF_MUL|BPF_X:
414 case BPF_ALU|BPF_DIV|BPF_X:
428 case BPF_ALU|BPF_AND|BPF_X:
432 case BPF_ALU|BPF_OR|BPF_X:
436 case BPF_ALU|BPF_LSH|BPF_X:
441 case BPF_ALU|BPF_RSH|BPF_X:
446 case BPF_ALU|BPF_ADD|BPF_K:
450 case BPF_ALU|BPF_SUB|BPF_K:
454 case BPF_ALU|BPF_MUL|BPF_K:
461 case BPF_ALU|BPF_DIV|BPF_K:
469 case BPF_ALU|BPF_AND|BPF_K:
473 case BPF_ALU|BPF_OR|BPF_K:
477 case BPF_ALU|BPF_LSH|BPF_K:
478 SHLib((ins->k) & 0xff, EAX);
481 case BPF_ALU|BPF_RSH|BPF_K:
482 SHRib((ins->k) & 0xff, EAX);
485 case BPF_ALU|BPF_NEG:
489 case BPF_MISC|BPF_TAX:
493 case BPF_MISC|BPF_TXA:
505 stream.ibuf = (char *)malloc(stream.cur_ip, M_BPFJIT, M_NOWAIT);
506 if (stream.ibuf == NULL) {
507 free(stream.refs, M_BPFJIT);
511 stream.ibuf = (char *)malloc(stream.cur_ip);
512 if (stream.ibuf == NULL) {
519 * modify the reference table to contain the offsets and
520 * not the lengths of the instructions
522 for (i = 1; i < nins + 1; i++)
523 stream.refs[i] += stream.refs[i - 1];
525 /* Reset the counters */
529 /* the second pass creates the actual code */
534 * the reference table is needed only during compilation,
538 free(stream.refs, M_BPFJIT);
543 return ((bpf_filter_func)stream.ibuf);