github.com/Rookout/GoSDK@v0.1.48/pkg/services/assembler/internal/obj/arm/obj5.go (about) 1 // Derived from Inferno utils/5c/swt.c 2 // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5c/swt.c 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 arm 32 33 import ( 34 "github.com/Rookout/GoSDK/pkg/services/assembler/internal/obj" 35 "github.com/Rookout/GoSDK/pkg/services/assembler/internal/objabi" 36 "github.com/Rookout/GoSDK/pkg/services/assembler/internal/sys" 37 "github.com/Rookout/GoSDK/pkg/services/assembler/internal/abi" 38 "github.com/Rookout/GoSDK/pkg/services/assembler/internal/buildcfg" 39 "log" 40 ) 41 42 var progedit_tlsfallback *obj.LSym 43 44 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { 45 p.From.Class = 0 46 p.To.Class = 0 47 48 c := ctxt5{ctxt: ctxt, newprog: newprog} 49 50 51 switch p.As { 52 case AB, ABL, obj.ADUFFZERO, obj.ADUFFCOPY: 53 if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil { 54 p.To.Type = obj.TYPE_BRANCH 55 } 56 } 57 58 59 switch p.As { 60 61 case AMRC: 62 if p.To.Offset&0xffff0fff == 0xee1d0f70 { 63 64 65 if p.To.Offset&0xf000 != 0 { 66 ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line()) 67 } 68 69 if buildcfg.GOARM < 7 { 70 71 if progedit_tlsfallback == nil { 72 progedit_tlsfallback = ctxt.Lookup("runtime.read_tls_fallback") 73 } 74 75 76 p.As = AMOVW 77 78 p.From.Type = obj.TYPE_REG 79 p.From.Reg = REGLINK 80 p.To.Type = obj.TYPE_REG 81 p.To.Reg = REGTMP 82 83 84 p = obj.Appendp(p, newprog) 85 86 p.As = ABL 87 p.To.Type = obj.TYPE_BRANCH 88 p.To.Sym = progedit_tlsfallback 89 p.To.Offset = 0 90 91 92 p = obj.Appendp(p, newprog) 93 94 p.As = AMOVW 95 p.From.Type = obj.TYPE_REG 96 p.From.Reg = REGTMP 97 p.To.Type = obj.TYPE_REG 98 p.To.Reg = REGLINK 99 break 100 } 101 } 102 103 104 p.As = AWORD 105 } 106 107 108 switch p.As { 109 case AMOVF: 110 if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) { 111 f32 := float32(p.From.Val.(float64)) 112 p.From.Type = obj.TYPE_MEM 113 p.From.Sym = ctxt.Float32Sym(f32) 114 p.From.Name = obj.NAME_EXTERN 115 p.From.Offset = 0 116 } 117 118 case AMOVD: 119 if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) { 120 p.From.Type = obj.TYPE_MEM 121 p.From.Sym = ctxt.Float64Sym(p.From.Val.(float64)) 122 p.From.Name = obj.NAME_EXTERN 123 p.From.Offset = 0 124 } 125 } 126 127 if ctxt.Flag_dynlink { 128 c.rewriteToUseGot(p) 129 } 130 } 131 132 133 func (c *ctxt5) rewriteToUseGot(p *obj.Prog) { 134 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO { 135 136 137 138 139 140 var sym *obj.LSym 141 if p.As == obj.ADUFFZERO { 142 sym = c.ctxt.Lookup("runtime.duffzero") 143 } else { 144 sym = c.ctxt.Lookup("runtime.duffcopy") 145 } 146 offset := p.To.Offset 147 p.As = AMOVW 148 p.From.Type = obj.TYPE_MEM 149 p.From.Name = obj.NAME_GOTREF 150 p.From.Sym = sym 151 p.To.Type = obj.TYPE_REG 152 p.To.Reg = REG_R9 153 p.To.Name = obj.NAME_NONE 154 p.To.Offset = 0 155 p.To.Sym = nil 156 p1 := obj.Appendp(p, c.newprog) 157 p1.As = AADD 158 p1.From.Type = obj.TYPE_CONST 159 p1.From.Offset = offset 160 p1.To.Type = obj.TYPE_REG 161 p1.To.Reg = REG_R9 162 p2 := obj.Appendp(p1, c.newprog) 163 p2.As = obj.ACALL 164 p2.To.Type = obj.TYPE_MEM 165 p2.To.Reg = REG_R9 166 return 167 } 168 169 170 171 172 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 173 174 175 if p.As != AMOVW { 176 c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p) 177 } 178 if p.To.Type != obj.TYPE_REG { 179 c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p) 180 } 181 p.From.Type = obj.TYPE_MEM 182 p.From.Name = obj.NAME_GOTREF 183 if p.From.Offset != 0 { 184 q := obj.Appendp(p, c.newprog) 185 q.As = AADD 186 q.From.Type = obj.TYPE_CONST 187 q.From.Offset = p.From.Offset 188 q.To = p.To 189 p.From.Offset = 0 190 } 191 } 192 if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN { 193 c.ctxt.Diag("don't know how to handle %v with -dynlink", p) 194 } 195 var source *obj.Addr 196 197 198 199 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 200 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { 201 c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p) 202 } 203 source = &p.From 204 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { 205 source = &p.To 206 } else { 207 return 208 } 209 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { 210 return 211 } 212 if source.Sym.Type == objabi.STLSBSS { 213 return 214 } 215 if source.Type != obj.TYPE_MEM { 216 c.ctxt.Diag("don't know how to handle %v with -dynlink", p) 217 } 218 p1 := obj.Appendp(p, c.newprog) 219 p2 := obj.Appendp(p1, c.newprog) 220 221 p1.As = AMOVW 222 p1.From.Type = obj.TYPE_MEM 223 p1.From.Sym = source.Sym 224 p1.From.Name = obj.NAME_GOTREF 225 p1.To.Type = obj.TYPE_REG 226 p1.To.Reg = REG_R9 227 228 p2.As = p.As 229 p2.From = p.From 230 p2.To = p.To 231 if p.From.Name == obj.NAME_EXTERN { 232 p2.From.Reg = REG_R9 233 p2.From.Name = obj.NAME_NONE 234 p2.From.Sym = nil 235 } else if p.To.Name == obj.NAME_EXTERN { 236 p2.To.Reg = REG_R9 237 p2.To.Name = obj.NAME_NONE 238 p2.To.Sym = nil 239 } else { 240 return 241 } 242 obj.Nopout(p) 243 } 244 245 246 const ( 247 FOLL = 1 << 0 248 LABEL = 1 << 1 249 LEAF = 1 << 2 250 ) 251 252 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { 253 autosize := int32(0) 254 255 if cursym.Func().Text == nil || cursym.Func().Text.Link == nil { 256 return 257 } 258 259 c := ctxt5{ctxt: ctxt, cursym: cursym, newprog: newprog} 260 261 p := c.cursym.Func().Text 262 autoffset := int32(p.To.Offset) 263 if autoffset == -4 { 264 265 p.From.Sym.Set(obj.AttrNoFrame, true) 266 autoffset = 0 267 } 268 if autoffset < 0 || autoffset%4 != 0 { 269 c.ctxt.Diag("frame size %d not 0 or a positive multiple of 4", autoffset) 270 } 271 if p.From.Sym.NoFrame() { 272 if autoffset != 0 { 273 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", autoffset) 274 } 275 } 276 277 cursym.Func().Locals = autoffset 278 cursym.Func().Args = p.To.Val.(int32) 279 280 281 for p := cursym.Func().Text; p != nil; p = p.Link { 282 switch p.As { 283 case obj.ATEXT: 284 p.Mark |= LEAF 285 286 case ADIV, ADIVU, AMOD, AMODU: 287 cursym.Func().Text.Mark &^= LEAF 288 289 case ABL, 290 ABX, 291 obj.ADUFFZERO, 292 obj.ADUFFCOPY: 293 cursym.Func().Text.Mark &^= LEAF 294 } 295 } 296 297 var q2 *obj.Prog 298 for p := cursym.Func().Text; p != nil; p = p.Link { 299 o := p.As 300 switch o { 301 case obj.ATEXT: 302 autosize = autoffset 303 304 if p.Mark&LEAF != 0 && autosize == 0 { 305 306 p.From.Sym.Set(obj.AttrNoFrame, true) 307 } 308 309 if !p.From.Sym.NoFrame() { 310 311 312 autosize += 4 313 } 314 315 if autosize == 0 && cursym.Func().Text.Mark&LEAF == 0 { 316 317 318 if ctxt.Debugvlog { 319 ctxt.Logf("save suppressed in: %s\n", cursym.Name) 320 } 321 322 cursym.Func().Text.Mark |= LEAF 323 } 324 325 326 p.To.Offset = int64(autosize) - 4 327 328 if cursym.Func().Text.Mark&LEAF != 0 { 329 cursym.Set(obj.AttrLeaf, true) 330 if p.From.Sym.NoFrame() { 331 break 332 } 333 } 334 335 if !p.From.Sym.NoSplit() { 336 p = c.stacksplit(p, autosize) 337 } 338 339 340 p = obj.Appendp(p, c.newprog) 341 342 p.As = AMOVW 343 p.Scond |= C_WBIT 344 p.From.Type = obj.TYPE_REG 345 p.From.Reg = REGLINK 346 p.To.Type = obj.TYPE_MEM 347 p.To.Offset = int64(-autosize) 348 p.To.Reg = REGSP 349 p.Spadj = autosize 350 351 if cursym.Func().Text.From.Sym.Wrapper() { 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 p = obj.Appendp(p, newprog) 373 p.As = AMOVW 374 p.From.Type = obj.TYPE_MEM 375 p.From.Reg = REGG 376 p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) 377 p.To.Type = obj.TYPE_REG 378 p.To.Reg = REG_R1 379 380 p = obj.Appendp(p, newprog) 381 p.As = ACMP 382 p.From.Type = obj.TYPE_CONST 383 p.From.Offset = 0 384 p.Reg = REG_R1 385 386 387 bne := obj.Appendp(p, newprog) 388 bne.As = ABNE 389 bne.To.Type = obj.TYPE_BRANCH 390 391 392 end := obj.Appendp(bne, newprog) 393 end.As = obj.ANOP 394 395 396 var last *obj.Prog 397 for last = end; last.Link != nil; last = last.Link { 398 } 399 400 401 mov := obj.Appendp(last, newprog) 402 mov.As = AMOVW 403 mov.From.Type = obj.TYPE_MEM 404 mov.From.Reg = REG_R1 405 mov.From.Offset = 0 406 mov.To.Type = obj.TYPE_REG 407 mov.To.Reg = REG_R2 408 409 410 bne.To.SetTarget(mov) 411 412 413 p = obj.Appendp(mov, newprog) 414 p.As = AADD 415 p.From.Type = obj.TYPE_CONST 416 p.From.Offset = int64(autosize) + 4 417 p.Reg = REG_R13 418 p.To.Type = obj.TYPE_REG 419 p.To.Reg = REG_R3 420 421 422 p = obj.Appendp(p, newprog) 423 p.As = ACMP 424 p.From.Type = obj.TYPE_REG 425 p.From.Reg = REG_R2 426 p.Reg = REG_R3 427 428 429 p = obj.Appendp(p, newprog) 430 p.As = ABNE 431 p.To.Type = obj.TYPE_BRANCH 432 p.To.SetTarget(end) 433 434 435 p = obj.Appendp(p, newprog) 436 p.As = AADD 437 p.From.Type = obj.TYPE_CONST 438 p.From.Offset = 4 439 p.Reg = REG_R13 440 p.To.Type = obj.TYPE_REG 441 p.To.Reg = REG_R4 442 443 444 p = obj.Appendp(p, newprog) 445 p.As = AMOVW 446 p.From.Type = obj.TYPE_REG 447 p.From.Reg = REG_R4 448 p.To.Type = obj.TYPE_MEM 449 p.To.Reg = REG_R1 450 p.To.Offset = 0 451 452 453 p = obj.Appendp(p, newprog) 454 p.As = AB 455 p.To.Type = obj.TYPE_BRANCH 456 p.To.SetTarget(end) 457 458 459 p = end 460 } 461 462 case obj.ARET: 463 nocache(p) 464 if cursym.Func().Text.Mark&LEAF != 0 { 465 if autosize == 0 { 466 p.As = AB 467 p.From = obj.Addr{} 468 if p.To.Sym != nil { 469 p.To.Type = obj.TYPE_BRANCH 470 } else { 471 p.To.Type = obj.TYPE_MEM 472 p.To.Offset = 0 473 p.To.Reg = REGLINK 474 } 475 476 break 477 } 478 } 479 480 p.As = AMOVW 481 p.Scond |= C_PBIT 482 p.From.Type = obj.TYPE_MEM 483 p.From.Offset = int64(autosize) 484 p.From.Reg = REGSP 485 p.To.Type = obj.TYPE_REG 486 p.To.Reg = REGPC 487 488 489 490 491 492 if p.To.Sym != nil { 493 p.To.Reg = REGLINK 494 q2 = obj.Appendp(p, newprog) 495 q2.As = AB 496 q2.To.Type = obj.TYPE_BRANCH 497 q2.To.Sym = p.To.Sym 498 p.To.Sym = nil 499 p.To.Name = obj.NAME_NONE 500 p = q2 501 } 502 503 case AADD: 504 if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP { 505 p.Spadj = int32(-p.From.Offset) 506 } 507 508 case ASUB: 509 if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP { 510 p.Spadj = int32(p.From.Offset) 511 } 512 513 case ADIV, ADIVU, AMOD, AMODU: 514 if cursym.Func().Text.From.Sym.NoSplit() { 515 ctxt.Diag("cannot divide in NOSPLIT function") 516 } 517 const debugdivmod = false 518 if debugdivmod { 519 break 520 } 521 if p.From.Type != obj.TYPE_REG { 522 break 523 } 524 if p.To.Type != obj.TYPE_REG { 525 break 526 } 527 528 529 q1 := *p 530 if q1.Reg == REGTMP || q1.Reg == 0 && q1.To.Reg == REGTMP { 531 ctxt.Diag("div already using REGTMP: %v", p) 532 } 533 534 535 p.As = AMOVW 536 p.Pos = q1.Pos 537 p.From.Type = obj.TYPE_MEM 538 p.From.Reg = REGG 539 p.From.Offset = 6 * 4 540 p.Reg = 0 541 p.To.Type = obj.TYPE_REG 542 p.To.Reg = REGTMP 543 544 545 p = obj.Appendp(p, newprog) 546 p.As = AMOVW 547 p.Pos = q1.Pos 548 p.From.Type = obj.TYPE_REG 549 p.From.Reg = q1.From.Reg 550 p.To.Type = obj.TYPE_MEM 551 p.To.Reg = REGTMP 552 p.To.Offset = 8 * 4 553 554 555 p = obj.Appendp(p, newprog) 556 p.As = AMOVW 557 p.Pos = q1.Pos 558 p.From.Type = obj.TYPE_REG 559 p.From.Reg = q1.Reg 560 if q1.Reg == 0 { 561 p.From.Reg = q1.To.Reg 562 } 563 p.To.Type = obj.TYPE_REG 564 p.To.Reg = REG_R8 565 p.To.Offset = 0 566 567 568 p = obj.Appendp(p, newprog) 569 p.As = ABL 570 p.Pos = q1.Pos 571 p.To.Type = obj.TYPE_BRANCH 572 switch o { 573 case ADIV: 574 p.To.Sym = symdiv 575 case ADIVU: 576 p.To.Sym = symdivu 577 case AMOD: 578 p.To.Sym = symmod 579 case AMODU: 580 p.To.Sym = symmodu 581 } 582 583 584 p = obj.Appendp(p, newprog) 585 p.As = AMOVW 586 p.Pos = q1.Pos 587 p.From.Type = obj.TYPE_REG 588 p.From.Reg = REGTMP 589 p.From.Offset = 0 590 p.To.Type = obj.TYPE_REG 591 p.To.Reg = q1.To.Reg 592 593 case AMOVW: 594 if (p.Scond&C_WBIT != 0) && p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP { 595 p.Spadj = int32(-p.To.Offset) 596 } 597 if (p.Scond&C_PBIT != 0) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP && p.To.Reg != REGPC { 598 p.Spadj = int32(-p.From.Offset) 599 } 600 if p.From.Type == obj.TYPE_ADDR && p.From.Reg == REGSP && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP { 601 p.Spadj = int32(-p.From.Offset) 602 } 603 604 case obj.AGETCALLERPC: 605 if cursym.Leaf() { 606 607 p.As = AMOVW 608 p.From.Type = obj.TYPE_REG 609 p.From.Reg = REGLINK 610 } else { 611 612 p.As = AMOVW 613 p.From.Type = obj.TYPE_MEM 614 p.From.Reg = REGSP 615 } 616 } 617 618 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 { 619 f := c.cursym.Func() 620 if f.FuncFlag&abi.FuncFlagSPWrite == 0 { 621 c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite 622 if ctxt.Debugvlog || !ctxt.IsAsm { 623 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p) 624 if !ctxt.IsAsm { 625 ctxt.Diag("invalid auto-SPWRITE in non-assembly") 626 ctxt.DiagFlush() 627 log.Fatalf("bad SPWRITE") 628 } 629 } 630 } 631 } 632 } 633 } 634 635 func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { 636 if c.ctxt.Flag_maymorestack != "" { 637 638 const frameSize = 8 639 640 p = obj.Appendp(p, c.newprog) 641 p.As = AMOVW 642 p.Scond |= C_WBIT 643 p.From.Type = obj.TYPE_REG 644 p.From.Reg = REGLINK 645 p.To.Type = obj.TYPE_MEM 646 p.To.Offset = -frameSize 647 p.To.Reg = REGSP 648 p.Spadj = frameSize 649 650 651 p = obj.Appendp(p, c.newprog) 652 p.As = AMOVW 653 p.From.Type = obj.TYPE_REG 654 p.From.Reg = REGCTXT 655 p.To.Type = obj.TYPE_MEM 656 p.To.Offset = 4 657 p.To.Reg = REGSP 658 659 660 p = obj.Appendp(p, c.newprog) 661 p.As = obj.ACALL 662 p.To.Type = obj.TYPE_BRANCH 663 664 p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI()) 665 666 667 668 669 p = obj.Appendp(p, c.newprog) 670 p.As = AMOVW 671 p.From.Type = obj.TYPE_MEM 672 p.From.Offset = 4 673 p.From.Reg = REGSP 674 p.To.Type = obj.TYPE_REG 675 p.To.Reg = REGCTXT 676 677 678 p.As = AMOVW 679 p.Scond |= C_PBIT 680 p.From.Type = obj.TYPE_MEM 681 p.From.Offset = frameSize 682 p.From.Reg = REGSP 683 p.To.Type = obj.TYPE_REG 684 p.To.Reg = REGLINK 685 p.Spadj = -frameSize 686 } 687 688 689 startPred := p 690 691 692 p = obj.Appendp(p, c.newprog) 693 694 p.As = AMOVW 695 p.From.Type = obj.TYPE_MEM 696 p.From.Reg = REGG 697 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) 698 if c.cursym.CFunc() { 699 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) 700 } 701 p.To.Type = obj.TYPE_REG 702 p.To.Reg = REG_R1 703 704 705 706 707 708 p = c.ctxt.StartUnsafePoint(p, c.newprog) 709 710 if framesize <= abi.StackSmall { 711 712 713 p = obj.Appendp(p, c.newprog) 714 715 p.As = ACMP 716 p.From.Type = obj.TYPE_REG 717 p.From.Reg = REG_R1 718 p.Reg = REGSP 719 } else if framesize <= abi.StackBig { 720 721 722 723 p = obj.Appendp(p, c.newprog) 724 725 p.As = AMOVW 726 p.From.Type = obj.TYPE_ADDR 727 p.From.Reg = REGSP 728 p.From.Offset = -(int64(framesize) - abi.StackSmall) 729 p.To.Type = obj.TYPE_REG 730 p.To.Reg = REG_R2 731 732 p = obj.Appendp(p, c.newprog) 733 p.As = ACMP 734 p.From.Type = obj.TYPE_REG 735 p.From.Reg = REG_R1 736 p.Reg = REG_R2 737 } else { 738 739 740 741 742 743 744 745 746 747 748 749 750 751 p = obj.Appendp(p, c.newprog) 752 p.As = ASUB 753 p.Scond = C_SBIT 754 p.From.Type = obj.TYPE_CONST 755 p.From.Offset = int64(framesize) - abi.StackSmall 756 p.Reg = REGSP 757 p.To.Type = obj.TYPE_REG 758 p.To.Reg = REG_R2 759 760 p = obj.Appendp(p, c.newprog) 761 p.As = ACMP 762 p.Scond = C_SCOND_HS 763 p.From.Type = obj.TYPE_REG 764 p.From.Reg = REG_R1 765 p.Reg = REG_R2 766 } 767 768 769 bls := obj.Appendp(p, c.newprog) 770 bls.As = ABLS 771 bls.To.Type = obj.TYPE_BRANCH 772 773 end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1) 774 775 var last *obj.Prog 776 for last = c.cursym.Func().Text; last.Link != nil; last = last.Link { 777 } 778 779 780 781 782 spfix := obj.Appendp(last, c.newprog) 783 spfix.As = obj.ANOP 784 spfix.Spadj = -framesize 785 786 pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog) 787 pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog) 788 789 790 movw := obj.Appendp(pcdata, c.newprog) 791 movw.As = AMOVW 792 movw.From.Type = obj.TYPE_REG 793 movw.From.Reg = REGLINK 794 movw.To.Type = obj.TYPE_REG 795 movw.To.Reg = REG_R3 796 797 bls.To.SetTarget(movw) 798 799 800 call := obj.Appendp(movw, c.newprog) 801 call.As = obj.ACALL 802 call.To.Type = obj.TYPE_BRANCH 803 morestack := "runtime.morestack" 804 switch { 805 case c.cursym.CFunc(): 806 morestack = "runtime.morestackc" 807 case !c.cursym.Func().Text.From.Sym.NeedCtxt(): 808 morestack = "runtime.morestack_noctxt" 809 } 810 call.To.Sym = c.ctxt.Lookup(morestack) 811 812 pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1) 813 814 815 b := obj.Appendp(pcdata, c.newprog) 816 b.As = obj.AJMP 817 b.To.Type = obj.TYPE_BRANCH 818 b.To.SetTarget(startPred.Link) 819 b.Spadj = +framesize 820 821 return end 822 } 823 824 var unaryDst = map[obj.As]bool{ 825 ASWI: true, 826 AWORD: true, 827 } 828 829 var Linkarm = obj.LinkArch{ 830 Arch: sys.ArchARM, 831 Init: buildop, 832 Preprocess: preprocess, 833 Assemble: span5, 834 Progedit: progedit, 835 UnaryDst: unaryDst, 836 DWARFRegisters: ARMDWARFRegisters, 837 }