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