github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/src/liblink/obj5.c (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 #include <u.h> 32 #include <libc.h> 33 #include <bio.h> 34 #include <link.h> 35 #include "../cmd/5l/5.out.h" 36 #include "../runtime/stack.h" 37 38 static Prog zprg = { 39 .as = AGOK, 40 .scond = C_SCOND_NONE, 41 .reg = NREG, 42 .from = { 43 .name = D_NONE, 44 .type = D_NONE, 45 .reg = NREG, 46 }, 47 .to = { 48 .name = D_NONE, 49 .type = D_NONE, 50 .reg = NREG, 51 }, 52 }; 53 54 static int 55 symtype(Addr *a) 56 { 57 return a->name; 58 } 59 60 static int 61 isdata(Prog *p) 62 { 63 return p->as == ADATA || p->as == AGLOBL; 64 } 65 66 static int 67 iscall(Prog *p) 68 { 69 return p->as == ABL; 70 } 71 72 static int 73 datasize(Prog *p) 74 { 75 return p->reg; 76 } 77 78 static int 79 textflag(Prog *p) 80 { 81 return p->reg; 82 } 83 84 static void 85 settextflag(Prog *p, int f) 86 { 87 p->reg = f; 88 } 89 90 static void 91 progedit(Link *ctxt, Prog *p) 92 { 93 char literal[64]; 94 LSym *s; 95 static LSym *tlsfallback; 96 97 p->from.class = 0; 98 p->to.class = 0; 99 100 // Rewrite B/BL to symbol as D_BRANCH. 101 switch(p->as) { 102 case AB: 103 case ABL: 104 case ADUFFZERO: 105 case ADUFFCOPY: 106 if(p->to.type == D_OREG && (p->to.name == D_EXTERN || p->to.name == D_STATIC) && p->to.sym != nil) 107 p->to.type = D_BRANCH; 108 break; 109 } 110 111 // Replace TLS register fetches on older ARM procesors. 112 switch(p->as) { 113 case AMRC: 114 // Treat MRC 15, 0, <reg>, C13, C0, 3 specially. 115 if((p->to.offset & 0xffff0fff) == 0xee1d0f70) { 116 // Because the instruction might be rewriten to a BL which returns in R0 117 // the register must be zero. 118 if ((p->to.offset & 0xf000) != 0) 119 ctxt->diag("%L: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p->lineno); 120 121 if(ctxt->goarm < 7) { 122 // Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension. 123 if(tlsfallback == nil) 124 tlsfallback = linklookup(ctxt, "runtime.read_tls_fallback", 0); 125 // MOVW LR, R11 126 p->as = AMOVW; 127 p->from.type = D_REG; 128 p->from.reg = REGLINK; 129 p->to.type = D_REG; 130 p->to.reg = REGTMP; 131 132 // BL runtime.read_tls_fallback(SB) 133 p = appendp(ctxt, p); 134 p->as = ABL; 135 p->to.type = D_BRANCH; 136 p->to.sym = tlsfallback; 137 p->to.offset = 0; 138 139 // MOVW R11, LR 140 p = appendp(ctxt, p); 141 p->as = AMOVW; 142 p->from.type = D_REG; 143 p->from.reg = REGTMP; 144 p->to.type = D_REG; 145 p->to.reg = REGLINK; 146 break; 147 } 148 } 149 // Otherwise, MRC/MCR instructions need no further treatment. 150 p->as = AWORD; 151 break; 152 } 153 154 // Rewrite float constants to values stored in memory. 155 switch(p->as) { 156 case AMOVF: 157 if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 && 158 (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) { 159 int32 i32; 160 float32 f32; 161 f32 = p->from.u.dval; 162 memmove(&i32, &f32, 4); 163 sprint(literal, "$f32.%08ux", (uint32)i32); 164 s = linklookup(ctxt, literal, 0); 165 if(s->type == 0) { 166 s->type = SRODATA; 167 adduint32(ctxt, s, i32); 168 s->reachable = 0; 169 } 170 p->from.type = D_OREG; 171 p->from.sym = s; 172 p->from.name = D_EXTERN; 173 p->from.offset = 0; 174 } 175 break; 176 177 case AMOVD: 178 if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 && 179 (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) { 180 int64 i64; 181 memmove(&i64, &p->from.u.dval, 8); 182 sprint(literal, "$f64.%016llux", (uvlong)i64); 183 s = linklookup(ctxt, literal, 0); 184 if(s->type == 0) { 185 s->type = SRODATA; 186 adduint64(ctxt, s, i64); 187 s->reachable = 0; 188 } 189 p->from.type = D_OREG; 190 p->from.sym = s; 191 p->from.name = D_EXTERN; 192 p->from.offset = 0; 193 } 194 break; 195 } 196 197 if(ctxt->flag_shared) { 198 // Shared libraries use R_ARM_TLS_IE32 instead of 199 // R_ARM_TLS_LE32, replacing the link time constant TLS offset in 200 // runtime.tlsg with an address to a GOT entry containing the 201 // offset. Rewrite $runtime.tlsg(SB) to runtime.tlsg(SB) to 202 // compensate. 203 if(ctxt->tlsg == nil) 204 ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0); 205 206 if(p->from.type == D_CONST && p->from.name == D_EXTERN && p->from.sym == ctxt->tlsg) 207 p->from.type = D_OREG; 208 if(p->to.type == D_CONST && p->to.name == D_EXTERN && p->to.sym == ctxt->tlsg) 209 p->to.type = D_OREG; 210 } 211 } 212 213 static Prog* 214 prg(void) 215 { 216 Prog *p; 217 218 p = emallocz(sizeof(*p)); 219 *p = zprg; 220 return p; 221 } 222 223 static Prog* stacksplit(Link*, Prog*, int32, int); 224 static void initdiv(Link*); 225 static void softfloat(Link*, LSym*); 226 227 // Prog.mark 228 enum 229 { 230 FOLL = 1<<0, 231 LABEL = 1<<1, 232 LEAF = 1<<2, 233 }; 234 235 static void 236 linkcase(Prog *casep) 237 { 238 Prog *p; 239 240 for(p = casep; p != nil; p = p->link){ 241 if(p->as == ABCASE) { 242 for(; p != nil && p->as == ABCASE; p = p->link) 243 p->pcrel = casep; 244 break; 245 } 246 } 247 } 248 249 static void 250 nocache(Prog *p) 251 { 252 p->optab = 0; 253 p->from.class = 0; 254 p->to.class = 0; 255 } 256 257 static void 258 addstacksplit(Link *ctxt, LSym *cursym) 259 { 260 Prog *p, *pl, *p1, *p2, *q, *q1, *q2; 261 int o; 262 int32 autosize, autoffset; 263 264 autosize = 0; 265 266 if(ctxt->symmorestack[0] == nil) { 267 ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0); 268 ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0); 269 } 270 271 q = nil; 272 273 ctxt->cursym = cursym; 274 275 if(cursym->text == nil || cursym->text->link == nil) 276 return; 277 278 softfloat(ctxt, cursym); 279 280 p = cursym->text; 281 autoffset = p->to.offset; 282 if(autoffset < 0) 283 autoffset = 0; 284 cursym->locals = autoffset; 285 cursym->args = p->to.offset2; 286 287 if(ctxt->debugzerostack) { 288 if(autoffset && !(p->reg&NOSPLIT)) { 289 // MOVW $4(R13), R1 290 p = appendp(ctxt, p); 291 p->as = AMOVW; 292 p->from.type = D_CONST; 293 p->from.reg = 13; 294 p->from.offset = 4; 295 p->to.type = D_REG; 296 p->to.reg = 1; 297 298 // MOVW $n(R13), R2 299 p = appendp(ctxt, p); 300 p->as = AMOVW; 301 p->from.type = D_CONST; 302 p->from.reg = 13; 303 p->from.offset = 4 + autoffset; 304 p->to.type = D_REG; 305 p->to.reg = 2; 306 307 // MOVW $0, R3 308 p = appendp(ctxt, p); 309 p->as = AMOVW; 310 p->from.type = D_CONST; 311 p->from.offset = 0; 312 p->to.type = D_REG; 313 p->to.reg = 3; 314 315 // L: 316 // MOVW.nil R3, 0(R1) +4 317 // CMP R1, R2 318 // BNE L 319 p = pl = appendp(ctxt, p); 320 p->as = AMOVW; 321 p->from.type = D_REG; 322 p->from.reg = 3; 323 p->to.type = D_OREG; 324 p->to.reg = 1; 325 p->to.offset = 4; 326 p->scond |= C_PBIT; 327 328 p = appendp(ctxt, p); 329 p->as = ACMP; 330 p->from.type = D_REG; 331 p->from.reg = 1; 332 p->reg = 2; 333 334 p = appendp(ctxt, p); 335 p->as = ABNE; 336 p->to.type = D_BRANCH; 337 p->pcond = pl; 338 } 339 } 340 341 /* 342 * find leaf subroutines 343 * strip NOPs 344 * expand RET 345 * expand BECOME pseudo 346 */ 347 348 for(p = cursym->text; p != nil; p = p->link) { 349 switch(p->as) { 350 case ACASE: 351 if(ctxt->flag_shared) 352 linkcase(p); 353 break; 354 355 case ATEXT: 356 p->mark |= LEAF; 357 break; 358 359 case ARET: 360 break; 361 362 case ADIV: 363 case ADIVU: 364 case AMOD: 365 case AMODU: 366 q = p; 367 if(ctxt->sym_div == nil) 368 initdiv(ctxt); 369 cursym->text->mark &= ~LEAF; 370 continue; 371 372 case ANOP: 373 q1 = p->link; 374 q->link = q1; /* q is non-nop */ 375 if(q1 != nil) 376 q1->mark |= p->mark; 377 continue; 378 379 case ABL: 380 case ABX: 381 case ADUFFZERO: 382 case ADUFFCOPY: 383 cursym->text->mark &= ~LEAF; 384 385 case ABCASE: 386 case AB: 387 388 case ABEQ: 389 case ABNE: 390 case ABCS: 391 case ABHS: 392 case ABCC: 393 case ABLO: 394 case ABMI: 395 case ABPL: 396 case ABVS: 397 case ABVC: 398 case ABHI: 399 case ABLS: 400 case ABGE: 401 case ABLT: 402 case ABGT: 403 case ABLE: 404 q1 = p->pcond; 405 if(q1 != nil) { 406 while(q1->as == ANOP) { 407 q1 = q1->link; 408 p->pcond = q1; 409 } 410 } 411 break; 412 } 413 q = p; 414 } 415 416 for(p = cursym->text; p != nil; p = p->link) { 417 o = p->as; 418 switch(o) { 419 case ATEXT: 420 autosize = p->to.offset + 4; 421 if(autosize <= 4) 422 if(cursym->text->mark & LEAF) { 423 p->to.offset = -4; 424 autosize = 0; 425 } 426 427 if(!autosize && !(cursym->text->mark & LEAF)) { 428 if(ctxt->debugvlog) { 429 Bprint(ctxt->bso, "save suppressed in: %s\n", 430 cursym->name); 431 Bflush(ctxt->bso); 432 } 433 cursym->text->mark |= LEAF; 434 } 435 if(cursym->text->mark & LEAF) { 436 cursym->leaf = 1; 437 if(!autosize) 438 break; 439 } 440 441 if(!(p->reg & NOSPLIT)) 442 p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check 443 444 // MOVW.W R14,$-autosize(SP) 445 p = appendp(ctxt, p); 446 p->as = AMOVW; 447 p->scond |= C_WBIT; 448 p->from.type = D_REG; 449 p->from.reg = REGLINK; 450 p->to.type = D_OREG; 451 p->to.offset = -autosize; 452 p->to.reg = REGSP; 453 p->spadj = autosize; 454 455 if(cursym->text->reg & WRAPPER) { 456 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 457 // 458 // MOVW g_panic(g), R1 459 // CMP $0, R1 460 // B.EQ end 461 // MOVW panic_argp(R1), R2 462 // ADD $(autosize+4), R13, R3 463 // CMP R2, R3 464 // B.NE end 465 // ADD $4, R13, R4 466 // MOVW R4, panic_argp(R1) 467 // end: 468 // NOP 469 // 470 // The NOP is needed to give the jumps somewhere to land. 471 // It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes. 472 473 p = appendp(ctxt, p); 474 p->as = AMOVW; 475 p->from.type = D_OREG; 476 p->from.reg = REGG; 477 p->from.offset = 4*ctxt->arch->ptrsize; // G.panic 478 p->to.type = D_REG; 479 p->to.reg = 1; 480 481 p = appendp(ctxt, p); 482 p->as = ACMP; 483 p->from.type = D_CONST; 484 p->from.offset = 0; 485 p->reg = 1; 486 487 p = appendp(ctxt, p); 488 p->as = ABEQ; 489 p->to.type = D_BRANCH; 490 p1 = p; 491 492 p = appendp(ctxt, p); 493 p->as = AMOVW; 494 p->from.type = D_OREG; 495 p->from.reg = 1; 496 p->from.offset = 0; // Panic.argp 497 p->to.type = D_REG; 498 p->to.reg = 2; 499 500 p = appendp(ctxt, p); 501 p->as = AADD; 502 p->from.type = D_CONST; 503 p->from.offset = autosize+4; 504 p->reg = 13; 505 p->to.type = D_REG; 506 p->to.reg = 3; 507 508 p = appendp(ctxt, p); 509 p->as = ACMP; 510 p->from.type = D_REG; 511 p->from.reg = 2; 512 p->reg = 3; 513 514 p = appendp(ctxt, p); 515 p->as = ABNE; 516 p->to.type = D_BRANCH; 517 p2 = p; 518 519 p = appendp(ctxt, p); 520 p->as = AADD; 521 p->from.type = D_CONST; 522 p->from.offset = 4; 523 p->reg = 13; 524 p->to.type = D_REG; 525 p->to.reg = 4; 526 527 p = appendp(ctxt, p); 528 p->as = AMOVW; 529 p->from.type = D_REG; 530 p->from.reg = 4; 531 p->to.type = D_OREG; 532 p->to.reg = 1; 533 p->to.offset = 0; // Panic.argp 534 535 p = appendp(ctxt, p); 536 p->as = ANOP; 537 p1->pcond = p; 538 p2->pcond = p; 539 } 540 break; 541 542 case ARET: 543 nocache(p); 544 if(cursym->text->mark & LEAF) { 545 if(!autosize) { 546 p->as = AB; 547 p->from = zprg.from; 548 if(p->to.sym) { // retjmp 549 p->to.type = D_BRANCH; 550 } else { 551 p->to.type = D_OREG; 552 p->to.offset = 0; 553 p->to.reg = REGLINK; 554 } 555 break; 556 } 557 } 558 559 p->as = AMOVW; 560 p->scond |= C_PBIT; 561 p->from.type = D_OREG; 562 p->from.offset = autosize; 563 p->from.reg = REGSP; 564 p->to.type = D_REG; 565 p->to.reg = REGPC; 566 // If there are instructions following 567 // this ARET, they come from a branch 568 // with the same stackframe, so no spadj. 569 570 if(p->to.sym) { // retjmp 571 p->to.reg = REGLINK; 572 q2 = appendp(ctxt, p); 573 q2->as = AB; 574 q2->to.type = D_BRANCH; 575 q2->to.sym = p->to.sym; 576 p->to.sym = nil; 577 p = q2; 578 } 579 break; 580 581 case AADD: 582 if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) 583 p->spadj = -p->from.offset; 584 break; 585 586 case ASUB: 587 if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) 588 p->spadj = p->from.offset; 589 break; 590 591 case ADIV: 592 case ADIVU: 593 case AMOD: 594 case AMODU: 595 if(ctxt->debugdivmod) 596 break; 597 if(p->from.type != D_REG) 598 break; 599 if(p->to.type != D_REG) 600 break; 601 q1 = p; 602 603 /* MOV a,4(SP) */ 604 p = appendp(ctxt, p); 605 p->as = AMOVW; 606 p->lineno = q1->lineno; 607 p->from.type = D_REG; 608 p->from.reg = q1->from.reg; 609 p->to.type = D_OREG; 610 p->to.reg = REGSP; 611 p->to.offset = 4; 612 613 /* MOV b,REGTMP */ 614 p = appendp(ctxt, p); 615 p->as = AMOVW; 616 p->lineno = q1->lineno; 617 p->from.type = D_REG; 618 p->from.reg = q1->reg; 619 if(q1->reg == NREG) 620 p->from.reg = q1->to.reg; 621 p->to.type = D_REG; 622 p->to.reg = REGTMP; 623 p->to.offset = 0; 624 625 /* CALL appropriate */ 626 p = appendp(ctxt, p); 627 p->as = ABL; 628 p->lineno = q1->lineno; 629 p->to.type = D_BRANCH; 630 switch(o) { 631 case ADIV: 632 p->to.sym = ctxt->sym_div; 633 break; 634 case ADIVU: 635 p->to.sym = ctxt->sym_divu; 636 break; 637 case AMOD: 638 p->to.sym = ctxt->sym_mod; 639 break; 640 case AMODU: 641 p->to.sym = ctxt->sym_modu; 642 break; 643 } 644 645 /* MOV REGTMP, b */ 646 p = appendp(ctxt, p); 647 p->as = AMOVW; 648 p->lineno = q1->lineno; 649 p->from.type = D_REG; 650 p->from.reg = REGTMP; 651 p->from.offset = 0; 652 p->to.type = D_REG; 653 p->to.reg = q1->to.reg; 654 655 /* ADD $8,SP */ 656 p = appendp(ctxt, p); 657 p->as = AADD; 658 p->lineno = q1->lineno; 659 p->from.type = D_CONST; 660 p->from.reg = NREG; 661 p->from.offset = 8; 662 p->reg = NREG; 663 p->to.type = D_REG; 664 p->to.reg = REGSP; 665 p->spadj = -8; 666 667 /* Keep saved LR at 0(SP) after SP change. */ 668 /* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */ 669 /* TODO: Remove SP adjustments; see issue 6699. */ 670 q1->as = AMOVW; 671 q1->from.type = D_OREG; 672 q1->from.reg = REGSP; 673 q1->from.offset = 0; 674 q1->reg = NREG; 675 q1->to.type = D_REG; 676 q1->to.reg = REGTMP; 677 678 /* SUB $8,SP */ 679 q1 = appendp(ctxt, q1); 680 q1->as = AMOVW; 681 q1->from.type = D_REG; 682 q1->from.reg = REGTMP; 683 q1->reg = NREG; 684 q1->to.type = D_OREG; 685 q1->to.reg = REGSP; 686 q1->to.offset = -8; 687 q1->scond |= C_WBIT; 688 q1->spadj = 8; 689 690 break; 691 case AMOVW: 692 if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP) 693 p->spadj = -p->to.offset; 694 if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC) 695 p->spadj = -p->from.offset; 696 if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP) 697 p->spadj = -p->from.offset; 698 break; 699 } 700 } 701 } 702 703 static void 704 softfloat(Link *ctxt, LSym *cursym) 705 { 706 Prog *p, *next; 707 LSym *symsfloat; 708 int wasfloat; 709 710 if(ctxt->goarm > 5) 711 return; 712 713 symsfloat = linklookup(ctxt, "_sfloat", 0); 714 715 wasfloat = 0; 716 for(p = cursym->text; p != nil; p = p->link) 717 if(p->pcond != nil) 718 p->pcond->mark |= LABEL; 719 for(p = cursym->text; p != nil; p = p->link) { 720 switch(p->as) { 721 case AMOVW: 722 if(p->to.type == D_FREG || p->from.type == D_FREG) 723 goto soft; 724 goto notsoft; 725 726 case AMOVWD: 727 case AMOVWF: 728 case AMOVDW: 729 case AMOVFW: 730 case AMOVFD: 731 case AMOVDF: 732 case AMOVF: 733 case AMOVD: 734 735 case ACMPF: 736 case ACMPD: 737 case AADDF: 738 case AADDD: 739 case ASUBF: 740 case ASUBD: 741 case AMULF: 742 case AMULD: 743 case ADIVF: 744 case ADIVD: 745 case ASQRTF: 746 case ASQRTD: 747 case AABSF: 748 case AABSD: 749 goto soft; 750 751 default: 752 goto notsoft; 753 } 754 755 soft: 756 if (!wasfloat || (p->mark&LABEL)) { 757 next = ctxt->arch->prg(); 758 *next = *p; 759 760 // BL _sfloat(SB) 761 *p = zprg; 762 p->link = next; 763 p->as = ABL; 764 p->to.type = D_BRANCH; 765 p->to.sym = symsfloat; 766 p->lineno = next->lineno; 767 768 p = next; 769 wasfloat = 1; 770 } 771 continue; 772 773 notsoft: 774 wasfloat = 0; 775 } 776 } 777 778 static Prog* 779 stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt) 780 { 781 // MOVW g_stackguard(g), R1 782 p = appendp(ctxt, p); 783 p->as = AMOVW; 784 p->from.type = D_OREG; 785 p->from.reg = REGG; 786 p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0 787 if(ctxt->cursym->cfunc) 788 p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1 789 p->to.type = D_REG; 790 p->to.reg = 1; 791 792 if(framesize <= StackSmall) { 793 // small stack: SP < stackguard 794 // CMP stackguard, SP 795 p = appendp(ctxt, p); 796 p->as = ACMP; 797 p->from.type = D_REG; 798 p->from.reg = 1; 799 p->reg = REGSP; 800 } else if(framesize <= StackBig) { 801 // large stack: SP-framesize < stackguard-StackSmall 802 // MOVW $-framesize(SP), R2 803 // CMP stackguard, R2 804 p = appendp(ctxt, p); 805 p->as = AMOVW; 806 p->from.type = D_CONST; 807 p->from.reg = REGSP; 808 p->from.offset = -framesize; 809 p->to.type = D_REG; 810 p->to.reg = 2; 811 812 p = appendp(ctxt, p); 813 p->as = ACMP; 814 p->from.type = D_REG; 815 p->from.reg = 1; 816 p->reg = 2; 817 } else { 818 // Such a large stack we need to protect against wraparound 819 // if SP is close to zero. 820 // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall) 821 // The +StackGuard on both sides is required to keep the left side positive: 822 // SP is allowed to be slightly below stackguard. See stack.h. 823 // CMP $StackPreempt, R1 824 // MOVW.NE $StackGuard(SP), R2 825 // SUB.NE R1, R2 826 // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3 827 // CMP.NE R3, R2 828 p = appendp(ctxt, p); 829 p->as = ACMP; 830 p->from.type = D_CONST; 831 p->from.offset = (uint32)StackPreempt; 832 p->reg = 1; 833 834 p = appendp(ctxt, p); 835 p->as = AMOVW; 836 p->from.type = D_CONST; 837 p->from.reg = REGSP; 838 p->from.offset = StackGuard; 839 p->to.type = D_REG; 840 p->to.reg = 2; 841 p->scond = C_SCOND_NE; 842 843 p = appendp(ctxt, p); 844 p->as = ASUB; 845 p->from.type = D_REG; 846 p->from.reg = 1; 847 p->to.type = D_REG; 848 p->to.reg = 2; 849 p->scond = C_SCOND_NE; 850 851 p = appendp(ctxt, p); 852 p->as = AMOVW; 853 p->from.type = D_CONST; 854 p->from.offset = framesize + (StackGuard - StackSmall); 855 p->to.type = D_REG; 856 p->to.reg = 3; 857 p->scond = C_SCOND_NE; 858 859 p = appendp(ctxt, p); 860 p->as = ACMP; 861 p->from.type = D_REG; 862 p->from.reg = 3; 863 p->reg = 2; 864 p->scond = C_SCOND_NE; 865 } 866 867 // MOVW.LS R14, R3 868 p = appendp(ctxt, p); 869 p->as = AMOVW; 870 p->scond = C_SCOND_LS; 871 p->from.type = D_REG; 872 p->from.reg = REGLINK; 873 p->to.type = D_REG; 874 p->to.reg = 3; 875 876 // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted 877 p = appendp(ctxt, p); 878 p->as = ABL; 879 p->scond = C_SCOND_LS; 880 p->to.type = D_BRANCH; 881 if(ctxt->cursym->cfunc) 882 p->to.sym = linklookup(ctxt, "runtime.morestackc", 0); 883 else 884 p->to.sym = ctxt->symmorestack[noctxt]; 885 886 // BLS start 887 p = appendp(ctxt, p); 888 p->as = ABLS; 889 p->to.type = D_BRANCH; 890 p->pcond = ctxt->cursym->text->link; 891 892 return p; 893 } 894 895 static void 896 initdiv(Link *ctxt) 897 { 898 if(ctxt->sym_div != nil) 899 return; 900 ctxt->sym_div = linklookup(ctxt, "_div", 0); 901 ctxt->sym_divu = linklookup(ctxt, "_divu", 0); 902 ctxt->sym_mod = linklookup(ctxt, "_mod", 0); 903 ctxt->sym_modu = linklookup(ctxt, "_modu", 0); 904 } 905 906 static void xfol(Link*, Prog*, Prog**); 907 908 static void 909 follow(Link *ctxt, LSym *s) 910 { 911 Prog *firstp, *lastp; 912 913 ctxt->cursym = s; 914 915 firstp = ctxt->arch->prg(); 916 lastp = firstp; 917 xfol(ctxt, s->text, &lastp); 918 lastp->link = nil; 919 s->text = firstp->link; 920 } 921 922 static int 923 relinv(int a) 924 { 925 switch(a) { 926 case ABEQ: return ABNE; 927 case ABNE: return ABEQ; 928 case ABCS: return ABCC; 929 case ABHS: return ABLO; 930 case ABCC: return ABCS; 931 case ABLO: return ABHS; 932 case ABMI: return ABPL; 933 case ABPL: return ABMI; 934 case ABVS: return ABVC; 935 case ABVC: return ABVS; 936 case ABHI: return ABLS; 937 case ABLS: return ABHI; 938 case ABGE: return ABLT; 939 case ABLT: return ABGE; 940 case ABGT: return ABLE; 941 case ABLE: return ABGT; 942 } 943 sysfatal("unknown relation: %s", anames5[a]); 944 return 0; 945 } 946 947 static void 948 xfol(Link *ctxt, Prog *p, Prog **last) 949 { 950 Prog *q, *r; 951 int a, i; 952 953 loop: 954 if(p == nil) 955 return; 956 a = p->as; 957 if(a == AB) { 958 q = p->pcond; 959 if(q != nil && q->as != ATEXT) { 960 p->mark |= FOLL; 961 p = q; 962 if(!(p->mark & FOLL)) 963 goto loop; 964 } 965 } 966 if(p->mark & FOLL) { 967 for(i=0,q=p; i<4; i++,q=q->link) { 968 if(q == *last || q == nil) 969 break; 970 a = q->as; 971 if(a == ANOP) { 972 i--; 973 continue; 974 } 975 if(a == AB || (a == ARET && q->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF) 976 goto copy; 977 if(q->pcond == nil || (q->pcond->mark&FOLL)) 978 continue; 979 if(a != ABEQ && a != ABNE) 980 continue; 981 copy: 982 for(;;) { 983 r = ctxt->arch->prg(); 984 *r = *p; 985 if(!(r->mark&FOLL)) 986 print("can't happen 1\n"); 987 r->mark |= FOLL; 988 if(p != q) { 989 p = p->link; 990 (*last)->link = r; 991 *last = r; 992 continue; 993 } 994 (*last)->link = r; 995 *last = r; 996 if(a == AB || (a == ARET && q->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF) 997 return; 998 r->as = ABNE; 999 if(a == ABNE) 1000 r->as = ABEQ; 1001 r->pcond = p->link; 1002 r->link = p->pcond; 1003 if(!(r->link->mark&FOLL)) 1004 xfol(ctxt, r->link, last); 1005 if(!(r->pcond->mark&FOLL)) 1006 print("can't happen 2\n"); 1007 return; 1008 } 1009 } 1010 a = AB; 1011 q = ctxt->arch->prg(); 1012 q->as = a; 1013 q->lineno = p->lineno; 1014 q->to.type = D_BRANCH; 1015 q->to.offset = p->pc; 1016 q->pcond = p; 1017 p = q; 1018 } 1019 p->mark |= FOLL; 1020 (*last)->link = p; 1021 *last = p; 1022 if(a == AB || (a == ARET && p->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF){ 1023 return; 1024 } 1025 if(p->pcond != nil) 1026 if(a != ABL && a != ABX && p->link != nil) { 1027 q = brchain(ctxt, p->link); 1028 if(a != ATEXT && a != ABCASE) 1029 if(q != nil && (q->mark&FOLL)) { 1030 p->as = relinv(a); 1031 p->link = p->pcond; 1032 p->pcond = q; 1033 } 1034 xfol(ctxt, p->link, last); 1035 q = brchain(ctxt, p->pcond); 1036 if(q == nil) 1037 q = p->pcond; 1038 if(q->mark&FOLL) { 1039 p->pcond = q; 1040 return; 1041 } 1042 p = q; 1043 goto loop; 1044 } 1045 p = p->link; 1046 goto loop; 1047 } 1048 1049 LinkArch linkarm = { 1050 .name = "arm", 1051 .thechar = '5', 1052 .endian = LittleEndian, 1053 1054 .addstacksplit = addstacksplit, 1055 .assemble = span5, 1056 .datasize = datasize, 1057 .follow = follow, 1058 .iscall = iscall, 1059 .isdata = isdata, 1060 .prg = prg, 1061 .progedit = progedit, 1062 .settextflag = settextflag, 1063 .symtype = symtype, 1064 .textflag = textflag, 1065 1066 .minlc = 4, 1067 .ptrsize = 4, 1068 .regsize = 4, 1069 1070 .D_ADDR = D_ADDR, 1071 .D_AUTO = D_AUTO, 1072 .D_BRANCH = D_BRANCH, 1073 .D_CONST = D_CONST, 1074 .D_EXTERN = D_EXTERN, 1075 .D_FCONST = D_FCONST, 1076 .D_NONE = D_NONE, 1077 .D_PARAM = D_PARAM, 1078 .D_SCONST = D_SCONST, 1079 .D_STATIC = D_STATIC, 1080 .D_OREG = D_OREG, 1081 1082 .ACALL = ABL, 1083 .ADATA = ADATA, 1084 .AEND = AEND, 1085 .AFUNCDATA = AFUNCDATA, 1086 .AGLOBL = AGLOBL, 1087 .AJMP = AB, 1088 .ANOP = ANOP, 1089 .APCDATA = APCDATA, 1090 .ARET = ARET, 1091 .ATEXT = ATEXT, 1092 .ATYPE = ATYPE, 1093 .AUSEFIELD = AUSEFIELD, 1094 };