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