github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/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/objabi" 35 "cmd/internal/sys" 36 ) 37 38 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { 39 p.From.Class = 0 40 p.To.Class = 0 41 42 c := ctxt9{ctxt: ctxt, newprog: newprog} 43 44 // Rewrite BR/BL to symbol as TYPE_BRANCH. 45 switch p.As { 46 case ABR, 47 ABL, 48 obj.ARET, 49 obj.ADUFFZERO, 50 obj.ADUFFCOPY: 51 if p.To.Sym != nil { 52 p.To.Type = obj.TYPE_BRANCH 53 } 54 } 55 56 // Rewrite float constants to values stored in memory. 57 switch p.As { 58 case AFMOVS: 59 if p.From.Type == obj.TYPE_FCONST { 60 f32 := float32(p.From.Val.(float64)) 61 p.From.Type = obj.TYPE_MEM 62 p.From.Sym = ctxt.Float32Sym(f32) 63 p.From.Name = obj.NAME_EXTERN 64 p.From.Offset = 0 65 } 66 67 case AFMOVD: 68 if p.From.Type == obj.TYPE_FCONST { 69 f64 := p.From.Val.(float64) 70 p.From.Type = obj.TYPE_MEM 71 p.From.Sym = ctxt.Float64Sym(f64) 72 p.From.Name = obj.NAME_EXTERN 73 p.From.Offset = 0 74 } 75 76 // Put >32-bit constants in memory and load them 77 case AMOVD: 78 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 { 79 p.From.Type = obj.TYPE_MEM 80 p.From.Sym = ctxt.Int64Sym(p.From.Offset) 81 p.From.Name = obj.NAME_EXTERN 82 p.From.Offset = 0 83 } 84 } 85 86 // Rewrite SUB constants into ADD. 87 switch p.As { 88 case ASUBC: 89 if p.From.Type == obj.TYPE_CONST { 90 p.From.Offset = -p.From.Offset 91 p.As = AADDC 92 } 93 94 case ASUBCCC: 95 if p.From.Type == obj.TYPE_CONST { 96 p.From.Offset = -p.From.Offset 97 p.As = AADDCCC 98 } 99 100 case ASUB: 101 if p.From.Type == obj.TYPE_CONST { 102 p.From.Offset = -p.From.Offset 103 p.As = AADD 104 } 105 } 106 if c.ctxt.Flag_dynlink { 107 c.rewriteToUseGot(p) 108 } 109 } 110 111 // Rewrite p, if necessary, to access global data via the global offset table. 112 func (c *ctxt9) rewriteToUseGot(p *obj.Prog) { 113 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO { 114 // ADUFFxxx $offset 115 // becomes 116 // MOVD runtime.duffxxx@GOT, R12 117 // ADD $offset, R12 118 // MOVD R12, CTR 119 // BL (CTR) 120 var sym *obj.LSym 121 if p.As == obj.ADUFFZERO { 122 sym = c.ctxt.Lookup("runtime.duffzero") 123 } else { 124 sym = c.ctxt.Lookup("runtime.duffcopy") 125 } 126 offset := p.To.Offset 127 p.As = AMOVD 128 p.From.Type = obj.TYPE_MEM 129 p.From.Name = obj.NAME_GOTREF 130 p.From.Sym = sym 131 p.To.Type = obj.TYPE_REG 132 p.To.Reg = REG_R12 133 p.To.Name = obj.NAME_NONE 134 p.To.Offset = 0 135 p.To.Sym = nil 136 p1 := obj.Appendp(p, c.newprog) 137 p1.As = AADD 138 p1.From.Type = obj.TYPE_CONST 139 p1.From.Offset = offset 140 p1.To.Type = obj.TYPE_REG 141 p1.To.Reg = REG_R12 142 p2 := obj.Appendp(p1, c.newprog) 143 p2.As = AMOVD 144 p2.From.Type = obj.TYPE_REG 145 p2.From.Reg = REG_R12 146 p2.To.Type = obj.TYPE_REG 147 p2.To.Reg = REG_CTR 148 p3 := obj.Appendp(p2, c.newprog) 149 p3.As = obj.ACALL 150 p3.From.Type = obj.TYPE_REG 151 p3.From.Reg = REG_R12 152 p3.To.Type = obj.TYPE_REG 153 p3.To.Reg = REG_CTR 154 } 155 156 // We only care about global data: NAME_EXTERN means a global 157 // symbol in the Go sense, and p.Sym.Local is true for a few 158 // internally defined symbols. 159 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 160 // MOVD $sym, Rx becomes MOVD sym@GOT, Rx 161 // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx 162 if p.As != AMOVD { 163 c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p) 164 } 165 if p.To.Type != obj.TYPE_REG { 166 c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p) 167 } 168 p.From.Type = obj.TYPE_MEM 169 p.From.Name = obj.NAME_GOTREF 170 if p.From.Offset != 0 { 171 q := obj.Appendp(p, c.newprog) 172 q.As = AADD 173 q.From.Type = obj.TYPE_CONST 174 q.From.Offset = p.From.Offset 175 q.To = p.To 176 p.From.Offset = 0 177 } 178 } 179 if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { 180 c.ctxt.Diag("don't know how to handle %v with -dynlink", p) 181 } 182 var source *obj.Addr 183 // MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry 184 // MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVx Ry, (REGTMP) 185 // An addition may be inserted between the two MOVs if there is an offset. 186 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 187 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { 188 c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p) 189 } 190 source = &p.From 191 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { 192 source = &p.To 193 } else { 194 return 195 } 196 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { 197 return 198 } 199 if source.Sym.Type == objabi.STLSBSS { 200 return 201 } 202 if source.Type != obj.TYPE_MEM { 203 c.ctxt.Diag("don't know how to handle %v with -dynlink", p) 204 } 205 p1 := obj.Appendp(p, c.newprog) 206 p2 := obj.Appendp(p1, c.newprog) 207 208 p1.As = AMOVD 209 p1.From.Type = obj.TYPE_MEM 210 p1.From.Sym = source.Sym 211 p1.From.Name = obj.NAME_GOTREF 212 p1.To.Type = obj.TYPE_REG 213 p1.To.Reg = REGTMP 214 215 p2.As = p.As 216 p2.From = p.From 217 p2.To = p.To 218 if p.From.Name == obj.NAME_EXTERN { 219 p2.From.Reg = REGTMP 220 p2.From.Name = obj.NAME_NONE 221 p2.From.Sym = nil 222 } else if p.To.Name == obj.NAME_EXTERN { 223 p2.To.Reg = REGTMP 224 p2.To.Name = obj.NAME_NONE 225 p2.To.Sym = nil 226 } else { 227 return 228 } 229 obj.Nopout(p) 230 } 231 232 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { 233 // TODO(minux): add morestack short-cuts with small fixed frame-size. 234 if cursym.Func.Text == nil || cursym.Func.Text.Link == nil { 235 return 236 } 237 238 c := ctxt9{ctxt: ctxt, cursym: cursym, newprog: newprog} 239 240 p := c.cursym.Func.Text 241 textstksiz := p.To.Offset 242 if textstksiz == -8 { 243 // Compatibility hack. 244 p.From.Sym.Set(obj.AttrNoFrame, true) 245 textstksiz = 0 246 } 247 if textstksiz%8 != 0 { 248 c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz) 249 } 250 if p.From.Sym.NoFrame() { 251 if textstksiz != 0 { 252 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz) 253 } 254 } 255 256 c.cursym.Func.Args = p.To.Val.(int32) 257 c.cursym.Func.Locals = int32(textstksiz) 258 259 /* 260 * find leaf subroutines 261 * strip NOPs 262 * expand RET 263 * expand BECOME pseudo 264 */ 265 266 var q *obj.Prog 267 var q1 *obj.Prog 268 for p := c.cursym.Func.Text; p != nil; p = p.Link { 269 switch p.As { 270 /* too hard, just leave alone */ 271 case obj.ATEXT: 272 q = p 273 274 p.Mark |= LABEL | LEAF | SYNC 275 if p.Link != nil { 276 p.Link.Mark |= LABEL 277 } 278 279 case ANOR: 280 q = p 281 if p.To.Type == obj.TYPE_REG { 282 if p.To.Reg == REGZERO { 283 p.Mark |= LABEL | SYNC 284 } 285 } 286 287 case ALWAR, 288 ALBAR, 289 ASTBCCC, 290 ASTWCCC, 291 AECIWX, 292 AECOWX, 293 AEIEIO, 294 AICBI, 295 AISYNC, 296 ATLBIE, 297 ATLBIEL, 298 ASLBIA, 299 ASLBIE, 300 ASLBMFEE, 301 ASLBMFEV, 302 ASLBMTE, 303 ADCBF, 304 ADCBI, 305 ADCBST, 306 ADCBT, 307 ADCBTST, 308 ADCBZ, 309 ASYNC, 310 ATLBSYNC, 311 APTESYNC, 312 ALWSYNC, 313 ATW, 314 AWORD, 315 ARFI, 316 ARFCI, 317 ARFID, 318 AHRFID: 319 q = p 320 p.Mark |= LABEL | SYNC 321 continue 322 323 case AMOVW, AMOVWZ, AMOVD: 324 q = p 325 if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL { 326 p.Mark |= LABEL | SYNC 327 } 328 continue 329 330 case AFABS, 331 AFABSCC, 332 AFADD, 333 AFADDCC, 334 AFCTIW, 335 AFCTIWCC, 336 AFCTIWZ, 337 AFCTIWZCC, 338 AFDIV, 339 AFDIVCC, 340 AFMADD, 341 AFMADDCC, 342 AFMOVD, 343 AFMOVDU, 344 /* case AFMOVDS: */ 345 AFMOVS, 346 AFMOVSU, 347 348 /* case AFMOVSD: */ 349 AFMSUB, 350 AFMSUBCC, 351 AFMUL, 352 AFMULCC, 353 AFNABS, 354 AFNABSCC, 355 AFNEG, 356 AFNEGCC, 357 AFNMADD, 358 AFNMADDCC, 359 AFNMSUB, 360 AFNMSUBCC, 361 AFRSP, 362 AFRSPCC, 363 AFSUB, 364 AFSUBCC: 365 q = p 366 367 p.Mark |= FLOAT 368 continue 369 370 case ABL, 371 ABCL, 372 obj.ADUFFZERO, 373 obj.ADUFFCOPY: 374 c.cursym.Func.Text.Mark &^= LEAF 375 fallthrough 376 377 case ABC, 378 ABEQ, 379 ABGE, 380 ABGT, 381 ABLE, 382 ABLT, 383 ABNE, 384 ABR, 385 ABVC, 386 ABVS: 387 p.Mark |= BRANCH 388 q = p 389 q1 = p.Pcond 390 if q1 != nil { 391 for q1.As == obj.ANOP { 392 q1 = q1.Link 393 p.Pcond = q1 394 } 395 396 if q1.Mark&LEAF == 0 { 397 q1.Mark |= LABEL 398 } 399 } else { 400 p.Mark |= LABEL 401 } 402 q1 = p.Link 403 if q1 != nil { 404 q1.Mark |= LABEL 405 } 406 continue 407 408 case AFCMPO, AFCMPU: 409 q = p 410 p.Mark |= FCMP | FLOAT 411 continue 412 413 case obj.ARET: 414 q = p 415 if p.Link != nil { 416 p.Link.Mark |= LABEL 417 } 418 continue 419 420 case obj.ANOP: 421 q1 = p.Link 422 q.Link = q1 /* q is non-nop */ 423 q1.Mark |= p.Mark 424 continue 425 426 default: 427 q = p 428 continue 429 } 430 } 431 432 autosize := int32(0) 433 var p1 *obj.Prog 434 var p2 *obj.Prog 435 for p := c.cursym.Func.Text; p != nil; p = p.Link { 436 o := p.As 437 switch o { 438 case obj.ATEXT: 439 autosize = int32(textstksiz) 440 441 if p.Mark&LEAF != 0 && autosize == 0 { 442 // A leaf function with no locals has no frame. 443 p.From.Sym.Set(obj.AttrNoFrame, true) 444 } 445 446 if !p.From.Sym.NoFrame() { 447 // If there is a stack frame at all, it includes 448 // space to save the LR. 449 autosize += int32(c.ctxt.FixedFrameSize()) 450 } 451 452 if p.Mark&LEAF != 0 && autosize < objabi.StackSmall { 453 // A leaf function with a small stack can be marked 454 // NOSPLIT, avoiding a stack check. 455 p.From.Sym.Set(obj.AttrNoSplit, true) 456 } 457 458 p.To.Offset = int64(autosize) 459 460 q = p 461 462 if c.ctxt.Flag_shared && c.cursym.Name != "runtime.duffzero" && c.cursym.Name != "runtime.duffcopy" { 463 // When compiling Go into PIC, all functions must start 464 // with instructions to load the TOC pointer into r2: 465 // 466 // addis r2, r12, .TOC.-func@ha 467 // addi r2, r2, .TOC.-func@l+4 468 // 469 // We could probably skip this prologue in some situations 470 // but it's a bit subtle. However, it is both safe and 471 // necessary to leave the prologue off duffzero and 472 // duffcopy as we rely on being able to jump to a specific 473 // instruction offset for them. 474 // 475 // These are AWORDS because there is no (afaict) way to 476 // generate the addis instruction except as part of the 477 // load of a large constant, and in that case there is no 478 // way to use r12 as the source. 479 q = obj.Appendp(q, c.newprog) 480 q.As = AWORD 481 q.Pos = p.Pos 482 q.From.Type = obj.TYPE_CONST 483 q.From.Offset = 0x3c4c0000 484 q = obj.Appendp(q, c.newprog) 485 q.As = AWORD 486 q.Pos = p.Pos 487 q.From.Type = obj.TYPE_CONST 488 q.From.Offset = 0x38420000 489 rel := obj.Addrel(c.cursym) 490 rel.Off = 0 491 rel.Siz = 8 492 rel.Sym = c.ctxt.Lookup(".TOC.") 493 rel.Type = objabi.R_ADDRPOWER_PCREL 494 } 495 496 if !c.cursym.Func.Text.From.Sym.NoSplit() { 497 q = c.stacksplit(q, autosize) // emit split check 498 } 499 500 if autosize != 0 { 501 // Save the link register and update the SP. MOVDU is used unless 502 // the frame size is too large. The link register must be saved 503 // even for non-empty leaf functions so that traceback works. 504 if autosize >= -BIG && autosize <= BIG { 505 // Use MOVDU to adjust R1 when saving R31, if autosize is small. 506 q = obj.Appendp(q, c.newprog) 507 q.As = AMOVD 508 q.Pos = p.Pos 509 q.From.Type = obj.TYPE_REG 510 q.From.Reg = REG_LR 511 q.To.Type = obj.TYPE_REG 512 q.To.Reg = REGTMP 513 514 q = obj.Appendp(q, c.newprog) 515 q.As = AMOVDU 516 q.Pos = p.Pos 517 q.From.Type = obj.TYPE_REG 518 q.From.Reg = REGTMP 519 q.To.Type = obj.TYPE_MEM 520 q.To.Offset = int64(-autosize) 521 q.To.Reg = REGSP 522 q.Spadj = int32(autosize) 523 } else { 524 // Frame size is too large for a MOVDU instruction. 525 // Store link register before decrementing SP, so if a signal comes 526 // during the execution of the function prologue, the traceback 527 // code will not see a half-updated stack frame. 528 q = obj.Appendp(q, c.newprog) 529 q.As = AMOVD 530 q.Pos = p.Pos 531 q.From.Type = obj.TYPE_REG 532 q.From.Reg = REG_LR 533 q.To.Type = obj.TYPE_REG 534 q.To.Reg = REG_R29 // REGTMP may be used to synthesize large offset in the next instruction 535 536 q = obj.Appendp(q, c.newprog) 537 q.As = AMOVD 538 q.Pos = p.Pos 539 q.From.Type = obj.TYPE_REG 540 q.From.Reg = REG_R29 541 q.To.Type = obj.TYPE_MEM 542 q.To.Offset = int64(-autosize) 543 q.To.Reg = REGSP 544 545 q = obj.Appendp(q, c.newprog) 546 q.As = AADD 547 q.Pos = p.Pos 548 q.From.Type = obj.TYPE_CONST 549 q.From.Offset = int64(-autosize) 550 q.To.Type = obj.TYPE_REG 551 q.To.Reg = REGSP 552 q.Spadj = +autosize 553 } 554 } else if c.cursym.Func.Text.Mark&LEAF == 0 { 555 // A very few functions that do not return to their caller 556 // (e.g. gogo) are not identified as leaves but still have 557 // no frame. 558 c.cursym.Func.Text.Mark |= LEAF 559 } 560 561 if c.cursym.Func.Text.Mark&LEAF != 0 { 562 c.cursym.Set(obj.AttrLeaf, true) 563 break 564 } 565 566 if c.ctxt.Flag_shared { 567 q = obj.Appendp(q, c.newprog) 568 q.As = AMOVD 569 q.Pos = p.Pos 570 q.From.Type = obj.TYPE_REG 571 q.From.Reg = REG_R2 572 q.To.Type = obj.TYPE_MEM 573 q.To.Reg = REGSP 574 q.To.Offset = 24 575 } 576 577 if c.cursym.Func.Text.From.Sym.Wrapper() { 578 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 579 // 580 // MOVD g_panic(g), R3 581 // CMP R0, R3 582 // BEQ end 583 // MOVD panic_argp(R3), R4 584 // ADD $(autosize+8), R1, R5 585 // CMP R4, R5 586 // BNE end 587 // ADD $8, R1, R6 588 // MOVD R6, panic_argp(R3) 589 // end: 590 // NOP 591 // 592 // The NOP is needed to give the jumps somewhere to land. 593 // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes. 594 595 q = obj.Appendp(q, c.newprog) 596 597 q.As = AMOVD 598 q.From.Type = obj.TYPE_MEM 599 q.From.Reg = REGG 600 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic 601 q.To.Type = obj.TYPE_REG 602 q.To.Reg = REG_R3 603 604 q = obj.Appendp(q, c.newprog) 605 q.As = ACMP 606 q.From.Type = obj.TYPE_REG 607 q.From.Reg = REG_R0 608 q.To.Type = obj.TYPE_REG 609 q.To.Reg = REG_R3 610 611 q = obj.Appendp(q, c.newprog) 612 q.As = ABEQ 613 q.To.Type = obj.TYPE_BRANCH 614 p1 = q 615 616 q = obj.Appendp(q, c.newprog) 617 q.As = AMOVD 618 q.From.Type = obj.TYPE_MEM 619 q.From.Reg = REG_R3 620 q.From.Offset = 0 // Panic.argp 621 q.To.Type = obj.TYPE_REG 622 q.To.Reg = REG_R4 623 624 q = obj.Appendp(q, c.newprog) 625 q.As = AADD 626 q.From.Type = obj.TYPE_CONST 627 q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize() 628 q.Reg = REGSP 629 q.To.Type = obj.TYPE_REG 630 q.To.Reg = REG_R5 631 632 q = obj.Appendp(q, c.newprog) 633 q.As = ACMP 634 q.From.Type = obj.TYPE_REG 635 q.From.Reg = REG_R4 636 q.To.Type = obj.TYPE_REG 637 q.To.Reg = REG_R5 638 639 q = obj.Appendp(q, c.newprog) 640 q.As = ABNE 641 q.To.Type = obj.TYPE_BRANCH 642 p2 = q 643 644 q = obj.Appendp(q, c.newprog) 645 q.As = AADD 646 q.From.Type = obj.TYPE_CONST 647 q.From.Offset = c.ctxt.FixedFrameSize() 648 q.Reg = REGSP 649 q.To.Type = obj.TYPE_REG 650 q.To.Reg = REG_R6 651 652 q = obj.Appendp(q, c.newprog) 653 q.As = AMOVD 654 q.From.Type = obj.TYPE_REG 655 q.From.Reg = REG_R6 656 q.To.Type = obj.TYPE_MEM 657 q.To.Reg = REG_R3 658 q.To.Offset = 0 // Panic.argp 659 660 q = obj.Appendp(q, c.newprog) 661 662 q.As = obj.ANOP 663 p1.Pcond = q 664 p2.Pcond = q 665 } 666 667 case obj.ARET: 668 if p.From.Type == obj.TYPE_CONST { 669 c.ctxt.Diag("using BECOME (%v) is not supported!", p) 670 break 671 } 672 673 retTarget := p.To.Sym 674 675 if c.cursym.Func.Text.Mark&LEAF != 0 { 676 if autosize == 0 { 677 p.As = ABR 678 p.From = obj.Addr{} 679 if retTarget == nil { 680 p.To.Type = obj.TYPE_REG 681 p.To.Reg = REG_LR 682 } else { 683 p.To.Type = obj.TYPE_BRANCH 684 p.To.Sym = retTarget 685 } 686 p.Mark |= BRANCH 687 break 688 } 689 690 p.As = AADD 691 p.From.Type = obj.TYPE_CONST 692 p.From.Offset = int64(autosize) 693 p.To.Type = obj.TYPE_REG 694 p.To.Reg = REGSP 695 p.Spadj = -autosize 696 697 q = c.newprog() 698 q.As = ABR 699 q.Pos = p.Pos 700 q.To.Type = obj.TYPE_REG 701 q.To.Reg = REG_LR 702 q.Mark |= BRANCH 703 q.Spadj = +autosize 704 705 q.Link = p.Link 706 p.Link = q 707 break 708 } 709 710 p.As = AMOVD 711 p.From.Type = obj.TYPE_MEM 712 p.From.Offset = 0 713 p.From.Reg = REGSP 714 p.To.Type = obj.TYPE_REG 715 p.To.Reg = REGTMP 716 717 q = c.newprog() 718 q.As = AMOVD 719 q.Pos = p.Pos 720 q.From.Type = obj.TYPE_REG 721 q.From.Reg = REGTMP 722 q.To.Type = obj.TYPE_REG 723 q.To.Reg = REG_LR 724 725 q.Link = p.Link 726 p.Link = q 727 p = q 728 729 if false { 730 // Debug bad returns 731 q = c.newprog() 732 733 q.As = AMOVD 734 q.Pos = p.Pos 735 q.From.Type = obj.TYPE_MEM 736 q.From.Offset = 0 737 q.From.Reg = REGTMP 738 q.To.Type = obj.TYPE_REG 739 q.To.Reg = REGTMP 740 741 q.Link = p.Link 742 p.Link = q 743 p = q 744 } 745 746 if autosize != 0 { 747 q = c.newprog() 748 q.As = AADD 749 q.Pos = p.Pos 750 q.From.Type = obj.TYPE_CONST 751 q.From.Offset = int64(autosize) 752 q.To.Type = obj.TYPE_REG 753 q.To.Reg = REGSP 754 q.Spadj = -autosize 755 756 q.Link = p.Link 757 p.Link = q 758 } 759 760 q1 = c.newprog() 761 q1.As = ABR 762 q1.Pos = p.Pos 763 if retTarget == nil { 764 q1.To.Type = obj.TYPE_REG 765 q1.To.Reg = REG_LR 766 } else { 767 q1.To.Type = obj.TYPE_BRANCH 768 q1.To.Sym = retTarget 769 } 770 q1.Mark |= BRANCH 771 q1.Spadj = +autosize 772 773 q1.Link = q.Link 774 q.Link = q1 775 case AADD: 776 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 777 p.Spadj = int32(-p.From.Offset) 778 } 779 } 780 } 781 } 782 783 /* 784 // instruction scheduling 785 if(debug['Q'] == 0) 786 return; 787 788 curtext = nil; 789 q = nil; // p - 1 790 q1 = firstp; // top of block 791 o = 0; // count of instructions 792 for(p = firstp; p != nil; p = p1) { 793 p1 = p->link; 794 o++; 795 if(p->mark & NOSCHED){ 796 if(q1 != p){ 797 sched(q1, q); 798 } 799 for(; p != nil; p = p->link){ 800 if(!(p->mark & NOSCHED)) 801 break; 802 q = p; 803 } 804 p1 = p; 805 q1 = p; 806 o = 0; 807 continue; 808 } 809 if(p->mark & (LABEL|SYNC)) { 810 if(q1 != p) 811 sched(q1, q); 812 q1 = p; 813 o = 1; 814 } 815 if(p->mark & (BRANCH|SYNC)) { 816 sched(q1, p); 817 q1 = p1; 818 o = 0; 819 } 820 if(o >= NSCHED) { 821 sched(q1, p); 822 q1 = p1; 823 o = 0; 824 } 825 q = p; 826 } 827 */ 828 func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { 829 p0 := p // save entry point, but skipping the two instructions setting R2 in shared mode 830 831 // MOVD g_stackguard(g), R3 832 p = obj.Appendp(p, c.newprog) 833 834 p.As = AMOVD 835 p.From.Type = obj.TYPE_MEM 836 p.From.Reg = REGG 837 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0 838 if c.cursym.CFunc() { 839 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1 840 } 841 p.To.Type = obj.TYPE_REG 842 p.To.Reg = REG_R3 843 844 var q *obj.Prog 845 if framesize <= objabi.StackSmall { 846 // small stack: SP < stackguard 847 // CMP stackguard, SP 848 p = obj.Appendp(p, c.newprog) 849 850 p.As = ACMPU 851 p.From.Type = obj.TYPE_REG 852 p.From.Reg = REG_R3 853 p.To.Type = obj.TYPE_REG 854 p.To.Reg = REGSP 855 } else if framesize <= objabi.StackBig { 856 // large stack: SP-framesize < stackguard-StackSmall 857 // ADD $-(framesize-StackSmall), SP, R4 858 // CMP stackguard, R4 859 p = obj.Appendp(p, c.newprog) 860 861 p.As = AADD 862 p.From.Type = obj.TYPE_CONST 863 p.From.Offset = -(int64(framesize) - objabi.StackSmall) 864 p.Reg = REGSP 865 p.To.Type = obj.TYPE_REG 866 p.To.Reg = REG_R4 867 868 p = obj.Appendp(p, c.newprog) 869 p.As = ACMPU 870 p.From.Type = obj.TYPE_REG 871 p.From.Reg = REG_R3 872 p.To.Type = obj.TYPE_REG 873 p.To.Reg = REG_R4 874 } else { 875 // Such a large stack we need to protect against wraparound. 876 // If SP is close to zero: 877 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 878 // The +StackGuard on both sides is required to keep the left side positive: 879 // SP is allowed to be slightly below stackguard. See stack.h. 880 // 881 // Preemption sets stackguard to StackPreempt, a very large value. 882 // That breaks the math above, so we have to check for that explicitly. 883 // // stackguard is R3 884 // CMP R3, $StackPreempt 885 // BEQ label-of-call-to-morestack 886 // ADD $StackGuard, SP, R4 887 // SUB R3, R4 888 // MOVD $(framesize+(StackGuard-StackSmall)), R31 889 // CMPU R31, R4 890 p = obj.Appendp(p, c.newprog) 891 892 p.As = ACMP 893 p.From.Type = obj.TYPE_REG 894 p.From.Reg = REG_R3 895 p.To.Type = obj.TYPE_CONST 896 p.To.Offset = objabi.StackPreempt 897 898 p = obj.Appendp(p, c.newprog) 899 q = p 900 p.As = ABEQ 901 p.To.Type = obj.TYPE_BRANCH 902 903 p = obj.Appendp(p, c.newprog) 904 p.As = AADD 905 p.From.Type = obj.TYPE_CONST 906 p.From.Offset = objabi.StackGuard 907 p.Reg = REGSP 908 p.To.Type = obj.TYPE_REG 909 p.To.Reg = REG_R4 910 911 p = obj.Appendp(p, c.newprog) 912 p.As = ASUB 913 p.From.Type = obj.TYPE_REG 914 p.From.Reg = REG_R3 915 p.To.Type = obj.TYPE_REG 916 p.To.Reg = REG_R4 917 918 p = obj.Appendp(p, c.newprog) 919 p.As = AMOVD 920 p.From.Type = obj.TYPE_CONST 921 p.From.Offset = int64(framesize) + objabi.StackGuard - objabi.StackSmall 922 p.To.Type = obj.TYPE_REG 923 p.To.Reg = REGTMP 924 925 p = obj.Appendp(p, c.newprog) 926 p.As = ACMPU 927 p.From.Type = obj.TYPE_REG 928 p.From.Reg = REGTMP 929 p.To.Type = obj.TYPE_REG 930 p.To.Reg = REG_R4 931 } 932 933 // q1: BLT done 934 p = obj.Appendp(p, c.newprog) 935 q1 := p 936 937 p.As = ABLT 938 p.To.Type = obj.TYPE_BRANCH 939 940 // MOVD LR, R5 941 p = obj.Appendp(p, c.newprog) 942 943 p.As = AMOVD 944 p.From.Type = obj.TYPE_REG 945 p.From.Reg = REG_LR 946 p.To.Type = obj.TYPE_REG 947 p.To.Reg = REG_R5 948 if q != nil { 949 q.Pcond = p 950 } 951 952 var morestacksym *obj.LSym 953 if c.cursym.CFunc() { 954 morestacksym = c.ctxt.Lookup("runtime.morestackc") 955 } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() { 956 morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt") 957 } else { 958 morestacksym = c.ctxt.Lookup("runtime.morestack") 959 } 960 961 if c.ctxt.Flag_shared { 962 // In PPC64 PIC code, R2 is used as TOC pointer derived from R12 963 // which is the address of function entry point when entering 964 // the function. We need to preserve R2 across call to morestack. 965 // Fortunately, in shared mode, 8(SP) and 16(SP) are reserved in 966 // the caller's frame, but not used (0(SP) is caller's saved LR, 967 // 24(SP) is caller's saved R2). Use 8(SP) to save this function's R2. 968 969 // MOVD R12, 8(SP) 970 p = obj.Appendp(p, c.newprog) 971 p.As = AMOVD 972 p.From.Type = obj.TYPE_REG 973 p.From.Reg = REG_R2 974 p.To.Type = obj.TYPE_MEM 975 p.To.Reg = REGSP 976 p.To.Offset = 8 977 } 978 979 if c.ctxt.Flag_dynlink { 980 // Avoid calling morestack via a PLT when dynamically linking. The 981 // PLT stubs generated by the system linker on ppc64le when "std r2, 982 // 24(r1)" to save the TOC pointer in their callers stack 983 // frame. Unfortunately (and necessarily) morestack is called before 984 // the function that calls it sets up its frame and so the PLT ends 985 // up smashing the saved TOC pointer for its caller's caller. 986 // 987 // According to the ABI documentation there is a mechanism to avoid 988 // the TOC save that the PLT stub does (put a R_PPC64_TOCSAVE 989 // relocation on the nop after the call to morestack) but at the time 990 // of writing it is not supported at all by gold and my attempt to 991 // use it with ld.bfd caused an internal linker error. So this hack 992 // seems preferable. 993 994 // MOVD $runtime.morestack(SB), R12 995 p = obj.Appendp(p, c.newprog) 996 p.As = AMOVD 997 p.From.Type = obj.TYPE_MEM 998 p.From.Sym = morestacksym 999 p.From.Name = obj.NAME_GOTREF 1000 p.To.Type = obj.TYPE_REG 1001 p.To.Reg = REG_R12 1002 1003 // MOVD R12, CTR 1004 p = obj.Appendp(p, c.newprog) 1005 p.As = AMOVD 1006 p.From.Type = obj.TYPE_REG 1007 p.From.Reg = REG_R12 1008 p.To.Type = obj.TYPE_REG 1009 p.To.Reg = REG_CTR 1010 1011 // BL CTR 1012 p = obj.Appendp(p, c.newprog) 1013 p.As = obj.ACALL 1014 p.From.Type = obj.TYPE_REG 1015 p.From.Reg = REG_R12 1016 p.To.Type = obj.TYPE_REG 1017 p.To.Reg = REG_CTR 1018 } else { 1019 // BL runtime.morestack(SB) 1020 p = obj.Appendp(p, c.newprog) 1021 1022 p.As = ABL 1023 p.To.Type = obj.TYPE_BRANCH 1024 p.To.Sym = morestacksym 1025 } 1026 1027 if c.ctxt.Flag_shared { 1028 // MOVD 8(SP), R2 1029 p = obj.Appendp(p, c.newprog) 1030 p.As = AMOVD 1031 p.From.Type = obj.TYPE_MEM 1032 p.From.Reg = REGSP 1033 p.From.Offset = 8 1034 p.To.Type = obj.TYPE_REG 1035 p.To.Reg = REG_R2 1036 } 1037 1038 // BR start 1039 p = obj.Appendp(p, c.newprog) 1040 p.As = ABR 1041 p.To.Type = obj.TYPE_BRANCH 1042 p.Pcond = p0.Link 1043 1044 // placeholder for q1's jump target 1045 p = obj.Appendp(p, c.newprog) 1046 1047 p.As = obj.ANOP // zero-width place holder 1048 q1.Pcond = p 1049 1050 return p 1051 } 1052 1053 var Linkppc64 = obj.LinkArch{ 1054 Arch: sys.ArchPPC64, 1055 Init: buildop, 1056 Preprocess: preprocess, 1057 Assemble: span9, 1058 Progedit: progedit, 1059 } 1060 1061 var Linkppc64le = obj.LinkArch{ 1062 Arch: sys.ArchPPC64LE, 1063 Init: buildop, 1064 Preprocess: preprocess, 1065 Assemble: span9, 1066 Progedit: progedit, 1067 }