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  }