Source file src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.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  type SymLookup func(uint64) (string, uint64)
    13  
    14  // GoSyntax returns the Go assembler syntax for the instruction.
    15  // The syntax was originally defined by Plan 9.
    16  // The pc is the program counter of the instruction, used for expanding
    17  // PC-relative addresses into absolute ones.
    18  // The symname function queries the symbol table for the program
    19  // being disassembled. Given a target address it returns the name and base
    20  // address of the symbol containing the target, if any; otherwise it returns "", 0.
    21  func GoSyntax(inst Inst, pc uint64, symname SymLookup) string {
    22  	if symname == nil {
    23  		symname = func(uint64) (string, uint64) { return "", 0 }
    24  	}
    25  	var args []string
    26  	for i := len(inst.Args) - 1; i >= 0; i-- {
    27  		a := inst.Args[i]
    28  		if a == nil {
    29  			continue
    30  		}
    31  		args = append(args, plan9Arg(&inst, pc, symname, a))
    32  	}
    33  
    34  	var rep string
    35  	var last Prefix
    36  	for _, p := range inst.Prefix {
    37  		if p == 0 || p.IsREX() || p.IsVEX() || p.IsEVEX() {
    38  			break
    39  		}
    40  
    41  		switch {
    42  		// Don't show prefixes implied by the instruction text.
    43  		case p&0xFF00 == PrefixImplicit:
    44  			continue
    45  		// Only REP and REPN are recognized repeaters. Plan 9 syntax
    46  		// treats them as separate opcodes.
    47  		case p&0xFF == PrefixREP:
    48  			rep = "REP; "
    49  		case p&0xFF == PrefixREPN:
    50  			rep = "REPNE; "
    51  		default:
    52  			last = p
    53  		}
    54  	}
    55  
    56  	prefix := ""
    57  	switch last & 0xFF {
    58  	case 0, 0x66, 0x67:
    59  		// ignore
    60  	default:
    61  		prefix += last.String() + " "
    62  	}
    63  
    64  	op := inst.Op.String()
    65  	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 {
    66  		vexL := 0
    67  		isEvex := false
    68  		for i, p := range inst.Prefix {
    69  			if p.IsEVEX() && i+3 < len(inst.Prefix) && inst.Prefix[i+3] != 0 {
    70  				vexL = int((inst.Prefix[i+3]&0xFF)>>5) & 3
    71  				isEvex = true
    72  				break
    73  			} else if p.IsVEX() && i+2 < len(inst.Prefix) {
    74  				if p&0xFF == 0xC4 {
    75  					vexL = int((inst.Prefix[i+2]&0xFF)>>2) & 1
    76  				} else if p&0xFF == 0xC5 {
    77  					vexL = int((inst.Prefix[i+1]&0xFF)>>2) & 1
    78  				}
    79  				break
    80  			}
    81  		}
    82  		if !isEvex || inst.Op == VFPCLASSPD || inst.Op == VFPCLASSPS || inst.Op == VCVTPD2DQ {
    83  			switch vexL {
    84  			case 0:
    85  				op += "X"
    86  			case 1:
    87  				if inst.Op != VCMPPD && inst.Op != VCMPPS && inst.Op != VCMPPH && inst.Op != VCMPBF16 {
    88  					op += "Y"
    89  				}
    90  			case 2:
    91  				if inst.Op != VCMPPD && inst.Op != VCMPPS && inst.Op != VCMPPH && inst.Op != VCMPBF16 {
    92  					op += "Z"
    93  				}
    94  			}
    95  		}
    96  	} else if inst.Op == VCVTTSD2SI || inst.Op == VCVTTSS2SI || inst.Op == VCVTSD2SI || inst.Op == VCVTSS2SI || inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS {
    97  		is64 := false
    98  		if (inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS) && inst.MemBytes == 8 {
    99  			is64 = true
   100  		} else {
   101  			for _, a := range inst.Args {
   102  				if r, ok := a.(Reg); ok && RAX <= r && r <= R15 {
   103  					is64 = true
   104  					break
   105  				}
   106  			}
   107  		}
   108  		if inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS {
   109  			if is64 {
   110  				op += "Q"
   111  			} else {
   112  				op += "L"
   113  			}
   114  		} else {
   115  			if is64 {
   116  				op += "Q"
   117  			}
   118  		}
   119  	} else if plan9Suffix[inst.Op] {
   120  		s := inst.DataSize
   121  		if inst.MemBytes != 0 {
   122  			s = inst.MemBytes * 8
   123  		} else if inst.Args[1] == nil { // look for register-only 64-bit instruction, like PUSHQ AX
   124  			if r, ok := inst.Args[0].(Reg); ok && RAX <= r && r <= R15 {
   125  				s = 64
   126  			}
   127  		}
   128  		switch s {
   129  		case 8:
   130  			op += "B"
   131  		case 16:
   132  			op += "W"
   133  		case 32:
   134  			op += "L"
   135  		case 64:
   136  			op += "Q"
   137  		}
   138  	}
   139  
   140  	if inst.Broadcast {
   141  		op += ".BCST"
   142  	}
   143  	if inst.SAE {
   144  		if hasRC(inst.Op) {
   145  			switch inst.Rounding {
   146  			case 0:
   147  				op += ".RN_SAE"
   148  			case 1:
   149  				op += ".RD_SAE"
   150  			case 2:
   151  				op += ".RU_SAE"
   152  			case 3:
   153  				op += ".RZ_SAE"
   154  			}
   155  		} else {
   156  			op += ".SAE"
   157  		}
   158  	}
   159  	if inst.Zeroing {
   160  		op += ".Z"
   161  	}
   162  
   163  	if inst.Op == CMP {
   164  		// Use reads-left-to-right ordering for comparisons.
   165  		// See issue 60920.
   166  		args[0], args[1] = args[1], args[0]
   167  	}
   168  
   169  	if args != nil {
   170  		op += " " + strings.Join(args, ", ")
   171  	}
   172  
   173  	return rep + prefix + op
   174  }
   175  
   176  func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
   177  	switch a := arg.(type) {
   178  	case Reg:
   179  		return plan9Reg[a]
   180  	case Rel:
   181  		if pc == 0 {
   182  			break
   183  		}
   184  		// If the absolute address is the start of a symbol, use the name.
   185  		// Otherwise use the raw address, so that things like relative
   186  		// jumps show up as JMP 0x123 instead of JMP f+10(SB).
   187  		// It is usually easier to search for 0x123 than to do the mental
   188  		// arithmetic to find f+10.
   189  		addr := pc + uint64(inst.Len) + uint64(a)
   190  		if s, base := symname(addr); s != "" && addr == base {
   191  			return fmt.Sprintf("%s(SB)", s)
   192  		}
   193  		return fmt.Sprintf("%#x", addr)
   194  
   195  	case Imm:
   196  		if (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 {
   197  			// Only try to convert an immediate to a symbol in certain
   198  			// special circumstances. See issue 72942.
   199  			//
   200  			// On 64-bit, symbol addresses always hit the Mem case below.
   201  			// Particularly, we use LEAQ to materialize the address of
   202  			// a global or function.
   203  			//
   204  			// On 32-bit, we sometimes use MOVL. Still try to symbolize
   205  			// those immediates.
   206  			if s, base := symname(uint64(a)); s != "" {
   207  				suffix := ""
   208  				if uint64(a) != base {
   209  					suffix = fmt.Sprintf("%+d", uint64(a)-base)
   210  				}
   211  				return fmt.Sprintf("$%s%s(SB)", s, suffix)
   212  			}
   213  		}
   214  		if inst.Mode == 32 {
   215  			return fmt.Sprintf("$%#x", uint32(a))
   216  		}
   217  		if Imm(int32(a)) == a {
   218  			return fmt.Sprintf("$%#x", int64(a))
   219  		}
   220  		return fmt.Sprintf("$%#x", uint64(a))
   221  	case Mem:
   222  		if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
   223  			suffix := ""
   224  			if disp != 0 {
   225  				suffix = fmt.Sprintf("%+d", disp)
   226  			}
   227  			return fmt.Sprintf("%s%s(SB)", s, suffix)
   228  		}
   229  		s := ""
   230  		if a.Segment != 0 {
   231  			s += fmt.Sprintf("%s:", plan9Reg[a.Segment])
   232  		}
   233  		if a.Disp != 0 {
   234  			s += fmt.Sprintf("%#x", a.Disp)
   235  		} else {
   236  			s += "0"
   237  		}
   238  		if a.Base != 0 {
   239  			s += fmt.Sprintf("(%s)", plan9Reg[a.Base])
   240  		}
   241  		if a.Index != 0 && a.Scale != 0 {
   242  			s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale)
   243  		}
   244  		return s
   245  	}
   246  	return arg.String()
   247  }
   248  
   249  func memArgToSymbol(a Mem, pc uint64, instrLen int, symname SymLookup) (string, int64) {
   250  	if a.Segment != 0 || a.Disp == 0 || a.Index != 0 || a.Scale != 0 {
   251  		return "", 0
   252  	}
   253  
   254  	var disp uint64
   255  	switch a.Base {
   256  	case IP, EIP, RIP:
   257  		disp = uint64(a.Disp + int64(pc) + int64(instrLen))
   258  	case 0:
   259  		disp = uint64(a.Disp)
   260  	default:
   261  		return "", 0
   262  	}
   263  
   264  	s, base := symname(disp)
   265  	return s, int64(disp) - int64(base)
   266  }
   267  
   268  var plan9Suffix = [maxOp + 1]bool{
   269  	ADC:       true,
   270  	ADD:       true,
   271  	AND:       true,
   272  	BSF:       true,
   273  	BSR:       true,
   274  	BT:        true,
   275  	BTC:       true,
   276  	BTR:       true,
   277  	BTS:       true,
   278  	CMP:       true,
   279  	CMPXCHG:   true,
   280  	CVTSI2SD:  true,
   281  	CVTSI2SS:  true,
   282  	CVTSD2SI:  true,
   283  	CVTSS2SI:  true,
   284  	CVTTSD2SI: true,
   285  	CVTTSS2SI: true,
   286  	DEC:       true,
   287  	DIV:       true,
   288  	FLDENV:    true,
   289  	FRSTOR:    true,
   290  	IDIV:      true,
   291  	IMUL:      true,
   292  	IN:        true,
   293  	INC:       true,
   294  	LEA:       true,
   295  	MOV:       true,
   296  	MOVNTI:    true,
   297  	MUL:       true,
   298  	NEG:       true,
   299  	NOP:       true,
   300  	NOT:       true,
   301  	OR:        true,
   302  	OUT:       true,
   303  	POP:       true,
   304  	POPA:      true,
   305  	POPCNT:    true,
   306  	PUSH:      true,
   307  	PUSHA:     true,
   308  	RCL:       true,
   309  	RCR:       true,
   310  	ROL:       true,
   311  	ROR:       true,
   312  	SAR:       true,
   313  	SBB:       true,
   314  	SHL:       true,
   315  	SHLD:      true,
   316  	SHR:       true,
   317  	SHRD:      true,
   318  	SUB:       true,
   319  	TEST:      true,
   320  	XADD:      true,
   321  	XCHG:      true,
   322  	XOR:       true,
   323  }
   324  
   325  var plan9Reg = [...]string{
   326  	AL:   "AL",
   327  	CL:   "CL",
   328  	BL:   "BL",
   329  	DL:   "DL",
   330  	AH:   "AH",
   331  	CH:   "CH",
   332  	BH:   "BH",
   333  	DH:   "DH",
   334  	SPB:  "SP",
   335  	BPB:  "BP",
   336  	SIB:  "SI",
   337  	DIB:  "DI",
   338  	R8B:  "R8",
   339  	R9B:  "R9",
   340  	R10B: "R10",
   341  	R11B: "R11",
   342  	R12B: "R12",
   343  	R13B: "R13",
   344  	R14B: "R14",
   345  	R15B: "R15",
   346  	AX:   "AX",
   347  	CX:   "CX",
   348  	BX:   "BX",
   349  	DX:   "DX",
   350  	SP:   "SP",
   351  	BP:   "BP",
   352  	SI:   "SI",
   353  	DI:   "DI",
   354  	R8W:  "R8",
   355  	R9W:  "R9",
   356  	R10W: "R10",
   357  	R11W: "R11",
   358  	R12W: "R12",
   359  	R13W: "R13",
   360  	R14W: "R14",
   361  	R15W: "R15",
   362  	EAX:  "AX",
   363  	ECX:  "CX",
   364  	EDX:  "DX",
   365  	EBX:  "BX",
   366  	ESP:  "SP",
   367  	EBP:  "BP",
   368  	ESI:  "SI",
   369  	EDI:  "DI",
   370  	R8L:  "R8",
   371  	R9L:  "R9",
   372  	R10L: "R10",
   373  	R11L: "R11",
   374  	R12L: "R12",
   375  	R13L: "R13",
   376  	R14L: "R14",
   377  	R15L: "R15",
   378  	RAX:  "AX",
   379  	RCX:  "CX",
   380  	RDX:  "DX",
   381  	RBX:  "BX",
   382  	RSP:  "SP",
   383  	RBP:  "BP",
   384  	RSI:  "SI",
   385  	RDI:  "DI",
   386  	R8:   "R8",
   387  	R9:   "R9",
   388  	R10:  "R10",
   389  	R11:  "R11",
   390  	R12:  "R12",
   391  	R13:  "R13",
   392  	R14:  "R14",
   393  	R15:  "R15",
   394  	IP:   "IP",
   395  	EIP:  "IP",
   396  	RIP:  "IP",
   397  	F0:   "F0",
   398  	F1:   "F1",
   399  	F2:   "F2",
   400  	F3:   "F3",
   401  	F4:   "F4",
   402  	F5:   "F5",
   403  	F6:   "F6",
   404  	F7:   "F7",
   405  	M0:   "M0",
   406  	M1:   "M1",
   407  	M2:   "M2",
   408  	M3:   "M3",
   409  	M4:   "M4",
   410  	M5:   "M5",
   411  	M6:   "M6",
   412  	M7:   "M7",
   413  	X0:   "X0",
   414  	X1:   "X1",
   415  	X2:   "X2",
   416  	X3:   "X3",
   417  	X4:   "X4",
   418  	X5:   "X5",
   419  	X6:   "X6",
   420  	X7:   "X7",
   421  	X8:   "X8",
   422  	X9:   "X9",
   423  	X10:  "X10",
   424  	X11:  "X11",
   425  	X12:  "X12",
   426  	X13:  "X13",
   427  	X14:  "X14",
   428  	X15:  "X15",
   429  	X16:  "X16",
   430  	X17:  "X17",
   431  	X18:  "X18",
   432  	X19:  "X19",
   433  	X20:  "X20",
   434  	X21:  "X21",
   435  	X22:  "X22",
   436  	X23:  "X23",
   437  	X24:  "X24",
   438  	X25:  "X25",
   439  	X26:  "X26",
   440  	X27:  "X27",
   441  	X28:  "X28",
   442  	X29:  "X29",
   443  	X30:  "X30",
   444  	X31:  "X31",
   445  	Y0:   "Y0",
   446  	Y1:   "Y1",
   447  	Y2:   "Y2",
   448  	Y3:   "Y3",
   449  	Y4:   "Y4",
   450  	Y5:   "Y5",
   451  	Y6:   "Y6",
   452  	Y7:   "Y7",
   453  	Y8:   "Y8",
   454  	Y9:   "Y9",
   455  	Y10:  "Y10",
   456  	Y11:  "Y11",
   457  	Y12:  "Y12",
   458  	Y13:  "Y13",
   459  	Y14:  "Y14",
   460  	Y15:  "Y15",
   461  	Y16:  "Y16",
   462  	Y17:  "Y17",
   463  	Y18:  "Y18",
   464  	Y19:  "Y19",
   465  	Y20:  "Y20",
   466  	Y21:  "Y21",
   467  	Y22:  "Y22",
   468  	Y23:  "Y23",
   469  	Y24:  "Y24",
   470  	Y25:  "Y25",
   471  	Y26:  "Y26",
   472  	Y27:  "Y27",
   473  	Y28:  "Y28",
   474  	Y29:  "Y29",
   475  	Y30:  "Y30",
   476  	Y31:  "Y31",
   477  	Z0:   "Z0",
   478  	Z1:   "Z1",
   479  	Z2:   "Z2",
   480  	Z3:   "Z3",
   481  	Z4:   "Z4",
   482  	Z5:   "Z5",
   483  	Z6:   "Z6",
   484  	Z7:   "Z7",
   485  	Z8:   "Z8",
   486  	Z9:   "Z9",
   487  	Z10:  "Z10",
   488  	Z11:  "Z11",
   489  	Z12:  "Z12",
   490  	Z13:  "Z13",
   491  	Z14:  "Z14",
   492  	Z15:  "Z15",
   493  	Z16:  "Z16",
   494  	Z17:  "Z17",
   495  	Z18:  "Z18",
   496  	Z19:  "Z19",
   497  	Z20:  "Z20",
   498  	Z21:  "Z21",
   499  	Z22:  "Z22",
   500  	Z23:  "Z23",
   501  	Z24:  "Z24",
   502  	Z25:  "Z25",
   503  	Z26:  "Z26",
   504  	Z27:  "Z27",
   505  	Z28:  "Z28",
   506  	Z29:  "Z29",
   507  	Z30:  "Z30",
   508  	Z31:  "Z31",
   509  	K0:   "K0",
   510  	K1:   "K1",
   511  	K2:   "K2",
   512  	K3:   "K3",
   513  	K4:   "K4",
   514  	K5:   "K5",
   515  	K6:   "K6",
   516  	K7:   "K7",
   517  	CS:   "CS",
   518  	SS:   "SS",
   519  	DS:   "DS",
   520  	ES:   "ES",
   521  	FS:   "FS",
   522  	GS:   "GS",
   523  	GDTR: "GDTR",
   524  	IDTR: "IDTR",
   525  	LDTR: "LDTR",
   526  	MSW:  "MSW",
   527  	TASK: "TASK",
   528  	CR0:  "CR0",
   529  	CR1:  "CR1",
   530  	CR2:  "CR2",
   531  	CR3:  "CR3",
   532  	CR4:  "CR4",
   533  	CR5:  "CR5",
   534  	CR6:  "CR6",
   535  	CR7:  "CR7",
   536  	CR8:  "CR8",
   537  	CR9:  "CR9",
   538  	CR10: "CR10",
   539  	CR11: "CR11",
   540  	CR12: "CR12",
   541  	CR13: "CR13",
   542  	CR14: "CR14",
   543  	CR15: "CR15",
   544  	DR0:  "DR0",
   545  	DR1:  "DR1",
   546  	DR2:  "DR2",
   547  	DR3:  "DR3",
   548  	DR4:  "DR4",
   549  	DR5:  "DR5",
   550  	DR6:  "DR6",
   551  	DR7:  "DR7",
   552  	DR8:  "DR8",
   553  	DR9:  "DR9",
   554  	DR10: "DR10",
   555  	DR11: "DR11",
   556  	DR12: "DR12",
   557  	DR13: "DR13",
   558  	DR14: "DR14",
   559  	DR15: "DR15",
   560  	TR0:  "TR0",
   561  	TR1:  "TR1",
   562  	TR2:  "TR2",
   563  	TR3:  "TR3",
   564  	TR4:  "TR4",
   565  	TR5:  "TR5",
   566  	TR6:  "TR6",
   567  	TR7:  "TR7",
   568  }
   569  

View as plain text