github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/golang.org/x/arch/x86/x86asm/plan9x.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  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() {
    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 plan9Suffix[inst.Op] {
    66  		s := inst.DataSize
    67  		if inst.MemBytes != 0 {
    68  			s = inst.MemBytes * 8
    69  		} else if inst.Args[1] == nil { // look for register-only 64-bit instruction, like PUSHQ AX
    70  			if r, ok := inst.Args[0].(Reg); ok && RAX <= r && r <= R15 {
    71  				s = 64
    72  			}
    73  		}
    74  		switch s {
    75  		case 8:
    76  			op += "B"
    77  		case 16:
    78  			op += "W"
    79  		case 32:
    80  			op += "L"
    81  		case 64:
    82  			op += "Q"
    83  		}
    84  	}
    85  
    86  	if inst.Op == CMP {
    87  		// Use reads-left-to-right ordering for comparisons.
    88  		// See issue 60920.
    89  		args[0], args[1] = args[1], args[0]
    90  	}
    91  
    92  	if args != nil {
    93  		op += " " + strings.Join(args, ", ")
    94  	}
    95  
    96  	return rep + prefix + op
    97  }
    98  
    99  func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
   100  	switch a := arg.(type) {
   101  	case Reg:
   102  		return plan9Reg[a]
   103  	case Rel:
   104  		if pc == 0 {
   105  			break
   106  		}
   107  		// If the absolute address is the start of a symbol, use the name.
   108  		// Otherwise use the raw address, so that things like relative
   109  		// jumps show up as JMP 0x123 instead of JMP f+10(SB).
   110  		// It is usually easier to search for 0x123 than to do the mental
   111  		// arithmetic to find f+10.
   112  		addr := pc + uint64(inst.Len) + uint64(a)
   113  		if s, base := symname(addr); s != "" && addr == base {
   114  			return fmt.Sprintf("%s(SB)", s)
   115  		}
   116  		return fmt.Sprintf("%#x", addr)
   117  
   118  	case Imm:
   119  		if s, base := symname(uint64(a)); s != "" {
   120  			suffix := ""
   121  			if uint64(a) != base {
   122  				suffix = fmt.Sprintf("%+d", uint64(a)-base)
   123  			}
   124  			return fmt.Sprintf("$%s%s(SB)", s, suffix)
   125  		}
   126  		if inst.Mode == 32 {
   127  			return fmt.Sprintf("$%#x", uint32(a))
   128  		}
   129  		if Imm(int32(a)) == a {
   130  			return fmt.Sprintf("$%#x", int64(a))
   131  		}
   132  		return fmt.Sprintf("$%#x", uint64(a))
   133  	case Mem:
   134  		if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
   135  			suffix := ""
   136  			if disp != 0 {
   137  				suffix = fmt.Sprintf("%+d", disp)
   138  			}
   139  			return fmt.Sprintf("%s%s(SB)", s, suffix)
   140  		}
   141  		s := ""
   142  		if a.Segment != 0 {
   143  			s += fmt.Sprintf("%s:", plan9Reg[a.Segment])
   144  		}
   145  		if a.Disp != 0 {
   146  			s += fmt.Sprintf("%#x", a.Disp)
   147  		} else {
   148  			s += "0"
   149  		}
   150  		if a.Base != 0 {
   151  			s += fmt.Sprintf("(%s)", plan9Reg[a.Base])
   152  		}
   153  		if a.Index != 0 && a.Scale != 0 {
   154  			s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale)
   155  		}
   156  		return s
   157  	}
   158  	return arg.String()
   159  }
   160  
   161  func memArgToSymbol(a Mem, pc uint64, instrLen int, symname SymLookup) (string, int64) {
   162  	if a.Segment != 0 || a.Disp == 0 || a.Index != 0 || a.Scale != 0 {
   163  		return "", 0
   164  	}
   165  
   166  	var disp uint64
   167  	switch a.Base {
   168  	case IP, EIP, RIP:
   169  		disp = uint64(a.Disp + int64(pc) + int64(instrLen))
   170  	case 0:
   171  		disp = uint64(a.Disp)
   172  	default:
   173  		return "", 0
   174  	}
   175  
   176  	s, base := symname(disp)
   177  	return s, int64(disp) - int64(base)
   178  }
   179  
   180  var plan9Suffix = [maxOp + 1]bool{
   181  	ADC:       true,
   182  	ADD:       true,
   183  	AND:       true,
   184  	BSF:       true,
   185  	BSR:       true,
   186  	BT:        true,
   187  	BTC:       true,
   188  	BTR:       true,
   189  	BTS:       true,
   190  	CMP:       true,
   191  	CMPXCHG:   true,
   192  	CVTSI2SD:  true,
   193  	CVTSI2SS:  true,
   194  	CVTSD2SI:  true,
   195  	CVTSS2SI:  true,
   196  	CVTTSD2SI: true,
   197  	CVTTSS2SI: true,
   198  	DEC:       true,
   199  	DIV:       true,
   200  	FLDENV:    true,
   201  	FRSTOR:    true,
   202  	IDIV:      true,
   203  	IMUL:      true,
   204  	IN:        true,
   205  	INC:       true,
   206  	LEA:       true,
   207  	MOV:       true,
   208  	MOVNTI:    true,
   209  	MUL:       true,
   210  	NEG:       true,
   211  	NOP:       true,
   212  	NOT:       true,
   213  	OR:        true,
   214  	OUT:       true,
   215  	POP:       true,
   216  	POPA:      true,
   217  	POPCNT:    true,
   218  	PUSH:      true,
   219  	PUSHA:     true,
   220  	RCL:       true,
   221  	RCR:       true,
   222  	ROL:       true,
   223  	ROR:       true,
   224  	SAR:       true,
   225  	SBB:       true,
   226  	SHL:       true,
   227  	SHLD:      true,
   228  	SHR:       true,
   229  	SHRD:      true,
   230  	SUB:       true,
   231  	TEST:      true,
   232  	XADD:      true,
   233  	XCHG:      true,
   234  	XOR:       true,
   235  }
   236  
   237  var plan9Reg = [...]string{
   238  	AL:   "AL",
   239  	CL:   "CL",
   240  	BL:   "BL",
   241  	DL:   "DL",
   242  	AH:   "AH",
   243  	CH:   "CH",
   244  	BH:   "BH",
   245  	DH:   "DH",
   246  	SPB:  "SP",
   247  	BPB:  "BP",
   248  	SIB:  "SI",
   249  	DIB:  "DI",
   250  	R8B:  "R8",
   251  	R9B:  "R9",
   252  	R10B: "R10",
   253  	R11B: "R11",
   254  	R12B: "R12",
   255  	R13B: "R13",
   256  	R14B: "R14",
   257  	R15B: "R15",
   258  	AX:   "AX",
   259  	CX:   "CX",
   260  	BX:   "BX",
   261  	DX:   "DX",
   262  	SP:   "SP",
   263  	BP:   "BP",
   264  	SI:   "SI",
   265  	DI:   "DI",
   266  	R8W:  "R8",
   267  	R9W:  "R9",
   268  	R10W: "R10",
   269  	R11W: "R11",
   270  	R12W: "R12",
   271  	R13W: "R13",
   272  	R14W: "R14",
   273  	R15W: "R15",
   274  	EAX:  "AX",
   275  	ECX:  "CX",
   276  	EDX:  "DX",
   277  	EBX:  "BX",
   278  	ESP:  "SP",
   279  	EBP:  "BP",
   280  	ESI:  "SI",
   281  	EDI:  "DI",
   282  	R8L:  "R8",
   283  	R9L:  "R9",
   284  	R10L: "R10",
   285  	R11L: "R11",
   286  	R12L: "R12",
   287  	R13L: "R13",
   288  	R14L: "R14",
   289  	R15L: "R15",
   290  	RAX:  "AX",
   291  	RCX:  "CX",
   292  	RDX:  "DX",
   293  	RBX:  "BX",
   294  	RSP:  "SP",
   295  	RBP:  "BP",
   296  	RSI:  "SI",
   297  	RDI:  "DI",
   298  	R8:   "R8",
   299  	R9:   "R9",
   300  	R10:  "R10",
   301  	R11:  "R11",
   302  	R12:  "R12",
   303  	R13:  "R13",
   304  	R14:  "R14",
   305  	R15:  "R15",
   306  	IP:   "IP",
   307  	EIP:  "IP",
   308  	RIP:  "IP",
   309  	F0:   "F0",
   310  	F1:   "F1",
   311  	F2:   "F2",
   312  	F3:   "F3",
   313  	F4:   "F4",
   314  	F5:   "F5",
   315  	F6:   "F6",
   316  	F7:   "F7",
   317  	M0:   "M0",
   318  	M1:   "M1",
   319  	M2:   "M2",
   320  	M3:   "M3",
   321  	M4:   "M4",
   322  	M5:   "M5",
   323  	M6:   "M6",
   324  	M7:   "M7",
   325  	X0:   "X0",
   326  	X1:   "X1",
   327  	X2:   "X2",
   328  	X3:   "X3",
   329  	X4:   "X4",
   330  	X5:   "X5",
   331  	X6:   "X6",
   332  	X7:   "X7",
   333  	X8:   "X8",
   334  	X9:   "X9",
   335  	X10:  "X10",
   336  	X11:  "X11",
   337  	X12:  "X12",
   338  	X13:  "X13",
   339  	X14:  "X14",
   340  	X15:  "X15",
   341  	CS:   "CS",
   342  	SS:   "SS",
   343  	DS:   "DS",
   344  	ES:   "ES",
   345  	FS:   "FS",
   346  	GS:   "GS",
   347  	GDTR: "GDTR",
   348  	IDTR: "IDTR",
   349  	LDTR: "LDTR",
   350  	MSW:  "MSW",
   351  	TASK: "TASK",
   352  	CR0:  "CR0",
   353  	CR1:  "CR1",
   354  	CR2:  "CR2",
   355  	CR3:  "CR3",
   356  	CR4:  "CR4",
   357  	CR5:  "CR5",
   358  	CR6:  "CR6",
   359  	CR7:  "CR7",
   360  	CR8:  "CR8",
   361  	CR9:  "CR9",
   362  	CR10: "CR10",
   363  	CR11: "CR11",
   364  	CR12: "CR12",
   365  	CR13: "CR13",
   366  	CR14: "CR14",
   367  	CR15: "CR15",
   368  	DR0:  "DR0",
   369  	DR1:  "DR1",
   370  	DR2:  "DR2",
   371  	DR3:  "DR3",
   372  	DR4:  "DR4",
   373  	DR5:  "DR5",
   374  	DR6:  "DR6",
   375  	DR7:  "DR7",
   376  	DR8:  "DR8",
   377  	DR9:  "DR9",
   378  	DR10: "DR10",
   379  	DR11: "DR11",
   380  	DR12: "DR12",
   381  	DR13: "DR13",
   382  	DR14: "DR14",
   383  	DR15: "DR15",
   384  	TR0:  "TR0",
   385  	TR1:  "TR1",
   386  	TR2:  "TR2",
   387  	TR3:  "TR3",
   388  	TR4:  "TR4",
   389  	TR5:  "TR5",
   390  	TR6:  "TR6",
   391  	TR7:  "TR7",
   392  }