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