Add an experimental and rudimentary JIT optimizer to reduce unncessary
overhead from short BPF filter programs such as "get the first 96 bytes".
This commit is contained in:
parent
080136212f
commit
35012a1e69
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=199619
@ -57,18 +57,19 @@ __FBSDID("$FreeBSD$");
|
||||
bpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, size_t *);
|
||||
|
||||
/*
|
||||
* emit routine to update the jump table
|
||||
* Emit routine to update the jump table.
|
||||
*/
|
||||
static void
|
||||
emit_length(bpf_bin_stream *stream, __unused u_int value, u_int len)
|
||||
{
|
||||
|
||||
(stream->refs)[stream->bpf_pc] += len;
|
||||
if (stream->refs != NULL)
|
||||
(stream->refs)[stream->bpf_pc] += len;
|
||||
stream->cur_ip += len;
|
||||
}
|
||||
|
||||
/*
|
||||
* emit routine to output the actual binary code
|
||||
* Emit routine to output the actual binary code.
|
||||
*/
|
||||
static void
|
||||
emit_code(bpf_bin_stream *stream, u_int value, u_int len)
|
||||
@ -95,37 +96,79 @@ emit_code(bpf_bin_stream *stream, u_int value, u_int len)
|
||||
}
|
||||
|
||||
/*
|
||||
* Function that does the real stuff
|
||||
* Scan the filter program and find possible optimization.
|
||||
*/
|
||||
static int
|
||||
bpf_jit_optimize(struct bpf_insn *prog, u_int nins)
|
||||
{
|
||||
const struct bpf_insn *p;
|
||||
int flags;
|
||||
u_int i;
|
||||
|
||||
/* Do we return immediately? */
|
||||
if (BPF_CLASS(prog[0].code) == BPF_RET)
|
||||
return (BPF_JIT_FLAG_RET);
|
||||
|
||||
for (flags = 0, i = 0; i < nins; i++) {
|
||||
p = &prog[i];
|
||||
|
||||
/* Do we need reference table? */
|
||||
if ((flags & BPF_JIT_FLAG_JMP) == 0 &&
|
||||
BPF_CLASS(p->code) == BPF_JMP)
|
||||
flags |= BPF_JIT_FLAG_JMP;
|
||||
|
||||
/* Do we need scratch memory? */
|
||||
if ((flags & BPF_JIT_FLAG_MEM) == 0 &&
|
||||
(p->code == BPF_ST || p->code == BPF_STX ||
|
||||
p->code == (BPF_LD|BPF_MEM) ||
|
||||
p->code == (BPF_LDX|BPF_MEM)))
|
||||
flags |= BPF_JIT_FLAG_MEM;
|
||||
|
||||
if (flags == BPF_JIT_FLAG_ALL)
|
||||
break;
|
||||
}
|
||||
|
||||
return (flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function that does the real stuff.
|
||||
*/
|
||||
bpf_filter_func
|
||||
bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
{
|
||||
bpf_bin_stream stream;
|
||||
struct bpf_insn *ins;
|
||||
int flags, flag_ret, flag_jmp, flag_mem;
|
||||
u_int i, pass;
|
||||
|
||||
flags = bpf_jit_optimize(prog, nins);
|
||||
flag_ret = (flags & BPF_JIT_FLAG_RET) != 0;
|
||||
flag_jmp = (flags & BPF_JIT_FLAG_JMP) != 0;
|
||||
flag_mem = (flags & BPF_JIT_FLAG_MEM) != 0;
|
||||
|
||||
/*
|
||||
* NOTE: Do not modify the name of this variable, as it's used by
|
||||
* the macros to emit code.
|
||||
*/
|
||||
emit_func emitm;
|
||||
|
||||
/* Allocate the reference table for the jumps. */
|
||||
#ifdef _KERNEL
|
||||
stream.refs = malloc((nins + 1) * sizeof(u_int), M_BPFJIT,
|
||||
M_NOWAIT | M_ZERO);
|
||||
#else
|
||||
stream.refs = malloc((nins + 1) * sizeof(u_int));
|
||||
#endif
|
||||
if (stream.refs == NULL)
|
||||
return (NULL);
|
||||
#ifndef _KERNEL
|
||||
memset(stream.refs, 0, (nins + 1) * sizeof(u_int));
|
||||
#endif
|
||||
memset(&stream, 0, sizeof(stream));
|
||||
|
||||
stream.cur_ip = 0;
|
||||
stream.bpf_pc = 0;
|
||||
stream.ibuf = NULL;
|
||||
/* Allocate the reference table for the jumps. */
|
||||
if (flag_jmp) {
|
||||
#ifdef _KERNEL
|
||||
stream.refs = malloc((nins + 1) * sizeof(u_int), M_BPFJIT,
|
||||
M_NOWAIT | M_ZERO);
|
||||
#else
|
||||
stream.refs = malloc((nins + 1) * sizeof(u_int));
|
||||
#endif
|
||||
if (stream.refs == NULL)
|
||||
return (NULL);
|
||||
#ifndef _KERNEL
|
||||
memset(stream.refs, 0, (nins + 1) * sizeof(u_int));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* The first pass will emit the lengths of the instructions
|
||||
@ -137,12 +180,16 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
ins = prog;
|
||||
|
||||
/* Create the procedure header. */
|
||||
PUSH(RBP);
|
||||
MOVrq(RSP, RBP);
|
||||
SUBib(BPF_MEMWORDS * sizeof(uint32_t), RSP);
|
||||
MOVrq2(RDI, R8);
|
||||
MOVrd2(ESI, R9D);
|
||||
MOVrd(EDX, EDI);
|
||||
if (flag_mem) {
|
||||
PUSH(RBP);
|
||||
MOVrq(RSP, RBP);
|
||||
SUBib(BPF_MEMWORDS * sizeof(uint32_t), RSP);
|
||||
}
|
||||
if (!flag_ret) {
|
||||
MOVrq2(RDI, R8);
|
||||
MOVrd2(ESI, R9D);
|
||||
MOVrd(EDX, EDI);
|
||||
}
|
||||
|
||||
for (i = 0; i < nins; i++) {
|
||||
stream.bpf_pc++;
|
||||
@ -157,11 +204,15 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
|
||||
case BPF_RET|BPF_K:
|
||||
MOVid(ins->k, EAX);
|
||||
LEAVE_RET();
|
||||
if (flag_mem)
|
||||
LEAVE();
|
||||
RET();
|
||||
break;
|
||||
|
||||
case BPF_RET|BPF_A:
|
||||
LEAVE_RET();
|
||||
if (flag_mem)
|
||||
LEAVE();
|
||||
RET();
|
||||
break;
|
||||
|
||||
case BPF_LD|BPF_W|BPF_ABS:
|
||||
@ -171,9 +222,15 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
MOVrd(EDI, ECX);
|
||||
SUBrd(ESI, ECX);
|
||||
CMPid(sizeof(int32_t), ECX);
|
||||
JAEb(4);
|
||||
ZEROrd(EAX);
|
||||
LEAVE_RET();
|
||||
if (flag_mem) {
|
||||
JAEb(4);
|
||||
ZEROrd(EAX);
|
||||
LEAVE();
|
||||
} else {
|
||||
JAEb(3);
|
||||
ZEROrd(EAX);
|
||||
}
|
||||
RET();
|
||||
MOVrq3(R8, RCX);
|
||||
MOVobd(RCX, RSI, EAX);
|
||||
BSWAP(EAX);
|
||||
@ -187,8 +244,12 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
MOVrd(EDI, ECX);
|
||||
SUBrd(ESI, ECX);
|
||||
CMPid(sizeof(int16_t), ECX);
|
||||
JAEb(2);
|
||||
LEAVE_RET();
|
||||
if (flag_mem) {
|
||||
JAEb(2);
|
||||
LEAVE();
|
||||
} else
|
||||
JAEb(1);
|
||||
RET();
|
||||
MOVrq3(R8, RCX);
|
||||
MOVobw(RCX, RSI, AX);
|
||||
SWAP_AX();
|
||||
@ -198,8 +259,12 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
ZEROrd(EAX);
|
||||
MOVid(ins->k, ESI);
|
||||
CMPrd(EDI, ESI);
|
||||
JBb(2);
|
||||
LEAVE_RET();
|
||||
if (flag_mem) {
|
||||
JBb(2);
|
||||
LEAVE();
|
||||
} else
|
||||
JBb(1);
|
||||
RET();
|
||||
MOVrq3(R8, RCX);
|
||||
MOVobb(RCX, RSI, AL);
|
||||
break;
|
||||
@ -224,9 +289,15 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
MOVrd(EDI, ECX);
|
||||
SUBrd(ESI, ECX);
|
||||
CMPid(sizeof(int32_t), ECX);
|
||||
JAEb(4);
|
||||
ZEROrd(EAX);
|
||||
LEAVE_RET();
|
||||
if (flag_mem) {
|
||||
JAEb(4);
|
||||
ZEROrd(EAX);
|
||||
LEAVE();
|
||||
} else {
|
||||
JAEb(3);
|
||||
ZEROrd(EAX);
|
||||
}
|
||||
RET();
|
||||
MOVrq3(R8, RCX);
|
||||
MOVobd(RCX, RSI, EAX);
|
||||
BSWAP(EAX);
|
||||
@ -245,8 +316,12 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
MOVrd(EDI, ECX);
|
||||
SUBrd(ESI, ECX);
|
||||
CMPid(sizeof(int16_t), ECX);
|
||||
JAEb(2);
|
||||
LEAVE_RET();
|
||||
if (flag_mem) {
|
||||
JAEb(2);
|
||||
LEAVE();
|
||||
} else
|
||||
JAEb(1);
|
||||
RET();
|
||||
MOVrq3(R8, RCX);
|
||||
MOVobw(RCX, RSI, AX);
|
||||
SWAP_AX();
|
||||
@ -260,8 +335,12 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
MOVrd(EDI, ECX);
|
||||
SUBrd(EDX, ECX);
|
||||
CMPrd(ESI, ECX);
|
||||
JAb(2);
|
||||
LEAVE_RET();
|
||||
if (flag_mem) {
|
||||
JAb(2);
|
||||
LEAVE();
|
||||
} else
|
||||
JAb(1);
|
||||
RET();
|
||||
MOVrq3(R8, RCX);
|
||||
ADDrd(EDX, ESI);
|
||||
MOVobb(RCX, RSI, AL);
|
||||
@ -270,9 +349,15 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
case BPF_LDX|BPF_MSH|BPF_B:
|
||||
MOVid(ins->k, ESI);
|
||||
CMPrd(EDI, ESI);
|
||||
JBb(4);
|
||||
ZEROrd(EAX);
|
||||
LEAVE_RET();
|
||||
if (flag_mem) {
|
||||
JBb(4);
|
||||
ZEROrd(EAX);
|
||||
LEAVE();
|
||||
} else {
|
||||
JBb(3);
|
||||
ZEROrd(EAX);
|
||||
}
|
||||
RET();
|
||||
ZEROrd(EDX);
|
||||
MOVrq3(R8, RCX);
|
||||
MOVobb(RCX, RSI, DL);
|
||||
@ -390,9 +475,15 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
|
||||
case BPF_ALU|BPF_DIV|BPF_X:
|
||||
TESTrd(EDX, EDX);
|
||||
JNEb(4);
|
||||
ZEROrd(EAX);
|
||||
LEAVE_RET();
|
||||
if (flag_mem) {
|
||||
JNEb(4);
|
||||
ZEROrd(EAX);
|
||||
LEAVE();
|
||||
} else {
|
||||
JNEb(3);
|
||||
ZEROrd(EAX);
|
||||
}
|
||||
RET();
|
||||
MOVrd(EDX, ECX);
|
||||
ZEROrd(EDX);
|
||||
DIVrd(ECX);
|
||||
@ -492,8 +583,9 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
* Modify the reference table to contain the offsets and
|
||||
* not the lengths of the instructions.
|
||||
*/
|
||||
for (i = 1; i < nins + 1; i++)
|
||||
stream.refs[i] += stream.refs[i - 1];
|
||||
if (flag_jmp)
|
||||
for (i = 1; i < nins + 1; i++)
|
||||
stream.refs[i] += stream.refs[i - 1];
|
||||
|
||||
/* Reset the counters. */
|
||||
stream.cur_ip = 0;
|
||||
@ -507,10 +599,14 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
* The reference table is needed only during compilation,
|
||||
* now we can free it.
|
||||
*/
|
||||
if (flag_jmp)
|
||||
#ifdef _KERNEL
|
||||
free(stream.refs, M_BPFJIT);
|
||||
free(stream.refs, M_BPFJIT);
|
||||
#else
|
||||
free(stream.refs);
|
||||
free(stream.refs);
|
||||
#endif
|
||||
|
||||
#ifndef _KERNEL
|
||||
if (stream.ibuf != NULL &&
|
||||
mprotect(stream.ibuf, *size, PROT_READ | PROT_EXEC) != 0) {
|
||||
munmap(stream.ibuf, *size);
|
||||
|
@ -85,7 +85,15 @@
|
||||
#define DL 2
|
||||
#define BL 3
|
||||
|
||||
/* A stream of native binary code.*/
|
||||
/* Optimization flags */
|
||||
#define BPF_JIT_FLAG_RET 0x01
|
||||
#define BPF_JIT_FLAG_JMP 0x02
|
||||
#define BPF_JIT_FLAG_MEM 0x04
|
||||
|
||||
#define BPF_JIT_FLAG_ALL \
|
||||
(BPF_JIT_FLAG_JMP | BPF_JIT_FLAG_MEM)
|
||||
|
||||
/* A stream of native binary code */
|
||||
typedef struct bpf_bin_stream {
|
||||
/* Current native instruction pointer. */
|
||||
int cur_ip;
|
||||
@ -117,7 +125,7 @@ typedef struct bpf_bin_stream {
|
||||
typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n);
|
||||
|
||||
/*
|
||||
* native Instruction Macros
|
||||
* Native instruction macros
|
||||
*/
|
||||
|
||||
/* movl i32,r32 */
|
||||
@ -220,9 +228,14 @@ typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n);
|
||||
emitm(&stream, (5 << 4) | (0 << 3) | (r64 & 0x7), 1); \
|
||||
} while (0)
|
||||
|
||||
/* leave/ret */
|
||||
#define LEAVE_RET() do { \
|
||||
emitm(&stream, 0xc3c9, 2); \
|
||||
/* leaveq */
|
||||
#define LEAVE() do { \
|
||||
emitm(&stream, 0xc9, 1); \
|
||||
} while (0)
|
||||
|
||||
/* retq */
|
||||
#define RET() do { \
|
||||
emitm(&stream, 0xc3, 1); \
|
||||
} while (0)
|
||||
|
||||
/* addl sr32,dr32 */
|
||||
|
@ -57,18 +57,19 @@ __FBSDID("$FreeBSD$");
|
||||
bpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, size_t *);
|
||||
|
||||
/*
|
||||
* emit routine to update the jump table
|
||||
* Emit routine to update the jump table.
|
||||
*/
|
||||
static void
|
||||
emit_length(bpf_bin_stream *stream, __unused u_int value, u_int len)
|
||||
{
|
||||
|
||||
(stream->refs)[stream->bpf_pc] += len;
|
||||
if (stream->refs != NULL)
|
||||
(stream->refs)[stream->bpf_pc] += len;
|
||||
stream->cur_ip += len;
|
||||
}
|
||||
|
||||
/*
|
||||
* emit routine to output the actual binary code
|
||||
* Emit routine to output the actual binary code.
|
||||
*/
|
||||
static void
|
||||
emit_code(bpf_bin_stream *stream, u_int value, u_int len)
|
||||
@ -95,37 +96,79 @@ emit_code(bpf_bin_stream *stream, u_int value, u_int len)
|
||||
}
|
||||
|
||||
/*
|
||||
* Function that does the real stuff
|
||||
* Scan the filter program and find possible optimization.
|
||||
*/
|
||||
static int
|
||||
bpf_jit_optimize(struct bpf_insn *prog, u_int nins)
|
||||
{
|
||||
const struct bpf_insn *p;
|
||||
int flags;
|
||||
u_int i;
|
||||
|
||||
/* Do we return immediately? */
|
||||
if (BPF_CLASS(prog[0].code) == BPF_RET)
|
||||
return (BPF_JIT_FLAG_RET);
|
||||
|
||||
for (flags = 0, i = 0; i < nins; i++) {
|
||||
p = &prog[i];
|
||||
|
||||
/* Do we need reference table? */
|
||||
if ((flags & BPF_JIT_FLAG_JMP) == 0 &&
|
||||
BPF_CLASS(p->code) == BPF_JMP)
|
||||
flags |= BPF_JIT_FLAG_JMP;
|
||||
|
||||
/* Do we need scratch memory? */
|
||||
if ((flags & BPF_JIT_FLAG_MEM) == 0 &&
|
||||
(p->code == BPF_ST || p->code == BPF_STX ||
|
||||
p->code == (BPF_LD|BPF_MEM) ||
|
||||
p->code == (BPF_LDX|BPF_MEM)))
|
||||
flags |= BPF_JIT_FLAG_MEM;
|
||||
|
||||
if (flags == BPF_JIT_FLAG_ALL)
|
||||
break;
|
||||
}
|
||||
|
||||
return (flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function that does the real stuff.
|
||||
*/
|
||||
bpf_filter_func
|
||||
bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
{
|
||||
bpf_bin_stream stream;
|
||||
struct bpf_insn *ins;
|
||||
int flags, flag_ret, flag_jmp, flag_mem;
|
||||
u_int i, pass;
|
||||
|
||||
flags = bpf_jit_optimize(prog, nins);
|
||||
flag_ret = (flags & BPF_JIT_FLAG_RET) != 0;
|
||||
flag_jmp = (flags & BPF_JIT_FLAG_JMP) != 0;
|
||||
flag_mem = (flags & BPF_JIT_FLAG_MEM) != 0;
|
||||
|
||||
/*
|
||||
* NOTE: Do not modify the name of this variable, as it's used by
|
||||
* the macros to emit code.
|
||||
*/
|
||||
emit_func emitm;
|
||||
|
||||
/* Allocate the reference table for the jumps. */
|
||||
#ifdef _KERNEL
|
||||
stream.refs = malloc((nins + 1) * sizeof(u_int), M_BPFJIT,
|
||||
M_NOWAIT | M_ZERO);
|
||||
#else
|
||||
stream.refs = malloc((nins + 1) * sizeof(u_int));
|
||||
#endif
|
||||
if (stream.refs == NULL)
|
||||
return (NULL);
|
||||
#ifndef _KERNEL
|
||||
memset(stream.refs, 0, (nins + 1) * sizeof(u_int));
|
||||
#endif
|
||||
memset(&stream, 0, sizeof(stream));
|
||||
|
||||
stream.cur_ip = 0;
|
||||
stream.bpf_pc = 0;
|
||||
stream.ibuf = NULL;
|
||||
/* Allocate the reference table for the jumps. */
|
||||
if (flag_jmp) {
|
||||
#ifdef _KERNEL
|
||||
stream.refs = malloc((nins + 1) * sizeof(u_int), M_BPFJIT,
|
||||
M_NOWAIT | M_ZERO);
|
||||
#else
|
||||
stream.refs = malloc((nins + 1) * sizeof(u_int));
|
||||
#endif
|
||||
if (stream.refs == NULL)
|
||||
return (NULL);
|
||||
#ifndef _KERNEL
|
||||
memset(stream.refs, 0, (nins + 1) * sizeof(u_int));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* The first pass will emit the lengths of the instructions
|
||||
@ -137,14 +180,19 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
ins = prog;
|
||||
|
||||
/* Create the procedure header. */
|
||||
PUSH(EBP);
|
||||
MOVrd(ESP, EBP);
|
||||
SUBib(BPF_MEMWORDS * sizeof(uint32_t), ESP);
|
||||
PUSH(EDI);
|
||||
PUSH(ESI);
|
||||
PUSH(EBX);
|
||||
MOVodd(8, EBP, EBX);
|
||||
MOVodd(16, EBP, EDI);
|
||||
if (!flag_ret) {
|
||||
PUSH(EBP);
|
||||
MOVrd(ESP, EBP);
|
||||
}
|
||||
if (flag_mem)
|
||||
SUBib(BPF_MEMWORDS * sizeof(uint32_t), ESP);
|
||||
if (!flag_ret) {
|
||||
PUSH(EDI);
|
||||
PUSH(ESI);
|
||||
PUSH(EBX);
|
||||
MOVodd(8, EBP, EBX);
|
||||
MOVodd(16, EBP, EDI);
|
||||
}
|
||||
|
||||
for (i = 0; i < nins; i++) {
|
||||
stream.bpf_pc++;
|
||||
@ -159,17 +207,23 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
|
||||
case BPF_RET|BPF_K:
|
||||
MOVid(ins->k, EAX);
|
||||
POP(EBX);
|
||||
POP(ESI);
|
||||
POP(EDI);
|
||||
LEAVE_RET();
|
||||
if (!flag_ret) {
|
||||
POP(EBX);
|
||||
POP(ESI);
|
||||
POP(EDI);
|
||||
LEAVE();
|
||||
}
|
||||
RET();
|
||||
break;
|
||||
|
||||
case BPF_RET|BPF_A:
|
||||
POP(EBX);
|
||||
POP(ESI);
|
||||
POP(EDI);
|
||||
LEAVE_RET();
|
||||
if (!flag_ret) {
|
||||
POP(EBX);
|
||||
POP(ESI);
|
||||
POP(EDI);
|
||||
LEAVE();
|
||||
}
|
||||
RET();
|
||||
break;
|
||||
|
||||
case BPF_LD|BPF_W|BPF_ABS:
|
||||
@ -184,7 +238,8 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
POP(EBX);
|
||||
POP(ESI);
|
||||
POP(EDI);
|
||||
LEAVE_RET();
|
||||
LEAVE();
|
||||
RET();
|
||||
MOVobd(EBX, ESI, EAX);
|
||||
BSWAP(EAX);
|
||||
break;
|
||||
@ -201,7 +256,8 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
POP(EBX);
|
||||
POP(ESI);
|
||||
POP(EDI);
|
||||
LEAVE_RET();
|
||||
LEAVE();
|
||||
RET();
|
||||
MOVobw(EBX, ESI, AX);
|
||||
SWAP_AX();
|
||||
break;
|
||||
@ -214,7 +270,8 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
POP(EBX);
|
||||
POP(ESI);
|
||||
POP(EDI);
|
||||
LEAVE_RET();
|
||||
LEAVE();
|
||||
RET();
|
||||
MOVobb(EBX, ESI, AL);
|
||||
break;
|
||||
|
||||
@ -243,7 +300,8 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
POP(EBX);
|
||||
POP(ESI);
|
||||
POP(EDI);
|
||||
LEAVE_RET();
|
||||
LEAVE();
|
||||
RET();
|
||||
MOVobd(EBX, ESI, EAX);
|
||||
BSWAP(EAX);
|
||||
break;
|
||||
@ -265,7 +323,8 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
POP(EBX);
|
||||
POP(ESI);
|
||||
POP(EDI);
|
||||
LEAVE_RET();
|
||||
LEAVE();
|
||||
RET();
|
||||
MOVobw(EBX, ESI, AX);
|
||||
SWAP_AX();
|
||||
break;
|
||||
@ -282,7 +341,8 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
POP(EBX);
|
||||
POP(ESI);
|
||||
POP(EDI);
|
||||
LEAVE_RET();
|
||||
LEAVE();
|
||||
RET();
|
||||
ADDrd(EDX, ESI);
|
||||
MOVobb(EBX, ESI, AL);
|
||||
break;
|
||||
@ -295,7 +355,8 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
POP(EBX);
|
||||
POP(ESI);
|
||||
POP(EDI);
|
||||
LEAVE_RET();
|
||||
LEAVE();
|
||||
RET();
|
||||
ZEROrd(EDX);
|
||||
MOVobb(EBX, ESI, DL);
|
||||
ANDib(0x0f, DL);
|
||||
@ -425,7 +486,8 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
POP(EBX);
|
||||
POP(ESI);
|
||||
POP(EDI);
|
||||
LEAVE_RET();
|
||||
LEAVE();
|
||||
RET();
|
||||
MOVrd(EDX, ECX);
|
||||
ZEROrd(EDX);
|
||||
DIVrd(ECX);
|
||||
@ -525,8 +587,9 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
* Modify the reference table to contain the offsets and
|
||||
* not the lengths of the instructions.
|
||||
*/
|
||||
for (i = 1; i < nins + 1; i++)
|
||||
stream.refs[i] += stream.refs[i - 1];
|
||||
if (flag_jmp)
|
||||
for (i = 1; i < nins + 1; i++)
|
||||
stream.refs[i] += stream.refs[i - 1];
|
||||
|
||||
/* Reset the counters. */
|
||||
stream.cur_ip = 0;
|
||||
@ -540,10 +603,14 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
|
||||
* The reference table is needed only during compilation,
|
||||
* now we can free it.
|
||||
*/
|
||||
if (flag_jmp)
|
||||
#ifdef _KERNEL
|
||||
free(stream.refs, M_BPFJIT);
|
||||
free(stream.refs, M_BPFJIT);
|
||||
#else
|
||||
free(stream.refs);
|
||||
free(stream.refs);
|
||||
#endif
|
||||
|
||||
#ifndef _KERNEL
|
||||
if (stream.ibuf != NULL &&
|
||||
mprotect(stream.ibuf, *size, PROT_READ | PROT_EXEC) != 0) {
|
||||
munmap(stream.ibuf, *size);
|
||||
|
@ -60,7 +60,15 @@
|
||||
#define DL 2
|
||||
#define BL 3
|
||||
|
||||
/* A stream of native binary code.*/
|
||||
/* Optimization flags */
|
||||
#define BPF_JIT_FLAG_RET 0x01
|
||||
#define BPF_JIT_FLAG_JMP 0x02
|
||||
#define BPF_JIT_FLAG_MEM 0x04
|
||||
|
||||
#define BPF_JIT_FLAG_ALL \
|
||||
(BPF_JIT_FLAG_JMP | BPF_JIT_FLAG_MEM)
|
||||
|
||||
/* A stream of native binary code */
|
||||
typedef struct bpf_bin_stream {
|
||||
/* Current native instruction pointer. */
|
||||
int cur_ip;
|
||||
@ -92,7 +100,7 @@ typedef struct bpf_bin_stream {
|
||||
typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n);
|
||||
|
||||
/*
|
||||
* native Instruction Macros
|
||||
* Native instruction macros
|
||||
*/
|
||||
|
||||
/* movl i32,r32 */
|
||||
@ -165,9 +173,14 @@ typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n);
|
||||
emitm(&stream, (5 << 4) | (1 << 3) | (r32 & 0x7), 1); \
|
||||
} while (0)
|
||||
|
||||
/* leave/ret */
|
||||
#define LEAVE_RET() do { \
|
||||
emitm(&stream, 0xc3c9, 2); \
|
||||
/* leave */
|
||||
#define LEAVE() do { \
|
||||
emitm(&stream, 0xc9, 1); \
|
||||
} while (0)
|
||||
|
||||
/* ret */
|
||||
#define RET() do { \
|
||||
emitm(&stream, 0xc3, 1); \
|
||||
} while (0)
|
||||
|
||||
/* addl sr32,dr32 */
|
||||
|
Loading…
Reference in New Issue
Block a user