github.com/alash3al/go@v0.0.0-20150827002835-d497eeb00540/src/cmd/internal/obj/arm/obj5.go (about) 1 // Derived from Inferno utils/5c/swt.c 2 // http://code.google.com/p/inferno-os/source/browse/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 "cmd/internal/obj" 35 "encoding/binary" 36 "fmt" 37 "log" 38 "math" 39 ) 40 41 var progedit_tlsfallback *obj.LSym 42 43 func progedit(ctxt *obj.Link, p *obj.Prog) { 44 p.From.Class = 0 45 p.To.Class = 0 46 47 // Rewrite B/BL to symbol as TYPE_BRANCH. 48 switch p.As { 49 case AB, 50 ABL, 51 obj.ADUFFZERO, 52 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 // Replace TLS register fetches on older ARM procesors. 59 switch p.As { 60 // Treat MRC 15, 0, <reg>, C13, C0, 3 specially. 61 case AMRC: 62 if p.To.Offset&0xffff0fff == 0xee1d0f70 { 63 // Because the instruction might be rewriten to a BL which returns in R0 64 // the register must be zero. 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 ctxt.Goarm < 7 { 70 // Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension. 71 if progedit_tlsfallback == nil { 72 progedit_tlsfallback = obj.Linklookup(ctxt, "runtime.read_tls_fallback", 0) 73 } 74 75 // MOVW LR, R11 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 // BL runtime.read_tls_fallback(SB) 84 p = obj.Appendp(ctxt, p) 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 // MOVW R11, LR 92 p = obj.Appendp(ctxt, p) 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 // Otherwise, MRC/MCR instructions need no further treatment. 104 p.As = AWORD 105 } 106 107 // Rewrite float constants to values stored in memory. 108 switch p.As { 109 case AMOVF: 110 if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.Val.(float64)) < 0 && (chipzero5(ctxt, p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) { 111 f32 := float32(p.From.Val.(float64)) 112 i32 := math.Float32bits(f32) 113 literal := fmt.Sprintf("$f32.%08x", i32) 114 s := obj.Linklookup(ctxt, literal, 0) 115 p.From.Type = obj.TYPE_MEM 116 p.From.Sym = s 117 p.From.Name = obj.NAME_EXTERN 118 p.From.Offset = 0 119 } 120 121 case AMOVD: 122 if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.Val.(float64)) < 0 && (chipzero5(ctxt, p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) { 123 i64 := math.Float64bits(p.From.Val.(float64)) 124 literal := fmt.Sprintf("$f64.%016x", i64) 125 s := obj.Linklookup(ctxt, literal, 0) 126 p.From.Type = obj.TYPE_MEM 127 p.From.Sym = s 128 p.From.Name = obj.NAME_EXTERN 129 p.From.Offset = 0 130 } 131 } 132 133 if ctxt.Flag_shared != 0 { 134 // Shared libraries use R_ARM_TLS_IE32 instead of 135 // R_ARM_TLS_LE32, replacing the link time constant TLS offset in 136 // runtime.tlsg with an address to a GOT entry containing the 137 // offset. Rewrite $runtime.tlsg(SB) to runtime.tlsg(SB) to 138 // compensate. 139 if ctxt.Tlsg == nil { 140 ctxt.Tlsg = obj.Linklookup(ctxt, "runtime.tlsg", 0) 141 } 142 143 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && p.From.Sym == ctxt.Tlsg { 144 p.From.Type = obj.TYPE_MEM 145 } 146 if p.To.Type == obj.TYPE_ADDR && p.To.Name == obj.NAME_EXTERN && p.To.Sym == ctxt.Tlsg { 147 p.To.Type = obj.TYPE_MEM 148 } 149 } 150 } 151 152 // Prog.mark 153 const ( 154 FOLL = 1 << 0 155 LABEL = 1 << 1 156 LEAF = 1 << 2 157 ) 158 159 func linkcase(casep *obj.Prog) { 160 for p := casep; p != nil; p = p.Link { 161 if p.As == ABCASE { 162 for ; p != nil && p.As == ABCASE; p = p.Link { 163 p.Rel = casep 164 } 165 break 166 } 167 } 168 } 169 170 func preprocess(ctxt *obj.Link, cursym *obj.LSym) { 171 autosize := int32(0) 172 173 ctxt.Cursym = cursym 174 175 if cursym.Text == nil || cursym.Text.Link == nil { 176 return 177 } 178 179 softfloat(ctxt, cursym) 180 181 p := cursym.Text 182 autoffset := int32(p.To.Offset) 183 if autoffset < 0 { 184 autoffset = 0 185 } 186 cursym.Locals = autoffset 187 cursym.Args = p.To.Val.(int32) 188 189 /* 190 * find leaf subroutines 191 * strip NOPs 192 * expand RET 193 * expand BECOME pseudo 194 */ 195 var q1 *obj.Prog 196 var q *obj.Prog 197 for p := cursym.Text; p != nil; p = p.Link { 198 switch p.As { 199 case ACASE: 200 if ctxt.Flag_shared != 0 { 201 linkcase(p) 202 } 203 204 case obj.ATEXT: 205 p.Mark |= LEAF 206 207 case obj.ARET: 208 break 209 210 case ADIV, ADIVU, AMOD, AMODU: 211 q = p 212 if ctxt.Sym_div == nil { 213 initdiv(ctxt) 214 } 215 cursym.Text.Mark &^= LEAF 216 continue 217 218 case obj.ANOP: 219 q1 = p.Link 220 q.Link = q1 /* q is non-nop */ 221 if q1 != nil { 222 q1.Mark |= p.Mark 223 } 224 continue 225 226 case ABL, 227 ABX, 228 obj.ADUFFZERO, 229 obj.ADUFFCOPY: 230 cursym.Text.Mark &^= LEAF 231 fallthrough 232 233 case ABCASE, 234 AB, 235 ABEQ, 236 ABNE, 237 ABCS, 238 ABHS, 239 ABCC, 240 ABLO, 241 ABMI, 242 ABPL, 243 ABVS, 244 ABVC, 245 ABHI, 246 ABLS, 247 ABGE, 248 ABLT, 249 ABGT, 250 ABLE: 251 q1 = p.Pcond 252 if q1 != nil { 253 for q1.As == obj.ANOP { 254 q1 = q1.Link 255 p.Pcond = q1 256 } 257 } 258 } 259 260 q = p 261 } 262 263 var o int 264 var p1 *obj.Prog 265 var p2 *obj.Prog 266 var q2 *obj.Prog 267 for p := cursym.Text; p != nil; p = p.Link { 268 o = int(p.As) 269 switch o { 270 case obj.ATEXT: 271 autosize = int32(p.To.Offset + 4) 272 if autosize <= 4 { 273 if cursym.Text.Mark&LEAF != 0 { 274 p.To.Offset = -4 275 autosize = 0 276 } 277 } 278 279 if autosize == 0 && cursym.Text.Mark&LEAF == 0 { 280 if ctxt.Debugvlog != 0 { 281 fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name) 282 ctxt.Bso.Flush() 283 } 284 285 cursym.Text.Mark |= LEAF 286 } 287 288 if cursym.Text.Mark&LEAF != 0 { 289 cursym.Leaf = 1 290 if autosize == 0 { 291 break 292 } 293 } 294 295 if p.From3.Offset&obj.NOSPLIT == 0 { 296 p = stacksplit(ctxt, p, autosize) // emit split check 297 } 298 299 // MOVW.W R14,$-autosize(SP) 300 p = obj.Appendp(ctxt, p) 301 302 p.As = AMOVW 303 p.Scond |= C_WBIT 304 p.From.Type = obj.TYPE_REG 305 p.From.Reg = REGLINK 306 p.To.Type = obj.TYPE_MEM 307 p.To.Offset = int64(-autosize) 308 p.To.Reg = REGSP 309 p.Spadj = autosize 310 311 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 312 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 313 // 314 // MOVW g_panic(g), R1 315 // CMP $0, R1 316 // B.EQ end 317 // MOVW panic_argp(R1), R2 318 // ADD $(autosize+4), R13, R3 319 // CMP R2, R3 320 // B.NE end 321 // ADD $4, R13, R4 322 // MOVW R4, panic_argp(R1) 323 // end: 324 // NOP 325 // 326 // The NOP is needed to give the jumps somewhere to land. 327 // It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes. 328 329 p = obj.Appendp(ctxt, p) 330 331 p.As = AMOVW 332 p.From.Type = obj.TYPE_MEM 333 p.From.Reg = REGG 334 p.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic 335 p.To.Type = obj.TYPE_REG 336 p.To.Reg = REG_R1 337 338 p = obj.Appendp(ctxt, p) 339 p.As = ACMP 340 p.From.Type = obj.TYPE_CONST 341 p.From.Offset = 0 342 p.Reg = REG_R1 343 344 p = obj.Appendp(ctxt, p) 345 p.As = ABEQ 346 p.To.Type = obj.TYPE_BRANCH 347 p1 = p 348 349 p = obj.Appendp(ctxt, p) 350 p.As = AMOVW 351 p.From.Type = obj.TYPE_MEM 352 p.From.Reg = REG_R1 353 p.From.Offset = 0 // Panic.argp 354 p.To.Type = obj.TYPE_REG 355 p.To.Reg = REG_R2 356 357 p = obj.Appendp(ctxt, p) 358 p.As = AADD 359 p.From.Type = obj.TYPE_CONST 360 p.From.Offset = int64(autosize) + 4 361 p.Reg = REG_R13 362 p.To.Type = obj.TYPE_REG 363 p.To.Reg = REG_R3 364 365 p = obj.Appendp(ctxt, p) 366 p.As = ACMP 367 p.From.Type = obj.TYPE_REG 368 p.From.Reg = REG_R2 369 p.Reg = REG_R3 370 371 p = obj.Appendp(ctxt, p) 372 p.As = ABNE 373 p.To.Type = obj.TYPE_BRANCH 374 p2 = p 375 376 p = obj.Appendp(ctxt, p) 377 p.As = AADD 378 p.From.Type = obj.TYPE_CONST 379 p.From.Offset = 4 380 p.Reg = REG_R13 381 p.To.Type = obj.TYPE_REG 382 p.To.Reg = REG_R4 383 384 p = obj.Appendp(ctxt, p) 385 p.As = AMOVW 386 p.From.Type = obj.TYPE_REG 387 p.From.Reg = REG_R4 388 p.To.Type = obj.TYPE_MEM 389 p.To.Reg = REG_R1 390 p.To.Offset = 0 // Panic.argp 391 392 p = obj.Appendp(ctxt, p) 393 394 p.As = obj.ANOP 395 p1.Pcond = p 396 p2.Pcond = p 397 } 398 399 case obj.ARET: 400 obj.Nocache(p) 401 if cursym.Text.Mark&LEAF != 0 { 402 if autosize == 0 { 403 p.As = AB 404 p.From = obj.Addr{} 405 if p.To.Sym != nil { // retjmp 406 p.To.Type = obj.TYPE_BRANCH 407 } else { 408 p.To.Type = obj.TYPE_MEM 409 p.To.Offset = 0 410 p.To.Reg = REGLINK 411 } 412 413 break 414 } 415 } 416 417 p.As = AMOVW 418 p.Scond |= C_PBIT 419 p.From.Type = obj.TYPE_MEM 420 p.From.Offset = int64(autosize) 421 p.From.Reg = REGSP 422 p.To.Type = obj.TYPE_REG 423 p.To.Reg = REGPC 424 425 // If there are instructions following 426 // this ARET, they come from a branch 427 // with the same stackframe, so no spadj. 428 if p.To.Sym != nil { // retjmp 429 p.To.Reg = REGLINK 430 q2 = obj.Appendp(ctxt, p) 431 q2.As = AB 432 q2.To.Type = obj.TYPE_BRANCH 433 q2.To.Sym = p.To.Sym 434 p.To.Sym = nil 435 p = q2 436 } 437 438 case AADD: 439 if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP { 440 p.Spadj = int32(-p.From.Offset) 441 } 442 443 case ASUB: 444 if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP { 445 p.Spadj = int32(p.From.Offset) 446 } 447 448 case ADIV, ADIVU, AMOD, AMODU: 449 if cursym.Text.From3.Offset&obj.NOSPLIT != 0 { 450 ctxt.Diag("cannot divide in NOSPLIT function") 451 } 452 if ctxt.Debugdivmod != 0 { 453 break 454 } 455 if p.From.Type != obj.TYPE_REG { 456 break 457 } 458 if p.To.Type != obj.TYPE_REG { 459 break 460 } 461 462 // Make copy because we overwrite p below. 463 q1 := *p 464 if q1.Reg == REGTMP || q1.Reg == 0 && q1.To.Reg == REGTMP { 465 ctxt.Diag("div already using REGTMP: %v", p) 466 } 467 468 /* MOV m(g),REGTMP */ 469 p.As = AMOVW 470 p.Lineno = q1.Lineno 471 p.From.Type = obj.TYPE_MEM 472 p.From.Reg = REGG 473 p.From.Offset = 6 * 4 // offset of g.m 474 p.Reg = 0 475 p.To.Type = obj.TYPE_REG 476 p.To.Reg = REGTMP 477 478 /* MOV a,m_divmod(REGTMP) */ 479 p = obj.Appendp(ctxt, p) 480 p.As = AMOVW 481 p.Lineno = q1.Lineno 482 p.From.Type = obj.TYPE_REG 483 p.From.Reg = q1.From.Reg 484 p.To.Type = obj.TYPE_MEM 485 p.To.Reg = REGTMP 486 p.To.Offset = 8 * 4 // offset of m.divmod 487 488 /* MOV b,REGTMP */ 489 p = obj.Appendp(ctxt, p) 490 p.As = AMOVW 491 p.Lineno = q1.Lineno 492 p.From.Type = obj.TYPE_REG 493 p.From.Reg = q1.Reg 494 if q1.Reg == 0 { 495 p.From.Reg = q1.To.Reg 496 } 497 p.To.Type = obj.TYPE_REG 498 p.To.Reg = REGTMP 499 p.To.Offset = 0 500 501 /* CALL appropriate */ 502 p = obj.Appendp(ctxt, p) 503 p.As = ABL 504 p.Lineno = q1.Lineno 505 p.To.Type = obj.TYPE_BRANCH 506 switch o { 507 case ADIV: 508 p.To.Sym = ctxt.Sym_div 509 510 case ADIVU: 511 p.To.Sym = ctxt.Sym_divu 512 513 case AMOD: 514 p.To.Sym = ctxt.Sym_mod 515 516 case AMODU: 517 p.To.Sym = ctxt.Sym_modu 518 } 519 520 /* MOV REGTMP, b */ 521 p = obj.Appendp(ctxt, p) 522 p.As = AMOVW 523 p.Lineno = q1.Lineno 524 p.From.Type = obj.TYPE_REG 525 p.From.Reg = REGTMP 526 p.From.Offset = 0 527 p.To.Type = obj.TYPE_REG 528 p.To.Reg = q1.To.Reg 529 530 case AMOVW: 531 if (p.Scond&C_WBIT != 0) && p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP { 532 p.Spadj = int32(-p.To.Offset) 533 } 534 if (p.Scond&C_PBIT != 0) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP && p.To.Reg != REGPC { 535 p.Spadj = int32(-p.From.Offset) 536 } 537 if p.From.Type == obj.TYPE_ADDR && p.From.Reg == REGSP && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP { 538 p.Spadj = int32(-p.From.Offset) 539 } 540 } 541 } 542 } 543 544 func isfloatreg(a *obj.Addr) bool { 545 return a.Type == obj.TYPE_REG && REG_F0 <= a.Reg && a.Reg <= REG_F15 546 } 547 548 func softfloat(ctxt *obj.Link, cursym *obj.LSym) { 549 if ctxt.Goarm > 5 { 550 return 551 } 552 553 symsfloat := obj.Linklookup(ctxt, "_sfloat", 0) 554 555 wasfloat := 0 556 for p := cursym.Text; p != nil; p = p.Link { 557 if p.Pcond != nil { 558 p.Pcond.Mark |= LABEL 559 } 560 } 561 var next *obj.Prog 562 for p := cursym.Text; p != nil; p = p.Link { 563 switch p.As { 564 case AMOVW: 565 if isfloatreg(&p.To) || isfloatreg(&p.From) { 566 goto soft 567 } 568 goto notsoft 569 570 case AMOVWD, 571 AMOVWF, 572 AMOVDW, 573 AMOVFW, 574 AMOVFD, 575 AMOVDF, 576 AMOVF, 577 AMOVD, 578 ACMPF, 579 ACMPD, 580 AADDF, 581 AADDD, 582 ASUBF, 583 ASUBD, 584 AMULF, 585 AMULD, 586 ADIVF, 587 ADIVD, 588 ASQRTF, 589 ASQRTD, 590 AABSF, 591 AABSD: 592 goto soft 593 594 default: 595 goto notsoft 596 } 597 598 soft: 599 if wasfloat == 0 || (p.Mark&LABEL != 0) { 600 next = ctxt.NewProg() 601 *next = *p 602 603 // BL _sfloat(SB) 604 *p = obj.Prog{} 605 p.Ctxt = ctxt 606 p.Link = next 607 p.As = ABL 608 p.To.Type = obj.TYPE_BRANCH 609 p.To.Sym = symsfloat 610 p.Lineno = next.Lineno 611 612 p = next 613 wasfloat = 1 614 } 615 616 continue 617 618 notsoft: 619 wasfloat = 0 620 } 621 } 622 623 func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog { 624 // MOVW g_stackguard(g), R1 625 p = obj.Appendp(ctxt, p) 626 627 p.As = AMOVW 628 p.From.Type = obj.TYPE_MEM 629 p.From.Reg = REGG 630 p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0 631 if ctxt.Cursym.Cfunc != 0 { 632 p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1 633 } 634 p.To.Type = obj.TYPE_REG 635 p.To.Reg = REG_R1 636 637 if framesize <= obj.StackSmall { 638 // small stack: SP < stackguard 639 // CMP stackguard, SP 640 p = obj.Appendp(ctxt, p) 641 642 p.As = ACMP 643 p.From.Type = obj.TYPE_REG 644 p.From.Reg = REG_R1 645 p.Reg = REGSP 646 } else if framesize <= obj.StackBig { 647 // large stack: SP-framesize < stackguard-StackSmall 648 // MOVW $-framesize(SP), R2 649 // CMP stackguard, R2 650 p = obj.Appendp(ctxt, p) 651 652 p.As = AMOVW 653 p.From.Type = obj.TYPE_ADDR 654 p.From.Reg = REGSP 655 p.From.Offset = int64(-framesize) 656 p.To.Type = obj.TYPE_REG 657 p.To.Reg = REG_R2 658 659 p = obj.Appendp(ctxt, p) 660 p.As = ACMP 661 p.From.Type = obj.TYPE_REG 662 p.From.Reg = REG_R1 663 p.Reg = REG_R2 664 } else { 665 // Such a large stack we need to protect against wraparound 666 // if SP is close to zero. 667 // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall) 668 // The +StackGuard on both sides is required to keep the left side positive: 669 // SP is allowed to be slightly below stackguard. See stack.h. 670 // CMP $StackPreempt, R1 671 // MOVW.NE $StackGuard(SP), R2 672 // SUB.NE R1, R2 673 // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3 674 // CMP.NE R3, R2 675 p = obj.Appendp(ctxt, p) 676 677 p.As = ACMP 678 p.From.Type = obj.TYPE_CONST 679 p.From.Offset = int64(uint32(obj.StackPreempt & (1<<32 - 1))) 680 p.Reg = REG_R1 681 682 p = obj.Appendp(ctxt, p) 683 p.As = AMOVW 684 p.From.Type = obj.TYPE_ADDR 685 p.From.Reg = REGSP 686 p.From.Offset = obj.StackGuard 687 p.To.Type = obj.TYPE_REG 688 p.To.Reg = REG_R2 689 p.Scond = C_SCOND_NE 690 691 p = obj.Appendp(ctxt, p) 692 p.As = ASUB 693 p.From.Type = obj.TYPE_REG 694 p.From.Reg = REG_R1 695 p.To.Type = obj.TYPE_REG 696 p.To.Reg = REG_R2 697 p.Scond = C_SCOND_NE 698 699 p = obj.Appendp(ctxt, p) 700 p.As = AMOVW 701 p.From.Type = obj.TYPE_ADDR 702 p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall) 703 p.To.Type = obj.TYPE_REG 704 p.To.Reg = REG_R3 705 p.Scond = C_SCOND_NE 706 707 p = obj.Appendp(ctxt, p) 708 p.As = ACMP 709 p.From.Type = obj.TYPE_REG 710 p.From.Reg = REG_R3 711 p.Reg = REG_R2 712 p.Scond = C_SCOND_NE 713 } 714 715 // BLS call-to-morestack 716 bls := obj.Appendp(ctxt, p) 717 bls.As = ABLS 718 bls.To.Type = obj.TYPE_BRANCH 719 720 var last *obj.Prog 721 for last = ctxt.Cursym.Text; last.Link != nil; last = last.Link { 722 } 723 724 // MOVW LR, R3 725 movw := obj.Appendp(ctxt, last) 726 movw.As = AMOVW 727 movw.From.Type = obj.TYPE_REG 728 movw.From.Reg = REGLINK 729 movw.To.Type = obj.TYPE_REG 730 movw.To.Reg = REG_R3 731 732 bls.Pcond = movw 733 734 // BL runtime.morestack 735 call := obj.Appendp(ctxt, movw) 736 call.As = obj.ACALL 737 call.To.Type = obj.TYPE_BRANCH 738 morestack := "runtime.morestack" 739 switch { 740 case ctxt.Cursym.Cfunc != 0: 741 morestack = "runtime.morestackc" 742 case ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0: 743 morestack = "runtime.morestack_noctxt" 744 } 745 call.To.Sym = obj.Linklookup(ctxt, morestack, 0) 746 747 // B start 748 b := obj.Appendp(ctxt, call) 749 b.As = obj.AJMP 750 b.To.Type = obj.TYPE_BRANCH 751 b.Pcond = ctxt.Cursym.Text.Link 752 753 return bls 754 } 755 756 func initdiv(ctxt *obj.Link) { 757 if ctxt.Sym_div != nil { 758 return 759 } 760 ctxt.Sym_div = obj.Linklookup(ctxt, "_div", 0) 761 ctxt.Sym_divu = obj.Linklookup(ctxt, "_divu", 0) 762 ctxt.Sym_mod = obj.Linklookup(ctxt, "_mod", 0) 763 ctxt.Sym_modu = obj.Linklookup(ctxt, "_modu", 0) 764 } 765 766 func follow(ctxt *obj.Link, s *obj.LSym) { 767 ctxt.Cursym = s 768 769 firstp := ctxt.NewProg() 770 lastp := firstp 771 xfol(ctxt, s.Text, &lastp) 772 lastp.Link = nil 773 s.Text = firstp.Link 774 } 775 776 func relinv(a int) int { 777 switch a { 778 case ABEQ: 779 return ABNE 780 case ABNE: 781 return ABEQ 782 case ABCS: 783 return ABCC 784 case ABHS: 785 return ABLO 786 case ABCC: 787 return ABCS 788 case ABLO: 789 return ABHS 790 case ABMI: 791 return ABPL 792 case ABPL: 793 return ABMI 794 case ABVS: 795 return ABVC 796 case ABVC: 797 return ABVS 798 case ABHI: 799 return ABLS 800 case ABLS: 801 return ABHI 802 case ABGE: 803 return ABLT 804 case ABLT: 805 return ABGE 806 case ABGT: 807 return ABLE 808 case ABLE: 809 return ABGT 810 } 811 812 log.Fatalf("unknown relation: %s", Anames[a]) 813 return 0 814 } 815 816 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 817 var q *obj.Prog 818 var r *obj.Prog 819 var a int 820 var i int 821 822 loop: 823 if p == nil { 824 return 825 } 826 a = int(p.As) 827 if a == AB { 828 q = p.Pcond 829 if q != nil && q.As != obj.ATEXT { 830 p.Mark |= FOLL 831 p = q 832 if p.Mark&FOLL == 0 { 833 goto loop 834 } 835 } 836 } 837 838 if p.Mark&FOLL != 0 { 839 i = 0 840 q = p 841 for ; i < 4; i, q = i+1, q.Link { 842 if q == *last || q == nil { 843 break 844 } 845 a = int(q.As) 846 if a == obj.ANOP { 847 i-- 848 continue 849 } 850 851 if a == AB || (a == obj.ARET && q.Scond == C_SCOND_NONE) || a == ARFE || a == obj.AUNDEF { 852 goto copy 853 } 854 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 855 continue 856 } 857 if a != ABEQ && a != ABNE { 858 continue 859 } 860 861 copy: 862 for { 863 r = ctxt.NewProg() 864 *r = *p 865 if r.Mark&FOLL == 0 { 866 fmt.Printf("can't happen 1\n") 867 } 868 r.Mark |= FOLL 869 if p != q { 870 p = p.Link 871 (*last).Link = r 872 *last = r 873 continue 874 } 875 876 (*last).Link = r 877 *last = r 878 if a == AB || (a == obj.ARET && q.Scond == C_SCOND_NONE) || a == ARFE || a == obj.AUNDEF { 879 return 880 } 881 r.As = ABNE 882 if a == ABNE { 883 r.As = ABEQ 884 } 885 r.Pcond = p.Link 886 r.Link = p.Pcond 887 if r.Link.Mark&FOLL == 0 { 888 xfol(ctxt, r.Link, last) 889 } 890 if r.Pcond.Mark&FOLL == 0 { 891 fmt.Printf("can't happen 2\n") 892 } 893 return 894 } 895 } 896 897 a = AB 898 q = ctxt.NewProg() 899 q.As = int16(a) 900 q.Lineno = p.Lineno 901 q.To.Type = obj.TYPE_BRANCH 902 q.To.Offset = p.Pc 903 q.Pcond = p 904 p = q 905 } 906 907 p.Mark |= FOLL 908 (*last).Link = p 909 *last = p 910 if a == AB || (a == obj.ARET && p.Scond == C_SCOND_NONE) || a == ARFE || a == obj.AUNDEF { 911 return 912 } 913 914 if p.Pcond != nil { 915 if a != ABL && a != ABX && p.Link != nil { 916 q = obj.Brchain(ctxt, p.Link) 917 if a != obj.ATEXT && a != ABCASE { 918 if q != nil && (q.Mark&FOLL != 0) { 919 p.As = int16(relinv(a)) 920 p.Link = p.Pcond 921 p.Pcond = q 922 } 923 } 924 925 xfol(ctxt, p.Link, last) 926 q = obj.Brchain(ctxt, p.Pcond) 927 if q == nil { 928 q = p.Pcond 929 } 930 if q.Mark&FOLL != 0 { 931 p.Pcond = q 932 return 933 } 934 935 p = q 936 goto loop 937 } 938 } 939 940 p = p.Link 941 goto loop 942 } 943 944 var unaryDst = map[int]bool{ 945 ASWI: true, 946 AWORD: true, 947 } 948 949 var Linkarm = obj.LinkArch{ 950 ByteOrder: binary.LittleEndian, 951 Name: "arm", 952 Thechar: '5', 953 Preprocess: preprocess, 954 Assemble: span5, 955 Follow: follow, 956 Progedit: progedit, 957 UnaryDst: unaryDst, 958 Minlc: 4, 959 Ptrsize: 4, 960 Regsize: 4, 961 }