github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/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.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 { 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 AB, 519 ABEQ, 520 ABNE, 521 ABCS, 522 ABHS, 523 ABCC, 524 ABLO, 525 ABMI, 526 ABPL, 527 ABVS, 528 ABVC, 529 ABHI, 530 ABLS, 531 ABGE, 532 ABLT, 533 ABGT, 534 ABLE, 535 AADR, /* strange */ 536 AADRP: 537 q1 = p.Pcond 538 539 if q1 != nil { 540 for q1.As == obj.ANOP { 541 q1 = q1.Link 542 p.Pcond = q1 543 } 544 } 545 546 break 547 } 548 549 q = p 550 } 551 552 var o int 553 var q2 *obj.Prog 554 var retjmp *obj.LSym 555 for p := cursym.Text; p != nil; p = p.Link { 556 o = int(p.As) 557 switch o { 558 case obj.ATEXT: 559 cursym.Text = p 560 if textstksiz < 0 { 561 ctxt.Autosize = 0 562 } else { 563 ctxt.Autosize = int32(textstksiz + 8) 564 } 565 if (cursym.Text.Mark&LEAF != 0) && ctxt.Autosize <= 8 { 566 ctxt.Autosize = 0 567 } else if ctxt.Autosize&(16-1) != 0 { 568 // The frame includes an LR. 569 // If the frame size is 8, it's only an LR, 570 // so there's no potential for breaking references to 571 // local variables by growing the frame size, 572 // because there are no local variables. 573 // But otherwise, if there is a non-empty locals section, 574 // the author of the code is responsible for making sure 575 // that the frame size is 8 mod 16. 576 if ctxt.Autosize == 8 { 577 ctxt.Autosize += 8 578 cursym.Locals += 8 579 } else { 580 ctxt.Diag("%v: unaligned frame size %d - must be 8 mod 16 (or 0)", p, ctxt.Autosize-8) 581 } 582 } 583 p.To.Offset = int64(ctxt.Autosize) - 8 584 if ctxt.Autosize == 0 && !(cursym.Text.Mark&LEAF != 0) { 585 if ctxt.Debugvlog != 0 { 586 fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Text.From.Sym.Name) 587 } 588 ctxt.Bso.Flush() 589 cursym.Text.Mark |= LEAF 590 } 591 592 if !(p.From3.Offset&obj.NOSPLIT != 0) { 593 p = stacksplit(ctxt, p, ctxt.Autosize) // emit split check 594 } 595 596 aoffset = ctxt.Autosize 597 if aoffset > 0xF0 { 598 aoffset = 0xF0 599 } 600 if cursym.Text.Mark&LEAF != 0 { 601 cursym.Leaf = 1 602 if ctxt.Autosize == 0 { 603 break 604 } 605 aoffset = 0 606 } 607 608 q = p 609 if ctxt.Autosize > aoffset { 610 q = ctxt.NewProg() 611 q.As = ASUB 612 q.Lineno = p.Lineno 613 q.From.Type = obj.TYPE_CONST 614 q.From.Offset = int64(ctxt.Autosize) - int64(aoffset) 615 q.To.Type = obj.TYPE_REG 616 q.To.Reg = REGSP 617 q.Spadj = int32(q.From.Offset) 618 q.Link = p.Link 619 p.Link = q 620 if cursym.Text.Mark&LEAF != 0 { 621 break 622 } 623 } 624 625 q1 = ctxt.NewProg() 626 q1.As = AMOVD 627 q1.Lineno = p.Lineno 628 q1.From.Type = obj.TYPE_REG 629 q1.From.Reg = REGLINK 630 q1.To.Type = obj.TYPE_MEM 631 q1.Scond = C_XPRE 632 q1.To.Offset = int64(-aoffset) 633 q1.To.Reg = REGSP 634 q1.Link = q.Link 635 q1.Spadj = aoffset 636 q.Link = q1 637 638 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 639 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 640 // 641 // MOV g_panic(g), R1 642 // CMP ZR, R1 643 // BEQ end 644 // MOV panic_argp(R1), R2 645 // ADD $(autosize+8), RSP, R3 646 // CMP R2, R3 647 // BNE end 648 // ADD $8, RSP, R4 649 // MOVD R4, panic_argp(R1) 650 // end: 651 // NOP 652 // 653 // The NOP is needed to give the jumps somewhere to land. 654 // It is a liblink NOP, not a ARM64 NOP: it encodes to 0 instruction bytes. 655 q = q1 656 657 q = obj.Appendp(ctxt, q) 658 q.As = AMOVD 659 q.From.Type = obj.TYPE_MEM 660 q.From.Reg = REGG 661 q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic 662 q.To.Type = obj.TYPE_REG 663 q.To.Reg = REG_R1 664 665 q = obj.Appendp(ctxt, q) 666 q.As = ACMP 667 q.From.Type = obj.TYPE_REG 668 q.From.Reg = REGZERO 669 q.Reg = REG_R1 670 671 q = obj.Appendp(ctxt, q) 672 q.As = ABEQ 673 q.To.Type = obj.TYPE_BRANCH 674 q1 = q 675 676 q = obj.Appendp(ctxt, q) 677 q.As = AMOVD 678 q.From.Type = obj.TYPE_MEM 679 q.From.Reg = REG_R1 680 q.From.Offset = 0 // Panic.argp 681 q.To.Type = obj.TYPE_REG 682 q.To.Reg = REG_R2 683 684 q = obj.Appendp(ctxt, q) 685 q.As = AADD 686 q.From.Type = obj.TYPE_CONST 687 q.From.Offset = int64(ctxt.Autosize) + 8 688 q.Reg = REGSP 689 q.To.Type = obj.TYPE_REG 690 q.To.Reg = REG_R3 691 692 q = obj.Appendp(ctxt, q) 693 q.As = ACMP 694 q.From.Type = obj.TYPE_REG 695 q.From.Reg = REG_R2 696 q.Reg = REG_R3 697 698 q = obj.Appendp(ctxt, q) 699 q.As = ABNE 700 q.To.Type = obj.TYPE_BRANCH 701 q2 = q 702 703 q = obj.Appendp(ctxt, q) 704 q.As = AADD 705 q.From.Type = obj.TYPE_CONST 706 q.From.Offset = 8 707 q.Reg = REGSP 708 q.To.Type = obj.TYPE_REG 709 q.To.Reg = REG_R4 710 711 q = obj.Appendp(ctxt, q) 712 q.As = AMOVD 713 q.From.Type = obj.TYPE_REG 714 q.From.Reg = REG_R4 715 q.To.Type = obj.TYPE_MEM 716 q.To.Reg = REG_R1 717 q.To.Offset = 0 // Panic.argp 718 719 q = obj.Appendp(ctxt, q) 720 721 q.As = obj.ANOP 722 q1.Pcond = q 723 q2.Pcond = q 724 } 725 726 case obj.ARET: 727 nocache(p) 728 if p.From.Type == obj.TYPE_CONST { 729 ctxt.Diag("using BECOME (%v) is not supported!", p) 730 break 731 } 732 733 retjmp = p.To.Sym 734 p.To = obj.Addr{} 735 if cursym.Text.Mark&LEAF != 0 { 736 if ctxt.Autosize != 0 { 737 p.As = AADD 738 p.From.Type = obj.TYPE_CONST 739 p.From.Offset = int64(ctxt.Autosize) 740 p.To.Type = obj.TYPE_REG 741 p.To.Reg = REGSP 742 p.Spadj = -ctxt.Autosize 743 } 744 } else { 745 /* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/ 746 aoffset = ctxt.Autosize 747 748 if aoffset > 0xF0 { 749 aoffset = 0xF0 750 } 751 p.As = AMOVD 752 p.From.Type = obj.TYPE_MEM 753 p.Scond = C_XPOST 754 p.From.Offset = int64(aoffset) 755 p.From.Reg = REGSP 756 p.To.Type = obj.TYPE_REG 757 p.To.Reg = REGLINK 758 p.Spadj = -aoffset 759 if ctxt.Autosize > aoffset { 760 q = ctxt.NewProg() 761 q.As = AADD 762 q.From.Type = obj.TYPE_CONST 763 q.From.Offset = int64(ctxt.Autosize) - int64(aoffset) 764 q.To.Type = obj.TYPE_REG 765 q.To.Reg = REGSP 766 q.Link = p.Link 767 q.Spadj = int32(-q.From.Offset) 768 q.Lineno = p.Lineno 769 p.Link = q 770 p = q 771 } 772 } 773 774 if p.As != obj.ARET { 775 q = ctxt.NewProg() 776 q.Lineno = p.Lineno 777 q.Link = p.Link 778 p.Link = q 779 p = q 780 } 781 782 if retjmp != nil { // retjmp 783 p.As = AB 784 p.To.Type = obj.TYPE_BRANCH 785 p.To.Sym = retjmp 786 p.Spadj = +ctxt.Autosize 787 break 788 } 789 790 p.As = obj.ARET 791 p.To.Type = obj.TYPE_MEM 792 p.To.Offset = 0 793 p.To.Reg = REGLINK 794 p.Spadj = +ctxt.Autosize 795 796 case AADD, ASUB: 797 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 798 if p.As == AADD { 799 p.Spadj = int32(-p.From.Offset) 800 } else { 801 p.Spadj = int32(+p.From.Offset) 802 } 803 } 804 break 805 } 806 } 807 } 808 809 func nocache(p *obj.Prog) { 810 p.Optab = 0 811 p.From.Class = 0 812 p.To.Class = 0 813 } 814 815 var unaryDst = map[int]bool{ 816 AWORD: true, 817 ADWORD: true, 818 ABL: true, 819 AB: true, 820 ASVC: true, 821 } 822 823 var Linkarm64 = obj.LinkArch{ 824 ByteOrder: binary.LittleEndian, 825 Name: "arm64", 826 Thechar: '7', 827 Preprocess: preprocess, 828 Assemble: span7, 829 Follow: follow, 830 Progedit: progedit, 831 UnaryDst: unaryDst, 832 Minlc: 4, 833 Ptrsize: 8, 834 Regsize: 8, 835 }