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