github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/src/cmd/internal/obj/arm64/obj7.go (about) 1 // cmd/7l/noop.c, cmd/7l/obj.c, cmd/ld/pass.c from Vita Nuova. 2 // https://code.google.com/p/ken-cc/source/browse/ 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 package arm64 32 33 import ( 34 "cmd/internal/obj" 35 "cmd/internal/sys" 36 "fmt" 37 "log" 38 "math" 39 ) 40 41 var complements = []obj.As{ 42 AADD: ASUB, 43 AADDW: ASUBW, 44 ASUB: AADD, 45 ASUBW: AADDW, 46 ACMP: ACMN, 47 ACMPW: ACMNW, 48 ACMN: ACMP, 49 ACMNW: ACMPW, 50 } 51 52 func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog { 53 // MOV g_stackguard(g), R1 54 p = obj.Appendp(ctxt, p) 55 56 p.As = AMOVD 57 p.From.Type = obj.TYPE_MEM 58 p.From.Reg = REGG 59 p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0 60 if ctxt.Cursym.Cfunc { 61 p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1 62 } 63 p.To.Type = obj.TYPE_REG 64 p.To.Reg = REG_R1 65 66 q := (*obj.Prog)(nil) 67 if framesize <= obj.StackSmall { 68 // small stack: SP < stackguard 69 // MOV SP, R2 70 // CMP stackguard, R2 71 p = obj.Appendp(ctxt, p) 72 73 p.As = AMOVD 74 p.From.Type = obj.TYPE_REG 75 p.From.Reg = REGSP 76 p.To.Type = obj.TYPE_REG 77 p.To.Reg = REG_R2 78 79 p = obj.Appendp(ctxt, p) 80 p.As = ACMP 81 p.From.Type = obj.TYPE_REG 82 p.From.Reg = REG_R1 83 p.Reg = REG_R2 84 } else if framesize <= obj.StackBig { 85 // large stack: SP-framesize < stackguard-StackSmall 86 // SUB $framesize, SP, R2 87 // CMP stackguard, R2 88 p = obj.Appendp(ctxt, p) 89 90 p.As = ASUB 91 p.From.Type = obj.TYPE_CONST 92 p.From.Offset = int64(framesize) 93 p.Reg = REGSP 94 p.To.Type = obj.TYPE_REG 95 p.To.Reg = REG_R2 96 97 p = obj.Appendp(ctxt, p) 98 p.As = ACMP 99 p.From.Type = obj.TYPE_REG 100 p.From.Reg = REG_R1 101 p.Reg = REG_R2 102 } else { 103 // Such a large stack we need to protect against wraparound 104 // if SP is close to zero. 105 // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall) 106 // The +StackGuard on both sides is required to keep the left side positive: 107 // SP is allowed to be slightly below stackguard. See stack.h. 108 // CMP $StackPreempt, R1 109 // BEQ label_of_call_to_morestack 110 // ADD $StackGuard, SP, R2 111 // SUB R1, R2 112 // MOV $(framesize+(StackGuard-StackSmall)), R3 113 // CMP R3, R2 114 p = obj.Appendp(ctxt, p) 115 116 p.As = ACMP 117 p.From.Type = obj.TYPE_CONST 118 p.From.Offset = obj.StackPreempt 119 p.Reg = REG_R1 120 121 p = obj.Appendp(ctxt, p) 122 q = p 123 p.As = ABEQ 124 p.To.Type = obj.TYPE_BRANCH 125 126 p = obj.Appendp(ctxt, p) 127 p.As = AADD 128 p.From.Type = obj.TYPE_CONST 129 p.From.Offset = obj.StackGuard 130 p.Reg = REGSP 131 p.To.Type = obj.TYPE_REG 132 p.To.Reg = REG_R2 133 134 p = obj.Appendp(ctxt, p) 135 p.As = ASUB 136 p.From.Type = obj.TYPE_REG 137 p.From.Reg = REG_R1 138 p.To.Type = obj.TYPE_REG 139 p.To.Reg = REG_R2 140 141 p = obj.Appendp(ctxt, p) 142 p.As = AMOVD 143 p.From.Type = obj.TYPE_CONST 144 p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall) 145 p.To.Type = obj.TYPE_REG 146 p.To.Reg = REG_R3 147 148 p = obj.Appendp(ctxt, p) 149 p.As = ACMP 150 p.From.Type = obj.TYPE_REG 151 p.From.Reg = REG_R3 152 p.Reg = REG_R2 153 } 154 155 // BLS do-morestack 156 bls := obj.Appendp(ctxt, p) 157 bls.As = ABLS 158 bls.To.Type = obj.TYPE_BRANCH 159 160 var last *obj.Prog 161 for last = ctxt.Cursym.Text; last.Link != nil; last = last.Link { 162 } 163 164 spfix := obj.Appendp(ctxt, last) 165 spfix.As = obj.ANOP 166 spfix.Spadj = -framesize 167 168 // MOV LR, R3 169 movlr := obj.Appendp(ctxt, spfix) 170 movlr.As = AMOVD 171 movlr.From.Type = obj.TYPE_REG 172 movlr.From.Reg = REGLINK 173 movlr.To.Type = obj.TYPE_REG 174 movlr.To.Reg = REG_R3 175 if q != nil { 176 q.Pcond = movlr 177 } 178 bls.Pcond = movlr 179 180 debug := movlr 181 if false { 182 debug = obj.Appendp(ctxt, debug) 183 debug.As = AMOVD 184 debug.From.Type = obj.TYPE_CONST 185 debug.From.Offset = int64(framesize) 186 debug.To.Type = obj.TYPE_REG 187 debug.To.Reg = REGTMP 188 } 189 190 // BL runtime.morestack(SB) 191 call := obj.Appendp(ctxt, debug) 192 call.As = ABL 193 call.To.Type = obj.TYPE_BRANCH 194 morestack := "runtime.morestack" 195 switch { 196 case ctxt.Cursym.Cfunc: 197 morestack = "runtime.morestackc" 198 case ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0: 199 morestack = "runtime.morestack_noctxt" 200 } 201 call.To.Sym = obj.Linklookup(ctxt, morestack, 0) 202 203 // B start 204 jmp := obj.Appendp(ctxt, call) 205 jmp.As = AB 206 jmp.To.Type = obj.TYPE_BRANCH 207 jmp.Pcond = ctxt.Cursym.Text.Link 208 jmp.Spadj = +framesize 209 210 // placeholder for bls's jump target 211 // p = obj.Appendp(ctxt, p) 212 // p.As = obj.ANOP 213 214 return bls 215 } 216 217 func progedit(ctxt *obj.Link, p *obj.Prog) { 218 p.From.Class = 0 219 p.To.Class = 0 220 221 // $0 results in C_ZCON, which matches both C_REG and various 222 // C_xCON, however the C_REG cases in asmout don't expect a 223 // constant, so they will use the register fields and assemble 224 // a R0. To prevent that, rewrite $0 as ZR. 225 if p.From.Type == obj.TYPE_CONST && p.From.Offset == 0 { 226 p.From.Type = obj.TYPE_REG 227 p.From.Reg = REGZERO 228 } 229 if p.To.Type == obj.TYPE_CONST && p.To.Offset == 0 { 230 p.To.Type = obj.TYPE_REG 231 p.To.Reg = REGZERO 232 } 233 234 // Rewrite BR/BL to symbol as TYPE_BRANCH. 235 switch p.As { 236 case AB, 237 ABL, 238 obj.ARET, 239 obj.ADUFFZERO, 240 obj.ADUFFCOPY: 241 if p.To.Sym != nil { 242 p.To.Type = obj.TYPE_BRANCH 243 } 244 break 245 } 246 247 // Rewrite float constants to values stored in memory. 248 switch p.As { 249 case AFMOVS: 250 if p.From.Type == obj.TYPE_FCONST { 251 f32 := float32(p.From.Val.(float64)) 252 i32 := math.Float32bits(f32) 253 literal := fmt.Sprintf("$f32.%08x", i32) 254 s := obj.Linklookup(ctxt, literal, 0) 255 s.Size = 4 256 p.From.Type = obj.TYPE_MEM 257 p.From.Sym = s 258 p.From.Sym.Local = true 259 p.From.Name = obj.NAME_EXTERN 260 p.From.Offset = 0 261 } 262 263 case AFMOVD: 264 if p.From.Type == obj.TYPE_FCONST { 265 i64 := math.Float64bits(p.From.Val.(float64)) 266 literal := fmt.Sprintf("$f64.%016x", i64) 267 s := obj.Linklookup(ctxt, literal, 0) 268 s.Size = 8 269 p.From.Type = obj.TYPE_MEM 270 p.From.Sym = s 271 p.From.Sym.Local = true 272 p.From.Name = obj.NAME_EXTERN 273 p.From.Offset = 0 274 } 275 276 break 277 } 278 279 // Rewrite negative immediates as positive immediates with 280 // complementary instruction. 281 switch p.As { 282 case AADD, 283 AADDW, 284 ASUB, 285 ASUBW, 286 ACMP, 287 ACMPW, 288 ACMN, 289 ACMNW: 290 if p.From.Type == obj.NAME_EXTERN && p.From.Offset < 0 { 291 p.From.Offset = -p.From.Offset 292 p.As = complements[p.As] 293 } 294 295 break 296 } 297 298 if ctxt.Flag_dynlink { 299 rewriteToUseGot(ctxt, p) 300 } 301 } 302 303 // Rewrite p, if necessary, to access global data via the global offset table. 304 func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) { 305 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO { 306 // ADUFFxxx $offset 307 // becomes 308 // MOVD runtime.duffxxx@GOT, REGTMP 309 // ADD $offset, REGTMP 310 // CALL REGTMP 311 var sym *obj.LSym 312 if p.As == obj.ADUFFZERO { 313 sym = obj.Linklookup(ctxt, "runtime.duffzero", 0) 314 } else { 315 sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0) 316 } 317 offset := p.To.Offset 318 p.As = AMOVD 319 p.From.Type = obj.TYPE_MEM 320 p.From.Name = obj.NAME_GOTREF 321 p.From.Sym = sym 322 p.To.Type = obj.TYPE_REG 323 p.To.Reg = REGTMP 324 p.To.Name = obj.NAME_NONE 325 p.To.Offset = 0 326 p.To.Sym = nil 327 p1 := obj.Appendp(ctxt, p) 328 p1.As = AADD 329 p1.From.Type = obj.TYPE_CONST 330 p1.From.Offset = offset 331 p1.To.Type = obj.TYPE_REG 332 p1.To.Reg = REGTMP 333 p2 := obj.Appendp(ctxt, p1) 334 p2.As = obj.ACALL 335 p2.To.Type = obj.TYPE_REG 336 p2.To.Reg = REGTMP 337 } 338 339 // We only care about global data: NAME_EXTERN means a global 340 // symbol in the Go sense, and p.Sym.Local is true for a few 341 // internally defined symbols. 342 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local { 343 // MOVD $sym, Rx becomes MOVD sym@GOT, Rx 344 // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx 345 if p.As != AMOVD { 346 ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p) 347 } 348 if p.To.Type != obj.TYPE_REG { 349 ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p) 350 } 351 p.From.Type = obj.TYPE_MEM 352 p.From.Name = obj.NAME_GOTREF 353 if p.From.Offset != 0 { 354 q := obj.Appendp(ctxt, p) 355 q.As = AADD 356 q.From.Type = obj.TYPE_CONST 357 q.From.Offset = p.From.Offset 358 q.To = p.To 359 p.From.Offset = 0 360 } 361 } 362 if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { 363 ctxt.Diag("don't know how to handle %v with -dynlink", p) 364 } 365 var source *obj.Addr 366 // MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry 367 // MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVD Ry, (REGTMP) 368 // An addition may be inserted between the two MOVs if there is an offset. 369 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local { 370 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local { 371 ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p) 372 } 373 source = &p.From 374 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local { 375 source = &p.To 376 } else { 377 return 378 } 379 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { 380 return 381 } 382 if source.Sym.Type == obj.STLSBSS { 383 return 384 } 385 if source.Type != obj.TYPE_MEM { 386 ctxt.Diag("don't know how to handle %v with -dynlink", p) 387 } 388 p1 := obj.Appendp(ctxt, p) 389 p2 := obj.Appendp(ctxt, p1) 390 p1.As = AMOVD 391 p1.From.Type = obj.TYPE_MEM 392 p1.From.Sym = source.Sym 393 p1.From.Name = obj.NAME_GOTREF 394 p1.To.Type = obj.TYPE_REG 395 p1.To.Reg = REGTMP 396 397 p2.As = p.As 398 p2.From = p.From 399 p2.To = p.To 400 if p.From.Name == obj.NAME_EXTERN { 401 p2.From.Reg = REGTMP 402 p2.From.Name = obj.NAME_NONE 403 p2.From.Sym = nil 404 } else if p.To.Name == obj.NAME_EXTERN { 405 p2.To.Reg = REGTMP 406 p2.To.Name = obj.NAME_NONE 407 p2.To.Sym = nil 408 } else { 409 return 410 } 411 obj.Nopout(p) 412 } 413 414 func follow(ctxt *obj.Link, s *obj.LSym) { 415 ctxt.Cursym = s 416 417 firstp := ctxt.NewProg() 418 lastp := firstp 419 xfol(ctxt, s.Text, &lastp) 420 lastp.Link = nil 421 s.Text = firstp.Link 422 } 423 424 func relinv(a obj.As) obj.As { 425 switch a { 426 case ABEQ: 427 return ABNE 428 case ABNE: 429 return ABEQ 430 case ABCS: 431 return ABCC 432 case ABHS: 433 return ABLO 434 case ABCC: 435 return ABCS 436 case ABLO: 437 return ABHS 438 case ABMI: 439 return ABPL 440 case ABPL: 441 return ABMI 442 case ABVS: 443 return ABVC 444 case ABVC: 445 return ABVS 446 case ABHI: 447 return ABLS 448 case ABLS: 449 return ABHI 450 case ABGE: 451 return ABLT 452 case ABLT: 453 return ABGE 454 case ABGT: 455 return ABLE 456 case ABLE: 457 return ABGT 458 } 459 460 log.Fatalf("unknown relation: %s", Anames[a]) 461 return 0 462 } 463 464 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 465 var q *obj.Prog 466 var r *obj.Prog 467 var i int 468 469 loop: 470 if p == nil { 471 return 472 } 473 a := p.As 474 if a == AB { 475 q = p.Pcond 476 if q != nil { 477 p.Mark |= FOLL 478 p = q 479 if !(p.Mark&FOLL != 0) { 480 goto loop 481 } 482 } 483 } 484 485 if p.Mark&FOLL != 0 { 486 i = 0 487 q = p 488 for ; i < 4; i, q = i+1, q.Link { 489 if q == *last || q == nil { 490 break 491 } 492 a = q.As 493 if a == obj.ANOP { 494 i-- 495 continue 496 } 497 498 if a == AB || a == obj.ARET || a == AERET { 499 goto copy 500 } 501 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 502 continue 503 } 504 if a != ABEQ && a != ABNE { 505 continue 506 } 507 508 copy: 509 for { 510 r = ctxt.NewProg() 511 *r = *p 512 if !(r.Mark&FOLL != 0) { 513 fmt.Printf("can't happen 1\n") 514 } 515 r.Mark |= FOLL 516 if p != q { 517 p = p.Link 518 (*last).Link = r 519 *last = r 520 continue 521 } 522 523 (*last).Link = r 524 *last = r 525 if a == AB || a == obj.ARET || a == AERET { 526 return 527 } 528 if a == ABNE { 529 r.As = ABEQ 530 } else { 531 r.As = ABNE 532 } 533 r.Pcond = p.Link 534 r.Link = p.Pcond 535 if !(r.Link.Mark&FOLL != 0) { 536 xfol(ctxt, r.Link, last) 537 } 538 if !(r.Pcond.Mark&FOLL != 0) { 539 fmt.Printf("can't happen 2\n") 540 } 541 return 542 } 543 } 544 545 a = AB 546 q = ctxt.NewProg() 547 q.As = a 548 q.Lineno = p.Lineno 549 q.To.Type = obj.TYPE_BRANCH 550 q.To.Offset = p.Pc 551 q.Pcond = p 552 p = q 553 } 554 555 p.Mark |= FOLL 556 (*last).Link = p 557 *last = p 558 if a == AB || a == obj.ARET || a == AERET { 559 return 560 } 561 if p.Pcond != nil { 562 if a != ABL && p.Link != nil { 563 q = obj.Brchain(ctxt, p.Link) 564 if a != obj.ATEXT { 565 if q != nil && (q.Mark&FOLL != 0) { 566 p.As = relinv(a) 567 p.Link = p.Pcond 568 p.Pcond = q 569 } 570 } 571 572 xfol(ctxt, p.Link, last) 573 q = obj.Brchain(ctxt, p.Pcond) 574 if q == nil { 575 q = p.Pcond 576 } 577 if q.Mark&FOLL != 0 { 578 p.Pcond = q 579 return 580 } 581 582 p = q 583 goto loop 584 } 585 } 586 587 p = p.Link 588 goto loop 589 } 590 591 func preprocess(ctxt *obj.Link, cursym *obj.LSym) { 592 ctxt.Cursym = cursym 593 594 if cursym.Text == nil || cursym.Text.Link == nil { 595 return 596 } 597 598 p := cursym.Text 599 textstksiz := p.To.Offset 600 aoffset := int32(textstksiz) 601 602 cursym.Args = p.To.Val.(int32) 603 cursym.Locals = int32(textstksiz) 604 605 /* 606 * find leaf subroutines 607 * strip NOPs 608 * expand RET 609 */ 610 ctxt.Bso.Flush() 611 q := (*obj.Prog)(nil) 612 var q1 *obj.Prog 613 for p := cursym.Text; p != nil; p = p.Link { 614 switch p.As { 615 case obj.ATEXT: 616 p.Mark |= LEAF 617 618 case obj.ARET: 619 break 620 621 case obj.ANOP: 622 q1 = p.Link 623 q.Link = q1 /* q is non-nop */ 624 q1.Mark |= p.Mark 625 continue 626 627 case ABL, 628 obj.ADUFFZERO, 629 obj.ADUFFCOPY: 630 cursym.Text.Mark &^= LEAF 631 fallthrough 632 633 case ACBNZ, 634 ACBZ, 635 ACBNZW, 636 ACBZW, 637 ATBZ, 638 ATBNZ, 639 AB, 640 ABEQ, 641 ABNE, 642 ABCS, 643 ABHS, 644 ABCC, 645 ABLO, 646 ABMI, 647 ABPL, 648 ABVS, 649 ABVC, 650 ABHI, 651 ABLS, 652 ABGE, 653 ABLT, 654 ABGT, 655 ABLE, 656 AADR, /* strange */ 657 AADRP: 658 q1 = p.Pcond 659 660 if q1 != nil { 661 for q1.As == obj.ANOP { 662 q1 = q1.Link 663 p.Pcond = q1 664 } 665 } 666 667 break 668 } 669 670 q = p 671 } 672 673 var q2 *obj.Prog 674 var retjmp *obj.LSym 675 for p := cursym.Text; p != nil; p = p.Link { 676 o := p.As 677 switch o { 678 case obj.ATEXT: 679 cursym.Text = p 680 if textstksiz < 0 { 681 ctxt.Autosize = 0 682 } else { 683 ctxt.Autosize = int32(textstksiz + 8) 684 } 685 if (cursym.Text.Mark&LEAF != 0) && ctxt.Autosize <= 8 { 686 ctxt.Autosize = 0 687 } else if ctxt.Autosize&(16-1) != 0 { 688 // The frame includes an LR. 689 // If the frame size is 8, it's only an LR, 690 // so there's no potential for breaking references to 691 // local variables by growing the frame size, 692 // because there are no local variables. 693 // But otherwise, if there is a non-empty locals section, 694 // the author of the code is responsible for making sure 695 // that the frame size is 8 mod 16. 696 if ctxt.Autosize == 8 { 697 ctxt.Autosize += 8 698 cursym.Locals += 8 699 } else { 700 ctxt.Diag("%v: unaligned frame size %d - must be 8 mod 16 (or 0)", p, ctxt.Autosize-8) 701 } 702 } 703 p.To.Offset = int64(ctxt.Autosize) - 8 704 if ctxt.Autosize == 0 && !(cursym.Text.Mark&LEAF != 0) { 705 if ctxt.Debugvlog != 0 { 706 fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Text.From.Sym.Name) 707 } 708 ctxt.Bso.Flush() 709 cursym.Text.Mark |= LEAF 710 } 711 712 if !(p.From3.Offset&obj.NOSPLIT != 0) { 713 p = stacksplit(ctxt, p, ctxt.Autosize) // emit split check 714 } 715 716 aoffset = ctxt.Autosize 717 if aoffset > 0xF0 { 718 aoffset = 0xF0 719 } 720 if cursym.Text.Mark&LEAF != 0 { 721 cursym.Leaf = true 722 if ctxt.Autosize == 0 { 723 break 724 } 725 aoffset = 0 726 } 727 728 q = p 729 if ctxt.Autosize > aoffset { 730 q = ctxt.NewProg() 731 q.As = ASUB 732 q.Lineno = p.Lineno 733 q.From.Type = obj.TYPE_CONST 734 q.From.Offset = int64(ctxt.Autosize) - int64(aoffset) 735 q.To.Type = obj.TYPE_REG 736 q.To.Reg = REGSP 737 q.Spadj = int32(q.From.Offset) 738 q.Link = p.Link 739 p.Link = q 740 if cursym.Text.Mark&LEAF != 0 { 741 break 742 } 743 } 744 745 q1 = ctxt.NewProg() 746 q1.As = AMOVD 747 q1.Lineno = p.Lineno 748 q1.From.Type = obj.TYPE_REG 749 q1.From.Reg = REGLINK 750 q1.To.Type = obj.TYPE_MEM 751 q1.Scond = C_XPRE 752 q1.To.Offset = int64(-aoffset) 753 q1.To.Reg = REGSP 754 q1.Link = q.Link 755 q1.Spadj = aoffset 756 q.Link = q1 757 758 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 759 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 760 // 761 // MOV g_panic(g), R1 762 // CMP ZR, R1 763 // BEQ end 764 // MOV panic_argp(R1), R2 765 // ADD $(autosize+8), RSP, R3 766 // CMP R2, R3 767 // BNE end 768 // ADD $8, RSP, R4 769 // MOVD R4, panic_argp(R1) 770 // end: 771 // NOP 772 // 773 // The NOP is needed to give the jumps somewhere to land. 774 // It is a liblink NOP, not a ARM64 NOP: it encodes to 0 instruction bytes. 775 q = q1 776 777 q = obj.Appendp(ctxt, q) 778 q.As = AMOVD 779 q.From.Type = obj.TYPE_MEM 780 q.From.Reg = REGG 781 q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic 782 q.To.Type = obj.TYPE_REG 783 q.To.Reg = REG_R1 784 785 q = obj.Appendp(ctxt, q) 786 q.As = ACMP 787 q.From.Type = obj.TYPE_REG 788 q.From.Reg = REGZERO 789 q.Reg = REG_R1 790 791 q = obj.Appendp(ctxt, q) 792 q.As = ABEQ 793 q.To.Type = obj.TYPE_BRANCH 794 q1 = q 795 796 q = obj.Appendp(ctxt, q) 797 q.As = AMOVD 798 q.From.Type = obj.TYPE_MEM 799 q.From.Reg = REG_R1 800 q.From.Offset = 0 // Panic.argp 801 q.To.Type = obj.TYPE_REG 802 q.To.Reg = REG_R2 803 804 q = obj.Appendp(ctxt, q) 805 q.As = AADD 806 q.From.Type = obj.TYPE_CONST 807 q.From.Offset = int64(ctxt.Autosize) + 8 808 q.Reg = REGSP 809 q.To.Type = obj.TYPE_REG 810 q.To.Reg = REG_R3 811 812 q = obj.Appendp(ctxt, q) 813 q.As = ACMP 814 q.From.Type = obj.TYPE_REG 815 q.From.Reg = REG_R2 816 q.Reg = REG_R3 817 818 q = obj.Appendp(ctxt, q) 819 q.As = ABNE 820 q.To.Type = obj.TYPE_BRANCH 821 q2 = q 822 823 q = obj.Appendp(ctxt, q) 824 q.As = AADD 825 q.From.Type = obj.TYPE_CONST 826 q.From.Offset = 8 827 q.Reg = REGSP 828 q.To.Type = obj.TYPE_REG 829 q.To.Reg = REG_R4 830 831 q = obj.Appendp(ctxt, q) 832 q.As = AMOVD 833 q.From.Type = obj.TYPE_REG 834 q.From.Reg = REG_R4 835 q.To.Type = obj.TYPE_MEM 836 q.To.Reg = REG_R1 837 q.To.Offset = 0 // Panic.argp 838 839 q = obj.Appendp(ctxt, q) 840 841 q.As = obj.ANOP 842 q1.Pcond = q 843 q2.Pcond = q 844 } 845 846 case obj.ARET: 847 nocache(p) 848 if p.From.Type == obj.TYPE_CONST { 849 ctxt.Diag("using BECOME (%v) is not supported!", p) 850 break 851 } 852 853 retjmp = p.To.Sym 854 p.To = obj.Addr{} 855 if cursym.Text.Mark&LEAF != 0 { 856 if ctxt.Autosize != 0 { 857 p.As = AADD 858 p.From.Type = obj.TYPE_CONST 859 p.From.Offset = int64(ctxt.Autosize) 860 p.To.Type = obj.TYPE_REG 861 p.To.Reg = REGSP 862 p.Spadj = -ctxt.Autosize 863 } 864 } else { 865 /* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/ 866 aoffset = ctxt.Autosize 867 868 if aoffset > 0xF0 { 869 aoffset = 0xF0 870 } 871 p.As = AMOVD 872 p.From.Type = obj.TYPE_MEM 873 p.Scond = C_XPOST 874 p.From.Offset = int64(aoffset) 875 p.From.Reg = REGSP 876 p.To.Type = obj.TYPE_REG 877 p.To.Reg = REGLINK 878 p.Spadj = -aoffset 879 if ctxt.Autosize > aoffset { 880 q = ctxt.NewProg() 881 q.As = AADD 882 q.From.Type = obj.TYPE_CONST 883 q.From.Offset = int64(ctxt.Autosize) - int64(aoffset) 884 q.To.Type = obj.TYPE_REG 885 q.To.Reg = REGSP 886 q.Link = p.Link 887 q.Spadj = int32(-q.From.Offset) 888 q.Lineno = p.Lineno 889 p.Link = q 890 p = q 891 } 892 } 893 894 if p.As != obj.ARET { 895 q = ctxt.NewProg() 896 q.Lineno = p.Lineno 897 q.Link = p.Link 898 p.Link = q 899 p = q 900 } 901 902 if retjmp != nil { // retjmp 903 p.As = AB 904 p.To.Type = obj.TYPE_BRANCH 905 p.To.Sym = retjmp 906 p.Spadj = +ctxt.Autosize 907 break 908 } 909 910 p.As = obj.ARET 911 p.To.Type = obj.TYPE_MEM 912 p.To.Offset = 0 913 p.To.Reg = REGLINK 914 p.Spadj = +ctxt.Autosize 915 916 case AADD, ASUB: 917 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 918 if p.As == AADD { 919 p.Spadj = int32(-p.From.Offset) 920 } else { 921 p.Spadj = int32(+p.From.Offset) 922 } 923 } 924 break 925 } 926 } 927 } 928 929 func nocache(p *obj.Prog) { 930 p.Optab = 0 931 p.From.Class = 0 932 p.To.Class = 0 933 } 934 935 var unaryDst = map[obj.As]bool{ 936 AWORD: true, 937 ADWORD: true, 938 ABL: true, 939 AB: true, 940 ASVC: true, 941 } 942 943 var Linkarm64 = obj.LinkArch{ 944 Arch: sys.ArchARM64, 945 Preprocess: preprocess, 946 Assemble: span7, 947 Follow: follow, 948 Progedit: progedit, 949 UnaryDst: unaryDst, 950 }