github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/5l/noop.c (about) 1 // Inferno utils/5l/noop.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/5l/noop.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 // Code transformations. 32 33 #include "l.h" 34 #include "../ld/lib.h" 35 #include "../../pkg/runtime/stack.h" 36 37 static Sym* sym_div; 38 static Sym* sym_divu; 39 static Sym* sym_mod; 40 static Sym* sym_modu; 41 static Sym* symmorestack; 42 static Prog* pmorestack; 43 44 static Prog* stacksplit(Prog*, int32); 45 46 static void 47 linkcase(Prog *casep) 48 { 49 Prog *p; 50 51 for(p = casep; p != P; p = p->link){ 52 if(p->as == ABCASE) { 53 for(; p != P && p->as == ABCASE; p = p->link) 54 p->pcrel = casep; 55 break; 56 } 57 } 58 } 59 60 void 61 noops(void) 62 { 63 Prog *p, *q, *q1, *q2; 64 int o; 65 Sym *tlsfallback, *gmsym; 66 67 /* 68 * find leaf subroutines 69 * strip NOPs 70 * expand RET 71 * expand BECOME pseudo 72 * fixup TLS 73 */ 74 75 if(debug['v']) 76 Bprint(&bso, "%5.2f noops\n", cputime()); 77 Bflush(&bso); 78 79 symmorestack = lookup("runtime.morestack", 0); 80 if(symmorestack->type != STEXT) { 81 diag("runtime·morestack not defined"); 82 errorexit(); 83 } 84 pmorestack = symmorestack->text; 85 pmorestack->reg |= NOSPLIT; 86 87 tlsfallback = lookup("runtime.read_tls_fallback", 0); 88 gmsym = S; 89 if(linkmode == LinkExternal) 90 gmsym = lookup("runtime.tlsgm", 0); 91 q = P; 92 for(cursym = textp; cursym != nil; cursym = cursym->next) { 93 for(p = cursym->text; p != P; p = p->link) { 94 switch(p->as) { 95 case ACASE: 96 if(flag_shared) 97 linkcase(p); 98 break; 99 100 case ATEXT: 101 p->mark |= LEAF; 102 break; 103 104 case ARET: 105 break; 106 107 case ADIV: 108 case ADIVU: 109 case AMOD: 110 case AMODU: 111 q = p; 112 if(prog_div == P) 113 initdiv(); 114 cursym->text->mark &= ~LEAF; 115 continue; 116 117 case ANOP: 118 q1 = p->link; 119 q->link = q1; /* q is non-nop */ 120 if(q1 != P) 121 q1->mark |= p->mark; 122 continue; 123 124 case ABL: 125 case ABX: 126 cursym->text->mark &= ~LEAF; 127 128 case ABCASE: 129 case AB: 130 131 case ABEQ: 132 case ABNE: 133 case ABCS: 134 case ABHS: 135 case ABCC: 136 case ABLO: 137 case ABMI: 138 case ABPL: 139 case ABVS: 140 case ABVC: 141 case ABHI: 142 case ABLS: 143 case ABGE: 144 case ABLT: 145 case ABGT: 146 case ABLE: 147 q1 = p->cond; 148 if(q1 != P) { 149 while(q1->as == ANOP) { 150 q1 = q1->link; 151 p->cond = q1; 152 } 153 } 154 break; 155 case AWORD: 156 // Rewrite TLS register fetch: MRC 15, 0, <reg>, C13, C0, 3 157 if((p->to.offset & 0xffff0fff) == 0xee1d0f70) { 158 if(HEADTYPE == Hopenbsd) { 159 p->as = ARET; 160 } else if(goarm < 7) { 161 if(tlsfallback->type != STEXT) { 162 diag("runtime·read_tls_fallback not defined"); 163 errorexit(); 164 } 165 // BL runtime.read_tls_fallback(SB) 166 p->as = ABL; 167 p->to.type = D_BRANCH; 168 p->to.sym = tlsfallback; 169 p->cond = tlsfallback->text; 170 p->to.offset = 0; 171 cursym->text->mark &= ~LEAF; 172 } 173 if(linkmode == LinkExternal) { 174 // runtime.tlsgm is relocated with R_ARM_TLS_LE32 175 // and $runtime.tlsgm will contain the TLS offset. 176 // 177 // MOV $runtime.tlsgm+tlsoffset(SB), REGTMP 178 // ADD REGTMP, <reg> 179 // 180 // In shared mode, runtime.tlsgm is relocated with 181 // R_ARM_TLS_IE32 and runtime.tlsgm(SB) will point 182 // to the GOT entry containing the TLS offset. 183 // 184 // MOV runtime.tlsgm(SB), REGTMP 185 // ADD REGTMP, <reg> 186 // SUB -tlsoffset, <reg> 187 // 188 // The SUB compensates for tlsoffset 189 // used in runtime.save_gm and runtime.load_gm. 190 q = p; 191 p = appendp(p); 192 p->as = AMOVW; 193 p->scond = 14; 194 p->reg = NREG; 195 if(flag_shared) { 196 p->from.type = D_OREG; 197 p->from.offset = 0; 198 } else { 199 p->from.type = D_CONST; 200 p->from.offset = tlsoffset; 201 } 202 p->from.sym = gmsym; 203 p->from.name = D_EXTERN; 204 p->to.type = D_REG; 205 p->to.reg = REGTMP; 206 p->to.offset = 0; 207 208 p = appendp(p); 209 p->as = AADD; 210 p->scond = 14; 211 p->reg = NREG; 212 p->from.type = D_REG; 213 p->from.reg = REGTMP; 214 p->to.type = D_REG; 215 p->to.reg = (q->to.offset & 0xf000) >> 12; 216 p->to.offset = 0; 217 218 if(flag_shared) { 219 p = appendp(p); 220 p->as = ASUB; 221 p->scond = 14; 222 p->reg = NREG; 223 p->from.type = D_CONST; 224 p->from.offset = -tlsoffset; 225 p->to.type = D_REG; 226 p->to.reg = (q->to.offset & 0xf000) >> 12; 227 p->to.offset = 0; 228 } 229 } 230 } 231 } 232 q = p; 233 } 234 } 235 236 for(cursym = textp; cursym != nil; cursym = cursym->next) { 237 for(p = cursym->text; p != P; p = p->link) { 238 o = p->as; 239 switch(o) { 240 case ATEXT: 241 autosize = p->to.offset + 4; 242 if(autosize <= 4) 243 if(cursym->text->mark & LEAF) { 244 p->to.offset = -4; 245 autosize = 0; 246 } 247 248 if(!autosize && !(cursym->text->mark & LEAF)) { 249 if(debug['v']) 250 Bprint(&bso, "save suppressed in: %s\n", 251 cursym->name); 252 Bflush(&bso); 253 cursym->text->mark |= LEAF; 254 } 255 if(cursym->text->mark & LEAF) { 256 cursym->leaf = 1; 257 if(!autosize) 258 break; 259 } 260 261 if(!(p->reg & NOSPLIT)) 262 p = stacksplit(p, autosize); // emit split check 263 264 // MOVW.W R14,$-autosize(SP) 265 p = appendp(p); 266 p->as = AMOVW; 267 p->scond |= C_WBIT; 268 p->from.type = D_REG; 269 p->from.reg = REGLINK; 270 p->to.type = D_OREG; 271 p->to.offset = -autosize; 272 p->to.reg = REGSP; 273 p->spadj = autosize; 274 275 if(cursym->text->reg & WRAPPER) { 276 // g->panicwrap += autosize; 277 // MOVW panicwrap_offset(g), R3 278 // ADD $autosize, R3 279 // MOVW R3 panicwrap_offset(g) 280 p = appendp(p); 281 p->as = AMOVW; 282 p->from.type = D_OREG; 283 p->from.reg = REGG; 284 p->from.offset = 2*PtrSize; 285 p->to.type = D_REG; 286 p->to.reg = 3; 287 288 p = appendp(p); 289 p->as = AADD; 290 p->from.type = D_CONST; 291 p->from.offset = autosize; 292 p->to.type = D_REG; 293 p->to.reg = 3; 294 295 p = appendp(p); 296 p->as = AMOVW; 297 p->from.type = D_REG; 298 p->from.reg = 3; 299 p->to.type = D_OREG; 300 p->to.reg = REGG; 301 p->to.offset = 2*PtrSize; 302 } 303 break; 304 305 case ARET: 306 nocache(p); 307 if(cursym->text->mark & LEAF) { 308 if(!autosize) { 309 p->as = AB; 310 p->from = zprg.from; 311 if(p->to.sym) { // retjmp 312 p->to.type = D_BRANCH; 313 p->cond = p->to.sym->text; 314 } else { 315 p->to.type = D_OREG; 316 p->to.offset = 0; 317 p->to.reg = REGLINK; 318 } 319 break; 320 } 321 } 322 323 if(cursym->text->reg & WRAPPER) { 324 int cond; 325 326 // Preserve original RET's cond, to allow RET.EQ 327 // in the implementation of reflect.call. 328 cond = p->scond; 329 p->scond = C_SCOND_NONE; 330 331 // g->panicwrap -= autosize; 332 // MOVW panicwrap_offset(g), R3 333 // SUB $autosize, R3 334 // MOVW R3 panicwrap_offset(g) 335 p->as = AMOVW; 336 p->from.type = D_OREG; 337 p->from.reg = REGG; 338 p->from.offset = 2*PtrSize; 339 p->to.type = D_REG; 340 p->to.reg = 3; 341 p = appendp(p); 342 343 p->as = ASUB; 344 p->from.type = D_CONST; 345 p->from.offset = autosize; 346 p->to.type = D_REG; 347 p->to.reg = 3; 348 p = appendp(p); 349 350 p->as = AMOVW; 351 p->from.type = D_REG; 352 p->from.reg = 3; 353 p->to.type = D_OREG; 354 p->to.reg = REGG; 355 p->to.offset = 2*PtrSize; 356 p = appendp(p); 357 358 p->scond = cond; 359 } 360 361 p->as = AMOVW; 362 p->scond |= C_PBIT; 363 p->from.type = D_OREG; 364 p->from.offset = autosize; 365 p->from.reg = REGSP; 366 p->to.type = D_REG; 367 p->to.reg = REGPC; 368 // If there are instructions following 369 // this ARET, they come from a branch 370 // with the same stackframe, so no spadj. 371 372 if(p->to.sym) { // retjmp 373 p->to.reg = REGLINK; 374 q2 = appendp(p); 375 q2->as = AB; 376 q2->to.type = D_BRANCH; 377 q2->to.sym = p->to.sym; 378 q2->cond = p->to.sym->text; 379 p->to.sym = nil; 380 p = q2; 381 } 382 break; 383 384 case AADD: 385 if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) 386 p->spadj = -p->from.offset; 387 break; 388 389 case ASUB: 390 if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) 391 p->spadj = p->from.offset; 392 break; 393 394 case ADIV: 395 case ADIVU: 396 case AMOD: 397 case AMODU: 398 if(debug['M']) 399 break; 400 if(p->from.type != D_REG) 401 break; 402 if(p->to.type != D_REG) 403 break; 404 q1 = p; 405 406 /* MOV a,4(SP) */ 407 p = appendp(p); 408 p->as = AMOVW; 409 p->line = q1->line; 410 p->from.type = D_REG; 411 p->from.reg = q1->from.reg; 412 p->to.type = D_OREG; 413 p->to.reg = REGSP; 414 p->to.offset = 4; 415 416 /* MOV b,REGTMP */ 417 p = appendp(p); 418 p->as = AMOVW; 419 p->line = q1->line; 420 p->from.type = D_REG; 421 p->from.reg = q1->reg; 422 if(q1->reg == NREG) 423 p->from.reg = q1->to.reg; 424 p->to.type = D_REG; 425 p->to.reg = REGTMP; 426 p->to.offset = 0; 427 428 /* CALL appropriate */ 429 p = appendp(p); 430 p->as = ABL; 431 p->line = q1->line; 432 p->to.type = D_BRANCH; 433 p->cond = p; 434 switch(o) { 435 case ADIV: 436 p->cond = prog_div; 437 p->to.sym = sym_div; 438 break; 439 case ADIVU: 440 p->cond = prog_divu; 441 p->to.sym = sym_divu; 442 break; 443 case AMOD: 444 p->cond = prog_mod; 445 p->to.sym = sym_mod; 446 break; 447 case AMODU: 448 p->cond = prog_modu; 449 p->to.sym = sym_modu; 450 break; 451 } 452 453 /* MOV REGTMP, b */ 454 p = appendp(p); 455 p->as = AMOVW; 456 p->line = q1->line; 457 p->from.type = D_REG; 458 p->from.reg = REGTMP; 459 p->from.offset = 0; 460 p->to.type = D_REG; 461 p->to.reg = q1->to.reg; 462 463 /* ADD $8,SP */ 464 p = appendp(p); 465 p->as = AADD; 466 p->line = q1->line; 467 p->from.type = D_CONST; 468 p->from.reg = NREG; 469 p->from.offset = 8; 470 p->reg = NREG; 471 p->to.type = D_REG; 472 p->to.reg = REGSP; 473 p->spadj = -8; 474 475 /* Keep saved LR at 0(SP) after SP change. */ 476 /* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */ 477 /* TODO: Remove SP adjustments; see issue 6699. */ 478 q1->as = AMOVW; 479 q1->from.type = D_OREG; 480 q1->from.reg = REGSP; 481 q1->from.offset = 0; 482 q1->reg = NREG; 483 q1->to.type = D_REG; 484 q1->to.reg = REGTMP; 485 486 /* SUB $8,SP */ 487 q1 = appendp(q1); 488 q1->as = AMOVW; 489 q1->from.type = D_REG; 490 q1->from.reg = REGTMP; 491 q1->reg = NREG; 492 q1->to.type = D_OREG; 493 q1->to.reg = REGSP; 494 q1->to.offset = -8; 495 q1->scond |= C_WBIT; 496 q1->spadj = 8; 497 498 break; 499 case AMOVW: 500 if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP) 501 p->spadj = -p->to.offset; 502 if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC) 503 p->spadj = -p->from.offset; 504 if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP) 505 p->spadj = -p->from.offset; 506 break; 507 } 508 } 509 } 510 } 511 512 static Prog* 513 stacksplit(Prog *p, int32 framesize) 514 { 515 int32 arg; 516 517 // MOVW g_stackguard(g), R1 518 p = appendp(p); 519 p->as = AMOVW; 520 p->from.type = D_OREG; 521 p->from.reg = REGG; 522 p->to.type = D_REG; 523 p->to.reg = 1; 524 525 if(framesize <= StackSmall) { 526 // small stack: SP < stackguard 527 // CMP stackguard, SP 528 p = appendp(p); 529 p->as = ACMP; 530 p->from.type = D_REG; 531 p->from.reg = 1; 532 p->reg = REGSP; 533 } else if(framesize <= StackBig) { 534 // large stack: SP-framesize < stackguard-StackSmall 535 // MOVW $-framesize(SP), R2 536 // CMP stackguard, R2 537 p = appendp(p); 538 p->as = AMOVW; 539 p->from.type = D_CONST; 540 p->from.reg = REGSP; 541 p->from.offset = -framesize; 542 p->to.type = D_REG; 543 p->to.reg = 2; 544 545 p = appendp(p); 546 p->as = ACMP; 547 p->from.type = D_REG; 548 p->from.reg = 1; 549 p->reg = 2; 550 } else { 551 // Such a large stack we need to protect against wraparound 552 // if SP is close to zero. 553 // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall) 554 // The +StackGuard on both sides is required to keep the left side positive: 555 // SP is allowed to be slightly below stackguard. See stack.h. 556 // CMP $StackPreempt, R1 557 // MOVW.NE $StackGuard(SP), R2 558 // SUB.NE R1, R2 559 // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3 560 // CMP.NE R3, R2 561 p = appendp(p); 562 p->as = ACMP; 563 p->from.type = D_CONST; 564 p->from.offset = (uint32)StackPreempt; 565 p->reg = 1; 566 567 p = appendp(p); 568 p->as = AMOVW; 569 p->from.type = D_CONST; 570 p->from.reg = REGSP; 571 p->from.offset = StackGuard; 572 p->to.type = D_REG; 573 p->to.reg = 2; 574 p->scond = C_SCOND_NE; 575 576 p = appendp(p); 577 p->as = ASUB; 578 p->from.type = D_REG; 579 p->from.reg = 1; 580 p->to.type = D_REG; 581 p->to.reg = 2; 582 p->scond = C_SCOND_NE; 583 584 p = appendp(p); 585 p->as = AMOVW; 586 p->from.type = D_CONST; 587 p->from.offset = framesize + (StackGuard - StackSmall); 588 p->to.type = D_REG; 589 p->to.reg = 3; 590 p->scond = C_SCOND_NE; 591 592 p = appendp(p); 593 p->as = ACMP; 594 p->from.type = D_REG; 595 p->from.reg = 3; 596 p->reg = 2; 597 p->scond = C_SCOND_NE; 598 } 599 600 // MOVW.LS $framesize, R1 601 p = appendp(p); 602 p->as = AMOVW; 603 p->scond = C_SCOND_LS; 604 p->from.type = D_CONST; 605 p->from.offset = framesize; 606 p->to.type = D_REG; 607 p->to.reg = 1; 608 609 // MOVW.LS $args, R2 610 p = appendp(p); 611 p->as = AMOVW; 612 p->scond = C_SCOND_LS; 613 p->from.type = D_CONST; 614 arg = cursym->text->to.offset2; 615 if(arg == 1) // special marker for known 0 616 arg = 0; 617 if(arg&3) 618 diag("misaligned argument size in stack split"); 619 p->from.offset = arg; 620 p->to.type = D_REG; 621 p->to.reg = 2; 622 623 // MOVW.LS R14, R3 624 p = appendp(p); 625 p->as = AMOVW; 626 p->scond = C_SCOND_LS; 627 p->from.type = D_REG; 628 p->from.reg = REGLINK; 629 p->to.type = D_REG; 630 p->to.reg = 3; 631 632 // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted 633 p = appendp(p); 634 p->as = ABL; 635 p->scond = C_SCOND_LS; 636 p->to.type = D_BRANCH; 637 p->to.sym = symmorestack; 638 p->cond = pmorestack; 639 640 // BLS start 641 p = appendp(p); 642 p->as = ABLS; 643 p->to.type = D_BRANCH; 644 p->cond = cursym->text->link; 645 646 return p; 647 } 648 649 static void 650 sigdiv(char *n) 651 { 652 Sym *s; 653 654 s = lookup(n, 0); 655 if(s->type == STEXT) 656 if(s->sig == 0) 657 s->sig = SIGNINTERN; 658 } 659 660 void 661 divsig(void) 662 { 663 sigdiv("_div"); 664 sigdiv("_divu"); 665 sigdiv("_mod"); 666 sigdiv("_modu"); 667 } 668 669 void 670 initdiv(void) 671 { 672 Sym *s2, *s3, *s4, *s5; 673 674 if(prog_div != P) 675 return; 676 sym_div = s2 = lookup("_div", 0); 677 sym_divu = s3 = lookup("_divu", 0); 678 sym_mod = s4 = lookup("_mod", 0); 679 sym_modu = s5 = lookup("_modu", 0); 680 prog_div = s2->text; 681 prog_divu = s3->text; 682 prog_mod = s4->text; 683 prog_modu = s5->text; 684 if(prog_div == P) { 685 diag("undefined: %s", s2->name); 686 prog_div = cursym->text; 687 } 688 if(prog_divu == P) { 689 diag("undefined: %s", s3->name); 690 prog_divu = cursym->text; 691 } 692 if(prog_mod == P) { 693 diag("undefined: %s", s4->name); 694 prog_mod = cursym->text; 695 } 696 if(prog_modu == P) { 697 diag("undefined: %s", s5->name); 698 prog_modu = cursym->text; 699 } 700 } 701 702 void 703 nocache(Prog *p) 704 { 705 p->optab = 0; 706 p->from.class = 0; 707 p->to.class = 0; 708 }