Source file src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.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  // GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
    13  // This general form is often called “AT&T syntax” as a reference to AT&T System V Unix.
    14  func GNUSyntax(inst Inst, pc uint64, symname SymLookup) string {
    15  	// Rewrite instruction to mimic GNU peculiarities.
    16  	// Note that inst has been passed by value and contains
    17  	// no pointers, so any changes we make here are local
    18  	// and will not propagate back out to the caller.
    19  
    20  	if symname == nil {
    21  		symname = func(uint64) (string, uint64) { return "", 0 }
    22  	}
    23  
    24  	// Adjust opcode [sic].
    25  	switch inst.Op {
    26  	case FDIV, FDIVR, FSUB, FSUBR, FDIVP, FDIVRP, FSUBP, FSUBRP:
    27  		// DC E0, DC F0: libopcodes swaps FSUBR/FSUB and FDIVR/FDIV, at least
    28  		// if you believe the Intel manual is correct (the encoding is irregular as given;
    29  		// libopcodes uses the more regular expected encoding).
    30  		// TODO(rsc): Test to ensure Intel manuals are correct and report to libopcodes maintainers?
    31  		// NOTE: iant thinks this is deliberate, but we can't find the history.
    32  		_, reg1 := inst.Args[0].(Reg)
    33  		_, reg2 := inst.Args[1].(Reg)
    34  		if reg1 && reg2 && (inst.Opcode>>24 == 0xDC || inst.Opcode>>24 == 0xDE) {
    35  			switch inst.Op {
    36  			case FDIV:
    37  				inst.Op = FDIVR
    38  			case FDIVR:
    39  				inst.Op = FDIV
    40  			case FSUB:
    41  				inst.Op = FSUBR
    42  			case FSUBR:
    43  				inst.Op = FSUB
    44  			case FDIVP:
    45  				inst.Op = FDIVRP
    46  			case FDIVRP:
    47  				inst.Op = FDIVP
    48  			case FSUBP:
    49  				inst.Op = FSUBRP
    50  			case FSUBRP:
    51  				inst.Op = FSUBP
    52  			}
    53  		}
    54  
    55  	case MOVNTSD:
    56  		// MOVNTSD is F2 0F 2B /r.
    57  		// MOVNTSS is F3 0F 2B /r (supposedly; not in manuals).
    58  		// Usually inner prefixes win for display,
    59  		// so that F3 F2 0F 2B 11 is REP MOVNTSD
    60  		// and F2 F3 0F 2B 11 is REPN MOVNTSS.
    61  		// Libopcodes always prefers MOVNTSS regardless of prefix order.
    62  		if countPrefix(&inst, 0xF3) > 0 {
    63  			found := false
    64  			for i := len(inst.Prefix) - 1; i >= 0; i-- {
    65  				switch inst.Prefix[i] & 0xFF {
    66  				case 0xF3:
    67  					if !found {
    68  						found = true
    69  						inst.Prefix[i] |= PrefixImplicit
    70  					}
    71  				case 0xF2:
    72  					inst.Prefix[i] &^= PrefixImplicit
    73  				}
    74  			}
    75  			inst.Op = MOVNTSS
    76  		}
    77  	}
    78  
    79  	// Add implicit arguments.
    80  	switch inst.Op {
    81  	case MONITOR:
    82  		inst.Args[0] = EDX
    83  		inst.Args[1] = ECX
    84  		inst.Args[2] = EAX
    85  		if inst.AddrSize == 16 {
    86  			inst.Args[2] = AX
    87  		}
    88  
    89  	case MWAIT:
    90  		if inst.Mode == 64 {
    91  			inst.Args[0] = RCX
    92  			inst.Args[1] = RAX
    93  		} else {
    94  			inst.Args[0] = ECX
    95  			inst.Args[1] = EAX
    96  		}
    97  	}
    98  
    99  	// Adjust which prefixes will be displayed.
   100  	// The rule is to display all the prefixes not implied by
   101  	// the usual instruction display, that is, all the prefixes
   102  	// except the ones with PrefixImplicit set.
   103  	// However, of course, there are exceptions to the rule.
   104  	switch inst.Op {
   105  	case CRC32:
   106  		// CRC32 has a mandatory F2 prefix.
   107  		// If there are multiple F2s and no F3s, the extra F2s do not print.
   108  		// (And Decode has already marked them implicit.)
   109  		// However, if there is an F3 anywhere, then the extra F2s do print.
   110  		// If there are multiple F2 prefixes *and* an (ignored) F3,
   111  		// then libopcodes prints the extra F2s as REPNs.
   112  		if countPrefix(&inst, 0xF2) > 1 {
   113  			unmarkImplicit(&inst, 0xF2)
   114  			markLastImplicit(&inst, 0xF2)
   115  		}
   116  
   117  		// An unused data size override should probably be shown,
   118  		// to distinguish DATA16 CRC32B from plain CRC32B,
   119  		// but libopcodes always treats the final override as implicit
   120  		// and the others as explicit.
   121  		unmarkImplicit(&inst, PrefixDataSize)
   122  		markLastImplicit(&inst, PrefixDataSize)
   123  
   124  	case CVTSI2SD, CVTSI2SS:
   125  		if !isMem(inst.Args[1]) {
   126  			markLastImplicit(&inst, PrefixDataSize)
   127  		}
   128  
   129  	case CVTSD2SI, CVTSS2SI, CVTTSD2SI, CVTTSS2SI,
   130  		ENTER, FLDENV, FNSAVE, FNSTENV, FRSTOR, LGDT, LIDT, LRET,
   131  		POP, PUSH, RET, SGDT, SIDT, SYSRET, XBEGIN:
   132  		markLastImplicit(&inst, PrefixDataSize)
   133  
   134  	case LOOP, LOOPE, LOOPNE, MONITOR:
   135  		markLastImplicit(&inst, PrefixAddrSize)
   136  
   137  	case MOV:
   138  		// The 16-bit and 32-bit forms of MOV Sreg, dst and MOV src, Sreg
   139  		// cannot be distinguished when src or dst refers to memory, because
   140  		// Sreg is always a 16-bit value, even when we're doing a 32-bit
   141  		// instruction. Because the instruction tables distinguished these two,
   142  		// any operand size prefix has been marked as used (to decide which
   143  		// branch to take). Unmark it, so that it will show up in disassembly,
   144  		// so that the reader can tell the size of memory operand.
   145  		// up with the same arguments
   146  		dst, _ := inst.Args[0].(Reg)
   147  		src, _ := inst.Args[1].(Reg)
   148  		if ES <= src && src <= GS && isMem(inst.Args[0]) || ES <= dst && dst <= GS && isMem(inst.Args[1]) {
   149  			unmarkImplicit(&inst, PrefixDataSize)
   150  		}
   151  
   152  	case MOVDQU:
   153  		if countPrefix(&inst, 0xF3) > 1 {
   154  			unmarkImplicit(&inst, 0xF3)
   155  			markLastImplicit(&inst, 0xF3)
   156  		}
   157  
   158  	case MOVQ2DQ:
   159  		markLastImplicit(&inst, PrefixDataSize)
   160  
   161  	case SLDT, SMSW, STR, FXRSTOR, XRSTOR, XSAVE, XSAVEOPT, CMPXCHG8B:
   162  		if isMem(inst.Args[0]) {
   163  			unmarkImplicit(&inst, PrefixDataSize)
   164  		}
   165  
   166  	case SYSEXIT:
   167  		unmarkImplicit(&inst, PrefixDataSize)
   168  	}
   169  
   170  	if isCondJmp[inst.Op] || isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ {
   171  		if countPrefix(&inst, PrefixCS) > 0 && countPrefix(&inst, PrefixDS) > 0 {
   172  			for i, p := range inst.Prefix {
   173  				switch p & 0xFFF {
   174  				case PrefixPN, PrefixPT:
   175  					inst.Prefix[i] &= 0xF0FF // cut interpretation bits, producing original segment prefix
   176  				}
   177  			}
   178  		}
   179  	}
   180  
   181  	// XACQUIRE/XRELEASE adjustment.
   182  	if inst.Op == MOV {
   183  		// MOV into memory is a candidate for turning REP into XRELEASE.
   184  		// However, if the REP is followed by a REPN, that REPN blocks the
   185  		// conversion.
   186  		haveREPN := false
   187  		for i := len(inst.Prefix) - 1; i >= 0; i-- {
   188  			switch inst.Prefix[i] &^ PrefixIgnored {
   189  			case PrefixREPN:
   190  				haveREPN = true
   191  			case PrefixXRELEASE:
   192  				if haveREPN {
   193  					inst.Prefix[i] = PrefixREP
   194  				}
   195  			}
   196  		}
   197  	}
   198  
   199  	// We only format the final F2/F3 as XRELEASE/XACQUIRE.
   200  	haveXA := false
   201  	haveXR := false
   202  	for i := len(inst.Prefix) - 1; i >= 0; i-- {
   203  		switch inst.Prefix[i] &^ PrefixIgnored {
   204  		case PrefixXRELEASE:
   205  			if !haveXR {
   206  				haveXR = true
   207  			} else {
   208  				inst.Prefix[i] = PrefixREP
   209  			}
   210  
   211  		case PrefixXACQUIRE:
   212  			if !haveXA {
   213  				haveXA = true
   214  			} else {
   215  				inst.Prefix[i] = PrefixREPN
   216  			}
   217  		}
   218  	}
   219  
   220  	// Determine opcode.
   221  	op := strings.ToLower(inst.Op.String())
   222  	if alt := gnuOp[inst.Op]; alt != "" {
   223  		op = alt
   224  	}
   225  
   226  	// Determine opcode suffix.
   227  	// Libopcodes omits the suffix if the width of the operation
   228  	// can be inferred from a register arguments. For example,
   229  	// add $1, %ebx has no suffix because you can tell from the
   230  	// 32-bit register destination that it is a 32-bit add,
   231  	// but in addl $1, (%ebx), the destination is memory, so the
   232  	// size is not evident without the l suffix.
   233  	needSuffix := true
   234  SuffixLoop:
   235  	for i, a := range inst.Args {
   236  		if a == nil {
   237  			break
   238  		}
   239  		switch a := a.(type) {
   240  		case Reg:
   241  			switch inst.Op {
   242  			case MOVSX, MOVZX:
   243  				continue
   244  
   245  			case SHL, SHR, RCL, RCR, ROL, ROR, SAR:
   246  				if i == 1 {
   247  					// shift count does not tell us operand size
   248  					continue
   249  				}
   250  
   251  			case CRC32:
   252  				// The source argument does tell us operand size,
   253  				// but libopcodes still always puts a suffix on crc32.
   254  				continue
   255  
   256  			case PUSH, POP:
   257  				// Even though segment registers are 16-bit, push and pop
   258  				// can save/restore them from 32-bit slots, so they
   259  				// do not imply operand size.
   260  				if ES <= a && a <= GS {
   261  					continue
   262  				}
   263  
   264  			case CVTSI2SD, CVTSI2SS:
   265  				// The integer register argument takes priority.
   266  				if X0 <= a && a <= X15 {
   267  					continue
   268  				}
   269  			}
   270  
   271  			if AL <= a && a <= R15 || ES <= a && a <= GS || X0 <= a && a <= X15 || M0 <= a && a <= M7 {
   272  				needSuffix = false
   273  				break SuffixLoop
   274  			}
   275  		}
   276  	}
   277  
   278  	if needSuffix {
   279  		switch inst.Op {
   280  		case CMPXCHG8B, FLDCW, FNSTCW, FNSTSW, LDMXCSR, LLDT, LMSW, LTR, PCLMULQDQ,
   281  			SETA, SETAE, SETB, SETBE, SETE, SETG, SETGE, SETL, SETLE, SETNE, SETNO, SETNP, SETNS, SETO, SETP, SETS,
   282  			SLDT, SMSW, STMXCSR, STR, VERR, VERW:
   283  			// For various reasons, libopcodes emits no suffix for these instructions.
   284  
   285  		case CRC32:
   286  			op += byteSizeSuffix(argBytes(&inst, inst.Args[1]))
   287  
   288  		case LGDT, LIDT, SGDT, SIDT:
   289  			op += byteSizeSuffix(inst.DataSize / 8)
   290  
   291  		case MOVZX, MOVSX:
   292  			// Integer size conversions get two suffixes.
   293  			op = op[:4] + byteSizeSuffix(argBytes(&inst, inst.Args[1])) + byteSizeSuffix(argBytes(&inst, inst.Args[0]))
   294  
   295  		case LOOP, LOOPE, LOOPNE:
   296  			// Add w suffix to indicate use of CX register instead of ECX.
   297  			if inst.AddrSize == 16 {
   298  				op += "w"
   299  			}
   300  
   301  		case CALL, ENTER, JMP, LCALL, LEAVE, LJMP, LRET, RET, SYSRET, XBEGIN:
   302  			// Add w suffix to indicate use of 16-bit target.
   303  			// Exclude JMP rel8.
   304  			if inst.Opcode>>24 == 0xEB {
   305  				break
   306  			}
   307  			if inst.DataSize == 16 && inst.Mode != 16 {
   308  				markLastImplicit(&inst, PrefixDataSize)
   309  				op += "w"
   310  			} else if inst.Mode == 64 {
   311  				op += "q"
   312  			}
   313  
   314  		case FRSTOR, FNSAVE, FNSTENV, FLDENV:
   315  			// Add s suffix to indicate shortened FPU state (I guess).
   316  			if inst.DataSize == 16 {
   317  				op += "s"
   318  			}
   319  
   320  		case PUSH, POP:
   321  			if markLastImplicit(&inst, PrefixDataSize) {
   322  				op += byteSizeSuffix(inst.DataSize / 8)
   323  			} else if inst.Mode == 64 {
   324  				op += "q"
   325  			} else {
   326  				op += byteSizeSuffix(inst.MemBytes)
   327  			}
   328  
   329  		default:
   330  			if isFloat(inst.Op) {
   331  				// I can't explain any of this, but it's what libopcodes does.
   332  				switch inst.MemBytes {
   333  				default:
   334  					if (inst.Op == FLD || inst.Op == FSTP) && isMem(inst.Args[0]) {
   335  						op += "t"
   336  					}
   337  				case 4:
   338  					if isFloatInt(inst.Op) {
   339  						op += "l"
   340  					} else {
   341  						op += "s"
   342  					}
   343  				case 8:
   344  					if isFloatInt(inst.Op) {
   345  						op += "ll"
   346  					} else {
   347  						op += "l"
   348  					}
   349  				}
   350  				break
   351  			}
   352  
   353  			op += byteSizeSuffix(inst.MemBytes)
   354  		}
   355  	}
   356  
   357  	// Adjust special case opcodes.
   358  	switch inst.Op {
   359  	case 0:
   360  		if inst.Prefix[0] != 0 {
   361  			return strings.ToLower(inst.Prefix[0].String())
   362  		}
   363  
   364  	case INT:
   365  		if inst.Opcode>>24 == 0xCC {
   366  			inst.Args[0] = nil
   367  			op = "int3"
   368  		}
   369  
   370  	case CMPPS, CMPPD, CMPSD_XMM, CMPSS:
   371  		imm, ok := inst.Args[2].(Imm)
   372  		if ok && 0 <= imm && imm < 8 {
   373  			inst.Args[2] = nil
   374  			op = cmppsOps[imm] + op[3:]
   375  		}
   376  
   377  	case PCLMULQDQ:
   378  		imm, ok := inst.Args[2].(Imm)
   379  		if ok && imm&^0x11 == 0 {
   380  			inst.Args[2] = nil
   381  			op = pclmulqOps[(imm&0x10)>>3|(imm&1)]
   382  		}
   383  
   384  	case XLATB:
   385  		if markLastImplicit(&inst, PrefixAddrSize) {
   386  			op = "xlat" // not xlatb
   387  		}
   388  	}
   389  
   390  	// Build list of argument strings.
   391  	var (
   392  		usedPrefixes bool     // segment prefixes consumed by Mem formatting
   393  		args         []string // formatted arguments
   394  	)
   395  	for i, a := range inst.Args {
   396  		if a == nil {
   397  			break
   398  		}
   399  		switch inst.Op {
   400  		case MOVSB, MOVSW, MOVSD, MOVSQ, OUTSB, OUTSW, OUTSD:
   401  			if i == 0 {
   402  				usedPrefixes = true // disable use of prefixes for first argument
   403  			} else {
   404  				usedPrefixes = false
   405  			}
   406  		}
   407  		if a == Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 {
   408  			continue
   409  		}
   410  		args = append(args, gnuArg(&inst, pc, symname, a, &usedPrefixes))
   411  	}
   412  
   413  	// The default is to print the arguments in reverse Intel order.
   414  	// A few instructions inhibit this behavior.
   415  	switch inst.Op {
   416  	case BOUND, LCALL, ENTER, LJMP:
   417  		// no reverse
   418  	default:
   419  		// reverse args
   420  		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   421  			args[i], args[j] = args[j], args[i]
   422  		}
   423  	}
   424  
   425  	// Build prefix string.
   426  	// Must be after argument formatting, which can turn off segment prefixes.
   427  	var (
   428  		prefix       = "" // output string
   429  		numAddr      = 0
   430  		numData      = 0
   431  		implicitData = false
   432  	)
   433  	for _, p := range inst.Prefix {
   434  		if p&0xFF == PrefixDataSize && p&PrefixImplicit != 0 {
   435  			implicitData = true
   436  		}
   437  	}
   438  	for _, p := range inst.Prefix {
   439  		if p == 0 || p.IsVEX() {
   440  			break
   441  		}
   442  		if p&PrefixImplicit != 0 {
   443  			continue
   444  		}
   445  		switch p &^ (PrefixIgnored | PrefixInvalid) {
   446  		default:
   447  			if p.IsREX() {
   448  				if p&0xFF == PrefixREX {
   449  					prefix += "rex "
   450  				} else {
   451  					prefix += "rex." + p.String()[4:] + " "
   452  				}
   453  				break
   454  			}
   455  			prefix += strings.ToLower(p.String()) + " "
   456  
   457  		case PrefixPN:
   458  			op += ",pn"
   459  			continue
   460  
   461  		case PrefixPT:
   462  			op += ",pt"
   463  			continue
   464  
   465  		case PrefixAddrSize, PrefixAddr16, PrefixAddr32:
   466  			// For unknown reasons, if the addr16 prefix is repeated,
   467  			// libopcodes displays all but the last as addr32, even though
   468  			// the addressing form used in a memory reference is clearly
   469  			// still 16-bit.
   470  			n := 32
   471  			if inst.Mode == 32 {
   472  				n = 16
   473  			}
   474  			numAddr++
   475  			if countPrefix(&inst, PrefixAddrSize) > numAddr {
   476  				n = inst.Mode
   477  			}
   478  			prefix += fmt.Sprintf("addr%d ", n)
   479  			continue
   480  
   481  		case PrefixData16, PrefixData32:
   482  			if implicitData && countPrefix(&inst, PrefixDataSize) > 1 {
   483  				// Similar to the addr32 logic above, but it only kicks in
   484  				// when something used the data size prefix (one is implicit).
   485  				n := 16
   486  				if inst.Mode == 16 {
   487  					n = 32
   488  				}
   489  				numData++
   490  				if countPrefix(&inst, PrefixDataSize) > numData {
   491  					if inst.Mode == 16 {
   492  						n = 16
   493  					} else {
   494  						n = 32
   495  					}
   496  				}
   497  				prefix += fmt.Sprintf("data%d ", n)
   498  				continue
   499  			}
   500  			prefix += strings.ToLower(p.String()) + " "
   501  		}
   502  	}
   503  
   504  	// Finally! Put it all together.
   505  	text := prefix + op
   506  	if args != nil {
   507  		text += " "
   508  		// Indirect call/jmp gets a star to distinguish from direct jump address.
   509  		if (inst.Op == CALL || inst.Op == JMP || inst.Op == LJMP || inst.Op == LCALL) && (isMem(inst.Args[0]) || isReg(inst.Args[0])) {
   510  			text += "*"
   511  		}
   512  		text += strings.Join(args, ",")
   513  	}
   514  	return text
   515  }
   516  
   517  // gnuArg returns the GNU syntax for the argument x from the instruction inst.
   518  // If *usedPrefixes is false and x is a Mem, then the formatting
   519  // includes any segment prefixes and sets *usedPrefixes to true.
   520  func gnuArg(inst *Inst, pc uint64, symname SymLookup, x Arg, usedPrefixes *bool) string {
   521  	if x == nil {
   522  		return "<nil>"
   523  	}
   524  	switch x := x.(type) {
   525  	case Reg:
   526  		switch inst.Op {
   527  		case CVTSI2SS, CVTSI2SD, CVTSS2SI, CVTSD2SI, CVTTSD2SI, CVTTSS2SI:
   528  			if inst.DataSize == 16 && EAX <= x && x <= R15L {
   529  				x -= EAX - AX
   530  			}
   531  
   532  		case IN, INSB, INSW, INSD, OUT, OUTSB, OUTSW, OUTSD:
   533  			// DX is the port, but libopcodes prints it as if it were a memory reference.
   534  			if x == DX {
   535  				return "(%dx)"
   536  			}
   537  		case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
   538  			return strings.Replace(gccRegName[x], "xmm", "ymm", -1)
   539  		}
   540  		return gccRegName[x]
   541  	case Mem:
   542  		if s, disp := memArgToSymbol(x, pc, inst.Len, symname); s != "" {
   543  			suffix := ""
   544  			if disp != 0 {
   545  				suffix = fmt.Sprintf("%+d", disp)
   546  			}
   547  			return fmt.Sprintf("%s%s", s, suffix)
   548  		}
   549  		seg := ""
   550  		var haveCS, haveDS, haveES, haveFS, haveGS, haveSS bool
   551  		switch x.Segment {
   552  		case CS:
   553  			haveCS = true
   554  		case DS:
   555  			haveDS = true
   556  		case ES:
   557  			haveES = true
   558  		case FS:
   559  			haveFS = true
   560  		case GS:
   561  			haveGS = true
   562  		case SS:
   563  			haveSS = true
   564  		}
   565  		switch inst.Op {
   566  		case INSB, INSW, INSD, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ:
   567  			// These do not accept segment prefixes, at least in the GNU rendering.
   568  		default:
   569  			if *usedPrefixes {
   570  				break
   571  			}
   572  			for i := len(inst.Prefix) - 1; i >= 0; i-- {
   573  				p := inst.Prefix[i] &^ PrefixIgnored
   574  				if p == 0 {
   575  					continue
   576  				}
   577  				switch p {
   578  				case PrefixCS:
   579  					if !haveCS {
   580  						haveCS = true
   581  						inst.Prefix[i] |= PrefixImplicit
   582  					}
   583  				case PrefixDS:
   584  					if !haveDS {
   585  						haveDS = true
   586  						inst.Prefix[i] |= PrefixImplicit
   587  					}
   588  				case PrefixES:
   589  					if !haveES {
   590  						haveES = true
   591  						inst.Prefix[i] |= PrefixImplicit
   592  					}
   593  				case PrefixFS:
   594  					if !haveFS {
   595  						haveFS = true
   596  						inst.Prefix[i] |= PrefixImplicit
   597  					}
   598  				case PrefixGS:
   599  					if !haveGS {
   600  						haveGS = true
   601  						inst.Prefix[i] |= PrefixImplicit
   602  					}
   603  				case PrefixSS:
   604  					if !haveSS {
   605  						haveSS = true
   606  						inst.Prefix[i] |= PrefixImplicit
   607  					}
   608  				}
   609  			}
   610  			*usedPrefixes = true
   611  		}
   612  		if haveCS {
   613  			seg += "%cs:"
   614  		}
   615  		if haveDS {
   616  			seg += "%ds:"
   617  		}
   618  		if haveSS {
   619  			seg += "%ss:"
   620  		}
   621  		if haveES {
   622  			seg += "%es:"
   623  		}
   624  		if haveFS {
   625  			seg += "%fs:"
   626  		}
   627  		if haveGS {
   628  			seg += "%gs:"
   629  		}
   630  		disp := ""
   631  		if x.Disp != 0 {
   632  			disp = fmt.Sprintf("%#x", x.Disp)
   633  		}
   634  		if x.Scale == 0 || x.Index == 0 && x.Scale == 1 && (x.Base == ESP || x.Base == RSP || x.Base == 0 && inst.Mode == 64) {
   635  			if x.Base == 0 {
   636  				return seg + disp
   637  			}
   638  			return fmt.Sprintf("%s%s(%s)", seg, disp, gccRegName[x.Base])
   639  		}
   640  		base := gccRegName[x.Base]
   641  		if x.Base == 0 {
   642  			base = ""
   643  		}
   644  		index := gccRegName[x.Index]
   645  		if x.Index == 0 {
   646  			if inst.AddrSize == 64 {
   647  				index = "%riz"
   648  			} else {
   649  				index = "%eiz"
   650  			}
   651  		}
   652  		if AX <= x.Base && x.Base <= DI {
   653  			// 16-bit addressing - no scale
   654  			return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
   655  		}
   656  		return fmt.Sprintf("%s%s(%s,%s,%d)", seg, disp, base, index, x.Scale)
   657  	case Rel:
   658  		if pc == 0 {
   659  			return fmt.Sprintf(".%+#x", int64(x))
   660  		} else {
   661  			addr := pc + uint64(inst.Len) + uint64(x)
   662  			if s, base := symname(addr); s != "" && addr == base {
   663  				return fmt.Sprintf("%s", s)
   664  			} else {
   665  				addr := pc + uint64(inst.Len) + uint64(x)
   666  				return fmt.Sprintf("%#x", addr)
   667  			}
   668  		}
   669  	case Imm:
   670  		if (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 { // See comment in plan9x.go.
   671  			if s, base := symname(uint64(x)); s != "" {
   672  				suffix := ""
   673  				if uint64(x) != base {
   674  					suffix = fmt.Sprintf("%+d", uint64(x)-base)
   675  				}
   676  				return fmt.Sprintf("$%s%s", s, suffix)
   677  			}
   678  		}
   679  		if inst.Mode == 32 {
   680  			return fmt.Sprintf("$%#x", uint32(x))
   681  		}
   682  		return fmt.Sprintf("$%#x", int64(x))
   683  	}
   684  	return x.String()
   685  }
   686  
   687  var gccRegName = [...]string{
   688  	0:    "REG0",
   689  	AL:   "%al",
   690  	CL:   "%cl",
   691  	BL:   "%bl",
   692  	DL:   "%dl",
   693  	AH:   "%ah",
   694  	CH:   "%ch",
   695  	BH:   "%bh",
   696  	DH:   "%dh",
   697  	SPB:  "%spl",
   698  	BPB:  "%bpl",
   699  	SIB:  "%sil",
   700  	DIB:  "%dil",
   701  	R8B:  "%r8b",
   702  	R9B:  "%r9b",
   703  	R10B: "%r10b",
   704  	R11B: "%r11b",
   705  	R12B: "%r12b",
   706  	R13B: "%r13b",
   707  	R14B: "%r14b",
   708  	R15B: "%r15b",
   709  	AX:   "%ax",
   710  	CX:   "%cx",
   711  	BX:   "%bx",
   712  	DX:   "%dx",
   713  	SP:   "%sp",
   714  	BP:   "%bp",
   715  	SI:   "%si",
   716  	DI:   "%di",
   717  	R8W:  "%r8w",
   718  	R9W:  "%r9w",
   719  	R10W: "%r10w",
   720  	R11W: "%r11w",
   721  	R12W: "%r12w",
   722  	R13W: "%r13w",
   723  	R14W: "%r14w",
   724  	R15W: "%r15w",
   725  	EAX:  "%eax",
   726  	ECX:  "%ecx",
   727  	EDX:  "%edx",
   728  	EBX:  "%ebx",
   729  	ESP:  "%esp",
   730  	EBP:  "%ebp",
   731  	ESI:  "%esi",
   732  	EDI:  "%edi",
   733  	R8L:  "%r8d",
   734  	R9L:  "%r9d",
   735  	R10L: "%r10d",
   736  	R11L: "%r11d",
   737  	R12L: "%r12d",
   738  	R13L: "%r13d",
   739  	R14L: "%r14d",
   740  	R15L: "%r15d",
   741  	RAX:  "%rax",
   742  	RCX:  "%rcx",
   743  	RDX:  "%rdx",
   744  	RBX:  "%rbx",
   745  	RSP:  "%rsp",
   746  	RBP:  "%rbp",
   747  	RSI:  "%rsi",
   748  	RDI:  "%rdi",
   749  	R8:   "%r8",
   750  	R9:   "%r9",
   751  	R10:  "%r10",
   752  	R11:  "%r11",
   753  	R12:  "%r12",
   754  	R13:  "%r13",
   755  	R14:  "%r14",
   756  	R15:  "%r15",
   757  	IP:   "%ip",
   758  	EIP:  "%eip",
   759  	RIP:  "%rip",
   760  	F0:   "%st",
   761  	F1:   "%st(1)",
   762  	F2:   "%st(2)",
   763  	F3:   "%st(3)",
   764  	F4:   "%st(4)",
   765  	F5:   "%st(5)",
   766  	F6:   "%st(6)",
   767  	F7:   "%st(7)",
   768  	M0:   "%mm0",
   769  	M1:   "%mm1",
   770  	M2:   "%mm2",
   771  	M3:   "%mm3",
   772  	M4:   "%mm4",
   773  	M5:   "%mm5",
   774  	M6:   "%mm6",
   775  	M7:   "%mm7",
   776  	X0:   "%xmm0",
   777  	X1:   "%xmm1",
   778  	X2:   "%xmm2",
   779  	X3:   "%xmm3",
   780  	X4:   "%xmm4",
   781  	X5:   "%xmm5",
   782  	X6:   "%xmm6",
   783  	X7:   "%xmm7",
   784  	X8:   "%xmm8",
   785  	X9:   "%xmm9",
   786  	X10:  "%xmm10",
   787  	X11:  "%xmm11",
   788  	X12:  "%xmm12",
   789  	X13:  "%xmm13",
   790  	X14:  "%xmm14",
   791  	X15:  "%xmm15",
   792  	CS:   "%cs",
   793  	SS:   "%ss",
   794  	DS:   "%ds",
   795  	ES:   "%es",
   796  	FS:   "%fs",
   797  	GS:   "%gs",
   798  	GDTR: "%gdtr",
   799  	IDTR: "%idtr",
   800  	LDTR: "%ldtr",
   801  	MSW:  "%msw",
   802  	TASK: "%task",
   803  	CR0:  "%cr0",
   804  	CR1:  "%cr1",
   805  	CR2:  "%cr2",
   806  	CR3:  "%cr3",
   807  	CR4:  "%cr4",
   808  	CR5:  "%cr5",
   809  	CR6:  "%cr6",
   810  	CR7:  "%cr7",
   811  	CR8:  "%cr8",
   812  	CR9:  "%cr9",
   813  	CR10: "%cr10",
   814  	CR11: "%cr11",
   815  	CR12: "%cr12",
   816  	CR13: "%cr13",
   817  	CR14: "%cr14",
   818  	CR15: "%cr15",
   819  	DR0:  "%db0",
   820  	DR1:  "%db1",
   821  	DR2:  "%db2",
   822  	DR3:  "%db3",
   823  	DR4:  "%db4",
   824  	DR5:  "%db5",
   825  	DR6:  "%db6",
   826  	DR7:  "%db7",
   827  	TR0:  "%tr0",
   828  	TR1:  "%tr1",
   829  	TR2:  "%tr2",
   830  	TR3:  "%tr3",
   831  	TR4:  "%tr4",
   832  	TR5:  "%tr5",
   833  	TR6:  "%tr6",
   834  	TR7:  "%tr7",
   835  }
   836  
   837  var gnuOp = map[Op]string{
   838  	CBW:       "cbtw",
   839  	CDQ:       "cltd",
   840  	CMPSD:     "cmpsl",
   841  	CMPSD_XMM: "cmpsd",
   842  	CWD:       "cwtd",
   843  	CWDE:      "cwtl",
   844  	CQO:       "cqto",
   845  	INSD:      "insl",
   846  	IRET:      "iretw",
   847  	IRETD:     "iret",
   848  	IRETQ:     "iretq",
   849  	LODSB:     "lods",
   850  	LODSD:     "lods",
   851  	LODSQ:     "lods",
   852  	LODSW:     "lods",
   853  	MOVSD:     "movsl",
   854  	MOVSD_XMM: "movsd",
   855  	OUTSD:     "outsl",
   856  	POPA:      "popaw",
   857  	POPAD:     "popa",
   858  	POPF:      "popfw",
   859  	POPFD:     "popf",
   860  	PUSHA:     "pushaw",
   861  	PUSHAD:    "pusha",
   862  	PUSHF:     "pushfw",
   863  	PUSHFD:    "pushf",
   864  	SCASB:     "scas",
   865  	SCASD:     "scas",
   866  	SCASQ:     "scas",
   867  	SCASW:     "scas",
   868  	STOSB:     "stos",
   869  	STOSD:     "stos",
   870  	STOSQ:     "stos",
   871  	STOSW:     "stos",
   872  	XLATB:     "xlat",
   873  }
   874  
   875  var cmppsOps = []string{
   876  	"cmpeq",
   877  	"cmplt",
   878  	"cmple",
   879  	"cmpunord",
   880  	"cmpneq",
   881  	"cmpnlt",
   882  	"cmpnle",
   883  	"cmpord",
   884  }
   885  
   886  var pclmulqOps = []string{
   887  	"pclmullqlqdq",
   888  	"pclmulhqlqdq",
   889  	"pclmullqhqdq",
   890  	"pclmulhqhqdq",
   891  }
   892  
   893  func countPrefix(inst *Inst, target Prefix) int {
   894  	n := 0
   895  	for _, p := range inst.Prefix {
   896  		if p&0xFF == target&0xFF {
   897  			n++
   898  		}
   899  	}
   900  	return n
   901  }
   902  
   903  func markLastImplicit(inst *Inst, prefix Prefix) bool {
   904  	for i := len(inst.Prefix) - 1; i >= 0; i-- {
   905  		p := inst.Prefix[i]
   906  		if p&0xFF == prefix {
   907  			inst.Prefix[i] |= PrefixImplicit
   908  			return true
   909  		}
   910  	}
   911  	return false
   912  }
   913  
   914  func unmarkImplicit(inst *Inst, prefix Prefix) {
   915  	for i := len(inst.Prefix) - 1; i >= 0; i-- {
   916  		p := inst.Prefix[i]
   917  		if p&0xFF == prefix {
   918  			inst.Prefix[i] &^= PrefixImplicit
   919  		}
   920  	}
   921  }
   922  
   923  func byteSizeSuffix(b int) string {
   924  	switch b {
   925  	case 1:
   926  		return "b"
   927  	case 2:
   928  		return "w"
   929  	case 4:
   930  		return "l"
   931  	case 8:
   932  		return "q"
   933  	}
   934  	return ""
   935  }
   936  
   937  func argBytes(inst *Inst, arg Arg) int {
   938  	if isMem(arg) {
   939  		return inst.MemBytes
   940  	}
   941  	return regBytes(arg)
   942  }
   943  
   944  func isFloat(op Op) bool {
   945  	switch op {
   946  	case FADD, FCOM, FCOMP, FDIV, FDIVR, FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR, FLD, FMUL, FST, FSTP, FSUB, FSUBR:
   947  		return true
   948  	}
   949  	return false
   950  }
   951  
   952  func isFloatInt(op Op) bool {
   953  	switch op {
   954  	case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR:
   955  		return true
   956  	}
   957  	return false
   958  }
   959  

View as plain text