Source file src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go

     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 (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 { // See comment in plan9x.go.
   345  			if s, base := symname(uint64(a)); s != "" {
   346  				suffix := ""
   347  				if uint64(a) != base {
   348  					suffix = fmt.Sprintf("%+d", uint64(a)-base)
   349  				}
   350  				return fmt.Sprintf("$%s%s", s, suffix)
   351  			}
   352  		}
   353  		if inst.Mode == 32 {
   354  			return fmt.Sprintf("%#x", uint32(a))
   355  		}
   356  		if Imm(int32(a)) == a {
   357  			return fmt.Sprintf("%#x", int64(a))
   358  		}
   359  		return fmt.Sprintf("%#x", uint64(a))
   360  	case Mem:
   361  		if a.Base == EIP {
   362  			a.Base = RIP
   363  		}
   364  		prefix := ""
   365  		switch inst.MemBytes {
   366  		case 1:
   367  			prefix = "byte "
   368  		case 2:
   369  			prefix = "word "
   370  		case 4:
   371  			prefix = "dword "
   372  		case 8:
   373  			prefix = "qword "
   374  		case 16:
   375  			prefix = "xmmword "
   376  		case 32:
   377  			prefix = "ymmword "
   378  		}
   379  		switch inst.Op {
   380  		case INVLPG:
   381  			prefix = "byte "
   382  		case STOSB, MOVSB, CMPSB, LODSB, SCASB:
   383  			prefix = "byte "
   384  		case STOSW, MOVSW, CMPSW, LODSW, SCASW:
   385  			prefix = "word "
   386  		case STOSD, MOVSD, CMPSD, LODSD, SCASD:
   387  			prefix = "dword "
   388  		case STOSQ, MOVSQ, CMPSQ, LODSQ, SCASQ:
   389  			prefix = "qword "
   390  		case LAR:
   391  			prefix = "word "
   392  		case BOUND:
   393  			if inst.Mode == 32 {
   394  				prefix = "qword "
   395  			} else {
   396  				prefix = "dword "
   397  			}
   398  		case PREFETCHW, PREFETCHNTA, PREFETCHT0, PREFETCHT1, PREFETCHT2, CLFLUSH:
   399  			prefix = "zmmword "
   400  		}
   401  		switch inst.Op {
   402  		case MOVSB, MOVSW, MOVSD, MOVSQ, CMPSB, CMPSW, CMPSD, CMPSQ, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ, LODSB, LODSW, LODSD, LODSQ:
   403  			switch a.Base {
   404  			case DI, EDI, RDI:
   405  				if a.Segment == ES {
   406  					a.Segment = 0
   407  				}
   408  			case SI, ESI, RSI:
   409  				if a.Segment == DS {
   410  					a.Segment = 0
   411  				}
   412  			}
   413  		case LEA:
   414  			a.Segment = 0
   415  		default:
   416  			switch a.Base {
   417  			case SP, ESP, RSP, BP, EBP, RBP:
   418  				if a.Segment == SS {
   419  					a.Segment = 0
   420  				}
   421  			default:
   422  				if a.Segment == DS {
   423  					a.Segment = 0
   424  				}
   425  			}
   426  		}
   427  
   428  		if inst.Mode == 64 && a.Segment != FS && a.Segment != GS {
   429  			a.Segment = 0
   430  		}
   431  
   432  		prefix += "ptr "
   433  		if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
   434  			suffix := ""
   435  			if disp != 0 {
   436  				suffix = fmt.Sprintf("%+d", disp)
   437  			}
   438  			return prefix + fmt.Sprintf("[%s%s]", s, suffix)
   439  		}
   440  		if a.Segment != 0 {
   441  			prefix += strings.ToLower(a.Segment.String()) + ":"
   442  		}
   443  		prefix += "["
   444  		if a.Base != 0 {
   445  			prefix += intelArg(inst, pc, symname, a.Base)
   446  		}
   447  		if a.Scale != 0 && a.Index != 0 {
   448  			if a.Base != 0 {
   449  				prefix += "+"
   450  			}
   451  			prefix += fmt.Sprintf("%s*%d", intelArg(inst, pc, symname, a.Index), a.Scale)
   452  		}
   453  		if a.Disp != 0 {
   454  			if prefix[len(prefix)-1] == '[' && (a.Disp >= 0 || int64(int32(a.Disp)) != a.Disp) {
   455  				prefix += fmt.Sprintf("%#x", uint64(a.Disp))
   456  			} else {
   457  				prefix += fmt.Sprintf("%+#x", a.Disp)
   458  			}
   459  		}
   460  		prefix += "]"
   461  		return prefix
   462  	case Rel:
   463  		if pc == 0 {
   464  			return fmt.Sprintf(".%+#x", int64(a))
   465  		} else {
   466  			addr := pc + uint64(inst.Len) + uint64(a)
   467  			if s, base := symname(addr); s != "" && addr == base {
   468  				return fmt.Sprintf("%s", s)
   469  			} else {
   470  				addr := pc + uint64(inst.Len) + uint64(a)
   471  				return fmt.Sprintf("%#x", addr)
   472  			}
   473  		}
   474  	case Reg:
   475  		if int(a) < len(intelReg) && intelReg[a] != "" {
   476  			switch inst.Op {
   477  			case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
   478  				return strings.Replace(intelReg[a], "xmm", "ymm", -1)
   479  			default:
   480  				return intelReg[a]
   481  			}
   482  		}
   483  	}
   484  	return strings.ToLower(arg.String())
   485  }
   486  
   487  var intelOp = map[Op]string{
   488  	JAE:       "jnb",
   489  	JA:        "jnbe",
   490  	JGE:       "jnl",
   491  	JNE:       "jnz",
   492  	JG:        "jnle",
   493  	JE:        "jz",
   494  	SETAE:     "setnb",
   495  	SETA:      "setnbe",
   496  	SETGE:     "setnl",
   497  	SETNE:     "setnz",
   498  	SETG:      "setnle",
   499  	SETE:      "setz",
   500  	CMOVAE:    "cmovnb",
   501  	CMOVA:     "cmovnbe",
   502  	CMOVGE:    "cmovnl",
   503  	CMOVNE:    "cmovnz",
   504  	CMOVG:     "cmovnle",
   505  	CMOVE:     "cmovz",
   506  	LCALL:     "call far",
   507  	LJMP:      "jmp far",
   508  	LRET:      "ret far",
   509  	ICEBP:     "int1",
   510  	MOVSD_XMM: "movsd",
   511  	XLATB:     "xlat",
   512  }
   513  
   514  var intelReg = [...]string{
   515  	F0:  "st0",
   516  	F1:  "st1",
   517  	F2:  "st2",
   518  	F3:  "st3",
   519  	F4:  "st4",
   520  	F5:  "st5",
   521  	F6:  "st6",
   522  	F7:  "st7",
   523  	M0:  "mmx0",
   524  	M1:  "mmx1",
   525  	M2:  "mmx2",
   526  	M3:  "mmx3",
   527  	M4:  "mmx4",
   528  	M5:  "mmx5",
   529  	M6:  "mmx6",
   530  	M7:  "mmx7",
   531  	X0:  "xmm0",
   532  	X1:  "xmm1",
   533  	X2:  "xmm2",
   534  	X3:  "xmm3",
   535  	X4:  "xmm4",
   536  	X5:  "xmm5",
   537  	X6:  "xmm6",
   538  	X7:  "xmm7",
   539  	X8:  "xmm8",
   540  	X9:  "xmm9",
   541  	X10: "xmm10",
   542  	X11: "xmm11",
   543  	X12: "xmm12",
   544  	X13: "xmm13",
   545  	X14: "xmm14",
   546  	X15: "xmm15",
   547  
   548  	// TODO: Maybe the constants are named wrong.
   549  	SPB: "spl",
   550  	BPB: "bpl",
   551  	SIB: "sil",
   552  	DIB: "dil",
   553  
   554  	R8L:  "r8d",
   555  	R9L:  "r9d",
   556  	R10L: "r10d",
   557  	R11L: "r11d",
   558  	R12L: "r12d",
   559  	R13L: "r13d",
   560  	R14L: "r14d",
   561  	R15L: "r15d",
   562  }
   563  

View as plain text