bpf_jit_machdep.c revision 181645
11541Srgrimes/*- 21541Srgrimes * Copyright (c) 2002 - 2003 NetGroup, Politecnico di Torino (Italy) 31541Srgrimes * Copyright (c) 2005 Jung-uk Kim <jkim@FreeBSD.org> 41541Srgrimes * All rights reserved. 551138Salfred * 6194263Sjhb * Redistribution and use in source and binary forms, with or without 71541Srgrimes * modification, are permitted provided that the following conditions 81541Srgrimes * are met: 9106149Sdwmalone * 101541Srgrimes * 1. Redistributions of source code must retain the above copyright 1164002Speter * notice, this list of conditions and the following disclaimer. 121541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 131541Srgrimes * notice, this list of conditions and the following disclaimer in the 141541Srgrimes * documentation and/or other materials provided with the distribution. 151541Srgrimes * 3. Neither the name of the Politecnico di Torino nor the names of its 161541Srgrimes * contributors may be used to endorse or promote products derived from 171541Srgrimes * this software without specific prior written permission. 18171210Speter * 191541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 201541Srgrimes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 211541Srgrimes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 221541Srgrimes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 231541Srgrimes * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 241541Srgrimes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 251541Srgrimes * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 261541Srgrimes * DATA, OR PROFITS; OR BUSINESS intERRUPTION) HOWEVER CAUSED AND ON ANY 271541Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28171210Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29171210Speter * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 301541Srgrimes */ 311541Srgrimes 321541Srgrimes#include <sys/cdefs.h> 331541Srgrimes__FBSDID("$FreeBSD: head/sys/i386/i386/bpf_jit_machdep.c 181645 2008-08-12 20:12:59Z jkim $"); 341541Srgrimes 351541Srgrimes#include "opt_bpf.h" 361541Srgrimes 371541Srgrimes#include <sys/param.h> 381541Srgrimes#include <sys/systm.h> 391541Srgrimes#include <sys/kernel.h> 401541Srgrimes#include <sys/types.h> 411541Srgrimes#include <sys/socket.h> 421541Srgrimes#include <sys/malloc.h> 431541Srgrimes 441541Srgrimes#include <net/if.h> 451541Srgrimes#include <net/bpf.h> 461541Srgrimes#include <net/bpf_jitter.h> 471541Srgrimes 48171210Speter#include <i386/i386/bpf_jit_machdep.h> 491541Srgrimes 50171210Speterbpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, int *); 511541Srgrimes 521541Srgrimes/* 531541Srgrimes * emit routine to update the jump table 541541Srgrimes */ 551541Srgrimesstatic void 56171210Speteremit_length(bpf_bin_stream *stream, u_int value, u_int len) 571541Srgrimes{ 58171210Speter 591541Srgrimes (stream->refs)[stream->bpf_pc] += len; 601541Srgrimes stream->cur_ip += len; 611541Srgrimes} 62171210Speter 631541Srgrimes/* 641541Srgrimes * emit routine to output the actual binary code 651541Srgrimes */ 661541Srgrimesstatic void 671541Srgrimesemit_code(bpf_bin_stream *stream, u_int value, u_int len) 681541Srgrimes{ 691541Srgrimes 701541Srgrimes switch (len) { 711541Srgrimes case 1: 72171210Speter stream->ibuf[stream->cur_ip] = (u_char)value; 73171210Speter stream->cur_ip++; 74171210Speter break; 751541Srgrimes 761541Srgrimes case 2: 771541Srgrimes *((u_short *)(stream->ibuf + stream->cur_ip)) = (u_short)value; 781541Srgrimes stream->cur_ip += 2; 791541Srgrimes break; 801541Srgrimes 81171210Speter case 4: 821541Srgrimes *((u_int *)(stream->ibuf + stream->cur_ip)) = value; 831541Srgrimes stream->cur_ip += 4; 841541Srgrimes break; 851541Srgrimes } 861541Srgrimes 871541Srgrimes return; 881541Srgrimes} 891541Srgrimes 901541Srgrimes/* 911541Srgrimes * Function that does the real stuff 921541Srgrimes */ 931541Srgrimesbpf_filter_func 94171210Speterbpf_jit_compile(struct bpf_insn *prog, u_int nins, int *mem) 951541Srgrimes{ 961541Srgrimes struct bpf_insn *ins; 97171210Speter u_int i, pass; 98171210Speter bpf_bin_stream stream; 991541Srgrimes 1001541Srgrimes /* 1011541Srgrimes * NOTE: do not modify the name of this variable, as it's used by 1021541Srgrimes * the macros to emit code. 1031541Srgrimes */ 1041541Srgrimes emit_func emitm; 1051541Srgrimes 1061541Srgrimes /* Do not compile an empty filter. */ 1071541Srgrimes if (nins == 0) 1081541Srgrimes return NULL; 109171210Speter 1101541Srgrimes /* Allocate the reference table for the jumps */ 111171210Speter stream.refs = (u_int *)malloc((nins + 1) * sizeof(u_int), 112171210Speter M_BPFJIT, M_NOWAIT); 113171210Speter if (stream.refs == NULL) 1141541Srgrimes return NULL; 1151541Srgrimes 1161541Srgrimes /* Reset the reference table */ 1171541Srgrimes for (i = 0; i < nins + 1; i++) 118171210Speter stream.refs[i] = 0; 119171210Speter 120171210Speter stream.cur_ip = 0; 121171210Speter stream.bpf_pc = 0; 122171210Speter 123171210Speter /* 124171210Speter * the first pass will emit the lengths of the instructions 1251541Srgrimes * to create the reference table 1261541Srgrimes */ 1271541Srgrimes emitm = emit_length; 1281541Srgrimes 12914220Speter pass = 0; 1301541Srgrimes for (;;) { 1311541Srgrimes ins = prog; 1321541Srgrimes 1331541Srgrimes /* create the procedure header */ 1341541Srgrimes PUSH(EBP); 135171210Speter MOVrd(ESP, EBP); 1368019Sache PUSH(EDI); 1378019Sache PUSH(ESI); 1381541Srgrimes PUSH(EBX); 139171210Speter MOVodd(8, EBP, EBX); 140171210Speter MOVodd(16, EBP, EDI); 1411541Srgrimes 1421541Srgrimes for (i = 0; i < nins; i++) { 1431541Srgrimes stream.bpf_pc++; 1441541Srgrimes 1451541Srgrimes switch (ins->code) { 1461541Srgrimes default: 1471541Srgrimes return NULL; 1481541Srgrimes 1491541Srgrimes case BPF_RET|BPF_K: 1501541Srgrimes MOVid(ins->k, EAX); 151171210Speter POP(EBX); 152171210Speter POP(ESI); 153171210Speter POP(EDI); 154171210Speter LEAVE_RET(); 155171210Speter break; 156171210Speter 1571541Srgrimes case BPF_RET|BPF_A: 1581541Srgrimes POP(EBX); 159171210Speter POP(ESI); 160171210Speter POP(EDI); 16114220Speter LEAVE_RET(); 16214220Speter break; 16314220Speter 164177634Sdfr case BPF_LD|BPF_W|BPF_ABS: 1651541Srgrimes MOVid(ins->k, ECX); 166171210Speter MOVrd(ECX, ESI); 167171210Speter ADDib(sizeof(int), ECX); 168171210Speter CMPrd(EDI, ECX); 1691541Srgrimes JLEb(7); 170127891Sdfr ZEROrd(EAX); 1711541Srgrimes POP(EBX); 172184790Sed POP(ESI); 173184790Sed POP(EDI); 174184790Sed LEAVE_RET(); 1751549Srgrimes MOVobd(EBX, ESI, EAX); 1762442Sdg BSWAP(EAX); 1771541Srgrimes break; 1781541Srgrimes 1792729Sdfr case BPF_LD|BPF_H|BPF_ABS: 1802729Sdfr ZEROrd(EAX); 1811541Srgrimes MOVid(ins->k, ECX); 1821541Srgrimes MOVrd(ECX, ESI); 183171210Speter ADDib(sizeof(short), ECX); 184171210Speter CMPrd(EDI, ECX); 185178888Sjulian JLEb(5); 1862297Swollman POP(EBX); 18714220Speter POP(ESI); 18814220Speter POP(EDI); 18914220Speter LEAVE_RET(); 1901541Srgrimes MOVobw(EBX, ESI, AX); 1911541Srgrimes SWAP_AX(); 1921541Srgrimes break; 1931541Srgrimes 19432889Sphk case BPF_LD|BPF_B|BPF_ABS: 19532889Sphk ZEROrd(EAX); 19632889Sphk MOVid(ins->k, ECX); 19732889Sphk CMPrd(EDI, ECX); 1981541Srgrimes JLEb(5); 1991541Srgrimes POP(EBX); 2001541Srgrimes POP(ESI); 2011541Srgrimes POP(EDI); 2021541Srgrimes LEAVE_RET(); 2031541Srgrimes MOVobb(EBX, ECX, AL); 2041541Srgrimes break; 2051541Srgrimes 2061541Srgrimes case BPF_LD|BPF_W|BPF_LEN: 207171210Speter MOVodd(0xc, EBP, EAX); 2081541Srgrimes break; 209171210Speter 210171210Speter case BPF_LDX|BPF_W|BPF_LEN: 211171210Speter MOVodd(0xc, EBP, EDX); 2121541Srgrimes break; 2131541Srgrimes 2141541Srgrimes case BPF_LD|BPF_W|BPF_IND: 21535938Sdyson MOVid(ins->k, ECX); 21635938Sdyson ADDrd(EDX, ECX); 21728400Speter MOVrd(ECX, ESI); 21825582Speter ADDib(sizeof(int), ECX); 21929349Speter CMPrd(EDI, ECX); 2202124Sdg JLEb(7); 2212124Sdg ZEROrd(EAX); 2222124Sdg POP(EBX); 2232124Sdg POP(ESI); 2242124Sdg POP(EDI); 2252124Sdg LEAVE_RET(); 2262124Sdg MOVobd(EBX, ESI, EAX); 2272124Sdg BSWAP(EAX); 2282124Sdg break; 2292124Sdg 23012865Speter case BPF_LD|BPF_H|BPF_IND: 23112865Speter ZEROrd(EAX); 23212865Speter MOVid(ins->k, ECX); 23359829Speter ADDrd(EDX, ECX); 23412865Speter MOVrd(ECX, ESI); 23512865Speter ADDib(sizeof(short), ECX); 23612865Speter CMPrd(EDI, ECX); 23712865Speter JLEb(5); 23812865Speter POP(EBX); 23912865Speter POP(ESI); 24012865Speter POP(EDI); 24112865Speter LEAVE_RET(); 24225582Speter MOVobw(EBX, ESI, AX); 24325582Speter SWAP_AX(); 24425582Speter break; 245156138Sdavidxu 246156138Sdavidxu case BPF_LD|BPF_B|BPF_IND: 247156138Sdavidxu ZEROrd(EAX); 248156138Sdavidxu MOVid(ins->k, ECX); 249156138Sdavidxu ADDrd(EDX, ECX); 25025582Speter CMPrd(EDI, ECX); 25114220Speter JLEb(5); 25214220Speter POP(EBX); 25314220Speter POP(ESI); 25414220Speter POP(EDI); 25514220Speter LEAVE_RET(); 25614220Speter MOVobb(EBX, ECX, AL); 25714220Speter break; 258137875Smarks 25914220Speter case BPF_LDX|BPF_MSH|BPF_B: 26014220Speter MOVid(ins->k, ECX); 26114220Speter CMPrd(EDI, ECX); 26229349Speter JLEb(7); 26324452Speter ZEROrd(EAX); 26424440Speter POP(EBX); 265151868Sdavidxu POP(ESI); 266151868Sdavidxu POP(EDI); 267151868Sdavidxu LEAVE_RET(); 268152846Sdavidxu ZEROrd(EDX); 269152846Sdavidxu MOVobb(EBX, ECX, DL); 270152846Sdavidxu ANDib(0xf, DL); 271152846Sdavidxu SHLib(2, EDX); 272152846Sdavidxu break; 273152846Sdavidxu 27425537Sdfr case BPF_LD|BPF_IMM: 27525537Sdfr MOVid(ins->k, EAX); 27625537Sdfr break; 27725537Sdfr 27825537Sdfr case BPF_LDX|BPF_IMM: 27925537Sdfr MOVid(ins->k, EDX); 28025537Sdfr break; 28125537Sdfr 28235938Sdyson case BPF_LD|BPF_MEM: 28325537Sdfr MOVid((uintptr_t)mem, ECX); 28435938Sdyson MOVid(ins->k * 4, ESI); 28535938Sdyson MOVobd(ECX, ESI, EAX); 28635938Sdyson break; 28735938Sdyson 28835938Sdyson case BPF_LDX|BPF_MEM: 28935938Sdyson MOVid((uintptr_t)mem, ECX); 29035938Sdyson MOVid(ins->k * 4, ESI); 29125537Sdfr MOVobd(ECX, ESI, EDX); 29225537Sdfr break; 29325537Sdfr 29425537Sdfr case BPF_ST: 29525537Sdfr /* 29625537Sdfr * XXX this command and the following could 29725537Sdfr * be optimized if the previous instruction 29825537Sdfr * was already of this type 299147814Sjhb */ 300147814Sjhb MOVid((uintptr_t)mem, ECX); 30125537Sdfr MOVid(ins->k * 4, ESI); 30225537Sdfr MOVomd(EAX, ECX, ESI); 30325537Sdfr break; 30425537Sdfr 30525537Sdfr case BPF_STX: 30625537Sdfr MOVid((uintptr_t)mem, ECX); 307171210Speter MOVid(ins->k * 4, ESI); 30851138Salfred MOVomd(EDX, ECX, ESI); 30951138Salfred break; 31025537Sdfr 31125537Sdfr case BPF_JMP|BPF_JA: 31225537Sdfr JMP(stream.refs[stream.bpf_pc + ins->k] - 31325537Sdfr stream.refs[stream.bpf_pc]); 31425537Sdfr break; 31525537Sdfr 31625537Sdfr case BPF_JMP|BPF_JGT|BPF_K: 31725537Sdfr CMPid(ins->k, EAX); 31825537Sdfr /* 5 is the size of the following JMP */ 31925537Sdfr JG(stream.refs[stream.bpf_pc + ins->jt] - 32028400Speter stream.refs[stream.bpf_pc] + 5 ); 32156115Speter JMP(stream.refs[stream.bpf_pc + ins->jf] - 32256115Speter stream.refs[stream.bpf_pc]); 32336034Speter break; 32426671Sdyson 32526671Sdyson case BPF_JMP|BPF_JGE|BPF_K: 32626671Sdyson CMPid(ins->k, EAX); 32726671Sdyson JGE(stream.refs[stream.bpf_pc + ins->jt] - 328151868Sdavidxu stream.refs[stream.bpf_pc] + 5); 329151868Sdavidxu JMP(stream.refs[stream.bpf_pc + ins->jf] - 330151868Sdavidxu stream.refs[stream.bpf_pc]); 33126671Sdyson break; 33269514Sjake 33369514Sjake case BPF_JMP|BPF_JEQ|BPF_K: 33426671Sdyson CMPid(ins->k, EAX); 33526671Sdyson JE(stream.refs[stream.bpf_pc + ins->jt] - 33629391Sphk stream.refs[stream.bpf_pc] + 5); 33734925Sdufault JMP(stream.refs[stream.bpf_pc + ins->jf] - 33834925Sdufault stream.refs[stream.bpf_pc]); 33934925Sdufault break; 34034925Sdufault 34134925Sdufault case BPF_JMP|BPF_JSET|BPF_K: 34234925Sdufault MOVrd(EAX, ECX); 34334925Sdufault ANDid(ins->k, ECX); 34434925Sdufault JE(stream.refs[stream.bpf_pc + ins->jf] - 34535938Sdyson stream.refs[stream.bpf_pc] + 5); 346171210Speter JMP(stream.refs[stream.bpf_pc + ins->jt] - 34741089Speter stream.refs[stream.bpf_pc]); 34846155Sphk break; 34949420Sjkh 35051791Smarcel case BPF_JMP|BPF_JGT|BPF_X: 35151791Smarcel CMPrd(EDX, EAX); 352171210Speter JA(stream.refs[stream.bpf_pc + ins->jt] - 35351791Smarcel stream.refs[stream.bpf_pc] + 5); 354171210Speter JMP(stream.refs[stream.bpf_pc + ins->jf] - 355112895Sjeff stream.refs[stream.bpf_pc]); 356112895Sjeff break; 35756271Srwatson 35856271Srwatson case BPF_JMP|BPF_JGE|BPF_X: 35956271Srwatson CMPrd(EDX, EAX); 36056271Srwatson JAE(stream.refs[stream.bpf_pc + ins->jt] - 36156271Srwatson stream.refs[stream.bpf_pc] + 5); 36256271Srwatson JMP(stream.refs[stream.bpf_pc + ins->jf] - 36356271Srwatson stream.refs[stream.bpf_pc]); 36456271Srwatson break; 36554803Srwatson 36654803Srwatson case BPF_JMP|BPF_JEQ|BPF_X: 36754803Srwatson CMPrd(EDX, EAX); 36854803Srwatson JE(stream.refs[stream.bpf_pc + ins->jt] - 36955943Sjasone stream.refs[stream.bpf_pc] + 5); 37056115Speter JMP(stream.refs[stream.bpf_pc + ins->jf] - 37156115Speter stream.refs[stream.bpf_pc]); 37259288Sjlemon break; 37359288Sjlemon 37498198Srwatson case BPF_JMP|BPF_JSET|BPF_X: 37598198Srwatson MOVrd(EAX, ECX); 37698198Srwatson ANDrd(EDX, ECX); 37798198Srwatson JE(stream.refs[stream.bpf_pc + ins->jf] - 37898198Srwatson stream.refs[stream.bpf_pc] + 5); 37998198Srwatson JMP(stream.refs[stream.bpf_pc + ins->jt] - 380183362Sjhb stream.refs[stream.bpf_pc]); 38175039Srwatson break; 38275039Srwatson 38375039Srwatson case BPF_ALU|BPF_ADD|BPF_X: 38475427Srwatson ADDrd(EDX, EAX); 38583652Speter break; 38683796Srwatson 38784884Srwatson case BPF_ALU|BPF_SUB|BPF_X: 38885891Sphk SUBrd(EDX, EAX); 389177091Sjeff break; 390177091Sjeff 391177091Sjeff case BPF_ALU|BPF_MUL|BPF_X: 392177091Sjeff MOVrd(EDX, ECX); 393177091Sjeff MULrd(EDX); 394100897Srwatson MOVrd(ECX, EDX); 395100897Srwatson break; 396100897Srwatson 397100897Srwatson case BPF_ALU|BPF_DIV|BPF_X: 398100897Srwatson CMPid(0, EDX); 399100897Srwatson JNEb(7); 40094936Smux ZEROrd(EAX); 40196084Smux POP(EBX); 40297372Smarcel POP(ESI); 40399856Salfred POP(EDI); 404101426Srwatson LEAVE_RET(); 405122540Smckusick MOVrd(EDX, ECX); 406122540Smckusick ZEROrd(EDX); 407122540Smckusick DIVrd(ECX); 408122540Smckusick MOVrd(ECX, EDX); 409103575Salfred break; 410103575Salfred 411103575Salfred case BPF_ALU|BPF_AND|BPF_X: 412103575Salfred ANDrd(EDX, EAX); 413103575Salfred break; 414103575Salfred 415103575Salfred case BPF_ALU|BPF_OR|BPF_X: 416103575Salfred ORrd(EDX, EAX); 417103575Salfred break; 418103575Salfred 419105692Srwatson case BPF_ALU|BPF_LSH|BPF_X: 420105692Srwatson MOVrd(EDX, ECX); 421105692Srwatson SHL_CLrb(EAX); 422104731Srwatson break; 423104731Srwatson 424104731Srwatson case BPF_ALU|BPF_RSH|BPF_X: 425106467Srwatson MOVrd(EDX, ECX); 426105950Speter SHR_CLrb(EAX); 427105950Speter break; 428105692Srwatson 429105692Srwatson case BPF_ALU|BPF_ADD|BPF_K: 430105692Srwatson ADD_EAXi(ins->k); 431106978Sdeischen break; 432106978Sdeischen 433106978Sdeischen case BPF_ALU|BPF_SUB|BPF_K: 434107914Sdillon SUB_EAXi(ins->k); 435108406Srwatson break; 436108406Srwatson 437108406Srwatson case BPF_ALU|BPF_MUL|BPF_K: 438108406Srwatson MOVrd(EDX, ECX); 439112895Sjeff MOVid(ins->k, EDX); 440112902Sjeff MULrd(EDX); 441112902Sjeff MOVrd(ECX, EDX); 442112902Sjeff break; 443112902Sjeff 444112909Sjeff case BPF_ALU|BPF_DIV|BPF_K: 445112909Sjeff MOVrd(EDX, ECX); 446113276Smike ZEROrd(EDX); 447115800Srwatson MOVid(ins->k, ESI); 448115800Srwatson DIVrd(ESI); 449115800Srwatson MOVrd(ECX, EDX); 450177091Sjeff break; 451125369Sdeischen 452127484Smtm case BPF_ALU|BPF_AND|BPF_K: 453127484Smtm ANDid(ins->k, EAX); 454132117Sphk break; 455136831Srwatson 456136831Srwatson case BPF_ALU|BPF_OR|BPF_K: 457136831Srwatson ORid(ins->k, EAX); 458136831Srwatson break; 459136831Srwatson 460136831Srwatson case BPF_ALU|BPF_LSH|BPF_K: 461136831Srwatson SHLib((ins->k) & 0xff, EAX); 462136831Srwatson break; 463136831Srwatson 464139013Sdavidxu case BPF_ALU|BPF_RSH|BPF_K: 465145435Sdavidxu SHRib((ins->k) & 0xff, EAX); 466151317Sdavidxu break; 467156138Sdavidxu 468156138Sdavidxu case BPF_ALU|BPF_NEG: 469156138Sdavidxu NEGd(EAX); 470156138Sdavidxu break; 471156138Sdavidxu 472156138Sdavidxu case BPF_MISC|BPF_TAX: 473153681Sphk MOVrd(EAX, EDX); 474155328Sdavidxu break; 475157039Sdavidxu 476162498Sdavidxu case BPF_MISC|BPF_TXA: 477162498Sdavidxu MOVrd(EDX, EAX); 478162498Sdavidxu break; 479161679Sdavidxu } 480161679Sdavidxu ins++; 481163953Srrs } 482163953Srrs 483163953Srrs pass++; 484163953Srrs if (pass == 2) 485171210Speter break; 486171210Speter 487171210Speter stream.ibuf = (char *)malloc(stream.cur_ip, M_BPFJIT, M_NOWAIT); 488171210Speter if (stream.ibuf == NULL) { 489171210Speter free(stream.refs, M_BPFJIT); 490171210Speter return NULL; 491171861Sdavidxu } 492175165Sjhb 493175165Sjhb /* 494176731Sjeff * modify the reference table to contain the offsets and 495176731Sjeff * not the lengths of the instructions 496176731Sjeff */ 497176731Sjeff for (i = 1; i < nins + 1; i++) 498176731Sjeff stream.refs[i] += stream.refs[i - 1]; 499177790Skib 500177790Skib /* Reset the counters */ 501177790Skib stream.cur_ip = 0; 502177790Skib stream.bpf_pc = 0; 503177790Skib 504177790Skib /* the second pass creates the actual code */ 505177790Skib emitm = emit_code; 506177790Skib } 507177790Skib 508177790Skib /* 509177790Skib * the reference table is needed only during compilation, 510177790Skib * now we can free it 511177790Skib */ 512177790Skib free(stream.refs, M_BPFJIT); 513177790Skib 514181905Sed return (bpf_filter_func)stream.ibuf; 515184589Sdfr} 516191675Sjamie