2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy)
5 * Copyright (C) 2005-2016 Jung-uk Kim <jkim@FreeBSD.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Politecnico di Torino nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #ifndef _BPF_JIT_MACHDEP_H_
37 #define _BPF_JIT_MACHDEP_H_
65 /* Optimization flags */
66 #define BPF_JIT_FRET 0x01
67 #define BPF_JIT_FPKT 0x02
68 #define BPF_JIT_FMEM 0x04
69 #define BPF_JIT_FJMP 0x08
70 #define BPF_JIT_FADK 0x10
72 #define BPF_JIT_FLAG_ALL \
73 (BPF_JIT_FPKT | BPF_JIT_FMEM | BPF_JIT_FJMP | BPF_JIT_FADK)
75 /* A stream of native binary code */
76 typedef struct bpf_bin_stream {
77 /* Current native instruction pointer. */
81 * Current BPF instruction pointer, i.e. position in
82 * the BPF program reached by the jitter.
86 /* Instruction buffer, contains the generated native code. */
89 /* Jumps reference table. */
94 * Prototype of the emit functions.
96 * Different emit functions are used to create the reference table and
97 * to generate the actual filtering code. This allows to have simpler
99 * The first parameter is the stream that will receive the data.
100 * The second one is a variable containing the data.
101 * The third one is the length, that can be 1, 2, or 4 since it is possible
102 * to emit a byte, a short, or a word at a time.
104 typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n);
107 * Native instruction macros
111 #define MOVid(i32, r32) do { \
112 emitm(&stream, (11 << 4) | (1 << 3) | (r32 & 0x7), 1); \
113 emitm(&stream, i32, 4); \
117 #define MOVrd(sr32, dr32) do { \
118 emitm(&stream, 0x89, 1); \
120 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \
123 /* movl off(sr32),dr32 */
124 #define MOVodd(off, sr32, dr32) do { \
125 emitm(&stream, 0x8b, 1); \
127 (1 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \
128 emitm(&stream, off, 1); \
131 /* movl (sr32,or32,1),dr32 */
132 #define MOVobd(sr32, or32, dr32) do { \
133 emitm(&stream, 0x8b, 1); \
134 emitm(&stream, ((dr32 & 0x7) << 3) | 4, 1); \
135 emitm(&stream, ((or32 & 0x7) << 3) | (sr32 & 0x7), 1); \
138 /* movw (sr32,or32,1),dr16 */
139 #define MOVobw(sr32, or32, dr16) do { \
140 emitm(&stream, 0x8b66, 2); \
141 emitm(&stream, ((dr16 & 0x7) << 3) | 4, 1); \
142 emitm(&stream, ((or32 & 0x7) << 3) | (sr32 & 0x7), 1); \
145 /* movb (sr32,or32,1),dr8 */
146 #define MOVobb(sr32, or32, dr8) do { \
147 emitm(&stream, 0x8a, 1); \
148 emitm(&stream, ((dr8 & 0x7) << 3) | 4, 1); \
149 emitm(&stream, ((or32 & 0x7) << 3) | (sr32 & 0x7), 1); \
152 /* movl sr32,(dr32,or32,1) */
153 #define MOVomd(sr32, dr32, or32) do { \
154 emitm(&stream, 0x89, 1); \
155 emitm(&stream, ((sr32 & 0x7) << 3) | 4, 1); \
156 emitm(&stream, ((or32 & 0x7) << 3) | (dr32 & 0x7), 1); \
160 #define BSWAP(dr32) do { \
161 emitm(&stream, 0xf, 1); \
162 emitm(&stream, (0x19 << 3) | dr32, 1); \
166 #define SWAP_AX() do { \
167 emitm(&stream, 0xc486, 2); \
171 #define PUSH(r32) do { \
172 emitm(&stream, (5 << 4) | (0 << 3) | (r32 & 0x7), 1); \
176 #define POP(r32) do { \
177 emitm(&stream, (5 << 4) | (1 << 3) | (r32 & 0x7), 1); \
181 #define LEAVE() do { \
182 emitm(&stream, 0xc9, 1); \
187 emitm(&stream, 0xc3, 1); \
191 #define ADDrd(sr32, dr32) do { \
192 emitm(&stream, 0x01, 1); \
194 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \
198 #define ADD_EAXi(i32) do { \
199 emitm(&stream, 0x05, 1); \
200 emitm(&stream, i32, 4); \
204 #define ADDib(i8, r32) do { \
205 emitm(&stream, 0x83, 1); \
206 emitm(&stream, (24 << 3) | r32, 1); \
207 emitm(&stream, i8, 1); \
211 #define SUBrd(sr32, dr32) do { \
212 emitm(&stream, 0x29, 1); \
214 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \
218 #define SUB_EAXi(i32) do { \
219 emitm(&stream, 0x2d, 1); \
220 emitm(&stream, i32, 4); \
224 #define SUBib(i8, r32) do { \
225 emitm(&stream, 0x83, 1); \
226 emitm(&stream, (29 << 3) | (r32 & 0x7), 1); \
227 emitm(&stream, i8, 1); \
231 #define MULrd(r32) do { \
232 emitm(&stream, 0xf7, 1); \
233 emitm(&stream, (7 << 5) | (r32 & 0x7), 1); \
237 #define DIVrd(r32) do { \
238 emitm(&stream, 0xf7, 1); \
239 emitm(&stream, (15 << 4) | (r32 & 0x7), 1); \
243 #define ANDib(i8, r8) do { \
245 emitm(&stream, 0x24, 1); \
247 emitm(&stream, 0x80, 1); \
248 emitm(&stream, (7 << 5) | r8, 1); \
250 emitm(&stream, i8, 1); \
254 #define ANDid(i32, r32) do { \
256 emitm(&stream, 0x25, 1); \
258 emitm(&stream, 0x81, 1); \
259 emitm(&stream, (7 << 5) | r32, 1); \
261 emitm(&stream, i32, 4); \
265 #define ANDrd(sr32, dr32) do { \
266 emitm(&stream, 0x21, 1); \
268 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \
272 #define TESTid(i32, r32) do { \
274 emitm(&stream, 0xa9, 1); \
276 emitm(&stream, 0xf7, 1); \
277 emitm(&stream, (3 << 6) | r32, 1); \
279 emitm(&stream, i32, 4); \
282 /* testl sr32,dr32 */
283 #define TESTrd(sr32, dr32) do { \
284 emitm(&stream, 0x85, 1); \
286 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \
290 #define ORrd(sr32, dr32) do { \
291 emitm(&stream, 0x09, 1); \
293 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \
297 #define ORid(i32, r32) do { \
299 emitm(&stream, 0x0d, 1); \
301 emitm(&stream, 0x81, 1); \
302 emitm(&stream, (25 << 3) | r32, 1); \
304 emitm(&stream, i32, 4); \
308 #define XORrd(sr32, dr32) do { \
309 emitm(&stream, 0x31, 1); \
311 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \
315 #define XORid(i32, r32) do { \
317 emitm(&stream, 0x35, 1); \
319 emitm(&stream, 0x81, 1); \
320 emitm(&stream, (25 << 3) | r32, 1); \
322 emitm(&stream, i32, 4); \
326 #define SHLib(i8, r32) do { \
327 emitm(&stream, 0xc1, 1); \
328 emitm(&stream, (7 << 5) | (r32 & 0x7), 1); \
329 emitm(&stream, i8, 1); \
333 #define SHL_CLrb(dr32) do { \
334 emitm(&stream, 0xd3, 1); \
335 emitm(&stream, (7 << 5) | (dr32 & 0x7), 1); \
339 #define SHRib(i8, r32) do { \
340 emitm(&stream, 0xc1, 1); \
341 emitm(&stream, (29 << 3) | (r32 & 0x7), 1); \
342 emitm(&stream, i8, 1); \
346 #define SHR_CLrb(dr32) do { \
347 emitm(&stream, 0xd3, 1); \
348 emitm(&stream, (29 << 3) | (dr32 & 0x7), 1); \
352 #define NEGd(r32) do { \
353 emitm(&stream, 0xf7, 1); \
354 emitm(&stream, (27 << 3) | (r32 & 0x7), 1); \
358 #define CMPrd(sr32, dr32) do { \
359 emitm(&stream, 0x39, 1); \
361 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \
365 #define CMPid(i32, dr32) do { \
367 emitm(&stream, 0x3d, 1); \
368 emitm(&stream, i32, 4); \
370 emitm(&stream, 0x81, 1); \
371 emitm(&stream, (0x1f << 3) | (dr32 & 0x7), 1); \
372 emitm(&stream, i32, 4); \
377 #define JBb(off8) do { \
378 emitm(&stream, 0x72, 1); \
379 emitm(&stream, off8, 1); \
383 #define JAEb(off8) do { \
384 emitm(&stream, 0x73, 1); \
385 emitm(&stream, off8, 1); \
389 #define JNEb(off8) do { \
390 emitm(&stream, 0x75, 1); \
391 emitm(&stream, off8, 1); \
395 #define JAb(off8) do { \
396 emitm(&stream, 0x77, 1); \
397 emitm(&stream, off8, 1); \
401 #define JMP(off32) do { \
402 emitm(&stream, 0xe9, 1); \
403 emitm(&stream, off32, 4); \
407 #define ZEROrd(r32) do { \
408 emitm(&stream, 0x31, 1); \
409 emitm(&stream, (3 << 6) | ((r32 & 0x7) << 3) | (r32 & 0x7), 1); \
413 * Conditional long jumps
422 #define JCC(t, f) do { \
423 if (ins->jt != 0 && ins->jf != 0) { \
424 /* 5 is the size of the following jmp */ \
425 emitm(&stream, ((t) << 8) | 0x0f, 2); \
426 emitm(&stream, stream.refs[stream.bpf_pc + ins->jt] - \
427 stream.refs[stream.bpf_pc] + 5, 4); \
428 JMP(stream.refs[stream.bpf_pc + ins->jf] - \
429 stream.refs[stream.bpf_pc]); \
430 } else if (ins->jt != 0) { \
431 emitm(&stream, ((t) << 8) | 0x0f, 2); \
432 emitm(&stream, stream.refs[stream.bpf_pc + ins->jt] - \
433 stream.refs[stream.bpf_pc], 4); \
435 emitm(&stream, ((f) << 8) | 0x0f, 2); \
436 emitm(&stream, stream.refs[stream.bpf_pc + ins->jf] - \
437 stream.refs[stream.bpf_pc], 4); \
441 #define JUMP(off) do { \
443 JMP(stream.refs[stream.bpf_pc + (off)] - \
444 stream.refs[stream.bpf_pc]); \
447 #endif /* _BPF_JIT_MACHDEP_H_ */