bpf_jit_machdep.h revision 331722
1/*-
2 * Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy)
3 * Copyright (C) 2005-2009 Jung-uk Kim <jkim@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
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.
18 *
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.
30 *
31 * $FreeBSD: stable/11/sys/i386/i386/bpf_jit_machdep.h 331722 2018-03-29 02:50:57Z eadler $
32 */
33
34#ifndef _BPF_JIT_MACHDEP_H_
35#define _BPF_JIT_MACHDEP_H_
36
37/*
38 * Registers
39 */
40#define EAX	0
41#define ECX	1
42#define EDX	2
43#define EBX	3
44#define ESP	4
45#define EBP	5
46#define ESI	6
47#define EDI	7
48
49#define AX	0
50#define CX	1
51#define DX	2
52#define BX	3
53#define SP	4
54#define BP	5
55#define SI	6
56#define DI	7
57
58#define AL	0
59#define CL	1
60#define DL	2
61#define BL	3
62
63/* Optimization flags */
64#define	BPF_JIT_FRET	0x01
65#define	BPF_JIT_FPKT	0x02
66#define	BPF_JIT_FMEM	0x04
67#define	BPF_JIT_FJMP	0x08
68#define	BPF_JIT_FADK	0x10
69
70#define	BPF_JIT_FLAG_ALL	\
71    (BPF_JIT_FPKT | BPF_JIT_FMEM | BPF_JIT_FJMP | BPF_JIT_FADK)
72
73/* A stream of native binary code */
74typedef struct bpf_bin_stream {
75	/* Current native instruction pointer. */
76	int		cur_ip;
77
78	/*
79	 * Current BPF instruction pointer, i.e. position in
80	 * the BPF program reached by the jitter.
81	 */
82	int		bpf_pc;
83
84	/* Instruction buffer, contains the generated native code. */
85	char		*ibuf;
86
87	/* Jumps reference table. */
88	u_int		*refs;
89} bpf_bin_stream;
90
91/*
92 * Prototype of the emit functions.
93 *
94 * Different emit functions are used to create the reference table and
95 * to generate the actual filtering code. This allows to have simpler
96 * instruction macros.
97 * The first parameter is the stream that will receive the data.
98 * The second one is a variable containing the data.
99 * The third one is the length, that can be 1, 2, or 4 since it is possible
100 * to emit a byte, a short, or a word at a time.
101 */
102typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n);
103
104/*
105 * Native instruction macros
106 */
107
108/* movl i32,r32 */
109#define MOVid(i32, r32) do {						\
110	emitm(&stream, (11 << 4) | (1 << 3) | (r32 & 0x7), 1);		\
111	emitm(&stream, i32, 4);						\
112} while (0)
113
114/* movl sr32,dr32 */
115#define MOVrd(sr32, dr32) do {						\
116	emitm(&stream, 0x89, 1);					\
117	emitm(&stream,							\
118	    (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1);		\
119} while (0)
120
121/* movl off(sr32),dr32 */
122#define MOVodd(off, sr32, dr32) do {					\
123	emitm(&stream, 0x8b, 1);					\
124	emitm(&stream,							\
125	    (1 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1);		\
126	emitm(&stream, off, 1);						\
127} while (0)
128
129/* movl (sr32,or32,1),dr32 */
130#define MOVobd(sr32, or32, dr32) do {					\
131	emitm(&stream, 0x8b, 1);					\
132	emitm(&stream, ((dr32 & 0x7) << 3) | 4, 1);			\
133	emitm(&stream, ((or32 & 0x7) << 3) | (sr32 & 0x7), 1);		\
134} while (0)
135
136/* movw (sr32,or32,1),dr16 */
137#define MOVobw(sr32, or32, dr16) do {					\
138	emitm(&stream, 0x8b66, 2);					\
139	emitm(&stream, ((dr16 & 0x7) << 3) | 4, 1);			\
140	emitm(&stream, ((or32 & 0x7) << 3) | (sr32 & 0x7), 1);		\
141} while (0)
142
143/* movb (sr32,or32,1),dr8 */
144#define MOVobb(sr32, or32, dr8) do {					\
145	emitm(&stream, 0x8a, 1);					\
146	emitm(&stream, ((dr8 & 0x7) << 3) | 4, 1);			\
147	emitm(&stream, ((or32 & 0x7) << 3) | (sr32 & 0x7), 1);		\
148} while (0)
149
150/* movl sr32,(dr32,or32,1) */
151#define MOVomd(sr32, dr32, or32) do {					\
152	emitm(&stream, 0x89, 1);					\
153	emitm(&stream, ((sr32 & 0x7) << 3) | 4, 1);			\
154	emitm(&stream, ((or32 & 0x7) << 3) | (dr32 & 0x7), 1);		\
155} while (0)
156
157/* bswapl dr32 */
158#define BSWAP(dr32) do {						\
159	emitm(&stream, 0xf, 1);						\
160	emitm(&stream, (0x19 << 3) | dr32, 1);				\
161} while (0)
162
163/* xchgb %al,%ah */
164#define SWAP_AX() do {							\
165	emitm(&stream, 0xc486, 2);					\
166} while (0)
167
168/* pushl r32 */
169#define PUSH(r32) do {							\
170	emitm(&stream, (5 << 4) | (0 << 3) | (r32 & 0x7), 1);		\
171} while (0)
172
173/* popl r32 */
174#define POP(r32) do {							\
175	emitm(&stream, (5 << 4) | (1 << 3) | (r32 & 0x7), 1);		\
176} while (0)
177
178/* leave */
179#define LEAVE() do {							\
180	emitm(&stream, 0xc9, 1);					\
181} while (0)
182
183/* ret */
184#define RET() do {							\
185	emitm(&stream, 0xc3, 1);					\
186} while (0)
187
188/* addl sr32,dr32 */
189#define ADDrd(sr32, dr32) do {						\
190	emitm(&stream, 0x01, 1);					\
191	emitm(&stream,							\
192	    (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1);		\
193} while (0)
194
195/* addl i32,%eax */
196#define ADD_EAXi(i32) do {						\
197	emitm(&stream, 0x05, 1);					\
198	emitm(&stream, i32, 4);						\
199} while (0)
200
201/* addl i8,r32 */
202#define ADDib(i8, r32) do {						\
203	emitm(&stream, 0x83, 1);					\
204	emitm(&stream, (24 << 3) | r32, 1);				\
205	emitm(&stream, i8, 1);						\
206} while (0)
207
208/* subl sr32,dr32 */
209#define SUBrd(sr32, dr32) do {						\
210	emitm(&stream, 0x29, 1);					\
211	emitm(&stream,							\
212	    (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1);		\
213} while (0)
214
215/* subl i32,%eax */
216#define SUB_EAXi(i32) do {						\
217	emitm(&stream, 0x2d, 1);					\
218	emitm(&stream, i32, 4);						\
219} while (0)
220
221/* subl i8,r32 */
222#define SUBib(i8, r32) do {						\
223	emitm(&stream, 0x83, 1);					\
224	emitm(&stream, (29 << 3) | (r32 & 0x7), 1);			\
225	emitm(&stream, i8, 1);						\
226} while (0)
227
228/* mull r32 */
229#define MULrd(r32) do {							\
230	emitm(&stream, 0xf7, 1);					\
231	emitm(&stream, (7 << 5) | (r32 & 0x7), 1);			\
232} while (0)
233
234/* divl r32 */
235#define DIVrd(r32) do {							\
236	emitm(&stream, 0xf7, 1);					\
237	emitm(&stream, (15 << 4) | (r32 & 0x7), 1);			\
238} while (0)
239
240/* andb i8,r8 */
241#define ANDib(i8, r8) do {						\
242	if (r8 == AL) {							\
243		emitm(&stream, 0x24, 1);				\
244	} else {							\
245		emitm(&stream, 0x80, 1);				\
246		emitm(&stream, (7 << 5) | r8, 1);			\
247	}								\
248	emitm(&stream, i8, 1);						\
249} while (0)
250
251/* andl i32,r32 */
252#define ANDid(i32, r32) do {						\
253	if (r32 == EAX) {						\
254		emitm(&stream, 0x25, 1);				\
255	} else {							\
256		emitm(&stream, 0x81, 1);				\
257		emitm(&stream, (7 << 5) | r32, 1);			\
258	}								\
259	emitm(&stream, i32, 4);						\
260} while (0)
261
262/* andl sr32,dr32 */
263#define ANDrd(sr32, dr32) do {						\
264	emitm(&stream, 0x21, 1);					\
265	emitm(&stream,							\
266	    (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1);		\
267} while (0)
268
269/* testl i32,r32 */
270#define TESTid(i32, r32) do {						\
271	if (r32 == EAX) {						\
272		emitm(&stream, 0xa9, 1);				\
273	} else {							\
274		emitm(&stream, 0xf7, 1);				\
275		emitm(&stream, (3 << 6) | r32, 1);			\
276	}								\
277	emitm(&stream, i32, 4);						\
278} while (0)
279
280/* testl sr32,dr32 */
281#define TESTrd(sr32, dr32) do {						\
282	emitm(&stream, 0x85, 1);					\
283	emitm(&stream,							\
284	    (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1);		\
285} while (0)
286
287/* orl sr32,dr32 */
288#define ORrd(sr32, dr32) do {						\
289	emitm(&stream, 0x09, 1);					\
290	emitm(&stream,							\
291	    (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1);		\
292} while (0)
293
294/* orl i32,r32 */
295#define ORid(i32, r32) do {						\
296	if (r32 == EAX) {						\
297		emitm(&stream, 0x0d, 1);				\
298	} else {							\
299		emitm(&stream, 0x81, 1);				\
300		emitm(&stream, (25 << 3) | r32, 1);			\
301	}								\
302	emitm(&stream, i32, 4);						\
303} while (0)
304
305/* shll i8,r32 */
306#define SHLib(i8, r32) do {						\
307	emitm(&stream, 0xc1, 1);					\
308	emitm(&stream, (7 << 5) | (r32 & 0x7), 1);			\
309	emitm(&stream, i8, 1);						\
310} while (0)
311
312/* shll %cl,dr32 */
313#define SHL_CLrb(dr32) do {						\
314	emitm(&stream, 0xd3, 1);					\
315	emitm(&stream, (7 << 5) | (dr32 & 0x7), 1);			\
316} while (0)
317
318/* shrl i8,r32 */
319#define SHRib(i8, r32) do {						\
320	emitm(&stream, 0xc1, 1);					\
321	emitm(&stream, (29 << 3) | (r32 & 0x7), 1);			\
322	emitm(&stream, i8, 1);						\
323} while (0)
324
325/* shrl %cl,dr32 */
326#define SHR_CLrb(dr32) do {						\
327	emitm(&stream, 0xd3, 1);					\
328	emitm(&stream, (29 << 3) | (dr32 & 0x7), 1);			\
329} while (0)
330
331/* negl r32 */
332#define NEGd(r32) do {							\
333	emitm(&stream, 0xf7, 1);					\
334	emitm(&stream, (27 << 3) | (r32 & 0x7), 1);			\
335} while (0)
336
337/* cmpl sr32,dr32 */
338#define CMPrd(sr32, dr32) do {						\
339	emitm(&stream, 0x39, 1);					\
340	emitm(&stream,							\
341	    (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1);		\
342} while (0)
343
344/* cmpl i32,dr32 */
345#define CMPid(i32, dr32) do {						\
346	if (dr32 == EAX){						\
347		emitm(&stream, 0x3d, 1);				\
348		emitm(&stream, i32, 4);					\
349	} else {							\
350		emitm(&stream, 0x81, 1);				\
351		emitm(&stream, (0x1f << 3) | (dr32 & 0x7), 1);		\
352		emitm(&stream, i32, 4);					\
353	}								\
354} while (0)
355
356/* jb off8 */
357#define JBb(off8) do {							\
358	emitm(&stream, 0x72, 1);					\
359	emitm(&stream, off8, 1);					\
360} while (0)
361
362/* jae off8 */
363#define JAEb(off8) do {							\
364	emitm(&stream, 0x73, 1);					\
365	emitm(&stream, off8, 1);					\
366} while (0)
367
368/* jne off8 */
369#define JNEb(off8) do {							\
370	emitm(&stream, 0x75, 1);					\
371	emitm(&stream, off8, 1);					\
372} while (0)
373
374/* ja off8 */
375#define JAb(off8) do {							\
376	emitm(&stream, 0x77, 1);					\
377	emitm(&stream, off8, 1);					\
378} while (0)
379
380/* jmp off32 */
381#define JMP(off32) do {							\
382	emitm(&stream, 0xe9, 1);					\
383	emitm(&stream, off32, 4);					\
384} while (0)
385
386/* xorl r32,r32 */
387#define ZEROrd(r32) do {						\
388	emitm(&stream, 0x31, 1);					\
389	emitm(&stream, (3 << 6) | ((r32 & 0x7) << 3) | (r32 & 0x7), 1);	\
390} while (0)
391
392/*
393 * Conditional long jumps
394 */
395#define	JB	0x82
396#define	JAE	0x83
397#define	JE	0x84
398#define	JNE	0x85
399#define	JBE	0x86
400#define	JA	0x87
401
402#define	JCC(t, f) do {							\
403	if (ins->jt != 0 && ins->jf != 0) {				\
404		/* 5 is the size of the following jmp */		\
405		emitm(&stream, ((t) << 8) | 0x0f, 2);			\
406		emitm(&stream, stream.refs[stream.bpf_pc + ins->jt] -	\
407		    stream.refs[stream.bpf_pc] + 5, 4);			\
408		JMP(stream.refs[stream.bpf_pc + ins->jf] -		\
409		    stream.refs[stream.bpf_pc]);			\
410	} else if (ins->jt != 0) {					\
411		emitm(&stream, ((t) << 8) | 0x0f, 2);			\
412		emitm(&stream, stream.refs[stream.bpf_pc + ins->jt] -	\
413		    stream.refs[stream.bpf_pc], 4);			\
414	} else {							\
415		emitm(&stream, ((f) << 8) | 0x0f, 2);			\
416		emitm(&stream, stream.refs[stream.bpf_pc + ins->jf] -	\
417		    stream.refs[stream.bpf_pc], 4);			\
418	}								\
419} while (0)
420
421#define	JUMP(off) do {							\
422	if ((off) != 0)							\
423		JMP(stream.refs[stream.bpf_pc + (off)] -		\
424		    stream.refs[stream.bpf_pc]);			\
425} while (0)
426
427#endif	/* _BPF_JIT_MACHDEP_H_ */
428