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