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