github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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 "encoding/binary" 36 "fmt" 37 "log" 38 "math" 39 ) 40 41 var complements = []int16{ 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 != 0 { 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 // MOV LR, R3 165 movlr := obj.Appendp(ctxt, last) 166 movlr.As = AMOVD 167 movlr.From.Type = obj.TYPE_REG 168 movlr.From.Reg = REGLINK 169 movlr.To.Type = obj.TYPE_REG 170 movlr.To.Reg = REG_R3 171 if q != nil { 172 q.Pcond = movlr 173 } 174 bls.Pcond = movlr 175 176 debug := movlr 177 if false { 178 debug = obj.Appendp(ctxt, debug) 179 debug.As = AMOVD 180 debug.From.Type = obj.TYPE_CONST 181 debug.From.Offset = int64(framesize) 182 debug.To.Type = obj.TYPE_REG 183 debug.To.Reg = REGTMP 184 } 185 186 // BL runtime.morestack(SB) 187 call := obj.Appendp(ctxt, debug) 188 call.As = ABL 189 call.To.Type = obj.TYPE_BRANCH 190 morestack := "runtime.morestack" 191 switch { 192 case ctxt.Cursym.Cfunc != 0: 193 morestack = "runtime.morestackc" 194 case ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0: 195 morestack = "runtime.morestack_noctxt" 196 } 197 call.To.Sym = obj.Linklookup(ctxt, morestack, 0) 198 199 // B start 200 jmp := obj.Appendp(ctxt, call) 201 jmp.As = AB 202 jmp.To.Type = obj.TYPE_BRANCH 203 jmp.Pcond = ctxt.Cursym.Text.Link 204 205 // placeholder for bls's jump target 206 // p = obj.Appendp(ctxt, p) 207 // p.As = obj.ANOP 208 209 return bls 210 } 211 212 func progedit(ctxt *obj.Link, p *obj.Prog) { 213 p.From.Class = 0 214 p.To.Class = 0 215 216 // $0 results in C_ZCON, which matches both C_REG and various 217 // C_xCON, however the C_REG cases in asmout don't expect a 218 // constant, so they will use the register fields and assemble 219 // a R0. To prevent that, rewrite $0 as ZR. 220 if p.From.Type == obj.TYPE_CONST && p.From.Offset == 0 { 221 p.From.Type = obj.TYPE_REG 222 p.From.Reg = REGZERO 223 } 224 if p.To.Type == obj.TYPE_CONST && p.To.Offset == 0 { 225 p.To.Type = obj.TYPE_REG 226 p.To.Reg = REGZERO 227 } 228 229 // Rewrite BR/BL to symbol as TYPE_BRANCH. 230 switch p.As { 231 case AB, 232 ABL, 233 obj.ARET, 234 obj.ADUFFZERO, 235 obj.ADUFFCOPY: 236 if p.To.Sym != nil { 237 p.To.Type = obj.TYPE_BRANCH 238 } 239 break 240 } 241 242 // Rewrite float constants to values stored in memory. 243 switch p.As { 244 case AFMOVS: 245 if p.From.Type == obj.TYPE_FCONST { 246 f32 := float32(p.From.Val.(float64)) 247 i32 := math.Float32bits(f32) 248 literal := fmt.Sprintf("$f32.%08x", uint32(i32)) 249 s := obj.Linklookup(ctxt, literal, 0) 250 s.Size = 4 251 p.From.Type = obj.TYPE_MEM 252 p.From.Sym = s 253 p.From.Sym.Local = true 254 p.From.Name = obj.NAME_EXTERN 255 p.From.Offset = 0 256 } 257 258 case AFMOVD: 259 if p.From.Type == obj.TYPE_FCONST { 260 i64 := math.Float64bits(p.From.Val.(float64)) 261 literal := fmt.Sprintf("$f64.%016x", uint64(i64)) 262 s := obj.Linklookup(ctxt, literal, 0) 263 s.Size = 8 264 p.From.Type = obj.TYPE_MEM 265 p.From.Sym = s 266 p.From.Sym.Local = true 267 p.From.Name = obj.NAME_EXTERN 268 p.From.Offset = 0 269 } 270 271 break 272 } 273 274 // Rewrite negative immediates as positive immediates with 275 // complementary instruction. 276 switch p.As { 277 case AADD, 278 AADDW, 279 ASUB, 280 ASUBW, 281 ACMP, 282 ACMPW, 283 ACMN, 284 ACMNW: 285 if p.From.Type == obj.NAME_EXTERN && p.From.Offset < 0 { 286 p.From.Offset = -p.From.Offset 287 p.As = complements[p.As] 288 } 289 290 break 291 } 292 293 if ctxt.Flag_dynlink { 294 rewriteToUseGot(ctxt, p) 295 } 296 } 297 298 // Rewrite p, if necessary, to access global data via the global offset table. 299 func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) { 300 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO { 301 // ADUFFxxx $offset 302 // becomes 303 // MOVD runtime.duffxxx@GOT, REGTMP 304 // ADD $offset, REGTMP 305 // CALL REGTMP 306 var sym *obj.LSym 307 if p.As == obj.ADUFFZERO { 308 sym = obj.Linklookup(ctxt, "runtime.duffzero", 0) 309 } else { 310 sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0) 311 } 312 offset := p.To.Offset 313 p.As = AMOVD 314 p.From.Type = obj.TYPE_MEM 315 p.From.Name = obj.NAME_GOTREF 316 p.From.Sym = sym 317 p.To.Type = obj.TYPE_REG 318 p.To.Reg = REGTMP 319 p.To.Name = obj.NAME_NONE 320 p.To.Offset = 0 321 p.To.Sym = nil 322 p1 := obj.Appendp(ctxt, p) 323 p1.As = AADD 324 p1.From.Type = obj.TYPE_CONST 325 p1.From.Offset = offset 326 p1.To.Type = obj.TYPE_REG 327 p1.To.Reg = REGTMP 328 p2 := obj.Appendp(ctxt, p1) 329 p2.As = obj.ACALL 330 p2.To.Type = obj.TYPE_REG 331 p2.To.Reg = REGTMP 332 } 333 334 // We only care about global data: NAME_EXTERN means a global 335 // symbol in the Go sense, and p.Sym.Local is true for a few 336 // internally defined symbols. 337 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local { 338 // MOVD $sym, Rx becomes MOVD sym@GOT, Rx 339 // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx 340 if p.As != AMOVD { 341 ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p) 342 } 343 if p.To.Type != obj.TYPE_REG { 344 ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p) 345 } 346 p.From.Type = obj.TYPE_MEM 347 p.From.Name = obj.NAME_GOTREF 348 if p.From.Offset != 0 { 349 q := obj.Appendp(ctxt, p) 350 q.As = AADD 351 q.From.Type = obj.TYPE_CONST 352 q.From.Offset = p.From.Offset 353 q.To = p.To 354 p.From.Offset = 0 355 } 356 } 357 if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { 358 ctxt.Diag("don't know how to handle %v with -dynlink", p) 359 } 360 var source *obj.Addr 361 // MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry 362 // MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVD Ry, (REGTMP) 363 // An addition may be inserted between the two MOVs if there is an offset. 364 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local { 365 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local { 366 ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p) 367 } 368 source = &p.From 369 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local { 370 source = &p.To 371 } else { 372 return 373 } 374 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { 375 return 376 } 377 if source.Sym.Type == obj.STLSBSS { 378 return 379 } 380 if source.Type != obj.TYPE_MEM { 381 ctxt.Diag("don't know how to handle %v with -dynlink", p) 382 } 383 p1 := obj.Appendp(ctxt, p) 384 p2 := obj.Appendp(ctxt, p1) 385 p1.As = AMOVD 386 p1.From.Type = obj.TYPE_MEM 387 p1.From.Sym = source.Sym 388 p1.From.Name = obj.NAME_GOTREF 389 p1.To.Type = obj.TYPE_REG 390 p1.To.Reg = REGTMP 391 392 p2.As = p.As 393 p2.From = p.From 394 p2.To = p.To 395 if p.From.Name == obj.NAME_EXTERN { 396 p2.From.Reg = REGTMP 397 p2.From.Name = obj.NAME_NONE 398 p2.From.Sym = nil 399 } else if p.To.Name == obj.NAME_EXTERN { 400 p2.To.Reg = REGTMP 401 p2.To.Name = obj.NAME_NONE 402 p2.To.Sym = nil 403 } else { 404 return 405 } 406 obj.Nopout(p) 407 } 408 409 func follow(ctxt *obj.Link, s *obj.LSym) { 410 ctxt.Cursym = s 411 412 firstp := ctxt.NewProg() 413 lastp := firstp 414 xfol(ctxt, s.Text, &lastp) 415 lastp.Link = nil 416 s.Text = firstp.Link 417 } 418 419 func relinv(a int) int { 420 switch a { 421 case ABEQ: 422 return ABNE 423 case ABNE: 424 return ABEQ 425 case ABCS: 426 return ABCC 427 case ABHS: 428 return ABLO 429 case ABCC: 430 return ABCS 431 case ABLO: 432 return ABHS 433 case ABMI: 434 return ABPL 435 case ABPL: 436 return ABMI 437 case ABVS: 438 return ABVC 439 case ABVC: 440 return ABVS 441 case ABHI: 442 return ABLS 443 case ABLS: 444 return ABHI 445 case ABGE: 446 return ABLT 447 case ABLT: 448 return ABGE 449 case ABGT: 450 return ABLE 451 case ABLE: 452 return ABGT 453 } 454 455 log.Fatalf("unknown relation: %s", Anames[a]) 456 return 0 457 } 458 459 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 460 var q *obj.Prog 461 var r *obj.Prog 462 var a int 463 var i int 464 465 loop: 466 if p == nil { 467 return 468 } 469 a = int(p.As) 470 if a == AB { 471 q = p.Pcond 472 if q != nil { 473 p.Mark |= FOLL 474 p = q 475 if !(p.Mark&FOLL != 0) { 476 goto loop 477 } 478 } 479 } 480 481 if p.Mark&FOLL != 0 { 482 i = 0 483 q = p 484 for ; i < 4; i, q = i+1, q.Link { 485 if q == *last || q == nil { 486 break 487 } 488 a = int(q.As) 489 if a == obj.ANOP { 490 i-- 491 continue 492 } 493 494 if a == AB || a == obj.ARET || a == AERET { 495 goto copy 496 } 497 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 498 continue 499 } 500 if a != ABEQ && a != ABNE { 501 continue 502 } 503 504 copy: 505 for { 506 r = ctxt.NewProg() 507 *r = *p 508 if !(r.Mark&FOLL != 0) { 509 fmt.Printf("cant happen 1\n") 510 } 511 r.Mark |= FOLL 512 if p != q { 513 p = p.Link 514 (*last).Link = r 515 *last = r 516 continue 517 } 518 519 (*last).Link = r 520 *last = r 521 if a == AB || a == obj.ARET || a == AERET { 522 return 523 } 524 if a == ABNE { 525 r.As = ABEQ 526 } else { 527 r.As = ABNE 528 } 529 r.Pcond = p.Link 530 r.Link = p.Pcond 531 if !(r.Link.Mark&FOLL != 0) { 532 xfol(ctxt, r.Link, last) 533 } 534 if !(r.Pcond.Mark&FOLL != 0) { 535 fmt.Printf("cant happen 2\n") 536 } 537 return 538 } 539 } 540 541 a = AB 542 q = ctxt.NewProg() 543 q.As = int16(a) 544 q.Lineno = p.Lineno 545 q.To.Type = obj.TYPE_BRANCH 546 q.To.Offset = p.Pc 547 q.Pcond = p 548 p = q 549 } 550 551 p.Mark |= FOLL 552 (*last).Link = p 553 *last = p 554 if a == AB || a == obj.ARET || a == AERET { 555 return 556 } 557 if p.Pcond != nil { 558 if a != ABL && p.Link != nil { 559 q = obj.Brchain(ctxt, p.Link) 560 if a != obj.ATEXT { 561 if q != nil && (q.Mark&FOLL != 0) { 562 p.As = int16(relinv(a)) 563 p.Link = p.Pcond 564 p.Pcond = q 565 } 566 } 567 568 xfol(ctxt, p.Link, last) 569 q = obj.Brchain(ctxt, p.Pcond) 570 if q == nil { 571 q = p.Pcond 572 } 573 if q.Mark&FOLL != 0 { 574 p.Pcond = q 575 return 576 } 577 578 p = q 579 goto loop 580 } 581 } 582 583 p = p.Link 584 goto loop 585 } 586 587 func preprocess(ctxt *obj.Link, cursym *obj.LSym) { 588 ctxt.Cursym = cursym 589 590 if cursym.Text == nil || cursym.Text.Link == nil { 591 return 592 } 593 594 p := cursym.Text 595 textstksiz := p.To.Offset 596 aoffset := int32(textstksiz) 597 598 cursym.Args = p.To.Val.(int32) 599 cursym.Locals = int32(textstksiz) 600 601 /* 602 * find leaf subroutines 603 * strip NOPs 604 * expand RET 605 */ 606 ctxt.Bso.Flush() 607 q := (*obj.Prog)(nil) 608 var q1 *obj.Prog 609 for p := cursym.Text; p != nil; p = p.Link { 610 switch p.As { 611 case obj.ATEXT: 612 p.Mark |= LEAF 613 614 case obj.ARET: 615 break 616 617 case obj.ANOP: 618 q1 = p.Link 619 q.Link = q1 /* q is non-nop */ 620 q1.Mark |= p.Mark 621 continue 622 623 case ABL, 624 obj.ADUFFZERO, 625 obj.ADUFFCOPY: 626 cursym.Text.Mark &^= LEAF 627 fallthrough 628 629 case ACBNZ, 630 ACBZ, 631 ACBNZW, 632 ACBZW, 633 ATBZ, 634 ATBNZ, 635 AB, 636 ABEQ, 637 ABNE, 638 ABCS, 639 ABHS, 640 ABCC, 641 ABLO, 642 ABMI, 643 ABPL, 644 ABVS, 645 ABVC, 646 ABHI, 647 ABLS, 648 ABGE, 649 ABLT, 650 ABGT, 651 ABLE, 652 AADR, /* strange */ 653 AADRP: 654 q1 = p.Pcond 655 656 if q1 != nil { 657 for q1.As == obj.ANOP { 658 q1 = q1.Link 659 p.Pcond = q1 660 } 661 } 662 663 break 664 } 665 666 q = p 667 } 668 669 var o int 670 var q2 *obj.Prog 671 var retjmp *obj.LSym 672 for p := cursym.Text; p != nil; p = p.Link { 673 o = int(p.As) 674 switch o { 675 case obj.ATEXT: 676 cursym.Text = p 677 if textstksiz < 0 { 678 ctxt.Autosize = 0 679 } else { 680 ctxt.Autosize = int32(textstksiz + 8) 681 } 682 if (cursym.Text.Mark&LEAF != 0) && ctxt.Autosize <= 8 { 683 ctxt.Autosize = 0 684 } else if ctxt.Autosize&(16-1) != 0 { 685 // The frame includes an LR. 686 // If the frame size is 8, it's only an LR, 687 // so there's no potential for breaking references to 688 // local variables by growing the frame size, 689 // because there are no local variables. 690 // But otherwise, if there is a non-empty locals section, 691 // the author of the code is responsible for making sure 692 // that the frame size is 8 mod 16. 693 if ctxt.Autosize == 8 { 694 ctxt.Autosize += 8 695 cursym.Locals += 8 696 } else { 697 ctxt.Diag("%v: unaligned frame size %d - must be 8 mod 16 (or 0)", p, ctxt.Autosize-8) 698 } 699 } 700 p.To.Offset = int64(ctxt.Autosize) - 8 701 if ctxt.Autosize == 0 && !(cursym.Text.Mark&LEAF != 0) { 702 if ctxt.Debugvlog != 0 { 703 fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Text.From.Sym.Name) 704 } 705 ctxt.Bso.Flush() 706 cursym.Text.Mark |= LEAF 707 } 708 709 if !(p.From3.Offset&obj.NOSPLIT != 0) { 710 p = stacksplit(ctxt, p, ctxt.Autosize) // emit split check 711 } 712 713 aoffset = ctxt.Autosize 714 if aoffset > 0xF0 { 715 aoffset = 0xF0 716 } 717 if cursym.Text.Mark&LEAF != 0 { 718 cursym.Leaf = 1 719 if ctxt.Autosize == 0 { 720 break 721 } 722 aoffset = 0 723 } 724 725 q = p 726 if ctxt.Autosize > aoffset { 727 q = ctxt.NewProg() 728 q.As = ASUB 729 q.Lineno = p.Lineno 730 q.From.Type = obj.TYPE_CONST 731 q.From.Offset = int64(ctxt.Autosize) - int64(aoffset) 732 q.To.Type = obj.TYPE_REG 733 q.To.Reg = REGSP 734 q.Spadj = int32(q.From.Offset) 735 q.Link = p.Link 736 p.Link = q 737 if cursym.Text.Mark&LEAF != 0 { 738 break 739 } 740 } 741 742 q1 = ctxt.NewProg() 743 q1.As = AMOVD 744 q1.Lineno = p.Lineno 745 q1.From.Type = obj.TYPE_REG 746 q1.From.Reg = REGLINK 747 q1.To.Type = obj.TYPE_MEM 748 q1.Scond = C_XPRE 749 q1.To.Offset = int64(-aoffset) 750 q1.To.Reg = REGSP 751 q1.Link = q.Link 752 q1.Spadj = aoffset 753 q.Link = q1 754 755 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 756 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 757 // 758 // MOV g_panic(g), R1 759 // CMP ZR, R1 760 // BEQ end 761 // MOV panic_argp(R1), R2 762 // ADD $(autosize+8), RSP, R3 763 // CMP R2, R3 764 // BNE end 765 // ADD $8, RSP, R4 766 // MOVD R4, panic_argp(R1) 767 // end: 768 // NOP 769 // 770 // The NOP is needed to give the jumps somewhere to land. 771 // It is a liblink NOP, not a ARM64 NOP: it encodes to 0 instruction bytes. 772 q = q1 773 774 q = obj.Appendp(ctxt, q) 775 q.As = AMOVD 776 q.From.Type = obj.TYPE_MEM 777 q.From.Reg = REGG 778 q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic 779 q.To.Type = obj.TYPE_REG 780 q.To.Reg = REG_R1 781 782 q = obj.Appendp(ctxt, q) 783 q.As = ACMP 784 q.From.Type = obj.TYPE_REG 785 q.From.Reg = REGZERO 786 q.Reg = REG_R1 787 788 q = obj.Appendp(ctxt, q) 789 q.As = ABEQ 790 q.To.Type = obj.TYPE_BRANCH 791 q1 = q 792 793 q = obj.Appendp(ctxt, q) 794 q.As = AMOVD 795 q.From.Type = obj.TYPE_MEM 796 q.From.Reg = REG_R1 797 q.From.Offset = 0 // Panic.argp 798 q.To.Type = obj.TYPE_REG 799 q.To.Reg = REG_R2 800 801 q = obj.Appendp(ctxt, q) 802 q.As = AADD 803 q.From.Type = obj.TYPE_CONST 804 q.From.Offset = int64(ctxt.Autosize) + 8 805 q.Reg = REGSP 806 q.To.Type = obj.TYPE_REG 807 q.To.Reg = REG_R3 808 809 q = obj.Appendp(ctxt, q) 810 q.As = ACMP 811 q.From.Type = obj.TYPE_REG 812 q.From.Reg = REG_R2 813 q.Reg = REG_R3 814 815 q = obj.Appendp(ctxt, q) 816 q.As = ABNE 817 q.To.Type = obj.TYPE_BRANCH 818 q2 = q 819 820 q = obj.Appendp(ctxt, q) 821 q.As = AADD 822 q.From.Type = obj.TYPE_CONST 823 q.From.Offset = 8 824 q.Reg = REGSP 825 q.To.Type = obj.TYPE_REG 826 q.To.Reg = REG_R4 827 828 q = obj.Appendp(ctxt, q) 829 q.As = AMOVD 830 q.From.Type = obj.TYPE_REG 831 q.From.Reg = REG_R4 832 q.To.Type = obj.TYPE_MEM 833 q.To.Reg = REG_R1 834 q.To.Offset = 0 // Panic.argp 835 836 q = obj.Appendp(ctxt, q) 837 838 q.As = obj.ANOP 839 q1.Pcond = q 840 q2.Pcond = q 841 } 842 843 case obj.ARET: 844 nocache(p) 845 if p.From.Type == obj.TYPE_CONST { 846 ctxt.Diag("using BECOME (%v) is not supported!", p) 847 break 848 } 849 850 retjmp = p.To.Sym 851 p.To = obj.Addr{} 852 if cursym.Text.Mark&LEAF != 0 { 853 if ctxt.Autosize != 0 { 854 p.As = AADD 855 p.From.Type = obj.TYPE_CONST 856 p.From.Offset = int64(ctxt.Autosize) 857 p.To.Type = obj.TYPE_REG 858 p.To.Reg = REGSP 859 p.Spadj = -ctxt.Autosize 860 } 861 } else { 862 /* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/ 863 aoffset = ctxt.Autosize 864 865 if aoffset > 0xF0 { 866 aoffset = 0xF0 867 } 868 p.As = AMOVD 869 p.From.Type = obj.TYPE_MEM 870 p.Scond = C_XPOST 871 p.From.Offset = int64(aoffset) 872 p.From.Reg = REGSP 873 p.To.Type = obj.TYPE_REG 874 p.To.Reg = REGLINK 875 p.Spadj = -aoffset 876 if ctxt.Autosize > aoffset { 877 q = ctxt.NewProg() 878 q.As = AADD 879 q.From.Type = obj.TYPE_CONST 880 q.From.Offset = int64(ctxt.Autosize) - int64(aoffset) 881 q.To.Type = obj.TYPE_REG 882 q.To.Reg = REGSP 883 q.Link = p.Link 884 q.Spadj = int32(-q.From.Offset) 885 q.Lineno = p.Lineno 886 p.Link = q 887 p = q 888 } 889 } 890 891 if p.As != obj.ARET { 892 q = ctxt.NewProg() 893 q.Lineno = p.Lineno 894 q.Link = p.Link 895 p.Link = q 896 p = q 897 } 898 899 if retjmp != nil { // retjmp 900 p.As = AB 901 p.To.Type = obj.TYPE_BRANCH 902 p.To.Sym = retjmp 903 p.Spadj = +ctxt.Autosize 904 break 905 } 906 907 p.As = obj.ARET 908 p.To.Type = obj.TYPE_MEM 909 p.To.Offset = 0 910 p.To.Reg = REGLINK 911 p.Spadj = +ctxt.Autosize 912 913 case AADD, ASUB: 914 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 915 if p.As == AADD { 916 p.Spadj = int32(-p.From.Offset) 917 } else { 918 p.Spadj = int32(+p.From.Offset) 919 } 920 } 921 break 922 } 923 } 924 } 925 926 func nocache(p *obj.Prog) { 927 p.Optab = 0 928 p.From.Class = 0 929 p.To.Class = 0 930 } 931 932 var unaryDst = map[int]bool{ 933 AWORD: true, 934 ADWORD: true, 935 ABL: true, 936 AB: true, 937 ASVC: true, 938 } 939 940 var Linkarm64 = obj.LinkArch{ 941 ByteOrder: binary.LittleEndian, 942 Name: "arm64", 943 Thechar: '7', 944 Preprocess: preprocess, 945 Assemble: span7, 946 Follow: follow, 947 Progedit: progedit, 948 UnaryDst: unaryDst, 949 Minlc: 4, 950 Ptrsize: 8, 951 Regsize: 8, 952 }