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