github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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 "cmd/internal/sys" 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.Set(obj.AttrLocal, 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.Set(obj.AttrLocal, 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.Set(obj.AttrLocal, 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 ctxt.Logf("%5.2f noops\n", obj.Cputime()) 279 } 280 281 var q *obj.Prog 282 var q1 *obj.Prog 283 for p := cursym.Text; p != nil; p = p.Link { 284 switch p.As { 285 /* too hard, just leave alone */ 286 case obj.ATEXT: 287 q = p 288 289 p.Mark |= LABEL | LEAF | SYNC 290 if p.Link != nil { 291 p.Link.Mark |= LABEL 292 } 293 294 case ANOR: 295 q = p 296 if p.To.Type == obj.TYPE_REG { 297 if p.To.Reg == REGZERO { 298 p.Mark |= LABEL | SYNC 299 } 300 } 301 302 case ALWAR, 303 ALBAR, 304 ASTBCCC, 305 ASTWCCC, 306 AECIWX, 307 AECOWX, 308 AEIEIO, 309 AICBI, 310 AISYNC, 311 ATLBIE, 312 ATLBIEL, 313 ASLBIA, 314 ASLBIE, 315 ASLBMFEE, 316 ASLBMFEV, 317 ASLBMTE, 318 ADCBF, 319 ADCBI, 320 ADCBST, 321 ADCBT, 322 ADCBTST, 323 ADCBZ, 324 ASYNC, 325 ATLBSYNC, 326 APTESYNC, 327 ALWSYNC, 328 ATW, 329 AWORD, 330 ARFI, 331 ARFCI, 332 ARFID, 333 AHRFID: 334 q = p 335 p.Mark |= LABEL | SYNC 336 continue 337 338 case AMOVW, AMOVWZ, AMOVD: 339 q = p 340 if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL { 341 p.Mark |= LABEL | SYNC 342 } 343 continue 344 345 case AFABS, 346 AFABSCC, 347 AFADD, 348 AFADDCC, 349 AFCTIW, 350 AFCTIWCC, 351 AFCTIWZ, 352 AFCTIWZCC, 353 AFDIV, 354 AFDIVCC, 355 AFMADD, 356 AFMADDCC, 357 AFMOVD, 358 AFMOVDU, 359 /* case AFMOVDS: */ 360 AFMOVS, 361 AFMOVSU, 362 363 /* case AFMOVSD: */ 364 AFMSUB, 365 AFMSUBCC, 366 AFMUL, 367 AFMULCC, 368 AFNABS, 369 AFNABSCC, 370 AFNEG, 371 AFNEGCC, 372 AFNMADD, 373 AFNMADDCC, 374 AFNMSUB, 375 AFNMSUBCC, 376 AFRSP, 377 AFRSPCC, 378 AFSUB, 379 AFSUBCC: 380 q = p 381 382 p.Mark |= FLOAT 383 continue 384 385 case ABL, 386 ABCL, 387 obj.ADUFFZERO, 388 obj.ADUFFCOPY: 389 cursym.Text.Mark &^= LEAF 390 fallthrough 391 392 case ABC, 393 ABEQ, 394 ABGE, 395 ABGT, 396 ABLE, 397 ABLT, 398 ABNE, 399 ABR, 400 ABVC, 401 ABVS: 402 p.Mark |= BRANCH 403 q = p 404 q1 = p.Pcond 405 if q1 != nil { 406 for q1.As == obj.ANOP { 407 q1 = q1.Link 408 p.Pcond = q1 409 } 410 411 if q1.Mark&LEAF == 0 { 412 q1.Mark |= LABEL 413 } 414 } else { 415 p.Mark |= LABEL 416 } 417 q1 = p.Link 418 if q1 != nil { 419 q1.Mark |= LABEL 420 } 421 continue 422 423 case AFCMPO, AFCMPU: 424 q = p 425 p.Mark |= FCMP | FLOAT 426 continue 427 428 case obj.ARET: 429 q = p 430 if p.Link != nil { 431 p.Link.Mark |= LABEL 432 } 433 continue 434 435 case obj.ANOP: 436 q1 = p.Link 437 q.Link = q1 /* q is non-nop */ 438 q1.Mark |= p.Mark 439 continue 440 441 default: 442 q = p 443 continue 444 } 445 } 446 447 autosize := int32(0) 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 autosize = int32(textstksiz) 455 456 if p.Mark&LEAF != 0 && autosize == 0 { 457 // A leaf function with no locals has no frame. 458 p.From3.Offset |= obj.NOFRAME 459 } 460 461 if p.From3.Offset&obj.NOFRAME == 0 { 462 // If there is a stack frame at all, it includes 463 // space to save the LR. 464 autosize += int32(ctxt.FixedFrameSize()) 465 } 466 467 if p.Mark&LEAF != 0 && autosize < obj.StackSmall { 468 // A leaf function with a small stack can be marked 469 // NOSPLIT, avoiding a stack check. 470 p.From3.Offset |= obj.NOSPLIT 471 } 472 473 p.To.Offset = int64(autosize) 474 475 q = p 476 477 if ctxt.Flag_shared && cursym.Name != "runtime.duffzero" && cursym.Name != "runtime.duffcopy" && cursym.Name != "runtime.stackBarrier" { 478 // When compiling Go into PIC, all functions must start 479 // with instructions to load the TOC pointer into r2: 480 // 481 // addis r2, r12, .TOC.-func@ha 482 // addi r2, r2, .TOC.-func@l+4 483 // 484 // We could probably skip this prologue in some situations 485 // but it's a bit subtle. However, it is both safe and 486 // necessary to leave the prologue off duffzero and 487 // duffcopy as we rely on being able to jump to a specific 488 // instruction offset for them, and stackBarrier is only 489 // ever called from an overwritten LR-save slot on the 490 // stack (when r12 will not be remotely the right thing) 491 // but fortunately does not access global data. 492 // 493 // These are AWORDS because there is no (afaict) way to 494 // generate the addis instruction except as part of the 495 // load of a large constant, and in that case there is no 496 // way to use r12 as the source. 497 q = obj.Appendp(ctxt, q) 498 q.As = AWORD 499 q.Lineno = p.Lineno 500 q.From.Type = obj.TYPE_CONST 501 q.From.Offset = 0x3c4c0000 502 q = obj.Appendp(ctxt, q) 503 q.As = AWORD 504 q.Lineno = p.Lineno 505 q.From.Type = obj.TYPE_CONST 506 q.From.Offset = 0x38420000 507 rel := obj.Addrel(ctxt.Cursym) 508 rel.Off = 0 509 rel.Siz = 8 510 rel.Sym = obj.Linklookup(ctxt, ".TOC.", 0) 511 rel.Type = obj.R_ADDRPOWER_PCREL 512 } 513 514 if cursym.Text.From3.Offset&obj.NOSPLIT == 0 { 515 q = stacksplit(ctxt, q, autosize) // emit split check 516 } 517 518 if autosize != 0 { 519 // Make sure to save link register for non-empty frame, even if 520 // it is a leaf function, so that traceback works. 521 if cursym.Text.Mark&LEAF == 0 && autosize >= -BIG && autosize <= BIG { 522 // Use MOVDU to adjust R1 when saving R31, if autosize is small. 523 q = obj.Appendp(ctxt, q) 524 q.As = AMOVD 525 q.Lineno = p.Lineno 526 q.From.Type = obj.TYPE_REG 527 q.From.Reg = REG_LR 528 q.To.Type = obj.TYPE_REG 529 q.To.Reg = REGTMP 530 531 q = obj.Appendp(ctxt, q) 532 q.As = AMOVDU 533 q.Lineno = p.Lineno 534 q.From.Type = obj.TYPE_REG 535 q.From.Reg = REGTMP 536 q.To.Type = obj.TYPE_MEM 537 q.To.Offset = int64(-autosize) 538 q.To.Reg = REGSP 539 q.Spadj = int32(autosize) 540 } else { 541 // Frame size is too large for a MOVDU instruction. 542 // Store link register before decrementing SP, so if a signal comes 543 // during the execution of the function prologue, the traceback 544 // code will not see a half-updated stack frame. 545 q = obj.Appendp(ctxt, q) 546 q.As = AMOVD 547 q.Lineno = p.Lineno 548 q.From.Type = obj.TYPE_REG 549 q.From.Reg = REG_LR 550 q.To.Type = obj.TYPE_REG 551 q.To.Reg = REG_R29 // REGTMP may be used to synthesize large offset in the next instruction 552 553 q = obj.Appendp(ctxt, q) 554 q.As = AMOVD 555 q.Lineno = p.Lineno 556 q.From.Type = obj.TYPE_REG 557 q.From.Reg = REG_R29 558 q.To.Type = obj.TYPE_MEM 559 q.To.Offset = int64(-autosize) 560 q.To.Reg = REGSP 561 562 q = obj.Appendp(ctxt, q) 563 q.As = AADD 564 q.Lineno = p.Lineno 565 q.From.Type = obj.TYPE_CONST 566 q.From.Offset = int64(-autosize) 567 q.To.Type = obj.TYPE_REG 568 q.To.Reg = REGSP 569 q.Spadj = +autosize 570 } 571 } else if cursym.Text.Mark&LEAF == 0 { 572 // A very few functions that do not return to their caller 573 // (e.g. gogo) are not identified as leaves but still have 574 // no frame. 575 cursym.Text.Mark |= LEAF 576 } 577 578 if cursym.Text.Mark&LEAF != 0 { 579 cursym.Set(obj.AttrLeaf, true) 580 break 581 } 582 583 if ctxt.Flag_shared { 584 q = obj.Appendp(ctxt, q) 585 q.As = AMOVD 586 q.Lineno = p.Lineno 587 q.From.Type = obj.TYPE_REG 588 q.From.Reg = REG_R2 589 q.To.Type = obj.TYPE_MEM 590 q.To.Reg = REGSP 591 q.To.Offset = 24 592 } 593 594 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 595 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 596 // 597 // MOVD g_panic(g), R3 598 // CMP R0, R3 599 // BEQ end 600 // MOVD panic_argp(R3), R4 601 // ADD $(autosize+8), R1, R5 602 // CMP R4, R5 603 // BNE end 604 // ADD $8, R1, R6 605 // MOVD R6, panic_argp(R3) 606 // end: 607 // NOP 608 // 609 // The NOP is needed to give the jumps somewhere to land. 610 // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes. 611 612 q = obj.Appendp(ctxt, q) 613 614 q.As = AMOVD 615 q.From.Type = obj.TYPE_MEM 616 q.From.Reg = REGG 617 q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic 618 q.To.Type = obj.TYPE_REG 619 q.To.Reg = REG_R3 620 621 q = obj.Appendp(ctxt, q) 622 q.As = ACMP 623 q.From.Type = obj.TYPE_REG 624 q.From.Reg = REG_R0 625 q.To.Type = obj.TYPE_REG 626 q.To.Reg = REG_R3 627 628 q = obj.Appendp(ctxt, q) 629 q.As = ABEQ 630 q.To.Type = obj.TYPE_BRANCH 631 p1 = q 632 633 q = obj.Appendp(ctxt, q) 634 q.As = AMOVD 635 q.From.Type = obj.TYPE_MEM 636 q.From.Reg = REG_R3 637 q.From.Offset = 0 // Panic.argp 638 q.To.Type = obj.TYPE_REG 639 q.To.Reg = REG_R4 640 641 q = obj.Appendp(ctxt, q) 642 q.As = AADD 643 q.From.Type = obj.TYPE_CONST 644 q.From.Offset = int64(autosize) + ctxt.FixedFrameSize() 645 q.Reg = REGSP 646 q.To.Type = obj.TYPE_REG 647 q.To.Reg = REG_R5 648 649 q = obj.Appendp(ctxt, q) 650 q.As = ACMP 651 q.From.Type = obj.TYPE_REG 652 q.From.Reg = REG_R4 653 q.To.Type = obj.TYPE_REG 654 q.To.Reg = REG_R5 655 656 q = obj.Appendp(ctxt, q) 657 q.As = ABNE 658 q.To.Type = obj.TYPE_BRANCH 659 p2 = q 660 661 q = obj.Appendp(ctxt, q) 662 q.As = AADD 663 q.From.Type = obj.TYPE_CONST 664 q.From.Offset = ctxt.FixedFrameSize() 665 q.Reg = REGSP 666 q.To.Type = obj.TYPE_REG 667 q.To.Reg = REG_R6 668 669 q = obj.Appendp(ctxt, q) 670 q.As = AMOVD 671 q.From.Type = obj.TYPE_REG 672 q.From.Reg = REG_R6 673 q.To.Type = obj.TYPE_MEM 674 q.To.Reg = REG_R3 675 q.To.Offset = 0 // Panic.argp 676 677 q = obj.Appendp(ctxt, q) 678 679 q.As = obj.ANOP 680 p1.Pcond = q 681 p2.Pcond = q 682 } 683 684 case obj.ARET: 685 if p.From.Type == obj.TYPE_CONST { 686 ctxt.Diag("using BECOME (%v) is not supported!", p) 687 break 688 } 689 690 retTarget := p.To.Sym 691 692 if cursym.Text.Mark&LEAF != 0 { 693 if autosize == 0 { 694 p.As = ABR 695 p.From = obj.Addr{} 696 if retTarget == nil { 697 p.To.Type = obj.TYPE_REG 698 p.To.Reg = REG_LR 699 } else { 700 p.To.Type = obj.TYPE_BRANCH 701 p.To.Sym = retTarget 702 } 703 p.Mark |= BRANCH 704 break 705 } 706 707 p.As = AADD 708 p.From.Type = obj.TYPE_CONST 709 p.From.Offset = int64(autosize) 710 p.To.Type = obj.TYPE_REG 711 p.To.Reg = REGSP 712 p.Spadj = -autosize 713 714 q = ctxt.NewProg() 715 q.As = ABR 716 q.Lineno = p.Lineno 717 q.To.Type = obj.TYPE_REG 718 q.To.Reg = REG_LR 719 q.Mark |= BRANCH 720 q.Spadj = +autosize 721 722 q.Link = p.Link 723 p.Link = q 724 break 725 } 726 727 p.As = AMOVD 728 p.From.Type = obj.TYPE_MEM 729 p.From.Offset = 0 730 p.From.Reg = REGSP 731 p.To.Type = obj.TYPE_REG 732 p.To.Reg = REGTMP 733 734 q = ctxt.NewProg() 735 q.As = AMOVD 736 q.Lineno = p.Lineno 737 q.From.Type = obj.TYPE_REG 738 q.From.Reg = REGTMP 739 q.To.Type = obj.TYPE_REG 740 q.To.Reg = REG_LR 741 742 q.Link = p.Link 743 p.Link = q 744 p = q 745 746 if false { 747 // Debug bad returns 748 q = ctxt.NewProg() 749 750 q.As = AMOVD 751 q.Lineno = p.Lineno 752 q.From.Type = obj.TYPE_MEM 753 q.From.Offset = 0 754 q.From.Reg = REGTMP 755 q.To.Type = obj.TYPE_REG 756 q.To.Reg = REGTMP 757 758 q.Link = p.Link 759 p.Link = q 760 p = q 761 } 762 763 if autosize != 0 { 764 q = ctxt.NewProg() 765 q.As = AADD 766 q.Lineno = p.Lineno 767 q.From.Type = obj.TYPE_CONST 768 q.From.Offset = int64(autosize) 769 q.To.Type = obj.TYPE_REG 770 q.To.Reg = REGSP 771 q.Spadj = -autosize 772 773 q.Link = p.Link 774 p.Link = q 775 } 776 777 q1 = ctxt.NewProg() 778 q1.As = ABR 779 q1.Lineno = p.Lineno 780 if retTarget == nil { 781 q1.To.Type = obj.TYPE_REG 782 q1.To.Reg = REG_LR 783 } else { 784 q1.To.Type = obj.TYPE_BRANCH 785 q1.To.Sym = retTarget 786 } 787 q1.Mark |= BRANCH 788 q1.Spadj = +autosize 789 790 q1.Link = q.Link 791 q.Link = q1 792 case AADD: 793 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 794 p.Spadj = int32(-p.From.Offset) 795 } 796 } 797 } 798 } 799 800 /* 801 // instruction scheduling 802 if(debug['Q'] == 0) 803 return; 804 805 curtext = nil; 806 q = nil; // p - 1 807 q1 = firstp; // top of block 808 o = 0; // count of instructions 809 for(p = firstp; p != nil; p = p1) { 810 p1 = p->link; 811 o++; 812 if(p->mark & NOSCHED){ 813 if(q1 != p){ 814 sched(q1, q); 815 } 816 for(; p != nil; p = p->link){ 817 if(!(p->mark & NOSCHED)) 818 break; 819 q = p; 820 } 821 p1 = p; 822 q1 = p; 823 o = 0; 824 continue; 825 } 826 if(p->mark & (LABEL|SYNC)) { 827 if(q1 != p) 828 sched(q1, q); 829 q1 = p; 830 o = 1; 831 } 832 if(p->mark & (BRANCH|SYNC)) { 833 sched(q1, p); 834 q1 = p1; 835 o = 0; 836 } 837 if(o >= NSCHED) { 838 sched(q1, p); 839 q1 = p1; 840 o = 0; 841 } 842 q = p; 843 } 844 */ 845 func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog { 846 p0 := p // save entry point, but skipping the two instructions setting R2 in shared mode 847 848 // MOVD g_stackguard(g), R3 849 p = obj.Appendp(ctxt, p) 850 851 p.As = AMOVD 852 p.From.Type = obj.TYPE_MEM 853 p.From.Reg = REGG 854 p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0 855 if ctxt.Cursym.CFunc() { 856 p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1 857 } 858 p.To.Type = obj.TYPE_REG 859 p.To.Reg = REG_R3 860 861 var q *obj.Prog 862 if framesize <= obj.StackSmall { 863 // small stack: SP < stackguard 864 // CMP stackguard, SP 865 p = obj.Appendp(ctxt, p) 866 867 p.As = ACMPU 868 p.From.Type = obj.TYPE_REG 869 p.From.Reg = REG_R3 870 p.To.Type = obj.TYPE_REG 871 p.To.Reg = REGSP 872 } else if framesize <= obj.StackBig { 873 // large stack: SP-framesize < stackguard-StackSmall 874 // ADD $-framesize, SP, R4 875 // CMP stackguard, R4 876 p = obj.Appendp(ctxt, p) 877 878 p.As = AADD 879 p.From.Type = obj.TYPE_CONST 880 p.From.Offset = int64(-framesize) 881 p.Reg = REGSP 882 p.To.Type = obj.TYPE_REG 883 p.To.Reg = REG_R4 884 885 p = obj.Appendp(ctxt, p) 886 p.As = ACMPU 887 p.From.Type = obj.TYPE_REG 888 p.From.Reg = REG_R3 889 p.To.Type = obj.TYPE_REG 890 p.To.Reg = REG_R4 891 } else { 892 // Such a large stack we need to protect against wraparound. 893 // If SP is close to zero: 894 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 895 // The +StackGuard on both sides is required to keep the left side positive: 896 // SP is allowed to be slightly below stackguard. See stack.h. 897 // 898 // Preemption sets stackguard to StackPreempt, a very large value. 899 // That breaks the math above, so we have to check for that explicitly. 900 // // stackguard is R3 901 // CMP R3, $StackPreempt 902 // BEQ label-of-call-to-morestack 903 // ADD $StackGuard, SP, R4 904 // SUB R3, R4 905 // MOVD $(framesize+(StackGuard-StackSmall)), R31 906 // CMPU R31, R4 907 p = obj.Appendp(ctxt, p) 908 909 p.As = ACMP 910 p.From.Type = obj.TYPE_REG 911 p.From.Reg = REG_R3 912 p.To.Type = obj.TYPE_CONST 913 p.To.Offset = obj.StackPreempt 914 915 p = obj.Appendp(ctxt, p) 916 q = p 917 p.As = ABEQ 918 p.To.Type = obj.TYPE_BRANCH 919 920 p = obj.Appendp(ctxt, p) 921 p.As = AADD 922 p.From.Type = obj.TYPE_CONST 923 p.From.Offset = obj.StackGuard 924 p.Reg = REGSP 925 p.To.Type = obj.TYPE_REG 926 p.To.Reg = REG_R4 927 928 p = obj.Appendp(ctxt, p) 929 p.As = ASUB 930 p.From.Type = obj.TYPE_REG 931 p.From.Reg = REG_R3 932 p.To.Type = obj.TYPE_REG 933 p.To.Reg = REG_R4 934 935 p = obj.Appendp(ctxt, p) 936 p.As = AMOVD 937 p.From.Type = obj.TYPE_CONST 938 p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall 939 p.To.Type = obj.TYPE_REG 940 p.To.Reg = REGTMP 941 942 p = obj.Appendp(ctxt, p) 943 p.As = ACMPU 944 p.From.Type = obj.TYPE_REG 945 p.From.Reg = REGTMP 946 p.To.Type = obj.TYPE_REG 947 p.To.Reg = REG_R4 948 } 949 950 // q1: BLT done 951 p = obj.Appendp(ctxt, p) 952 q1 := p 953 954 p.As = ABLT 955 p.To.Type = obj.TYPE_BRANCH 956 957 // MOVD LR, R5 958 p = obj.Appendp(ctxt, p) 959 960 p.As = AMOVD 961 p.From.Type = obj.TYPE_REG 962 p.From.Reg = REG_LR 963 p.To.Type = obj.TYPE_REG 964 p.To.Reg = REG_R5 965 if q != nil { 966 q.Pcond = p 967 } 968 969 var morestacksym *obj.LSym 970 if ctxt.Cursym.CFunc() { 971 morestacksym = obj.Linklookup(ctxt, "runtime.morestackc", 0) 972 } else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 { 973 morestacksym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0) 974 } else { 975 morestacksym = obj.Linklookup(ctxt, "runtime.morestack", 0) 976 } 977 978 if ctxt.Flag_shared { 979 // In PPC64 PIC code, R2 is used as TOC pointer derived from R12 980 // which is the address of function entry point when entering 981 // the function. We need to preserve R2 across call to morestack. 982 // Fortunately, in shared mode, 8(SP) and 16(SP) are reserved in 983 // the caller's frame, but not used (0(SP) is caller's saved LR, 984 // 24(SP) is caller's saved R2). Use 8(SP) to save this function's R2. 985 986 // MOVD R12, 8(SP) 987 p = obj.Appendp(ctxt, p) 988 p.As = AMOVD 989 p.From.Type = obj.TYPE_REG 990 p.From.Reg = REG_R2 991 p.To.Type = obj.TYPE_MEM 992 p.To.Reg = REGSP 993 p.To.Offset = 8 994 } 995 996 if ctxt.Flag_dynlink { 997 // Avoid calling morestack via a PLT when dynamically linking. The 998 // PLT stubs generated by the system linker on ppc64le when "std r2, 999 // 24(r1)" to save the TOC pointer in their callers stack 1000 // frame. Unfortunately (and necessarily) morestack is called before 1001 // the function that calls it sets up its frame and so the PLT ends 1002 // up smashing the saved TOC pointer for its caller's caller. 1003 // 1004 // According to the ABI documentation there is a mechanism to avoid 1005 // the TOC save that the PLT stub does (put a R_PPC64_TOCSAVE 1006 // relocation on the nop after the call to morestack) but at the time 1007 // of writing it is not supported at all by gold and my attempt to 1008 // use it with ld.bfd caused an internal linker error. So this hack 1009 // seems preferable. 1010 1011 // MOVD $runtime.morestack(SB), R12 1012 p = obj.Appendp(ctxt, p) 1013 p.As = AMOVD 1014 p.From.Type = obj.TYPE_MEM 1015 p.From.Sym = morestacksym 1016 p.From.Name = obj.NAME_GOTREF 1017 p.To.Type = obj.TYPE_REG 1018 p.To.Reg = REG_R12 1019 1020 // MOVD R12, CTR 1021 p = obj.Appendp(ctxt, p) 1022 p.As = AMOVD 1023 p.From.Type = obj.TYPE_REG 1024 p.From.Reg = REG_R12 1025 p.To.Type = obj.TYPE_REG 1026 p.To.Reg = REG_CTR 1027 1028 // BL CTR 1029 p = obj.Appendp(ctxt, p) 1030 p.As = obj.ACALL 1031 p.From.Type = obj.TYPE_REG 1032 p.From.Reg = REG_R12 1033 p.To.Type = obj.TYPE_REG 1034 p.To.Reg = REG_CTR 1035 } else { 1036 // BL runtime.morestack(SB) 1037 p = obj.Appendp(ctxt, p) 1038 1039 p.As = ABL 1040 p.To.Type = obj.TYPE_BRANCH 1041 p.To.Sym = morestacksym 1042 } 1043 1044 if ctxt.Flag_shared { 1045 // MOVD 8(SP), R2 1046 p = obj.Appendp(ctxt, p) 1047 p.As = AMOVD 1048 p.From.Type = obj.TYPE_MEM 1049 p.From.Reg = REGSP 1050 p.From.Offset = 8 1051 p.To.Type = obj.TYPE_REG 1052 p.To.Reg = REG_R2 1053 } 1054 1055 // BR start 1056 p = obj.Appendp(ctxt, p) 1057 p.As = ABR 1058 p.To.Type = obj.TYPE_BRANCH 1059 p.Pcond = p0.Link 1060 1061 // placeholder for q1's jump target 1062 p = obj.Appendp(ctxt, p) 1063 1064 p.As = obj.ANOP // zero-width place holder 1065 q1.Pcond = p 1066 1067 return p 1068 } 1069 1070 func follow(ctxt *obj.Link, s *obj.LSym) { 1071 ctxt.Cursym = s 1072 1073 firstp := ctxt.NewProg() 1074 lastp := firstp 1075 xfol(ctxt, s.Text, &lastp) 1076 lastp.Link = nil 1077 s.Text = firstp.Link 1078 } 1079 1080 func relinv(a obj.As) obj.As { 1081 switch a { 1082 case ABEQ: 1083 return ABNE 1084 case ABNE: 1085 return ABEQ 1086 1087 case ABGE: 1088 return ABLT 1089 case ABLT: 1090 return ABGE 1091 1092 case ABGT: 1093 return ABLE 1094 case ABLE: 1095 return ABGT 1096 1097 case ABVC: 1098 return ABVS 1099 case ABVS: 1100 return ABVC 1101 } 1102 1103 return 0 1104 } 1105 1106 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 1107 var q *obj.Prog 1108 var r *obj.Prog 1109 var b obj.As 1110 var i int 1111 1112 loop: 1113 if p == nil { 1114 return 1115 } 1116 a := p.As 1117 if a == ABR { 1118 q = p.Pcond 1119 if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) { 1120 p.Mark |= FOLL 1121 (*last).Link = p 1122 *last = p 1123 p = p.Link 1124 xfol(ctxt, p, last) 1125 p = q 1126 if p != nil && p.Mark&FOLL == 0 { 1127 goto loop 1128 } 1129 return 1130 } 1131 1132 if q != nil { 1133 p.Mark |= FOLL 1134 p = q 1135 if p.Mark&FOLL == 0 { 1136 goto loop 1137 } 1138 } 1139 } 1140 1141 if p.Mark&FOLL != 0 { 1142 i = 0 1143 q = p 1144 for ; i < 4; i, q = i+1, q.Link { 1145 if q == *last || (q.Mark&NOSCHED != 0) { 1146 break 1147 } 1148 b = 0 /* set */ 1149 a = q.As 1150 if a == obj.ANOP { 1151 i-- 1152 continue 1153 } 1154 1155 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 1156 goto copy 1157 } 1158 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 1159 continue 1160 } 1161 b = relinv(a) 1162 if b == 0 { 1163 continue 1164 } 1165 1166 copy: 1167 for { 1168 r = ctxt.NewProg() 1169 *r = *p 1170 if r.Mark&FOLL == 0 { 1171 fmt.Printf("can't happen 1\n") 1172 } 1173 r.Mark |= FOLL 1174 if p != q { 1175 p = p.Link 1176 (*last).Link = r 1177 *last = r 1178 continue 1179 } 1180 1181 (*last).Link = r 1182 *last = r 1183 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 1184 return 1185 } 1186 r.As = b 1187 r.Pcond = p.Link 1188 r.Link = p.Pcond 1189 if r.Link.Mark&FOLL == 0 { 1190 xfol(ctxt, r.Link, last) 1191 } 1192 if r.Pcond.Mark&FOLL == 0 { 1193 fmt.Printf("can't happen 2\n") 1194 } 1195 return 1196 } 1197 } 1198 1199 a = ABR 1200 q = ctxt.NewProg() 1201 q.As = a 1202 q.Lineno = p.Lineno 1203 q.To.Type = obj.TYPE_BRANCH 1204 q.To.Offset = p.Pc 1205 q.Pcond = p 1206 p = q 1207 } 1208 1209 p.Mark |= FOLL 1210 (*last).Link = p 1211 *last = p 1212 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 1213 if p.Mark&NOSCHED != 0 { 1214 p = p.Link 1215 goto loop 1216 } 1217 1218 return 1219 } 1220 1221 if p.Pcond != nil { 1222 if a != ABL && p.Link != nil { 1223 xfol(ctxt, p.Link, last) 1224 p = p.Pcond 1225 if p == nil || (p.Mark&FOLL != 0) { 1226 return 1227 } 1228 goto loop 1229 } 1230 } 1231 1232 p = p.Link 1233 goto loop 1234 } 1235 1236 var Linkppc64 = obj.LinkArch{ 1237 Arch: sys.ArchPPC64, 1238 Preprocess: preprocess, 1239 Assemble: span9, 1240 Follow: follow, 1241 Progedit: progedit, 1242 } 1243 1244 var Linkppc64le = obj.LinkArch{ 1245 Arch: sys.ArchPPC64LE, 1246 Preprocess: preprocess, 1247 Assemble: span9, 1248 Follow: follow, 1249 Progedit: progedit, 1250 }