void peinit(void) { int32 l; switch(thechar) { // 64-bit architectures case '6': pe64 = 1; l = sizeof(oh64); dd = oh64.DataDirectory; break; // 32-bit architectures default: l = sizeof(oh); dd = oh.DataDirectory; break; } PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN); PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN); nextsectoff = PESECTHEADR; nextfileoff = PEFILEHEADR; // some mingw libs depend on this symbol, for example, FindPESectionByName xdefine("__image_base__", SDATA, PEBASE); xdefine("_image_base__", SDATA, PEBASE); }
void dobss(void) { int i; Sym *s; int32 t; if(dynptrsize > 0) { /* dynamic pointer section between data and bss */ datsize = rnd(datsize, 8); } /* now the bss */ bsssize = 0; for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { if(!s->reachable) continue; if(s->type != SBSS) continue; t = s->value; s->size = t; if(t >= 8) bsssize = rnd(bsssize, 8); s->value = bsssize + dynptrsize + datsize; bsssize += t; } xdefine("data", SBSS, 0); xdefine("edata", SBSS, datsize); xdefine("end", SBSS, dynptrsize + bsssize + datsize); }
// assign addresses void address(void) { Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss; Sym *sym, *sub; uvlong va; va = INITTEXT; segtext.rwx = 05; segtext.vaddr = va; segtext.fileoff = HEADR; for(s=segtext.sect; s != nil; s=s->next) { s->vaddr = va; va += rnd(s->len, PtrSize); } segtext.len = va - INITTEXT; segtext.filelen = segtext.len; va = rnd(va, INITRND); segdata.rwx = 06; segdata.vaddr = va; segdata.fileoff = va - segtext.vaddr + segtext.fileoff; segdata.filelen = 0; if(HEADTYPE == Hwindows) segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); if(HEADTYPE == Hplan9x32) segdata.fileoff = segtext.fileoff + segtext.filelen; data = nil; noptr = nil; bss = nil; noptrbss = nil; for(s=segdata.sect; s != nil; s=s->next) { s->vaddr = va; va += s->len; segdata.filelen += s->len; segdata.len = va - segdata.vaddr; if(strcmp(s->name, ".data") == 0) data = s; if(strcmp(s->name, ".noptrdata") == 0) noptr = s; if(strcmp(s->name, ".bss") == 0) bss = s; if(strcmp(s->name, ".noptrbss") == 0) noptrbss = s; } segdata.filelen -= bss->len + noptrbss->len; // deduct .bss text = segtext.sect; rodata = text->next; symtab = rodata->next; pclntab = symtab->next; for(sym = datap; sym != nil; sym = sym->next) { cursym = sym; if(sym->type < SNOPTRDATA) sym->value += rodata->vaddr; else sym->value += segdata.sect->vaddr; for(sub = sym->sub; sub != nil; sub = sub->sub) sub->value += sym->value; } xdefine("text", STEXT, text->vaddr); xdefine("etext", STEXT, text->vaddr + text->len); xdefine("rodata", SRODATA, rodata->vaddr); xdefine("erodata", SRODATA, rodata->vaddr + rodata->len); xdefine("symtab", SRODATA, symtab->vaddr); xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len); xdefine("pclntab", SRODATA, pclntab->vaddr); xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len); xdefine("noptrdata", SNOPTRDATA, noptr->vaddr); xdefine("enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len); xdefine("bss", SBSS, bss->vaddr); xdefine("ebss", SBSS, bss->vaddr + bss->len); xdefine("data", SDATA, data->vaddr); xdefine("edata", SDATA, data->vaddr + data->len); xdefine("noptrbss", SNOPTRBSS, noptrbss->vaddr); xdefine("enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len); xdefine("end", SBSS, segdata.vaddr + segdata.len); }
void span(void) { Prog *p, *q; int32 v, c, idat; int m, n, again; xdefine("etext", STEXT, 0L); idat = INITDAT; for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) curtext = p; n = 0; if(p->to.type == D_BRANCH) if(p->pcond == P) p->pcond = p; if((q = p->pcond) != P) if(q->back != 2) n = 1; p->back = n; if(p->as == AADJSP) { p->to.type = D_SP; v = -p->from.offset; p->from.offset = v; p->as = AADDL; if(v < 0) { p->as = ASUBL; v = -v; p->from.offset = v; } if(v == 0) p->as = ANOP; } } n = 0; start: do{ again = 0; if(debug['v']) Bprint(&bso, "%5.2f span %d\n", cputime(), n); Bflush(&bso); if(n > 500) { // TODO(rsc): figure out why nacl takes so long to converge. print("span must be looping - %d\n", textsize); errorexit(); } c = INITTEXT; for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) { curtext = p; if(HEADTYPE == 8) c = (c+31)&~31; } if(p->to.type == D_BRANCH) if(p->back) p->pc = c; if(n == 0 || HEADTYPE == 8 || p->to.type == D_BRANCH) { if(HEADTYPE == 8) p->pc = c; asmins(p); m = andptr-and; if(p->mark != m) again = 1; p->mark = m; } if(HEADTYPE == 8) { c = p->pc + p->mark; } else { p->pc = c; c += p->mark; } } textsize = c; n++; }while(again); if(INITRND) { INITDAT = rnd(c, INITRND); if(INITDAT != idat) { idat = INITDAT; goto start; } } xdefine("etext", STEXT, c); if(debug['v']) Bprint(&bso, "etext = %lux\n", c); Bflush(&bso); for(p = textp; p != P; p = p->pcond) p->from.sym->value = p->pc; textsize = c - INITTEXT; }
void dodata(void) { int i, t; Sym *s; Prog *p, *p1; long orig, orig1, v; if(debug['v']) Bprint(&bso, "%5.2f dodata\n", cputime()); Bflush(&bso); for(p = datap; p != P; p = p->link) { s = p->from.sym; if(p->as == ADYNT || p->as == AINIT) s->value = dtype; if(s->type == SBSS) s->type = SDATA; if(s->type != SDATA) diag("initialize non-data (%d): %s\n%P", s->type, s->name, p); v = p->from.offset + p->reg; if(v > s->value) diag("initialize bounds (%ld): %s\n%P", s->value, s->name, p); } /* * pass 1 * assign 'small' variables to data segment * (rational is that data segment is more easily * addressed through offset on REGSB) */ orig = 0; for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { t = s->type; if(t != SDATA && t != SBSS) continue; v = s->value; if(v == 0) { diag("%s: no size", s->name); v = 1; } while(v & 3) v++; s->value = v; if(v > MINSIZ) continue; if(v >= 8) while(orig & 7) orig++; s->value = orig; orig += v; s->type = SDATA1; } orig1 = orig; /* * pass 2 * assign 'data' variables to data segment */ for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { t = s->type; if(t != SDATA) { if(t == SDATA1) s->type = SDATA; continue; } v = s->value; if(v >= 8) while(orig & 7) orig++; s->value = orig; orig += v; s->type = SDATA1; } while(orig & 7) orig++; datsize = orig; /* * pass 3 * everything else to bss segment */ for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { if(s->type != SBSS) continue; v = s->value; if(v >= 8) while(orig & 7) orig++; s->value = orig; orig += v; } while(orig & 7) orig++; bsssize = orig-datsize; /* * pass 4 * add literals to all large values. * at this time: * small data is allocated DATA * large data is allocated DATA1 * large bss is allocated BSS * the new literals are loaded between * small data and large data. */ orig = 0; for(p = firstp; p != P; p = p->link) { if(p->as != AMOVW) continue; if(p->from.type != D_CONST) continue; if(s = p->from.sym) { t = s->type; if(t != SDATA && t != SDATA1 && t != SBSS) continue; t = p->from.name; if(t != D_EXTERN && t != D_STATIC) continue; v = s->value + p->from.offset; if(v >= 0 && v <= 0xffff) continue; if(!strcmp(s->name, "setSB")) continue; /* size should be 19 max */ if(strlen(s->name) >= 10) /* has loader address */ sprint(literal, "$%p.%lux", s, p->from.offset); else sprint(literal, "$%s.%d.%lux", s->name, s->version, p->from.offset); } else { if(p->from.name != D_NONE) continue; if(p->from.reg != NREG) continue; v = p->from.offset; if(v >= -0x7fff-1 && v <= 0x7fff) continue; if(!(v & 0xffff)) continue; if(v) continue; /* quicker to build it than load it */ /* size should be 9 max */ sprint(literal, "$%lux", v); } s = lookup(literal, 0); if(s->type == 0) { s->type = SDATA; s->value = orig1+orig; orig += 4; p1 = prg(); p1->as = ADATA; p1->line = p->line; p1->from.type = D_OREG; p1->from.sym = s; p1->from.name = D_EXTERN; p1->reg = 4; p1->to = p->from; p1->link = datap; datap = p1; } if(s->type != SDATA) diag("literal not data: %s", s->name); p->from.type = D_OREG; p->from.sym = s; p->from.name = D_EXTERN; p->from.offset = 0; continue; } while(orig & 7) orig++; /* * pass 5 * re-adjust offsets */ for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { t = s->type; if(t == SBSS) { s->value += orig; continue; } if(t == SDATA1) { s->type = SDATA; s->value += orig; continue; } } datsize += orig; xdefine("setSB", SDATA, 0L+BIG); xdefine("bdata", SDATA, 0L); xdefine("edata", SDATA, datsize); xdefine("end", SBSS, datsize+bsssize); xdefine("etext", STEXT, 0L); }
void dodata(void) { int i, t; Sym *s; Prog *p; int32 orig, v; if(debug['v']) Bprint(&bso, "%5.2f dodata\n", cputime()); Bflush(&bso); for(p = datap; p != P; p = p->link) { s = p->from.sym; if(p->as == ADYNT || p->as == AINIT) s->value = dtype; if(s->type == SBSS) s->type = SDATA; if(s->type != SDATA) diag("initialize non-data (%d): %s\n%P", s->type, s->name, p); v = p->from.offset + p->reg; if(v > s->value) diag("initialize bounds (%ld/%ld): %s\n%P", v, s->value, s->name, p); if((s->type == SBSS || s->type == SDATA) && (p->to.type == D_CONST || p->to.type == D_OCONST) && (p->to.name == D_EXTERN || p->to.name == D_STATIC)){ s = p->to.sym; if(s != S && (s->type == STEXT || s->type == SLEAF || s->type == SCONST || s->type == SXREF)) s->fnptr = 1; } } if(debug['t']) { /* * pull out string constants */ for(p = datap; p != P; p = p->link) { s = p->from.sym; if(p->to.type == D_SCONST) s->type = SSTRING; } } /* * pass 1 * assign 'small' variables to data segment * (rational is that data segment is more easily * addressed through offset on R12) */ orig = 0; for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { t = s->type; if(t != SDATA && t != SBSS) continue; v = s->value; if(v == 0) { diag("%s: no size", s->name); v = 1; } while(v & 3) v++; s->size = v; s->value = v; if(v > MINSIZ) continue; s->value = orig; orig += v; s->type = SDATA1; } /* * pass 2 * assign large 'data' variables to data segment */ for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { t = s->type; if(t != SDATA) { if(t == SDATA1) s->type = SDATA; continue; } v = s->value; s->size = v; s->value = orig; orig += v; } while(orig & 7) orig++; datsize = orig; /* * pass 3 * everything else to bss segment */ for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { if(s->type != SBSS) continue; v = s->value; s->size = v; s->value = orig; orig += v; } while(orig & 7) orig++; bsssize = orig-datsize; xdefine("setR12", SDATA, 0L+BIG); xdefine("bdata", SDATA, 0L); xdefine("data", SBSS, 0); xdefine("edata", SDATA, datsize); xdefine("end", SBSS, datsize+bsssize); xdefine("etext", STEXT, 0L); }
// assign addresses void address(void) { Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss, *datarelro; Section *typelink; Sym *sym, *sub; uvlong va; vlong vlen; va = INITTEXT; segtext.rwx = 05; segtext.vaddr = va; segtext.fileoff = HEADR; for(s=segtext.sect; s != nil; s=s->next) { va = rnd(va, s->align); s->vaddr = va; va += s->len; } segtext.len = va - INITTEXT; segtext.filelen = segtext.len; va = rnd(va, INITRND); segdata.rwx = 06; segdata.vaddr = va; segdata.fileoff = va - segtext.vaddr + segtext.fileoff; segdata.filelen = 0; if(HEADTYPE == Hwindows) segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); if(HEADTYPE == Hplan9x64 || HEADTYPE == Hplan9x32) segdata.fileoff = segtext.fileoff + segtext.filelen; data = nil; noptr = nil; bss = nil; noptrbss = nil; datarelro = nil; for(s=segdata.sect; s != nil; s=s->next) { vlen = s->len; if(s->next) vlen = s->next->vaddr - s->vaddr; s->vaddr = va; va += vlen; segdata.len = va - segdata.vaddr; if(strcmp(s->name, ".data") == 0) data = s; if(strcmp(s->name, ".noptrdata") == 0) noptr = s; if(strcmp(s->name, ".bss") == 0) bss = s; if(strcmp(s->name, ".noptrbss") == 0) noptrbss = s; if(strcmp(s->name, ".data.rel.ro") == 0) datarelro = s; } segdata.filelen = bss->vaddr - segdata.vaddr; text = segtext.sect; rodata = text->next; typelink = rodata->next; symtab = typelink->next; pclntab = symtab->next; for(sym = datap; sym != nil; sym = sym->next) { cursym = sym; if(sym->type < SNOPTRDATA) sym->value += rodata->vaddr; else sym->value += segdata.sect->vaddr; for(sub = sym->sub; sub != nil; sub = sub->sub) sub->value += sym->value; } xdefine("text", STEXT, text->vaddr); xdefine("etext", STEXT, text->vaddr + text->len); xdefine("rodata", SRODATA, rodata->vaddr); xdefine("erodata", SRODATA, rodata->vaddr + rodata->len); xdefine("typelink", SRODATA, typelink->vaddr); xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len); if(datarelro != nil) { xdefine("datarelro", SRODATA, datarelro->vaddr); xdefine("edatarelro", SRODATA, datarelro->vaddr + datarelro->len); } sym = lookup("gcdata", 0); xdefine("egcdata", STYPE, symaddr(sym) + sym->size); lookup("egcdata", 0)->sect = sym->sect; sym = lookup("gcbss", 0); xdefine("egcbss", STYPE, symaddr(sym) + sym->size); lookup("egcbss", 0)->sect = sym->sect; xdefine("symtab", SRODATA, symtab->vaddr); xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len); xdefine("pclntab", SRODATA, pclntab->vaddr); xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len); xdefine("noptrdata", SNOPTRDATA, noptr->vaddr); xdefine("enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len); xdefine("bss", SBSS, bss->vaddr); xdefine("ebss", SBSS, bss->vaddr + bss->len); xdefine("data", SDATA, data->vaddr); xdefine("edata", SDATA, data->vaddr + data->len); xdefine("noptrbss", SNOPTRBSS, noptrbss->vaddr); xdefine("enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len); xdefine("end", SBSS, segdata.vaddr + segdata.len); }
void noops(void) { Prog *p, *p1, *q, *q1; int o, mov, aoffset, curframe, curbecome, maxbecome; /* * find leaf subroutines * become sizes * frame sizes * strip NOPs * expand RET * expand BECOME pseudo */ if(debug['v']) Bprint(&bso, "%5.2f noops\n", cputime()); Bflush(&bso); curframe = 0; curbecome = 0; maxbecome = 0; curtext = 0; q = P; for(p = firstp; p != P; p = p->link) { /* find out how much arg space is used in this TEXT */ if(p->to.type == D_OREG && p->to.reg == REGSP) if(p->to.offset > curframe) curframe = p->to.offset; switch(p->as) { /* too hard, just leave alone */ case ATEXT: if(curtext && curtext->from.sym) { curtext->from.sym->frame = curframe; curtext->from.sym->become = curbecome; if(curbecome > maxbecome) maxbecome = curbecome; } curframe = 0; curbecome = 0; q = p; p->mark |= LABEL|LEAF|SYNC; if(p->link) p->link->mark |= LABEL; curtext = p; break; case ANOR: q = p; if(p->to.type == D_REG) if(p->to.reg == REGZERO) p->mark |= LABEL|SYNC; break; case ALWAR: case ASTWCCC: case AECIWX: case AECOWX: case AEIEIO: case AICBI: case AISYNC: case ATLBIE: case ADCBF: case ADCBI: case ADCBST: case ADCBT: case ADCBTST: case ADCBZ: case ASYNC: case ATW: case AWORD: case ARFI: case ARFCI: q = p; p->mark |= LABEL|SYNC; continue; case AMOVW: q = p; switch(p->from.type) { case D_MSR: case D_SREG: case D_SPR: case D_FPSCR: case D_CREG: case D_DCR: p->mark |= LABEL|SYNC; } switch(p->to.type) { case D_MSR: case D_SREG: case D_SPR: case D_FPSCR: case D_CREG: case D_DCR: p->mark |= LABEL|SYNC; } continue; case AFABS: case AFABSCC: case AFADD: case AFADDCC: case AFCTIW: case AFCTIWCC: case AFCTIWZ: case AFCTIWZCC: case AFDIV: case AFDIVCC: case AFMADD: case AFMADDCC: case AFMOVD: case AFMOVDU: /* case AFMOVDS: */ case AFMOVS: case AFMOVSU: /* case AFMOVSD: */ case AFMSUB: case AFMSUBCC: case AFMUL: case AFMULCC: case AFNABS: case AFNABSCC: case AFNEG: case AFNEGCC: case AFNMADD: case AFNMADDCC: case AFNMSUB: case AFNMSUBCC: case AFRSP: case AFRSPCC: case AFSUB: case AFSUBCC: q = p; p->mark |= FLOAT; continue; case ABL: case ABCL: if(curtext != P) curtext->mark &= ~LEAF; case ABC: case ABEQ: case ABGE: case ABGT: case ABLE: case ABLT: case ABNE: case ABR: case ABVC: case ABVS: p->mark |= BRANCH; q = p; q1 = p->cond; if(q1 != P) { while(q1->as == ANOP) { q1 = q1->link; p->cond = q1; } if(!(q1->mark & LEAF)) q1->mark |= LABEL; } else p->mark |= LABEL; q1 = p->link; if(q1 != P) q1->mark |= LABEL; continue; case AFCMPO: case AFCMPU: q = p; p->mark |= FCMP|FLOAT; continue; case ARETURN: /* special form of RETURN is BECOME */ if(p->from.type == D_CONST) if(p->from.offset > curbecome) curbecome = p->from.offset; q = p; if(p->link != P) p->link->mark |= LABEL; continue; case ANOP: q1 = p->link; q->link = q1; /* q is non-nop */ q1->mark |= p->mark; continue; default: q = p; continue; } } if(curtext && curtext->from.sym) { curtext->from.sym->frame = curframe; curtext->from.sym->become = curbecome; if(curbecome > maxbecome) maxbecome = curbecome; } if(debug['b']) print("max become = %d\n", maxbecome); xdefine("ALEFbecome", STEXT, maxbecome); curtext = 0; for(p = firstp; p != P; p = p->link) { switch(p->as) { case ATEXT: curtext = p; break; case ABL: /* ABCL? */ if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { o = maxbecome - curtext->from.sym->frame; if(o <= 0) break; /* calling a become or calling a variable */ if(p->to.sym == S || p->to.sym->become) { curtext->to.offset += o; if(debug['b']) { curp = p; print("%D calling %D increase %d\n", &curtext->from, &p->to, o); } } } break; } } curtext = P; for(p = firstp; p != P; p = p->link) { o = p->as; switch(o) { case ATEXT: mov = AMOVW; aoffset = 0; curtext = p; autosize = p->to.offset + 4; if((p->mark & LEAF) && autosize <= 4) autosize = 0; else if(autosize & 4) autosize += 4; p->to.offset = autosize - 4; q = p; if(autosize) { /* use MOVWU to adjust R1 when saving R31, if autosize is small */ if(!(curtext->mark & LEAF) && autosize >= -BIG && autosize <= BIG) { mov = AMOVWU; aoffset = -autosize; } else { q = prg(); q->as = AADD; q->line = p->line; q->from.type = D_CONST; q->from.offset = -autosize; q->to.type = D_REG; q->to.reg = REGSP; q->link = p->link; p->link = q; } } else if(!(curtext->mark & LEAF)) { if(debug['v']) Bprint(&bso, "save suppressed in: %s\n", curtext->from.sym->name); curtext->mark |= LEAF; } if(curtext->mark & LEAF) { if(curtext->from.sym) curtext->from.sym->type = SLEAF; break; } q1 = prg(); q1->as = mov; q1->line = p->line; q1->from.type = D_REG; q1->from.reg = REGTMP; q1->to.type = D_OREG; q1->to.offset = aoffset; q1->to.reg = REGSP; q1->link = q->link; q->link = q1; q1 = prg(); q1->as = AMOVW; q1->line = p->line; q1->from.type = D_SPR; q1->from.offset = D_LR; q1->to.type = D_REG; q1->to.reg = REGTMP; q1->link = q->link; q->link = q1; break; case ARETURN: if(p->from.type == D_CONST) goto become; if(curtext->mark & LEAF) { if(!autosize) { p->as = ABR; p->from = zprg.from; p->to.type = D_SPR; p->to.offset = D_LR; p->mark |= BRANCH; break; } p->as = AADD; p->from.type = D_CONST; p->from.offset = autosize; p->to.type = D_REG; p->to.reg = REGSP; q = prg(); q->as = ABR; q->line = p->line; q->to.type = D_SPR; q->to.offset = D_LR; q->mark |= BRANCH; q->link = p->link; p->link = q; break; } p->as = AMOVW; p->from.type = D_OREG; p->from.offset = 0; p->from.reg = REGSP; p->to.type = D_REG; p->to.reg = REGTMP; q = prg(); q->as = AMOVW; q->line = p->line; q->from.type = D_REG; q->from.reg = REGTMP; q->to.type = D_SPR; q->to.offset = D_LR; q->link = p->link; p->link = q; p = q; if(autosize) { q = prg(); q->as = AADD; q->line = p->line; q->from.type = D_CONST; q->from.offset = autosize; q->to.type = D_REG; q->to.reg = REGSP; q->link = p->link; p->link = q; } q1 = prg(); q1->as = ABR; q1->line = p->line; q1->to.type = D_SPR; q1->to.offset = D_LR; q1->mark |= BRANCH; q1->link = q->link; q->link = q1; break; become: if(curtext->mark & LEAF) { q = prg(); q->line = p->line; q->as = ABR; q->from = zprg.from; q->to = p->to; q->cond = p->cond; q->link = p->link; q->mark |= BRANCH; p->link = q; p->as = AADD; p->from = zprg.from; p->from.type = D_CONST; p->from.offset = autosize; p->to = zprg.to; p->to.type = D_REG; p->to.reg = REGSP; break; } q = prg(); q->line = p->line; q->as = ABR; q->from = zprg.from; q->to = p->to; q->cond = p->cond; q->mark |= BRANCH; q->link = p->link; p->link = q; q = prg(); q->line = p->line; q->as = AADD; q->from.type = D_CONST; q->from.offset = autosize; q->to.type = D_REG; q->to.reg = REGSP; q->link = p->link; p->link = q; q = prg(); q->line = p->line; q->as = AMOVW; q->line = p->line; q->from.type = D_REG; q->from.reg = REGTMP; q->to.type = D_SPR; q->to.offset = D_LR; q->link = p->link; p->link = q; p->as = AMOVW; p->from = zprg.from; p->from.type = D_OREG; p->from.offset = 0; p->from.reg = REGSP; p->to = zprg.to; p->to.type = D_REG; p->to.reg = REGTMP; break; } } if(debug['Q'] == 0) return; curtext = P; q = P; /* p - 1 */ q1 = firstp; /* top of block */ o = 0; /* count of instructions */ for(p = firstp; p != P; p = p1) { p1 = p->link; o++; if(p->mark & NOSCHED){ if(q1 != p){ sched(q1, q); } for(; p != P; p = p->link){ if(!(p->mark & NOSCHED)) break; q = p; } p1 = p; q1 = p; o = 0; continue; } if(p->mark & (LABEL|SYNC)) { if(q1 != p) sched(q1, q); q1 = p; o = 1; } if(p->mark & (BRANCH|SYNC)) { sched(q1, p); q1 = p1; o = 0; } if(o >= NSCHED) { sched(q1, p); q1 = p1; o = 0; } q = p; } }
void dostkoff(void) { Prog *p, *q; long autoffset, deltasp; int a, f, curframe, curbecome, maxbecome; curframe = 0; curbecome = 0; maxbecome = 0; curtext = 0; for(p = firstp; p != P; p = p->link) { /* find out how much arg space is used in this TEXT */ if(p->to.type == (D_INDIR+D_SP)) if(p->to.offset > curframe) curframe = p->to.offset; switch(p->as) { case ATEXT: if(curtext && curtext->from.sym) { curtext->from.sym->frame = curframe; curtext->from.sym->become = curbecome; if(curbecome > maxbecome) maxbecome = curbecome; } curframe = 0; curbecome = 0; curtext = p; break; case ARET: /* special form of RET is BECOME */ if(p->from.type == D_CONST) if(p->from.offset > curbecome) curbecome = p->from.offset; break; } } if(curtext && curtext->from.sym) { curtext->from.sym->frame = curframe; curtext->from.sym->become = curbecome; if(curbecome > maxbecome) maxbecome = curbecome; } if(debug['b']) print("max become = %d\n", maxbecome); xdefine("ALEFbecome", STEXT, maxbecome); curtext = 0; for(p = firstp; p != P; p = p->link) { switch(p->as) { case ATEXT: curtext = p; break; case ACALL: if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { f = maxbecome - curtext->from.sym->frame; if(f <= 0) break; /* calling a become or calling a variable */ if(p->to.sym == S || p->to.sym->become) { curtext->to.offset += f; if(debug['b']) { curp = p; print("%D calling %D increase %d\n", &curtext->from, &p->to, f); } } } break; } } autoffset = 0; deltasp = 0; for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) { curtext = p; autoffset = p->to.offset; if(autoffset < 0) autoffset = 0; if(autoffset) { p = appendp(p); p->as = AADJSP; p->from.type = D_CONST; p->from.offset = autoffset; } deltasp = autoffset; } a = p->from.type; if(a == D_AUTO) p->from.offset += deltasp; if(a == D_PARAM) p->from.offset += deltasp + 4; a = p->to.type; if(a == D_AUTO) p->to.offset += deltasp; if(a == D_PARAM) p->to.offset += deltasp + 4; switch(p->as) { default: continue; case APUSHL: case APUSHFL: deltasp += 4; continue; case APUSHW: case APUSHFW: deltasp += 2; continue; case APOPL: case APOPFL: deltasp -= 4; continue; case APOPW: case APOPFW: deltasp -= 2; continue; case ARET: break; } if(autoffset != deltasp) diag("unbalanced PUSH/POP"); if(p->from.type == D_CONST) goto become; if(autoffset) { q = p; p = appendp(p); p->as = ARET; q->as = AADJSP; q->from.type = D_CONST; q->from.offset = -autoffset; } continue; become: q = p; p = appendp(p); p->as = AJMP; p->to = q->to; p->pcond = q->pcond; q->as = AADJSP; q->from = zprg.from; q->from.type = D_CONST; q->from.offset = -autoffset; q->to = zprg.to; continue; } }
void dodata(void) { int i; Sym *s; Prog *p; long t, u; if(debug['v']) Bprint(&bso, "%5.2f dodata\n", cputime()); Bflush(&bso); for(p = datap; p != P; p = p->link) { s = p->from.sym; if(p->as == ADYNT || p->as == AINIT) s->value = dtype; if(s->type == SBSS) s->type = SDATA; if(s->type != SDATA) diag("initialize non-data (%d): %s\n%P", s->type, s->name, p); t = p->from.offset + p->width; if(t > s->value) diag("initialize bounds (%ld): %s\n%P", s->value, s->name, p); } /* allocate small guys */ datsize = 0; for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { if(s->type != SDATA) if(s->type != SBSS) continue; t = s->value; if(t == 0) { diag("%s: no size", s->name); t = 1; } t = rnd(t, 4);; s->value = t; if(t > MINSIZ) continue; s->value = datsize; datsize += t; s->type = SDATA1; } /* allocate the rest of the data */ for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { if(s->type != SDATA) { if(s->type == SDATA1) s->type = SDATA; continue; } t = s->value; s->value = datsize; datsize += t; } if(debug['j']) { /* * pad data with bss that fits up to next * 8k boundary, then push data to 8k */ u = rnd(datsize, 8192); u -= datsize; for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { if(s->type != SBSS) continue; t = s->value; if(t > u) continue; u -= t; s->value = datsize; s->type = SDATA; datsize += t; } datsize += u; } /* now the bss */ bsssize = 0; for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->link) { if(s->type != SBSS) continue; t = s->value; s->value = bsssize + datsize; bsssize += t; } xdefine("bdata", SDATA, 0L); xdefine("edata", SBSS, datsize); xdefine("end", SBSS, bsssize + datsize); /* etext is defined in span.c */ }
void span(void) { Prog *p, *q; long v; vlong c, idat; int m, n, again; xdefine("etext", STEXT, 0L); idat = INITDAT; for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) curtext = p; n = 0; if(p->to.type == D_BRANCH) if(p->pcond == P) p->pcond = p; if((q = p->pcond) != P) if(q->back != 2) n = 1; p->back = n; if(p->as == AADJSP) { p->to.type = D_SP; v = -p->from.offset; p->from.offset = v; p->as = p->mode != 64? AADDL: AADDQ; if(v < 0) { p->as = p->mode != 64? ASUBL: ASUBQ; v = -v; p->from.offset = v; } if(v == 0) p->as = ANOP; } } n = 0; start: if(debug['v']) Bprint(&bso, "%5.2f span\n", cputime()); Bflush(&bso); c = INITTEXT; for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) curtext = p; if(p->to.type == D_BRANCH) if(p->back) p->pc = c; asmins(p); p->pc = c; m = andptr-and; p->mark = m; c += m; } loop: n++; if(debug['v']) Bprint(&bso, "%5.2f span %d\n", cputime(), n); Bflush(&bso); if(n > 50) { print("span must be looping\n"); errorexit(); } again = 0; c = INITTEXT; for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) curtext = p; if(p->to.type == D_BRANCH || p->back & 0100) { if(p->back) p->pc = c; asmins(p); m = andptr-and; if(m != p->mark) { p->mark = m; again++; } } p->pc = c; c += p->mark; } if(again) { textsize = c; goto loop; } if(INITRND) { INITDAT = rnd(c, INITRND); if(INITDAT != idat) { idat = INITDAT; goto start; } } xdefine("etext", STEXT, c); if(debug['v']) Bprint(&bso, "etext = %llux\n", c); Bflush(&bso); for(p = textp; p != P; p = p->pcond) p->from.sym->value = p->pc; textsize = c - INITTEXT; }
// assign addresses void address(void) { Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss; Section *typelink; LSym *sym, *sub; uvlong va; vlong vlen; va = INITTEXT; segtext.rwx = 05; segtext.vaddr = va; segtext.fileoff = HEADR; for(s=segtext.sect; s != nil; s=s->next) { va = rnd(va, s->align); s->vaddr = va; va += s->len; } segtext.len = va - INITTEXT; segtext.filelen = segtext.len; if(HEADTYPE == Hnacl) va += 32; // room for the "halt sled" if(segrodata.sect != nil) { // align to page boundary so as not to mix // rodata and executable text. va = rnd(va, INITRND); segrodata.rwx = 04; segrodata.vaddr = va; segrodata.fileoff = va - segtext.vaddr + segtext.fileoff; segrodata.filelen = 0; for(s=segrodata.sect; s != nil; s=s->next) { va = rnd(va, s->align); s->vaddr = va; va += s->len; } segrodata.len = va - segrodata.vaddr; segrodata.filelen = segrodata.len; } va = rnd(va, INITRND); segdata.rwx = 06; segdata.vaddr = va; segdata.fileoff = va - segtext.vaddr + segtext.fileoff; segdata.filelen = 0; if(HEADTYPE == Hwindows) segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); if(HEADTYPE == Hplan9) segdata.fileoff = segtext.fileoff + segtext.filelen; data = nil; noptr = nil; bss = nil; noptrbss = nil; for(s=segdata.sect; s != nil; s=s->next) { vlen = s->len; if(s->next) vlen = s->next->vaddr - s->vaddr; s->vaddr = va; va += vlen; segdata.len = va - segdata.vaddr; if(strcmp(s->name, ".data") == 0) data = s; if(strcmp(s->name, ".noptrdata") == 0) noptr = s; if(strcmp(s->name, ".bss") == 0) bss = s; if(strcmp(s->name, ".noptrbss") == 0) noptrbss = s; } segdata.filelen = bss->vaddr - segdata.vaddr; text = segtext.sect; if(segrodata.sect) rodata = segrodata.sect; else rodata = text->next; typelink = rodata->next; symtab = typelink->next; pclntab = symtab->next; for(sym = datap; sym != nil; sym = sym->next) { ctxt->cursym = sym; if(sym->sect != nil) sym->value += sym->sect->vaddr; for(sub = sym->sub; sub != nil; sub = sub->sub) sub->value += sym->value; } xdefine("runtime.text", STEXT, text->vaddr); xdefine("runtime.etext", STEXT, text->vaddr + text->len); xdefine("runtime.rodata", SRODATA, rodata->vaddr); xdefine("runtime.erodata", SRODATA, rodata->vaddr + rodata->len); xdefine("runtime.typelink", SRODATA, typelink->vaddr); xdefine("runtime.etypelink", SRODATA, typelink->vaddr + typelink->len); sym = linklookup(ctxt, "runtime.gcdata", 0); xdefine("runtime.egcdata", SRODATA, symaddr(sym) + sym->size); linklookup(ctxt, "runtime.egcdata", 0)->sect = sym->sect; sym = linklookup(ctxt, "runtime.gcbss", 0); xdefine("runtime.egcbss", SRODATA, symaddr(sym) + sym->size); linklookup(ctxt, "runtime.egcbss", 0)->sect = sym->sect; xdefine("runtime.symtab", SRODATA, symtab->vaddr); xdefine("runtime.esymtab", SRODATA, symtab->vaddr + symtab->len); xdefine("runtime.pclntab", SRODATA, pclntab->vaddr); xdefine("runtime.epclntab", SRODATA, pclntab->vaddr + pclntab->len); xdefine("runtime.noptrdata", SNOPTRDATA, noptr->vaddr); xdefine("runtime.enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len); xdefine("runtime.bss", SBSS, bss->vaddr); xdefine("runtime.ebss", SBSS, bss->vaddr + bss->len); xdefine("runtime.data", SDATA, data->vaddr); xdefine("runtime.edata", SDATA, data->vaddr + data->len); xdefine("runtime.noptrbss", SNOPTRBSS, noptrbss->vaddr); xdefine("runtime.enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len); xdefine("runtime.end", SBSS, segdata.vaddr + segdata.len); }
void dostkoff(void) { Prog *p, *q, *q1; int32 autoffset, deltasp; int a, f, curframe, curbecome, maxbecome, pcsize; uint32 moreconst1, moreconst2, i; for(i=0; i<nelem(morename); i++) { symmorestack[i] = lookup(morename[i], 0); pmorestack[i] = P; } for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) { for(i=0; i<nelem(morename); i++) { if(p->from.sym == symmorestack[i]) { pmorestack[i] = p; break; } } } } for(i=0; i<nelem(morename); i++) { if(pmorestack[i] == P) diag("morestack trampoline not defined"); } curframe = 0; curbecome = 0; maxbecome = 0; curtext = 0; for(p = firstp; p != P; p = p->link) { /* find out how much arg space is used in this TEXT */ if(p->to.type == (D_INDIR+D_SP)) if(p->to.offset > curframe) curframe = p->to.offset; switch(p->as) { case ATEXT: if(curtext && curtext->from.sym) { curtext->from.sym->frame = curframe; curtext->from.sym->become = curbecome; if(curbecome > maxbecome) maxbecome = curbecome; } curframe = 0; curbecome = 0; curtext = p; break; case ARET: /* special form of RET is BECOME */ if(p->from.type == D_CONST) if(p->from.offset > curbecome) curbecome = p->from.offset; break; } } if(curtext && curtext->from.sym) { curtext->from.sym->frame = curframe; curtext->from.sym->become = curbecome; if(curbecome > maxbecome) maxbecome = curbecome; } if(debug['b']) print("max become = %d\n", maxbecome); xdefine("ALEFbecome", STEXT, maxbecome); curtext = 0; for(p = firstp; p != P; p = p->link) { switch(p->as) { case ATEXT: curtext = p; break; case ACALL: if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { f = maxbecome - curtext->from.sym->frame; if(f <= 0) break; /* calling a become or calling a variable */ if(p->to.sym == S || p->to.sym->become) { curtext->to.offset += f; if(debug['b']) { curp = p; print("%D calling %D increase %d\n", &curtext->from, &p->to, f); } } } break; } } autoffset = 0; deltasp = 0; for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) { curtext = p; parsetextconst(p->to.offset); autoffset = textstksiz; if(autoffset < 0) autoffset = 0; q = P; q1 = P; if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) diag("nosplit func likely to overflow stack"); if(!(p->from.scale & NOSPLIT)) { if(debug['K']) { // 6l -K means check not only for stack // overflow but stack underflow. // On underflow, INT 3 (breakpoint). // Underflow itself is rare but this also // catches out-of-sync stack guard info p = appendp(p); p->as = ACMPQ; p->from.type = D_INDIR+D_R15; p->from.offset = 8; p->to.type = D_SP; p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; p->to.offset = 4; q1 = p; p = appendp(p); p->as = AINT; p->from.type = D_CONST; p->from.offset = 3; } if(autoffset < StackBig) { // do we need to call morestack? if(autoffset <= StackSmall) { // small stack p = appendp(p); p->as = ACMPQ; p->from.type = D_SP; p->to.type = D_INDIR+D_R15; if(q1) { q1->pcond = p; q1 = P; } } else { // large stack p = appendp(p); p->as = ALEAQ; p->from.type = D_INDIR+D_SP; p->from.offset = -(autoffset-StackSmall); p->to.type = D_AX; if(q1) { q1->pcond = p; q1 = P; } p = appendp(p); p->as = ACMPQ; p->from.type = D_AX; p->to.type = D_INDIR+D_R15; } // common p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; p->to.offset = 4; q = p; } /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */ moreconst1 = 0; if(autoffset+160 > 4096) moreconst1 = (autoffset+160) & ~7LL; moreconst2 = textarg; // 4 varieties varieties (const1==0 cross const2==0) // and 6 subvarieties of (const1==0 and const2!=0) p = appendp(p); if(moreconst1 == 0 && moreconst2 == 0) { p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[0]; p->to.sym = symmorestack[0]; if(q1) { q1->pcond = p; q1 = P; } } else if(moreconst1 != 0 && moreconst2 == 0) { p->as = AMOVL; p->from.type = D_CONST; p->from.offset = moreconst1; p->to.type = D_AX; if(q1) { q1->pcond = p; q1 = P; } p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[1]; p->to.sym = symmorestack[1]; } else if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { i = moreconst2/8 + 3; p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[i]; p->to.sym = symmorestack[i]; if(q1) { q1->pcond = p; q1 = P; } } else if(moreconst1 == 0 && moreconst2 != 0) { p->as = AMOVL; p->from.type = D_CONST; p->from.offset = moreconst2; p->to.type = D_AX; if(q1) { q1->pcond = p; q1 = P; } p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[2]; p->to.sym = symmorestack[2]; } else { p->as = AMOVQ; p->from.type = D_CONST; p->from.offset = (uint64)moreconst2 << 32; p->from.offset |= moreconst1; p->to.type = D_AX; if(q1) { q1->pcond = p; q1 = P; } p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[3]; p->to.sym = symmorestack[3]; } } if(q != P) q->pcond = p->link; if(autoffset) { p = appendp(p); p->as = AADJSP; p->from.type = D_CONST; p->from.offset = autoffset; if(q != P) q->pcond = p; } deltasp = autoffset; if(debug['K'] > 1 && autoffset) { // 6l -KK means double-check for stack overflow // even after calling morestack and even if the // function is marked as nosplit. p = appendp(p); p->as = AMOVQ; p->from.type = D_INDIR+D_R15; p->from.offset = 0; p->to.type = D_BX; p = appendp(p); p->as = ASUBQ; p->from.type = D_CONST; p->from.offset = StackSmall+32; p->to.type = D_BX; p = appendp(p); p->as = ACMPQ; p->from.type = D_SP; p->to.type = D_BX; p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; q1 = p; p = appendp(p); p->as = AINT; p->from.type = D_CONST; p->from.offset = 3; p = appendp(p); p->as = ANOP; q1->pcond = p; q1 = P; } } pcsize = p->mode/8; a = p->from.type; if(a == D_AUTO) p->from.offset += deltasp; if(a == D_PARAM) p->from.offset += deltasp + pcsize; a = p->to.type; if(a == D_AUTO) p->to.offset += deltasp; if(a == D_PARAM) p->to.offset += deltasp + pcsize; switch(p->as) { default: continue; case APUSHL: case APUSHFL: deltasp += 4; continue; case APUSHQ: case APUSHFQ: deltasp += 8; continue; case APUSHW: case APUSHFW: deltasp += 2; continue; case APOPL: case APOPFL: deltasp -= 4; continue; case APOPQ: case APOPFQ: deltasp -= 8; continue; case APOPW: case APOPFW: deltasp -= 2; continue; case ARET: break; } if(autoffset != deltasp) diag("unbalanced PUSH/POP"); if(p->from.type == D_CONST) goto become; if(autoffset) { p->as = AADJSP; p->from.type = D_CONST; p->from.offset = -autoffset; p = appendp(p); p->as = ARET; } continue; become: q = p; p = appendp(p); p->as = AJMP; p->to = q->to; p->pcond = q->pcond; q->as = AADJSP; q->from = zprg.from; q->from.type = D_CONST; q->from.offset = -autoffset; q->to = zprg.to; continue; } }