Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/asm/internal/asm/asm.go

Documentation: cmd/asm/internal/asm

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

View as plain text