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 (a] 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 (a] 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.Name = obj.NAME_EXTERN 254 p.From.Offset = 0 255 } 256 257 case AFMOVD: 258 if p.From.Type == obj.TYPE_FCONST { 259 i64 := math.Float64bits(p.From.Val.(float64)) 260 literal := fmt.Sprintf("$f64.%016x", uint64(i64)) 261 s := obj.Linklookup(ctxt, literal, 0) 262 s.Size = 8 263 p.From.Type = obj.TYPE_MEM 264 p.From.Sym = s 265 p.From.Name = obj.NAME_EXTERN 266 p.From.Offset = 0 267 } 268 269 break 270 } 271 272 // Rewrite negative immediates as positive immediates with 273 // complementary instruction. 274 switch p.As { 275 case AADD, 276 AADDW, 277 ASUB, 278 ASUBW, 279 ACMP, 280 ACMPW, 281 ACMN, 282 ACMNW: 283 if p.From.Type == obj.NAME_EXTERN && p.From.Offset < 0 { 284 p.From.Offset = -p.From.Offset 285 p.As = complements[p.As] 286 } 287 288 break 289 } 290 } 291 292 func follow(ctxt *obj.Link, s *obj.LSym) { 293 ctxt.Cursym = s 294 295 firstp := ctxt.NewProg() 296 lastp := firstp 297 xfol(ctxt, s.Text, &lastp) 298 lastp.Link = nil 299 s.Text = firstp.Link 300 } 301 302 func relinv(a int) int { 303 switch a { 304 case ABEQ: 305 return ABNE 306 case ABNE: 307 return ABEQ 308 case ABCS: 309 return ABCC 310 case ABHS: 311 return ABLO 312 case ABCC: 313 return ABCS 314 case ABLO: 315 return ABHS 316 case ABMI: 317 return ABPL 318 case ABPL: 319 return ABMI 320 case ABVS: 321 return ABVC 322 case ABVC: 323 return ABVS 324 case ABHI: 325 return ABLS 326 case ABLS: 327 return ABHI 328 case ABGE: 329 return ABLT 330 case ABLT: 331 return ABGE 332 case ABGT: 333 return ABLE 334 case ABLE: 335 return ABGT 336 } 337 338 log.Fatalf("unknown relation: %s", Anames[a]) 339 return 0 340 } 341 342 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 343 var q *obj.Prog 344 var r *obj.Prog 345 var a int 346 var i int 347 348 loop: 349 if p == nil { 350 return 351 } 352 a = int(p.As) 353 if a == AB { 354 q = p.Pcond 355 if q != nil { 356 p.Mark |= FOLL 357 p = q 358 if !(p.Mark&FOLL != 0) { 359 goto loop 360 } 361 } 362 } 363 364 if p.Mark&FOLL != 0 { 365 i = 0 366 q = p 367 for ; i < 4; i, q = i+1, q.Link { 368 if q == *last || q == nil { 369 break 370 } 371 a = int(q.As) 372 if a == obj.ANOP { 373 i-- 374 continue 375 } 376 377 if a == AB || a == obj.ARET || a == AERET { 378 goto copy 379 } 380 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 381 continue 382 } 383 if a != ABEQ && a != ABNE { 384 continue 385 } 386 387 copy: 388 for { 389 r = ctxt.NewProg() 390 *r = *p 391 if !(r.Mark&FOLL != 0) { 392 fmt.Printf("cant happen 1\n") 393 } 394 r.Mark |= FOLL 395 if p != q { 396 p = p.Link 397 (*last).Link = r 398 *last = r 399 continue 400 } 401 402 (*last).Link = r 403 *last = r 404 if a == AB || a == obj.ARET || a == AERET { 405 return 406 } 407 if a == ABNE { 408 r.As = ABEQ 409 } else { 410 r.As = ABNE 411 } 412 r.Pcond = p.Link 413 r.Link = p.Pcond 414 if !(r.Link.Mark&FOLL != 0) { 415 xfol(ctxt, r.Link, last) 416 } 417 if !(r.Pcond.Mark&FOLL != 0) { 418 fmt.Printf("cant happen 2\n") 419 } 420 return 421 } 422 } 423 424 a = AB 425 q = ctxt.NewProg() 426 q.As = int16(a) 427 q.Lineno = p.Lineno 428 q.To.Type = obj.TYPE_BRANCH 429 q.To.Offset = p.Pc 430 q.Pcond = p 431 p = q 432 } 433 434 p.Mark |= FOLL 435 (*last).Link = p 436 *last = p 437 if a == AB || a == obj.ARET || a == AERET { 438 return 439 } 440 if p.Pcond != nil { 441 if a != ABL && p.Link != nil { 442 q = obj.Brchain(ctxt, p.Link) 443 if a != obj.ATEXT && a != ABCASE { 444 if q != nil && (q.Mark&FOLL != 0) { 445 p.As = int16(relinv(a)) 446 p.Link = p.Pcond 447 p.Pcond = q 448 } 449 } 450 451 xfol(ctxt, p.Link, last) 452 q = obj.Brchain(ctxt, p.Pcond) 453 if q == nil { 454 q = p.Pcond 455 } 456 if q.Mark&FOLL != 0 { 457 p.Pcond = q 458 return 459 } 460 461 p = q 462 goto loop 463 } 464 } 465 466 p = p.Link 467 goto loop 468 } 469 470 func preprocess(ctxt *obj.Link, cursym *obj.LSym) { 471 ctxt.Cursym = cursym 472 473 if cursym.Text == nil || cursym.Text.Link == nil { 474 return 475 } 476 477 p := cursym.Text 478 textstksiz := p.To.Offset 479 aoffset := int32(textstksiz) 480 481 cursym.Args = p.To.Val.(int32) 482 cursym.Locals = int32(textstksiz) 483 484 /* 485 * find leaf subroutines 486 * strip NOPs 487 * expand RET 488 */ 489 ctxt.Bso.Flush() 490 q := (*obj.Prog)(nil) 491 var q1 *obj.Prog 492 for p := cursym.Text; p != nil; p = p.Link { 493 switch p.As { 494 case obj.ATEXT: 495 p.Mark |= LEAF 496 497 case obj.ARET: 498 break 499 500 case obj.ANOP: 501 q1 = p.Link 502 q.Link = q1 /* q is non-nop */ 503 q1.Mark |= p.Mark 504 continue 505 506 case ABL, 507 obj.ADUFFZERO, 508 obj.ADUFFCOPY: 509 cursym.Text.Mark &^= LEAF 510 fallthrough 511 512 case ACBNZ, 513 ACBZ, 514 ACBNZW, 515 ACBZW, 516 ATBZ, 517 ATBNZ, 518 ABCASE, 519 AB, 520 ABEQ, 521 ABNE, 522 ABCS, 523 ABHS, 524 ABCC, 525 ABLO, 526 ABMI, 527 ABPL, 528 ABVS, 529 ABVC, 530 ABHI, 531 ABLS, 532 ABGE, 533 ABLT, 534 ABGT, 535 ABLE, 536 AADR, /* strange */ 537 AADRP: 538 q1 = p.Pcond 539 540 if q1 != nil { 541 for q1.As == obj.ANOP { 542 q1 = q1.Link 543 p.Pcond = q1 544 } 545 } 546 547 break 548 } 549 550 q = p 551 } 552 553 var o int 554 var q2 *obj.Prog 555 var retjmp *obj.LSym 556 for p := cursym.Text; p != nil; p = p.Link { 557 o = int(p.As) 558 switch o { 559 case obj.ATEXT: 560 cursym.Text = p 561 if textstksiz < 0 { 562 ctxt.Autosize = 0 563 } else { 564 ctxt.Autosize = int32(textstksiz + 8) 565 } 566 if (cursym.Text.Mark&LEAF != 0) && ctxt.Autosize <= 8 { 567 ctxt.Autosize = 0 568 } else if ctxt.Autosize&(16-1) != 0 { 569 // The frame includes an LR. 570 // If the frame size is 8, it's only an LR, 571 // so there's no potential for breaking references to 572 // local variables by growing the frame size, 573 // because there are no local variables. 574 // But otherwise, if there is a non-empty locals section, 575 // the author of the code is responsible for making sure 576 // that the frame size is 8 mod 16. 577 if ctxt.Autosize == 8 { 578 ctxt.Autosize += 8 579 cursym.Locals += 8 580 } else { 581 ctxt.Diag("%v: unaligned frame size %d - must be 8 mod 16 (or 0)", p, ctxt.Autosize-8) 582 } 583 } 584 p.To.Offset = int64(ctxt.Autosize) - 8 585 if ctxt.Autosize == 0 && !(cursym.Text.Mark&LEAF != 0) { 586 if ctxt.Debugvlog != 0 { 587 fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Text.From.Sym.Name) 588 } 589 ctxt.Bso.Flush() 590 cursym.Text.Mark |= LEAF 591 } 592 593 if !(p.From3.Offset&obj.NOSPLIT != 0) { 594 p = stacksplit(ctxt, p, ctxt.Autosize) // emit split check 595 } 596 597 aoffset = ctxt.Autosize 598 if aoffset > 0xF0 { 599 aoffset = 0xF0 600 } 601 if cursym.Text.Mark&LEAF != 0 { 602 cursym.Leaf = 1 603 if ctxt.Autosize == 0 { 604 break 605 } 606 aoffset = 0 607 } 608 609 q = p 610 if ctxt.Autosize > aoffset { 611 q = ctxt.NewProg() 612 q.As = ASUB 613 q.Lineno = p.Lineno 614 q.From.Type = obj.TYPE_CONST 615 q.From.Offset = int64(ctxt.Autosize) - int64(aoffset) 616 q.To.Type = obj.TYPE_REG 617 q.To.Reg = REGSP 618 q.Spadj = int32(q.From.Offset) 619 q.Link = p.Link 620 p.Link = q 621 if cursym.Text.Mark&LEAF != 0 { 622 break 623 } 624 } 625 626 q1 = ctxt.NewProg() 627 q1.As = AMOVD 628 q1.Lineno = p.Lineno 629 q1.From.Type = obj.TYPE_REG 630 q1.From.Reg = REGLINK 631 q1.To.Type = obj.TYPE_MEM 632 q1.Scond = C_XPRE 633 q1.To.Offset = int64(-aoffset) 634 q1.To.Reg = REGSP 635 q1.Link = q.Link 636 q1.Spadj = aoffset 637 q.Link = q1 638 639 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 640 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 641 // 642 // MOV g_panic(g), R1 643 // CMP ZR, R1 644 // BEQ end 645 // MOV panic_argp(R1), R2 646 // ADD $(autosize+8), RSP, R3 647 // CMP R2, R3 648 // BNE end 649 // ADD $8, RSP, R4 650 // MOVD R4, panic_argp(R1) 651 // end: 652 // NOP 653 // 654 // The NOP is needed to give the jumps somewhere to land. 655 // It is a liblink NOP, not a ARM64 NOP: it encodes to 0 instruction bytes. 656 q = q1 657 658 q = obj.Appendp(ctxt, q) 659 q.As = AMOVD 660 q.From.Type = obj.TYPE_MEM 661 q.From.Reg = REGG 662 q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic 663 q.To.Type = obj.TYPE_REG 664 q.To.Reg = REG_R1 665 666 q = obj.Appendp(ctxt, q) 667 q.As = ACMP 668 q.From.Type = obj.TYPE_REG 669 q.From.Reg = REGZERO 670 q.Reg = REG_R1 671 672 q = obj.Appendp(ctxt, q) 673 q.As = ABEQ 674 q.To.Type = obj.TYPE_BRANCH 675 q1 = q 676 677 q = obj.Appendp(ctxt, q) 678 q.As = AMOVD 679 q.From.Type = obj.TYPE_MEM 680 q.From.Reg = REG_R1 681 q.From.Offset = 0 // Panic.argp 682 q.To.Type = obj.TYPE_REG 683 q.To.Reg = REG_R2 684 685 q = obj.Appendp(ctxt, q) 686 q.As = AADD 687 q.From.Type = obj.TYPE_CONST 688 q.From.Offset = int64(ctxt.Autosize) + 8 689 q.Reg = REGSP 690 q.To.Type = obj.TYPE_REG 691 q.To.Reg = REG_R3 692 693 q = obj.Appendp(ctxt, q) 694 q.As = ACMP 695 q.From.Type = obj.TYPE_REG 696 q.From.Reg = REG_R2 697 q.Reg = REG_R3 698 699 q = obj.Appendp(ctxt, q) 700 q.As = ABNE 701 q.To.Type = obj.TYPE_BRANCH 702 q2 = q 703 704 q = obj.Appendp(ctxt, q) 705 q.As = AADD 706 q.From.Type = obj.TYPE_CONST 707 q.From.Offset = 8 708 q.Reg = REGSP 709 q.To.Type = obj.TYPE_REG 710 q.To.Reg = REG_R4 711 712 q = obj.Appendp(ctxt, q) 713 q.As = AMOVD 714 q.From.Type = obj.TYPE_REG 715 q.From.Reg = REG_R4 716 q.To.Type = obj.TYPE_MEM 717 q.To.Reg = REG_R1 718 q.To.Offset = 0 // Panic.argp 719 720 q = obj.Appendp(ctxt, q) 721 722 q.As = obj.ANOP 723 q1.Pcond = q 724 q2.Pcond = q 725 } 726 727 case obj.ARET: 728 nocache(p) 729 if p.From.Type == obj.TYPE_CONST { 730 ctxt.Diag("using BECOME (%v) is not supported!", p) 731 break 732 } 733 734 retjmp = p.To.Sym 735 p.To = obj.Addr{} 736 if cursym.Text.Mark&LEAF != 0 { 737 if ctxt.Autosize != 0 { 738 p.As = AADD 739 p.From.Type = obj.TYPE_CONST 740 p.From.Offset = int64(ctxt.Autosize) 741 p.To.Type = obj.TYPE_REG 742 p.To.Reg = REGSP 743 p.Spadj = -ctxt.Autosize 744 } 745 } else { 746 /* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/ 747 aoffset = ctxt.Autosize 748 749 if aoffset > 0xF0 { 750 aoffset = 0xF0 751 } 752 p.As = AMOVD 753 p.From.Type = obj.TYPE_MEM 754 p.Scond = C_XPOST 755 p.From.Offset = int64(aoffset) 756 p.From.Reg = REGSP 757 p.To.Type = obj.TYPE_REG 758 p.To.Reg = REGLINK 759 p.Spadj = -aoffset 760 if ctxt.Autosize > aoffset { 761 q = ctxt.NewProg() 762 q.As = AADD 763 q.From.Type = obj.TYPE_CONST 764 q.From.Offset = int64(ctxt.Autosize) - int64(aoffset) 765 q.To.Type = obj.TYPE_REG 766 q.To.Reg = REGSP 767 q.Link = p.Link 768 q.Spadj = int32(-q.From.Offset) 769 q.Lineno = p.Lineno 770 p.Link = q 771 p = q 772 } 773 } 774 775 if p.As != obj.ARET { 776 q = ctxt.NewProg() 777 q.Lineno = p.Lineno 778 q.Link = p.Link 779 p.Link = q 780 p = q 781 } 782 783 if retjmp != nil { // retjmp 784 p.As = AB 785 p.To.Type = obj.TYPE_BRANCH 786 p.To.Sym = retjmp 787 p.Spadj = +ctxt.Autosize 788 break 789 } 790 791 p.As = obj.ARET 792 p.To.Type = obj.TYPE_MEM 793 p.To.Offset = 0 794 p.To.Reg = REGLINK 795 p.Spadj = +ctxt.Autosize 796 797 case AADD, ASUB: 798 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 799 if p.As == AADD { 800 p.Spadj = int32(-p.From.Offset) 801 } else { 802 p.Spadj = int32(+p.From.Offset) 803 } 804 } 805 break 806 } 807 } 808 } 809 810 func nocache(p *obj.Prog) { 811 p.Optab = 0 812 p.From.Class = 0 813 p.To.Class = 0 814 } 815 816 var unaryDst = map[int]bool{ 817 AWORD: true, 818 ADWORD: true, 819 ABL: true, 820 AB: true, 821 ASVC: true, 822 } 823 824 var Linkarm64 = obj.LinkArch{ 825 ByteOrder: binary.LittleEndian, 826 Name: "arm64", 827 Thechar: '7', 828 Preprocess: preprocess, 829 Assemble: span7, 830 Follow: follow, 831 Progedit: progedit, 832 UnaryDst: unaryDst, 833 Minlc: 4, 834 Ptrsize: 8, 835 Regsize: 8, 836 } 837