github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/internal/obj/ppc64/obj9.go (about) 1 // cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova. 2 // 3 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 4 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 5 // Portions Copyright © 1997-1999 Vita Nuova Limited 6 // Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) 7 // Portions Copyright © 2004,2006 Bruce Ellis 8 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 9 // Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others 10 // Portions Copyright © 2009 The Go Authors. All rights reserved. 11 // 12 // Permission is hereby granted, free of charge, to any person obtaining a copy 13 // of this software and associated documentation files (the "Software"), to deal 14 // in the Software without restriction, including without limitation the rights 15 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 // copies of the Software, and to permit persons to whom the Software is 17 // furnished to do so, subject to the following conditions: 18 // 19 // The above copyright notice and this permission notice shall be included in 20 // all copies or substantial portions of the Software. 21 // 22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 // THE SOFTWARE. 29 30 package ppc64 31 32 import ( 33 "cmd/internal/obj" 34 "encoding/binary" 35 "fmt" 36 "math" 37 ) 38 39 func progedit(ctxt *obj.Link, p *obj.Prog) { 40 p.From.Class = 0 41 p.To.Class = 0 42 43 // Rewrite BR/BL to symbol as TYPE_BRANCH. 44 switch p.As { 45 case ABR, 46 ABL, 47 obj.ARET, 48 obj.ADUFFZERO, 49 obj.ADUFFCOPY: 50 if p.To.Sym != nil { 51 p.To.Type = obj.TYPE_BRANCH 52 } 53 } 54 55 // Rewrite float constants to values stored in memory. 56 switch p.As { 57 case AFMOVS: 58 if p.From.Type == obj.TYPE_FCONST { 59 f32 := float32(p.From.Val.(float64)) 60 i32 := math.Float32bits(f32) 61 literal := fmt.Sprintf("$f32.%08x", i32) 62 s := obj.Linklookup(ctxt, literal, 0) 63 s.Size = 4 64 p.From.Type = obj.TYPE_MEM 65 p.From.Sym = s 66 p.From.Sym.Local = true 67 p.From.Name = obj.NAME_EXTERN 68 p.From.Offset = 0 69 } 70 71 case AFMOVD: 72 if p.From.Type == obj.TYPE_FCONST { 73 i64 := math.Float64bits(p.From.Val.(float64)) 74 literal := fmt.Sprintf("$f64.%016x", i64) 75 s := obj.Linklookup(ctxt, literal, 0) 76 s.Size = 8 77 p.From.Type = obj.TYPE_MEM 78 p.From.Sym = s 79 p.From.Sym.Local = true 80 p.From.Name = obj.NAME_EXTERN 81 p.From.Offset = 0 82 } 83 84 // Put >32-bit constants in memory and load them 85 case AMOVD: 86 if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset { 87 literal := fmt.Sprintf("$i64.%016x", uint64(p.From.Offset)) 88 s := obj.Linklookup(ctxt, literal, 0) 89 s.Size = 8 90 p.From.Type = obj.TYPE_MEM 91 p.From.Sym = s 92 p.From.Sym.Local = true 93 p.From.Name = obj.NAME_EXTERN 94 p.From.Offset = 0 95 } 96 } 97 98 // Rewrite SUB constants into ADD. 99 switch p.As { 100 case ASUBC: 101 if p.From.Type == obj.TYPE_CONST { 102 p.From.Offset = -p.From.Offset 103 p.As = AADDC 104 } 105 106 case ASUBCCC: 107 if p.From.Type == obj.TYPE_CONST { 108 p.From.Offset = -p.From.Offset 109 p.As = AADDCCC 110 } 111 112 case ASUB: 113 if p.From.Type == obj.TYPE_CONST { 114 p.From.Offset = -p.From.Offset 115 p.As = AADD 116 } 117 } 118 if ctxt.Flag_dynlink { 119 rewriteToUseGot(ctxt, p) 120 } 121 } 122 123 // Rewrite p, if necessary, to access global data via the global offset table. 124 func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) { 125 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO { 126 // ADUFFxxx $offset 127 // becomes 128 // MOVD runtime.duffxxx@GOT, R12 129 // ADD $offset, R12 130 // MOVD R12, CTR 131 // BL (CTR) 132 var sym *obj.LSym 133 if p.As == obj.ADUFFZERO { 134 sym = obj.Linklookup(ctxt, "runtime.duffzero", 0) 135 } else { 136 sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0) 137 } 138 offset := p.To.Offset 139 p.As = AMOVD 140 p.From.Type = obj.TYPE_MEM 141 p.From.Name = obj.NAME_GOTREF 142 p.From.Sym = sym 143 p.To.Type = obj.TYPE_REG 144 p.To.Reg = REG_R12 145 p.To.Name = obj.NAME_NONE 146 p.To.Offset = 0 147 p.To.Sym = nil 148 p1 := obj.Appendp(ctxt, p) 149 p1.As = AADD 150 p1.From.Type = obj.TYPE_CONST 151 p1.From.Offset = offset 152 p1.To.Type = obj.TYPE_REG 153 p1.To.Reg = REG_R12 154 p2 := obj.Appendp(ctxt, p1) 155 p2.As = AMOVD 156 p2.From.Type = obj.TYPE_REG 157 p2.From.Reg = REG_R12 158 p2.To.Type = obj.TYPE_REG 159 p2.To.Reg = REG_CTR 160 p3 := obj.Appendp(ctxt, p2) 161 p3.As = obj.ACALL 162 p3.From.Type = obj.TYPE_REG 163 p3.From.Reg = REG_R12 164 p3.To.Type = obj.TYPE_REG 165 p3.To.Reg = REG_CTR 166 } 167 168 // We only care about global data: NAME_EXTERN means a global 169 // symbol in the Go sense, and p.Sym.Local is true for a few 170 // internally defined symbols. 171 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local { 172 // MOVD $sym, Rx becomes MOVD sym@GOT, Rx 173 // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx 174 if p.As != AMOVD { 175 ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p) 176 } 177 if p.To.Type != obj.TYPE_REG { 178 ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p) 179 } 180 p.From.Type = obj.TYPE_MEM 181 p.From.Name = obj.NAME_GOTREF 182 if p.From.Offset != 0 { 183 q := obj.Appendp(ctxt, p) 184 q.As = AADD 185 q.From.Type = obj.TYPE_CONST 186 q.From.Offset = p.From.Offset 187 q.To = p.To 188 p.From.Offset = 0 189 } 190 } 191 if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { 192 ctxt.Diag("don't know how to handle %v with -dynlink", p) 193 } 194 var source *obj.Addr 195 // MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry 196 // MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVx Ry, (REGTMP) 197 // An addition may be inserted between the two MOVs if there is an offset. 198 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local { 199 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local { 200 ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p) 201 } 202 source = &p.From 203 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local { 204 source = &p.To 205 } else { 206 return 207 } 208 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { 209 return 210 } 211 if source.Sym.Type == obj.STLSBSS { 212 return 213 } 214 if source.Type != obj.TYPE_MEM { 215 ctxt.Diag("don't know how to handle %v with -dynlink", p) 216 } 217 p1 := obj.Appendp(ctxt, p) 218 p2 := obj.Appendp(ctxt, p1) 219 220 p1.As = AMOVD 221 p1.From.Type = obj.TYPE_MEM 222 p1.From.Sym = source.Sym 223 p1.From.Name = obj.NAME_GOTREF 224 p1.To.Type = obj.TYPE_REG 225 p1.To.Reg = REGTMP 226 227 p2.As = p.As 228 p2.From = p.From 229 p2.To = p.To 230 if p.From.Name == obj.NAME_EXTERN { 231 p2.From.Reg = REGTMP 232 p2.From.Name = obj.NAME_NONE 233 p2.From.Sym = nil 234 } else if p.To.Name == obj.NAME_EXTERN { 235 p2.To.Reg = REGTMP 236 p2.To.Name = obj.NAME_NONE 237 p2.To.Sym = nil 238 } else { 239 return 240 } 241 obj.Nopout(p) 242 } 243 244 func preprocess(ctxt *obj.Link, cursym *obj.LSym) { 245 // TODO(minux): add morestack short-cuts with small fixed frame-size. 246 ctxt.Cursym = cursym 247 248 if cursym.Text == nil || cursym.Text.Link == nil { 249 return 250 } 251 252 p := cursym.Text 253 textstksiz := p.To.Offset 254 if textstksiz == -8 { 255 // Compatibility hack. 256 p.From3.Offset |= obj.NOFRAME 257 textstksiz = 0 258 } 259 if textstksiz%8 != 0 { 260 ctxt.Diag("frame size %d not a multiple of 8", textstksiz) 261 } 262 if p.From3.Offset&obj.NOFRAME != 0 { 263 if textstksiz != 0 { 264 ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz) 265 } 266 } 267 268 cursym.Args = p.To.Val.(int32) 269 cursym.Locals = int32(textstksiz) 270 271 /* 272 * find leaf subroutines 273 * strip NOPs 274 * expand RET 275 * expand BECOME pseudo 276 */ 277 if ctxt.Debugvlog != 0 { 278 fmt.Fprintf(ctxt.Bso, "%5.2f noops\n", obj.Cputime()) 279 } 280 ctxt.Bso.Flush() 281 282 var q *obj.Prog 283 var q1 *obj.Prog 284 for p := cursym.Text; p != nil; p = p.Link { 285 switch p.As { 286 /* too hard, just leave alone */ 287 case obj.ATEXT: 288 q = p 289 290 p.Mark |= LABEL | LEAF | SYNC 291 if p.Link != nil { 292 p.Link.Mark |= LABEL 293 } 294 295 case ANOR: 296 q = p 297 if p.To.Type == obj.TYPE_REG { 298 if p.To.Reg == REGZERO { 299 p.Mark |= LABEL | SYNC 300 } 301 } 302 303 case ALWAR, 304 ASTWCCC, 305 AECIWX, 306 AECOWX, 307 AEIEIO, 308 AICBI, 309 AISYNC, 310 ATLBIE, 311 ATLBIEL, 312 ASLBIA, 313 ASLBIE, 314 ASLBMFEE, 315 ASLBMFEV, 316 ASLBMTE, 317 ADCBF, 318 ADCBI, 319 ADCBST, 320 ADCBT, 321 ADCBTST, 322 ADCBZ, 323 ASYNC, 324 ATLBSYNC, 325 APTESYNC, 326 ATW, 327 AWORD, 328 ARFI, 329 ARFCI, 330 ARFID, 331 AHRFID: 332 q = p 333 p.Mark |= LABEL | SYNC 334 continue 335 336 case AMOVW, AMOVWZ, AMOVD: 337 q = p 338 if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL { 339 p.Mark |= LABEL | SYNC 340 } 341 continue 342 343 case AFABS, 344 AFABSCC, 345 AFADD, 346 AFADDCC, 347 AFCTIW, 348 AFCTIWCC, 349 AFCTIWZ, 350 AFCTIWZCC, 351 AFDIV, 352 AFDIVCC, 353 AFMADD, 354 AFMADDCC, 355 AFMOVD, 356 AFMOVDU, 357 /* case AFMOVDS: */ 358 AFMOVS, 359 AFMOVSU, 360 361 /* case AFMOVSD: */ 362 AFMSUB, 363 AFMSUBCC, 364 AFMUL, 365 AFMULCC, 366 AFNABS, 367 AFNABSCC, 368 AFNEG, 369 AFNEGCC, 370 AFNMADD, 371 AFNMADDCC, 372 AFNMSUB, 373 AFNMSUBCC, 374 AFRSP, 375 AFRSPCC, 376 AFSUB, 377 AFSUBCC: 378 q = p 379 380 p.Mark |= FLOAT 381 continue 382 383 case ABL, 384 ABCL, 385 obj.ADUFFZERO, 386 obj.ADUFFCOPY: 387 cursym.Text.Mark &^= LEAF 388 fallthrough 389 390 case ABC, 391 ABEQ, 392 ABGE, 393 ABGT, 394 ABLE, 395 ABLT, 396 ABNE, 397 ABR, 398 ABVC, 399 ABVS: 400 p.Mark |= BRANCH 401 q = p 402 q1 = p.Pcond 403 if q1 != nil { 404 for q1.As == obj.ANOP { 405 q1 = q1.Link 406 p.Pcond = q1 407 } 408 409 if q1.Mark&LEAF == 0 { 410 q1.Mark |= LABEL 411 } 412 } else { 413 p.Mark |= LABEL 414 } 415 q1 = p.Link 416 if q1 != nil { 417 q1.Mark |= LABEL 418 } 419 continue 420 421 case AFCMPO, AFCMPU: 422 q = p 423 p.Mark |= FCMP | FLOAT 424 continue 425 426 case obj.ARET: 427 q = p 428 if p.Link != nil { 429 p.Link.Mark |= LABEL 430 } 431 continue 432 433 case obj.ANOP: 434 q1 = p.Link 435 q.Link = q1 /* q is non-nop */ 436 q1.Mark |= p.Mark 437 continue 438 439 default: 440 q = p 441 continue 442 } 443 } 444 445 autosize := int32(0) 446 var aoffset int 447 var mov obj.As 448 var p1 *obj.Prog 449 var p2 *obj.Prog 450 for p := cursym.Text; p != nil; p = p.Link { 451 o := p.As 452 switch o { 453 case obj.ATEXT: 454 mov = AMOVD 455 aoffset = 0 456 autosize = int32(textstksiz) 457 458 if p.Mark&LEAF != 0 && autosize == 0 && p.From3.Offset&obj.NOFRAME == 0 { 459 // A leaf function with no locals has no frame. 460 p.From3.Offset |= obj.NOFRAME 461 } 462 463 if p.From3.Offset&obj.NOFRAME == 0 { 464 // If there is a stack frame at all, it includes 465 // space to save the LR. 466 autosize += int32(ctxt.FixedFrameSize()) 467 } 468 469 p.To.Offset = int64(autosize) 470 471 q = p 472 473 if ctxt.Flag_shared != 0 && cursym.Name != "runtime.duffzero" && cursym.Name != "runtime.duffcopy" && cursym.Name != "runtime.stackBarrier" { 474 // When compiling Go into PIC, all functions must start 475 // with instructions to load the TOC pointer into r2: 476 // 477 // addis r2, r12, .TOC.-func@ha 478 // addi r2, r2, .TOC.-func@l+4 479 // 480 // We could probably skip this prologue in some situations 481 // but it's a bit subtle. However, it is both safe and 482 // necessary to leave the prologue off duffzero and 483 // duffcopy as we rely on being able to jump to a specific 484 // instruction offset for them, and stackBarrier is only 485 // ever called from an overwritten LR-save slot on the 486 // stack (when r12 will not be remotely the right thing) 487 // but fortunately does not access global data. 488 // 489 // These are AWORDS because there is no (afaict) way to 490 // generate the addis instruction except as part of the 491 // load of a large constant, and in that case there is no 492 // way to use r12 as the source. 493 q = obj.Appendp(ctxt, q) 494 q.As = AWORD 495 q.Lineno = p.Lineno 496 q.From.Type = obj.TYPE_CONST 497 q.From.Offset = 0x3c4c0000 498 q = obj.Appendp(ctxt, q) 499 q.As = AWORD 500 q.Lineno = p.Lineno 501 q.From.Type = obj.TYPE_CONST 502 q.From.Offset = 0x38420000 503 rel := obj.Addrel(ctxt.Cursym) 504 rel.Off = 0 505 rel.Siz = 8 506 rel.Sym = obj.Linklookup(ctxt, ".TOC.", 0) 507 rel.Type = obj.R_ADDRPOWER_PCREL 508 } 509 510 if cursym.Text.From3.Offset&obj.NOSPLIT == 0 { 511 q = stacksplit(ctxt, q, autosize) // emit split check 512 } 513 514 if autosize != 0 { 515 /* use MOVDU to adjust R1 when saving R31, if autosize is small */ 516 if cursym.Text.Mark&LEAF == 0 && autosize >= -BIG && autosize <= BIG { 517 mov = AMOVDU 518 aoffset = int(-autosize) 519 } else { 520 q = obj.Appendp(ctxt, q) 521 q.As = AADD 522 q.Lineno = p.Lineno 523 q.From.Type = obj.TYPE_CONST 524 q.From.Offset = int64(-autosize) 525 q.To.Type = obj.TYPE_REG 526 q.To.Reg = REGSP 527 q.Spadj = +autosize 528 } 529 } else if cursym.Text.Mark&LEAF == 0 { 530 // A very few functions that do not return to their caller 531 // (e.g. gogo) are not identified as leaves but still have 532 // no frame. 533 cursym.Text.Mark |= LEAF 534 } 535 536 if cursym.Text.Mark&LEAF != 0 { 537 cursym.Leaf = true 538 break 539 } 540 541 q = obj.Appendp(ctxt, q) 542 q.As = AMOVD 543 q.Lineno = p.Lineno 544 q.From.Type = obj.TYPE_REG 545 q.From.Reg = REG_LR 546 q.To.Type = obj.TYPE_REG 547 q.To.Reg = REGTMP 548 549 q = obj.Appendp(ctxt, q) 550 q.As = mov 551 q.Lineno = p.Lineno 552 q.From.Type = obj.TYPE_REG 553 q.From.Reg = REGTMP 554 q.To.Type = obj.TYPE_MEM 555 q.To.Offset = int64(aoffset) 556 q.To.Reg = REGSP 557 if q.As == AMOVDU { 558 q.Spadj = int32(-aoffset) 559 } 560 561 if ctxt.Flag_shared != 0 { 562 q = obj.Appendp(ctxt, q) 563 q.As = AMOVD 564 q.Lineno = p.Lineno 565 q.From.Type = obj.TYPE_REG 566 q.From.Reg = REG_R2 567 q.To.Type = obj.TYPE_MEM 568 q.To.Reg = REGSP 569 q.To.Offset = 24 570 } 571 572 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 573 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 574 // 575 // MOVD g_panic(g), R3 576 // CMP R0, R3 577 // BEQ end 578 // MOVD panic_argp(R3), R4 579 // ADD $(autosize+8), R1, R5 580 // CMP R4, R5 581 // BNE end 582 // ADD $8, R1, R6 583 // MOVD R6, panic_argp(R3) 584 // end: 585 // NOP 586 // 587 // The NOP is needed to give the jumps somewhere to land. 588 // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes. 589 590 q = obj.Appendp(ctxt, q) 591 592 q.As = AMOVD 593 q.From.Type = obj.TYPE_MEM 594 q.From.Reg = REGG 595 q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic 596 q.To.Type = obj.TYPE_REG 597 q.To.Reg = REG_R3 598 599 q = obj.Appendp(ctxt, q) 600 q.As = ACMP 601 q.From.Type = obj.TYPE_REG 602 q.From.Reg = REG_R0 603 q.To.Type = obj.TYPE_REG 604 q.To.Reg = REG_R3 605 606 q = obj.Appendp(ctxt, q) 607 q.As = ABEQ 608 q.To.Type = obj.TYPE_BRANCH 609 p1 = q 610 611 q = obj.Appendp(ctxt, q) 612 q.As = AMOVD 613 q.From.Type = obj.TYPE_MEM 614 q.From.Reg = REG_R3 615 q.From.Offset = 0 // Panic.argp 616 q.To.Type = obj.TYPE_REG 617 q.To.Reg = REG_R4 618 619 q = obj.Appendp(ctxt, q) 620 q.As = AADD 621 q.From.Type = obj.TYPE_CONST 622 q.From.Offset = int64(autosize) + ctxt.FixedFrameSize() 623 q.Reg = REGSP 624 q.To.Type = obj.TYPE_REG 625 q.To.Reg = REG_R5 626 627 q = obj.Appendp(ctxt, q) 628 q.As = ACMP 629 q.From.Type = obj.TYPE_REG 630 q.From.Reg = REG_R4 631 q.To.Type = obj.TYPE_REG 632 q.To.Reg = REG_R5 633 634 q = obj.Appendp(ctxt, q) 635 q.As = ABNE 636 q.To.Type = obj.TYPE_BRANCH 637 p2 = q 638 639 q = obj.Appendp(ctxt, q) 640 q.As = AADD 641 q.From.Type = obj.TYPE_CONST 642 q.From.Offset = ctxt.FixedFrameSize() 643 q.Reg = REGSP 644 q.To.Type = obj.TYPE_REG 645 q.To.Reg = REG_R6 646 647 q = obj.Appendp(ctxt, q) 648 q.As = AMOVD 649 q.From.Type = obj.TYPE_REG 650 q.From.Reg = REG_R6 651 q.To.Type = obj.TYPE_MEM 652 q.To.Reg = REG_R3 653 q.To.Offset = 0 // Panic.argp 654 655 q = obj.Appendp(ctxt, q) 656 657 q.As = obj.ANOP 658 p1.Pcond = q 659 p2.Pcond = q 660 } 661 662 case obj.ARET: 663 if p.From.Type == obj.TYPE_CONST { 664 ctxt.Diag("using BECOME (%v) is not supported!", p) 665 break 666 } 667 668 retTarget := p.To.Sym 669 670 if cursym.Text.Mark&LEAF != 0 { 671 if autosize == 0 { 672 p.As = ABR 673 p.From = obj.Addr{} 674 if retTarget == nil { 675 p.To.Type = obj.TYPE_REG 676 p.To.Reg = REG_LR 677 } else { 678 p.To.Type = obj.TYPE_BRANCH 679 p.To.Sym = retTarget 680 } 681 p.Mark |= BRANCH 682 break 683 } 684 685 p.As = AADD 686 p.From.Type = obj.TYPE_CONST 687 p.From.Offset = int64(autosize) 688 p.To.Type = obj.TYPE_REG 689 p.To.Reg = REGSP 690 p.Spadj = -autosize 691 692 q = ctxt.NewProg() 693 q.As = ABR 694 q.Lineno = p.Lineno 695 q.To.Type = obj.TYPE_REG 696 q.To.Reg = REG_LR 697 q.Mark |= BRANCH 698 q.Spadj = +autosize 699 700 q.Link = p.Link 701 p.Link = q 702 break 703 } 704 705 p.As = AMOVD 706 p.From.Type = obj.TYPE_MEM 707 p.From.Offset = 0 708 p.From.Reg = REGSP 709 p.To.Type = obj.TYPE_REG 710 p.To.Reg = REGTMP 711 712 q = ctxt.NewProg() 713 q.As = AMOVD 714 q.Lineno = p.Lineno 715 q.From.Type = obj.TYPE_REG 716 q.From.Reg = REGTMP 717 q.To.Type = obj.TYPE_REG 718 q.To.Reg = REG_LR 719 720 q.Link = p.Link 721 p.Link = q 722 p = q 723 724 if false { 725 // Debug bad returns 726 q = ctxt.NewProg() 727 728 q.As = AMOVD 729 q.Lineno = p.Lineno 730 q.From.Type = obj.TYPE_MEM 731 q.From.Offset = 0 732 q.From.Reg = REGTMP 733 q.To.Type = obj.TYPE_REG 734 q.To.Reg = REGTMP 735 736 q.Link = p.Link 737 p.Link = q 738 p = q 739 } 740 741 if autosize != 0 { 742 q = ctxt.NewProg() 743 q.As = AADD 744 q.Lineno = p.Lineno 745 q.From.Type = obj.TYPE_CONST 746 q.From.Offset = int64(autosize) 747 q.To.Type = obj.TYPE_REG 748 q.To.Reg = REGSP 749 q.Spadj = -autosize 750 751 q.Link = p.Link 752 p.Link = q 753 } 754 755 q1 = ctxt.NewProg() 756 q1.As = ABR 757 q1.Lineno = p.Lineno 758 if retTarget == nil { 759 q1.To.Type = obj.TYPE_REG 760 q1.To.Reg = REG_LR 761 } else { 762 q1.To.Type = obj.TYPE_BRANCH 763 q1.To.Sym = retTarget 764 } 765 q1.Mark |= BRANCH 766 q1.Spadj = +autosize 767 768 q1.Link = q.Link 769 q.Link = q1 770 case AADD: 771 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 772 p.Spadj = int32(-p.From.Offset) 773 } 774 } 775 } 776 } 777 778 /* 779 // instruction scheduling 780 if(debug['Q'] == 0) 781 return; 782 783 curtext = nil; 784 q = nil; // p - 1 785 q1 = firstp; // top of block 786 o = 0; // count of instructions 787 for(p = firstp; p != nil; p = p1) { 788 p1 = p->link; 789 o++; 790 if(p->mark & NOSCHED){ 791 if(q1 != p){ 792 sched(q1, q); 793 } 794 for(; p != nil; p = p->link){ 795 if(!(p->mark & NOSCHED)) 796 break; 797 q = p; 798 } 799 p1 = p; 800 q1 = p; 801 o = 0; 802 continue; 803 } 804 if(p->mark & (LABEL|SYNC)) { 805 if(q1 != p) 806 sched(q1, q); 807 q1 = p; 808 o = 1; 809 } 810 if(p->mark & (BRANCH|SYNC)) { 811 sched(q1, p); 812 q1 = p1; 813 o = 0; 814 } 815 if(o >= NSCHED) { 816 sched(q1, p); 817 q1 = p1; 818 o = 0; 819 } 820 q = p; 821 } 822 */ 823 func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog { 824 // MOVD g_stackguard(g), R3 825 p = obj.Appendp(ctxt, p) 826 827 p.As = AMOVD 828 p.From.Type = obj.TYPE_MEM 829 p.From.Reg = REGG 830 p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0 831 if ctxt.Cursym.Cfunc { 832 p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1 833 } 834 p.To.Type = obj.TYPE_REG 835 p.To.Reg = REG_R3 836 837 var q *obj.Prog 838 if framesize <= obj.StackSmall { 839 // small stack: SP < stackguard 840 // CMP stackguard, SP 841 p = obj.Appendp(ctxt, p) 842 843 p.As = ACMPU 844 p.From.Type = obj.TYPE_REG 845 p.From.Reg = REG_R3 846 p.To.Type = obj.TYPE_REG 847 p.To.Reg = REGSP 848 } else if framesize <= obj.StackBig { 849 // large stack: SP-framesize < stackguard-StackSmall 850 // ADD $-framesize, SP, R4 851 // CMP stackguard, R4 852 p = obj.Appendp(ctxt, p) 853 854 p.As = AADD 855 p.From.Type = obj.TYPE_CONST 856 p.From.Offset = int64(-framesize) 857 p.Reg = REGSP 858 p.To.Type = obj.TYPE_REG 859 p.To.Reg = REG_R4 860 861 p = obj.Appendp(ctxt, p) 862 p.As = ACMPU 863 p.From.Type = obj.TYPE_REG 864 p.From.Reg = REG_R3 865 p.To.Type = obj.TYPE_REG 866 p.To.Reg = REG_R4 867 } else { 868 // Such a large stack we need to protect against wraparound. 869 // If SP is close to zero: 870 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 871 // The +StackGuard on both sides is required to keep the left side positive: 872 // SP is allowed to be slightly below stackguard. See stack.h. 873 // 874 // Preemption sets stackguard to StackPreempt, a very large value. 875 // That breaks the math above, so we have to check for that explicitly. 876 // // stackguard is R3 877 // CMP R3, $StackPreempt 878 // BEQ label-of-call-to-morestack 879 // ADD $StackGuard, SP, R4 880 // SUB R3, R4 881 // MOVD $(framesize+(StackGuard-StackSmall)), R31 882 // CMPU R31, R4 883 p = obj.Appendp(ctxt, p) 884 885 p.As = ACMP 886 p.From.Type = obj.TYPE_REG 887 p.From.Reg = REG_R3 888 p.To.Type = obj.TYPE_CONST 889 p.To.Offset = obj.StackPreempt 890 891 p = obj.Appendp(ctxt, p) 892 q = p 893 p.As = ABEQ 894 p.To.Type = obj.TYPE_BRANCH 895 896 p = obj.Appendp(ctxt, p) 897 p.As = AADD 898 p.From.Type = obj.TYPE_CONST 899 p.From.Offset = obj.StackGuard 900 p.Reg = REGSP 901 p.To.Type = obj.TYPE_REG 902 p.To.Reg = REG_R4 903 904 p = obj.Appendp(ctxt, p) 905 p.As = ASUB 906 p.From.Type = obj.TYPE_REG 907 p.From.Reg = REG_R3 908 p.To.Type = obj.TYPE_REG 909 p.To.Reg = REG_R4 910 911 p = obj.Appendp(ctxt, p) 912 p.As = AMOVD 913 p.From.Type = obj.TYPE_CONST 914 p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall 915 p.To.Type = obj.TYPE_REG 916 p.To.Reg = REGTMP 917 918 p = obj.Appendp(ctxt, p) 919 p.As = ACMPU 920 p.From.Type = obj.TYPE_REG 921 p.From.Reg = REGTMP 922 p.To.Type = obj.TYPE_REG 923 p.To.Reg = REG_R4 924 } 925 926 // q1: BLT done 927 p = obj.Appendp(ctxt, p) 928 q1 := p 929 930 p.As = ABLT 931 p.To.Type = obj.TYPE_BRANCH 932 933 // MOVD LR, R5 934 p = obj.Appendp(ctxt, p) 935 936 p.As = AMOVD 937 p.From.Type = obj.TYPE_REG 938 p.From.Reg = REG_LR 939 p.To.Type = obj.TYPE_REG 940 p.To.Reg = REG_R5 941 if q != nil { 942 q.Pcond = p 943 } 944 945 var morestacksym *obj.LSym 946 if ctxt.Cursym.Cfunc { 947 morestacksym = obj.Linklookup(ctxt, "runtime.morestackc", 0) 948 } else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 { 949 morestacksym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0) 950 } else { 951 morestacksym = obj.Linklookup(ctxt, "runtime.morestack", 0) 952 } 953 954 if ctxt.Flag_dynlink { 955 // Avoid calling morestack via a PLT when dynamically linking. The 956 // PLT stubs generated by the system linker on ppc64le when "std r2, 957 // 24(r1)" to save the TOC pointer in their callers stack 958 // frame. Unfortunately (and necessarily) morestack is called before 959 // the function that calls it sets up its frame and so the PLT ends 960 // up smashing the saved TOC pointer for its caller's caller. 961 // 962 // According to the ABI documentation there is a mechanism to avoid 963 // the TOC save that the PLT stub does (put a R_PPC64_TOCSAVE 964 // relocation on the nop after the call to morestack) but at the time 965 // of writing it is not supported at all by gold and my attempt to 966 // use it with ld.bfd caused an internal linker error. So this hack 967 // seems preferable. 968 969 // MOVD $runtime.morestack(SB), R12 970 p = obj.Appendp(ctxt, p) 971 p.As = AMOVD 972 p.From.Type = obj.TYPE_MEM 973 p.From.Sym = morestacksym 974 p.From.Name = obj.NAME_GOTREF 975 p.To.Type = obj.TYPE_REG 976 p.To.Reg = REG_R12 977 978 // MOVD R12, CTR 979 p = obj.Appendp(ctxt, p) 980 p.As = AMOVD 981 p.From.Type = obj.TYPE_REG 982 p.From.Reg = REG_R12 983 p.To.Type = obj.TYPE_REG 984 p.To.Reg = REG_CTR 985 986 // BL CTR 987 p = obj.Appendp(ctxt, p) 988 p.As = obj.ACALL 989 p.From.Type = obj.TYPE_REG 990 p.From.Reg = REG_R12 991 p.To.Type = obj.TYPE_REG 992 p.To.Reg = REG_CTR 993 } else { 994 // BL runtime.morestack(SB) 995 p = obj.Appendp(ctxt, p) 996 997 p.As = ABL 998 p.To.Type = obj.TYPE_BRANCH 999 p.To.Sym = morestacksym 1000 } 1001 // BR start 1002 p = obj.Appendp(ctxt, p) 1003 1004 p.As = ABR 1005 p.To.Type = obj.TYPE_BRANCH 1006 p.Pcond = ctxt.Cursym.Text.Link 1007 1008 // placeholder for q1's jump target 1009 p = obj.Appendp(ctxt, p) 1010 1011 p.As = obj.ANOP // zero-width place holder 1012 q1.Pcond = p 1013 1014 return p 1015 } 1016 1017 func follow(ctxt *obj.Link, s *obj.LSym) { 1018 ctxt.Cursym = s 1019 1020 firstp := ctxt.NewProg() 1021 lastp := firstp 1022 xfol(ctxt, s.Text, &lastp) 1023 lastp.Link = nil 1024 s.Text = firstp.Link 1025 } 1026 1027 func relinv(a obj.As) obj.As { 1028 switch a { 1029 case ABEQ: 1030 return ABNE 1031 case ABNE: 1032 return ABEQ 1033 1034 case ABGE: 1035 return ABLT 1036 case ABLT: 1037 return ABGE 1038 1039 case ABGT: 1040 return ABLE 1041 case ABLE: 1042 return ABGT 1043 1044 case ABVC: 1045 return ABVS 1046 case ABVS: 1047 return ABVC 1048 } 1049 1050 return 0 1051 } 1052 1053 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 1054 var q *obj.Prog 1055 var r *obj.Prog 1056 var b obj.As 1057 var i int 1058 1059 loop: 1060 if p == nil { 1061 return 1062 } 1063 a := p.As 1064 if a == ABR { 1065 q = p.Pcond 1066 if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) { 1067 p.Mark |= FOLL 1068 (*last).Link = p 1069 *last = p 1070 p = p.Link 1071 xfol(ctxt, p, last) 1072 p = q 1073 if p != nil && p.Mark&FOLL == 0 { 1074 goto loop 1075 } 1076 return 1077 } 1078 1079 if q != nil { 1080 p.Mark |= FOLL 1081 p = q 1082 if p.Mark&FOLL == 0 { 1083 goto loop 1084 } 1085 } 1086 } 1087 1088 if p.Mark&FOLL != 0 { 1089 i = 0 1090 q = p 1091 for ; i < 4; i, q = i+1, q.Link { 1092 if q == *last || (q.Mark&NOSCHED != 0) { 1093 break 1094 } 1095 b = 0 /* set */ 1096 a = q.As 1097 if a == obj.ANOP { 1098 i-- 1099 continue 1100 } 1101 1102 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 1103 goto copy 1104 } 1105 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 1106 continue 1107 } 1108 b = relinv(a) 1109 if b == 0 { 1110 continue 1111 } 1112 1113 copy: 1114 for { 1115 r = ctxt.NewProg() 1116 *r = *p 1117 if r.Mark&FOLL == 0 { 1118 fmt.Printf("can't happen 1\n") 1119 } 1120 r.Mark |= FOLL 1121 if p != q { 1122 p = p.Link 1123 (*last).Link = r 1124 *last = r 1125 continue 1126 } 1127 1128 (*last).Link = r 1129 *last = r 1130 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 1131 return 1132 } 1133 r.As = b 1134 r.Pcond = p.Link 1135 r.Link = p.Pcond 1136 if r.Link.Mark&FOLL == 0 { 1137 xfol(ctxt, r.Link, last) 1138 } 1139 if r.Pcond.Mark&FOLL == 0 { 1140 fmt.Printf("can't happen 2\n") 1141 } 1142 return 1143 } 1144 } 1145 1146 a = ABR 1147 q = ctxt.NewProg() 1148 q.As = a 1149 q.Lineno = p.Lineno 1150 q.To.Type = obj.TYPE_BRANCH 1151 q.To.Offset = p.Pc 1152 q.Pcond = p 1153 p = q 1154 } 1155 1156 p.Mark |= FOLL 1157 (*last).Link = p 1158 *last = p 1159 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 1160 if p.Mark&NOSCHED != 0 { 1161 p = p.Link 1162 goto loop 1163 } 1164 1165 return 1166 } 1167 1168 if p.Pcond != nil { 1169 if a != ABL && p.Link != nil { 1170 xfol(ctxt, p.Link, last) 1171 p = p.Pcond 1172 if p == nil || (p.Mark&FOLL != 0) { 1173 return 1174 } 1175 goto loop 1176 } 1177 } 1178 1179 p = p.Link 1180 goto loop 1181 } 1182 1183 var Linkppc64 = obj.LinkArch{ 1184 ByteOrder: binary.BigEndian, 1185 Name: "ppc64", 1186 Thechar: '9', 1187 Preprocess: preprocess, 1188 Assemble: span9, 1189 Follow: follow, 1190 Progedit: progedit, 1191 Minlc: 4, 1192 Ptrsize: 8, 1193 Regsize: 8, 1194 } 1195 1196 var Linkppc64le = obj.LinkArch{ 1197 ByteOrder: binary.LittleEndian, 1198 Name: "ppc64le", 1199 Thechar: '9', 1200 Preprocess: preprocess, 1201 Assemble: span9, 1202 Follow: follow, 1203 Progedit: progedit, 1204 Minlc: 4, 1205 Ptrsize: 8, 1206 Regsize: 8, 1207 }