github.com/zxy12/golang_with_comment@v0.0.0-20190701084843-0e6b2aff5ef3/cmd/asm/internal/asm/asm.go (about) 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 runtime·sigtramp(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.From3 = newAddr(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 main·morestack(SB) 421 prog.To = *target 422 case target.Type == obj.TYPE_INDIR && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC): 423 // JMP *main·morestack(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.IsARMSTREX(op) { 511 /* 512 STREX x, (y) 513 from=(y) reg=x to=x 514 STREX (x), y 515 from=(x) reg=y to=y 516 */ 517 if a[0].Type == obj.TYPE_REG && a[1].Type != obj.TYPE_REG { 518 prog.From = a[1] 519 prog.Reg = a[0].Reg 520 prog.To = a[0] 521 break 522 } else if a[0].Type != obj.TYPE_REG && a[1].Type == obj.TYPE_REG { 523 prog.From = a[0] 524 prog.Reg = a[1].Reg 525 prog.To = a[1] 526 break 527 } 528 p.errorf("unrecognized addressing for %s", op) 529 return 530 } 531 if arch.IsARMFloatCmp(op) { 532 prog.From = a[0] 533 prog.Reg = p.getRegister(prog, op, &a[1]) 534 break 535 } 536 } else if p.arch.Family == sys.ARM64 && arch.IsARM64CMP(op) { 537 prog.From = a[0] 538 prog.Reg = p.getRegister(prog, op, &a[1]) 539 break 540 } else if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 { 541 if arch.IsMIPSCMP(op) || arch.IsMIPSMUL(op) { 542 prog.From = a[0] 543 prog.Reg = p.getRegister(prog, op, &a[1]) 544 break 545 } 546 } 547 prog.From = a[0] 548 prog.To = a[1] 549 case 3: 550 switch p.arch.Family { 551 case sys.MIPS, sys.MIPS64: 552 prog.From = a[0] 553 prog.Reg = p.getRegister(prog, op, &a[1]) 554 prog.To = a[2] 555 case sys.ARM: 556 // Special cases. 557 if arch.IsARMSTREX(op) { 558 /* 559 STREX x, (y), z 560 from=(y) reg=x to=z 561 */ 562 prog.From = a[1] 563 prog.Reg = p.getRegister(prog, op, &a[0]) 564 prog.To = a[2] 565 break 566 } 567 // Otherwise the 2nd operand (a[1]) must be a register. 568 prog.From = a[0] 569 prog.Reg = p.getRegister(prog, op, &a[1]) 570 prog.To = a[2] 571 case sys.AMD64: 572 // Catch missing operand here, because we store immediate as part of From3, and can't distinguish 573 // missing operand from legal value 0 in obj/x86/asm6. 574 if arch.IsAMD4OP(op) { 575 p.errorf("4 operands required, but only 3 are provided for %s instruction", op) 576 } 577 prog.From = a[0] 578 prog.From3 = newAddr(a[1]) 579 prog.To = a[2] 580 case sys.ARM64: 581 // ARM64 instructions with one input and two outputs. 582 if arch.IsARM64STLXR(op) { 583 prog.From = a[0] 584 prog.To = a[1] 585 if a[2].Type != obj.TYPE_REG { 586 p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op) 587 return 588 } 589 prog.RegTo2 = a[2].Reg 590 break 591 } 592 prog.From = a[0] 593 prog.Reg = p.getRegister(prog, op, &a[1]) 594 prog.To = a[2] 595 case sys.I386: 596 prog.From = a[0] 597 prog.From3 = newAddr(a[1]) 598 prog.To = a[2] 599 case sys.PPC64: 600 if arch.IsPPC64CMP(op) { 601 // CMPW etc.; third argument is a CR register that goes into prog.Reg. 602 prog.From = a[0] 603 prog.Reg = p.getRegister(prog, op, &a[2]) 604 prog.To = a[1] 605 break 606 } 607 // Arithmetic. Choices are: 608 // reg reg reg 609 // imm reg reg 610 // reg imm reg 611 // If the immediate is the middle argument, use From3. 612 switch a[1].Type { 613 case obj.TYPE_REG: 614 prog.From = a[0] 615 prog.Reg = p.getRegister(prog, op, &a[1]) 616 prog.To = a[2] 617 case obj.TYPE_CONST: 618 prog.From = a[0] 619 prog.From3 = newAddr(a[1]) 620 prog.To = a[2] 621 default: 622 p.errorf("invalid addressing modes for %s instruction", op) 623 return 624 } 625 case sys.S390X: 626 prog.From = a[0] 627 if a[1].Type == obj.TYPE_REG { 628 prog.Reg = p.getRegister(prog, op, &a[1]) 629 } else { 630 prog.From3 = newAddr(a[1]) 631 } 632 prog.To = a[2] 633 default: 634 p.errorf("TODO: implement three-operand instructions for this architecture") 635 return 636 } 637 case 4: 638 if p.arch.Family == sys.ARM && arch.IsARMMULA(op) { 639 // All must be registers. 640 p.getRegister(prog, op, &a[0]) 641 r1 := p.getRegister(prog, op, &a[1]) 642 r2 := p.getRegister(prog, op, &a[2]) 643 p.getRegister(prog, op, &a[3]) 644 prog.From = a[0] 645 prog.To = a[3] 646 prog.To.Type = obj.TYPE_REGREG2 647 prog.To.Offset = int64(r2) 648 prog.Reg = r1 649 break 650 } 651 if p.arch.Family == sys.AMD64 { 652 // 4 operand instruction have form ymm1, ymm2, ymm3/m256, imm8 653 // So From3 is always just a register, so we store imm8 in Offset field, 654 // to avoid increasing size of Prog. 655 prog.From = a[1] 656 prog.From3 = newAddr(a[2]) 657 if a[0].Type != obj.TYPE_CONST { 658 p.errorf("first operand must be an immediate in %s instruction", op) 659 } 660 if prog.From3.Type != obj.TYPE_REG { 661 p.errorf("third operand must be a register in %s instruction", op) 662 } 663 prog.From3.Offset = int64(p.getImmediate(prog, op, &a[0])) 664 prog.To = a[3] 665 prog.RegTo2 = -1 666 break 667 } 668 if p.arch.Family == sys.ARM64 { 669 prog.From = a[0] 670 prog.Reg = p.getRegister(prog, op, &a[1]) 671 prog.From3 = newAddr(a[2]) 672 prog.To = a[3] 673 break 674 } 675 if p.arch.Family == sys.PPC64 { 676 if arch.IsPPC64RLD(op) { 677 prog.From = a[0] 678 prog.Reg = p.getRegister(prog, op, &a[1]) 679 prog.From3 = newAddr(a[2]) 680 prog.To = a[3] 681 break 682 } else if arch.IsPPC64ISEL(op) { 683 // ISEL BC,RB,RA,RT becomes isel rt,ra,rb,bc 684 prog.From3 = newAddr(a[2]) // ra 685 prog.From = a[0] // bc 686 prog.Reg = p.getRegister(prog, op, &a[1]) // rb 687 prog.To = a[3] // rt 688 break 689 } 690 // Else, it is a VA-form instruction 691 // reg reg reg reg 692 // imm reg reg reg 693 // Or a VX-form instruction 694 // imm imm reg reg 695 if a[1].Type == obj.TYPE_REG { 696 prog.From = a[0] 697 prog.Reg = p.getRegister(prog, op, &a[1]) 698 prog.From3 = newAddr(a[2]) 699 prog.To = a[3] 700 break 701 } else if a[1].Type == obj.TYPE_CONST { 702 prog.From = a[0] 703 prog.Reg = p.getRegister(prog, op, &a[2]) 704 prog.From3 = newAddr(a[1]) 705 prog.To = a[3] 706 break 707 } else { 708 p.errorf("invalid addressing modes for %s instruction", op) 709 return 710 } 711 } 712 if p.arch.Family == sys.S390X { 713 if a[1].Type != obj.TYPE_REG { 714 p.errorf("second operand must be a register in %s instruction", op) 715 return 716 } 717 prog.From = a[0] 718 prog.Reg = p.getRegister(prog, op, &a[1]) 719 prog.From3 = newAddr(a[2]) 720 prog.To = a[3] 721 break 722 } 723 p.errorf("can't handle %s instruction with 4 operands", op) 724 return 725 case 5: 726 if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) { 727 // Always reg, reg, con, con, reg. (con, con is a 'mask'). 728 prog.From = a[0] 729 prog.Reg = p.getRegister(prog, op, &a[1]) 730 mask1 := p.getConstant(prog, op, &a[2]) 731 mask2 := p.getConstant(prog, op, &a[3]) 732 var mask uint32 733 if mask1 < mask2 { 734 mask = (^uint32(0) >> uint(mask1)) & (^uint32(0) << uint(31-mask2)) 735 } else { 736 mask = (^uint32(0) >> uint(mask2+1)) & (^uint32(0) << uint(31-(mask1-1))) 737 } 738 prog.From3 = &obj.Addr{ 739 Type: obj.TYPE_CONST, 740 Offset: int64(mask), 741 } 742 prog.To = a[4] 743 break 744 } 745 p.errorf("can't handle %s instruction with 5 operands", op) 746 return 747 case 6: 748 if p.arch.Family == sys.ARM && arch.IsARMMRC(op) { 749 // Strange special case: MCR, MRC. 750 prog.To.Type = obj.TYPE_CONST 751 x0 := p.getConstant(prog, op, &a[0]) 752 x1 := p.getConstant(prog, op, &a[1]) 753 x2 := int64(p.getRegister(prog, op, &a[2])) 754 x3 := int64(p.getRegister(prog, op, &a[3])) 755 x4 := int64(p.getRegister(prog, op, &a[4])) 756 x5 := p.getConstant(prog, op, &a[5]) 757 // Cond is handled specially for this instruction. 758 offset, MRC, ok := arch.ARMMRCOffset(op, cond, x0, x1, x2, x3, x4, x5) 759 if !ok { 760 p.errorf("unrecognized condition code .%q", cond) 761 } 762 prog.To.Offset = offset 763 cond = "" 764 prog.As = MRC // Both instructions are coded as MRC. 765 break 766 } 767 fallthrough 768 default: 769 p.errorf("can't handle %s instruction with %d operands", op, len(a)) 770 return 771 } 772 773 p.append(prog, cond, true) 774 } 775 776 // newAddr returns a new(Addr) initialized to x. 777 func newAddr(x obj.Addr) *obj.Addr { 778 p := new(obj.Addr) 779 *p = x 780 return p 781 } 782 783 // symbolName returns the symbol name, or an error string if none if available. 784 func symbolName(addr *obj.Addr) string { 785 if addr.Sym != nil { 786 return addr.Sym.Name 787 } 788 return "<erroneous symbol>" 789 } 790 791 var emptyProg obj.Prog 792 793 // getConstantPseudo checks that addr represents a plain constant and returns its value. 794 func (p *Parser) getConstantPseudo(pseudo string, addr *obj.Addr) int64 { 795 if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 { 796 p.errorf("%s: expected integer constant; found %s", pseudo, obj.Dconv(&emptyProg, addr)) 797 } 798 return addr.Offset 799 } 800 801 // getConstant checks that addr represents a plain constant and returns its value. 802 func (p *Parser) getConstant(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 { 803 if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 { 804 p.errorf("%s: expected integer constant; found %s", op, obj.Dconv(prog, addr)) 805 } 806 return addr.Offset 807 } 808 809 // getImmediate checks that addr represents an immediate constant and returns its value. 810 func (p *Parser) getImmediate(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 { 811 if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 { 812 p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, addr)) 813 } 814 return addr.Offset 815 } 816 817 // getRegister checks that addr represents a register and returns its value. 818 func (p *Parser) getRegister(prog *obj.Prog, op obj.As, addr *obj.Addr) int16 { 819 if addr.Type != obj.TYPE_REG || addr.Offset != 0 || addr.Name != 0 || addr.Index != 0 { 820 p.errorf("%s: expected register; found %s", op, obj.Dconv(prog, addr)) 821 } 822 return addr.Reg 823 }