github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/golang.org/x/arch/x86/x86asm/intel.go (about)

     1  // Copyright 2014 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package x86asm
     6  
     7  import (
     8  	"fmt"
     9  	"strings"
    10  )
    11  
    12  // IntelSyntax returns the Intel assembler syntax for the instruction, as defined by Intel's XED tool.
    13  func IntelSyntax(inst Inst, pc uint64, symname SymLookup) string {
    14  	if symname == nil {
    15  		symname = func(uint64) (string, uint64) { return "", 0 }
    16  	}
    17  
    18  	var iargs []Arg
    19  	for _, a := range inst.Args {
    20  		if a == nil {
    21  			break
    22  		}
    23  		iargs = append(iargs, a)
    24  	}
    25  
    26  	switch inst.Op {
    27  	case INSB, INSD, INSW, OUTSB, OUTSD, OUTSW, LOOPNE, JCXZ, JECXZ, JRCXZ, LOOP, LOOPE, MOV, XLATB:
    28  		if inst.Op == MOV && (inst.Opcode>>16)&0xFFFC != 0x0F20 {
    29  			break
    30  		}
    31  		for i, p := range inst.Prefix {
    32  			if p&0xFF == PrefixAddrSize {
    33  				inst.Prefix[i] &^= PrefixImplicit
    34  			}
    35  		}
    36  	}
    37  
    38  	switch inst.Op {
    39  	case MOV:
    40  		dst, _ := inst.Args[0].(Reg)
    41  		src, _ := inst.Args[1].(Reg)
    42  		if ES <= dst && dst <= GS && EAX <= src && src <= R15L {
    43  			src -= EAX - AX
    44  			iargs[1] = src
    45  		}
    46  		if ES <= dst && dst <= GS && RAX <= src && src <= R15 {
    47  			src -= RAX - AX
    48  			iargs[1] = src
    49  		}
    50  
    51  		if inst.Opcode>>24&^3 == 0xA0 {
    52  			for i, p := range inst.Prefix {
    53  				if p&0xFF == PrefixAddrSize {
    54  					inst.Prefix[i] |= PrefixImplicit
    55  				}
    56  			}
    57  		}
    58  	}
    59  
    60  	switch inst.Op {
    61  	case AAM, AAD:
    62  		if imm, ok := iargs[0].(Imm); ok {
    63  			if inst.DataSize == 32 {
    64  				iargs[0] = Imm(uint32(int8(imm)))
    65  			} else if inst.DataSize == 16 {
    66  				iargs[0] = Imm(uint16(int8(imm)))
    67  			}
    68  		}
    69  
    70  	case PUSH:
    71  		if imm, ok := iargs[0].(Imm); ok {
    72  			iargs[0] = Imm(uint32(imm))
    73  		}
    74  	}
    75  
    76  	for _, p := range inst.Prefix {
    77  		if p&PrefixImplicit != 0 {
    78  			for j, pj := range inst.Prefix {
    79  				if pj&0xFF == p&0xFF {
    80  					inst.Prefix[j] |= PrefixImplicit
    81  				}
    82  			}
    83  		}
    84  	}
    85  
    86  	if inst.Op != 0 {
    87  		for i, p := range inst.Prefix {
    88  			switch p &^ PrefixIgnored {
    89  			case PrefixData16, PrefixData32, PrefixCS, PrefixDS, PrefixES, PrefixSS:
    90  				inst.Prefix[i] |= PrefixImplicit
    91  			}
    92  			if p.IsREX() {
    93  				inst.Prefix[i] |= PrefixImplicit
    94  			}
    95  			if p.IsVEX() {
    96  				if p == PrefixVEX3Bytes {
    97  					inst.Prefix[i+2] |= PrefixImplicit
    98  				}
    99  				inst.Prefix[i] |= PrefixImplicit
   100  				inst.Prefix[i+1] |= PrefixImplicit
   101  			}
   102  		}
   103  	}
   104  
   105  	if isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ {
   106  		for i, p := range inst.Prefix {
   107  			if p == PrefixPT || p == PrefixPN {
   108  				inst.Prefix[i] |= PrefixImplicit
   109  			}
   110  		}
   111  	}
   112  
   113  	switch inst.Op {
   114  	case AAA, AAS, CBW, CDQE, CLC, CLD, CLI, CLTS, CMC, CPUID, CQO, CWD, DAA, DAS,
   115  		FDECSTP, FINCSTP, FNCLEX, FNINIT, FNOP, FWAIT, HLT,
   116  		ICEBP, INSB, INSD, INSW, INT, INTO, INVD, IRET, IRETQ,
   117  		LAHF, LEAVE, LRET, MONITOR, MWAIT, NOP, OUTSB, OUTSD, OUTSW,
   118  		PAUSE, POPA, POPF, POPFQ, PUSHA, PUSHF, PUSHFQ,
   119  		RDMSR, RDPMC, RDTSC, RDTSCP, RET, RSM,
   120  		SAHF, STC, STD, STI, SYSENTER, SYSEXIT, SYSRET,
   121  		UD2, WBINVD, WRMSR, XEND, XLATB, XTEST:
   122  
   123  		if inst.Op == NOP && inst.Opcode>>24 != 0x90 {
   124  			break
   125  		}
   126  		if inst.Op == RET && inst.Opcode>>24 != 0xC3 {
   127  			break
   128  		}
   129  		if inst.Op == INT && inst.Opcode>>24 != 0xCC {
   130  			break
   131  		}
   132  		if inst.Op == LRET && inst.Opcode>>24 != 0xcb {
   133  			break
   134  		}
   135  		for i, p := range inst.Prefix {
   136  			if p&0xFF == PrefixDataSize {
   137  				inst.Prefix[i] &^= PrefixImplicit | PrefixIgnored
   138  			}
   139  		}
   140  
   141  	case 0:
   142  		// ok
   143  	}
   144  
   145  	switch inst.Op {
   146  	case INSB, INSD, INSW, OUTSB, OUTSD, OUTSW, MONITOR, MWAIT, XLATB:
   147  		iargs = nil
   148  
   149  	case STOSB, STOSW, STOSD, STOSQ:
   150  		iargs = iargs[:1]
   151  
   152  	case LODSB, LODSW, LODSD, LODSQ, SCASB, SCASW, SCASD, SCASQ:
   153  		iargs = iargs[1:]
   154  	}
   155  
   156  	const (
   157  		haveData16 = 1 << iota
   158  		haveData32
   159  		haveAddr16
   160  		haveAddr32
   161  		haveXacquire
   162  		haveXrelease
   163  		haveLock
   164  		haveHintTaken
   165  		haveHintNotTaken
   166  		haveBnd
   167  	)
   168  	var prefixBits uint32
   169  	prefix := ""
   170  	for _, p := range inst.Prefix {
   171  		if p == 0 {
   172  			break
   173  		}
   174  		if p&0xFF == 0xF3 {
   175  			prefixBits &^= haveBnd
   176  		}
   177  		if p&(PrefixImplicit|PrefixIgnored) != 0 {
   178  			continue
   179  		}
   180  		switch p {
   181  		default:
   182  			prefix += strings.ToLower(p.String()) + " "
   183  		case PrefixCS, PrefixDS, PrefixES, PrefixFS, PrefixGS, PrefixSS:
   184  			if inst.Op == 0 {
   185  				prefix += strings.ToLower(p.String()) + " "
   186  			}
   187  		case PrefixREPN:
   188  			prefix += "repne "
   189  		case PrefixLOCK:
   190  			prefixBits |= haveLock
   191  		case PrefixData16, PrefixDataSize:
   192  			prefixBits |= haveData16
   193  		case PrefixData32:
   194  			prefixBits |= haveData32
   195  		case PrefixAddrSize, PrefixAddr16:
   196  			prefixBits |= haveAddr16
   197  		case PrefixAddr32:
   198  			prefixBits |= haveAddr32
   199  		case PrefixXACQUIRE:
   200  			prefixBits |= haveXacquire
   201  		case PrefixXRELEASE:
   202  			prefixBits |= haveXrelease
   203  		case PrefixPT:
   204  			prefixBits |= haveHintTaken
   205  		case PrefixPN:
   206  			prefixBits |= haveHintNotTaken
   207  		case PrefixBND:
   208  			prefixBits |= haveBnd
   209  		}
   210  	}
   211  	switch inst.Op {
   212  	case JMP:
   213  		if inst.Opcode>>24 == 0xEB {
   214  			prefixBits &^= haveBnd
   215  		}
   216  	case RET, LRET:
   217  		prefixBits &^= haveData16 | haveData32
   218  	}
   219  
   220  	if prefixBits&haveXacquire != 0 {
   221  		prefix += "xacquire "
   222  	}
   223  	if prefixBits&haveXrelease != 0 {
   224  		prefix += "xrelease "
   225  	}
   226  	if prefixBits&haveLock != 0 {
   227  		prefix += "lock "
   228  	}
   229  	if prefixBits&haveBnd != 0 {
   230  		prefix += "bnd "
   231  	}
   232  	if prefixBits&haveHintTaken != 0 {
   233  		prefix += "hint-taken "
   234  	}
   235  	if prefixBits&haveHintNotTaken != 0 {
   236  		prefix += "hint-not-taken "
   237  	}
   238  	if prefixBits&haveAddr16 != 0 {
   239  		prefix += "addr16 "
   240  	}
   241  	if prefixBits&haveAddr32 != 0 {
   242  		prefix += "addr32 "
   243  	}
   244  	if prefixBits&haveData16 != 0 {
   245  		prefix += "data16 "
   246  	}
   247  	if prefixBits&haveData32 != 0 {
   248  		prefix += "data32 "
   249  	}
   250  
   251  	if inst.Op == 0 {
   252  		if prefix == "" {
   253  			return "<no instruction>"
   254  		}
   255  		return prefix[:len(prefix)-1]
   256  	}
   257  
   258  	var args []string
   259  	for _, a := range iargs {
   260  		if a == nil {
   261  			break
   262  		}
   263  		args = append(args, intelArg(&inst, pc, symname, a))
   264  	}
   265  
   266  	var op string
   267  	switch inst.Op {
   268  	case NOP:
   269  		if inst.Opcode>>24 == 0x0F {
   270  			if inst.DataSize == 16 {
   271  				args = append(args, "ax")
   272  			} else {
   273  				args = append(args, "eax")
   274  			}
   275  		}
   276  
   277  	case BLENDVPD, BLENDVPS, PBLENDVB:
   278  		args = args[:2]
   279  
   280  	case INT:
   281  		if inst.Opcode>>24 == 0xCC {
   282  			args = nil
   283  			op = "int3"
   284  		}
   285  
   286  	case LCALL, LJMP:
   287  		if len(args) == 2 {
   288  			args[0], args[1] = args[1], args[0]
   289  		}
   290  
   291  	case FCHS, FABS, FTST, FLDPI, FLDL2E, FLDLG2, F2XM1, FXAM, FLD1, FLDL2T, FSQRT, FRNDINT, FCOS, FSIN:
   292  		if len(args) == 0 {
   293  			args = append(args, "st0")
   294  		}
   295  
   296  	case FPTAN, FSINCOS, FUCOMPP, FCOMPP, FYL2X, FPATAN, FXTRACT, FPREM1, FPREM, FYL2XP1, FSCALE:
   297  		if len(args) == 0 {
   298  			args = []string{"st0", "st1"}
   299  		}
   300  
   301  	case FST, FSTP, FISTTP, FIST, FISTP, FBSTP:
   302  		if len(args) == 1 {
   303  			args = append(args, "st0")
   304  		}
   305  
   306  	case FLD, FXCH, FCOM, FCOMP, FIADD, FIMUL, FICOM, FICOMP, FISUBR, FIDIV, FUCOM, FUCOMP, FILD, FBLD, FADD, FMUL, FSUB, FSUBR, FISUB, FDIV, FDIVR, FIDIVR:
   307  		if len(args) == 1 {
   308  			args = []string{"st0", args[0]}
   309  		}
   310  
   311  	case MASKMOVDQU, MASKMOVQ, XLATB, OUTSB, OUTSW, OUTSD:
   312  	FixSegment:
   313  		for i := len(inst.Prefix) - 1; i >= 0; i-- {
   314  			p := inst.Prefix[i] & 0xFF
   315  			switch p {
   316  			case PrefixCS, PrefixES, PrefixFS, PrefixGS, PrefixSS:
   317  				if inst.Mode != 64 || p == PrefixFS || p == PrefixGS {
   318  					args = append(args, strings.ToLower((inst.Prefix[i] & 0xFF).String()))
   319  					break FixSegment
   320  				}
   321  			case PrefixDS:
   322  				if inst.Mode != 64 {
   323  					break FixSegment
   324  				}
   325  			}
   326  		}
   327  	}
   328  
   329  	if op == "" {
   330  		op = intelOp[inst.Op]
   331  	}
   332  	if op == "" {
   333  		op = strings.ToLower(inst.Op.String())
   334  	}
   335  	if args != nil {
   336  		op += " " + strings.Join(args, ", ")
   337  	}
   338  	return prefix + op
   339  }
   340  
   341  func intelArg(inst *Inst, pc uint64, symname SymLookup, arg Arg) string {
   342  	switch a := arg.(type) {
   343  	case Imm:
   344  		if s, base := symname(uint64(a)); s != "" {
   345  			suffix := ""
   346  			if uint64(a) != base {
   347  				suffix = fmt.Sprintf("%+d", uint64(a)-base)
   348  			}
   349  			return fmt.Sprintf("$%s%s", s, suffix)
   350  		}
   351  		if inst.Mode == 32 {
   352  			return fmt.Sprintf("%#x", uint32(a))
   353  		}
   354  		if Imm(int32(a)) == a {
   355  			return fmt.Sprintf("%#x", int64(a))
   356  		}
   357  		return fmt.Sprintf("%#x", uint64(a))
   358  	case Mem:
   359  		if a.Base == EIP {
   360  			a.Base = RIP
   361  		}
   362  		prefix := ""
   363  		switch inst.MemBytes {
   364  		case 1:
   365  			prefix = "byte "
   366  		case 2:
   367  			prefix = "word "
   368  		case 4:
   369  			prefix = "dword "
   370  		case 8:
   371  			prefix = "qword "
   372  		case 16:
   373  			prefix = "xmmword "
   374  		case 32:
   375  			prefix = "ymmword "
   376  		}
   377  		switch inst.Op {
   378  		case INVLPG:
   379  			prefix = "byte "
   380  		case STOSB, MOVSB, CMPSB, LODSB, SCASB:
   381  			prefix = "byte "
   382  		case STOSW, MOVSW, CMPSW, LODSW, SCASW:
   383  			prefix = "word "
   384  		case STOSD, MOVSD, CMPSD, LODSD, SCASD:
   385  			prefix = "dword "
   386  		case STOSQ, MOVSQ, CMPSQ, LODSQ, SCASQ:
   387  			prefix = "qword "
   388  		case LAR:
   389  			prefix = "word "
   390  		case BOUND:
   391  			if inst.Mode == 32 {
   392  				prefix = "qword "
   393  			} else {
   394  				prefix = "dword "
   395  			}
   396  		case PREFETCHW, PREFETCHNTA, PREFETCHT0, PREFETCHT1, PREFETCHT2, CLFLUSH:
   397  			prefix = "zmmword "
   398  		}
   399  		switch inst.Op {
   400  		case MOVSB, MOVSW, MOVSD, MOVSQ, CMPSB, CMPSW, CMPSD, CMPSQ, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ, LODSB, LODSW, LODSD, LODSQ:
   401  			switch a.Base {
   402  			case DI, EDI, RDI:
   403  				if a.Segment == ES {
   404  					a.Segment = 0
   405  				}
   406  			case SI, ESI, RSI:
   407  				if a.Segment == DS {
   408  					a.Segment = 0
   409  				}
   410  			}
   411  		case LEA:
   412  			a.Segment = 0
   413  		default:
   414  			switch a.Base {
   415  			case SP, ESP, RSP, BP, EBP, RBP:
   416  				if a.Segment == SS {
   417  					a.Segment = 0
   418  				}
   419  			default:
   420  				if a.Segment == DS {
   421  					a.Segment = 0
   422  				}
   423  			}
   424  		}
   425  
   426  		if inst.Mode == 64 && a.Segment != FS && a.Segment != GS {
   427  			a.Segment = 0
   428  		}
   429  
   430  		prefix += "ptr "
   431  		if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
   432  			suffix := ""
   433  			if disp != 0 {
   434  				suffix = fmt.Sprintf("%+d", disp)
   435  			}
   436  			return prefix + fmt.Sprintf("[%s%s]", s, suffix)
   437  		}
   438  		if a.Segment != 0 {
   439  			prefix += strings.ToLower(a.Segment.String()) + ":"
   440  		}
   441  		prefix += "["
   442  		if a.Base != 0 {
   443  			prefix += intelArg(inst, pc, symname, a.Base)
   444  		}
   445  		if a.Scale != 0 && a.Index != 0 {
   446  			if a.Base != 0 {
   447  				prefix += "+"
   448  			}
   449  			prefix += fmt.Sprintf("%s*%d", intelArg(inst, pc, symname, a.Index), a.Scale)
   450  		}
   451  		if a.Disp != 0 {
   452  			if prefix[len(prefix)-1] == '[' && (a.Disp >= 0 || int64(int32(a.Disp)) != a.Disp) {
   453  				prefix += fmt.Sprintf("%#x", uint64(a.Disp))
   454  			} else {
   455  				prefix += fmt.Sprintf("%+#x", a.Disp)
   456  			}
   457  		}
   458  		prefix += "]"
   459  		return prefix
   460  	case Rel:
   461  		if pc == 0 {
   462  			return fmt.Sprintf(".%+#x", int64(a))
   463  		} else {
   464  			addr := pc + uint64(inst.Len) + uint64(a)
   465  			if s, base := symname(addr); s != "" && addr == base {
   466  				return fmt.Sprintf("%s", s)
   467  			} else {
   468  				addr := pc + uint64(inst.Len) + uint64(a)
   469  				return fmt.Sprintf("%#x", addr)
   470  			}
   471  		}
   472  	case Reg:
   473  		if int(a) < len(intelReg) && intelReg[a] != "" {
   474  			switch inst.Op {
   475  			case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
   476  				return strings.Replace(intelReg[a], "xmm", "ymm", -1)
   477  			default:
   478  				return intelReg[a]
   479  			}
   480  		}
   481  	}
   482  	return strings.ToLower(arg.String())
   483  }
   484  
   485  var intelOp = map[Op]string{
   486  	JAE:       "jnb",
   487  	JA:        "jnbe",
   488  	JGE:       "jnl",
   489  	JNE:       "jnz",
   490  	JG:        "jnle",
   491  	JE:        "jz",
   492  	SETAE:     "setnb",
   493  	SETA:      "setnbe",
   494  	SETGE:     "setnl",
   495  	SETNE:     "setnz",
   496  	SETG:      "setnle",
   497  	SETE:      "setz",
   498  	CMOVAE:    "cmovnb",
   499  	CMOVA:     "cmovnbe",
   500  	CMOVGE:    "cmovnl",
   501  	CMOVNE:    "cmovnz",
   502  	CMOVG:     "cmovnle",
   503  	CMOVE:     "cmovz",
   504  	LCALL:     "call far",
   505  	LJMP:      "jmp far",
   506  	LRET:      "ret far",
   507  	ICEBP:     "int1",
   508  	MOVSD_XMM: "movsd",
   509  	XLATB:     "xlat",
   510  }
   511  
   512  var intelReg = [...]string{
   513  	F0:  "st0",
   514  	F1:  "st1",
   515  	F2:  "st2",
   516  	F3:  "st3",
   517  	F4:  "st4",
   518  	F5:  "st5",
   519  	F6:  "st6",
   520  	F7:  "st7",
   521  	M0:  "mmx0",
   522  	M1:  "mmx1",
   523  	M2:  "mmx2",
   524  	M3:  "mmx3",
   525  	M4:  "mmx4",
   526  	M5:  "mmx5",
   527  	M6:  "mmx6",
   528  	M7:  "mmx7",
   529  	X0:  "xmm0",
   530  	X1:  "xmm1",
   531  	X2:  "xmm2",
   532  	X3:  "xmm3",
   533  	X4:  "xmm4",
   534  	X5:  "xmm5",
   535  	X6:  "xmm6",
   536  	X7:  "xmm7",
   537  	X8:  "xmm8",
   538  	X9:  "xmm9",
   539  	X10: "xmm10",
   540  	X11: "xmm11",
   541  	X12: "xmm12",
   542  	X13: "xmm13",
   543  	X14: "xmm14",
   544  	X15: "xmm15",
   545  
   546  	// TODO: Maybe the constants are named wrong.
   547  	SPB: "spl",
   548  	BPB: "bpl",
   549  	SIB: "sil",
   550  	DIB: "dil",
   551  
   552  	R8L:  "r8d",
   553  	R9L:  "r9d",
   554  	R10L: "r10d",
   555  	R11L: "r11d",
   556  	R12L: "r12d",
   557  	R13L: "r13d",
   558  	R14L: "r14d",
   559  	R15L: "r15d",
   560  }