syzkaller/pkg/ifuzz/encode.go
2017-06-03 10:41:09 +02:00

259 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 Developers Manual Volume 2: Instruction Set Reference
// and AMD64 Architecture Programmers Manual Volume 3: General-Purpose and System Instructions
// for details of instruction encoding.
package ifuzz
import (
"math/rand"
)
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 if insn.Rexw == 1 {
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
}