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/amd64/amd64/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 RAX 0 41#define RCX 1 42#define RDX 2 43#define RBX 3 44#define RSP 4 45#define RBP 5 46#define RSI 6 47#define RDI 7 48#define R8 0 49#define R9 1 50#define R10 2 51#define R11 3 52#define R12 4 53#define R13 5 54#define R14 6 55#define R15 7 56 57#define EAX 0 58#define ECX 1 59#define EDX 2 60#define EBX 3 61#define ESP 4 62#define EBP 5 63#define ESI 6 64#define EDI 7 65#define R8D 0 66#define R9D 1 67#define R10D 2 68#define R11D 3 69#define R12D 4 70#define R13D 5 71#define R14D 6 72#define R15D 7 73 74#define AX 0 75#define CX 1 76#define DX 2 77#define BX 3 78#define SP 4 79#define BP 5 80#define SI 6 81#define DI 7 82 83#define AL 0 84#define CL 1 85#define DL 2 86#define BL 3 87 88/* Optimization flags */ 89#define BPF_JIT_FRET 0x01 90#define BPF_JIT_FPKT 0x02 91#define BPF_JIT_FMEM 0x04 92#define BPF_JIT_FJMP 0x08 93#define BPF_JIT_FLEN 0x10 94 95#define BPF_JIT_FLAG_ALL \ 96 (BPF_JIT_FPKT | BPF_JIT_FMEM | BPF_JIT_FJMP | BPF_JIT_FLEN) 97 98/* A stream of native binary code */ 99typedef struct bpf_bin_stream { 100 /* Current native instruction pointer. */ 101 int cur_ip; 102 103 /* 104 * Current BPF instruction pointer, i.e. position in 105 * the BPF program reached by the jitter. 106 */ 107 int bpf_pc; 108 109 /* Instruction buffer, contains the generated native code. */ 110 char *ibuf; 111 112 /* Jumps reference table. */ 113 u_int *refs; 114} bpf_bin_stream; 115 116/* 117 * Prototype of the emit functions. 118 * 119 * Different emit functions are used to create the reference table and 120 * to generate the actual filtering code. This allows to have simpler 121 * instruction macros. 122 * The first parameter is the stream that will receive the data. 123 * The second one is a variable containing the data. 124 * The third one is the length, that can be 1, 2, or 4 since it is possible 125 * to emit a byte, a short, or a word at a time. 126 */ 127typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n); 128 129/* 130 * Native instruction macros 131 */ 132 133/* movl i32,r32 */ 134#define MOVid(i32, r32) do { \ 135 emitm(&stream, (11 << 4) | (1 << 3) | (r32 & 0x7), 1); \ 136 emitm(&stream, i32, 4); \ 137} while (0) 138 139/* movq i64,r64 */ 140#define MOViq(i64, r64) do { \ 141 emitm(&stream, 0x48, 1); \ 142 emitm(&stream, (11 << 4) | (1 << 3) | (r64 & 0x7), 1); \ 143 emitm(&stream, i64, 4); \ 144 emitm(&stream, (i64 >> 32), 4); \ 145} while (0) 146 147/* movl sr32,dr32 */ 148#define MOVrd(sr32, dr32) do { \ 149 emitm(&stream, 0x89, 1); \ 150 emitm(&stream, \ 151 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \ 152} while (0) 153 154/* movl sr32,dr32 (dr32 = %r8-15d) */ 155#define MOVrd2(sr32, dr32) do { \ 156 emitm(&stream, 0x8941, 2); \ 157 emitm(&stream, \ 158 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \ 159} while (0) 160 161/* movl sr32,dr32 (sr32 = %r8-15d) */ 162#define MOVrd3(sr32, dr32) do { \ 163 emitm(&stream, 0x8944, 2); \ 164 emitm(&stream, \ 165 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \ 166} while (0) 167 168/* movq sr64,dr64 */ 169#define MOVrq(sr64, dr64) do { \ 170 emitm(&stream, 0x8948, 2); \ 171 emitm(&stream, \ 172 (3 << 6) | ((sr64 & 0x7) << 3) | (dr64 & 0x7), 1); \ 173} while (0) 174 175/* movq sr64,dr64 (dr64 = %r8-15) */ 176#define MOVrq2(sr64, dr64) do { \ 177 emitm(&stream, 0x8949, 2); \ 178 emitm(&stream, \ 179 (3 << 6) | ((sr64 & 0x7) << 3) | (dr64 & 0x7), 1); \ 180} while (0) 181 182/* movq sr64,dr64 (sr64 = %r8-15) */ 183#define MOVrq3(sr64, dr64) do { \ 184 emitm(&stream, 0x894c, 2); \ 185 emitm(&stream, \ 186 (3 << 6) | ((sr64 & 0x7) << 3) | (dr64 & 0x7), 1); \ 187} while (0) 188 189/* movl (sr64,or64,1),dr32 */ 190#define MOVobd(sr64, or64, dr32) do { \ 191 emitm(&stream, 0x8b, 1); \ 192 emitm(&stream, ((dr32 & 0x7) << 3) | 4, 1); \ 193 emitm(&stream, ((or64 & 0x7) << 3) | (sr64 & 0x7), 1); \ 194} while (0) 195 196/* movw (sr64,or64,1),dr16 */ 197#define MOVobw(sr64, or64, dr16) do { \ 198 emitm(&stream, 0x8b66, 2); \ 199 emitm(&stream, ((dr16 & 0x7) << 3) | 4, 1); \ 200 emitm(&stream, ((or64 & 0x7) << 3) | (sr64 & 0x7), 1); \ 201} while (0) 202 203/* movb (sr64,or64,1),dr8 */ 204#define MOVobb(sr64, or64, dr8) do { \ 205 emitm(&stream, 0x8a, 1); \ 206 emitm(&stream, ((dr8 & 0x7) << 3) | 4, 1); \ 207 emitm(&stream, ((or64 & 0x7) << 3) | (sr64 & 0x7), 1); \ 208} while (0) 209 210/* movl sr32,(dr64,or64,1) */ 211#define MOVomd(sr32, dr64, or64) do { \ 212 emitm(&stream, 0x89, 1); \ 213 emitm(&stream, ((sr32 & 0x7) << 3) | 4, 1); \ 214 emitm(&stream, ((or64 & 0x7) << 3) | (dr64 & 0x7), 1); \ 215} while (0) 216 217/* bswapl dr32 */ 218#define BSWAP(dr32) do { \ 219 emitm(&stream, 0xf, 1); \ 220 emitm(&stream, (0x19 << 3) | dr32, 1); \ 221} while (0) 222 223/* xchgb %al,%ah */ 224#define SWAP_AX() do { \ 225 emitm(&stream, 0xc486, 2); \ 226} while (0) 227 228/* pushq r64 */ 229#define PUSH(r64) do { \ 230 emitm(&stream, (5 << 4) | (0 << 3) | (r64 & 0x7), 1); \ 231} while (0) 232 233/* leaveq */ 234#define LEAVE() do { \ 235 emitm(&stream, 0xc9, 1); \ 236} while (0) 237 238/* retq */ 239#define RET() do { \ 240 emitm(&stream, 0xc3, 1); \ 241} while (0) 242 243/* addl sr32,dr32 */ 244#define ADDrd(sr32, dr32) do { \ 245 emitm(&stream, 0x01, 1); \ 246 emitm(&stream, \ 247 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \ 248} while (0) 249 250/* addl i32,%eax */ 251#define ADD_EAXi(i32) do { \ 252 emitm(&stream, 0x05, 1); \ 253 emitm(&stream, i32, 4); \ 254} while (0) 255 256/* addl i8,r32 */ 257#define ADDib(i8, r32) do { \ 258 emitm(&stream, 0x83, 1); \ 259 emitm(&stream, (24 << 3) | r32, 1); \ 260 emitm(&stream, i8, 1); \ 261} while (0) 262 263/* subl sr32,dr32 */ 264#define SUBrd(sr32, dr32) do { \ 265 emitm(&stream, 0x29, 1); \ 266 emitm(&stream, \ 267 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \ 268} while (0) 269 270/* subl i32,%eax */ 271#define SUB_EAXi(i32) do { \ 272 emitm(&stream, 0x2d, 1); \ 273 emitm(&stream, i32, 4); \ 274} while (0) 275 276/* subq i8,r64 */ 277#define SUBib(i8, r64) do { \ 278 emitm(&stream, 0x8348, 2); \ 279 emitm(&stream, (29 << 3) | (r64 & 0x7), 1); \ 280 emitm(&stream, i8, 1); \ 281} while (0) 282 283/* mull r32 */ 284#define MULrd(r32) do { \ 285 emitm(&stream, 0xf7, 1); \ 286 emitm(&stream, (7 << 5) | (r32 & 0x7), 1); \ 287} while (0) 288 289/* divl r32 */ 290#define DIVrd(r32) do { \ 291 emitm(&stream, 0xf7, 1); \ 292 emitm(&stream, (15 << 4) | (r32 & 0x7), 1); \ 293} while (0) 294 295/* andb i8,r8 */ 296#define ANDib(i8, r8) do { \ 297 if (r8 == AL) { \ 298 emitm(&stream, 0x24, 1); \ 299 } else { \ 300 emitm(&stream, 0x80, 1); \ 301 emitm(&stream, (7 << 5) | r8, 1); \ 302 } \ 303 emitm(&stream, i8, 1); \ 304} while (0) 305 306/* andl i32,r32 */ 307#define ANDid(i32, r32) do { \ 308 if (r32 == EAX) { \ 309 emitm(&stream, 0x25, 1); \ 310 } else { \ 311 emitm(&stream, 0x81, 1); \ 312 emitm(&stream, (7 << 5) | r32, 1); \ 313 } \ 314 emitm(&stream, i32, 4); \ 315} while (0) 316 317/* andl sr32,dr32 */ 318#define ANDrd(sr32, dr32) do { \ 319 emitm(&stream, 0x21, 1); \ 320 emitm(&stream, \ 321 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \ 322} while (0) 323 324/* testl i32,r32 */ 325#define TESTid(i32, r32) do { \ 326 if (r32 == EAX) { \ 327 emitm(&stream, 0xa9, 1); \ 328 } else { \ 329 emitm(&stream, 0xf7, 1); \ 330 emitm(&stream, (3 << 6) | r32, 1); \ 331 } \ 332 emitm(&stream, i32, 4); \ 333} while (0) 334 335/* testl sr32,dr32 */ 336#define TESTrd(sr32, dr32) do { \ 337 emitm(&stream, 0x85, 1); \ 338 emitm(&stream, \ 339 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \ 340} while (0) 341 342/* orl sr32,dr32 */ 343#define ORrd(sr32, dr32) do { \ 344 emitm(&stream, 0x09, 1); \ 345 emitm(&stream, \ 346 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \ 347} while (0) 348 349/* orl i32,r32 */ 350#define ORid(i32, r32) do { \ 351 if (r32 == EAX) { \ 352 emitm(&stream, 0x0d, 1); \ 353 } else { \ 354 emitm(&stream, 0x81, 1); \ 355 emitm(&stream, (25 << 3) | r32, 1); \ 356 } \ 357 emitm(&stream, i32, 4); \ 358} while (0) 359 360/* shll i8,r32 */ 361#define SHLib(i8, r32) do { \ 362 emitm(&stream, 0xc1, 1); \ 363 emitm(&stream, (7 << 5) | (r32 & 0x7), 1); \ 364 emitm(&stream, i8, 1); \ 365} while (0) 366 367/* shll %cl,dr32 */ 368#define SHL_CLrb(dr32) do { \ 369 emitm(&stream, 0xd3, 1); \ 370 emitm(&stream, (7 << 5) | (dr32 & 0x7), 1); \ 371} while (0) 372 373/* shrl i8,r32 */ 374#define SHRib(i8, r32) do { \ 375 emitm(&stream, 0xc1, 1); \ 376 emitm(&stream, (29 << 3) | (r32 & 0x7), 1); \ 377 emitm(&stream, i8, 1); \ 378} while (0) 379 380/* shrl %cl,dr32 */ 381#define SHR_CLrb(dr32) do { \ 382 emitm(&stream, 0xd3, 1); \ 383 emitm(&stream, (29 << 3) | (dr32 & 0x7), 1); \ 384} while (0) 385 386/* negl r32 */ 387#define NEGd(r32) do { \ 388 emitm(&stream, 0xf7, 1); \ 389 emitm(&stream, (27 << 3) | (r32 & 0x7), 1); \ 390} while (0) 391 392/* cmpl sr32,dr32 */ 393#define CMPrd(sr32, dr32) do { \ 394 emitm(&stream, 0x39, 1); \ 395 emitm(&stream, \ 396 (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \ 397} while (0) 398 399/* cmpl i32,dr32 */ 400#define CMPid(i32, dr32) do { \ 401 if (dr32 == EAX){ \ 402 emitm(&stream, 0x3d, 1); \ 403 emitm(&stream, i32, 4); \ 404 } else { \ 405 emitm(&stream, 0x81, 1); \ 406 emitm(&stream, (0x1f << 3) | (dr32 & 0x7), 1); \ 407 emitm(&stream, i32, 4); \ 408 } \ 409} while (0) 410 411/* jb off8 */ 412#define JBb(off8) do { \ 413 emitm(&stream, 0x72, 1); \ 414 emitm(&stream, off8, 1); \ 415} while (0) 416 417/* jae off8 */ 418#define JAEb(off8) do { \ 419 emitm(&stream, 0x73, 1); \ 420 emitm(&stream, off8, 1); \ 421} while (0) 422 423/* jne off8 */ 424#define JNEb(off8) do { \ 425 emitm(&stream, 0x75, 1); \ 426 emitm(&stream, off8, 1); \ 427} while (0) 428 429/* ja off8 */ 430#define JAb(off8) do { \ 431 emitm(&stream, 0x77, 1); \ 432 emitm(&stream, off8, 1); \ 433} while (0) 434 435/* jmp off32 */ 436#define JMP(off32) do { \ 437 emitm(&stream, 0xe9, 1); \ 438 emitm(&stream, off32, 4); \ 439} while (0) 440 441/* xorl r32,r32 */ 442#define ZEROrd(r32) do { \ 443 emitm(&stream, 0x31, 1); \ 444 emitm(&stream, (3 << 6) | ((r32 & 0x7) << 3) | (r32 & 0x7), 1); \ 445} while (0) 446 447/* 448 * Conditional long jumps 449 */ 450#define JB 0x82 451#define JAE 0x83 452#define JE 0x84 453#define JNE 0x85 454#define JBE 0x86 455#define JA 0x87 456 457#define JCC(t, f) do { \ 458 if (ins->jt != 0 && ins->jf != 0) { \ 459 /* 5 is the size of the following jmp */ \ 460 emitm(&stream, ((t) << 8) | 0x0f, 2); \ 461 emitm(&stream, stream.refs[stream.bpf_pc + ins->jt] - \ 462 stream.refs[stream.bpf_pc] + 5, 4); \ 463 JMP(stream.refs[stream.bpf_pc + ins->jf] - \ 464 stream.refs[stream.bpf_pc]); \ 465 } else if (ins->jt != 0) { \ 466 emitm(&stream, ((t) << 8) | 0x0f, 2); \ 467 emitm(&stream, stream.refs[stream.bpf_pc + ins->jt] - \ 468 stream.refs[stream.bpf_pc], 4); \ 469 } else { \ 470 emitm(&stream, ((f) << 8) | 0x0f, 2); \ 471 emitm(&stream, stream.refs[stream.bpf_pc + ins->jf] - \ 472 stream.refs[stream.bpf_pc], 4); \ 473 } \ 474} while (0) 475 476#define JUMP(off) do { \ 477 if ((off) != 0) \ 478 JMP(stream.refs[stream.bpf_pc + (off)] - \ 479 stream.refs[stream.bpf_pc]); \ 480} while (0) 481 482#endif /* _BPF_JIT_MACHDEP_H_ */ 483