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