github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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 Sym *gmsym; 277 278 if(debug['v']) 279 Bprint(&bso, "%5.2f mkfwd\n", cputime()); 280 Bflush(&bso); 281 mkfwd(); 282 if(debug['v']) 283 Bprint(&bso, "%5.2f patch\n", cputime()); 284 Bflush(&bso); 285 286 if(flag_shared) { 287 s = lookup("init_array", 0); 288 s->type = SINITARR; 289 s->reachable = 1; 290 s->hide = 1; 291 addaddr(s, lookup(INITENTRY, 0)); 292 } 293 294 gmsym = lookup("runtime.tlsgm", 0); 295 if(linkmode != LinkExternal) 296 gmsym->reachable = 0; 297 s = lookup("exit", 0); 298 vexit = s->value; 299 for(cursym = textp; cursym != nil; cursym = cursym->next) 300 for(p = cursym->text; p != P; p = p->link) { 301 if(HEADTYPE == Hwindows) { 302 // Windows 303 // Convert 304 // op n(GS), reg 305 // to 306 // MOVL 0x28(GS), reg 307 // op n(reg), reg 308 // The purpose of this patch is to fix some accesses 309 // to extern register variables (TLS) on Windows, as 310 // a different method is used to access them. 311 if(p->from.type == D_INDIR+D_GS 312 && p->to.type >= D_AX && p->to.type <= D_DI 313 && p->from.offset <= 8) { 314 q = appendp(p); 315 q->from = p->from; 316 q->from.type = D_INDIR + p->to.type; 317 q->to = p->to; 318 q->as = p->as; 319 p->as = AMOVQ; 320 p->from.type = D_INDIR+D_GS; 321 p->from.offset = 0x28; 322 } 323 } 324 if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd 325 || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd 326 || HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) { 327 // ELF uses FS instead of GS. 328 if(p->from.type == D_INDIR+D_GS) 329 p->from.type = D_INDIR+D_FS; 330 if(p->to.type == D_INDIR+D_GS) 331 p->to.type = D_INDIR+D_FS; 332 if(p->from.index == D_GS) 333 p->from.index = D_FS; 334 if(p->to.index == D_GS) 335 p->to.index = D_FS; 336 } 337 if(!flag_shared) { 338 // Convert g() or m() accesses of the form 339 // op n(reg)(GS*1), reg 340 // to 341 // op n(GS*1), reg 342 if(p->from.index == D_FS || p->from.index == D_GS) { 343 p->from.type = D_INDIR + p->from.index; 344 p->from.index = D_NONE; 345 } 346 // Convert g() or m() accesses of the form 347 // op reg, n(reg)(GS*1) 348 // to 349 // op reg, n(GS*1) 350 if(p->to.index == D_FS || p->to.index == D_GS) { 351 p->to.type = D_INDIR + p->to.index; 352 p->to.index = D_NONE; 353 } 354 // Convert get_tls access of the form 355 // op runtime.tlsgm(SB), reg 356 // to 357 // NOP 358 if(gmsym != S && p->from.sym == gmsym) { 359 p->as = ANOP; 360 p->from.type = D_NONE; 361 p->to.type = D_NONE; 362 p->from.sym = nil; 363 p->to.sym = nil; 364 continue; 365 } 366 } else { 367 // Convert TLS reads of the form 368 // op n(GS), reg 369 // to 370 // MOVQ $runtime.tlsgm(SB), reg 371 // op n(reg)(GS*1), reg 372 if((p->from.type == D_INDIR+D_FS || p->from.type == D_INDIR + D_GS) && p->to.type >= D_AX && p->to.type <= D_DI) { 373 q = appendp(p); 374 q->to = p->to; 375 q->as = p->as; 376 q->from.type = D_INDIR+p->to.type; 377 q->from.index = p->from.type - D_INDIR; 378 q->from.scale = 1; 379 q->from.offset = p->from.offset; 380 p->as = AMOVQ; 381 p->from.type = D_EXTERN; 382 p->from.sym = gmsym; 383 p->from.offset = 0; 384 } 385 } 386 if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) { 387 s = p->to.sym; 388 if(s) { 389 if(debug['c']) 390 Bprint(&bso, "%s calls %s\n", TNAME, s->name); 391 if((s->type&SMASK) != STEXT) { 392 /* diag prints TNAME first */ 393 diag("undefined: %s", s->name); 394 s->type = STEXT; 395 s->value = vexit; 396 continue; // avoid more error messages 397 } 398 if(s->text == nil) 399 continue; 400 p->to.type = D_BRANCH; 401 p->to.offset = s->text->pc; 402 p->pcond = s->text; 403 continue; 404 } 405 } 406 if(p->to.type != D_BRANCH) 407 continue; 408 c = p->to.offset; 409 for(q = cursym->text; q != P;) { 410 if(c == q->pc) 411 break; 412 if(q->forwd != P && c >= q->forwd->pc) 413 q = q->forwd; 414 else 415 q = q->link; 416 } 417 if(q == P) { 418 diag("branch out of range in %s (%#ux)\n%P [%s]", 419 TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>"); 420 p->to.type = D_NONE; 421 } 422 p->pcond = q; 423 } 424 425 for(cursym = textp; cursym != nil; cursym = cursym->next) 426 for(p = cursym->text; p != P; p = p->link) { 427 p->mark = 0; /* initialization for follow */ 428 if(p->pcond != P) { 429 p->pcond = brloop(p->pcond); 430 if(p->pcond != P) 431 if(p->to.type == D_BRANCH) 432 p->to.offset = p->pcond->pc; 433 } 434 } 435 } 436 437 Prog* 438 brloop(Prog *p) 439 { 440 int c; 441 Prog *q; 442 443 c = 0; 444 for(q = p; q != P; q = q->pcond) { 445 if(q->as != AJMP) 446 break; 447 c++; 448 if(c >= 5000) 449 return P; 450 } 451 return q; 452 } 453 454 static char* 455 morename[] = 456 { 457 "runtime.morestack00", 458 "runtime.morestack10", 459 "runtime.morestack01", 460 "runtime.morestack11", 461 462 "runtime.morestack8", 463 "runtime.morestack16", 464 "runtime.morestack24", 465 "runtime.morestack32", 466 "runtime.morestack40", 467 "runtime.morestack48", 468 }; 469 Prog* pmorestack[nelem(morename)]; 470 Sym* symmorestack[nelem(morename)]; 471 Sym* gmsym; 472 473 static Prog* load_g_cx(Prog*); 474 static Prog* stacksplit(Prog*, int32, Prog**); 475 476 void 477 dostkoff(void) 478 { 479 Prog *p, *q, *q1; 480 int32 autoffset, deltasp; 481 int a, pcsize; 482 uint32 i; 483 484 gmsym = lookup("runtime.tlsgm", 0); 485 for(i=0; i<nelem(morename); i++) { 486 symmorestack[i] = lookup(morename[i], 0); 487 if(symmorestack[i]->type != STEXT) 488 diag("morestack trampoline not defined - %s", morename[i]); 489 pmorestack[i] = symmorestack[i]->text; 490 } 491 492 for(cursym = textp; cursym != nil; cursym = cursym->next) { 493 if(cursym->text == nil || cursym->text->link == nil) 494 continue; 495 496 p = cursym->text; 497 parsetextconst(p->to.offset); 498 autoffset = textstksiz; 499 if(autoffset < 0) 500 autoffset = 0; 501 502 if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) { 503 for(q = p; q != P; q = q->link) 504 if(q->as == ACALL) 505 goto noleaf; 506 p->from.scale |= NOSPLIT; 507 noleaf:; 508 } 509 510 if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) 511 diag("nosplit func likely to overflow stack"); 512 513 q = P; 514 if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) { 515 p = appendp(p); 516 p = load_g_cx(p); // load g into CX 517 } 518 if(!(cursym->text->from.scale & NOSPLIT)) 519 p = stacksplit(p, autoffset, &q); // emit split check 520 521 if(autoffset) { 522 p = appendp(p); 523 p->as = AADJSP; 524 p->from.type = D_CONST; 525 p->from.offset = autoffset; 526 p->spadj = autoffset; 527 } else { 528 // zero-byte stack adjustment. 529 // Insert a fake non-zero adjustment so that stkcheck can 530 // recognize the end of the stack-splitting prolog. 531 p = appendp(p); 532 p->as = ANOP; 533 p->spadj = -PtrSize; 534 p = appendp(p); 535 p->as = ANOP; 536 p->spadj = PtrSize; 537 } 538 if(q != P) 539 q->pcond = p; 540 deltasp = autoffset; 541 542 if(cursym->text->from.scale & WRAPPER) { 543 // g->panicwrap += autoffset + PtrSize; 544 p = appendp(p); 545 p->as = AADDL; 546 p->from.type = D_CONST; 547 p->from.offset = autoffset + PtrSize; 548 p->to.type = D_INDIR+D_CX; 549 p->to.offset = 2*PtrSize; 550 } 551 552 if(debug['K'] > 1 && autoffset) { 553 // 6l -KK means double-check for stack overflow 554 // even after calling morestack and even if the 555 // function is marked as nosplit. 556 p = appendp(p); 557 p->as = AMOVQ; 558 p->from.type = D_INDIR+D_CX; 559 p->from.offset = 0; 560 p->to.type = D_BX; 561 562 p = appendp(p); 563 p->as = ASUBQ; 564 p->from.type = D_CONST; 565 p->from.offset = StackSmall+32; 566 p->to.type = D_BX; 567 568 p = appendp(p); 569 p->as = ACMPQ; 570 p->from.type = D_SP; 571 p->to.type = D_BX; 572 573 p = appendp(p); 574 p->as = AJHI; 575 p->to.type = D_BRANCH; 576 q1 = p; 577 578 p = appendp(p); 579 p->as = AINT; 580 p->from.type = D_CONST; 581 p->from.offset = 3; 582 583 p = appendp(p); 584 p->as = ANOP; 585 q1->pcond = p; 586 } 587 588 if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) { 589 // 6l -Z means zero the stack frame on entry. 590 // This slows down function calls but can help avoid 591 // false positives in garbage collection. 592 p = appendp(p); 593 p->as = AMOVQ; 594 p->from.type = D_SP; 595 p->to.type = D_DI; 596 597 p = appendp(p); 598 p->as = AMOVQ; 599 p->from.type = D_CONST; 600 p->from.offset = autoffset/8; 601 p->to.type = D_CX; 602 603 p = appendp(p); 604 p->as = AMOVQ; 605 p->from.type = D_CONST; 606 p->from.offset = 0; 607 p->to.type = D_AX; 608 609 p = appendp(p); 610 p->as = AREP; 611 612 p = appendp(p); 613 p->as = ASTOSQ; 614 } 615 616 for(; p != P; p = p->link) { 617 pcsize = p->mode/8; 618 a = p->from.type; 619 if(a == D_AUTO) 620 p->from.offset += deltasp; 621 if(a == D_PARAM) 622 p->from.offset += deltasp + pcsize; 623 a = p->to.type; 624 if(a == D_AUTO) 625 p->to.offset += deltasp; 626 if(a == D_PARAM) 627 p->to.offset += deltasp + pcsize; 628 629 switch(p->as) { 630 default: 631 continue; 632 case APUSHL: 633 case APUSHFL: 634 deltasp += 4; 635 p->spadj = 4; 636 continue; 637 case APUSHQ: 638 case APUSHFQ: 639 deltasp += 8; 640 p->spadj = 8; 641 continue; 642 case APUSHW: 643 case APUSHFW: 644 deltasp += 2; 645 p->spadj = 2; 646 continue; 647 case APOPL: 648 case APOPFL: 649 deltasp -= 4; 650 p->spadj = -4; 651 continue; 652 case APOPQ: 653 case APOPFQ: 654 deltasp -= 8; 655 p->spadj = -8; 656 continue; 657 case APOPW: 658 case APOPFW: 659 deltasp -= 2; 660 p->spadj = -2; 661 continue; 662 case ARET: 663 break; 664 } 665 666 if(autoffset != deltasp) 667 diag("unbalanced PUSH/POP"); 668 669 if(cursym->text->from.scale & WRAPPER) { 670 p = load_g_cx(p); 671 p = appendp(p); 672 // g->panicwrap -= autoffset + PtrSize; 673 p->as = ASUBL; 674 p->from.type = D_CONST; 675 p->from.offset = autoffset + PtrSize; 676 p->to.type = D_INDIR+D_CX; 677 p->to.offset = 2*PtrSize; 678 p = appendp(p); 679 p->as = ARET; 680 } 681 682 if(autoffset) { 683 p->as = AADJSP; 684 p->from.type = D_CONST; 685 p->from.offset = -autoffset; 686 p->spadj = -autoffset; 687 p = appendp(p); 688 p->as = ARET; 689 // If there are instructions following 690 // this ARET, they come from a branch 691 // with the same stackframe, so undo 692 // the cleanup. 693 p->spadj = +autoffset; 694 } 695 if(p->to.sym) // retjmp 696 p->as = AJMP; 697 } 698 } 699 } 700 701 // Append code to p to load g into cx. 702 // Overwrites p with the first instruction (no first appendp). 703 // Overwriting p is unusual but it lets use this in both the 704 // prologue (caller must call appendp first) and in the epilogue. 705 // Returns last new instruction. 706 static Prog* 707 load_g_cx(Prog *p) 708 { 709 if(flag_shared) { 710 // Load TLS offset with MOVQ $runtime.tlsgm(SB), CX 711 p->as = AMOVQ; 712 p->from.type = D_EXTERN; 713 p->from.sym = gmsym; 714 p->to.type = D_CX; 715 p = appendp(p); 716 } 717 p->as = AMOVQ; 718 if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd 719 || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd 720 || HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) 721 // ELF uses FS 722 p->from.type = D_INDIR+D_FS; 723 else 724 p->from.type = D_INDIR+D_GS; 725 if(flag_shared) { 726 // Add TLS offset stored in CX 727 p->from.index = p->from.type - D_INDIR; 728 p->from.type = D_INDIR + D_CX; 729 } 730 p->from.offset = tlsoffset+0; 731 p->to.type = D_CX; 732 if(HEADTYPE == Hwindows) { 733 // movq %gs:0x28, %rcx 734 // movq (%rcx), %rcx 735 p->as = AMOVQ; 736 p->from.type = D_INDIR+D_GS; 737 p->from.offset = 0x28; 738 p->to.type = D_CX; 739 740 p = appendp(p); 741 p->as = AMOVQ; 742 p->from.type = D_INDIR+D_CX; 743 p->from.offset = 0; 744 p->to.type = D_CX; 745 } 746 return p; 747 } 748 749 // Append code to p to check for stack split. 750 // Appends to (does not overwrite) p. 751 // Assumes g is in CX. 752 // Returns last new instruction. 753 // On return, *jmpok is the instruction that should jump 754 // to the stack frame allocation if no split is needed. 755 static Prog* 756 stacksplit(Prog *p, int32 framesize, Prog **jmpok) 757 { 758 Prog *q, *q1; 759 uint32 moreconst1, moreconst2, i; 760 761 if(debug['K']) { 762 // 6l -K means check not only for stack 763 // overflow but stack underflow. 764 // On underflow, INT 3 (breakpoint). 765 // Underflow itself is rare but this also 766 // catches out-of-sync stack guard info 767 768 p = appendp(p); 769 p->as = ACMPQ; 770 p->from.type = D_INDIR+D_CX; 771 p->from.offset = 8; 772 p->to.type = D_SP; 773 774 p = appendp(p); 775 p->as = AJHI; 776 p->to.type = D_BRANCH; 777 p->to.offset = 4; 778 q1 = p; 779 780 p = appendp(p); 781 p->as = AINT; 782 p->from.type = D_CONST; 783 p->from.offset = 3; 784 785 p = appendp(p); 786 p->as = ANOP; 787 q1->pcond = p; 788 } 789 790 q = P; 791 q1 = P; 792 if(framesize <= StackSmall) { 793 // small stack: SP <= stackguard 794 // CMPQ SP, stackguard 795 p = appendp(p); 796 p->as = ACMPQ; 797 p->from.type = D_SP; 798 p->to.type = D_INDIR+D_CX; 799 } else if(framesize <= StackBig) { 800 // large stack: SP-framesize <= stackguard-StackSmall 801 // LEAQ -xxx(SP), AX 802 // CMPQ AX, stackguard 803 p = appendp(p); 804 p->as = ALEAQ; 805 p->from.type = D_INDIR+D_SP; 806 p->from.offset = -(framesize-StackSmall); 807 p->to.type = D_AX; 808 809 p = appendp(p); 810 p->as = ACMPQ; 811 p->from.type = D_AX; 812 p->to.type = D_INDIR+D_CX; 813 } else { 814 // Such a large stack we need to protect against wraparound. 815 // If SP is close to zero: 816 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 817 // The +StackGuard on both sides is required to keep the left side positive: 818 // SP is allowed to be slightly below stackguard. See stack.h. 819 // 820 // Preemption sets stackguard to StackPreempt, a very large value. 821 // That breaks the math above, so we have to check for that explicitly. 822 // MOVQ stackguard, CX 823 // CMPQ CX, $StackPreempt 824 // JEQ label-of-call-to-morestack 825 // LEAQ StackGuard(SP), AX 826 // SUBQ CX, AX 827 // CMPQ AX, $(framesize+(StackGuard-StackSmall)) 828 829 p = appendp(p); 830 p->as = AMOVQ; 831 p->from.type = D_INDIR+D_CX; 832 p->from.offset = 0; 833 p->to.type = D_SI; 834 835 p = appendp(p); 836 p->as = ACMPQ; 837 p->from.type = D_SI; 838 p->to.type = D_CONST; 839 p->to.offset = StackPreempt; 840 841 p = appendp(p); 842 p->as = AJEQ; 843 p->to.type = D_BRANCH; 844 q1 = p; 845 846 p = appendp(p); 847 p->as = ALEAQ; 848 p->from.type = D_INDIR+D_SP; 849 p->from.offset = StackGuard; 850 p->to.type = D_AX; 851 852 p = appendp(p); 853 p->as = ASUBQ; 854 p->from.type = D_SI; 855 p->to.type = D_AX; 856 857 p = appendp(p); 858 p->as = ACMPQ; 859 p->from.type = D_AX; 860 p->to.type = D_CONST; 861 p->to.offset = framesize+(StackGuard-StackSmall); 862 } 863 864 // common 865 p = appendp(p); 866 p->as = AJHI; 867 p->to.type = D_BRANCH; 868 q = p; 869 870 // If we ask for more stack, we'll get a minimum of StackMin bytes. 871 // We need a stack frame large enough to hold the top-of-stack data, 872 // the function arguments+results, our caller's PC, our frame, 873 // a word for the return PC of the next call, and then the StackLimit bytes 874 // that must be available on entry to any function called from a function 875 // that did a stack check. If StackMin is enough, don't ask for a specific 876 // amount: then we can use the custom functions and save a few 877 // instructions. 878 moreconst1 = 0; 879 if(StackTop + textarg + PtrSize + framesize + PtrSize + StackLimit >= StackMin) 880 moreconst1 = framesize; 881 moreconst2 = textarg; 882 if(moreconst2 == 1) // special marker 883 moreconst2 = 0; 884 if((moreconst2&7) != 0) 885 diag("misaligned argument size in stack split"); 886 // 4 varieties varieties (const1==0 cross const2==0) 887 // and 6 subvarieties of (const1==0 and const2!=0) 888 p = appendp(p); 889 if(moreconst1 == 0 && moreconst2 == 0) { 890 p->as = ACALL; 891 p->to.type = D_BRANCH; 892 p->pcond = pmorestack[0]; 893 p->to.sym = symmorestack[0]; 894 } else 895 if(moreconst1 != 0 && moreconst2 == 0) { 896 p->as = AMOVL; 897 p->from.type = D_CONST; 898 p->from.offset = moreconst1; 899 p->to.type = D_AX; 900 901 p = appendp(p); 902 p->as = ACALL; 903 p->to.type = D_BRANCH; 904 p->pcond = pmorestack[1]; 905 p->to.sym = symmorestack[1]; 906 } else 907 if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { 908 i = moreconst2/8 + 3; 909 p->as = ACALL; 910 p->to.type = D_BRANCH; 911 p->pcond = pmorestack[i]; 912 p->to.sym = symmorestack[i]; 913 } else 914 if(moreconst1 == 0 && moreconst2 != 0) { 915 p->as = AMOVL; 916 p->from.type = D_CONST; 917 p->from.offset = moreconst2; 918 p->to.type = D_AX; 919 920 p = appendp(p); 921 p->as = ACALL; 922 p->to.type = D_BRANCH; 923 p->pcond = pmorestack[2]; 924 p->to.sym = symmorestack[2]; 925 } else { 926 p->as = AMOVQ; 927 p->from.type = D_CONST; 928 p->from.offset = (uint64)moreconst2 << 32; 929 p->from.offset |= moreconst1; 930 p->to.type = D_AX; 931 932 p = appendp(p); 933 p->as = ACALL; 934 p->to.type = D_BRANCH; 935 p->pcond = pmorestack[3]; 936 p->to.sym = symmorestack[3]; 937 } 938 939 p = appendp(p); 940 p->as = AJMP; 941 p->to.type = D_BRANCH; 942 p->pcond = cursym->text->link; 943 944 if(q != P) 945 q->pcond = p->link; 946 if(q1 != P) 947 q1->pcond = q->link; 948 949 *jmpok = q; 950 return p; 951 } 952 953 vlong 954 atolwhex(char *s) 955 { 956 vlong n; 957 int f; 958 959 n = 0; 960 f = 0; 961 while(*s == ' ' || *s == '\t') 962 s++; 963 if(*s == '-' || *s == '+') { 964 if(*s++ == '-') 965 f = 1; 966 while(*s == ' ' || *s == '\t') 967 s++; 968 } 969 if(s[0]=='0' && s[1]){ 970 if(s[1]=='x' || s[1]=='X'){ 971 s += 2; 972 for(;;){ 973 if(*s >= '0' && *s <= '9') 974 n = n*16 + *s++ - '0'; 975 else if(*s >= 'a' && *s <= 'f') 976 n = n*16 + *s++ - 'a' + 10; 977 else if(*s >= 'A' && *s <= 'F') 978 n = n*16 + *s++ - 'A' + 10; 979 else 980 break; 981 } 982 } else 983 while(*s >= '0' && *s <= '7') 984 n = n*8 + *s++ - '0'; 985 } else 986 while(*s >= '0' && *s <= '9') 987 n = n*10 + *s++ - '0'; 988 if(f) 989 n = -n; 990 return n; 991 }