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 <= Z31 || M0 <= a && a <= M7 || K0 <= a && a <= K7 {
   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, VLDMXCSR, VSTMXCSR:
   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  	isVexOrEvex := false
   358  	for _, p := range inst.Prefix {
   359  		if p.IsVEX() || p&0xFF == 0x62 {
   360  			isVexOrEvex = true
   361  			break
   362  		}
   363  	}
   364  	if isVexOrEvex {
   365  		hasMem := false
   366  		for _, a := range inst.Args {
   367  			if _, ok := a.(Mem); ok {
   368  				hasMem = true
   369  				break
   370  			}
   371  		}
   372  		if hasMem {
   373  			if inst.Op == VFPCLASSPD || inst.Op == VFPCLASSPS || inst.Op == VCVTTPD2DQ || inst.Op == VCVTTPD2UDQ || inst.Op == VCVTTPD2QQ || inst.Op == VCVTTPD2UQQ || inst.Op == VCVTPD2DQ || inst.Op == VCVTPD2UDQ || inst.Op == VCVTPD2QQ || inst.Op == VCVTPD2UQQ || inst.Op == VCVTPD2PS {
   374  				vexL := 0
   375  				isEvex := false
   376  				for i, p := range inst.Prefix {
   377  					if p.IsEVEX() && i+3 < len(inst.Prefix) && inst.Prefix[i+3] != 0 {
   378  						vexL = int((inst.Prefix[i+3]&0xFF)>>5) & 3
   379  						isEvex = true
   380  						break
   381  					} else if p.IsVEX() && i+2 < len(inst.Prefix) {
   382  						if p&0xFF == 0xC4 {
   383  							vexL = int((inst.Prefix[i+2]&0xFF)>>2) & 1
   384  						} else if p&0xFF == 0xC5 {
   385  							vexL = int((inst.Prefix[i+1]&0xFF)>>2) & 1
   386  						}
   387  						break
   388  					}
   389  				}
   390  				if !isEvex || inst.Op == VFPCLASSPD || inst.Op == VFPCLASSPS || inst.Op == VCVTPD2DQ {
   391  					switch vexL {
   392  					case 0:
   393  						op += "x"
   394  					case 1:
   395  						if inst.Op != VCMPPD && inst.Op != VCMPPS && inst.Op != VCMPPH && inst.Op != VCMPBF16 {
   396  							op += "y"
   397  						}
   398  					case 2:
   399  						if inst.Op != VCMPPD && inst.Op != VCMPPS && inst.Op != VCMPPH && inst.Op != VCMPBF16 {
   400  							op += "z"
   401  						}
   402  					}
   403  				}
   404  			} else if inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS {
   405  				is64 := false
   406  				if (inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS) && inst.MemBytes == 8 {
   407  					is64 = true
   408  				} else {
   409  					for _, a := range inst.Args {
   410  						if r, ok := a.(Reg); ok && RAX <= r && r <= R15 {
   411  							is64 = true
   412  							break
   413  						}
   414  					}
   415  				}
   416  				if is64 {
   417  					op += "q"
   418  				} else {
   419  					op += "l"
   420  				}
   421  			}
   422  		}
   423  	}
   424  
   425  	// Adjust special case opcodes.
   426  	switch inst.Op {
   427  	case 0:
   428  		if inst.Prefix[0] != 0 {
   429  			return strings.ToLower(inst.Prefix[0].String())
   430  		}
   431  
   432  	case INT:
   433  		if inst.Opcode>>24 == 0xCC {
   434  			inst.Args[0] = nil
   435  			op = "int3"
   436  		}
   437  
   438  	case CMPPS, CMPPD, CMPSD_XMM, CMPSS:
   439  		imm, ok := inst.Args[2].(Imm)
   440  		if ok && 0 <= imm && imm < 8 {
   441  			inst.Args[2] = nil
   442  			op = cmppsOps[imm] + op[3:]
   443  		}
   444  
   445  	case VCMPPD, VCMPPS, VCMPSD, VCMPSS, VCMPPH, VCMPSH, VCMPBF16:
   446  		for i := len(inst.Args) - 1; i >= 0; i-- {
   447  			if imm, ok := inst.Args[i].(Imm); ok {
   448  				if 0 <= imm && imm < 8 {
   449  					inst.Args[i] = nil
   450  					op = "v" + cmppsOps[imm] + op[4:]
   451  				}
   452  				break
   453  			}
   454  			if inst.Args[i] != nil {
   455  				break
   456  			}
   457  		}
   458  
   459  	case PCLMULQDQ:
   460  		imm, ok := inst.Args[2].(Imm)
   461  		if ok && imm&^0x11 == 0 {
   462  			inst.Args[2] = nil
   463  			op = pclmulqOps[(imm&0x10)>>3|(imm&1)]
   464  		}
   465  
   466  	case XLATB:
   467  		if markLastImplicit(&inst, PrefixAddrSize) {
   468  			op = "xlat" // not xlatb
   469  		}
   470  	}
   471  
   472  	// Build list of argument strings.
   473  	var (
   474  		usedPrefixes bool     // segment prefixes consumed by Mem formatting
   475  		args         []string // formatted arguments
   476  	)
   477  	for i, a := range inst.Args {
   478  		if a == nil {
   479  			break
   480  		}
   481  		switch inst.Op {
   482  		case MOVSB, MOVSW, MOVSD, MOVSQ, OUTSB, OUTSW, OUTSD:
   483  			if i == 0 {
   484  				usedPrefixes = true // disable use of prefixes for first argument
   485  			} else {
   486  				usedPrefixes = false
   487  			}
   488  		}
   489  		if a == Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 {
   490  			continue
   491  		}
   492  		argStr := gnuArg(&inst, pc, symname, a, &usedPrefixes)
   493  		if i == 1 {
   494  			r, ok := a.(Reg)
   495  			// In GNU syntax, the mask register usually appears as the second argument (index 1).
   496  			if ok && K1 <= r && r <= K7 {
   497  				if !strings.HasPrefix(inst.Op.String(), "K") {
   498  					if len(args) > 0 {
   499  						args[0] += fmt.Sprintf(" {%s}", argStr)
   500  						if inst.Zeroing {
   501  							args[0] += " {z}"
   502  						}
   503  					}
   504  					continue
   505  				}
   506  			} else if ok && r == K0 {
   507  				if !strings.HasPrefix(inst.Op.String(), "K") {
   508  					if inst.Zeroing && len(args) > 0 {
   509  						args[0] += "{z}"
   510  					}
   511  					continue
   512  				}
   513  			}
   514  		}
   515  		if _, ok := a.(Mem); ok && inst.Broadcast && len(args) > 0 {
   516  			if dstReg, ok := inst.Args[0].(Reg); ok {
   517  				var vBytes int
   518  				if X0 <= dstReg && dstReg <= X31 {
   519  					vBytes = 16
   520  				} else if Y0 <= dstReg && dstReg <= Y31 {
   521  					vBytes = 32
   522  				} else if Z0 <= dstReg && dstReg <= Z31 {
   523  					vBytes = 64
   524  				}
   525  				if vBytes > 0 && inst.MemBytes > 0 {
   526  					argStr += fmt.Sprintf("{1to%d}", vBytes/inst.MemBytes)
   527  				}
   528  			}
   529  		}
   530  		args = append(args, argStr)
   531  	}
   532  
   533  	if inst.SAE {
   534  		var sae string
   535  		if hasRC(inst.Op) {
   536  			switch inst.Rounding {
   537  			case 0:
   538  				sae = "{rn-sae}"
   539  			case 1:
   540  				sae = "{rd-sae}"
   541  			case 2:
   542  				sae = "{ru-sae}"
   543  			case 3:
   544  				sae = "{rz-sae}"
   545  			}
   546  		} else {
   547  			sae = "{sae}"
   548  		}
   549  		args = append(args, sae)
   550  	}
   551  
   552  	// The default is to print the arguments in reverse Intel order.
   553  	// A few instructions inhibit this behavior.
   554  	switch inst.Op {
   555  	case BOUND, LCALL, ENTER, LJMP:
   556  		// no reverse
   557  	default:
   558  		// reverse args
   559  		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   560  			args[i], args[j] = args[j], args[i]
   561  		}
   562  	}
   563  
   564  	// Build prefix string.
   565  	// Must be after argument formatting, which can turn off segment prefixes.
   566  	var (
   567  		prefix       = "" // output string
   568  		numAddr      = 0
   569  		numData      = 0
   570  		implicitData = false
   571  	)
   572  	for _, p := range inst.Prefix {
   573  		if p&0xFF == PrefixDataSize && p&PrefixImplicit != 0 {
   574  			implicitData = true
   575  		}
   576  	}
   577  	for _, p := range inst.Prefix {
   578  		if p == 0 || p.IsVEX() || p.IsEVEX() {
   579  			break
   580  		}
   581  		if p&PrefixImplicit != 0 {
   582  			continue
   583  		}
   584  		switch p &^ (PrefixIgnored | PrefixInvalid) {
   585  		default:
   586  			if p.IsREX() {
   587  				if p&0xFF == PrefixREX {
   588  					prefix += "rex "
   589  				} else {
   590  					prefix += "rex." + p.String()[4:] + " "
   591  				}
   592  				break
   593  			}
   594  			prefix += strings.ToLower(p.String()) + " "
   595  
   596  		case PrefixPN:
   597  			op += ",pn"
   598  			continue
   599  
   600  		case PrefixPT:
   601  			op += ",pt"
   602  			continue
   603  
   604  		case PrefixAddrSize, PrefixAddr16, PrefixAddr32:
   605  			// For unknown reasons, if the addr16 prefix is repeated,
   606  			// libopcodes displays all but the last as addr32, even though
   607  			// the addressing form used in a memory reference is clearly
   608  			// still 16-bit.
   609  			n := 32
   610  			if inst.Mode == 32 {
   611  				n = 16
   612  			}
   613  			numAddr++
   614  			if countPrefix(&inst, PrefixAddrSize) > numAddr {
   615  				n = inst.Mode
   616  			}
   617  			prefix += fmt.Sprintf("addr%d ", n)
   618  			continue
   619  
   620  		case PrefixData16, PrefixData32:
   621  			if implicitData && countPrefix(&inst, PrefixDataSize) > 1 {
   622  				// Similar to the addr32 logic above, but it only kicks in
   623  				// when something used the data size prefix (one is implicit).
   624  				n := 16
   625  				if inst.Mode == 16 {
   626  					n = 32
   627  				}
   628  				numData++
   629  				if countPrefix(&inst, PrefixDataSize) > numData {
   630  					if inst.Mode == 16 {
   631  						n = 16
   632  					} else {
   633  						n = 32
   634  					}
   635  				}
   636  				prefix += fmt.Sprintf("data%d ", n)
   637  				continue
   638  			}
   639  			prefix += strings.ToLower(p.String()) + " "
   640  		}
   641  	}
   642  
   643  	// Finally! Put it all together.
   644  	text := prefix + op
   645  	if args != nil {
   646  		text += " "
   647  		// Indirect call/jmp gets a star to distinguish from direct jump address.
   648  		if (inst.Op == CALL || inst.Op == JMP || inst.Op == LJMP || inst.Op == LCALL) && (isMem(inst.Args[0]) || isReg(inst.Args[0])) {
   649  			text += "*"
   650  		}
   651  		text += strings.Join(args, ",")
   652  	}
   653  	return text
   654  }
   655  
   656  // gnuArg returns the GNU syntax for the argument x from the instruction inst.
   657  // If *usedPrefixes is false and x is a Mem, then the formatting
   658  // includes any segment prefixes and sets *usedPrefixes to true.
   659  func gnuArg(inst *Inst, pc uint64, symname SymLookup, x Arg, usedPrefixes *bool) string {
   660  	if x == nil {
   661  		return "<nil>"
   662  	}
   663  	switch x := x.(type) {
   664  	case Reg:
   665  		switch inst.Op {
   666  		case CVTSI2SS, CVTSI2SD, CVTSS2SI, CVTSD2SI, CVTTSD2SI, CVTTSS2SI:
   667  			if inst.DataSize == 16 && EAX <= x && x <= R15L {
   668  				x -= EAX - AX
   669  			}
   670  
   671  		case IN, INSB, INSW, INSD, OUT, OUTSB, OUTSW, OUTSD:
   672  			// DX is the port, but libopcodes prints it as if it were a memory reference.
   673  			if x == DX {
   674  				return "(%dx)"
   675  			}
   676  		}
   677  		return gccRegName[x]
   678  	case Mem:
   679  		if s, disp := memArgToSymbol(x, pc, inst.Len, symname); s != "" {
   680  			suffix := ""
   681  			if disp != 0 {
   682  				suffix = fmt.Sprintf("%+d", disp)
   683  			}
   684  			return fmt.Sprintf("%s%s", s, suffix)
   685  		}
   686  		seg := ""
   687  		var haveCS, haveDS, haveES, haveFS, haveGS, haveSS bool
   688  		switch x.Segment {
   689  		case CS:
   690  			haveCS = true
   691  		case DS:
   692  			haveDS = true
   693  		case ES:
   694  			haveES = true
   695  		case FS:
   696  			haveFS = true
   697  		case GS:
   698  			haveGS = true
   699  		case SS:
   700  			haveSS = true
   701  		}
   702  		switch inst.Op {
   703  		case INSB, INSW, INSD, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ:
   704  			// These do not accept segment prefixes, at least in the GNU rendering.
   705  		default:
   706  			if isVSIB(inst.Op) {
   707  				haveCS, haveDS, haveES, haveSS = false, false, false, false
   708  				break
   709  			}
   710  			if *usedPrefixes {
   711  				break
   712  			}
   713  			for i := len(inst.Prefix) - 1; i >= 0; i-- {
   714  				p := inst.Prefix[i] &^ PrefixIgnored
   715  				if p == 0 {
   716  					continue
   717  				}
   718  				switch p {
   719  				case PrefixCS:
   720  					if !haveCS {
   721  						haveCS = true
   722  						inst.Prefix[i] |= PrefixImplicit
   723  					}
   724  				case PrefixDS:
   725  					if !haveDS {
   726  						haveDS = true
   727  						inst.Prefix[i] |= PrefixImplicit
   728  					}
   729  				case PrefixES:
   730  					if !haveES {
   731  						haveES = true
   732  						inst.Prefix[i] |= PrefixImplicit
   733  					}
   734  				case PrefixFS:
   735  					if !haveFS {
   736  						haveFS = true
   737  						inst.Prefix[i] |= PrefixImplicit
   738  					}
   739  				case PrefixGS:
   740  					if !haveGS {
   741  						haveGS = true
   742  						inst.Prefix[i] |= PrefixImplicit
   743  					}
   744  				case PrefixSS:
   745  					if !haveSS {
   746  						haveSS = true
   747  						inst.Prefix[i] |= PrefixImplicit
   748  					}
   749  				}
   750  			}
   751  			*usedPrefixes = true
   752  		}
   753  		if haveCS {
   754  			seg += "%cs:"
   755  		}
   756  		if haveDS {
   757  			seg += "%ds:"
   758  		}
   759  		if haveSS {
   760  			seg += "%ss:"
   761  		}
   762  		if haveES {
   763  			seg += "%es:"
   764  		}
   765  		if haveFS {
   766  			seg += "%fs:"
   767  		}
   768  		if haveGS {
   769  			seg += "%gs:"
   770  		}
   771  		disp := ""
   772  		if x.Disp != 0 {
   773  			disp = fmt.Sprintf("%#x", x.Disp)
   774  		}
   775  		if x.Scale == 0 || x.Index == 0 && x.Scale == 1 && (x.Base == ESP || x.Base == RSP || x.Base == 0 && inst.Mode == 64) {
   776  			if x.Base == 0 {
   777  				return seg + disp
   778  			}
   779  			return fmt.Sprintf("%s%s(%s)", seg, disp, gccRegName[x.Base])
   780  		}
   781  		base := gccRegName[x.Base]
   782  		if x.Base == 0 {
   783  			base = ""
   784  		}
   785  		index := gccRegName[x.Index]
   786  		if x.Index == 0 {
   787  			if inst.AddrSize == 64 {
   788  				index = "%riz"
   789  			} else {
   790  				index = "%eiz"
   791  			}
   792  		}
   793  		if AX <= x.Base && x.Base <= DI {
   794  			// 16-bit addressing - no scale
   795  			return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
   796  		}
   797  		if x.Scale == 1 {
   798  			// Special case to match objdump output for explicit scale 1.
   799  			// XXX is this the only one?
   800  			if inst.Op.String() == "VMOVNTDQA" {
   801  				return fmt.Sprintf("%s%s(%s,%s,1)", seg, disp, base, index)
   802  			}
   803  			return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
   804  		}
   805  		return fmt.Sprintf("%s%s(%s,%s,%d)", seg, disp, base, index, x.Scale)
   806  	case Rel:
   807  		if pc == 0 {
   808  			return fmt.Sprintf(".%+#x", int64(x))
   809  		} else {
   810  			addr := pc + uint64(inst.Len) + uint64(x)
   811  			if s, base := symname(addr); s != "" && addr == base {
   812  				return fmt.Sprintf("%s", s)
   813  			} else {
   814  				addr := pc + uint64(inst.Len) + uint64(x)
   815  				return fmt.Sprintf("%#x", addr)
   816  			}
   817  		}
   818  	case Imm:
   819  		if (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 { // See comment in plan9x.go.
   820  			if s, base := symname(uint64(x)); s != "" {
   821  				suffix := ""
   822  				if uint64(x) != base {
   823  					suffix = fmt.Sprintf("%+d", uint64(x)-base)
   824  				}
   825  				return fmt.Sprintf("$%s%s", s, suffix)
   826  			}
   827  		}
   828  		if inst.Mode == 32 {
   829  			return fmt.Sprintf("$%#x", uint32(x))
   830  		}
   831  		return fmt.Sprintf("$%#x", int64(x))
   832  	}
   833  	return x.String()
   834  }
   835  
   836  var gccRegName = [...]string{
   837  	0:    "REG0",
   838  	AL:   "%al",
   839  	CL:   "%cl",
   840  	BL:   "%bl",
   841  	DL:   "%dl",
   842  	AH:   "%ah",
   843  	CH:   "%ch",
   844  	BH:   "%bh",
   845  	DH:   "%dh",
   846  	SPB:  "%spl",
   847  	BPB:  "%bpl",
   848  	SIB:  "%sil",
   849  	DIB:  "%dil",
   850  	R8B:  "%r8b",
   851  	R9B:  "%r9b",
   852  	R10B: "%r10b",
   853  	R11B: "%r11b",
   854  	R12B: "%r12b",
   855  	R13B: "%r13b",
   856  	R14B: "%r14b",
   857  	R15B: "%r15b",
   858  	AX:   "%ax",
   859  	CX:   "%cx",
   860  	BX:   "%bx",
   861  	DX:   "%dx",
   862  	SP:   "%sp",
   863  	BP:   "%bp",
   864  	SI:   "%si",
   865  	DI:   "%di",
   866  	R8W:  "%r8w",
   867  	R9W:  "%r9w",
   868  	R10W: "%r10w",
   869  	R11W: "%r11w",
   870  	R12W: "%r12w",
   871  	R13W: "%r13w",
   872  	R14W: "%r14w",
   873  	R15W: "%r15w",
   874  	EAX:  "%eax",
   875  	ECX:  "%ecx",
   876  	EDX:  "%edx",
   877  	EBX:  "%ebx",
   878  	ESP:  "%esp",
   879  	EBP:  "%ebp",
   880  	ESI:  "%esi",
   881  	EDI:  "%edi",
   882  	R8L:  "%r8d",
   883  	R9L:  "%r9d",
   884  	R10L: "%r10d",
   885  	R11L: "%r11d",
   886  	R12L: "%r12d",
   887  	R13L: "%r13d",
   888  	R14L: "%r14d",
   889  	R15L: "%r15d",
   890  	RAX:  "%rax",
   891  	RCX:  "%rcx",
   892  	RDX:  "%rdx",
   893  	RBX:  "%rbx",
   894  	RSP:  "%rsp",
   895  	RBP:  "%rbp",
   896  	RSI:  "%rsi",
   897  	RDI:  "%rdi",
   898  	R8:   "%r8",
   899  	R9:   "%r9",
   900  	R10:  "%r10",
   901  	R11:  "%r11",
   902  	R12:  "%r12",
   903  	R13:  "%r13",
   904  	R14:  "%r14",
   905  	R15:  "%r15",
   906  	IP:   "%ip",
   907  	EIP:  "%eip",
   908  	RIP:  "%rip",
   909  	F0:   "%st",
   910  	F1:   "%st(1)",
   911  	F2:   "%st(2)",
   912  	F3:   "%st(3)",
   913  	F4:   "%st(4)",
   914  	F5:   "%st(5)",
   915  	F6:   "%st(6)",
   916  	F7:   "%st(7)",
   917  	M0:   "%mm0",
   918  	M1:   "%mm1",
   919  	M2:   "%mm2",
   920  	M3:   "%mm3",
   921  	M4:   "%mm4",
   922  	M5:   "%mm5",
   923  	M6:   "%mm6",
   924  	M7:   "%mm7",
   925  	X0:   "%xmm0",
   926  	X1:   "%xmm1",
   927  	X2:   "%xmm2",
   928  	X3:   "%xmm3",
   929  	X4:   "%xmm4",
   930  	X5:   "%xmm5",
   931  	X6:   "%xmm6",
   932  	X7:   "%xmm7",
   933  	X8:   "%xmm8",
   934  	X9:   "%xmm9",
   935  	X10:  "%xmm10",
   936  	X11:  "%xmm11",
   937  	X12:  "%xmm12",
   938  	X13:  "%xmm13",
   939  	X14:  "%xmm14",
   940  	X15:  "%xmm15",
   941  	X16:  "%xmm16",
   942  	X17:  "%xmm17",
   943  	X18:  "%xmm18",
   944  	X19:  "%xmm19",
   945  	X20:  "%xmm20",
   946  	X21:  "%xmm21",
   947  	X22:  "%xmm22",
   948  	X23:  "%xmm23",
   949  	X24:  "%xmm24",
   950  	X25:  "%xmm25",
   951  	X26:  "%xmm26",
   952  	X27:  "%xmm27",
   953  	X28:  "%xmm28",
   954  	X29:  "%xmm29",
   955  	X30:  "%xmm30",
   956  	X31:  "%xmm31",
   957  	Y0:   "%ymm0",
   958  	Y1:   "%ymm1",
   959  	Y2:   "%ymm2",
   960  	Y3:   "%ymm3",
   961  	Y4:   "%ymm4",
   962  	Y5:   "%ymm5",
   963  	Y6:   "%ymm6",
   964  	Y7:   "%ymm7",
   965  	Y8:   "%ymm8",
   966  	Y9:   "%ymm9",
   967  	Y10:  "%ymm10",
   968  	Y11:  "%ymm11",
   969  	Y12:  "%ymm12",
   970  	Y13:  "%ymm13",
   971  	Y14:  "%ymm14",
   972  	Y15:  "%ymm15",
   973  	Y16:  "%ymm16",
   974  	Y17:  "%ymm17",
   975  	Y18:  "%ymm18",
   976  	Y19:  "%ymm19",
   977  	Y20:  "%ymm20",
   978  	Y21:  "%ymm21",
   979  	Y22:  "%ymm22",
   980  	Y23:  "%ymm23",
   981  	Y24:  "%ymm24",
   982  	Y25:  "%ymm25",
   983  	Y26:  "%ymm26",
   984  	Y27:  "%ymm27",
   985  	Y28:  "%ymm28",
   986  	Y29:  "%ymm29",
   987  	Y30:  "%ymm30",
   988  	Y31:  "%ymm31",
   989  	Z0:   "%zmm0",
   990  	Z1:   "%zmm1",
   991  	Z2:   "%zmm2",
   992  	Z3:   "%zmm3",
   993  	Z4:   "%zmm4",
   994  	Z5:   "%zmm5",
   995  	Z6:   "%zmm6",
   996  	Z7:   "%zmm7",
   997  	Z8:   "%zmm8",
   998  	Z9:   "%zmm9",
   999  	Z10:  "%zmm10",
  1000  	Z11:  "%zmm11",
  1001  	Z12:  "%zmm12",
  1002  	Z13:  "%zmm13",
  1003  	Z14:  "%zmm14",
  1004  	Z15:  "%zmm15",
  1005  	Z16:  "%zmm16",
  1006  	Z17:  "%zmm17",
  1007  	Z18:  "%zmm18",
  1008  	Z19:  "%zmm19",
  1009  	Z20:  "%zmm20",
  1010  	Z21:  "%zmm21",
  1011  	Z22:  "%zmm22",
  1012  	Z23:  "%zmm23",
  1013  	Z24:  "%zmm24",
  1014  	Z25:  "%zmm25",
  1015  	Z26:  "%zmm26",
  1016  	Z27:  "%zmm27",
  1017  	Z28:  "%zmm28",
  1018  	Z29:  "%zmm29",
  1019  	Z30:  "%zmm30",
  1020  	Z31:  "%zmm31",
  1021  	K0:   "%k0",
  1022  	K1:   "%k1",
  1023  	K2:   "%k2",
  1024  	K3:   "%k3",
  1025  	K4:   "%k4",
  1026  	K5:   "%k5",
  1027  	K6:   "%k6",
  1028  	K7:   "%k7",
  1029  	CS:   "%cs",
  1030  	SS:   "%ss",
  1031  	DS:   "%ds",
  1032  	ES:   "%es",
  1033  	FS:   "%fs",
  1034  	GS:   "%gs",
  1035  	GDTR: "%gdtr",
  1036  	IDTR: "%idtr",
  1037  	LDTR: "%ldtr",
  1038  	MSW:  "%msw",
  1039  	TASK: "%task",
  1040  	CR0:  "%cr0",
  1041  	CR1:  "%cr1",
  1042  	CR2:  "%cr2",
  1043  	CR3:  "%cr3",
  1044  	CR4:  "%cr4",
  1045  	CR5:  "%cr5",
  1046  	CR6:  "%cr6",
  1047  	CR7:  "%cr7",
  1048  	CR8:  "%cr8",
  1049  	CR9:  "%cr9",
  1050  	CR10: "%cr10",
  1051  	CR11: "%cr11",
  1052  	CR12: "%cr12",
  1053  	CR13: "%cr13",
  1054  	CR14: "%cr14",
  1055  	CR15: "%cr15",
  1056  	DR0:  "%db0",
  1057  	DR1:  "%db1",
  1058  	DR2:  "%db2",
  1059  	DR3:  "%db3",
  1060  	DR4:  "%db4",
  1061  	DR5:  "%db5",
  1062  	DR6:  "%db6",
  1063  	DR7:  "%db7",
  1064  	TR0:  "%tr0",
  1065  	TR1:  "%tr1",
  1066  	TR2:  "%tr2",
  1067  	TR3:  "%tr3",
  1068  	TR4:  "%tr4",
  1069  	TR5:  "%tr5",
  1070  	TR6:  "%tr6",
  1071  	TR7:  "%tr7",
  1072  }
  1073  
  1074  var gnuOp = map[Op]string{
  1075  	CBW:       "cbtw",
  1076  	CDQ:       "cltd",
  1077  	CMPSD:     "cmpsl",
  1078  	CMPSD_XMM: "cmpsd",
  1079  	CWD:       "cwtd",
  1080  	CWDE:      "cwtl",
  1081  	CQO:       "cqto",
  1082  	INSD:      "insl",
  1083  	IRET:      "iretw",
  1084  	IRETD:     "iret",
  1085  	IRETQ:     "iretq",
  1086  	LODSB:     "lods",
  1087  	LODSD:     "lods",
  1088  	LODSQ:     "lods",
  1089  	LODSW:     "lods",
  1090  	MOVSD:     "movsl",
  1091  	MOVSD_XMM: "movsd",
  1092  	OUTSD:     "outsl",
  1093  	POPA:      "popaw",
  1094  	POPAD:     "popa",
  1095  	POPF:      "popfw",
  1096  	POPFD:     "popf",
  1097  	PUSHA:     "pushaw",
  1098  	PUSHAD:    "pusha",
  1099  	PUSHF:     "pushfw",
  1100  	PUSHFD:    "pushf",
  1101  	SCASB:     "scas",
  1102  	SCASD:     "scas",
  1103  	SCASQ:     "scas",
  1104  	SCASW:     "scas",
  1105  	STOSB:     "stos",
  1106  	STOSD:     "stos",
  1107  	STOSQ:     "stos",
  1108  	STOSW:     "stos",
  1109  	XLATB:     "xlat",
  1110  }
  1111  
  1112  var cmppsOps = []string{
  1113  	"cmpeq",
  1114  	"cmplt",
  1115  	"cmple",
  1116  	"cmpunord",
  1117  	"cmpneq",
  1118  	"cmpnlt",
  1119  	"cmpnle",
  1120  	"cmpord",
  1121  }
  1122  
  1123  var pclmulqOps = []string{
  1124  	"pclmullqlqdq",
  1125  	"pclmulhqlqdq",
  1126  	"pclmullqhqdq",
  1127  	"pclmulhqhqdq",
  1128  }
  1129  
  1130  func countPrefix(inst *Inst, target Prefix) int {
  1131  	n := 0
  1132  	for _, p := range inst.Prefix {
  1133  		if p&0xFF == target&0xFF {
  1134  			n++
  1135  		}
  1136  	}
  1137  	return n
  1138  }
  1139  
  1140  func markLastImplicit(inst *Inst, prefix Prefix) bool {
  1141  	for i := len(inst.Prefix) - 1; i >= 0; i-- {
  1142  		p := inst.Prefix[i]
  1143  		if p&0xFF == prefix {
  1144  			inst.Prefix[i] |= PrefixImplicit
  1145  			return true
  1146  		}
  1147  	}
  1148  	return false
  1149  }
  1150  
  1151  func unmarkImplicit(inst *Inst, prefix Prefix) {
  1152  	for i := len(inst.Prefix) - 1; i >= 0; i-- {
  1153  		p := inst.Prefix[i]
  1154  		if p&0xFF == prefix {
  1155  			inst.Prefix[i] &^= PrefixImplicit
  1156  		}
  1157  	}
  1158  }
  1159  
  1160  func byteSizeSuffix(b int) string {
  1161  	switch b {
  1162  	case 1:
  1163  		return "b"
  1164  	case 2:
  1165  		return "w"
  1166  	case 4:
  1167  		return "l"
  1168  	case 8:
  1169  		return "q"
  1170  	}
  1171  	return ""
  1172  }
  1173  
  1174  func argBytes(inst *Inst, arg Arg) int {
  1175  	if isMem(arg) {
  1176  		return inst.MemBytes
  1177  	}
  1178  	return regBytes(arg)
  1179  }
  1180  
  1181  func isFloat(op Op) bool {
  1182  	switch op {
  1183  	case FADD, FCOM, FCOMP, FDIV, FDIVR, FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR, FLD, FMUL, FST, FSTP, FSUB, FSUBR:
  1184  		return true
  1185  	}
  1186  	return false
  1187  }
  1188  
  1189  func isFloatInt(op Op) bool {
  1190  	switch op {
  1191  	case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR:
  1192  		return true
  1193  	}
  1194  	return false
  1195  }
  1196  

View as plain text