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  }