2 * Copyright (c) 2002 - 2003 NetGroup, Politecnico di Torino (Italy)
3 * Copyright (c) 2005 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/types.h>
41 #include <sys/socket.h>
42 #include <sys/malloc.h>
46 #include <net/bpf_jitter.h>
48 #include <i386/i386/bpf_jit_machdep.h>
50 bpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, int *);
53 * emit routine to update the jump table
56 emit_length(bpf_bin_stream *stream, u_int value, u_int len)
59 (stream->refs)[stream->bpf_pc] += len;
60 stream->cur_ip += len;
64 * emit routine to output the actual binary code
67 emit_code(bpf_bin_stream *stream, u_int value, u_int len)
72 stream->ibuf[stream->cur_ip] = (u_char)value;
77 *((u_short *)(stream->ibuf + stream->cur_ip)) = (u_short)value;
82 *((u_int *)(stream->ibuf + stream->cur_ip)) = value;
91 * Function that does the real stuff
94 bpf_jit_compile(struct bpf_insn *prog, u_int nins, int *mem)
98 bpf_bin_stream stream;
101 * NOTE: do not modify the name of this variable, as it's used by
102 * the macros to emit code.
106 /* Do not compile an empty filter. */
110 /* Allocate the reference table for the jumps */
111 stream.refs = (u_int *)malloc((nins + 1) * sizeof(u_int),
113 if (stream.refs == NULL)
116 /* Reset the reference table */
117 for (i = 0; i < nins + 1; i++)
124 * the first pass will emit the lengths of the instructions
125 * to create the reference table
133 /* create the procedure header */
141 for (i = 0; i < nins; i++) {
163 case BPF_LD|BPF_W|BPF_ABS:
166 ADDib(ECX, sizeof(int));
167 CMPodd(ECX, EBP, 0x10);
174 MOVobd(EAX, EBX, ESI);
178 case BPF_LD|BPF_H|BPF_ABS:
182 ADDib(ECX, sizeof(short));
183 CMPodd(ECX, EBP, 0x10);
189 MOVobw(AX, EBX, ESI);
193 case BPF_LD|BPF_B|BPF_ABS:
196 CMPodd(ECX, EBP, 0x10);
202 MOVobb(AL, EBX, ECX);
205 case BPF_LD|BPF_W|BPF_LEN:
206 MOVodd(EAX, EBP, 0xc);
209 case BPF_LDX|BPF_W|BPF_LEN:
210 MOVodd(EDX, EBP, 0xc);
213 case BPF_LD|BPF_W|BPF_IND:
217 ADDib(ECX, sizeof(int));
218 CMPodd(ECX, EBP, 0x10);
225 MOVobd(EAX, EBX, ESI);
229 case BPF_LD|BPF_H|BPF_IND:
234 ADDib(ECX, sizeof(short));
235 CMPodd(ECX, EBP, 0x10);
241 MOVobw(AX, EBX, ESI);
245 case BPF_LD|BPF_B|BPF_IND:
249 CMPodd(ECX, EBP, 0x10);
255 MOVobb(AL, EBX, ECX);
258 case BPF_LDX|BPF_MSH|BPF_B:
260 CMPodd(ECX, EBP, 0x10);
268 MOVobb(DL, EBX, ECX);
277 case BPF_LDX|BPF_IMM:
282 MOVid(ECX, (uintptr_t)mem);
283 MOVid(ESI, ins->k * 4);
284 MOVobd(EAX, ECX, ESI);
287 case BPF_LDX|BPF_MEM:
288 MOVid(ECX, (uintptr_t)mem);
289 MOVid(ESI, ins->k * 4);
290 MOVobd(EDX, ECX, ESI);
295 * XXX this command and the following could
296 * be optimized if the previous instruction
297 * was already of this type
299 MOVid(ECX, (uintptr_t)mem);
300 MOVid(ESI, ins->k * 4);
301 MOVomd(ECX, ESI, EAX);
305 MOVid(ECX, (uintptr_t)mem);
306 MOVid(ESI, ins->k * 4);
307 MOVomd(ECX, ESI, EDX);
311 JMP(stream.refs[stream.bpf_pc + ins->k] -
312 stream.refs[stream.bpf_pc]);
315 case BPF_JMP|BPF_JGT|BPF_K:
317 /* 5 is the size of the following JMP */
318 JG(stream.refs[stream.bpf_pc + ins->jt] -
319 stream.refs[stream.bpf_pc] + 5 );
320 JMP(stream.refs[stream.bpf_pc + ins->jf] -
321 stream.refs[stream.bpf_pc]);
324 case BPF_JMP|BPF_JGE|BPF_K:
326 JGE(stream.refs[stream.bpf_pc + ins->jt] -
327 stream.refs[stream.bpf_pc] + 5);
328 JMP(stream.refs[stream.bpf_pc + ins->jf] -
329 stream.refs[stream.bpf_pc]);
332 case BPF_JMP|BPF_JEQ|BPF_K:
334 JE(stream.refs[stream.bpf_pc + ins->jt] -
335 stream.refs[stream.bpf_pc] + 5);
336 JMP(stream.refs[stream.bpf_pc + ins->jf] -
337 stream.refs[stream.bpf_pc]);
340 case BPF_JMP|BPF_JSET|BPF_K:
343 JE(stream.refs[stream.bpf_pc + ins->jf] -
344 stream.refs[stream.bpf_pc] + 5);
345 JMP(stream.refs[stream.bpf_pc + ins->jt] -
346 stream.refs[stream.bpf_pc]);
349 case BPF_JMP|BPF_JGT|BPF_X:
351 JA(stream.refs[stream.bpf_pc + ins->jt] -
352 stream.refs[stream.bpf_pc] + 5);
353 JMP(stream.refs[stream.bpf_pc + ins->jf] -
354 stream.refs[stream.bpf_pc]);
357 case BPF_JMP|BPF_JGE|BPF_X:
359 JAE(stream.refs[stream.bpf_pc + ins->jt] -
360 stream.refs[stream.bpf_pc] + 5);
361 JMP(stream.refs[stream.bpf_pc + ins->jf] -
362 stream.refs[stream.bpf_pc]);
365 case BPF_JMP|BPF_JEQ|BPF_X:
367 JE(stream.refs[stream.bpf_pc + ins->jt] -
368 stream.refs[stream.bpf_pc] + 5);
369 JMP(stream.refs[stream.bpf_pc + ins->jf] -
370 stream.refs[stream.bpf_pc]);
373 case BPF_JMP|BPF_JSET|BPF_X:
376 JE(stream.refs[stream.bpf_pc + ins->jf] -
377 stream.refs[stream.bpf_pc] + 5);
378 JMP(stream.refs[stream.bpf_pc + ins->jt] -
379 stream.refs[stream.bpf_pc]);
382 case BPF_ALU|BPF_ADD|BPF_X:
386 case BPF_ALU|BPF_SUB|BPF_X:
390 case BPF_ALU|BPF_MUL|BPF_X:
396 case BPF_ALU|BPF_DIV|BPF_X:
410 case BPF_ALU|BPF_AND|BPF_X:
414 case BPF_ALU|BPF_OR|BPF_X:
418 case BPF_ALU|BPF_LSH|BPF_X:
423 case BPF_ALU|BPF_RSH|BPF_X:
428 case BPF_ALU|BPF_ADD|BPF_K:
432 case BPF_ALU|BPF_SUB|BPF_K:
436 case BPF_ALU|BPF_MUL|BPF_K:
443 case BPF_ALU|BPF_DIV|BPF_K:
451 case BPF_ALU|BPF_AND|BPF_K:
455 case BPF_ALU|BPF_OR|BPF_K:
459 case BPF_ALU|BPF_LSH|BPF_K:
460 SHLib(EAX, (ins->k) & 255);
463 case BPF_ALU|BPF_RSH|BPF_K:
464 SHRib(EAX, (ins->k) & 255);
467 case BPF_ALU|BPF_NEG:
471 case BPF_MISC|BPF_TAX:
475 case BPF_MISC|BPF_TXA:
486 stream.ibuf = (char *)malloc(stream.cur_ip, M_BPFJIT, M_NOWAIT);
487 if (stream.ibuf == NULL) {
488 free(stream.refs, M_BPFJIT);
493 * modify the reference table to contain the offsets and
494 * not the lengths of the instructions
496 for (i = 1; i < nins + 1; i++)
497 stream.refs[i] += stream.refs[i - 1];
499 /* Reset the counters */
503 /* the second pass creates the actual code */
508 * the reference table is needed only during compilation,
511 free(stream.refs, M_BPFJIT);
513 return (bpf_filter_func)stream.ibuf;