...

Source file src/pkg/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 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	}
   561	

View as plain text