| // Copyright 2017 syzkaller project authors. All rights reserved. |
| // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. |
| |
| // See Intel Software Developer’s Manual Volume 2: Instruction Set Reference |
| // and AMD64 Architecture Programmer’s Manual Volume 3: General-Purpose and System Instructions |
| // for details of instruction encoding. |
| |
| package ifuzz |
| |
| import ( |
| "math/rand" |
| ) |
| |
| // nolint: gocyclo |
| func (insn *Insn) Encode(cfg *Config, r *rand.Rand) []byte { |
| if !insn.isCompatible(cfg) { |
| panic("instruction is not suitable for this mode") |
| } |
| if insn.Pseudo { |
| return insn.generator(cfg, r) |
| } |
| |
| var operSize, immSize, dispSize, addrSize int |
| switch cfg.Mode { |
| case ModeLong64: |
| operSize, immSize, dispSize, addrSize = 4, 4, 4, 8 |
| case ModeProt32: |
| operSize, immSize, dispSize, addrSize = 4, 4, 4, 4 |
| case ModeProt16, ModeReal16: |
| operSize, immSize, dispSize, addrSize = 2, 2, 2, 2 |
| default: |
| panic("bad mode") |
| } |
| |
| var code []byte |
| |
| rexR := false |
| var vvvv, vexR, vexX, vexB byte |
| |
| // LEGACY PREFIXES |
| if insn.Vex == 0 { |
| for r.Intn(3) == 0 { |
| // LOCK 0xF0 is always added to insn.Prefix |
| prefixes := []byte{ |
| 0x2E, // CS |
| 0x3E, // DS |
| 0x26, // ES |
| 0x64, // FS |
| 0x65, // GS |
| 0x36, // SS |
| } |
| if !insn.No66Prefix { |
| prefixes = append(prefixes, 0x66) // operand size |
| } |
| if cfg.Mode == ModeLong64 || !insn.Mem32 { |
| prefixes = append(prefixes, 0x67) // address size |
| } |
| if !insn.NoRepPrefix { |
| prefixes = append(prefixes, |
| 0xF3, // REP |
| 0xF2, // REPNE |
| ) |
| } |
| pref := prefixes[r.Intn(len(prefixes))] |
| code = append(code, pref) |
| } |
| |
| code = append(code, insn.Prefix...) |
| |
| // REX |
| var rex byte |
| if cfg.Mode == ModeLong64 && r.Intn(2) == 0 { |
| // bit 0 - B |
| // bit 1 - X |
| // bit 2 - R |
| // bit 3 - W |
| rex = byte(0x40 | r.Intn(16)) |
| if insn.Rexw == 1 { |
| rex |= 1 << 3 |
| } else { |
| rex &^= 1 << 3 |
| } |
| rexR = rex&0x4 != 0 |
| code = append(code, rex) |
| } |
| |
| operSize1, immSize1, dispSize1, addrSize1 := operSize, immSize, dispSize, addrSize |
| for _, pref := range code { |
| switch pref { |
| case 0x66: |
| if immSize == 4 { |
| immSize1 = 2 |
| operSize1 = 2 |
| } else if immSize == 2 { |
| immSize1 = 4 |
| operSize1 = 4 |
| } |
| case 0x67: |
| if addrSize == 8 { |
| addrSize1 = 4 |
| } else if addrSize == 4 { |
| dispSize1 = 2 |
| addrSize1 = 2 |
| } else if addrSize == 2 { |
| dispSize1 = 4 |
| addrSize1 = 4 |
| } |
| } |
| if rex&(1<<3) != 0 { |
| operSize1 = 8 |
| immSize1 = 4 |
| } |
| } |
| operSize, immSize, dispSize, addrSize = operSize1, immSize1, dispSize1, addrSize1 |
| } else { |
| // VEX/VOP |
| code = append(code, insn.Vex) |
| vexR = byte(1) |
| vexX = byte(1) |
| if cfg.Mode == ModeLong64 { |
| vexR = byte(r.Intn(2)) |
| vexX = byte(r.Intn(2)) |
| } |
| vexB = byte(r.Intn(2)) |
| W := byte(r.Intn(2)) |
| if insn.Rexw == 1 { |
| W = 1 |
| } else if insn.Rexw == -1 { |
| W = 0 |
| } |
| L := byte(r.Intn(2)) |
| if insn.VexL == 1 { |
| L = 1 |
| } else if insn.VexL == -1 { |
| L = 0 |
| } |
| pp := byte(r.Intn(4)) |
| if insn.VexP != -1 { |
| pp = byte(insn.VexP) |
| } |
| vvvv = 15 |
| if !insn.VexNoR { |
| vvvv = byte(r.Intn(16)) |
| } |
| code = append(code, vexR<<7|vexX<<6|vexB<<5|insn.VexMap) |
| code = append(code, W<<7|vvvv<<3|L<<2|pp) |
| // TODO: short encoding |
| if cfg.Mode != ModeLong64 { |
| vvvv |= 8 |
| } |
| } |
| |
| // OPCODE |
| code = append(code, insn.Opcode...) |
| |
| if insn.Srm { |
| rm := byte(insn.Rm) |
| if insn.Rm == -1 { |
| rm = byte(r.Intn(8)) |
| } |
| code[len(code)-1] |= rm |
| } else if insn.Modrm { |
| // MODRM |
| var mod byte |
| switch insn.Mod { |
| case 0, 1, 2, 3: |
| mod = byte(insn.Mod) |
| case -1: |
| mod = byte(r.Intn(4)) |
| case -3: |
| mod = byte(r.Intn(3)) |
| } |
| |
| reg := byte(insn.Reg) |
| if insn.Reg == -1 { |
| reg = byte(r.Intn(8)) |
| } else if insn.Reg == -6 { |
| reg = byte(r.Intn(6)) // segment register |
| } else if insn.Reg == -8 { |
| if rexR { |
| reg = 0 // CR8 |
| } else { |
| crs := []byte{0, 2, 3, 4} |
| reg = crs[r.Intn(len(crs))] |
| } |
| } |
| if insn.Avx2Gather { |
| if reg|(1-vexR)<<3 == vvvv^0xf { |
| reg = (reg + 1) & 7 |
| } |
| } |
| |
| rm := byte(insn.Rm) |
| if insn.Rm == -1 { |
| rm = byte(r.Intn(8)) |
| } |
| |
| modrm := mod<<6 | reg<<3 | rm |
| code = append(code, modrm) |
| |
| if !insn.NoSibDisp { |
| if addrSize == 2 { |
| if mod == 1 { |
| // disp8 |
| code = append(code, generateArg(cfg, r, 1)...) |
| } else if mod == 2 || mod == 0 && rm == 6 { |
| // disp16 |
| code = append(code, generateArg(cfg, r, 2)...) |
| } |
| } else { |
| var sibbase byte |
| if mod != 3 && rm == 4 { |
| // SIB |
| scale := byte(r.Intn(4)) |
| index := byte(r.Intn(8)) |
| sibbase = byte(r.Intn(8)) |
| if insn.Avx2Gather { |
| rrrr := reg | (1-vexR)<<3 |
| for { |
| iiii := index | (1-vexX)<<3 |
| if iiii != vvvv^0xf && iiii != rrrr { |
| break |
| } |
| index = (index + 1) & 7 |
| } |
| } |
| sib := scale<<6 | index<<3 | sibbase |
| code = append(code, sib) |
| } |
| |
| if mod == 1 { |
| // disp8 |
| code = append(code, generateArg(cfg, r, 1)...) |
| } else if mod == 2 || mod == 0 && rm == 5 || mod == 0 && sibbase == 5 { |
| // disp16/32 |
| code = append(code, generateArg(cfg, r, dispSize)...) |
| } |
| } |
| } |
| } |
| |
| addImm := func(imm int) { |
| if imm == -1 { |
| imm = immSize |
| } else if imm == -2 { |
| imm = addrSize |
| } else if imm == -3 { |
| imm = operSize |
| } |
| if imm != 0 { |
| code = append(code, generateArg(cfg, r, imm)...) |
| } |
| } |
| addImm(int(insn.Imm)) |
| addImm(int(insn.Imm2)) |
| |
| code = append(code, insn.Suffix...) |
| return code |
| } |