github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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 // 480 // Note that the same condition is tested in 481 // putelfsym in cmd/link/internal/ld/symtab.go 482 // where we set the st_other field to indicate 483 // the presence of these instructions. 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 = 0x3c4c0000 489 q = obj.Appendp(q, c.newprog) 490 q.As = AWORD 491 q.Pos = p.Pos 492 q.From.Type = obj.TYPE_CONST 493 q.From.Offset = 0x38420000 494 rel := obj.Addrel(c.cursym) 495 rel.Off = 0 496 rel.Siz = 8 497 rel.Sym = c.ctxt.Lookup(".TOC.") 498 rel.Type = objabi.R_ADDRPOWER_PCREL 499 } 500 501 if !c.cursym.Func.Text.From.Sym.NoSplit() { 502 q = c.stacksplit(q, autosize) // emit split check 503 } 504 505 if autosize != 0 { 506 // Save the link register and update the SP. MOVDU is used unless 507 // the frame size is too large. The link register must be saved 508 // even for non-empty leaf functions so that traceback works. 509 if autosize >= -BIG && autosize <= BIG { 510 // Use MOVDU to adjust R1 when saving R31, if autosize is small. 511 q = obj.Appendp(q, c.newprog) 512 q.As = AMOVD 513 q.Pos = p.Pos 514 q.From.Type = obj.TYPE_REG 515 q.From.Reg = REG_LR 516 q.To.Type = obj.TYPE_REG 517 q.To.Reg = REGTMP 518 519 q = obj.Appendp(q, c.newprog) 520 q.As = AMOVDU 521 q.Pos = p.Pos 522 q.From.Type = obj.TYPE_REG 523 q.From.Reg = REGTMP 524 q.To.Type = obj.TYPE_MEM 525 q.To.Offset = int64(-autosize) 526 q.To.Reg = REGSP 527 q.Spadj = int32(autosize) 528 } else { 529 // Frame size is too large for a MOVDU instruction. 530 // Store link register before decrementing SP, so if a signal comes 531 // during the execution of the function prologue, the traceback 532 // code will not see a half-updated stack frame. 533 q = obj.Appendp(q, c.newprog) 534 q.As = AMOVD 535 q.Pos = p.Pos 536 q.From.Type = obj.TYPE_REG 537 q.From.Reg = REG_LR 538 q.To.Type = obj.TYPE_REG 539 q.To.Reg = REG_R29 // REGTMP may be used to synthesize large offset in the next instruction 540 541 q = obj.Appendp(q, c.newprog) 542 q.As = AMOVD 543 q.Pos = p.Pos 544 q.From.Type = obj.TYPE_REG 545 q.From.Reg = REG_R29 546 q.To.Type = obj.TYPE_MEM 547 q.To.Offset = int64(-autosize) 548 q.To.Reg = REGSP 549 550 q = obj.Appendp(q, c.newprog) 551 q.As = AADD 552 q.Pos = p.Pos 553 q.From.Type = obj.TYPE_CONST 554 q.From.Offset = int64(-autosize) 555 q.To.Type = obj.TYPE_REG 556 q.To.Reg = REGSP 557 q.Spadj = +autosize 558 } 559 } else if c.cursym.Func.Text.Mark&LEAF == 0 { 560 // A very few functions that do not return to their caller 561 // (e.g. gogo) are not identified as leaves but still have 562 // no frame. 563 c.cursym.Func.Text.Mark |= LEAF 564 } 565 566 if c.cursym.Func.Text.Mark&LEAF != 0 { 567 c.cursym.Set(obj.AttrLeaf, true) 568 break 569 } 570 571 if c.ctxt.Flag_shared { 572 q = obj.Appendp(q, c.newprog) 573 q.As = AMOVD 574 q.Pos = p.Pos 575 q.From.Type = obj.TYPE_REG 576 q.From.Reg = REG_R2 577 q.To.Type = obj.TYPE_MEM 578 q.To.Reg = REGSP 579 q.To.Offset = 24 580 } 581 582 if c.cursym.Func.Text.From.Sym.Wrapper() { 583 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 584 // 585 // MOVD g_panic(g), R3 586 // CMP R0, R3 587 // BEQ end 588 // MOVD panic_argp(R3), R4 589 // ADD $(autosize+8), R1, R5 590 // CMP R4, R5 591 // BNE end 592 // ADD $8, R1, R6 593 // MOVD R6, panic_argp(R3) 594 // end: 595 // NOP 596 // 597 // The NOP is needed to give the jumps somewhere to land. 598 // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes. 599 600 q = obj.Appendp(q, c.newprog) 601 602 q.As = AMOVD 603 q.From.Type = obj.TYPE_MEM 604 q.From.Reg = REGG 605 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic 606 q.To.Type = obj.TYPE_REG 607 q.To.Reg = REG_R3 608 609 q = obj.Appendp(q, c.newprog) 610 q.As = ACMP 611 q.From.Type = obj.TYPE_REG 612 q.From.Reg = REG_R0 613 q.To.Type = obj.TYPE_REG 614 q.To.Reg = REG_R3 615 616 q = obj.Appendp(q, c.newprog) 617 q.As = ABEQ 618 q.To.Type = obj.TYPE_BRANCH 619 p1 = q 620 621 q = obj.Appendp(q, c.newprog) 622 q.As = AMOVD 623 q.From.Type = obj.TYPE_MEM 624 q.From.Reg = REG_R3 625 q.From.Offset = 0 // Panic.argp 626 q.To.Type = obj.TYPE_REG 627 q.To.Reg = REG_R4 628 629 q = obj.Appendp(q, c.newprog) 630 q.As = AADD 631 q.From.Type = obj.TYPE_CONST 632 q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize() 633 q.Reg = REGSP 634 q.To.Type = obj.TYPE_REG 635 q.To.Reg = REG_R5 636 637 q = obj.Appendp(q, c.newprog) 638 q.As = ACMP 639 q.From.Type = obj.TYPE_REG 640 q.From.Reg = REG_R4 641 q.To.Type = obj.TYPE_REG 642 q.To.Reg = REG_R5 643 644 q = obj.Appendp(q, c.newprog) 645 q.As = ABNE 646 q.To.Type = obj.TYPE_BRANCH 647 p2 = q 648 649 q = obj.Appendp(q, c.newprog) 650 q.As = AADD 651 q.From.Type = obj.TYPE_CONST 652 q.From.Offset = c.ctxt.FixedFrameSize() 653 q.Reg = REGSP 654 q.To.Type = obj.TYPE_REG 655 q.To.Reg = REG_R6 656 657 q = obj.Appendp(q, c.newprog) 658 q.As = AMOVD 659 q.From.Type = obj.TYPE_REG 660 q.From.Reg = REG_R6 661 q.To.Type = obj.TYPE_MEM 662 q.To.Reg = REG_R3 663 q.To.Offset = 0 // Panic.argp 664 665 q = obj.Appendp(q, c.newprog) 666 667 q.As = obj.ANOP 668 p1.Pcond = q 669 p2.Pcond = q 670 } 671 672 case obj.ARET: 673 if p.From.Type == obj.TYPE_CONST { 674 c.ctxt.Diag("using BECOME (%v) is not supported!", p) 675 break 676 } 677 678 retTarget := p.To.Sym 679 680 if c.cursym.Func.Text.Mark&LEAF != 0 { 681 if autosize == 0 { 682 p.As = ABR 683 p.From = obj.Addr{} 684 if retTarget == nil { 685 p.To.Type = obj.TYPE_REG 686 p.To.Reg = REG_LR 687 } else { 688 p.To.Type = obj.TYPE_BRANCH 689 p.To.Sym = retTarget 690 } 691 p.Mark |= BRANCH 692 break 693 } 694 695 p.As = AADD 696 p.From.Type = obj.TYPE_CONST 697 p.From.Offset = int64(autosize) 698 p.To.Type = obj.TYPE_REG 699 p.To.Reg = REGSP 700 p.Spadj = -autosize 701 702 q = c.newprog() 703 q.As = ABR 704 q.Pos = p.Pos 705 q.To.Type = obj.TYPE_REG 706 q.To.Reg = REG_LR 707 q.Mark |= BRANCH 708 q.Spadj = +autosize 709 710 q.Link = p.Link 711 p.Link = q 712 break 713 } 714 715 p.As = AMOVD 716 p.From.Type = obj.TYPE_MEM 717 p.From.Offset = 0 718 p.From.Reg = REGSP 719 p.To.Type = obj.TYPE_REG 720 p.To.Reg = REGTMP 721 722 q = c.newprog() 723 q.As = AMOVD 724 q.Pos = p.Pos 725 q.From.Type = obj.TYPE_REG 726 q.From.Reg = REGTMP 727 q.To.Type = obj.TYPE_REG 728 q.To.Reg = REG_LR 729 730 q.Link = p.Link 731 p.Link = q 732 p = q 733 734 if false { 735 // Debug bad returns 736 q = c.newprog() 737 738 q.As = AMOVD 739 q.Pos = p.Pos 740 q.From.Type = obj.TYPE_MEM 741 q.From.Offset = 0 742 q.From.Reg = REGTMP 743 q.To.Type = obj.TYPE_REG 744 q.To.Reg = REGTMP 745 746 q.Link = p.Link 747 p.Link = q 748 p = q 749 } 750 751 if autosize != 0 { 752 q = c.newprog() 753 q.As = AADD 754 q.Pos = p.Pos 755 q.From.Type = obj.TYPE_CONST 756 q.From.Offset = int64(autosize) 757 q.To.Type = obj.TYPE_REG 758 q.To.Reg = REGSP 759 q.Spadj = -autosize 760 761 q.Link = p.Link 762 p.Link = q 763 } 764 765 q1 = c.newprog() 766 q1.As = ABR 767 q1.Pos = p.Pos 768 if retTarget == nil { 769 q1.To.Type = obj.TYPE_REG 770 q1.To.Reg = REG_LR 771 } else { 772 q1.To.Type = obj.TYPE_BRANCH 773 q1.To.Sym = retTarget 774 } 775 q1.Mark |= BRANCH 776 q1.Spadj = +autosize 777 778 q1.Link = q.Link 779 q.Link = q1 780 case AADD: 781 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 782 p.Spadj = int32(-p.From.Offset) 783 } 784 } 785 } 786 } 787 788 /* 789 // instruction scheduling 790 if(debug['Q'] == 0) 791 return; 792 793 curtext = nil; 794 q = nil; // p - 1 795 q1 = firstp; // top of block 796 o = 0; // count of instructions 797 for(p = firstp; p != nil; p = p1) { 798 p1 = p->link; 799 o++; 800 if(p->mark & NOSCHED){ 801 if(q1 != p){ 802 sched(q1, q); 803 } 804 for(; p != nil; p = p->link){ 805 if(!(p->mark & NOSCHED)) 806 break; 807 q = p; 808 } 809 p1 = p; 810 q1 = p; 811 o = 0; 812 continue; 813 } 814 if(p->mark & (LABEL|SYNC)) { 815 if(q1 != p) 816 sched(q1, q); 817 q1 = p; 818 o = 1; 819 } 820 if(p->mark & (BRANCH|SYNC)) { 821 sched(q1, p); 822 q1 = p1; 823 o = 0; 824 } 825 if(o >= NSCHED) { 826 sched(q1, p); 827 q1 = p1; 828 o = 0; 829 } 830 q = p; 831 } 832 */ 833 func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { 834 p0 := p // save entry point, but skipping the two instructions setting R2 in shared mode 835 836 // MOVD g_stackguard(g), R3 837 p = obj.Appendp(p, c.newprog) 838 839 p.As = AMOVD 840 p.From.Type = obj.TYPE_MEM 841 p.From.Reg = REGG 842 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0 843 if c.cursym.CFunc() { 844 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1 845 } 846 p.To.Type = obj.TYPE_REG 847 p.To.Reg = REG_R3 848 849 var q *obj.Prog 850 if framesize <= objabi.StackSmall { 851 // small stack: SP < stackguard 852 // CMP stackguard, SP 853 p = obj.Appendp(p, c.newprog) 854 855 p.As = ACMPU 856 p.From.Type = obj.TYPE_REG 857 p.From.Reg = REG_R3 858 p.To.Type = obj.TYPE_REG 859 p.To.Reg = REGSP 860 } else if framesize <= objabi.StackBig { 861 // large stack: SP-framesize < stackguard-StackSmall 862 // ADD $-(framesize-StackSmall), SP, R4 863 // CMP stackguard, R4 864 p = obj.Appendp(p, c.newprog) 865 866 p.As = AADD 867 p.From.Type = obj.TYPE_CONST 868 p.From.Offset = -(int64(framesize) - objabi.StackSmall) 869 p.Reg = REGSP 870 p.To.Type = obj.TYPE_REG 871 p.To.Reg = REG_R4 872 873 p = obj.Appendp(p, c.newprog) 874 p.As = ACMPU 875 p.From.Type = obj.TYPE_REG 876 p.From.Reg = REG_R3 877 p.To.Type = obj.TYPE_REG 878 p.To.Reg = REG_R4 879 } else { 880 // Such a large stack we need to protect against wraparound. 881 // If SP is close to zero: 882 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 883 // The +StackGuard on both sides is required to keep the left side positive: 884 // SP is allowed to be slightly below stackguard. See stack.h. 885 // 886 // Preemption sets stackguard to StackPreempt, a very large value. 887 // That breaks the math above, so we have to check for that explicitly. 888 // // stackguard is R3 889 // CMP R3, $StackPreempt 890 // BEQ label-of-call-to-morestack 891 // ADD $StackGuard, SP, R4 892 // SUB R3, R4 893 // MOVD $(framesize+(StackGuard-StackSmall)), R31 894 // CMPU R31, R4 895 p = obj.Appendp(p, c.newprog) 896 897 p.As = ACMP 898 p.From.Type = obj.TYPE_REG 899 p.From.Reg = REG_R3 900 p.To.Type = obj.TYPE_CONST 901 p.To.Offset = objabi.StackPreempt 902 903 p = obj.Appendp(p, c.newprog) 904 q = p 905 p.As = ABEQ 906 p.To.Type = obj.TYPE_BRANCH 907 908 p = obj.Appendp(p, c.newprog) 909 p.As = AADD 910 p.From.Type = obj.TYPE_CONST 911 p.From.Offset = objabi.StackGuard 912 p.Reg = REGSP 913 p.To.Type = obj.TYPE_REG 914 p.To.Reg = REG_R4 915 916 p = obj.Appendp(p, c.newprog) 917 p.As = ASUB 918 p.From.Type = obj.TYPE_REG 919 p.From.Reg = REG_R3 920 p.To.Type = obj.TYPE_REG 921 p.To.Reg = REG_R4 922 923 p = obj.Appendp(p, c.newprog) 924 p.As = AMOVD 925 p.From.Type = obj.TYPE_CONST 926 p.From.Offset = int64(framesize) + objabi.StackGuard - objabi.StackSmall 927 p.To.Type = obj.TYPE_REG 928 p.To.Reg = REGTMP 929 930 p = obj.Appendp(p, c.newprog) 931 p.As = ACMPU 932 p.From.Type = obj.TYPE_REG 933 p.From.Reg = REGTMP 934 p.To.Type = obj.TYPE_REG 935 p.To.Reg = REG_R4 936 } 937 938 // q1: BLT done 939 p = obj.Appendp(p, c.newprog) 940 q1 := p 941 942 p.As = ABLT 943 p.To.Type = obj.TYPE_BRANCH 944 945 // MOVD LR, R5 946 p = obj.Appendp(p, c.newprog) 947 948 p.As = AMOVD 949 p.From.Type = obj.TYPE_REG 950 p.From.Reg = REG_LR 951 p.To.Type = obj.TYPE_REG 952 p.To.Reg = REG_R5 953 if q != nil { 954 q.Pcond = p 955 } 956 957 var morestacksym *obj.LSym 958 if c.cursym.CFunc() { 959 morestacksym = c.ctxt.Lookup("runtime.morestackc") 960 } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() { 961 morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt") 962 } else { 963 morestacksym = c.ctxt.Lookup("runtime.morestack") 964 } 965 966 if c.ctxt.Flag_shared { 967 // In PPC64 PIC code, R2 is used as TOC pointer derived from R12 968 // which is the address of function entry point when entering 969 // the function. We need to preserve R2 across call to morestack. 970 // Fortunately, in shared mode, 8(SP) and 16(SP) are reserved in 971 // the caller's frame, but not used (0(SP) is caller's saved LR, 972 // 24(SP) is caller's saved R2). Use 8(SP) to save this function's R2. 973 974 // MOVD R12, 8(SP) 975 p = obj.Appendp(p, c.newprog) 976 p.As = AMOVD 977 p.From.Type = obj.TYPE_REG 978 p.From.Reg = REG_R2 979 p.To.Type = obj.TYPE_MEM 980 p.To.Reg = REGSP 981 p.To.Offset = 8 982 } 983 984 if c.ctxt.Flag_dynlink { 985 // Avoid calling morestack via a PLT when dynamically linking. The 986 // PLT stubs generated by the system linker on ppc64le when "std r2, 987 // 24(r1)" to save the TOC pointer in their callers stack 988 // frame. Unfortunately (and necessarily) morestack is called before 989 // the function that calls it sets up its frame and so the PLT ends 990 // up smashing the saved TOC pointer for its caller's caller. 991 // 992 // According to the ABI documentation there is a mechanism to avoid 993 // the TOC save that the PLT stub does (put a R_PPC64_TOCSAVE 994 // relocation on the nop after the call to morestack) but at the time 995 // of writing it is not supported at all by gold and my attempt to 996 // use it with ld.bfd caused an internal linker error. So this hack 997 // seems preferable. 998 999 // MOVD $runtime.morestack(SB), R12 1000 p = obj.Appendp(p, c.newprog) 1001 p.As = AMOVD 1002 p.From.Type = obj.TYPE_MEM 1003 p.From.Sym = morestacksym 1004 p.From.Name = obj.NAME_GOTREF 1005 p.To.Type = obj.TYPE_REG 1006 p.To.Reg = REG_R12 1007 1008 // MOVD R12, CTR 1009 p = obj.Appendp(p, c.newprog) 1010 p.As = AMOVD 1011 p.From.Type = obj.TYPE_REG 1012 p.From.Reg = REG_R12 1013 p.To.Type = obj.TYPE_REG 1014 p.To.Reg = REG_CTR 1015 1016 // BL CTR 1017 p = obj.Appendp(p, c.newprog) 1018 p.As = obj.ACALL 1019 p.From.Type = obj.TYPE_REG 1020 p.From.Reg = REG_R12 1021 p.To.Type = obj.TYPE_REG 1022 p.To.Reg = REG_CTR 1023 } else { 1024 // BL runtime.morestack(SB) 1025 p = obj.Appendp(p, c.newprog) 1026 1027 p.As = ABL 1028 p.To.Type = obj.TYPE_BRANCH 1029 p.To.Sym = morestacksym 1030 } 1031 1032 if c.ctxt.Flag_shared { 1033 // MOVD 8(SP), R2 1034 p = obj.Appendp(p, c.newprog) 1035 p.As = AMOVD 1036 p.From.Type = obj.TYPE_MEM 1037 p.From.Reg = REGSP 1038 p.From.Offset = 8 1039 p.To.Type = obj.TYPE_REG 1040 p.To.Reg = REG_R2 1041 } 1042 1043 // BR start 1044 p = obj.Appendp(p, c.newprog) 1045 p.As = ABR 1046 p.To.Type = obj.TYPE_BRANCH 1047 p.Pcond = p0.Link 1048 1049 // placeholder for q1's jump target 1050 p = obj.Appendp(p, c.newprog) 1051 1052 p.As = obj.ANOP // zero-width place holder 1053 q1.Pcond = p 1054 1055 return p 1056 } 1057 1058 var Linkppc64 = obj.LinkArch{ 1059 Arch: sys.ArchPPC64, 1060 Init: buildop, 1061 Preprocess: preprocess, 1062 Assemble: span9, 1063 Progedit: progedit, 1064 } 1065 1066 var Linkppc64le = obj.LinkArch{ 1067 Arch: sys.ArchPPC64LE, 1068 Init: buildop, 1069 Preprocess: preprocess, 1070 Assemble: span9, 1071 Progedit: progedit, 1072 }