github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/src/liblink/obj8.c (about) 1 // Inferno utils/8l/pass.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/8l/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 #include <u.h> 32 #include <libc.h> 33 #include <bio.h> 34 #include <link.h> 35 #include "../cmd/8l/8.out.h" 36 #include "../runtime/stack.h" 37 38 static Prog zprg = { 39 .back = 2, 40 .as = AGOK, 41 .from = { 42 .type = D_NONE, 43 .index = D_NONE, 44 .scale = 1, 45 }, 46 .to = { 47 .type = D_NONE, 48 .index = D_NONE, 49 .scale = 1, 50 }, 51 }; 52 53 static int 54 symtype(Addr *a) 55 { 56 int t; 57 58 t = a->type; 59 if(t == D_ADDR) 60 t = a->index; 61 return t; 62 } 63 64 static int 65 isdata(Prog *p) 66 { 67 return p->as == ADATA || p->as == AGLOBL; 68 } 69 70 static int 71 iscall(Prog *p) 72 { 73 return p->as == ACALL; 74 } 75 76 static int 77 datasize(Prog *p) 78 { 79 return p->from.scale; 80 } 81 82 static int 83 textflag(Prog *p) 84 { 85 return p->from.scale; 86 } 87 88 static void 89 settextflag(Prog *p, int f) 90 { 91 p->from.scale = f; 92 } 93 94 static int 95 canuselocaltls(Link *ctxt) 96 { 97 switch(ctxt->headtype) { 98 case Hlinux: 99 case Hnacl: 100 case Hplan9: 101 case Hwindows: 102 return 0; 103 } 104 return 1; 105 } 106 107 static void 108 progedit(Link *ctxt, Prog *p) 109 { 110 char literal[64]; 111 LSym *s; 112 Prog *q; 113 114 // See obj6.c for discussion of TLS. 115 if(canuselocaltls(ctxt)) { 116 // Reduce TLS initial exec model to TLS local exec model. 117 // Sequences like 118 // MOVL TLS, BX 119 // ... off(BX)(TLS*1) ... 120 // become 121 // NOP 122 // ... off(TLS) ... 123 if(p->as == AMOVL && p->from.type == D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) { 124 p->as = ANOP; 125 p->from.type = D_NONE; 126 p->to.type = D_NONE; 127 } 128 if(p->from.index == D_TLS && D_INDIR+D_AX <= p->from.type && p->from.type <= D_INDIR+D_DI) { 129 p->from.type = D_INDIR+D_TLS; 130 p->from.scale = 0; 131 p->from.index = D_NONE; 132 } 133 if(p->to.index == D_TLS && D_INDIR+D_AX <= p->to.type && p->to.type <= D_INDIR+D_DI) { 134 p->to.type = D_INDIR+D_TLS; 135 p->to.scale = 0; 136 p->to.index = D_NONE; 137 } 138 } else { 139 // As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load. 140 // The instruction 141 // MOVL off(TLS), BX 142 // becomes the sequence 143 // MOVL TLS, BX 144 // MOVL off(BX)(TLS*1), BX 145 // This allows the C compilers to emit references to m and g using the direct off(TLS) form. 146 if(p->as == AMOVL && p->from.type == D_INDIR+D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) { 147 q = appendp(ctxt, p); 148 q->as = p->as; 149 q->from = p->from; 150 q->from.type = D_INDIR + p->to.type; 151 q->from.index = D_TLS; 152 q->from.scale = 2; // TODO: use 1 153 q->to = p->to; 154 p->from.type = D_TLS; 155 p->from.index = D_NONE; 156 p->from.offset = 0; 157 } 158 } 159 160 // TODO: Remove. 161 if(ctxt->headtype == Hplan9) { 162 if(p->from.scale == 1 && p->from.index == D_TLS) 163 p->from.scale = 2; 164 if(p->to.scale == 1 && p->to.index == D_TLS) 165 p->to.scale = 2; 166 } 167 168 // Rewrite CALL/JMP/RET to symbol as D_BRANCH. 169 switch(p->as) { 170 case ACALL: 171 case AJMP: 172 case ARET: 173 if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil) 174 p->to.type = D_BRANCH; 175 break; 176 } 177 178 // Rewrite float constants to values stored in memory. 179 switch(p->as) { 180 case AMOVSS: 181 // Convert AMOVSS $(0), Xx to AXORPS Xx, Xx 182 if(p->from.type == D_FCONST) 183 if(p->from.u.dval == 0) 184 if(p->to.type >= D_X0) 185 if(p->to.type <= D_X7) { 186 p->as = AXORPS; 187 p->from.type = p->to.type; 188 p->from.index = p->to.index; 189 break; 190 } 191 // fallthrough 192 193 case AFMOVF: 194 case AFADDF: 195 case AFSUBF: 196 case AFSUBRF: 197 case AFMULF: 198 case AFDIVF: 199 case AFDIVRF: 200 case AFCOMF: 201 case AFCOMFP: 202 case AADDSS: 203 case ASUBSS: 204 case AMULSS: 205 case ADIVSS: 206 case ACOMISS: 207 case AUCOMISS: 208 if(p->from.type == D_FCONST) { 209 int32 i32; 210 float32 f32; 211 f32 = p->from.u.dval; 212 memmove(&i32, &f32, 4); 213 sprint(literal, "$f32.%08ux", (uint32)i32); 214 s = linklookup(ctxt, literal, 0); 215 if(s->type == 0) { 216 s->type = SRODATA; 217 adduint32(ctxt, s, i32); 218 s->reachable = 0; 219 } 220 p->from.type = D_EXTERN; 221 p->from.sym = s; 222 p->from.offset = 0; 223 } 224 break; 225 226 case AMOVSD: 227 // Convert AMOVSD $(0), Xx to AXORPS Xx, Xx 228 if(p->from.type == D_FCONST) 229 if(p->from.u.dval == 0) 230 if(p->to.type >= D_X0) 231 if(p->to.type <= D_X7) { 232 p->as = AXORPS; 233 p->from.type = p->to.type; 234 p->from.index = p->to.index; 235 break; 236 } 237 // fallthrough 238 239 case AFMOVD: 240 case AFADDD: 241 case AFSUBD: 242 case AFSUBRD: 243 case AFMULD: 244 case AFDIVD: 245 case AFDIVRD: 246 case AFCOMD: 247 case AFCOMDP: 248 case AADDSD: 249 case ASUBSD: 250 case AMULSD: 251 case ADIVSD: 252 case ACOMISD: 253 case AUCOMISD: 254 if(p->from.type == D_FCONST) { 255 int64 i64; 256 memmove(&i64, &p->from.u.dval, 8); 257 sprint(literal, "$f64.%016llux", (uvlong)i64); 258 s = linklookup(ctxt, literal, 0); 259 if(s->type == 0) { 260 s->type = SRODATA; 261 adduint64(ctxt, s, i64); 262 s->reachable = 0; 263 } 264 p->from.type = D_EXTERN; 265 p->from.sym = s; 266 p->from.offset = 0; 267 } 268 break; 269 } 270 } 271 272 static Prog* 273 prg(void) 274 { 275 Prog *p; 276 277 p = emallocz(sizeof(*p)); 278 *p = zprg; 279 return p; 280 } 281 282 static Prog* load_g_cx(Link*, Prog*); 283 static Prog* stacksplit(Link*, Prog*, int32, int, Prog**); 284 285 static void 286 addstacksplit(Link *ctxt, LSym *cursym) 287 { 288 Prog *p, *q, *p1, *p2; 289 int32 autoffset, deltasp; 290 int a; 291 292 if(ctxt->symmorestack[0] == nil) { 293 ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0); 294 ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0); 295 } 296 297 if(ctxt->headtype == Hplan9 && ctxt->plan9privates == nil) 298 ctxt->plan9privates = linklookup(ctxt, "_privates", 0); 299 300 ctxt->cursym = cursym; 301 302 if(cursym->text == nil || cursym->text->link == nil) 303 return; 304 305 p = cursym->text; 306 autoffset = p->to.offset; 307 if(autoffset < 0) 308 autoffset = 0; 309 310 cursym->locals = autoffset; 311 cursym->args = p->to.offset2; 312 313 q = nil; 314 315 if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) { 316 p = appendp(ctxt, p); 317 p = load_g_cx(ctxt, p); // load g into CX 318 } 319 if(!(cursym->text->from.scale & NOSPLIT)) 320 p = stacksplit(ctxt, p, autoffset, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check 321 322 if(autoffset) { 323 p = appendp(ctxt, p); 324 p->as = AADJSP; 325 p->from.type = D_CONST; 326 p->from.offset = autoffset; 327 p->spadj = autoffset; 328 } else { 329 // zero-byte stack adjustment. 330 // Insert a fake non-zero adjustment so that stkcheck can 331 // recognize the end of the stack-splitting prolog. 332 p = appendp(ctxt, p); 333 p->as = ANOP; 334 p->spadj = -ctxt->arch->ptrsize; 335 p = appendp(ctxt, p); 336 p->as = ANOP; 337 p->spadj = ctxt->arch->ptrsize; 338 } 339 if(q != nil) 340 q->pcond = p; 341 deltasp = autoffset; 342 343 if(cursym->text->from.scale & WRAPPER) { 344 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 345 // 346 // MOVL g_panic(CX), BX 347 // TESTL BX, BX 348 // JEQ end 349 // LEAL (autoffset+4)(SP), DI 350 // CMPL panic_argp(BX), DI 351 // JNE end 352 // MOVL SP, panic_argp(BX) 353 // end: 354 // NOP 355 // 356 // The NOP is needed to give the jumps somewhere to land. 357 // It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes. 358 359 p = appendp(ctxt, p); 360 p->as = AMOVL; 361 p->from.type = D_INDIR+D_CX; 362 p->from.offset = 4*ctxt->arch->ptrsize; // G.panic 363 p->to.type = D_BX; 364 365 p = appendp(ctxt, p); 366 p->as = ATESTL; 367 p->from.type = D_BX; 368 p->to.type = D_BX; 369 370 p = appendp(ctxt, p); 371 p->as = AJEQ; 372 p->to.type = D_BRANCH; 373 p1 = p; 374 375 p = appendp(ctxt, p); 376 p->as = ALEAL; 377 p->from.type = D_INDIR+D_SP; 378 p->from.offset = autoffset+4; 379 p->to.type = D_DI; 380 381 p = appendp(ctxt, p); 382 p->as = ACMPL; 383 p->from.type = D_INDIR+D_BX; 384 p->from.offset = 0; // Panic.argp 385 p->to.type = D_DI; 386 387 p = appendp(ctxt, p); 388 p->as = AJNE; 389 p->to.type = D_BRANCH; 390 p2 = p; 391 392 p = appendp(ctxt, p); 393 p->as = AMOVL; 394 p->from.type = D_SP; 395 p->to.type = D_INDIR+D_BX; 396 p->to.offset = 0; // Panic.argp 397 398 p = appendp(ctxt, p); 399 p->as = ANOP; 400 p1->pcond = p; 401 p2->pcond = p; 402 } 403 404 if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) { 405 // 8l -Z means zero the stack frame on entry. 406 // This slows down function calls but can help avoid 407 // false positives in garbage collection. 408 p = appendp(ctxt, p); 409 p->as = AMOVL; 410 p->from.type = D_SP; 411 p->to.type = D_DI; 412 413 p = appendp(ctxt, p); 414 p->as = AMOVL; 415 p->from.type = D_CONST; 416 p->from.offset = autoffset/4; 417 p->to.type = D_CX; 418 419 p = appendp(ctxt, p); 420 p->as = AMOVL; 421 p->from.type = D_CONST; 422 p->from.offset = 0; 423 p->to.type = D_AX; 424 425 p = appendp(ctxt, p); 426 p->as = AREP; 427 428 p = appendp(ctxt, p); 429 p->as = ASTOSL; 430 } 431 432 for(; p != nil; p = p->link) { 433 a = p->from.type; 434 if(a == D_AUTO) 435 p->from.offset += deltasp; 436 if(a == D_PARAM) 437 p->from.offset += deltasp + 4; 438 a = p->to.type; 439 if(a == D_AUTO) 440 p->to.offset += deltasp; 441 if(a == D_PARAM) 442 p->to.offset += deltasp + 4; 443 444 switch(p->as) { 445 default: 446 continue; 447 case APUSHL: 448 case APUSHFL: 449 deltasp += 4; 450 p->spadj = 4; 451 continue; 452 case APUSHW: 453 case APUSHFW: 454 deltasp += 2; 455 p->spadj = 2; 456 continue; 457 case APOPL: 458 case APOPFL: 459 deltasp -= 4; 460 p->spadj = -4; 461 continue; 462 case APOPW: 463 case APOPFW: 464 deltasp -= 2; 465 p->spadj = -2; 466 continue; 467 case ARET: 468 break; 469 } 470 471 if(autoffset != deltasp) 472 ctxt->diag("unbalanced PUSH/POP"); 473 474 if(autoffset) { 475 p->as = AADJSP; 476 p->from.type = D_CONST; 477 p->from.offset = -autoffset; 478 p->spadj = -autoffset; 479 p = appendp(ctxt, p); 480 p->as = ARET; 481 // If there are instructions following 482 // this ARET, they come from a branch 483 // with the same stackframe, so undo 484 // the cleanup. 485 p->spadj = +autoffset; 486 } 487 if(p->to.sym) // retjmp 488 p->as = AJMP; 489 } 490 } 491 492 // Append code to p to load g into cx. 493 // Overwrites p with the first instruction (no first appendp). 494 // Overwriting p is unusual but it lets use this in both the 495 // prologue (caller must call appendp first) and in the epilogue. 496 // Returns last new instruction. 497 static Prog* 498 load_g_cx(Link *ctxt, Prog *p) 499 { 500 Prog *next; 501 502 p->as = AMOVL; 503 p->from.type = D_INDIR+D_TLS; 504 p->from.offset = 0; 505 p->to.type = D_CX; 506 507 next = p->link; 508 progedit(ctxt, p); 509 while(p->link != next) 510 p = p->link; 511 512 if(p->from.index == D_TLS) 513 p->from.scale = 2; 514 515 return p; 516 } 517 518 // Append code to p to check for stack split. 519 // Appends to (does not overwrite) p. 520 // Assumes g is in CX. 521 // Returns last new instruction. 522 // On return, *jmpok is the instruction that should jump 523 // to the stack frame allocation if no split is needed. 524 static Prog* 525 stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) 526 { 527 Prog *q, *q1; 528 529 if(ctxt->debugstack) { 530 // 8l -K means check not only for stack 531 // overflow but stack underflow. 532 // On underflow, INT 3 (breakpoint). 533 // Underflow itself is rare but this also 534 // catches out-of-sync stack guard info. 535 p = appendp(ctxt, p); 536 p->as = ACMPL; 537 p->from.type = D_INDIR+D_CX; 538 p->from.offset = 4; 539 p->to.type = D_SP; 540 541 p = appendp(ctxt, p); 542 p->as = AJCC; 543 p->to.type = D_BRANCH; 544 p->to.offset = 4; 545 q1 = p; 546 547 p = appendp(ctxt, p); 548 p->as = AINT; 549 p->from.type = D_CONST; 550 p->from.offset = 3; 551 552 p = appendp(ctxt, p); 553 p->as = ANOP; 554 q1->pcond = p; 555 } 556 q1 = nil; 557 558 if(framesize <= StackSmall) { 559 // small stack: SP <= stackguard 560 // CMPL SP, stackguard 561 p = appendp(ctxt, p); 562 p->as = ACMPL; 563 p->from.type = D_SP; 564 p->to.type = D_INDIR+D_CX; 565 p->to.offset = 2*ctxt->arch->ptrsize; // G.stackguard0 566 if(ctxt->cursym->cfunc) 567 p->to.offset = 3*ctxt->arch->ptrsize; // G.stackguard1 568 } else if(framesize <= StackBig) { 569 // large stack: SP-framesize <= stackguard-StackSmall 570 // LEAL -(framesize-StackSmall)(SP), AX 571 // CMPL AX, stackguard 572 p = appendp(ctxt, p); 573 p->as = ALEAL; 574 p->from.type = D_INDIR+D_SP; 575 p->from.offset = -(framesize-StackSmall); 576 p->to.type = D_AX; 577 578 p = appendp(ctxt, p); 579 p->as = ACMPL; 580 p->from.type = D_AX; 581 p->to.type = D_INDIR+D_CX; 582 p->to.offset = 2*ctxt->arch->ptrsize; // G.stackguard0 583 if(ctxt->cursym->cfunc) 584 p->to.offset = 3*ctxt->arch->ptrsize; // G.stackguard1 585 } else { 586 // Such a large stack we need to protect against wraparound 587 // if SP is close to zero. 588 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 589 // The +StackGuard on both sides is required to keep the left side positive: 590 // SP is allowed to be slightly below stackguard. See stack.h. 591 // 592 // Preemption sets stackguard to StackPreempt, a very large value. 593 // That breaks the math above, so we have to check for that explicitly. 594 // MOVL stackguard, CX 595 // CMPL CX, $StackPreempt 596 // JEQ label-of-call-to-morestack 597 // LEAL StackGuard(SP), AX 598 // SUBL stackguard, AX 599 // CMPL AX, $(framesize+(StackGuard-StackSmall)) 600 p = appendp(ctxt, p); 601 p->as = AMOVL; 602 p->from.type = D_INDIR+D_CX; 603 p->from.offset = 0; 604 p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0 605 if(ctxt->cursym->cfunc) 606 p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1 607 p->to.type = D_SI; 608 609 p = appendp(ctxt, p); 610 p->as = ACMPL; 611 p->from.type = D_SI; 612 p->to.type = D_CONST; 613 p->to.offset = (uint32)StackPreempt; 614 615 p = appendp(ctxt, p); 616 p->as = AJEQ; 617 p->to.type = D_BRANCH; 618 q1 = p; 619 620 p = appendp(ctxt, p); 621 p->as = ALEAL; 622 p->from.type = D_INDIR+D_SP; 623 p->from.offset = StackGuard; 624 p->to.type = D_AX; 625 626 p = appendp(ctxt, p); 627 p->as = ASUBL; 628 p->from.type = D_SI; 629 p->from.offset = 0; 630 p->to.type = D_AX; 631 632 p = appendp(ctxt, p); 633 p->as = ACMPL; 634 p->from.type = D_AX; 635 p->to.type = D_CONST; 636 p->to.offset = framesize+(StackGuard-StackSmall); 637 } 638 639 // common 640 p = appendp(ctxt, p); 641 p->as = AJHI; 642 p->to.type = D_BRANCH; 643 p->to.offset = 4; 644 q = p; 645 646 p = appendp(ctxt, p); 647 p->as = ACALL; 648 p->to.type = D_BRANCH; 649 if(ctxt->cursym->cfunc) 650 p->to.sym = linklookup(ctxt, "runtime.morestackc", 0); 651 else 652 p->to.sym = ctxt->symmorestack[noctxt]; 653 654 p = appendp(ctxt, p); 655 p->as = AJMP; 656 p->to.type = D_BRANCH; 657 p->pcond = ctxt->cursym->text->link; 658 659 if(q != nil) 660 q->pcond = p->link; 661 if(q1 != nil) 662 q1->pcond = q->link; 663 664 *jmpok = q; 665 return p; 666 } 667 668 static void xfol(Link*, Prog*, Prog**); 669 670 static void 671 follow(Link *ctxt, LSym *s) 672 { 673 Prog *firstp, *lastp; 674 675 ctxt->cursym = s; 676 677 firstp = ctxt->arch->prg(); 678 lastp = firstp; 679 xfol(ctxt, s->text, &lastp); 680 lastp->link = nil; 681 s->text = firstp->link; 682 } 683 684 static int 685 nofollow(int a) 686 { 687 switch(a) { 688 case AJMP: 689 case ARET: 690 case AIRETL: 691 case AIRETW: 692 case AUNDEF: 693 return 1; 694 } 695 return 0; 696 } 697 698 static int 699 pushpop(int a) 700 { 701 switch(a) { 702 case APUSHL: 703 case APUSHFL: 704 case APUSHW: 705 case APUSHFW: 706 case APOPL: 707 case APOPFL: 708 case APOPW: 709 case APOPFW: 710 return 1; 711 } 712 return 0; 713 } 714 715 static int 716 relinv(int a) 717 { 718 719 switch(a) { 720 case AJEQ: return AJNE; 721 case AJNE: return AJEQ; 722 case AJLE: return AJGT; 723 case AJLS: return AJHI; 724 case AJLT: return AJGE; 725 case AJMI: return AJPL; 726 case AJGE: return AJLT; 727 case AJPL: return AJMI; 728 case AJGT: return AJLE; 729 case AJHI: return AJLS; 730 case AJCS: return AJCC; 731 case AJCC: return AJCS; 732 case AJPS: return AJPC; 733 case AJPC: return AJPS; 734 case AJOS: return AJOC; 735 case AJOC: return AJOS; 736 } 737 sysfatal("unknown relation: %s", anames8[a]); 738 return 0; 739 } 740 741 static void 742 xfol(Link *ctxt, Prog *p, Prog **last) 743 { 744 Prog *q; 745 int i; 746 int a; 747 748 loop: 749 if(p == nil) 750 return; 751 if(p->as == AJMP) 752 if((q = p->pcond) != nil && q->as != ATEXT) { 753 /* mark instruction as done and continue layout at target of jump */ 754 p->mark = 1; 755 p = q; 756 if(p->mark == 0) 757 goto loop; 758 } 759 if(p->mark) { 760 /* 761 * p goes here, but already used it elsewhere. 762 * copy up to 4 instructions or else branch to other copy. 763 */ 764 for(i=0,q=p; i<4; i++,q=q->link) { 765 if(q == nil) 766 break; 767 if(q == *last) 768 break; 769 a = q->as; 770 if(a == ANOP) { 771 i--; 772 continue; 773 } 774 if(nofollow(a) || pushpop(a)) 775 break; // NOTE(rsc): arm does goto copy 776 if(q->pcond == nil || q->pcond->mark) 777 continue; 778 if(a == ACALL || a == ALOOP) 779 continue; 780 for(;;) { 781 if(p->as == ANOP) { 782 p = p->link; 783 continue; 784 } 785 q = copyp(ctxt, p); 786 p = p->link; 787 q->mark = 1; 788 (*last)->link = q; 789 *last = q; 790 if(q->as != a || q->pcond == nil || q->pcond->mark) 791 continue; 792 793 q->as = relinv(q->as); 794 p = q->pcond; 795 q->pcond = q->link; 796 q->link = p; 797 xfol(ctxt, q->link, last); 798 p = q->link; 799 if(p->mark) 800 return; 801 goto loop; 802 } 803 } /* */ 804 q = ctxt->arch->prg(); 805 q->as = AJMP; 806 q->lineno = p->lineno; 807 q->to.type = D_BRANCH; 808 q->to.offset = p->pc; 809 q->pcond = p; 810 p = q; 811 } 812 813 /* emit p */ 814 p->mark = 1; 815 (*last)->link = p; 816 *last = p; 817 a = p->as; 818 819 /* continue loop with what comes after p */ 820 if(nofollow(a)) 821 return; 822 if(p->pcond != nil && a != ACALL) { 823 /* 824 * some kind of conditional branch. 825 * recurse to follow one path. 826 * continue loop on the other. 827 */ 828 if((q = brchain(ctxt, p->pcond)) != nil) 829 p->pcond = q; 830 if((q = brchain(ctxt, p->link)) != nil) 831 p->link = q; 832 if(p->from.type == D_CONST) { 833 if(p->from.offset == 1) { 834 /* 835 * expect conditional jump to be taken. 836 * rewrite so that's the fall-through case. 837 */ 838 p->as = relinv(a); 839 q = p->link; 840 p->link = p->pcond; 841 p->pcond = q; 842 } 843 } else { 844 q = p->link; 845 if(q->mark) 846 if(a != ALOOP) { 847 p->as = relinv(a); 848 p->link = p->pcond; 849 p->pcond = q; 850 } 851 } 852 xfol(ctxt, p->link, last); 853 if(p->pcond->mark) 854 return; 855 p = p->pcond; 856 goto loop; 857 } 858 p = p->link; 859 goto loop; 860 } 861 862 LinkArch link386 = { 863 .name = "386", 864 .thechar = '8', 865 .endian = LittleEndian, 866 867 .addstacksplit = addstacksplit, 868 .assemble = span8, 869 .datasize = datasize, 870 .follow = follow, 871 .iscall = iscall, 872 .isdata = isdata, 873 .prg = prg, 874 .progedit = progedit, 875 .settextflag = settextflag, 876 .symtype = symtype, 877 .textflag = textflag, 878 879 .minlc = 1, 880 .ptrsize = 4, 881 .regsize = 4, 882 883 .D_ADDR = D_ADDR, 884 .D_AUTO = D_AUTO, 885 .D_BRANCH = D_BRANCH, 886 .D_CONST = D_CONST, 887 .D_EXTERN = D_EXTERN, 888 .D_FCONST = D_FCONST, 889 .D_NONE = D_NONE, 890 .D_PARAM = D_PARAM, 891 .D_SCONST = D_SCONST, 892 .D_STATIC = D_STATIC, 893 894 .ACALL = ACALL, 895 .ADATA = ADATA, 896 .AEND = AEND, 897 .AFUNCDATA = AFUNCDATA, 898 .AGLOBL = AGLOBL, 899 .AJMP = AJMP, 900 .ANOP = ANOP, 901 .APCDATA = APCDATA, 902 .ARET = ARET, 903 .ATEXT = ATEXT, 904 .ATYPE = ATYPE, 905 .AUSEFIELD = AUSEFIELD, 906 };