github.com/aloncn/graphics-go@v0.0.1/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 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 != 0: 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", uint32(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", uint64(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 int) int { 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 a int 468 var i int 469 470 loop: 471 if p == nil { 472 return 473 } 474 a = int(p.As) 475 if a == AB { 476 q = p.Pcond 477 if q != nil { 478 p.Mark |= FOLL 479 p = q 480 if !(p.Mark&FOLL != 0) { 481 goto loop 482 } 483 } 484 } 485 486 if p.Mark&FOLL != 0 { 487 i = 0 488 q = p 489 for ; i < 4; i, q = i+1, q.Link { 490 if q == *last || q == nil { 491 break 492 } 493 a = int(q.As) 494 if a == obj.ANOP { 495 i-- 496 continue 497 } 498 499 if a == AB || a == obj.ARET || a == AERET { 500 goto copy 501 } 502 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 503 continue 504 } 505 if a != ABEQ && a != ABNE { 506 continue 507 } 508 509 copy: 510 for { 511 r = ctxt.NewProg() 512 *r = *p 513 if !(r.Mark&FOLL != 0) { 514 fmt.Printf("cant happen 1\n") 515 } 516 r.Mark |= FOLL 517 if p != q { 518 p = p.Link 519 (*last).Link = r 520 *last = r 521 continue 522 } 523 524 (*last).Link = r 525 *last = r 526 if a == AB || a == obj.ARET || a == AERET { 527 return 528 } 529 if a == ABNE { 530 r.As = ABEQ 531 } else { 532 r.As = ABNE 533 } 534 r.Pcond = p.Link 535 r.Link = p.Pcond 536 if !(r.Link.Mark&FOLL != 0) { 537 xfol(ctxt, r.Link, last) 538 } 539 if !(r.Pcond.Mark&FOLL != 0) { 540 fmt.Printf("cant happen 2\n") 541 } 542 return 543 } 544 } 545 546 a = AB 547 q = ctxt.NewProg() 548 q.As = int16(a) 549 q.Lineno = p.Lineno 550 q.To.Type = obj.TYPE_BRANCH 551 q.To.Offset = p.Pc 552 q.Pcond = p 553 p = q 554 } 555 556 p.Mark |= FOLL 557 (*last).Link = p 558 *last = p 559 if a == AB || a == obj.ARET || a == AERET { 560 return 561 } 562 if p.Pcond != nil { 563 if a != ABL && p.Link != nil { 564 q = obj.Brchain(ctxt, p.Link) 565 if a != obj.ATEXT { 566 if q != nil && (q.Mark&FOLL != 0) { 567 p.As = int16(relinv(a)) 568 p.Link = p.Pcond 569 p.Pcond = q 570 } 571 } 572 573 xfol(ctxt, p.Link, last) 574 q = obj.Brchain(ctxt, p.Pcond) 575 if q == nil { 576 q = p.Pcond 577 } 578 if q.Mark&FOLL != 0 { 579 p.Pcond = q 580 return 581 } 582 583 p = q 584 goto loop 585 } 586 } 587 588 p = p.Link 589 goto loop 590 } 591 592 func preprocess(ctxt *obj.Link, cursym *obj.LSym) { 593 ctxt.Cursym = cursym 594 595 if cursym.Text == nil || cursym.Text.Link == nil { 596 return 597 } 598 599 p := cursym.Text 600 textstksiz := p.To.Offset 601 aoffset := int32(textstksiz) 602 603 cursym.Args = p.To.Val.(int32) 604 cursym.Locals = int32(textstksiz) 605 606 /* 607 * find leaf subroutines 608 * strip NOPs 609 * expand RET 610 */ 611 ctxt.Bso.Flush() 612 q := (*obj.Prog)(nil) 613 var q1 *obj.Prog 614 for p := cursym.Text; p != nil; p = p.Link { 615 switch p.As { 616 case obj.ATEXT: 617 p.Mark |= LEAF 618 619 case obj.ARET: 620 break 621 622 case obj.ANOP: 623 q1 = p.Link 624 q.Link = q1 /* q is non-nop */ 625 q1.Mark |= p.Mark 626 continue 627 628 case ABL, 629 obj.ADUFFZERO, 630 obj.ADUFFCOPY: 631 cursym.Text.Mark &^= LEAF 632 fallthrough 633 634 case ACBNZ, 635 ACBZ, 636 ACBNZW, 637 ACBZW, 638 ATBZ, 639 ATBNZ, 640 AB, 641 ABEQ, 642 ABNE, 643 ABCS, 644 ABHS, 645 ABCC, 646 ABLO, 647 ABMI, 648 ABPL, 649 ABVS, 650 ABVC, 651 ABHI, 652 ABLS, 653 ABGE, 654 ABLT, 655 ABGT, 656 ABLE, 657 AADR, /* strange */ 658 AADRP: 659 q1 = p.Pcond 660 661 if q1 != nil { 662 for q1.As == obj.ANOP { 663 q1 = q1.Link 664 p.Pcond = q1 665 } 666 } 667 668 break 669 } 670 671 q = p 672 } 673 674 var o int 675 var q2 *obj.Prog 676 var retjmp *obj.LSym 677 for p := cursym.Text; p != nil; p = p.Link { 678 o = int(p.As) 679 switch o { 680 case obj.ATEXT: 681 cursym.Text = p 682 if textstksiz < 0 { 683 ctxt.Autosize = 0 684 } else { 685 ctxt.Autosize = int32(textstksiz + 8) 686 } 687 if (cursym.Text.Mark&LEAF != 0) && ctxt.Autosize <= 8 { 688 ctxt.Autosize = 0 689 } else if ctxt.Autosize&(16-1) != 0 { 690 // The frame includes an LR. 691 // If the frame size is 8, it's only an LR, 692 // so there's no potential for breaking references to 693 // local variables by growing the frame size, 694 // because there are no local variables. 695 // But otherwise, if there is a non-empty locals section, 696 // the author of the code is responsible for making sure 697 // that the frame size is 8 mod 16. 698 if ctxt.Autosize == 8 { 699 ctxt.Autosize += 8 700 cursym.Locals += 8 701 } else { 702 ctxt.Diag("%v: unaligned frame size %d - must be 8 mod 16 (or 0)", p, ctxt.Autosize-8) 703 } 704 } 705 p.To.Offset = int64(ctxt.Autosize) - 8 706 if ctxt.Autosize == 0 && !(cursym.Text.Mark&LEAF != 0) { 707 if ctxt.Debugvlog != 0 { 708 fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Text.From.Sym.Name) 709 } 710 ctxt.Bso.Flush() 711 cursym.Text.Mark |= LEAF 712 } 713 714 if !(p.From3.Offset&obj.NOSPLIT != 0) { 715 p = stacksplit(ctxt, p, ctxt.Autosize) // emit split check 716 } 717 718 aoffset = ctxt.Autosize 719 if aoffset > 0xF0 { 720 aoffset = 0xF0 721 } 722 if cursym.Text.Mark&LEAF != 0 { 723 cursym.Leaf = 1 724 if ctxt.Autosize == 0 { 725 break 726 } 727 aoffset = 0 728 } 729 730 q = p 731 if ctxt.Autosize > aoffset { 732 q = ctxt.NewProg() 733 q.As = ASUB 734 q.Lineno = p.Lineno 735 q.From.Type = obj.TYPE_CONST 736 q.From.Offset = int64(ctxt.Autosize) - int64(aoffset) 737 q.To.Type = obj.TYPE_REG 738 q.To.Reg = REGSP 739 q.Spadj = int32(q.From.Offset) 740 q.Link = p.Link 741 p.Link = q 742 if cursym.Text.Mark&LEAF != 0 { 743 break 744 } 745 } 746 747 q1 = ctxt.NewProg() 748 q1.As = AMOVD 749 q1.Lineno = p.Lineno 750 q1.From.Type = obj.TYPE_REG 751 q1.From.Reg = REGLINK 752 q1.To.Type = obj.TYPE_MEM 753 q1.Scond = C_XPRE 754 q1.To.Offset = int64(-aoffset) 755 q1.To.Reg = REGSP 756 q1.Link = q.Link 757 q1.Spadj = aoffset 758 q.Link = q1 759 760 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 761 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 762 // 763 // MOV g_panic(g), R1 764 // CMP ZR, R1 765 // BEQ end 766 // MOV panic_argp(R1), R2 767 // ADD $(autosize+8), RSP, R3 768 // CMP R2, R3 769 // BNE end 770 // ADD $8, RSP, R4 771 // MOVD R4, panic_argp(R1) 772 // end: 773 // NOP 774 // 775 // The NOP is needed to give the jumps somewhere to land. 776 // It is a liblink NOP, not a ARM64 NOP: it encodes to 0 instruction bytes. 777 q = q1 778 779 q = obj.Appendp(ctxt, q) 780 q.As = AMOVD 781 q.From.Type = obj.TYPE_MEM 782 q.From.Reg = REGG 783 q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic 784 q.To.Type = obj.TYPE_REG 785 q.To.Reg = REG_R1 786 787 q = obj.Appendp(ctxt, q) 788 q.As = ACMP 789 q.From.Type = obj.TYPE_REG 790 q.From.Reg = REGZERO 791 q.Reg = REG_R1 792 793 q = obj.Appendp(ctxt, q) 794 q.As = ABEQ 795 q.To.Type = obj.TYPE_BRANCH 796 q1 = q 797 798 q = obj.Appendp(ctxt, q) 799 q.As = AMOVD 800 q.From.Type = obj.TYPE_MEM 801 q.From.Reg = REG_R1 802 q.From.Offset = 0 // Panic.argp 803 q.To.Type = obj.TYPE_REG 804 q.To.Reg = REG_R2 805 806 q = obj.Appendp(ctxt, q) 807 q.As = AADD 808 q.From.Type = obj.TYPE_CONST 809 q.From.Offset = int64(ctxt.Autosize) + 8 810 q.Reg = REGSP 811 q.To.Type = obj.TYPE_REG 812 q.To.Reg = REG_R3 813 814 q = obj.Appendp(ctxt, q) 815 q.As = ACMP 816 q.From.Type = obj.TYPE_REG 817 q.From.Reg = REG_R2 818 q.Reg = REG_R3 819 820 q = obj.Appendp(ctxt, q) 821 q.As = ABNE 822 q.To.Type = obj.TYPE_BRANCH 823 q2 = q 824 825 q = obj.Appendp(ctxt, q) 826 q.As = AADD 827 q.From.Type = obj.TYPE_CONST 828 q.From.Offset = 8 829 q.Reg = REGSP 830 q.To.Type = obj.TYPE_REG 831 q.To.Reg = REG_R4 832 833 q = obj.Appendp(ctxt, q) 834 q.As = AMOVD 835 q.From.Type = obj.TYPE_REG 836 q.From.Reg = REG_R4 837 q.To.Type = obj.TYPE_MEM 838 q.To.Reg = REG_R1 839 q.To.Offset = 0 // Panic.argp 840 841 q = obj.Appendp(ctxt, q) 842 843 q.As = obj.ANOP 844 q1.Pcond = q 845 q2.Pcond = q 846 } 847 848 case obj.ARET: 849 nocache(p) 850 if p.From.Type == obj.TYPE_CONST { 851 ctxt.Diag("using BECOME (%v) is not supported!", p) 852 break 853 } 854 855 retjmp = p.To.Sym 856 p.To = obj.Addr{} 857 if cursym.Text.Mark&LEAF != 0 { 858 if ctxt.Autosize != 0 { 859 p.As = AADD 860 p.From.Type = obj.TYPE_CONST 861 p.From.Offset = int64(ctxt.Autosize) 862 p.To.Type = obj.TYPE_REG 863 p.To.Reg = REGSP 864 p.Spadj = -ctxt.Autosize 865 } 866 } else { 867 /* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/ 868 aoffset = ctxt.Autosize 869 870 if aoffset > 0xF0 { 871 aoffset = 0xF0 872 } 873 p.As = AMOVD 874 p.From.Type = obj.TYPE_MEM 875 p.Scond = C_XPOST 876 p.From.Offset = int64(aoffset) 877 p.From.Reg = REGSP 878 p.To.Type = obj.TYPE_REG 879 p.To.Reg = REGLINK 880 p.Spadj = -aoffset 881 if ctxt.Autosize > aoffset { 882 q = ctxt.NewProg() 883 q.As = AADD 884 q.From.Type = obj.TYPE_CONST 885 q.From.Offset = int64(ctxt.Autosize) - int64(aoffset) 886 q.To.Type = obj.TYPE_REG 887 q.To.Reg = REGSP 888 q.Link = p.Link 889 q.Spadj = int32(-q.From.Offset) 890 q.Lineno = p.Lineno 891 p.Link = q 892 p = q 893 } 894 } 895 896 if p.As != obj.ARET { 897 q = ctxt.NewProg() 898 q.Lineno = p.Lineno 899 q.Link = p.Link 900 p.Link = q 901 p = q 902 } 903 904 if retjmp != nil { // retjmp 905 p.As = AB 906 p.To.Type = obj.TYPE_BRANCH 907 p.To.Sym = retjmp 908 p.Spadj = +ctxt.Autosize 909 break 910 } 911 912 p.As = obj.ARET 913 p.To.Type = obj.TYPE_MEM 914 p.To.Offset = 0 915 p.To.Reg = REGLINK 916 p.Spadj = +ctxt.Autosize 917 918 case AADD, ASUB: 919 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 920 if p.As == AADD { 921 p.Spadj = int32(-p.From.Offset) 922 } else { 923 p.Spadj = int32(+p.From.Offset) 924 } 925 } 926 break 927 } 928 } 929 } 930 931 func nocache(p *obj.Prog) { 932 p.Optab = 0 933 p.From.Class = 0 934 p.To.Class = 0 935 } 936 937 var unaryDst = map[int]bool{ 938 AWORD: true, 939 ADWORD: true, 940 ABL: true, 941 AB: true, 942 ASVC: true, 943 } 944 945 var Linkarm64 = obj.LinkArch{ 946 ByteOrder: binary.LittleEndian, 947 Name: "arm64", 948 Thechar: '7', 949 Preprocess: preprocess, 950 Assemble: span7, 951 Follow: follow, 952 Progedit: progedit, 953 UnaryDst: unaryDst, 954 Minlc: 4, 955 Ptrsize: 8, 956 Regsize: 8, 957 }