github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/6l/pass.c (about) 1 // Inferno utils/6l/pass.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.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 and data passes. 32 33 #include "l.h" 34 #include "../ld/lib.h" 35 #include "../../pkg/runtime/stack.h" 36 37 static void xfol(Prog*, Prog**); 38 39 Prog* 40 brchain(Prog *p) 41 { 42 int i; 43 44 for(i=0; i<20; i++) { 45 if(p == P || p->as != AJMP) 46 return p; 47 p = p->pcond; 48 } 49 return P; 50 } 51 52 void 53 follow(void) 54 { 55 Prog *firstp, *lastp; 56 57 if(debug['v']) 58 Bprint(&bso, "%5.2f follow\n", cputime()); 59 Bflush(&bso); 60 61 for(cursym = textp; cursym != nil; cursym = cursym->next) { 62 firstp = prg(); 63 lastp = firstp; 64 xfol(cursym->text, &lastp); 65 lastp->link = nil; 66 cursym->text = firstp->link; 67 } 68 } 69 70 static int 71 nofollow(int a) 72 { 73 switch(a) { 74 case AJMP: 75 case ARET: 76 case AIRETL: 77 case AIRETQ: 78 case AIRETW: 79 case ARETFL: 80 case ARETFQ: 81 case ARETFW: 82 case AUNDEF: 83 return 1; 84 } 85 return 0; 86 } 87 88 static int 89 pushpop(int a) 90 { 91 switch(a) { 92 case APUSHL: 93 case APUSHFL: 94 case APUSHQ: 95 case APUSHFQ: 96 case APUSHW: 97 case APUSHFW: 98 case APOPL: 99 case APOPFL: 100 case APOPQ: 101 case APOPFQ: 102 case APOPW: 103 case APOPFW: 104 return 1; 105 } 106 return 0; 107 } 108 109 static void 110 xfol(Prog *p, Prog **last) 111 { 112 Prog *q; 113 int i; 114 enum as a; 115 116 loop: 117 if(p == P) 118 return; 119 if(p->as == AJMP) 120 if((q = p->pcond) != P && q->as != ATEXT) { 121 /* mark instruction as done and continue layout at target of jump */ 122 p->mark = 1; 123 p = q; 124 if(p->mark == 0) 125 goto loop; 126 } 127 if(p->mark) { 128 /* 129 * p goes here, but already used it elsewhere. 130 * copy up to 4 instructions or else branch to other copy. 131 */ 132 for(i=0,q=p; i<4; i++,q=q->link) { 133 if(q == P) 134 break; 135 if(q == *last) 136 break; 137 a = q->as; 138 if(a == ANOP) { 139 i--; 140 continue; 141 } 142 if(nofollow(a) || pushpop(a)) 143 break; // NOTE(rsc): arm does goto copy 144 if(q->pcond == P || q->pcond->mark) 145 continue; 146 if(a == ACALL || a == ALOOP) 147 continue; 148 for(;;) { 149 if(p->as == ANOP) { 150 p = p->link; 151 continue; 152 } 153 q = copyp(p); 154 p = p->link; 155 q->mark = 1; 156 (*last)->link = q; 157 *last = q; 158 if(q->as != a || q->pcond == P || q->pcond->mark) 159 continue; 160 161 q->as = relinv(q->as); 162 p = q->pcond; 163 q->pcond = q->link; 164 q->link = p; 165 xfol(q->link, last); 166 p = q->link; 167 if(p->mark) 168 return; 169 goto loop; 170 } 171 } /* */ 172 q = prg(); 173 q->as = AJMP; 174 q->line = p->line; 175 q->to.type = D_BRANCH; 176 q->to.offset = p->pc; 177 q->pcond = p; 178 p = q; 179 } 180 181 /* emit p */ 182 p->mark = 1; 183 (*last)->link = p; 184 *last = p; 185 a = p->as; 186 187 /* continue loop with what comes after p */ 188 if(nofollow(a)) 189 return; 190 if(p->pcond != P && a != ACALL) { 191 /* 192 * some kind of conditional branch. 193 * recurse to follow one path. 194 * continue loop on the other. 195 */ 196 if((q = brchain(p->pcond)) != P) 197 p->pcond = q; 198 if((q = brchain(p->link)) != P) 199 p->link = q; 200 if(p->from.type == D_CONST) { 201 if(p->from.offset == 1) { 202 /* 203 * expect conditional jump to be taken. 204 * rewrite so that's the fall-through case. 205 */ 206 p->as = relinv(a); 207 q = p->link; 208 p->link = p->pcond; 209 p->pcond = q; 210 } 211 } else { 212 q = p->link; 213 if(q->mark) 214 if(a != ALOOP) { 215 p->as = relinv(a); 216 p->link = p->pcond; 217 p->pcond = q; 218 } 219 } 220 xfol(p->link, last); 221 if(p->pcond->mark) 222 return; 223 p = p->pcond; 224 goto loop; 225 } 226 p = p->link; 227 goto loop; 228 } 229 230 Prog* 231 byteq(int v) 232 { 233 Prog *p; 234 235 p = prg(); 236 p->as = ABYTE; 237 p->from.type = D_CONST; 238 p->from.offset = v&0xff; 239 return p; 240 } 241 242 int 243 relinv(int a) 244 { 245 246 switch(a) { 247 case AJEQ: return AJNE; 248 case AJNE: return AJEQ; 249 case AJLE: return AJGT; 250 case AJLS: return AJHI; 251 case AJLT: return AJGE; 252 case AJMI: return AJPL; 253 case AJGE: return AJLT; 254 case AJPL: return AJMI; 255 case AJGT: return AJLE; 256 case AJHI: return AJLS; 257 case AJCS: return AJCC; 258 case AJCC: return AJCS; 259 case AJPS: return AJPC; 260 case AJPC: return AJPS; 261 case AJOS: return AJOC; 262 case AJOC: return AJOS; 263 } 264 diag("unknown relation: %s in %s", anames[a], TNAME); 265 errorexit(); 266 return a; 267 } 268 269 void 270 patch(void) 271 { 272 int32 c; 273 Prog *p, *q; 274 Sym *s; 275 int32 vexit; 276 277 if(debug['v']) 278 Bprint(&bso, "%5.2f mkfwd\n", cputime()); 279 Bflush(&bso); 280 mkfwd(); 281 if(debug['v']) 282 Bprint(&bso, "%5.2f patch\n", cputime()); 283 Bflush(&bso); 284 285 s = lookup("exit", 0); 286 vexit = s->value; 287 for(cursym = textp; cursym != nil; cursym = cursym->next) 288 for(p = cursym->text; p != P; p = p->link) { 289 if(HEADTYPE == Hwindows) { 290 // Windows 291 // Convert 292 // op n(GS), reg 293 // to 294 // MOVL 0x28(GS), reg 295 // op n(reg), reg 296 // The purpose of this patch is to fix some accesses 297 // to extern register variables (TLS) on Windows, as 298 // a different method is used to access them. 299 if(p->from.type == D_INDIR+D_GS 300 && p->to.type >= D_AX && p->to.type <= D_DI 301 && p->from.offset <= 8) { 302 q = appendp(p); 303 q->from = p->from; 304 q->from.type = D_INDIR + p->to.type; 305 q->to = p->to; 306 q->as = p->as; 307 p->as = AMOVQ; 308 p->from.type = D_INDIR+D_GS; 309 p->from.offset = 0x28; 310 } 311 } 312 if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd 313 || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd 314 || HEADTYPE == Hplan9x64) { 315 // ELF uses FS instead of GS. 316 if(p->from.type == D_INDIR+D_GS) 317 p->from.type = D_INDIR+D_FS; 318 if(p->to.type == D_INDIR+D_GS) 319 p->to.type = D_INDIR+D_FS; 320 } 321 if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) { 322 s = p->to.sym; 323 if(s) { 324 if(debug['c']) 325 Bprint(&bso, "%s calls %s\n", TNAME, s->name); 326 if((s->type&SMASK) != STEXT) { 327 /* diag prints TNAME first */ 328 diag("undefined: %s", s->name); 329 s->type = STEXT; 330 s->value = vexit; 331 continue; // avoid more error messages 332 } 333 if(s->text == nil) 334 continue; 335 p->to.type = D_BRANCH; 336 p->to.offset = s->text->pc; 337 p->pcond = s->text; 338 continue; 339 } 340 } 341 if(p->to.type != D_BRANCH) 342 continue; 343 c = p->to.offset; 344 for(q = cursym->text; q != P;) { 345 if(c == q->pc) 346 break; 347 if(q->forwd != P && c >= q->forwd->pc) 348 q = q->forwd; 349 else 350 q = q->link; 351 } 352 if(q == P) { 353 diag("branch out of range in %s (%#ux)\n%P [%s]", 354 TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>"); 355 p->to.type = D_NONE; 356 } 357 p->pcond = q; 358 } 359 360 for(cursym = textp; cursym != nil; cursym = cursym->next) 361 for(p = cursym->text; p != P; p = p->link) { 362 p->mark = 0; /* initialization for follow */ 363 if(p->pcond != P) { 364 p->pcond = brloop(p->pcond); 365 if(p->pcond != P) 366 if(p->to.type == D_BRANCH) 367 p->to.offset = p->pcond->pc; 368 } 369 } 370 } 371 372 Prog* 373 brloop(Prog *p) 374 { 375 int c; 376 Prog *q; 377 378 c = 0; 379 for(q = p; q != P; q = q->pcond) { 380 if(q->as != AJMP) 381 break; 382 c++; 383 if(c >= 5000) 384 return P; 385 } 386 return q; 387 } 388 389 static char* 390 morename[] = 391 { 392 "runtime.morestack00", 393 "runtime.morestack10", 394 "runtime.morestack01", 395 "runtime.morestack11", 396 397 "runtime.morestack8", 398 "runtime.morestack16", 399 "runtime.morestack24", 400 "runtime.morestack32", 401 "runtime.morestack40", 402 "runtime.morestack48", 403 }; 404 Prog* pmorestack[nelem(morename)]; 405 Sym* symmorestack[nelem(morename)]; 406 407 void 408 dostkoff(void) 409 { 410 Prog *p, *q, *q1; 411 int32 autoffset, deltasp; 412 int a, pcsize; 413 uint32 moreconst1, moreconst2, i; 414 415 for(i=0; i<nelem(morename); i++) { 416 symmorestack[i] = lookup(morename[i], 0); 417 if(symmorestack[i]->type != STEXT) 418 diag("morestack trampoline not defined - %s", morename[i]); 419 pmorestack[i] = symmorestack[i]->text; 420 } 421 422 for(cursym = textp; cursym != nil; cursym = cursym->next) { 423 if(cursym->text == nil || cursym->text->link == nil) 424 continue; 425 426 p = cursym->text; 427 parsetextconst(p->to.offset); 428 autoffset = textstksiz; 429 if(autoffset < 0) 430 autoffset = 0; 431 432 if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) { 433 for(q = p; q != P; q = q->link) 434 if(q->as == ACALL) 435 goto noleaf; 436 p->from.scale |= NOSPLIT; 437 noleaf:; 438 } 439 440 q = P; 441 if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) 442 diag("nosplit func likely to overflow stack"); 443 444 if(!(p->from.scale & NOSPLIT)) { 445 p = appendp(p); // load g into CX 446 p->as = AMOVQ; 447 if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd 448 || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd 449 || HEADTYPE == Hplan9x64) // ELF uses FS 450 p->from.type = D_INDIR+D_FS; 451 else 452 p->from.type = D_INDIR+D_GS; 453 p->from.offset = tlsoffset+0; 454 p->to.type = D_CX; 455 if(HEADTYPE == Hwindows) { 456 // movq %gs:0x28, %rcx 457 // movq (%rcx), %rcx 458 p->as = AMOVQ; 459 p->from.type = D_INDIR+D_GS; 460 p->from.offset = 0x28; 461 p->to.type = D_CX; 462 463 464 p = appendp(p); 465 p->as = AMOVQ; 466 p->from.type = D_INDIR+D_CX; 467 p->from.offset = 0; 468 p->to.type = D_CX; 469 } 470 471 if(debug['K']) { 472 // 6l -K means check not only for stack 473 // overflow but stack underflow. 474 // On underflow, INT 3 (breakpoint). 475 // Underflow itself is rare but this also 476 // catches out-of-sync stack guard info 477 478 p = appendp(p); 479 p->as = ACMPQ; 480 p->from.type = D_INDIR+D_CX; 481 p->from.offset = 8; 482 p->to.type = D_SP; 483 484 p = appendp(p); 485 p->as = AJHI; 486 p->to.type = D_BRANCH; 487 p->to.offset = 4; 488 q1 = p; 489 490 p = appendp(p); 491 p->as = AINT; 492 p->from.type = D_CONST; 493 p->from.offset = 3; 494 495 p = appendp(p); 496 p->as = ANOP; 497 q1->pcond = p; 498 } 499 500 if(autoffset < StackBig) { // do we need to call morestack? 501 if(autoffset <= StackSmall) { 502 // small stack 503 p = appendp(p); 504 p->as = ACMPQ; 505 p->from.type = D_SP; 506 p->to.type = D_INDIR+D_CX; 507 } else { 508 // large stack 509 p = appendp(p); 510 p->as = ALEAQ; 511 p->from.type = D_INDIR+D_SP; 512 p->from.offset = -(autoffset-StackSmall); 513 p->to.type = D_AX; 514 515 p = appendp(p); 516 p->as = ACMPQ; 517 p->from.type = D_AX; 518 p->to.type = D_INDIR+D_CX; 519 } 520 521 // common 522 p = appendp(p); 523 p->as = AJHI; 524 p->to.type = D_BRANCH; 525 p->to.offset = 4; 526 q = p; 527 } 528 529 // If we ask for more stack, we'll get a minimum of StackMin bytes. 530 // We need a stack frame large enough to hold the top-of-stack data, 531 // the function arguments+results, our caller's PC, our frame, 532 // a word for the return PC of the next call, and then the StackLimit bytes 533 // that must be available on entry to any function called from a function 534 // that did a stack check. If StackMin is enough, don't ask for a specific 535 // amount: then we can use the custom functions and save a few 536 // instructions. 537 moreconst1 = 0; 538 if(StackTop + textarg + PtrSize + autoffset + PtrSize + StackLimit >= StackMin) 539 moreconst1 = autoffset; 540 moreconst2 = textarg; 541 542 // 4 varieties varieties (const1==0 cross const2==0) 543 // and 6 subvarieties of (const1==0 and const2!=0) 544 p = appendp(p); 545 if(moreconst1 == 0 && moreconst2 == 0) { 546 p->as = ACALL; 547 p->to.type = D_BRANCH; 548 p->pcond = pmorestack[0]; 549 p->to.sym = symmorestack[0]; 550 } else 551 if(moreconst1 != 0 && moreconst2 == 0) { 552 p->as = AMOVL; 553 p->from.type = D_CONST; 554 p->from.offset = moreconst1; 555 p->to.type = D_AX; 556 557 p = appendp(p); 558 p->as = ACALL; 559 p->to.type = D_BRANCH; 560 p->pcond = pmorestack[1]; 561 p->to.sym = symmorestack[1]; 562 } else 563 if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { 564 i = moreconst2/8 + 3; 565 p->as = ACALL; 566 p->to.type = D_BRANCH; 567 p->pcond = pmorestack[i]; 568 p->to.sym = symmorestack[i]; 569 } else 570 if(moreconst1 == 0 && moreconst2 != 0) { 571 p->as = AMOVL; 572 p->from.type = D_CONST; 573 p->from.offset = moreconst2; 574 p->to.type = D_AX; 575 576 p = appendp(p); 577 p->as = ACALL; 578 p->to.type = D_BRANCH; 579 p->pcond = pmorestack[2]; 580 p->to.sym = symmorestack[2]; 581 } else { 582 p->as = AMOVQ; 583 p->from.type = D_CONST; 584 p->from.offset = (uint64)moreconst2 << 32; 585 p->from.offset |= moreconst1; 586 p->to.type = D_AX; 587 588 p = appendp(p); 589 p->as = ACALL; 590 p->to.type = D_BRANCH; 591 p->pcond = pmorestack[3]; 592 p->to.sym = symmorestack[3]; 593 } 594 } 595 596 if(q != P) 597 q->pcond = p->link; 598 599 if(autoffset) { 600 p = appendp(p); 601 p->as = AADJSP; 602 p->from.type = D_CONST; 603 p->from.offset = autoffset; 604 p->spadj = autoffset; 605 if(q != P) 606 q->pcond = p; 607 } else { 608 // zero-byte stack adjustment. 609 // Insert a fake non-zero adjustment so that stkcheck can 610 // recognize the end of the stack-splitting prolog. 611 p = appendp(p); 612 p->as = ANOP; 613 p->spadj = -PtrSize; 614 p = appendp(p); 615 p->as = ANOP; 616 p->spadj = PtrSize; 617 } 618 deltasp = autoffset; 619 620 if(debug['K'] > 1 && autoffset) { 621 // 6l -KK means double-check for stack overflow 622 // even after calling morestack and even if the 623 // function is marked as nosplit. 624 p = appendp(p); 625 p->as = AMOVQ; 626 p->from.type = D_INDIR+D_CX; 627 p->from.offset = 0; 628 p->to.type = D_BX; 629 630 p = appendp(p); 631 p->as = ASUBQ; 632 p->from.type = D_CONST; 633 p->from.offset = StackSmall+32; 634 p->to.type = D_BX; 635 636 p = appendp(p); 637 p->as = ACMPQ; 638 p->from.type = D_SP; 639 p->to.type = D_BX; 640 641 p = appendp(p); 642 p->as = AJHI; 643 p->to.type = D_BRANCH; 644 q1 = p; 645 646 p = appendp(p); 647 p->as = AINT; 648 p->from.type = D_CONST; 649 p->from.offset = 3; 650 651 p = appendp(p); 652 p->as = ANOP; 653 q1->pcond = p; 654 } 655 656 if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) { 657 // 6l -Z means zero the stack frame on entry. 658 // This slows down function calls but can help avoid 659 // false positives in garbage collection. 660 p = appendp(p); 661 p->as = AMOVQ; 662 p->from.type = D_SP; 663 p->to.type = D_DI; 664 665 p = appendp(p); 666 p->as = AMOVQ; 667 p->from.type = D_CONST; 668 p->from.offset = autoffset/8; 669 p->to.type = D_CX; 670 671 p = appendp(p); 672 p->as = AMOVQ; 673 p->from.type = D_CONST; 674 p->from.offset = 0; 675 p->to.type = D_AX; 676 677 p = appendp(p); 678 p->as = AREP; 679 680 p = appendp(p); 681 p->as = ASTOSQ; 682 } 683 684 for(; p != P; p = p->link) { 685 pcsize = p->mode/8; 686 a = p->from.type; 687 if(a == D_AUTO) 688 p->from.offset += deltasp; 689 if(a == D_PARAM) 690 p->from.offset += deltasp + pcsize; 691 a = p->to.type; 692 if(a == D_AUTO) 693 p->to.offset += deltasp; 694 if(a == D_PARAM) 695 p->to.offset += deltasp + pcsize; 696 697 switch(p->as) { 698 default: 699 continue; 700 case APUSHL: 701 case APUSHFL: 702 deltasp += 4; 703 p->spadj = 4; 704 continue; 705 case APUSHQ: 706 case APUSHFQ: 707 deltasp += 8; 708 p->spadj = 8; 709 continue; 710 case APUSHW: 711 case APUSHFW: 712 deltasp += 2; 713 p->spadj = 2; 714 continue; 715 case APOPL: 716 case APOPFL: 717 deltasp -= 4; 718 p->spadj = -4; 719 continue; 720 case APOPQ: 721 case APOPFQ: 722 deltasp -= 8; 723 p->spadj = -8; 724 continue; 725 case APOPW: 726 case APOPFW: 727 deltasp -= 2; 728 p->spadj = -2; 729 continue; 730 case ARET: 731 break; 732 } 733 734 if(autoffset != deltasp) 735 diag("unbalanced PUSH/POP"); 736 737 if(autoffset) { 738 p->as = AADJSP; 739 p->from.type = D_CONST; 740 p->from.offset = -autoffset; 741 p->spadj = -autoffset; 742 p = appendp(p); 743 p->as = ARET; 744 // If there are instructions following 745 // this ARET, they come from a branch 746 // with the same stackframe, so undo 747 // the cleanup. 748 p->spadj = +autoffset; 749 } 750 } 751 } 752 } 753 754 vlong 755 atolwhex(char *s) 756 { 757 vlong n; 758 int f; 759 760 n = 0; 761 f = 0; 762 while(*s == ' ' || *s == '\t') 763 s++; 764 if(*s == '-' || *s == '+') { 765 if(*s++ == '-') 766 f = 1; 767 while(*s == ' ' || *s == '\t') 768 s++; 769 } 770 if(s[0]=='0' && s[1]){ 771 if(s[1]=='x' || s[1]=='X'){ 772 s += 2; 773 for(;;){ 774 if(*s >= '0' && *s <= '9') 775 n = n*16 + *s++ - '0'; 776 else if(*s >= 'a' && *s <= 'f') 777 n = n*16 + *s++ - 'a' + 10; 778 else if(*s >= 'A' && *s <= 'F') 779 n = n*16 + *s++ - 'A' + 10; 780 else 781 break; 782 } 783 } else 784 while(*s >= '0' && *s <= '7') 785 n = n*8 + *s++ - '0'; 786 } else 787 while(*s >= '0' && *s <= '9') 788 n = n*10 + *s++ - '0'; 789 if(f) 790 n = -n; 791 return n; 792 }