...

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

Documentation: cmd/vendor/golang.org/x/arch/x86/x86asm

     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 s, base := symname(uint64(x)); s != "" {
   671  			suffix := ""
   672  			if uint64(x) != base {
   673  				suffix = fmt.Sprintf("%+d", uint64(x)-base)
   674  			}
   675  			return fmt.Sprintf("$%s%s", s, suffix)
   676  		}
   677  		if inst.Mode == 32 {
   678  			return fmt.Sprintf("$%#x", uint32(x))
   679  		}
   680  		return fmt.Sprintf("$%#x", int64(x))
   681  	}
   682  	return x.String()
   683  }
   684  
   685  var gccRegName = [...]string{
   686  	0:    "REG0",
   687  	AL:   "%al",
   688  	CL:   "%cl",
   689  	BL:   "%bl",
   690  	DL:   "%dl",
   691  	AH:   "%ah",
   692  	CH:   "%ch",
   693  	BH:   "%bh",
   694  	DH:   "%dh",
   695  	SPB:  "%spl",
   696  	BPB:  "%bpl",
   697  	SIB:  "%sil",
   698  	DIB:  "%dil",
   699  	R8B:  "%r8b",
   700  	R9B:  "%r9b",
   701  	R10B: "%r10b",
   702  	R11B: "%r11b",
   703  	R12B: "%r12b",
   704  	R13B: "%r13b",
   705  	R14B: "%r14b",
   706  	R15B: "%r15b",
   707  	AX:   "%ax",
   708  	CX:   "%cx",
   709  	BX:   "%bx",
   710  	DX:   "%dx",
   711  	SP:   "%sp",
   712  	BP:   "%bp",
   713  	SI:   "%si",
   714  	DI:   "%di",
   715  	R8W:  "%r8w",
   716  	R9W:  "%r9w",
   717  	R10W: "%r10w",
   718  	R11W: "%r11w",
   719  	R12W: "%r12w",
   720  	R13W: "%r13w",
   721  	R14W: "%r14w",
   722  	R15W: "%r15w",
   723  	EAX:  "%eax",
   724  	ECX:  "%ecx",
   725  	EDX:  "%edx",
   726  	EBX:  "%ebx",
   727  	ESP:  "%esp",
   728  	EBP:  "%ebp",
   729  	ESI:  "%esi",
   730  	EDI:  "%edi",
   731  	R8L:  "%r8d",
   732  	R9L:  "%r9d",
   733  	R10L: "%r10d",
   734  	R11L: "%r11d",
   735  	R12L: "%r12d",
   736  	R13L: "%r13d",
   737  	R14L: "%r14d",
   738  	R15L: "%r15d",
   739  	RAX:  "%rax",
   740  	RCX:  "%rcx",
   741  	RDX:  "%rdx",
   742  	RBX:  "%rbx",
   743  	RSP:  "%rsp",
   744  	RBP:  "%rbp",
   745  	RSI:  "%rsi",
   746  	RDI:  "%rdi",
   747  	R8:   "%r8",
   748  	R9:   "%r9",
   749  	R10:  "%r10",
   750  	R11:  "%r11",
   751  	R12:  "%r12",
   752  	R13:  "%r13",
   753  	R14:  "%r14",
   754  	R15:  "%r15",
   755  	IP:   "%ip",
   756  	EIP:  "%eip",
   757  	RIP:  "%rip",
   758  	F0:   "%st",
   759  	F1:   "%st(1)",
   760  	F2:   "%st(2)",
   761  	F3:   "%st(3)",
   762  	F4:   "%st(4)",
   763  	F5:   "%st(5)",
   764  	F6:   "%st(6)",
   765  	F7:   "%st(7)",
   766  	M0:   "%mm0",
   767  	M1:   "%mm1",
   768  	M2:   "%mm2",
   769  	M3:   "%mm3",
   770  	M4:   "%mm4",
   771  	M5:   "%mm5",
   772  	M6:   "%mm6",
   773  	M7:   "%mm7",
   774  	X0:   "%xmm0",
   775  	X1:   "%xmm1",
   776  	X2:   "%xmm2",
   777  	X3:   "%xmm3",
   778  	X4:   "%xmm4",
   779  	X5:   "%xmm5",
   780  	X6:   "%xmm6",
   781  	X7:   "%xmm7",
   782  	X8:   "%xmm8",
   783  	X9:   "%xmm9",
   784  	X10:  "%xmm10",
   785  	X11:  "%xmm11",
   786  	X12:  "%xmm12",
   787  	X13:  "%xmm13",
   788  	X14:  "%xmm14",
   789  	X15:  "%xmm15",
   790  	CS:   "%cs",
   791  	SS:   "%ss",
   792  	DS:   "%ds",
   793  	ES:   "%es",
   794  	FS:   "%fs",
   795  	GS:   "%gs",
   796  	GDTR: "%gdtr",
   797  	IDTR: "%idtr",
   798  	LDTR: "%ldtr",
   799  	MSW:  "%msw",
   800  	TASK: "%task",
   801  	CR0:  "%cr0",
   802  	CR1:  "%cr1",
   803  	CR2:  "%cr2",
   804  	CR3:  "%cr3",
   805  	CR4:  "%cr4",
   806  	CR5:  "%cr5",
   807  	CR6:  "%cr6",
   808  	CR7:  "%cr7",
   809  	CR8:  "%cr8",
   810  	CR9:  "%cr9",
   811  	CR10: "%cr10",
   812  	CR11: "%cr11",
   813  	CR12: "%cr12",
   814  	CR13: "%cr13",
   815  	CR14: "%cr14",
   816  	CR15: "%cr15",
   817  	DR0:  "%db0",
   818  	DR1:  "%db1",
   819  	DR2:  "%db2",
   820  	DR3:  "%db3",
   821  	DR4:  "%db4",
   822  	DR5:  "%db5",
   823  	DR6:  "%db6",
   824  	DR7:  "%db7",
   825  	TR0:  "%tr0",
   826  	TR1:  "%tr1",
   827  	TR2:  "%tr2",
   828  	TR3:  "%tr3",
   829  	TR4:  "%tr4",
   830  	TR5:  "%tr5",
   831  	TR6:  "%tr6",
   832  	TR7:  "%tr7",
   833  }
   834  
   835  var gnuOp = map[Op]string{
   836  	CBW:       "cbtw",
   837  	CDQ:       "cltd",
   838  	CMPSD:     "cmpsl",
   839  	CMPSD_XMM: "cmpsd",
   840  	CWD:       "cwtd",
   841  	CWDE:      "cwtl",
   842  	CQO:       "cqto",
   843  	INSD:      "insl",
   844  	IRET:      "iretw",
   845  	IRETD:     "iret",
   846  	IRETQ:     "iretq",
   847  	LODSB:     "lods",
   848  	LODSD:     "lods",
   849  	LODSQ:     "lods",
   850  	LODSW:     "lods",
   851  	MOVSD:     "movsl",
   852  	MOVSD_XMM: "movsd",
   853  	OUTSD:     "outsl",
   854  	POPA:      "popaw",
   855  	POPAD:     "popa",
   856  	POPF:      "popfw",
   857  	POPFD:     "popf",
   858  	PUSHA:     "pushaw",
   859  	PUSHAD:    "pusha",
   860  	PUSHF:     "pushfw",
   861  	PUSHFD:    "pushf",
   862  	SCASB:     "scas",
   863  	SCASD:     "scas",
   864  	SCASQ:     "scas",
   865  	SCASW:     "scas",
   866  	STOSB:     "stos",
   867  	STOSD:     "stos",
   868  	STOSQ:     "stos",
   869  	STOSW:     "stos",
   870  	XLATB:     "xlat",
   871  }
   872  
   873  var cmppsOps = []string{
   874  	"cmpeq",
   875  	"cmplt",
   876  	"cmple",
   877  	"cmpunord",
   878  	"cmpneq",
   879  	"cmpnlt",
   880  	"cmpnle",
   881  	"cmpord",
   882  }
   883  
   884  var pclmulqOps = []string{
   885  	"pclmullqlqdq",
   886  	"pclmulhqlqdq",
   887  	"pclmullqhqdq",
   888  	"pclmulhqhqdq",
   889  }
   890  
   891  func countPrefix(inst *Inst, target Prefix) int {
   892  	n := 0
   893  	for _, p := range inst.Prefix {
   894  		if p&0xFF == target&0xFF {
   895  			n++
   896  		}
   897  	}
   898  	return n
   899  }
   900  
   901  func markLastImplicit(inst *Inst, prefix Prefix) bool {
   902  	for i := len(inst.Prefix) - 1; i >= 0; i-- {
   903  		p := inst.Prefix[i]
   904  		if p&0xFF == prefix {
   905  			inst.Prefix[i] |= PrefixImplicit
   906  			return true
   907  		}
   908  	}
   909  	return false
   910  }
   911  
   912  func unmarkImplicit(inst *Inst, prefix Prefix) {
   913  	for i := len(inst.Prefix) - 1; i >= 0; i-- {
   914  		p := inst.Prefix[i]
   915  		if p&0xFF == prefix {
   916  			inst.Prefix[i] &^= PrefixImplicit
   917  		}
   918  	}
   919  }
   920  
   921  func byteSizeSuffix(b int) string {
   922  	switch b {
   923  	case 1:
   924  		return "b"
   925  	case 2:
   926  		return "w"
   927  	case 4:
   928  		return "l"
   929  	case 8:
   930  		return "q"
   931  	}
   932  	return ""
   933  }
   934  
   935  func argBytes(inst *Inst, arg Arg) int {
   936  	if isMem(arg) {
   937  		return inst.MemBytes
   938  	}
   939  	return regBytes(arg)
   940  }
   941  
   942  func isFloat(op Op) bool {
   943  	switch op {
   944  	case FADD, FCOM, FCOMP, FDIV, FDIVR, FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR, FLD, FMUL, FST, FSTP, FSUB, FSUBR:
   945  		return true
   946  	}
   947  	return false
   948  }
   949  
   950  func isFloatInt(op Op) bool {
   951  	switch op {
   952  	case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR:
   953  		return true
   954  	}
   955  	return false
   956  }
   957  

View as plain text