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