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