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