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