github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/ifuzz/x86/encode.go (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 // See Intel Software Developer’s Manual Volume 2: Instruction Set Reference 5 // and AMD64 Architecture Programmer’s Manual Volume 3: General-Purpose and System Instructions 6 // for details of instruction encoding. 7 8 package x86 9 10 import ( 11 "math/rand" 12 13 "github.com/google/syzkaller/pkg/ifuzz/iset" 14 ) 15 16 // nolint: gocyclo, nestif, gocognit, funlen 17 func (insn *Insn) Encode(cfg *iset.Config, r *rand.Rand) []byte { 18 if !cfg.IsCompatible(insn) { 19 panic("instruction is not suitable for this mode") 20 } 21 if insn.Pseudo { 22 return insn.generator(cfg, r) 23 } 24 25 var operSize, immSize, dispSize, addrSize int 26 switch cfg.Mode { 27 case iset.ModeLong64: 28 operSize, immSize, dispSize, addrSize = 4, 4, 4, 8 29 case iset.ModeProt32: 30 operSize, immSize, dispSize, addrSize = 4, 4, 4, 4 31 case iset.ModeProt16, iset.ModeReal16: 32 operSize, immSize, dispSize, addrSize = 2, 2, 2, 2 33 default: 34 panic("bad mode") 35 } 36 37 var code []byte 38 39 rexR := false 40 var vvvv, vexR, vexX, vexB byte 41 42 // LEGACY PREFIXES 43 if insn.Vex == 0 { 44 for r.Intn(3) == 0 { 45 // LOCK 0xF0 is always added to insn.Prefix 46 prefixes := []byte{ 47 0x2E, // CS 48 0x3E, // DS 49 0x26, // ES 50 0x64, // FS 51 0x65, // GS 52 0x36, // SS 53 } 54 if !insn.No66Prefix { 55 prefixes = append(prefixes, 0x66) // operand size 56 } 57 if cfg.Mode == iset.ModeLong64 || !insn.Mem32 { 58 prefixes = append(prefixes, 0x67) // address size 59 } 60 if !insn.NoRepPrefix { 61 prefixes = append(prefixes, 62 0xF3, // REP 63 0xF2, // REPNE 64 ) 65 } 66 pref := prefixes[r.Intn(len(prefixes))] 67 code = append(code, pref) 68 } 69 70 code = append(code, insn.Prefix...) 71 72 // REX 73 var rex byte 74 if cfg.Mode == iset.ModeLong64 && r.Intn(2) == 0 { 75 // bit 0 - B 76 // bit 1 - X 77 // bit 2 - R 78 // bit 3 - W 79 rex = byte(0x40 | r.Intn(16)) 80 if insn.Rexw == 1 { 81 rex |= 1 << 3 82 } else { 83 rex &^= 1 << 3 84 } 85 rexR = rex&0x4 != 0 86 code = append(code, rex) 87 } 88 89 operSize1, immSize1, dispSize1, addrSize1 := operSize, immSize, dispSize, addrSize 90 for _, pref := range code { 91 switch pref { 92 case 0x66: 93 switch immSize { 94 case 4: 95 immSize1 = 2 96 operSize1 = 2 97 case 2: 98 immSize1 = 4 99 operSize1 = 4 100 } 101 case 0x67: 102 switch addrSize { 103 case 8: 104 addrSize1 = 4 105 case 4: 106 dispSize1 = 2 107 addrSize1 = 2 108 case 2: 109 dispSize1 = 4 110 addrSize1 = 4 111 } 112 } 113 if rex&(1<<3) != 0 { 114 operSize1 = 8 115 immSize1 = 4 116 } 117 } 118 operSize, immSize, dispSize, addrSize = operSize1, immSize1, dispSize1, addrSize1 119 } else { 120 // VEX/VOP 121 code = append(code, insn.Vex) 122 vexR = byte(1) 123 vexX = byte(1) 124 if cfg.Mode == iset.ModeLong64 { 125 vexR = byte(r.Intn(2)) 126 vexX = byte(r.Intn(2)) 127 } 128 vexB = byte(r.Intn(2)) 129 W := byte(r.Intn(2)) 130 switch insn.Rexw { 131 case 1: 132 W = 1 133 case -1: 134 W = 0 135 } 136 L := byte(r.Intn(2)) 137 switch insn.VexL { 138 case 1: 139 L = 1 140 case -1: 141 L = 0 142 } 143 pp := byte(r.Intn(4)) 144 if insn.VexP != -1 { 145 pp = byte(insn.VexP) 146 } 147 vvvv = 15 148 if !insn.VexNoR { 149 vvvv = byte(r.Intn(16)) 150 } 151 code = append(code, vexR<<7|vexX<<6|vexB<<5|insn.VexMap) 152 code = append(code, W<<7|vvvv<<3|L<<2|pp) 153 // TODO: short encoding 154 if cfg.Mode != iset.ModeLong64 { 155 vvvv |= 8 156 } 157 } 158 159 // OPCODE 160 code = append(code, insn.Opcode...) 161 162 if insn.Srm { 163 rm := byte(insn.Rm) 164 if insn.Rm == -1 { 165 rm = byte(r.Intn(8)) 166 } 167 code[len(code)-1] |= rm 168 } else if insn.Modrm { 169 // MODRM 170 var mod byte 171 switch insn.Mod { 172 case 0, 1, 2, 3: 173 mod = byte(insn.Mod) 174 case -1: 175 mod = byte(r.Intn(4)) 176 case -3: 177 mod = byte(r.Intn(3)) 178 } 179 180 reg := byte(insn.Reg) 181 switch insn.Reg { 182 case -1: 183 reg = byte(r.Intn(8)) 184 case -6: 185 reg = byte(r.Intn(6)) // segment register 186 case -8: 187 if rexR { 188 reg = 0 // CR8 189 } else { 190 crs := []byte{0, 2, 3, 4} 191 reg = crs[r.Intn(len(crs))] 192 } 193 } 194 if insn.Avx2Gather { 195 if reg|(1-vexR)<<3 == vvvv^0xf { 196 reg = (reg + 1) & 7 197 } 198 } 199 200 rm := byte(insn.Rm) 201 if insn.Rm == -1 { 202 rm = byte(r.Intn(8)) 203 } 204 205 modrm := mod<<6 | reg<<3 | rm 206 code = append(code, modrm) 207 208 if !insn.NoSibDisp { 209 if addrSize == 2 { 210 if mod == 1 { 211 // disp8 212 code = append(code, generateArg(cfg, r, 1)...) 213 } else if mod == 2 || mod == 0 && rm == 6 { 214 // disp16 215 code = append(code, generateArg(cfg, r, 2)...) 216 } 217 } else { 218 var sibbase byte 219 if mod != 3 && rm == 4 { 220 // SIB 221 scale := byte(r.Intn(4)) 222 index := byte(r.Intn(8)) 223 sibbase = byte(r.Intn(8)) 224 if insn.Avx2Gather { 225 rrrr := reg | (1-vexR)<<3 226 for { 227 iiii := index | (1-vexX)<<3 228 if iiii != vvvv^0xf && iiii != rrrr { 229 break 230 } 231 index = (index + 1) & 7 232 } 233 } 234 sib := scale<<6 | index<<3 | sibbase 235 code = append(code, sib) 236 } 237 238 if mod == 1 { 239 // disp8 240 code = append(code, generateArg(cfg, r, 1)...) 241 } else if mod == 2 || mod == 0 && rm == 5 || mod == 0 && sibbase == 5 { 242 // disp16/32 243 code = append(code, generateArg(cfg, r, dispSize)...) 244 } 245 } 246 } 247 } 248 249 addImm := func(imm int) { 250 switch imm { 251 case -1: 252 imm = immSize 253 case -2: 254 imm = addrSize 255 case -3: 256 imm = operSize 257 } 258 if imm != 0 { 259 code = append(code, generateArg(cfg, r, imm)...) 260 } 261 } 262 addImm(int(insn.Imm)) 263 addImm(int(insn.Imm2)) 264 265 code = append(code, insn.Suffix...) 266 return code 267 }