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

View as plain text