Source file src/cmd/asm/internal/asm/asm.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 asm
     6  
     7  import (
     8  	"fmt"
     9  	"internal/abi"
    10  	"strconv"
    11  	"strings"
    12  	"text/scanner"
    13  
    14  	"cmd/asm/internal/arch"
    15  	"cmd/asm/internal/flags"
    16  	"cmd/asm/internal/lex"
    17  	"cmd/internal/obj"
    18  	"cmd/internal/obj/ppc64"
    19  	"cmd/internal/obj/riscv"
    20  	"cmd/internal/obj/x86"
    21  	"cmd/internal/sys"
    22  )
    23  
    24  // TODO: configure the architecture
    25  
    26  var testOut *strings.Builder // Gathers output when testing.
    27  
    28  // append adds the Prog to the end of the program-thus-far.
    29  // If doLabel is set, it also defines the labels collect for this Prog.
    30  func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
    31  	if cond != "" {
    32  		switch p.arch.Family {
    33  		case sys.ARM:
    34  			if !arch.ARMConditionCodes(prog, cond) {
    35  				p.errorf("unrecognized condition code .%q", cond)
    36  				return
    37  			}
    38  
    39  		case sys.ARM64:
    40  			if !arch.ARM64Suffix(prog, cond) {
    41  				p.errorf("unrecognized suffix .%q", cond)
    42  				return
    43  			}
    44  
    45  		case sys.AMD64, sys.I386:
    46  			if err := x86.ParseSuffix(prog, cond); err != nil {
    47  				p.errorf("%v", err)
    48  				return
    49  			}
    50  		case sys.RISCV64:
    51  			if err := riscv.ParseSuffix(prog, cond); err != nil {
    52  				p.errorf("unrecognized suffix .%q", cond)
    53  				return
    54  			}
    55  		default:
    56  			p.errorf("unrecognized suffix .%q", cond)
    57  			return
    58  		}
    59  	}
    60  	if p.firstProg == nil {
    61  		p.firstProg = prog
    62  	} else {
    63  		p.lastProg.Link = prog
    64  	}
    65  	p.lastProg = prog
    66  	if doLabel {
    67  		p.pc++
    68  		for _, label := range p.pendingLabels {
    69  			if p.labels[label] != nil {
    70  				p.errorf("label %q multiply defined", label)
    71  				return
    72  			}
    73  			p.labels[label] = prog
    74  		}
    75  		p.pendingLabels = p.pendingLabels[0:0]
    76  	}
    77  	prog.Pc = p.pc
    78  	if *flags.Debug {
    79  		fmt.Println(p.lineNum, prog)
    80  	}
    81  	if testOut != nil {
    82  		fmt.Fprintln(testOut, prog)
    83  	}
    84  }
    85  
    86  // validSymbol checks that addr represents a valid name for a pseudo-op.
    87  func (p *Parser) validSymbol(pseudo string, addr *obj.Addr, offsetOk bool) bool {
    88  	if addr.Sym == nil || addr.Name != obj.NAME_EXTERN && addr.Name != obj.NAME_STATIC || addr.Scale != 0 || addr.Reg != 0 {
    89  		p.errorf("%s symbol %q must be a symbol(SB)", pseudo, symbolName(addr))
    90  		return false
    91  	}
    92  	if !offsetOk && addr.Offset != 0 {
    93  		p.errorf("%s symbol %q must not be offset from SB", pseudo, symbolName(addr))
    94  		return false
    95  	}
    96  	return true
    97  }
    98  
    99  // evalInteger evaluates an integer constant for a pseudo-op.
   100  func (p *Parser) evalInteger(pseudo string, operands []lex.Token) int64 {
   101  	addr := p.address(operands)
   102  	return p.getConstantPseudo(pseudo, &addr)
   103  }
   104  
   105  // validImmediate checks that addr represents an immediate constant.
   106  func (p *Parser) validImmediate(pseudo string, addr *obj.Addr) bool {
   107  	if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
   108  		p.errorf("%s: expected immediate constant; found %s", pseudo, obj.Dconv(&emptyProg, addr))
   109  		return false
   110  	}
   111  	return true
   112  }
   113  
   114  // asmText assembles a TEXT pseudo-op.
   115  // TEXT runtime·sigtramp(SB),4,$0-0
   116  func (p *Parser) asmText(operands [][]lex.Token) {
   117  	if len(operands) != 2 && len(operands) != 3 {
   118  		p.errorf("expect two or three operands for TEXT")
   119  		return
   120  	}
   121  
   122  	// Labels are function scoped. Patch existing labels and
   123  	// create a new label space for this TEXT.
   124  	p.patch()
   125  	p.labels = make(map[string]*obj.Prog)
   126  
   127  	// Operand 0 is the symbol name in the form foo(SB).
   128  	// That means symbol plus indirect on SB and no offset.
   129  	nameAddr := p.address(operands[0])
   130  	if !p.validSymbol("TEXT", &nameAddr, false) {
   131  		return
   132  	}
   133  	name := symbolName(&nameAddr)
   134  	next := 1
   135  
   136  	// Next operand is the optional text flag, a literal integer.
   137  	var flag = int64(0)
   138  	if len(operands) == 3 {
   139  		flag = p.evalInteger("TEXT", operands[1])
   140  		next++
   141  	}
   142  
   143  	// Issue an error if we see a function defined as ABIInternal
   144  	// without NOSPLIT. In ABIInternal, obj needs to know the function
   145  	// signature in order to construct the morestack path, so this
   146  	// currently isn't supported for asm functions.
   147  	if nameAddr.Sym.ABI() == obj.ABIInternal && flag&obj.NOSPLIT == 0 {
   148  		p.errorf("TEXT %q: ABIInternal requires NOSPLIT", name)
   149  	}
   150  
   151  	// Next operand is the frame and arg size.
   152  	// Bizarre syntax: $frameSize-argSize is two words, not subtraction.
   153  	// Both frameSize and argSize must be simple integers; only frameSize
   154  	// can be negative.
   155  	// The "-argSize" may be missing; if so, set it to objabi.ArgsSizeUnknown.
   156  	// Parse left to right.
   157  	op := operands[next]
   158  	if len(op) < 2 || op[0].ScanToken != '$' {
   159  		p.errorf("TEXT %s: frame size must be an immediate constant", name)
   160  		return
   161  	}
   162  	op = op[1:]
   163  	negative := false
   164  	if op[0].ScanToken == '-' {
   165  		negative = true
   166  		op = op[1:]
   167  	}
   168  	if len(op) == 0 || op[0].ScanToken != scanner.Int {
   169  		p.errorf("TEXT %s: frame size must be an immediate constant", name)
   170  		return
   171  	}
   172  	frameSize := p.positiveAtoi(op[0].String())
   173  	if negative {
   174  		frameSize = -frameSize
   175  	}
   176  	op = op[1:]
   177  	argSize := int64(abi.ArgsSizeUnknown)
   178  	if len(op) > 0 {
   179  		// There is an argument size. It must be a minus sign followed by a non-negative integer literal.
   180  		if len(op) != 2 || op[0].ScanToken != '-' || op[1].ScanToken != scanner.Int {
   181  			p.errorf("TEXT %s: argument size must be of form -integer", name)
   182  			return
   183  		}
   184  		argSize = p.positiveAtoi(op[1].String())
   185  	}
   186  	p.ctxt.InitTextSym(nameAddr.Sym, int(flag), p.pos())
   187  	prog := &obj.Prog{
   188  		Ctxt: p.ctxt,
   189  		As:   obj.ATEXT,
   190  		Pos:  p.pos(),
   191  		From: nameAddr,
   192  		To: obj.Addr{
   193  			Type:   obj.TYPE_TEXTSIZE,
   194  			Offset: frameSize,
   195  			// Argsize set below.
   196  		},
   197  	}
   198  	nameAddr.Sym.Func().Text = prog
   199  	prog.To.Val = int32(argSize)
   200  	p.append(prog, "", true)
   201  }
   202  
   203  // asmData assembles a DATA pseudo-op.
   204  // DATA masks<>+0x00(SB)/4, $0x00000000
   205  func (p *Parser) asmData(operands [][]lex.Token) {
   206  	if len(operands) != 2 {
   207  		p.errorf("expect two operands for DATA")
   208  		return
   209  	}
   210  
   211  	// Operand 0 has the general form foo<>+0x04(SB)/4.
   212  	op := operands[0]
   213  	n := len(op)
   214  	if n < 3 || op[n-2].ScanToken != '/' || op[n-1].ScanToken != scanner.Int {
   215  		p.errorf("expect /size for DATA argument")
   216  		return
   217  	}
   218  	szop := op[n-1].String()
   219  	sz, err := strconv.Atoi(szop)
   220  	if err != nil {
   221  		p.errorf("bad size for DATA argument: %q", szop)
   222  	}
   223  	op = op[:n-2]
   224  	nameAddr := p.address(op)
   225  	if !p.validSymbol("DATA", &nameAddr, true) {
   226  		return
   227  	}
   228  	name := symbolName(&nameAddr)
   229  
   230  	// Operand 1 is an immediate constant or address.
   231  	valueAddr := p.address(operands[1])
   232  	switch valueAddr.Type {
   233  	case obj.TYPE_CONST, obj.TYPE_FCONST, obj.TYPE_SCONST, obj.TYPE_ADDR:
   234  		// OK
   235  	default:
   236  		p.errorf("DATA value must be an immediate constant or address")
   237  		return
   238  	}
   239  
   240  	// The addresses must not overlap. Easiest test: require monotonicity.
   241  	if lastAddr, ok := p.dataAddr[name]; ok && nameAddr.Offset < lastAddr {
   242  		p.errorf("overlapping DATA entry for %s", name)
   243  		return
   244  	}
   245  	p.dataAddr[name] = nameAddr.Offset + int64(sz)
   246  
   247  	switch valueAddr.Type {
   248  	case obj.TYPE_CONST:
   249  		switch sz {
   250  		case 1, 2, 4, 8:
   251  			nameAddr.Sym.WriteInt(p.ctxt, nameAddr.Offset, int(sz), valueAddr.Offset)
   252  		default:
   253  			p.errorf("bad int size for DATA argument: %d", sz)
   254  		}
   255  	case obj.TYPE_FCONST:
   256  		switch sz {
   257  		case 4:
   258  			nameAddr.Sym.WriteFloat32(p.ctxt, nameAddr.Offset, float32(valueAddr.Val.(float64)))
   259  		case 8:
   260  			nameAddr.Sym.WriteFloat64(p.ctxt, nameAddr.Offset, valueAddr.Val.(float64))
   261  		default:
   262  			p.errorf("bad float size for DATA argument: %d", sz)
   263  		}
   264  	case obj.TYPE_SCONST:
   265  		nameAddr.Sym.WriteString(p.ctxt, nameAddr.Offset, int(sz), valueAddr.Val.(string))
   266  	case obj.TYPE_ADDR:
   267  		if sz == p.arch.PtrSize {
   268  			nameAddr.Sym.WriteAddr(p.ctxt, nameAddr.Offset, int(sz), valueAddr.Sym, valueAddr.Offset)
   269  		} else {
   270  			p.errorf("bad addr size for DATA argument: %d", sz)
   271  		}
   272  	}
   273  }
   274  
   275  // asmGlobl assembles a GLOBL pseudo-op.
   276  // GLOBL shifts<>(SB),8,$256
   277  // GLOBL shifts<>(SB),$256
   278  func (p *Parser) asmGlobl(operands [][]lex.Token) {
   279  	if len(operands) != 2 && len(operands) != 3 {
   280  		p.errorf("expect two or three operands for GLOBL")
   281  		return
   282  	}
   283  
   284  	// Operand 0 has the general form foo<>+0x04(SB).
   285  	nameAddr := p.address(operands[0])
   286  	if !p.validSymbol("GLOBL", &nameAddr, false) {
   287  		return
   288  	}
   289  	next := 1
   290  
   291  	// Next operand is the optional flag, a literal integer.
   292  	var flag = int64(0)
   293  	if len(operands) == 3 {
   294  		flag = p.evalInteger("GLOBL", operands[1])
   295  		next++
   296  	}
   297  
   298  	// Final operand is an immediate constant.
   299  	addr := p.address(operands[next])
   300  	if !p.validImmediate("GLOBL", &addr) {
   301  		return
   302  	}
   303  
   304  	// log.Printf("GLOBL %s %d, $%d", name, flag, size)
   305  	p.ctxt.GloblPos(nameAddr.Sym, addr.Offset, int(flag), p.pos())
   306  }
   307  
   308  // asmPCData assembles a PCDATA pseudo-op.
   309  // PCDATA $2, $705
   310  func (p *Parser) asmPCData(operands [][]lex.Token) {
   311  	if len(operands) != 2 {
   312  		p.errorf("expect two operands for PCDATA")
   313  		return
   314  	}
   315  
   316  	// Operand 0 must be an immediate constant.
   317  	key := p.address(operands[0])
   318  	if !p.validImmediate("PCDATA", &key) {
   319  		return
   320  	}
   321  
   322  	// Operand 1 must be an immediate constant.
   323  	value := p.address(operands[1])
   324  	if !p.validImmediate("PCDATA", &value) {
   325  		return
   326  	}
   327  
   328  	// log.Printf("PCDATA $%d, $%d", key.Offset, value.Offset)
   329  	prog := &obj.Prog{
   330  		Ctxt: p.ctxt,
   331  		As:   obj.APCDATA,
   332  		Pos:  p.pos(),
   333  		From: key,
   334  		To:   value,
   335  	}
   336  	p.append(prog, "", true)
   337  }
   338  
   339  // asmPCAlign assembles a PCALIGN pseudo-op.
   340  // PCALIGN $16
   341  func (p *Parser) asmPCAlign(operands [][]lex.Token) {
   342  	if len(operands) != 1 {
   343  		p.errorf("expect one operand for PCALIGN")
   344  		return
   345  	}
   346  
   347  	// Operand 0 must be an immediate constant.
   348  	key := p.address(operands[0])
   349  	if !p.validImmediate("PCALIGN", &key) {
   350  		return
   351  	}
   352  
   353  	prog := &obj.Prog{
   354  		Ctxt: p.ctxt,
   355  		As:   obj.APCALIGN,
   356  		From: key,
   357  	}
   358  	p.append(prog, "", true)
   359  }
   360  
   361  // asmFuncData assembles a FUNCDATA pseudo-op.
   362  // FUNCDATA $1, funcdata<>+4(SB)
   363  func (p *Parser) asmFuncData(operands [][]lex.Token) {
   364  	if len(operands) != 2 {
   365  		p.errorf("expect two operands for FUNCDATA")
   366  		return
   367  	}
   368  
   369  	// Operand 0 must be an immediate constant.
   370  	valueAddr := p.address(operands[0])
   371  	if !p.validImmediate("FUNCDATA", &valueAddr) {
   372  		return
   373  	}
   374  
   375  	// Operand 1 is a symbol name in the form foo(SB).
   376  	nameAddr := p.address(operands[1])
   377  	if !p.validSymbol("FUNCDATA", &nameAddr, true) {
   378  		return
   379  	}
   380  
   381  	prog := &obj.Prog{
   382  		Ctxt: p.ctxt,
   383  		As:   obj.AFUNCDATA,
   384  		Pos:  p.pos(),
   385  		From: valueAddr,
   386  		To:   nameAddr,
   387  	}
   388  	p.append(prog, "", true)
   389  }
   390  
   391  // asmJump assembles a jump instruction.
   392  // JMP	R1
   393  // JMP	exit
   394  // JMP	3(PC)
   395  func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
   396  	var target *obj.Addr
   397  	prog := &obj.Prog{
   398  		Ctxt: p.ctxt,
   399  		Pos:  p.pos(),
   400  		As:   op,
   401  	}
   402  	targetAddr := &prog.To
   403  	switch len(a) {
   404  	case 0:
   405  		if p.arch.Family == sys.Wasm {
   406  			target = &obj.Addr{Type: obj.TYPE_NONE}
   407  			break
   408  		}
   409  		p.errorf("wrong number of arguments to %s instruction", op)
   410  		return
   411  	case 1:
   412  		target = &a[0]
   413  	case 2:
   414  		// Special 2-operand jumps.
   415  		if p.arch.Family == sys.ARM64 && arch.IsARM64ADR(op) {
   416  			// ADR label, R. Label is in From.
   417  			target = &a[0]
   418  			prog.To = a[1]
   419  			targetAddr = &prog.From
   420  		} else {
   421  			target = &a[1]
   422  			prog.From = a[0]
   423  		}
   424  	case 3:
   425  		if p.arch.Family == sys.PPC64 {
   426  			// Special 3-operand jumps.
   427  			// a[1] is a register number expressed as a constant or register value
   428  			target = &a[2]
   429  			prog.From = a[0]
   430  			if a[0].Type != obj.TYPE_CONST {
   431  				// Legacy code may use a plain constant, accept it, and coerce
   432  				// into a constant. E.g:
   433  				//   BC 4,...
   434  				// into
   435  				//   BC $4,...
   436  				prog.From = obj.Addr{
   437  					Type:   obj.TYPE_CONST,
   438  					Offset: p.getConstant(prog, op, &a[0]),
   439  				}
   440  
   441  			}
   442  
   443  			// Likewise, fixup usage like:
   444  			//   BC x,LT,...
   445  			//   BC x,foo+2,...
   446  			//   BC x,4
   447  			//   BC x,$5
   448  			// into
   449  			//   BC x,CR0LT,...
   450  			//   BC x,CR0EQ,...
   451  			//   BC x,CR1LT,...
   452  			//   BC x,CR1GT,...
   453  			// The first and second cases demonstrate a symbol name which is
   454  			// effectively discarded. In these cases, the offset determines
   455  			// the CR bit.
   456  			prog.Reg = a[1].Reg
   457  			if a[1].Type != obj.TYPE_REG {
   458  				// The CR bit is represented as a constant 0-31. Convert it to a Reg.
   459  				c := p.getConstant(prog, op, &a[1])
   460  				reg, success := ppc64.ConstantToCRbit(c)
   461  				if !success {
   462  					p.errorf("invalid CR bit register number %d", c)
   463  				}
   464  				prog.Reg = reg
   465  			}
   466  			break
   467  		}
   468  		if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 || p.arch.Family == sys.RISCV64 {
   469  			// 3-operand jumps.
   470  			// First two must be registers
   471  			target = &a[2]
   472  			prog.From = a[0]
   473  			prog.Reg = p.getRegister(prog, op, &a[1])
   474  			break
   475  		}
   476  		if p.arch.Family == sys.Loong64 {
   477  			// 3-operand jumps.
   478  			// First two must be registers
   479  			target = &a[2]
   480  			prog.From = a[0]
   481  			prog.Reg = p.getRegister(prog, op, &a[1])
   482  			break
   483  		}
   484  		if p.arch.Family == sys.S390X {
   485  			// 3-operand jumps.
   486  			target = &a[2]
   487  			prog.From = a[0]
   488  			if a[1].Reg != 0 {
   489  				// Compare two registers and jump.
   490  				prog.Reg = p.getRegister(prog, op, &a[1])
   491  			} else {
   492  				// Compare register with immediate and jump.
   493  				prog.AddRestSource(a[1])
   494  			}
   495  			break
   496  		}
   497  		if p.arch.Family == sys.ARM64 {
   498  			// Special 3-operand jumps.
   499  			// a[0] must be immediate constant; a[1] is a register.
   500  			if a[0].Type != obj.TYPE_CONST {
   501  				p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, &a[0]))
   502  				return
   503  			}
   504  			prog.From = a[0]
   505  			prog.Reg = p.getRegister(prog, op, &a[1])
   506  			target = &a[2]
   507  			break
   508  		}
   509  		p.errorf("wrong number of arguments to %s instruction", op)
   510  		return
   511  	case 4:
   512  		if p.arch.Family == sys.S390X || p.arch.Family == sys.PPC64 {
   513  			// 4-operand compare-and-branch.
   514  			prog.From = a[0]
   515  			prog.Reg = p.getRegister(prog, op, &a[1])
   516  			prog.AddRestSource(a[2])
   517  			target = &a[3]
   518  			break
   519  		}
   520  		p.errorf("wrong number of arguments to %s instruction", op)
   521  		return
   522  	default:
   523  		p.errorf("wrong number of arguments to %s instruction", op)
   524  		return
   525  	}
   526  	switch {
   527  	case target.Type == obj.TYPE_BRANCH:
   528  		// JMP 4(PC)
   529  		*targetAddr = obj.Addr{
   530  			Type:   obj.TYPE_BRANCH,
   531  			Offset: p.pc + 1 + target.Offset, // +1 because p.pc is incremented in append, below.
   532  		}
   533  	case target.Type == obj.TYPE_REG:
   534  		// JMP R1
   535  		*targetAddr = *target
   536  	case target.Type == obj.TYPE_MEM && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC):
   537  		// JMP main·morestack(SB)
   538  		*targetAddr = *target
   539  	case target.Type == obj.TYPE_INDIR && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC):
   540  		// JMP *main·morestack(SB)
   541  		*targetAddr = *target
   542  		targetAddr.Type = obj.TYPE_INDIR
   543  	case target.Type == obj.TYPE_MEM && target.Reg == 0 && target.Offset == 0:
   544  		// JMP exit
   545  		if target.Sym == nil {
   546  			// Parse error left name unset.
   547  			return
   548  		}
   549  		targetProg := p.labels[target.Sym.Name]
   550  		if targetProg == nil {
   551  			p.toPatch = append(p.toPatch, Patch{targetAddr, target.Sym.Name})
   552  		} else {
   553  			p.branch(targetAddr, targetProg)
   554  		}
   555  	case target.Type == obj.TYPE_MEM && target.Name == obj.NAME_NONE:
   556  		// JMP 4(R0)
   557  		*targetAddr = *target
   558  		// On the ppc64, 9a encodes BR (CTR) as BR CTR. We do the same.
   559  		if p.arch.Family == sys.PPC64 && target.Offset == 0 {
   560  			targetAddr.Type = obj.TYPE_REG
   561  		}
   562  	case target.Type == obj.TYPE_CONST:
   563  		// JMP $4
   564  		*targetAddr = a[0]
   565  	case target.Type == obj.TYPE_NONE:
   566  		// JMP
   567  	default:
   568  		p.errorf("cannot assemble jump %+v", target)
   569  		return
   570  	}
   571  
   572  	p.append(prog, cond, true)
   573  }
   574  
   575  func (p *Parser) patch() {
   576  	for _, patch := range p.toPatch {
   577  		targetProg := p.labels[patch.label]
   578  		if targetProg == nil {
   579  			p.errorf("undefined label %s", patch.label)
   580  			return
   581  		}
   582  		p.branch(patch.addr, targetProg)
   583  	}
   584  	p.toPatch = p.toPatch[:0]
   585  }
   586  
   587  func (p *Parser) branch(addr *obj.Addr, target *obj.Prog) {
   588  	*addr = obj.Addr{
   589  		Type:  obj.TYPE_BRANCH,
   590  		Index: 0,
   591  	}
   592  	addr.Val = target
   593  }
   594  
   595  // asmInstruction assembles an instruction.
   596  // MOVW R9, (R10)
   597  func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
   598  	// fmt.Printf("%s %+v\n", op, a)
   599  	prog := &obj.Prog{
   600  		Ctxt: p.ctxt,
   601  		Pos:  p.pos(),
   602  		As:   op,
   603  	}
   604  	switch len(a) {
   605  	case 0:
   606  		// Nothing to do.
   607  	case 1:
   608  		if p.arch.UnaryDst[op] || op == obj.ARET || op == obj.AGETCALLERPC {
   609  			// prog.From is no address.
   610  			prog.To = a[0]
   611  		} else {
   612  			prog.From = a[0]
   613  			// prog.To is no address.
   614  		}
   615  		if p.arch.Family == sys.PPC64 && arch.IsPPC64NEG(op) {
   616  			// NEG: From and To are both a[0].
   617  			prog.To = a[0]
   618  			prog.From = a[0]
   619  			break
   620  		}
   621  	case 2:
   622  		if p.arch.Family == sys.ARM {
   623  			if arch.IsARMCMP(op) {
   624  				prog.From = a[0]
   625  				prog.Reg = p.getRegister(prog, op, &a[1])
   626  				break
   627  			}
   628  			// Strange special cases.
   629  			if arch.IsARMFloatCmp(op) {
   630  				prog.From = a[0]
   631  				prog.Reg = p.getRegister(prog, op, &a[1])
   632  				break
   633  			}
   634  		} else if p.arch.Family == sys.ARM64 && arch.IsARM64CMP(op) {
   635  			prog.From = a[0]
   636  			prog.Reg = p.getRegister(prog, op, &a[1])
   637  			break
   638  		} else if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 {
   639  			if arch.IsMIPSCMP(op) || arch.IsMIPSMUL(op) {
   640  				prog.From = a[0]
   641  				prog.Reg = p.getRegister(prog, op, &a[1])
   642  				break
   643  			}
   644  		} else if p.arch.Family == sys.Loong64 {
   645  			if arch.IsLoong64CMP(op) {
   646  				prog.From = a[0]
   647  				prog.Reg = p.getRegister(prog, op, &a[1])
   648  				break
   649  			}
   650  
   651  			if arch.IsLoong64RDTIME(op) {
   652  				// The Loong64 RDTIME family of instructions is a bit special,
   653  				// in that both its register operands are outputs
   654  				prog.To = a[0]
   655  				if a[1].Type != obj.TYPE_REG {
   656  					p.errorf("invalid addressing modes for 2nd operand to %s instruction, must be register", op)
   657  					return
   658  				}
   659  				prog.RegTo2 = a[1].Reg
   660  				break
   661  			}
   662  		}
   663  		prog.From = a[0]
   664  		prog.To = a[1]
   665  	case 3:
   666  		switch p.arch.Family {
   667  		case sys.MIPS, sys.MIPS64:
   668  			prog.From = a[0]
   669  			prog.Reg = p.getRegister(prog, op, &a[1])
   670  			prog.To = a[2]
   671  		case sys.Loong64:
   672  			prog.From = a[0]
   673  			prog.Reg = p.getRegister(prog, op, &a[1])
   674  			prog.To = a[2]
   675  		case sys.ARM:
   676  			// Special cases.
   677  			if arch.IsARMSTREX(op) {
   678  				/*
   679  					STREX x, (y), z
   680  						from=(y) reg=x to=z
   681  				*/
   682  				prog.From = a[1]
   683  				prog.Reg = p.getRegister(prog, op, &a[0])
   684  				prog.To = a[2]
   685  				break
   686  			}
   687  			if arch.IsARMBFX(op) {
   688  				// a[0] and a[1] must be constants, a[2] must be a register
   689  				prog.From = a[0]
   690  				prog.AddRestSource(a[1])
   691  				prog.To = a[2]
   692  				break
   693  			}
   694  			// Otherwise the 2nd operand (a[1]) must be a register.
   695  			prog.From = a[0]
   696  			prog.Reg = p.getRegister(prog, op, &a[1])
   697  			prog.To = a[2]
   698  		case sys.AMD64:
   699  			prog.From = a[0]
   700  			prog.AddRestSource(a[1])
   701  			prog.To = a[2]
   702  		case sys.ARM64:
   703  			switch {
   704  			case arch.IsARM64STLXR(op):
   705  				// ARM64 instructions with one input and two outputs.
   706  				prog.From = a[0]
   707  				prog.To = a[1]
   708  				if a[2].Type != obj.TYPE_REG {
   709  					p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op)
   710  					return
   711  				}
   712  				prog.RegTo2 = a[2].Reg
   713  			case arch.IsARM64TBL(op):
   714  				// one of its inputs does not fit into prog.Reg.
   715  				prog.From = a[0]
   716  				prog.AddRestSource(a[1])
   717  				prog.To = a[2]
   718  			case arch.IsARM64CASP(op):
   719  				prog.From = a[0]
   720  				prog.To = a[1]
   721  				// both 1st operand and 3rd operand are (Rs, Rs+1) register pair.
   722  				// And the register pair must be contiguous.
   723  				if (a[0].Type != obj.TYPE_REGREG) || (a[2].Type != obj.TYPE_REGREG) {
   724  					p.errorf("invalid addressing modes for 1st or 3rd operand to %s instruction, must be register pair", op)
   725  					return
   726  				}
   727  				// For ARM64 CASP-like instructions, its 2nd destination operand is register pair(Rt, Rt+1) that can
   728  				// not fit into prog.RegTo2, so save it to the prog.RestArgs.
   729  				prog.AddRestDest(a[2])
   730  			default:
   731  				prog.From = a[0]
   732  				prog.Reg = p.getRegister(prog, op, &a[1])
   733  				prog.To = a[2]
   734  			}
   735  		case sys.I386:
   736  			prog.From = a[0]
   737  			prog.AddRestSource(a[1])
   738  			prog.To = a[2]
   739  		case sys.PPC64:
   740  			if arch.IsPPC64CMP(op) {
   741  				// CMPW etc.; third argument is a CR register that goes into prog.Reg.
   742  				prog.From = a[0]
   743  				prog.Reg = p.getRegister(prog, op, &a[2])
   744  				prog.To = a[1]
   745  				break
   746  			}
   747  
   748  			prog.From = a[0]
   749  			prog.To = a[2]
   750  
   751  			// If the second argument is not a register argument, it must be
   752  			// passed RestArgs/AddRestSource
   753  			switch a[1].Type {
   754  			case obj.TYPE_REG:
   755  				prog.Reg = p.getRegister(prog, op, &a[1])
   756  			default:
   757  				prog.AddRestSource(a[1])
   758  			}
   759  		case sys.RISCV64:
   760  			// RISCV64 instructions with one input and two outputs.
   761  			if arch.IsRISCV64AMO(op) {
   762  				prog.From = a[0]
   763  				prog.To = a[1]
   764  				if a[2].Type != obj.TYPE_REG {
   765  					p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op)
   766  					return
   767  				}
   768  				prog.RegTo2 = a[2].Reg
   769  				break
   770  			}
   771  			prog.From = a[0]
   772  			prog.Reg = p.getRegister(prog, op, &a[1])
   773  			prog.To = a[2]
   774  		case sys.S390X:
   775  			prog.From = a[0]
   776  			if a[1].Type == obj.TYPE_REG {
   777  				prog.Reg = p.getRegister(prog, op, &a[1])
   778  			} else {
   779  				prog.AddRestSource(a[1])
   780  			}
   781  			prog.To = a[2]
   782  		default:
   783  			p.errorf("TODO: implement three-operand instructions for this architecture")
   784  			return
   785  		}
   786  	case 4:
   787  		if p.arch.Family == sys.ARM {
   788  			if arch.IsARMBFX(op) {
   789  				// a[0] and a[1] must be constants, a[2] and a[3] must be registers
   790  				prog.From = a[0]
   791  				prog.AddRestSource(a[1])
   792  				prog.Reg = p.getRegister(prog, op, &a[2])
   793  				prog.To = a[3]
   794  				break
   795  			}
   796  			if arch.IsARMMULA(op) {
   797  				// All must be registers.
   798  				p.getRegister(prog, op, &a[0])
   799  				r1 := p.getRegister(prog, op, &a[1])
   800  				r2 := p.getRegister(prog, op, &a[2])
   801  				p.getRegister(prog, op, &a[3])
   802  				prog.From = a[0]
   803  				prog.To = a[3]
   804  				prog.To.Type = obj.TYPE_REGREG2
   805  				prog.To.Offset = int64(r2)
   806  				prog.Reg = r1
   807  				break
   808  			}
   809  		}
   810  		if p.arch.Family == sys.AMD64 {
   811  			prog.From = a[0]
   812  			prog.AddRestSourceArgs([]obj.Addr{a[1], a[2]})
   813  			prog.To = a[3]
   814  			break
   815  		}
   816  		if p.arch.Family == sys.ARM64 {
   817  			prog.From = a[0]
   818  			prog.Reg = p.getRegister(prog, op, &a[1])
   819  			prog.AddRestSource(a[2])
   820  			prog.To = a[3]
   821  			break
   822  		}
   823  		if p.arch.Family == sys.PPC64 {
   824  			prog.From = a[0]
   825  			prog.To = a[3]
   826  			// If the second argument is not a register argument, it must be
   827  			// passed RestArgs/AddRestSource
   828  			if a[1].Type == obj.TYPE_REG {
   829  				prog.Reg = p.getRegister(prog, op, &a[1])
   830  				prog.AddRestSource(a[2])
   831  			} else {
   832  				// Don't set prog.Reg if a1 isn't a reg arg.
   833  				prog.AddRestSourceArgs([]obj.Addr{a[1], a[2]})
   834  			}
   835  			break
   836  		}
   837  		if p.arch.Family == sys.RISCV64 {
   838  			prog.From = a[0]
   839  			prog.Reg = p.getRegister(prog, op, &a[1])
   840  			prog.AddRestSource(a[2])
   841  			prog.To = a[3]
   842  			break
   843  		}
   844  		if p.arch.Family == sys.S390X {
   845  			if a[1].Type != obj.TYPE_REG {
   846  				p.errorf("second operand must be a register in %s instruction", op)
   847  				return
   848  			}
   849  			prog.From = a[0]
   850  			prog.Reg = p.getRegister(prog, op, &a[1])
   851  			prog.AddRestSource(a[2])
   852  			prog.To = a[3]
   853  			break
   854  		}
   855  		p.errorf("can't handle %s instruction with 4 operands", op)
   856  		return
   857  	case 5:
   858  		if p.arch.Family == sys.PPC64 {
   859  			prog.From = a[0]
   860  			// Second arg is always a register type on ppc64.
   861  			prog.Reg = p.getRegister(prog, op, &a[1])
   862  			prog.AddRestSourceArgs([]obj.Addr{a[2], a[3]})
   863  			prog.To = a[4]
   864  			break
   865  		}
   866  		if p.arch.Family == sys.AMD64 {
   867  			prog.From = a[0]
   868  			prog.AddRestSourceArgs([]obj.Addr{a[1], a[2], a[3]})
   869  			prog.To = a[4]
   870  			break
   871  		}
   872  		if p.arch.Family == sys.S390X {
   873  			prog.From = a[0]
   874  			prog.AddRestSourceArgs([]obj.Addr{a[1], a[2], a[3]})
   875  			prog.To = a[4]
   876  			break
   877  		}
   878  		p.errorf("can't handle %s instruction with 5 operands", op)
   879  		return
   880  	case 6:
   881  		if p.arch.Family == sys.ARM && arch.IsARMMRC(op) {
   882  			// Strange special case: MCR, MRC.
   883  			prog.To.Type = obj.TYPE_CONST
   884  			x0 := p.getConstant(prog, op, &a[0])
   885  			x1 := p.getConstant(prog, op, &a[1])
   886  			x2 := int64(p.getRegister(prog, op, &a[2]))
   887  			x3 := int64(p.getRegister(prog, op, &a[3]))
   888  			x4 := int64(p.getRegister(prog, op, &a[4]))
   889  			x5 := p.getConstant(prog, op, &a[5])
   890  			// Cond is handled specially for this instruction.
   891  			offset, MRC, ok := arch.ARMMRCOffset(op, cond, x0, x1, x2, x3, x4, x5)
   892  			if !ok {
   893  				p.errorf("unrecognized condition code .%q", cond)
   894  			}
   895  			prog.To.Offset = offset
   896  			cond = ""
   897  			prog.As = MRC // Both instructions are coded as MRC.
   898  			break
   899  		}
   900  		if p.arch.Family == sys.PPC64 {
   901  			prog.From = a[0]
   902  			// Second arg is always a register type on ppc64.
   903  			prog.Reg = p.getRegister(prog, op, &a[1])
   904  			prog.AddRestSourceArgs([]obj.Addr{a[2], a[3], a[4]})
   905  			prog.To = a[5]
   906  			break
   907  		}
   908  		fallthrough
   909  	default:
   910  		p.errorf("can't handle %s instruction with %d operands", op, len(a))
   911  		return
   912  	}
   913  
   914  	p.append(prog, cond, true)
   915  }
   916  
   917  // symbolName returns the symbol name, or an error string if none is available.
   918  func symbolName(addr *obj.Addr) string {
   919  	if addr.Sym != nil {
   920  		return addr.Sym.Name
   921  	}
   922  	return "<erroneous symbol>"
   923  }
   924  
   925  var emptyProg obj.Prog
   926  
   927  // getConstantPseudo checks that addr represents a plain constant and returns its value.
   928  func (p *Parser) getConstantPseudo(pseudo string, addr *obj.Addr) int64 {
   929  	if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
   930  		p.errorf("%s: expected integer constant; found %s", pseudo, obj.Dconv(&emptyProg, addr))
   931  	}
   932  	return addr.Offset
   933  }
   934  
   935  // getConstant checks that addr represents a plain constant and returns its value.
   936  func (p *Parser) getConstant(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
   937  	if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
   938  		p.errorf("%s: expected integer constant; found %s", op, obj.Dconv(prog, addr))
   939  	}
   940  	return addr.Offset
   941  }
   942  
   943  // getImmediate checks that addr represents an immediate constant and returns its value.
   944  func (p *Parser) getImmediate(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
   945  	if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
   946  		p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, addr))
   947  	}
   948  	return addr.Offset
   949  }
   950  
   951  // getRegister checks that addr represents a register and returns its value.
   952  func (p *Parser) getRegister(prog *obj.Prog, op obj.As, addr *obj.Addr) int16 {
   953  	if addr.Type != obj.TYPE_REG || addr.Offset != 0 || addr.Name != 0 || addr.Index != 0 {
   954  		p.errorf("%s: expected register; found %s", op, obj.Dconv(prog, addr))
   955  	}
   956  	return addr.Reg
   957  }
   958  

View as plain text