github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/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 if immSize == 4 { 94 immSize1 = 2 95 operSize1 = 2 96 } else if immSize == 2 { 97 immSize1 = 4 98 operSize1 = 4 99 } 100 case 0x67: 101 if addrSize == 8 { 102 addrSize1 = 4 103 } else if addrSize == 4 { 104 dispSize1 = 2 105 addrSize1 = 2 106 } else if addrSize == 2 { 107 dispSize1 = 4 108 addrSize1 = 4 109 } 110 } 111 if rex&(1<<3) != 0 { 112 operSize1 = 8 113 immSize1 = 4 114 } 115 } 116 operSize, immSize, dispSize, addrSize = operSize1, immSize1, dispSize1, addrSize1 117 } else { 118 // VEX/VOP 119 code = append(code, insn.Vex) 120 vexR = byte(1) 121 vexX = byte(1) 122 if cfg.Mode == iset.ModeLong64 { 123 vexR = byte(r.Intn(2)) 124 vexX = byte(r.Intn(2)) 125 } 126 vexB = byte(r.Intn(2)) 127 W := byte(r.Intn(2)) 128 if insn.Rexw == 1 { 129 W = 1 130 } else if insn.Rexw == -1 { 131 W = 0 132 } 133 L := byte(r.Intn(2)) 134 if insn.VexL == 1 { 135 L = 1 136 } else if insn.VexL == -1 { 137 L = 0 138 } 139 pp := byte(r.Intn(4)) 140 if insn.VexP != -1 { 141 pp = byte(insn.VexP) 142 } 143 vvvv = 15 144 if !insn.VexNoR { 145 vvvv = byte(r.Intn(16)) 146 } 147 code = append(code, vexR<<7|vexX<<6|vexB<<5|insn.VexMap) 148 code = append(code, W<<7|vvvv<<3|L<<2|pp) 149 // TODO: short encoding 150 if cfg.Mode != iset.ModeLong64 { 151 vvvv |= 8 152 } 153 } 154 155 // OPCODE 156 code = append(code, insn.Opcode...) 157 158 if insn.Srm { 159 rm := byte(insn.Rm) 160 if insn.Rm == -1 { 161 rm = byte(r.Intn(8)) 162 } 163 code[len(code)-1] |= rm 164 } else if insn.Modrm { 165 // MODRM 166 var mod byte 167 switch insn.Mod { 168 case 0, 1, 2, 3: 169 mod = byte(insn.Mod) 170 case -1: 171 mod = byte(r.Intn(4)) 172 case -3: 173 mod = byte(r.Intn(3)) 174 } 175 176 reg := byte(insn.Reg) 177 if insn.Reg == -1 { 178 reg = byte(r.Intn(8)) 179 } else if insn.Reg == -6 { 180 reg = byte(r.Intn(6)) // segment register 181 } else if insn.Reg == -8 { 182 if rexR { 183 reg = 0 // CR8 184 } else { 185 crs := []byte{0, 2, 3, 4} 186 reg = crs[r.Intn(len(crs))] 187 } 188 } 189 if insn.Avx2Gather { 190 if reg|(1-vexR)<<3 == vvvv^0xf { 191 reg = (reg + 1) & 7 192 } 193 } 194 195 rm := byte(insn.Rm) 196 if insn.Rm == -1 { 197 rm = byte(r.Intn(8)) 198 } 199 200 modrm := mod<<6 | reg<<3 | rm 201 code = append(code, modrm) 202 203 if !insn.NoSibDisp { 204 if addrSize == 2 { 205 if mod == 1 { 206 // disp8 207 code = append(code, generateArg(cfg, r, 1)...) 208 } else if mod == 2 || mod == 0 && rm == 6 { 209 // disp16 210 code = append(code, generateArg(cfg, r, 2)...) 211 } 212 } else { 213 var sibbase byte 214 if mod != 3 && rm == 4 { 215 // SIB 216 scale := byte(r.Intn(4)) 217 index := byte(r.Intn(8)) 218 sibbase = byte(r.Intn(8)) 219 if insn.Avx2Gather { 220 rrrr := reg | (1-vexR)<<3 221 for { 222 iiii := index | (1-vexX)<<3 223 if iiii != vvvv^0xf && iiii != rrrr { 224 break 225 } 226 index = (index + 1) & 7 227 } 228 } 229 sib := scale<<6 | index<<3 | sibbase 230 code = append(code, sib) 231 } 232 233 if mod == 1 { 234 // disp8 235 code = append(code, generateArg(cfg, r, 1)...) 236 } else if mod == 2 || mod == 0 && rm == 5 || mod == 0 && sibbase == 5 { 237 // disp16/32 238 code = append(code, generateArg(cfg, r, dispSize)...) 239 } 240 } 241 } 242 } 243 244 addImm := func(imm int) { 245 if imm == -1 { 246 imm = immSize 247 } else if imm == -2 { 248 imm = addrSize 249 } else if imm == -3 { 250 imm = operSize 251 } 252 if imm != 0 { 253 code = append(code, generateArg(cfg, r, imm)...) 254 } 255 } 256 addImm(int(insn.Imm)) 257 addImm(int(insn.Imm2)) 258 259 code = append(code, insn.Suffix...) 260 return code 261 }