From: Russ Cox Date: Fri, 15 Oct 2010 03:48:40 +0000 (-0400) Subject: 5l, 6l, 8l: accumulate data image during import X-Git-Tag: weekly.2010-10-20~50 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=be2c2120d0abe8a269c1c96bd6bbaed26a190196;p=gostls13.git 5l, 6l, 8l: accumulate data image during import Using explicit relocations internally, we can represent the data for a particular symbol as an initialized block of memory instead of a linked list of ADATA instructions. The real goal here is to be able to hand off some of the relocations to the dynamic linker when interacting with system libraries, but a pleasant side effect is that the memory image is much more compact than the ADATA list, so the linkers use less memory. R=ken2 CC=golang-dev https://golang.org/cl/2512041 --- diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile index c68ef42da9..e05682c4b2 100644 --- a/src/cmd/5l/Makefile +++ b/src/cmd/5l/Makefile @@ -9,6 +9,7 @@ TARG=5l OFILES=\ asm.$O\ + data.$O\ elf.$O\ enam.$O\ lib.$O\ diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c index a033898c00..4d9264c914 100644 --- a/src/cmd/5l/asm.c +++ b/src/cmd/5l/asm.c @@ -52,125 +52,11 @@ entryvalue(void) s = lookup(a, 0); if(s->type == 0) return INITTEXT; - switch(s->type) { - case STEXT: - case SLEAF: - break; - case SDATA: - default: + if(s->type != STEXT) diag("entry not text: %s", s->name); - } return s->value; } -vlong -addstring(Sym *s, char *str) -{ - int n, m; - vlong r; - Prog *p; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->value; - n = strlen(str)+1; - while(n > 0) { - m = n; - if(m > NSNAME) - m = NSNAME; - p = newdata(s, s->value, m, D_EXTERN); - p->to.type = D_SCONST; - p->to.sval = mal(NSNAME); - memmove(p->to.sval, str, m); - s->value += m; - str += m; - n -= m; - } - return r; -} - -vlong -adduintxx(Sym *s, uint64 v, int wid) -{ - vlong r; - Prog *p; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->value; - p = newdata(s, s->value, wid, D_EXTERN); - s->value += wid; - p->to.type = D_CONST; - p->to.offset = v; - return r; -} - -vlong -adduint8(Sym *s, uint8 v) -{ - return adduintxx(s, v, 1); -} - -vlong -adduint16(Sym *s, uint16 v) -{ - return adduintxx(s, v, 2); -} - -vlong -adduint32(Sym *s, uint32 v) -{ - return adduintxx(s, v, 4); -} - -vlong -adduint64(Sym *s, uint64 v) -{ - return adduintxx(s, v, 8); -} - -vlong -addaddr(Sym *s, Sym *t) -{ - vlong r; - Prog *p; - enum { Ptrsize = 4 }; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->value; - p = newdata(s, s->value, Ptrsize, D_EXTERN); - s->value += Ptrsize; - p->to.type = D_ADDR; - p->to.index = D_EXTERN; - p->to.offset = 0; - p->to.sym = t; - return r; -} - -vlong -addsize(Sym *s, Sym *t) -{ - vlong r; - Prog *p; - enum { Ptrsize = 4 }; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->value; - p = newdata(s, s->value, Ptrsize, D_EXTERN); - s->value += Ptrsize; - p->to.type = D_SIZE; - p->to.index = D_EXTERN; - p->to.offset = 0; - p->to.sym = t; - return r; -} - enum { ElfStrEmpty, ElfStrInterp, @@ -220,10 +106,13 @@ doelf(void) /* predefine strings we need for section headers */ shstrtab = lookup(".shstrtab", 0); + shstrtab->type = SELFDATA; shstrtab->reachable = 1; + elfstr[ElfStrEmpty] = addstring(shstrtab, ""); elfstr[ElfStrText] = addstring(shstrtab, ".text"); elfstr[ElfStrData] = addstring(shstrtab, ".data"); + addstring(shstrtab, ".rodata"); elfstr[ElfStrBss] = addstring(shstrtab, ".bss"); if(!debug['s']) { elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts"); @@ -372,16 +261,18 @@ doelf(void) vlong datoff(vlong addr) { - if(addr >= INITDAT) - return addr - INITDAT + rnd(HEADR+textsize, INITRND); - diag("datoff %#llx", addr); + if(addr >= segdata.vaddr) + return addr - segdata.vaddr + segdata.fileoff; + if(addr >= segtext.vaddr) + return addr - segtext.vaddr + segtext.fileoff; + diag("datoff %#x", addr); return 0; } void shsym(Elf64_Shdr *sh, Sym *s) { - sh->addr = s->value + INITDAT; + sh->addr = symaddr(s); sh->off = datoff(sh->addr); sh->size = s->size; } @@ -401,7 +292,7 @@ void asmb(void) { Prog *p; - int32 t, etext; + int32 t; int a, dynsym; uint32 va, fo, w, symo, startva; uint32 symdatva = SYMDATVA; @@ -410,6 +301,7 @@ asmb(void) ElfEhdr *eh; ElfPhdr *ph, *pph; ElfShdr *sh; + Section *sect; strtabsize = 0; symo = 0; @@ -441,26 +333,16 @@ asmb(void) pc += o->size; } } - while(pc-INITTEXT < textsize) { - cput(0); - pc++; - } - - if(debug['a']) - Bprint(&bso, "\n"); - Bflush(&bso); cflush(); + if(seek(cout, 0, 1) != pc - segtext.vaddr + segtext.fileoff) + diag("text phase error"); - /* output strings in text segment */ - etext = INITTEXT + textsize; - for(t = pc; t < etext; t += sizeof(buf)-100) { - if(etext-t > sizeof(buf)-100) - datblk(t, sizeof(buf)-100, 1); - else - datblk(t, etext-t, 1); - } + /* output read-only data in text segment */ + sect = segtext.sect->next; + seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0); + datblk(sect->vaddr, sect->len); - /* output section header strings */ + /* output data segment */ cursym = nil; switch(HEADTYPE) { case 0: @@ -475,17 +357,12 @@ asmb(void) seek(cout, OFFSET, 0); break; case 6: - OFFSET = rnd(HEADR+textsize, INITRND); + OFFSET = rnd(segtext.fileoff+segtext.filelen, INITRND); seek(cout, OFFSET, 0); break; } - for(t = 0; t < datsize; t += sizeof(buf)-100) { - if(datsize-t > sizeof(buf)-100) - datblk(t, sizeof(buf)-100, 0); - else - datblk(t, datsize-t, 0); - } - cflush(); + segdata.fileoff = seek(cout, 0, 1); + datblk(INITDAT, segdata.filelen); /* output symbol table */ symsize = 0; @@ -502,16 +379,16 @@ asmb(void) debug['s'] = 1; break; case 2: - OFFSET = HEADR+textsize+datsize; + OFFSET = HEADR+textsize+segdata.filelen; seek(cout, OFFSET, 0); break; case 3: - OFFSET += rnd(datsize, 4096); + OFFSET += rnd(segdata.filelen, 4096); seek(cout, OFFSET, 0); break; case 6: - symo = rnd(HEADR+textsize, INITRND)+datsize+strtabsize; - symo = rnd(symo, INITRND); + OFFSET += segdata.filelen; + symo = rnd(OFFSET, INITRND); seek(cout, symo + 8, 0); break; } @@ -555,10 +432,10 @@ asmb(void) lputl(0xef000011); /* SWI - exit code */ lputl(textsize+HEADR); /* text size */ - lputl(datsize); /* data size */ + lputl(segdata.filelen); /* data size */ lputl(0); /* sym size */ - lputl(bsssize); /* bss size */ + lputl(segdata.len - segdata.filelen); /* bss size */ lputl(0); /* sym type */ lputl(INITTEXT-HEADR); /* text addr */ lputl(0); /* workspace - ignored */ @@ -575,8 +452,8 @@ asmb(void) case 2: /* plan 9 */ lput(0x647); /* magic */ lput(textsize); /* sizes */ - lput(datsize); - lput(bsssize); + lput(segdata.filelen); + lput(segdata.len - segdata.filelen); lput(symsize); /* nsyms */ lput(entryvalue()); /* va of entry */ lput(0L); @@ -585,8 +462,8 @@ asmb(void) case 3: /* boot for NetBSD */ lput((143<<16)|0413); /* magic */ lputl(rnd(HEADR+textsize, 4096)); - lputl(rnd(datsize, 4096)); - lputl(bsssize); + lputl(rnd(segdata.filelen, 4096)); + lputl(segdata.len - segdata.filelen); lputl(symsize); /* nsyms */ lputl(entryvalue()); /* va of entry */ lputl(0L); @@ -634,40 +511,16 @@ asmb(void) phsh(ph, sh); } - ph = newElfPhdr(); - ph->type = PT_LOAD; - ph->flags = PF_X+PF_R; - ph->vaddr = va; - ph->paddr = va; - ph->off = fo; - ph->filesz = w; - ph->memsz = w; - ph->align = INITRND; - - fo = rnd(fo+w, INITRND); - va = rnd(va+w, INITRND); - w = datsize; - - ph = newElfPhdr(); - ph->type = PT_LOAD; - ph->flags = PF_W+PF_R; - ph->off = fo; - ph->vaddr = va; - ph->paddr = va; - ph->filesz = w; - ph->memsz = w+bsssize; - ph->align = INITRND; + elfphload(&segtext); + elfphload(&segdata); if(!debug['s']) { - ph = newElfPhdr(); - ph->type = PT_LOAD; - ph->flags = PF_R; - ph->off = symo; - ph->vaddr = symdatva; - ph->paddr = symdatva; - ph->filesz = rnd(8+symsize+lcsize, INITRND); - ph->memsz = rnd(8+symsize+lcsize, INITRND); - ph->align = INITRND; + segsym.rwx = 04; + segsym.vaddr = symdatva; + segsym.len = rnd(8+symsize+lcsize, INITRND); + segsym.fileoff = symo; + segsym.filelen = segsym.len; + elfphload(&segsym); } /* Dynamic linking sections */ @@ -750,47 +603,12 @@ asmb(void) ph->flags = PF_W+PF_R; ph->align = 4; - fo = ELFRESERVE; - va = startva + fo; - w = textsize; - - /* - * The alignments are bigger than they really need - * to be here, but they are necessary to keep the - * arm strip from moving everything around. - */ - - sh = newElfShdr(elfstr[ElfStrText]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC+SHF_EXECINSTR; - sh->addr = va; - sh->off = fo; - sh->size = w; - sh->addralign = ELFRESERVE; - - fo = rnd(fo+w, INITRND); - va = rnd(va+w, INITRND); - w = datsize; - - sh = newElfShdr(elfstr[ElfStrData]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_WRITE+SHF_ALLOC; - sh->addr = va + elfdatsize; - sh->off = fo + elfdatsize; - sh->size = w - elfdatsize; - sh->addralign = INITRND; - - fo += w; - va += w; - w = bsssize; - - sh = newElfShdr(elfstr[ElfStrBss]); - sh->type = SHT_NOBITS; - sh->flags = SHF_WRITE+SHF_ALLOC; - sh->addr = va; - sh->off = fo; - sh->size = w; - sh->addralign = 4; + for(sect=segtext.sect; sect!=nil; sect=sect->next) + elfshbits(sect); + for(sect=segrodata.sect; sect!=nil; sect=sect->next) + elfshbits(sect); + for(sect=segdata.sect; sect!=nil; sect=sect->next) + elfshbits(sect); if (!debug['s']) { fo = symo; @@ -864,25 +682,14 @@ asmb(void) cflush(); if(debug['c']){ print("textsize=%d\n", textsize); - print("datsize=%d\n", datsize); - print("bsssize=%d\n", bsssize); + print("datsize=%d\n", segdata.filelen); + print("bsssize=%d\n", segdata.len - segdata.filelen); print("symsize=%d\n", symsize); print("lcsize=%d\n", lcsize); - print("total=%d\n", textsize+datsize+bsssize+symsize+lcsize); + print("total=%d\n", textsize+segdata.len+symsize+lcsize); } } -void -strnput(char *s, int n) -{ - for(; *s; s++){ - cput(*s); - n--; - } - for(; n > 0; n--) - cput(0); -} - void cput(int c) { @@ -1038,140 +845,6 @@ asmthumbmap(void) outt(lastt, pc+1); } -void -datblk(int32 s, int32 n, int str) -{ - Sym *v; - Prog *p; - char *cast; - int32 a, l, fl, j, d; - int i, c; - - memset(buf.dbuf, 0, n+100); - for(p = datap; p != P; p = p->link) { - if(str != (p->from.sym->type == SSTRING)) - continue; - curp = p; - a = p->from.sym->value + p->from.offset; - l = a - s; - c = p->reg; - i = 0; - if(l < 0) { - if(l+c <= 0) - continue; - while(l < 0) { - l++; - i++; - } - } - if(l >= n) - continue; - for(j=l+(c-i)-1; j>=l; j--) - if(buf.dbuf[j]) { - print("%P\n", p); - diag("multiple initialization"); - break; - } - switch(p->to.type) { - default: - diag("unknown mode in initialization%P", p); - break; - - case D_FCONST: - switch(c) { - default: - case 4: - fl = ieeedtof(p->to.ieee); - cast = (char*)&fl; - for(; ito.ieee; - for(; ito.sval[i]; - l++; - } - break; - - case D_CONST: - d = p->to.offset; - v = p->to.sym; - if(v) { - switch(v->type) { - case STEXT: - case SLEAF: - d += v->value; -#ifdef CALLEEBX - d += fnpinc(v); -#else - if(v->thumb) - d++; // T bit -#endif - break; - case SSTRING: - d += v->value; - break; - case SDATA: - case SBSS: - if(p->to.type == D_SIZE) - d += v->size; - else - d += v->value + INITDAT; - break; - } - } - cast = (char*)&d; - switch(c) { - default: - diag("bad nuxi %d %d%P", c, i, curp); - break; - case 1: - for(; ito.sbig[i]; - l++; - } - break; - } - } - ewrite(cout, buf.dbuf, n); -} - void asmout(Prog *p, Optab *o) { @@ -1644,7 +1317,7 @@ if(debug['G']) print("%ux: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym- case 54: /* floating point arith */ o1 = oprrr(p->as, p->scond); if(p->from.type == D_FCONST) { - rf = chipfloat(p->from.ieee); + rf = chipfloat(&p->from.ieee); if(rf < 0){ diag("invalid floating-point immediate\n%P", p); rf = 0; diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h index 5b1f46af01..6414b023ac 100644 --- a/src/cmd/5l/l.h +++ b/src/cmd/5l/l.h @@ -49,6 +49,7 @@ typedef struct Adr Adr; typedef struct Sym Sym; typedef struct Autom Auto; typedef struct Prog Prog; +typedef struct Reloc Reloc; typedef struct Optab Optab; typedef struct Oprang Oprang; typedef uchar Opcross[32][2][32]; @@ -66,7 +67,7 @@ struct Adr { int32 u0offset; char* u0sval; - Ieee* u0ieee; + Ieee u0ieee; char* u0sbig; } u0; Sym* sym; @@ -81,9 +82,19 @@ struct Adr #define offset u0.u0offset #define sval u0.u0sval +#define scon sval #define ieee u0.u0ieee #define sbig u0.u0sbig +struct Reloc +{ + int32 off; + uchar siz; + uchar type; + int32 add; + Sym* sym; +}; + struct Prog { Adr from; @@ -105,8 +116,10 @@ struct Prog uchar reg; uchar align; }; + #define regused u0.u0regused #define forwd u0.u0forwd +#define datasize reg struct Sym { @@ -116,6 +129,7 @@ struct Sym uchar dupok; uchar reachable; uchar dynexport; + uchar leaf; int32 value; int32 sig; int32 size; @@ -136,7 +150,12 @@ struct Sym Prog* text; // SDATA, SBSS - Prog* data; + uchar* p; + int32 np; + int32 maxp; + Reloc* r; + int32 nr; + int32 maxr; }; #define SIGNINTERN (1729*325*1729) @@ -180,20 +199,18 @@ struct Use enum { Sxxx, - + + /* order here is order in output file */ STEXT = 1, + SRODATA, + SELFDATA, SDATA, SBSS, - SDATA1, + SXREF, - SLEAF, SFILE, SCONST, - SSTRING, - SREMOVED, - SFIXED, - SELFDATA, LFROM = 1<<0, LTO = 1<<1, @@ -300,7 +317,6 @@ EXTERN int32 INITTEXT; /* text location */ EXTERN char* INITENTRY; /* entry point */ EXTERN int32 autosize; EXTERN Biobuf bso; -EXTERN int32 bsssize; EXTERN int cbc; EXTERN uchar* cbp; EXTERN int cout; @@ -308,11 +324,9 @@ EXTERN Auto* curauto; EXTERN Auto* curhist; EXTERN Prog* curp; EXTERN Sym* cursym; -EXTERN Prog* datap; -EXTERN int32 datsize; +EXTERN Sym* datap; EXTERN int32 elfdatsize; EXTERN char debug[128]; -EXTERN Prog* edatap; EXTERN Sym* etextp; EXTERN char* noname; EXTERN int xrefresolv; @@ -388,7 +402,6 @@ int chipfloat(Ieee*); int cmp(int, int); int compound(Prog*); double cputime(void); -void datblk(int32, int32, int); void diag(char*, ...); void divsig(void); void dodata(void); @@ -407,7 +420,6 @@ void lput(int32); void lputl(int32); void* mysbrk(uint32); void names(void); -Prog* newdata(Sym *s, int o, int w, int t); void nocache(Prog*); int ocmp(const void*, const void*); int32 opirr(int); @@ -435,6 +447,7 @@ int32 rnd(int32, int32); void softfloat(void); void span(void); void strnput(char*, int); +int32 symaddr(Sym*); void undef(void); void wput(int32); void wputl(ushort w); diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c index 666b03fde0..582e79aadc 100644 --- a/src/cmd/5l/list.c +++ b/src/cmd/5l/list.c @@ -274,7 +274,7 @@ Dconv(Fmt *fp) break; case D_FCONST: - snprint(str, sizeof str, "$%e", ieeedtod(a->ieee)); + snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee)); break; case D_SCONST: diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c index 5b456c9e5c..a3a0ae29b2 100644 --- a/src/cmd/5l/noop.c +++ b/src/cmd/5l/noop.c @@ -234,7 +234,7 @@ noops(void) } #endif if(cursym->text->mark & LEAF) { - cursym->type = SLEAF; + cursym->leaf = 1; if(!autosize) break; } diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c index 8232e29625..b811a609fd 100644 --- a/src/cmd/5l/obj.c +++ b/src/cmd/5l/obj.c @@ -226,9 +226,6 @@ main(int argc, char *argv[]) buildop(); thumbbuildop(); // could build on demand histgen = 0; - textp = nil; - datap = P; - edatap = P; pc = 0; dtype = 4; nuxiinit(); @@ -245,6 +242,10 @@ main(int argc, char *argv[]) for(i=0; itype == D_CONST || a->type == D_OCONST) { if(a->name == D_EXTERN || a->name == D_STATIC) { s = a->sym; - if(s != S && (s->type == STEXT || s->type == SLEAF || s->type == SCONST || s->type == SXREF)) { + if(s != S && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) { if(0 && !s->fnptr && s->name[0] != '.') print("%s used as function pointer\n", s->name); s->fnptr = 1; // over the top cos of SXREF @@ -351,9 +349,8 @@ zaddr(Biobuf *f, Adr *a, Sym *h[]) break; case D_FCONST: - a->ieee = mal(sizeof(Ieee)); - a->ieee->l = Bget4(f); - a->ieee->h = Bget4(f); + a->ieee.l = Bget4(f); + a->ieee.h = Bget4(f); break; } s = a->sym; @@ -394,7 +391,7 @@ void ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) { int32 ipc; - Prog *p, *t; + Prog *p; Sym *h[NSYM], *s, *di; int v, o, r, skip; uint32 sig; @@ -492,8 +489,8 @@ loop: zaddr(f, &p->from, h); zaddr(f, &p->to, h); - if(p->reg > NREG) - diag("register out of range %d", p->reg); + if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG) + diag("register out of range %A %d", p->as, p->reg); p->link = P; p->cond = P; @@ -541,8 +538,8 @@ loop: s->type = SBSS; s->value = 0; } - if(p->to.offset > s->value) - s->value = p->to.offset; + if(p->to.offset > s->size) + s->size = p->to.offset; if(p->reg & DUPOK) s->dupok = 1; break; @@ -553,26 +550,19 @@ loop: // ignore any more ADATA we see, which must be // redefinitions. s = p->from.sym; - if(s != S && s->dupok) { + if(s->dupok) { if(debug['v']) Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); goto loop; } - if(s != S) { - p->dlink = s->data; - s->data = p; - if(s->file == nil) - s->file = pn; - else if(s->file != pn) { - diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); - errorexit(); - } + if(s->file == nil) + s->file = pn; + else if(s->file != pn) { + diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); + errorexit(); } - if(edatap == P) - datap = p; - else - edatap->link = p; - edatap = p; + savedata(s, p); + unmal(p, sizeof *p); break; case AGOK: @@ -673,27 +663,14 @@ loop: if(skip) goto casedef; - if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) { + if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0) { /* size sb 9 max */ - sprint(literal, "$%ux", ieeedtof(p->from.ieee)); + sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); s = lookup(literal, 0); if(s->type == 0) { s->type = SBSS; - s->value = 4; - t = prg(); - t->as = ADATA; - t->line = p->line; - t->from.type = D_OREG; - t->from.sym = s; - t->from.name = D_EXTERN; - t->reg = 4; - t->to = p->from; - if(edatap == P) - datap = t; - else - edatap->link = t; - edatap = t; - t->link = P; + adduint32(s, ieeedtof(&p->from.ieee)); + s->reachable = 0; } p->from.type = D_OREG; p->from.sym = s; @@ -708,28 +685,16 @@ loop: if(skip) goto casedef; - if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) { + if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0) { /* size sb 18 max */ sprint(literal, "$%ux.%ux", - p->from.ieee->l, p->from.ieee->h); + p->from.ieee.l, p->from.ieee.h); s = lookup(literal, 0); if(s->type == 0) { s->type = SBSS; - s->value = 8; - t = prg(); - t->as = ADATA; - t->line = p->line; - t->from.type = D_OREG; - t->from.sym = s; - t->from.name = D_EXTERN; - t->reg = 8; - t->to = p->from; - if(edatap == P) - datap = t; - else - edatap->link = t; - edatap = t; - t->link = P; + adduint32(s, p->from.ieee.l); + adduint32(s, p->from.ieee.h); + s->reachable = 0; } p->from.type = D_OREG; p->from.sym = s; diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c index 8225a43fc7..e16b34171b 100644 --- a/src/cmd/5l/pass.c +++ b/src/cmd/5l/pass.c @@ -35,143 +35,6 @@ static void xfol(Prog*, Prog**); -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(s->type == SBSS) - s->type = SDATA; - if(s->type != SDATA && s->type != SELFDATA) - 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 (%d/%d): %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 0 - * assign elf data - must be segregated from real data - */ - orig = 0; - for(i=0; ihash) { - if(!s->reachable || s->type != SELFDATA) - continue; - v = s->value; - while(v & 3) - v++; - s->size = v; - s->value = orig; - orig += v; - } - elfdatsize = orig; - - /* - * pass 1 - * assign 'small' variables to data segment - * (rational is that data segment is more easily - * addressed through offset on R12) - */ - for(i=0; ihash) { - 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; ihash) { - 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; ihash) { - 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); - - if(debug['s']) - xdefine("symdat", SFIXED, 0); - else - xdefine("symdat", SFIXED, SYMDATVA); -} - void undef(void) { @@ -500,205 +363,3 @@ rnd(int32 v, int32 r) v -= c; return v; } - -static void -fused(Adr *a, Prog *p, Prog *ct) -{ - Sym *s = a->sym; - Use *u; - - if(s == S) - return; - if(a->type == D_OREG || a->type == D_OCONST || a->type == D_CONST){ - if(a->name == D_EXTERN || a->name == D_STATIC){ - u = malloc(sizeof(Use)); - u->p = p; - u->ct = ct; - u->link = s->use; - s->use = u; - } - } - else if(a->type == D_BRANCH){ - u = malloc(sizeof(Use)); - u->p = p; - u->ct = ct; - u->link = s->use; - s->use = u; - } -} - -static int -ckfpuse(Prog *p, Prog *ct, Sym *fp, Sym *r) -{ - int reg; - - USED(fp); - USED(ct); - if(p->from.sym == r && p->as == AMOVW && (p->from.type == D_CONST || p->from.type == D_OREG) && p->reg == NREG && p->to.type == D_REG){ - reg = p->to.reg; - for(p = p->link; p != P && p->as != ATEXT; p = p->link){ - if((p->as == ABL || p->as == ABX) && p->to.type == D_OREG && p->to.reg == reg) - return 1; - if(!debug['F'] && (isbranch(p) || p->as == ARET)){ - // print("%s: branch %P in %s\n", fp->name, p, ct->from.sym->name); - return 0; - } - if((p->from.type == D_REG || p->from.type == D_OREG) && p->from.reg == reg){ - if(!debug['F'] && p->to.type != D_REG){ - // print("%s: store %P in %s\n", fp->name, p, ct->from.sym->name); - return 0; - } - reg = p->to.reg; - } - } - } - // print("%s: no MOVW O(R), R\n", fp->name); - return debug['F']; -} - -static void -setfpuse(Prog *p, Sym *fp, Sym *r) -{ - int reg; - - if(p->from.sym == r && p->as == AMOVW && (p->from.type == D_CONST || p->from.type == D_OREG) && p->reg == NREG && p->to.type == D_REG){ - reg = p->to.reg; - for(p = p->link; p != P && p->as != ATEXT; p = p->link){ - if((p->as == ABL || p->as == ABX) && p->to.type == D_OREG && p->to.reg == reg){ - fp->fnptr = 0; - p->as = ABL; // safe to do so -// print("simplified %s call\n", fp->name); - break; - } - if(!debug['F'] && (isbranch(p) || p->as == ARET)) - diag("bad setfpuse call"); - if((p->from.type == D_REG || p->from.type == D_OREG) && p->from.reg == reg){ - if(!debug['F'] && p->to.type != D_REG) - diag("bad setfpuse call"); - reg = p->to.reg; - } - } - } -} - -static int -cksymuse(Sym *s, int t) -{ - Prog *p; - - for(p = datap; p != P; p = p->link){ - if(p->from.sym == s && p->to.sym != nil && strcmp(p->to.sym->name, ".string") != 0 && p->to.sym->thumb != t){ - // print("%s %s %d %d ", p->from.sym->name, p->to.sym->name, p->to.sym->thumb, t); - return 0; - } - } - return 1; -} - -/* check the use of s at the given point */ -static int -ckuse(Sym *s, Sym *s0, Use *u) -{ - Sym *s1; - - s1 = u->p->from.sym; -// print("ckuse %s %s %s\n", s->name, s0->name, s1 ? s1->name : "nil"); - if(u->ct == nil){ /* in data area */ - if(s0 == s && !cksymuse(s1, s0->thumb)){ - // print("%s: cksymuse fails\n", s0->name); - return 0; - } - for(u = s1->use; u != U; u = u->link) - if(!ckuse(s1, s0, u)) - return 0; - } - else{ /* in text area */ - if(u->ct->from.sym->thumb != s0->thumb){ - // print("%s(%d): foreign call %s(%d)\n", s0->name, s0->thumb, u->ct->from.sym->name, u->ct->from.sym->thumb); - return 0; - } - return ckfpuse(u->p, u->ct, s0, s); - } - return 1; -} - -static void -setuse(Sym *s, Sym *s0, Use *u) -{ - Sym *s1; - - s1 = u->p->from.sym; - if(u->ct == nil){ /* in data area */ - for(u = s1->use; u != U; u = u->link) - setuse(s1, s0, u); - } - else{ /* in text area */ - setfpuse(u->p, s0, s); - } -} - -/* detect BX O(R) which can be done as BL O(R) */ -void -fnptrs(void) -{ - int i; - Sym *s; - Prog *p; - Use *u; - - for(i=0; ihash){ - if(s->fnptr && (s->type == STEXT || s->type == SLEAF || s->type == SCONST)){ - // print("%s : fnptr %d %d\n", s->name, s->thumb, s->foreign); - } - } - } - /* record use of syms */ - for(cursym = textp; cursym != nil; cursym = cursym->next) - for(p = cursym->text; p != P; p = p->link) { - if(p->as != ATEXT) { - fused(&p->from, p, cursym->text); - fused(&p->to, p, cursym->text); - } - } - for(p = datap; p != P; p = p->link) - fused(&p->to, p, nil); - - /* now look for fn ptrs */ - for(i=0; ihash){ - if(s->fnptr && (s->type == STEXT || s->type == SLEAF || s->type == SCONST)){ - for(u = s->use; u != U; u = u->link){ - if(!ckuse(s, s, u)) - break; - } - if(u == U){ // can simplify - for(u = s->use; u != U; u = u->link) - setuse(s, s, u); - } - } - } - } - - /* now free Use structures */ -} - -Prog* -newdata(Sym *s, int o, int w, int t) -{ - Prog *p; - - p = prg(); - p->link = datap; - datap = p; - p->as = ADATA; - p->reg = w; - p->from.type = D_OREG; - p->from.name = t; - p->from.sym = s; - p->from.offset = o; - p->to.type = D_CONST; - p->to.name = D_NONE; - s->data = p; - return p; -} diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c index 4a168870b1..e02ee91381 100644 --- a/src/cmd/5l/span.c +++ b/src/cmd/5l/span.c @@ -165,16 +165,19 @@ void span(void) { Prog *p, *op; - Sym *setext, *s; Optab *o; - int m, bflag, i; - int32 c, otxt, v; + int m, bflag; + int32 c, otxt; int lastthumb = -1; + Section *rosect, *sect; + Sym *sym; if(debug['v']) Bprint(&bso, "%5.2f span\n", cputime()); Bflush(&bso); + xdefine("etext", STEXT, 0); + bflag = 0; c = INITTEXT; op = nil; @@ -364,36 +367,61 @@ span(void) goto loop; } } - - if(debug['t']) { - /* - * add strings to text segment - */ - c = rnd(c, 8); - for(i=0; ihash) { - if(s->type != SSTRING) - continue; - v = s->value; - while(v & 3) - v++; - s->value = c; - c += v; - } - } - c = rnd(c, 8); - setext = lookup("etext", 0); - if(setext != S) { - setext->value = c; - textsize = c - INITTEXT; + xdefine("etext", STEXT, c); + for(cursym = textp; cursym != nil; cursym = cursym->next) + cursym->value = cursym->text->pc; + textsize = c - INITTEXT; + + rosect = segtext.sect->next; + if(rosect) { + if(INITRND) + c = rnd(c, INITRND); + rosect->vaddr = c; + c += rosect->len; } + if(INITRND) INITDAT = rnd(c, INITRND); + if(debug['v']) Bprint(&bso, "tsize = %ux\n", textsize); Bflush(&bso); + + segtext.rwx = 05; + segtext.vaddr = INITTEXT - HEADR; + segtext.len = INITDAT - INITTEXT + HEADR; + segtext.filelen = segtext.len; + + sect = segtext.sect; + sect->vaddr = INITTEXT; + sect->len = textsize; + + // Adjust everything now that we know INITDAT. + // This will get simpler when everything is relocatable + // and we can run span before dodata. + + segdata.vaddr += INITDAT; + for(sect=segdata.sect; sect!=nil; sect=sect->next) + sect->vaddr += INITDAT; + + xdefine("data", SBSS, INITDAT); + xdefine("edata", SBSS, INITDAT+segdata.filelen); + xdefine("end", SBSS, INITDAT+segdata.len); + + for(sym=datap; sym!=nil; sym=sym->next) { + switch(sym->type) { + case SELFDATA: + case SRODATA: + sym->value += rosect->vaddr; + break; + case SDATA: + case SBSS: + sym->value += INITDAT; + break; + } + } } /* @@ -512,10 +540,8 @@ xdefine(char *p, int t, int32 v) Sym *s; s = lookup(p, 0); - if(s->type == 0 || s->type == SXREF) { - s->type = t; - s->value = v; - } + s->type = t; + s->value = v; } int32 @@ -572,6 +598,37 @@ immhalf(int32 v) return 0; } +int32 +symaddr(Sym *s) +{ + int32 v; + + v = s->value; + switch(s->type) { + default: + diag("unexpected type %d in symaddr(%s)", s->type, s->name); + return 0; + + case STEXT: +#ifdef CALLEEBX + v += fnpinc(s); +#else + if(s->thumb) + v++; // T bit +#endif + break; + + case SELFDATA: + case SRODATA: + case SDATA: + case SBSS: + case SFIXED: + case SCONST: + break; + } + return v; +} + int aclass(Adr *a) { @@ -613,7 +670,7 @@ aclass(Adr *a) s->name, TNAME); s->type = SDATA; } - instoffset = s->value + a->offset - BIG; + instoffset = s->value + a->offset - INITDAT - BIG; t = immaddr(instoffset); if(t) { if(immhalf(instoffset)) @@ -682,21 +739,7 @@ aclass(Adr *a) s->name, TNAME); s->type = SDATA; } - if(s->type == SFIXED) { - instoffset = s->value + a->offset; - return C_LCON; - } - instoffset = s->value + a->offset + INITDAT; - if(s->type == STEXT || s->type == SLEAF) { - instoffset = s->value + a->offset; -#ifdef CALLEEBX - instoffset += fnpinc(s); -#else - if(s->thumb) - instoffset++; // T bit -#endif - return C_LCON; - } + instoffset = symaddr(s) + a->offset; return C_LCON; } return C_GOK; @@ -735,26 +778,16 @@ aclass(Adr *a) s->type = SDATA; break; case SFIXED: - instoffset = s->value + a->offset; - return C_LCON; case STEXT: - case SSTRING: case SCONST: - case SLEAF: - instoffset = s->value + a->offset; -#ifdef CALLEEBX - instoffset += fnpinc(s); -#else - if(s->thumb) - instoffset++; // T bit -#endif + instoffset = symaddr(s) + a->offset; return C_LCON; } - instoffset = s->value + a->offset - BIG; + instoffset = s->value + a->offset - INITDAT - BIG; t = immrot(instoffset); if(t && instoffset != 0) return C_RECON; - instoffset = s->value + a->offset + INITDAT; + instoffset = symaddr(s) + a->offset; return C_LCON; case D_AUTO: diff --git a/src/cmd/5l/symtab.c b/src/cmd/5l/symtab.c index 04e50fe1d4..247024c33f 100644 --- a/src/cmd/5l/symtab.c +++ b/src/cmd/5l/symtab.c @@ -46,37 +46,30 @@ asmsym(void) putsymb(s->name, 'T', s->value, s->version); for(h=0; hhash) + for(s=hash[h]; s!=S; s=s->hash) { + if(!s->reachable) + continue; switch(s->type) { case SCONST: - putsymb(s->name, 'D', s->value, s->version); - continue; - case SDATA: case SELFDATA: - putsymb(s->name, 'D', s->value+INITDAT, s->version); + putsymb(s->name, 'D', s->value, s->version); continue; case SBSS: - putsymb(s->name, 'B', s->value+INITDAT, s->version); - continue; - case SFIXED: putsymb(s->name, 'B', s->value, s->version); continue; - case SSTRING: - putsymb(s->name, 'T', s->value, s->version); - continue; - case SFILE: putsymb(s->name, 'f', s->value, s->version); continue; } + } for(s=textp; s!=nil; s=s->next) { p = s->text; - if(s->type != STEXT && s->type != SLEAF) + if(s->type != STEXT) continue; /* filenames first */ @@ -90,7 +83,7 @@ asmsym(void) if(!s->reachable) continue; - if(s->type == STEXT) + if(s->leaf == 0) putsymb(s->name, 'T', s->value, s->version); else putsymb(s->name, 'L', s->value, s->version); diff --git a/src/cmd/5l/thumb.c b/src/cmd/5l/thumb.c index db7e01bdd5..415d0d4bd8 100644 --- a/src/cmd/5l/thumb.c +++ b/src/cmd/5l/thumb.c @@ -203,7 +203,7 @@ thumbaclass(Adr *a, Prog *p) a->sym->name, TNAME); a->sym->type = SDATA; } - instoffset = a->sym->value + a->offset + INITDAT; + instoffset = a->sym->value + a->offset; return C_LEXT; /* INITDAT unknown at this stage */ // return immacon(instoffset, p, C_SEXT, C_LEXT); case D_AUTO: @@ -235,8 +235,8 @@ thumbaclass(Adr *a, Prog *p) s->name, TNAME); s->type = SDATA; } - instoffset = s->value + a->offset + INITDAT; - if(s->type == STEXT || s->type == SLEAF){ + instoffset = s->value + a->offset; + if(s->type == STEXT){ instoffset = s->value + a->offset; #ifdef CALLEEBX instoffset += fnpinc(s); @@ -275,7 +275,6 @@ thumbaclass(Adr *a, Prog *p) break; case SCONST: case STEXT: - case SLEAF: instoffset = s->value + a->offset; #ifdef CALLEEBX instoffset += fnpinc(s); @@ -285,7 +284,7 @@ thumbaclass(Adr *a, Prog *p) #endif return C_LCON; } - instoffset = s->value + a->offset + INITDAT; + instoffset = s->value + a->offset; return C_LCON; /* INITDAT unknown at this stage */ // return immcon(instoffset, p); case D_AUTO: diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile index 8d396546c3..94e520a93e 100644 --- a/src/cmd/6l/Makefile +++ b/src/cmd/6l/Makefile @@ -9,6 +9,7 @@ TARG=6l OFILES=\ asm.$O\ + data.$O\ dwarf.$O\ elf.$O\ enam.$O\ diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index fcca32748d..839ebdf3de 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -44,7 +44,6 @@ char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2"; char freebsddynld[] = "/libexec/ld-elf.so.1"; char zeroes[32]; -Prog* datsort(Prog *l); vlong entryvalue(void) @@ -58,13 +57,8 @@ entryvalue(void) s = lookup(a, 0); if(s->type == 0) return INITTEXT; - switch(s->type) { - case STEXT: - break; - case SDATA: - default: + if(s->type != STEXT) diag("entry not text: %s", s->name); - } return s->value; } @@ -114,132 +108,13 @@ vputl(uint64 v) lputl(v>>32); } -void -strnput(char *s, int n) -{ - int i; - - for(i=0; itype == 0) - s->type = SDATA; - s->reachable = 1; - r = s->size; - n = strlen(str)+1; - if(strcmp(s->name, ".shstrtab") == 0) - elfsetstring(str, r); - while(n > 0) { - m = n; - if(m > sizeof(p->to.scon)) - m = sizeof(p->to.scon); - p = newdata(s, s->size, m, D_EXTERN); - p->to.type = D_SCONST; - memmove(p->to.scon, str, m); - s->size += m; - str += m; - n -= m; - } - return r; -} - -vlong -adduintxx(Sym *s, uint64 v, int wid) -{ - vlong r; - Prog *p; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->size; - p = newdata(s, s->size, wid, D_EXTERN); - s->size += wid; - p->to.type = D_CONST; - p->to.offset = v; - return r; -} - -vlong -adduint8(Sym *s, uint8 v) -{ - return adduintxx(s, v, 1); -} - -vlong -adduint16(Sym *s, uint16 v) -{ - return adduintxx(s, v, 2); -} - -vlong -adduint32(Sym *s, uint32 v) -{ - return adduintxx(s, v, 4); -} - -vlong -adduint64(Sym *s, uint64 v) -{ - return adduintxx(s, v, 8); -} - -vlong -addaddr(Sym *s, Sym *t) -{ - vlong r; - Prog *p; - enum { Ptrsize = 8 }; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->size; - p = newdata(s, s->size, Ptrsize, D_EXTERN); - s->size += Ptrsize; - p->to.type = D_ADDR; - p->to.index = D_EXTERN; - p->to.offset = 0; - p->to.sym = t; - return r; -} - -vlong -addsize(Sym *s, Sym *t) -{ - vlong r; - Prog *p; - enum { Ptrsize = 8 }; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->size; - p = newdata(s, s->size, Ptrsize, D_EXTERN); - s->size += Ptrsize; - p->to.type = D_SIZE; - p->to.index = D_EXTERN; - p->to.offset = 0; - p->to.sym = t; - return r; -} - vlong datoff(vlong addr) { if(addr >= segdata.vaddr) return addr - segdata.vaddr + segdata.fileoff; + if(addr >= segtext.vaddr) + return addr - segtext.vaddr + segtext.fileoff; diag("datoff %#llx", addr); return 0; } @@ -295,6 +170,9 @@ doelf(void) /* predefine strings we need for section headers */ shstrtab = lookup(".shstrtab", 0); + shstrtab->type = SELFDATA; + shstrtab->reachable = 1; + elfstr[ElfStrEmpty] = addstring(shstrtab, ""); elfstr[ElfStrText] = addstring(shstrtab, ".text"); elfstr[ElfStrData] = addstring(shstrtab, ".data"); @@ -470,7 +348,7 @@ asmb(void) int32 v, magic; int a, dynsym; uchar *op1; - vlong vl, va, startva, fo, w, symo, elfsymo, elfstro, elfsymsize, machlink, erodata; + vlong vl, va, startva, fo, w, symo, elfsymo, elfstro, elfsymsize, machlink; vlong symdatva = SYMDATVA; ElfEhdr *eh; ElfPhdr *ph, *pph; @@ -518,17 +396,9 @@ asmb(void) } cflush(); - datap = datsort(datap); - /* output read-only data in text segment */ sect = segtext.sect->next; - erodata = sect->vaddr + sect->len; - for(v = pc; v < erodata; v += sizeof(buf)-Dbufslop) { - if(erodata - v > sizeof(buf)-Dbufslop) - datblk(v, sizeof(buf)-Dbufslop); - else - datblk(v, erodata-v); - } + datblk(pc, sect->vaddr + sect->len - pc); switch(HEADTYPE) { default: @@ -568,12 +438,7 @@ asmb(void) Bflush(&bso); segdata.fileoff = seek(cout, 0, 1); - for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) { - if(datsize-v > sizeof(buf)-Dbufslop) - datblk(v+INITDAT, sizeof(buf)-Dbufslop); - else - datblk(v+INITDAT, datsize-v); - } + datblk(INITDAT, segdata.filelen); machlink = 0; if(HEADTYPE == 6) @@ -592,14 +457,14 @@ asmb(void) case 2: case 5: debug['s'] = 1; - symo = HEADR+textsize+datsize; + symo = HEADR+textsize+segdata.filelen; break; case 6: - symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND)+machlink; + symo = rnd(HEADR+textsize, INITRND)+rnd(segdata.filelen, INITRND)+machlink; break; case 7: case 9: - symo = rnd(HEADR+textsize, INITRND)+datsize; + symo = rnd(HEADR+textsize, INITRND)+segdata.filelen; symo = rnd(symo, INITRND); break; } @@ -655,8 +520,8 @@ asmb(void) magic |= 0x00008000; /* fat header */ lputb(magic); /* magic */ lputb(textsize); /* sizes */ - lputb(datsize); - lputb(bsssize); + lputb(segdata.filelen); + lputb(segdata.len - segdata.filelen); lputb(symsize); /* nsyms */ vl = entryvalue(); lputb(PADDR(vl)); /* va of entry */ @@ -668,8 +533,8 @@ asmb(void) magic = 4*26*26+7; lputb(magic); /* magic */ lputb(textsize); /* sizes */ - lputb(datsize); - lputb(bsssize); + lputb(segdata.filelen); + lputb(segdata.len - segdata.filelen); lputb(symsize); /* nsyms */ lputb(entryvalue()); /* va of entry */ lputb(spsize); /* sp offsets */ @@ -928,335 +793,6 @@ cpos(void) return seek(cout, 0, 1) + sizeof(buf.cbuf) - cbc; } -void -outa(int n, uchar *cast, uchar *map, vlong l) -{ - int i, j; - - Bprint(&bso, pcstr, l); - for(i=0; ifrom.offset; - v2 = p2->from.offset; - if(v1 > v2) - return +1; - if(v1 < v2) - return -1; - return 0; -} - -Prog* -dsort(Prog *l) -{ - Prog *l1, *l2, *le; - - if(l == 0 || l->link == 0) - return l; - - l1 = l; - l2 = l; - for(;;) { - l2 = l2->link; - if(l2 == 0) - break; - l2 = l2->link; - if(l2 == 0) - break; - l1 = l1->link; - } - - l2 = l1->link; - l1->link = 0; - l1 = dsort(l); - l2 = dsort(l2); - - /* set up lead element */ - if(datcmp(l1, l2) < 0) { - l = l1; - l1 = l1->link; - } else { - l = l2; - l2 = l2->link; - } - le = l; - - for(;;) { - if(l1 == 0) { - while(l2) { - le->link = l2; - le = l2; - l2 = l2->link; - } - le->link = 0; - break; - } - if(l2 == 0) { - while(l1) { - le->link = l1; - le = l1; - l1 = l1->link; - } - break; - } - if(datcmp(l1, l2) < 0) { - le->link = l1; - le = l1; - l1 = l1->link; - } else { - le->link = l2; - le = l2; - l2 = l2->link; - } - } - le->link = 0; - return l; -} - -static Prog *datp; - -Prog* -datsort(Prog *l) -{ - Prog *p; - Adr *a; - - for(p = l; p != P; p = p->link) { - a = &p->from; - a->offset += a->sym->value; - if(a->sym->type != SRODATA) - a->offset += INITDAT; - } - datp = dsort(l); - return datp; -} - -void -datblk(int32 s, int32 n) -{ - Prog *p; - uchar *cast; - int32 l, fl, j; - vlong o; - int i, c; - Adr *a; - - for(p = datp; p != P; p = p->link) { - a = &p->from; - l = a->offset - s; - if(l+a->scale < 0) - continue; - datp = p; - break; - } - - memset(buf.dbuf, 0, n+Dbufslop); - for(p = datp; p != P; p = p->link) { - a = &p->from; - - l = a->offset - s; - if(l >= n) - break; - - c = a->scale; - i = 0; - if(l < 0) { - if(l+c <= 0) - continue; - i = -l; - l = 0; - } - - curp = p; - if(!a->sym->reachable) - diag("unreachable symbol in datblk - %s", a->sym->name); - if(a->sym->type == SMACHO) - continue; - - for(j=l+(c-i)-1; j>=l; j--) - if(buf.dbuf[j]) { - print("%P\n", p); - diag("multiple initialization for %d %d", s, j); - break; - } - - switch(p->to.type) { - case D_FCONST: - switch(c) { - default: - case 4: - fl = ieeedtof(&p->to.ieee); - cast = (uchar*)&fl; - for(; ito.ieee; - for(; ito.scon[i]; - l++; - } - break; - - default: - o = p->to.offset; - if(p->to.type == D_SIZE) - o += p->to.sym->size; - if(p->to.type == D_ADDR) { - if(p->to.index != D_STATIC && p->to.index != D_EXTERN) - diag("DADDR type%P", p); - if(p->to.sym) { - if(p->to.sym->type == Sxxx) { - cursym = p->from.sym; - diag("missing symbol %s", p->to.sym->name); - cursym = nil; - } - o += p->to.sym->value; - if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF && p->to.sym->type != SRODATA) - o += INITDAT; - } - } - fl = o; - cast = (uchar*)&fl; - switch(c) { - default: - diag("bad nuxi %d %d\n%P", c, i, curp); - break; - case 1: - for(; ilink) { - a = &p->from; - - l = a->offset - s; - if(l >= n) - continue; - - c = a->scale; - i = 0; - if(l < 0) - continue; - - if(a->sym->type == SMACHO) - continue; - - curp = p; - switch(p->to.type) { - case D_FCONST: - switch(c) { - default: - case 4: - fl = ieeedtof(&p->to.ieee); - cast = (uchar*)&fl; - outa(c, cast, fnuxi4, l+s); - break; - case 8: - cast = (uchar*)&p->to.ieee; - outa(c, cast, fnuxi8, l+s); - break; - } - break; - - case D_SCONST: - outa(c, (uchar*)p->to.scon, nil, l+s); - break; - - default: - o = p->to.offset; - if(p->to.type == D_SIZE) - o += p->to.sym->size; - if(p->to.type == D_ADDR) { - if(p->to.sym) { - o += p->to.sym->value; - if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF && p->to.sym->type != SRODATA) - o += INITDAT; - } - } - fl = o; - cast = (uchar*)&fl; - switch(c) { - case 1: - outa(c, cast, inuxi1, l+s); - break; - case 2: - outa(c, cast, inuxi2, l+s); - break; - case 4: - outa(c, cast, inuxi4, l+s); - break; - case 8: - cast = (uchar*)&o; - outa(c, cast, inuxi8, l+s); - break; - } - break; - } - } -} - vlong rnd(vlong v, vlong r) { diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index d8aa25eb9d..b9a283ad34 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -56,6 +56,7 @@ typedef struct Sym Sym; typedef struct Auto Auto; typedef struct Optab Optab; typedef struct Movtab Movtab; +typedef struct Reloc Reloc; struct Adr { @@ -79,6 +80,15 @@ struct Adr #define ieee u0.u0ieee #define sbig u0.u0sbig +struct Reloc +{ + int32 off; + uchar siz; + uchar type; + int64 add; + Sym* sym; +}; + struct Prog { Adr from; @@ -99,6 +109,8 @@ struct Prog char width; /* fake for DATA */ char mode; /* 16, 32, or 64 */ }; +#define datasize from.scale + struct Auto { Sym* asym; @@ -130,7 +142,12 @@ struct Sym Prog* text; // SDATA, SBSS - Prog* data; + uchar* p; + int32 np; + int32 maxp; + Reloc* r; + int32 nr; + int32 maxr; }; struct Optab { @@ -151,19 +168,19 @@ struct Movtab enum { Sxxx, + + /* order here is order in output file */ STEXT = 1, + SELFDATA, + SRODATA, SDATA, SBSS, - SDATA1, + SXREF, + SMACHO, SFILE, SCONST, - SUNDEF, - - SMACHO, SFIXED, - SELFDATA, - SRODATA, NHASH = 10007, NHUNK = 100000, @@ -298,7 +315,6 @@ EXTERN int32 INITRND; EXTERN vlong INITTEXT; EXTERN char* INITENTRY; /* entry point */ EXTERN Biobuf bso; -EXTERN int32 bsssize; EXTERN int cbc; EXTERN char* cbp; EXTERN char* pcstr; @@ -306,9 +322,7 @@ EXTERN Auto* curauto; EXTERN Auto* curhist; EXTERN Prog* curp; EXTERN Sym* cursym; -EXTERN Prog* datap; -EXTERN Prog* edatap; -EXTERN vlong datsize; +EXTERN Sym* datap; EXTERN vlong elfdatsize; EXTERN char debug[128]; EXTERN char literal[32]; @@ -359,11 +373,6 @@ int Sconv(Fmt*); void addhist(int32, int); void addstackmark(void); Prog* appendp(Prog*); -vlong addstring(Sym*, char*); -vlong adduint32(Sym*, uint32); -vlong adduint64(Sym*, uint64); -vlong addaddr(Sym*, Sym*); -vlong addsize(Sym*, Sym*); void asmb(void); void asmdyn(void); void asmins(Prog*); @@ -380,10 +389,8 @@ double cputime(void); void datblk(int32, int32); void deadcode(void); void diag(char*, ...); -void dobss(void); void dodata(void); void doelf(void); -void doinit(void); void domacho(void); void doprof1(void); void doprof2(void); @@ -399,7 +406,6 @@ void lputl(int32); void instinit(void); void main(int, char*[]); void* mysbrk(uint32); -Prog* newdata(Sym*, int, int, int); Prog* newtext(Prog*, Sym*); void nopout(Prog*); int opsize(Prog*); @@ -407,12 +413,9 @@ void patch(void); Prog* prg(void); void parsetextconst(vlong); int relinv(int); -int32 reuse(Prog*, Sym*); vlong rnd(vlong, vlong); void span(void); -void strnput(char*, int); void undef(void); -vlong vaddr(Adr*); vlong symaddr(Sym*); void vputl(uint64); void wputb(uint16); diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index 112199b61c..97b79d53cb 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -223,9 +223,6 @@ main(int argc, char *argv[]) pcstr = "%.6llux "; nuxiinit(); histgen = 0; - textp = nil; - datap = P; - edatap = P; pc = 0; dtype = 4; version = 0; @@ -234,16 +231,13 @@ main(int argc, char *argv[]) addlibpath("command line", "command line", argv[0], "main"); loadlib(); - deadcode(); - patch(); follow(); doelf(); if(HEADTYPE == 6) domacho(); dodata(); - dobss(); dostkoff(); paramspace = "SP"; /* (FP) now (SP) on output */ if(debug['p']) @@ -252,7 +246,7 @@ main(int argc, char *argv[]) else doprof2(); span(); - doinit(); + reloc(); asmb(); undef(); if(debug['v']) { @@ -362,7 +356,7 @@ void ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) { vlong ipc; - Prog *p, *t; + Prog *p; int v, o, r, skip, mode; Sym *h[NSYM], *s, *di; uint32 sig; @@ -532,27 +526,19 @@ loop: // ignore any more ADATA we see, which must be // redefinitions. s = p->from.sym; - if(s != S && s->dupok) { + if(s->dupok) { // if(debug['v']) // Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); goto loop; } - if(s != S) { - p->dlink = s->data; - s->data = p; - if(s->file == nil) - s->file = pn; - else if(s->file != pn) { - diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); - errorexit(); - } + if(s->file == nil) + s->file = pn; + else if(s->file != pn) { + diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); + errorexit(); } - if(edatap == P) - datap = p; - else - edatap->link = p; - edatap = p; - p->link = P; + savedata(s, p); + unmal(p, sizeof *p); goto loop; case AGOK: @@ -636,21 +622,9 @@ loop: sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); s = lookup(literal, 0); if(s->type == 0) { - s->type = SBSS; - s->size = 4; - t = prg(); - t->as = ADATA; - t->line = p->line; - t->from.type = D_EXTERN; - t->from.sym = s; - t->from.scale = 4; - t->to = p->from; - if(edatap == P) - datap = t; - else - edatap->link = t; - edatap = t; - t->link = P; + s->type = SDATA; + adduint32(s, ieeedtof(&p->from.ieee)); + s->reachable = 1; } p->from.type = D_EXTERN; p->from.sym = s; @@ -682,21 +656,10 @@ loop: p->from.ieee.l, p->from.ieee.h); s = lookup(literal, 0); if(s->type == 0) { - s->type = SBSS; - s->size = 8; - t = prg(); - t->as = ADATA; - t->line = p->line; - t->from.type = D_EXTERN; - t->from.sym = s; - t->from.scale = 8; - t->to = p->from; - if(edatap == P) - datap = t; - else - edatap->link = t; - edatap = t; - t->link = P; + s->type = SDATA; + adduint32(s, p->from.ieee.l); + adduint32(s, p->from.ieee.h); + s->reachable = 1; } p->from.type = D_EXTERN; p->from.sym = s; diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c index 2a5a18abd9..a2a82a18b5 100644 --- a/src/cmd/6l/pass.c +++ b/src/cmd/6l/pass.c @@ -42,168 +42,6 @@ enum StackBig = 4096, }; -void -dodata(void) -{ - int i; - Sym *s; - Prog *p; - int32 t, u; - Section *sect; - - if(debug['v']) - Bprint(&bso, "%5.2f dodata\n", cputime()); - Bflush(&bso); - - segdata.rwx = 06; - segdata.vaddr = 0; /* span will += INITDAT */ - - for(p = datap; p != P; p = p->link) { - s = p->from.sym; - if(s->type == SBSS) - s->type = SDATA; - if(s->type != SDATA && s->type != SELFDATA && s->type != SRODATA) - diag("%s: initialize non-data (%d)\n%P", - s->name, s->type, p); - t = p->from.offset + p->width; - if(t > s->size) - diag("%s: initialize bounds (%lld)\n%P", - s->name, s->size, p); - } - - /* allocate elf guys - must be segregated from real data */ - datsize = 0; - for(i=0; ihash) { - if(!s->reachable) - continue; - if(s->type != SELFDATA) - continue; - t = rnd(s->size, 8); - s->size = t; - s->value = datsize; - datsize += t; - } - elfdatsize = datsize; - - sect = addsection(&segdata, ".data", 06); - sect->vaddr = datsize; - - /* allocate small guys */ - for(i=0; ihash) { - if(!s->reachable) - continue; - if(s->type != SDATA) - if(s->type != SBSS) - continue; - t = s->size; - if(t == 0 && s->name[0] != '.') { - diag("%s: no size", s->name); - t = 1; - } - t = rnd(t, 4); - if(t > MINSIZ) - continue; - if(t >= 8) - datsize = rnd(datsize, 8); - s->size = t; - s->value = datsize; - datsize += t; - s->type = SDATA1; - } - - /* allocate the rest of the data */ - for(i=0; ihash) { - if(!s->reachable) - continue; - if(s->type != SDATA) { - if(s->type == SDATA1) - s->type = SDATA; - continue; - } - t = s->size; - if(t >= 8) - datsize = rnd(datsize, 8); - s->value = datsize; - datsize += t; - } - if(datsize) - datsize = rnd(datsize, 8); - - 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; ihash) { - if(!s->reachable) - continue; - if(s->type != SBSS) - continue; - t = s->value; - if(t > u) - continue; - u -= t; - s->size = t; - s->value = datsize; - s->type = SDATA; - datsize += t; - } - datsize += u; - } - sect->len = datsize - sect->vaddr; -} - -void -dobss(void) -{ - int i; - Sym *s; - int32 t; - Section *sect; - - if(dynptrsize > 0) { - /* dynamic pointer section between data and bss */ - datsize = rnd(datsize, 8); - } - - sect = addsection(&segdata, ".bss", 06); - sect->vaddr = datsize; - - /* now the bss */ - bsssize = 0; - for(i=0; ihash) { - if(!s->reachable) - continue; - if(s->type != SBSS) - continue; - t = s->size; - if(t >= 8) - bsssize = rnd(bsssize, 8); - s->value = bsssize + dynptrsize + datsize; - bsssize += t; - } - sect->len = bsssize; - - segdata.len = datsize+bsssize; - segdata.filelen = datsize; - - xdefine("data", SBSS, 0); - xdefine("edata", SBSS, datsize); - xdefine("end", SBSS, dynptrsize + bsssize + datsize); - - if(debug['s']) - xdefine("symdat", SFIXED, 0); - else - xdefine("symdat", SFIXED, SYMDATVA); -} - Prog* brchain(Prog *p) { @@ -419,28 +257,6 @@ relinv(int a) return a; } -void -doinit(void) -{ - Sym *s; - Prog *p; - int x; - - for(p = datap; p != P; p = p->link) { - x = p->to.type; - if(x != D_EXTERN && x != D_STATIC) - continue; - s = p->to.sym; - if(s->type == 0 || s->type == SXREF) - diag("undefined %s initializer of %s", - s->name, p->from.sym->name); - p->to.offset += s->value; - p->to.type = D_CONST; - if(s->type == SDATA || s->type == SBSS) - p->to.offset += INITDAT; - } -} - void patch(void) { @@ -878,26 +694,3 @@ undef(void) if(s->type == SXREF) diag("%s: not defined", s->name); } - -Prog* -newdata(Sym *s, int o, int w, int t) -{ - Prog *p; - - p = prg(); - if(edatap == P) - datap = p; - else - edatap->link = p; - edatap = p; - p->as = ADATA; - p->width = w; - p->from.scale = w; - p->from.type = t; - p->from.sym = s; - p->from.offset = o; - p->to.type = D_CONST; - p->dlink = s->data; - s->data = p; - return p; -} diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c index 92f72a32c4..978ed0088a 100644 --- a/src/cmd/6l/span.c +++ b/src/cmd/6l/span.c @@ -40,11 +40,11 @@ void span(void) { Prog *p, *q; - int32 i, v; - vlong c, idat, etext, rodata, erodata; + int32 v; + vlong c, idat, etext, rosize; int m, n, again; - Sym *s; - Section *sect; + Section *sect, *rosect; + Sym *sym; xdefine("etext", STEXT, 0L); xdefine("rodata", SRODATA, 0L); @@ -77,6 +77,9 @@ span(void) } } n = 0; + + rosect = segtext.sect->next; + rosize = rosect->len; start: if(debug['v']) @@ -128,24 +131,16 @@ loop: goto loop; } etext = c; - - /* - * allocate read-only data to the text segment. - */ - c = rnd(c, 8); - rodata = c; - xdefine("rodata", SRODATA, c); - for(i=0; ihash) { - if(s->type != SRODATA) - continue; - v = s->size; - while(v & 7) - v++; - s->value = c; - c += v; + + if(rosect) { + if(INITRND) + c = rnd(c, INITRND); + if(rosect->vaddr != c){ + rosect->vaddr = c; + goto start; + } + c += rosect->len; } - erodata = c; if(INITRND) { INITDAT = rnd(c, INITRND); @@ -156,8 +151,6 @@ loop: } xdefine("etext", STEXT, etext); - xdefine("rodata", SRODATA, rodata); - xdefine("erodata", SRODATA, erodata); if(debug['v']) Bprint(&bso, "etext = %llux\n", c); @@ -171,17 +164,34 @@ loop: segtext.len = INITDAT - INITTEXT + HEADR; segtext.filelen = textsize + HEADR; - sect = addsection(&segtext, ".text", 05); + sect = segtext.sect; sect->vaddr = INITTEXT; sect->len = etext - sect->vaddr; - - sect = addsection(&segtext, ".rodata", 04); - sect->vaddr = rodata; - sect->len = erodata - rodata; - + + // Adjust everything now that we know INITDAT. + // This will get simpler when everything is relocatable + // and we can run span before dodata. + segdata.vaddr += INITDAT; for(sect=segdata.sect; sect!=nil; sect=sect->next) sect->vaddr += INITDAT; + + xdefine("data", SBSS, INITDAT); + xdefine("edata", SBSS, INITDAT+segdata.filelen); + xdefine("end", SBSS, INITDAT+segdata.len); + + for(sym=datap; sym!=nil; sym=sym->next) { + switch(sym->type) { + case SELFDATA: + case SRODATA: + sym->value += rosect->vaddr; + break; + case SDATA: + case SBSS: + sym->value += INITDAT; + break; + } + } } void @@ -628,6 +638,8 @@ put8(vlong v) andptr += 8; } +static vlong vaddr(Adr*); + vlong symaddr(Sym *s) { @@ -640,7 +652,7 @@ symaddr(Sym *s) return vaddr(&a); } -vlong +static vlong vaddr(Adr *a) { int t; @@ -657,28 +669,16 @@ vaddr(Adr *a) s = a->sym; if(s != nil) { switch(s->type) { - case SUNDEF: - case STEXT: - case SCONST: - case SRODATA: - if(!s->reachable) - diag("unreachable symbol in vaddr - %s", s->name); - if((uvlong)s->value < (uvlong)INITTEXT) - v += INITTEXT; /* TO DO */ - v += s->value; - break; case SFIXED: v += s->value; break; case SMACHO: - if(!s->reachable) - sysfatal("unreachable symbol in vaddr - %s", s->name); - v += INITDAT + datsize + s->value; + v += INITDAT + segdata.filelen - dynptrsize + s->value; break; default: if(!s->reachable) diag("unreachable symbol in vaddr - %s", s->name); - v += INITDAT + s->value; + v += s->value; } } } diff --git a/src/cmd/6l/symtab.c b/src/cmd/6l/symtab.c index ef3e707e06..f2ffa269e3 100644 --- a/src/cmd/6l/symtab.c +++ b/src/cmd/6l/symtab.c @@ -177,28 +177,17 @@ genasmsym(void (*put)(char*, int, vlong, vlong, int, Sym*)) switch(s->type) { case SCONST: case SRODATA: - if(!s->reachable) - continue; - put(s->name, 'D', s->value, s->size, s->version, s->gotype); - continue; - case SDATA: case SELFDATA: if(!s->reachable) continue; - put(s->name, 'D', s->value+INITDAT, s->size, s->version, s->gotype); - continue; - - case SMACHO: - if(!s->reachable) - continue; - put(s->name, 'D', s->value+INITDAT+segdata.len, s->size, s->version, s->gotype); + put(s->name, 'D', symaddr(s), s->size, s->version, s->gotype); continue; case SBSS: if(!s->reachable) continue; - put(s->name, 'B', s->value+INITDAT, s->size, s->version, s->gotype); + put(s->name, 'B', symaddr(s), s->size, s->version, s->gotype); continue; case SFIXED: diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile index cdaef22b53..f814ab3993 100644 --- a/src/cmd/8l/Makefile +++ b/src/cmd/8l/Makefile @@ -9,6 +9,7 @@ TARG=8l OFILES=\ asm.$O\ + data.$O\ dwarf.$O\ elf.$O\ enam.$O\ diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index b76d731e1e..99d5b61563 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -55,13 +55,8 @@ entryvalue(void) s = lookup(a, 0); if(s->type == 0) return INITTEXT; - switch(s->type) { - case STEXT: - break; - case SDATA: - default: + if(s->type != STEXT) diag("entry not text: %s", s->name); - } return s->value; } @@ -104,133 +99,13 @@ vputl(uvlong l) lputl(l); } -void -strnput(char *s, int n) -{ - for(; *s && n > 0; s++) { - cput(*s); - n--; - } - while(n > 0) { - cput(0); - n--; - } -} - -vlong -addstring(Sym *s, char *str) -{ - int n, m; - vlong r; - Prog *p; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->size; - n = strlen(str)+1; - if(strcmp(s->name, ".shstrtab") == 0) - elfsetstring(str, r); - while(n > 0) { - m = n; - if(m > sizeof(p->to.scon)) - m = sizeof(p->to.scon); - p = newdata(s, s->size, m, D_EXTERN); - p->to.type = D_SCONST; - memmove(p->to.scon, str, m); - s->size += m; - str += m; - n -= m; - } - return r; -} - -vlong -adduintxx(Sym *s, uint64 v, int wid) -{ - vlong r; - Prog *p; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->size; - p = newdata(s, s->size, wid, D_EXTERN); - s->size += wid; - p->to.type = D_CONST; - p->to.offset = v; - return r; -} - -vlong -adduint8(Sym *s, uint8 v) -{ - return adduintxx(s, v, 1); -} - -vlong -adduint16(Sym *s, uint16 v) -{ - return adduintxx(s, v, 2); -} - -vlong -adduint32(Sym *s, uint32 v) -{ - return adduintxx(s, v, 4); -} - -vlong -adduint64(Sym *s, uint64 v) -{ - return adduintxx(s, v, 8); -} - -vlong -addaddr(Sym *s, Sym *t) -{ - vlong r; - Prog *p; - enum { Ptrsize = 4 }; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->size; - p = newdata(s, s->size, Ptrsize, D_EXTERN); - s->size += Ptrsize; - p->to.type = D_ADDR; - p->to.index = D_EXTERN; - p->to.offset = 0; - p->to.sym = t; - return r; -} - -vlong -addsize(Sym *s, Sym *t) -{ - vlong r; - Prog *p; - enum { Ptrsize = 4 }; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->size; - p = newdata(s, s->size, Ptrsize, D_EXTERN); - s->size += Ptrsize; - p->to.type = D_SIZE; - p->to.index = D_EXTERN; - p->to.offset = 0; - p->to.sym = t; - return r; -} - vlong datoff(vlong addr) { if(addr >= segdata.vaddr) return addr - segdata.vaddr + segdata.fileoff; + if(addr >= segtext.vaddr) + return addr - segtext.vaddr + segtext.fileoff; diag("datoff %#llx", addr); return 0; } @@ -284,7 +159,9 @@ doelf(void) /* predefine strings we need for section headers */ shstrtab = lookup(".shstrtab", 0); + shstrtab->type = SELFDATA; shstrtab->reachable = 1; + elfstr[ElfStrEmpty] = addstring(shstrtab, ""); elfstr[ElfStrText] = addstring(shstrtab, ".text"); elfstr[ElfStrData] = addstring(shstrtab, ".data"); @@ -458,7 +335,7 @@ asmb(void) Prog *p; int32 v, magic; int a, dynsym; - uint32 va, fo, w, symo, startva, machlink, erodata; + uint32 va, fo, w, symo, startva, machlink; uchar *op1; ulong expectpc; ElfEhdr *eh; @@ -533,20 +410,8 @@ asmb(void) cflush(); /* output read-only data in text segment */ - if(HEADTYPE == 8) { - // Native Client - sect = segrodata.sect; - segrodata.fileoff = seek(cout, 0, 1); - } else - sect = segtext.sect->next; - - erodata = sect->vaddr + sect->len; - for(v = pc; v < erodata; v += sizeof(buf)-Dbufslop) { - if(erodata-v > sizeof(buf)-Dbufslop) - datblk(v, sizeof(buf)-Dbufslop, 1); - else - datblk(v, erodata-v, 1); - } + sect = segtext.sect->next; + datblk(pc, sect->vaddr + sect->len - pc); switch(HEADTYPE) { default: @@ -597,12 +462,7 @@ asmb(void) Bflush(&bso); segdata.fileoff = seek(cout, 0, 1); - for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) { - if(datsize-v > sizeof(buf)-Dbufslop) - datblk(v, sizeof(buf)-Dbufslop, 0); - else - datblk(v, datsize-v, 0); - } + datblk(INITDAT, segdata.filelen); machlink = 0; if(HEADTYPE == 6) @@ -621,25 +481,25 @@ asmb(void) if(iself) goto Elfsym; case 0: - seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0); + seek(cout, rnd(HEADR+textsize, 8192)+segdata.filelen, 0); break; case 1: - seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0); + seek(cout, rnd(HEADR+textsize, INITRND)+segdata.filelen, 0); break; case 2: - seek(cout, HEADR+textsize+datsize, 0); + seek(cout, HEADR+textsize+segdata.filelen, 0); break; case 3: case 4: debug['s'] = 1; - symo = HEADR+textsize+datsize; + symo = HEADR+textsize+segdata.filelen; break; case 6: - symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND)+machlink; + symo = rnd(HEADR+textsize, INITRND)+rnd(segdata.filelen, INITRND)+machlink; break; Elfsym: case 10: - symo = rnd(HEADR+textsize, INITRND)+datsize; + symo = rnd(HEADR+textsize, INITRND)+segdata.filelen; symo = rnd(symo, INITRND); break; } @@ -679,17 +539,17 @@ asmb(void) case 0: /* garbage */ lput(0x160L<<16); /* magic and sections */ lput(0L); /* time and date */ - lput(rnd(HEADR+textsize, 4096)+datsize); + lput(rnd(HEADR+textsize, 4096)+segdata.filelen); lput(symsize); /* nsyms */ lput((0x38L<<16)|7L); /* size of optional hdr and flags */ lput((0413<<16)|0437L); /* magic and version */ lput(rnd(HEADR+textsize, 4096)); /* sizes */ - lput(datsize); - lput(bsssize); + lput(segdata.filelen); + lput(segdata.len - segdata.filelen); lput(entryvalue()); /* va of entry */ lput(INITTEXT-HEADR); /* va of base of text */ lput(INITDAT); /* va of base of data */ - lput(INITDAT+datsize); /* va of base of bss */ + lput(INITDAT+segdata.filelen); /* va of base of bss */ lput(~0L); /* gp reg mask */ lput(0L); lput(0L); @@ -712,8 +572,8 @@ asmb(void) */ lputl(0x10b); /* magic, version stamp */ lputl(rnd(textsize, INITRND)); /* text sizes */ - lputl(datsize); /* data sizes */ - lputl(bsssize); /* bss sizes */ + lputl(segdata.filelen); /* data sizes */ + lputl(segdata.len - segdata.filelen); /* bss sizes */ lput(entryvalue()); /* va of entry */ lputl(INITTEXT); /* text start */ lputl(INITDAT); /* data start */ @@ -735,7 +595,7 @@ asmb(void) s8put(".data"); lputl(INITDAT); /* pa */ lputl(INITDAT); /* va */ - lputl(datsize); /* data size */ + lputl(segdata.filelen); /* data size */ lputl(HEADR+textsize); /* file offset */ lputl(0); /* relocation */ lputl(0); /* line numbers */ @@ -745,9 +605,9 @@ asmb(void) * bss section header */ s8put(".bss"); - lputl(INITDAT+datsize); /* pa */ - lputl(INITDAT+datsize); /* va */ - lputl(bsssize); /* bss size */ + lputl(INITDAT+segdata.filelen); /* pa */ + lputl(INITDAT+segdata.filelen); /* va */ + lputl(segdata.len - segdata.filelen); /* bss size */ lputl(0); /* file offset */ lputl(0); /* relocation */ lputl(0); /* line numbers */ @@ -760,9 +620,9 @@ asmb(void) lputl(0); /* pa */ lputl(0); /* va */ lputl(symsize+lcsize); /* comment size */ - lputl(HEADR+textsize+datsize); /* file offset */ - lputl(HEADR+textsize+datsize); /* offset of syms */ - lputl(HEADR+textsize+datsize+symsize);/* offset of line numbers */ + lputl(HEADR+textsize+segdata.filelen); /* file offset */ + lputl(HEADR+textsize+segdata.filelen); /* offset of syms */ + lputl(HEADR+textsize+segdata.filelen+symsize);/* offset of line numbers */ lputl(0); /* relocation, line numbers */ lputl(0x200); /* flags comment only */ break; @@ -770,8 +630,8 @@ asmb(void) magic = 4*11*11+7; lput(magic); /* magic */ lput(textsize); /* sizes */ - lput(datsize); - lput(bsssize); + lput(segdata.filelen); + lput(segdata.len - segdata.filelen); lput(symsize); /* nsyms */ lput(entryvalue()); /* va of entry */ lput(spsize); /* sp offsets */ @@ -782,7 +642,7 @@ asmb(void) break; case 4: /* fake MS-DOS .EXE */ - v = rnd(HEADR+textsize, INITRND)+datsize; + v = rnd(HEADR+textsize, INITRND)+segdata.filelen; wputl(0x5A4D); /* 'MZ' */ wputl(v % 512); /* bytes in last page */ wputl(rnd(v, 512)/512); /* total number of pages */ @@ -1072,216 +932,6 @@ cpos(void) return seek(cout, 0, 1) + sizeof(buf.cbuf) - cbc; } -void -datblk(int32 s, int32 n, int32 rodata) -{ - Prog *p; - char *cast; - int32 l, fl, j; - int i, c; - Adr *a; - int32 base; - - base = INITDAT; - if(rodata) - base = 0; - - memset(buf.dbuf, 0, n+Dbufslop); - for(p = datap; p != P; p = p->link) { - a = &p->from; - if(rodata != (a->sym->type == SRODATA)) - continue; - - l = a->sym->value + a->offset - s; - if(l >= n) - continue; - - c = a->scale; - i = 0; - if(l < 0) { - if(l+c <= 0) - continue; - i = -l; - l = 0; - } - - curp = p; - if(!a->sym->reachable) - diag("unreachable symbol in datblk - %s", a->sym->name); - if(a->sym->type == SMACHO) - continue; - - for(j=l+(c-i)-1; j>=l; j--) - if(buf.dbuf[j]) { - print("%P\n", p); - diag("multiple initialization"); - break; - } - switch(p->to.type) { - case D_FCONST: - switch(c) { - default: - case 4: - fl = ieeedtof(&p->to.ieee); - cast = (char*)&fl; - for(; ito.ieee; - for(; ito.scon[i]; - l++; - } - break; - - default: - fl = p->to.offset; - if(p->to.type == D_SIZE) - fl += p->to.sym->size; - if(p->to.type == D_ADDR) { - if(p->to.index != D_STATIC && p->to.index != D_EXTERN) - diag("DADDR type%P", p); - if(p->to.sym) { - if(p->to.sym->type == Sxxx) { - cursym = p->from.sym; - diag("missing symbol %s", p->to.sym->name); - cursym = nil; - } - fl += p->to.sym->value; - if(p->to.sym->type != STEXT && p->to.sym->type != SRODATA) - fl += INITDAT; - } - } - cast = (char*)&fl; - switch(c) { - default: - diag("bad nuxi %d %d\n%P", c, i, curp); - break; - case 1: - for(; ilink) { - a = &p->from; - if(rodata != (a->sym->type == SRODATA)) - continue; - - l = a->sym->value + a->offset - s; - if(l < 0 || l >= n) - continue; - - c = a->scale; - i = 0; - - switch(p->to.type) { - case D_FCONST: - switch(c) { - default: - case 4: - fl = ieeedtof(&p->to.ieee); - cast = (char*)&fl; - Bprint(&bso, pcstr, l+s+base); - for(j=0; jto.ieee; - Bprint(&bso, pcstr, l+s+base); - for(j=0; jto.scon[j] & 0xff); - Bprint(&bso, "\t%P\n", p); - break; - - default: - fl = p->to.offset; - if(p->to.type == D_SIZE) - fl += p->to.sym->size; - if(p->to.type == D_ADDR) { - if(p->to.index != D_STATIC && p->to.index != D_EXTERN) - diag("DADDR type%P", p); - if(p->to.sym) { - fl += p->to.sym->value; - if(p->to.sym->type != STEXT && p->to.sym->type != SRODATA) - fl += INITDAT; - } - } - cast = (char*)&fl; - switch(c) { - default: - diag("bad nuxi %d %d\n%P", c, i, p); - break; - case 1: - Bprint(&bso, pcstr, l+s+base); - for(j=0; jfrom.sym; - if(s != S && s->dupok) { + if(s->dupok) { // if(debug['v']) // Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); goto loop; } - if(s != S) { - p->dlink = s->data; - s->data = p; - if(s->file == nil) - s->file = pn; - else if(s->file != pn) { - diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); - errorexit(); - } + if(s->file == nil) + s->file = pn; + else if(s->file != pn) { + diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); + errorexit(); } - if(edatap == P) - datap = p; - else - edatap->link = p; - edatap = p; - p->link = P; + savedata(s, p); + unmal(p, sizeof *p); goto loop; case AGOK: @@ -686,21 +673,9 @@ loop: sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); s = lookup(literal, 0); if(s->type == 0) { - s->type = SBSS; - s->size = 4; - t = prg(); - t->as = ADATA; - t->line = p->line; - t->from.type = D_EXTERN; - t->from.sym = s; - t->from.scale = 4; - t->to = p->from; - if(edatap == P) - datap = t; - else - edatap->link = t; - edatap = t; - t->link = P; + s->type = SDATA; + adduint32(s, ieeedtof(&p->from.ieee)); + s->reachable = 0; } p->from.type = D_EXTERN; p->from.sym = s; @@ -725,21 +700,10 @@ loop: p->from.ieee.l, p->from.ieee.h); s = lookup(literal, 0); if(s->type == 0) { - s->type = SBSS; - s->size = 8; - t = prg(); - t->as = ADATA; - t->line = p->line; - t->from.type = D_EXTERN; - t->from.sym = s; - t->from.scale = 8; - t->to = p->from; - if(edatap == P) - datap = t; - else - edatap->link = t; - edatap = t; - t->link = P; + s->type = SDATA; + adduint32(s, p->from.ieee.l); + adduint32(s, p->from.ieee.h); + s->reachable = 0; } p->from.type = D_EXTERN; p->from.sym = s; diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c index bebb0d45e8..329a87094b 100644 --- a/src/cmd/8l/pass.c +++ b/src/cmd/8l/pass.c @@ -42,148 +42,6 @@ enum StackBig = 4096, }; -void -dodata(void) -{ - int i; - Sym *s; - Prog *p; - int32 t, u; - Section *sect; - - if(debug['v']) - Bprint(&bso, "%5.2f dodata\n", cputime()); - Bflush(&bso); - - segdata.rwx = 06; - segdata.vaddr = 0; /* span will += INITDAT */ - - for(p = datap; p != P; p = p->link) { - s = p->from.sym; - if(s->type == SBSS) - s->type = SDATA; - if(s->type != SDATA && s->type != SELFDATA && s->type != SRODATA) - diag("%s: initialize non-data (%d)\n%P", - s->name, s->type, p); - t = p->from.offset + p->width; - if(t > s->size) - diag("%s: initialize bounds (%lld)\n%P", - s->name, s->size, p); - } - - /* allocate elf guys - must be segregated from real data */ - datsize = 0; - for(i=0; ihash) { - if(!s->reachable) - continue; - if(s->type != SELFDATA) - continue; - t = rnd(s->size, 4); - s->size = t; - s->value = datsize; - datsize += t; - } - elfdatsize = datsize; - - sect = addsection(&segdata, ".data", 06); - sect->vaddr = datsize; - - /* allocate small guys */ - for(i=0; ihash) { - if(!s->reachable) - continue; - if(s->type != SDATA) - if(s->type != SBSS) - continue; - t = s->size; - if(t == 0 && s->name[0] != '.') { - diag("%s: no size", s->name); - t = 1; - } - t = rnd(t, 4); - s->size = t; - if(t > MINSIZ) - continue; - s->value = datsize; - datsize += t; - s->type = SDATA1; - } - - /* allocate the rest of the data */ - for(i=0; ihash) { - if(s->type != SDATA) { - if(s->type == SDATA1) - s->type = SDATA; - continue; - } - t = s->size; - 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; ihash) { - if(!s->reachable) - continue; - if(s->type != SBSS) - continue; - t = s->value; - if(t > u) - continue; - u -= t; - s->size = t; - s->value = datsize; - s->type = SDATA; - datsize += t; - } - datsize += u; - } - - if(dynptrsize > 0) { - /* dynamic pointer section between data and bss */ - datsize = rnd(datsize, 4); - } - sect->len = datsize - sect->vaddr; - - /* now the bss */ - sect = addsection(&segdata, ".bss", 06); - sect->vaddr = datsize; - bsssize = 0; - for(i=0; ihash) { - if(!s->reachable) - continue; - if(s->type != SBSS) - continue; - t = s->size; - s->value = bsssize + dynptrsize + datsize; - bsssize += t; - } - sect->len = bsssize; - - segdata.len = datsize+bsssize; - segdata.filelen = datsize; - - xdefine("data", SBSS, 0); - xdefine("edata", SBSS, datsize); - xdefine("end", SBSS, dynptrsize + bsssize + datsize); - - if(debug['s'] || HEADTYPE == 8) - xdefine("symdat", SFIXED, 0); - else - xdefine("symdat", SFIXED, SYMDATVA); -} - Prog* brchain(Prog *p) { @@ -279,7 +137,7 @@ loop: continue; } if(nofollow(a) || pushpop(a)) - break; + break; // NOTE(rsc): arm does goto copy if(q->pcond == P || q->pcond->mark) continue; if(a == ACALL || a == ALOOP) @@ -378,28 +236,6 @@ relinv(int a) return a; } -void -doinit(void) -{ - Sym *s; - Prog *p; - int x; - - for(p = datap; p != P; p = p->link) { - x = p->to.type; - if(x != D_EXTERN && x != D_STATIC) - continue; - s = p->to.sym; - if(s->type == 0 || s->type == SXREF) - diag("undefined %s initializer of %s", - s->name, p->from.sym->name); - p->to.offset += s->value; - p->to.type = D_CONST; - if(s->type == SDATA || s->type == SBSS) - p->to.offset += INITDAT; - } -} - void patch(void) { @@ -790,26 +626,3 @@ undef(void) if(s->type == SXREF) diag("%s: not defined", s->name); } - -Prog* -newdata(Sym *s, int o, int w, int t) -{ - Prog *p; - - p = prg(); - if(edatap == P) - datap = p; - else - edatap->link = p; - edatap = p; - p->as = ADATA; - p->width = w; - p->from.scale = w; - p->from.type = t; - p->from.sym = s; - p->from.offset = o; - p->to.type = D_CONST; - p->dlink = s->data; - s->data = p; - return p; -} diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c index a5102e8911..42738e34ff 100644 --- a/src/cmd/8l/span.c +++ b/src/cmd/8l/span.c @@ -37,10 +37,10 @@ void span(void) { Prog *p, *q; - int32 i, v, c, idat, etext, rodata, erodata; + int32 v, c, idat, etext; int m, n, again; Sym *s; - Section *sect; + Section *sect, *rosect; xdefine("etext", STEXT, 0L); xdefine("rodata", SRODATA, 0L); @@ -72,8 +72,10 @@ span(void) } } } - n = 0; + + rosect = segtext.sect->next; + start: do{ again = 0; @@ -115,24 +117,15 @@ start: etext = c; c += textpad; - /* - * allocate read-only data to the text segment. - */ - if(HEADTYPE == 8) - c = rnd(c, INITRND); - c = rnd(c, 8); - rodata = c; - for(i=0; ihash) { - if(s->type != SRODATA) - continue; - v = s->size; - while(v & 3) - v++; - s->value = c; - c += v; + if(rosect) { + if(INITRND) + c = rnd(c, INITRND); + if(rosect->vaddr != c){ + rosect->vaddr = c; + goto start; + } + c += rosect->len; } - erodata = c; if(INITRND) { INITDAT = rnd(c, INITRND); @@ -143,8 +136,6 @@ start: } xdefine("etext", STEXT, etext); - xdefine("rodata", SRODATA, rodata); - xdefine("erodata", SRODATA, erodata); if(debug['v']) Bprint(&bso, "etext = %ux\n", c); @@ -154,37 +145,40 @@ start: textsize = c - INITTEXT; segtext.rwx = 05; - if(HEADTYPE == 8) { - segtext.vaddr = INITTEXT; - segtext.len = rodata - INITTEXT; - segtext.fileoff = HEADR; - segtext.filelen = etext - INITTEXT; - - segrodata.rwx = 04; - segrodata.vaddr = rodata; - segrodata.len = erodata - rodata; - segrodata.filelen = segrodata.len; - } else { - segtext.vaddr = INITTEXT - HEADR; - segtext.len = INITDAT - INITTEXT + HEADR; - segtext.fileoff = 0; - segtext.filelen = segtext.len; - } - - sect = addsection(&segtext, ".text", 05); + segtext.vaddr = INITTEXT - HEADR; + segtext.len = INITDAT - INITTEXT + HEADR; + segtext.filelen = textsize + HEADR; + + sect = segtext.sect; sect->vaddr = INITTEXT; sect->len = etext - sect->vaddr; - - if(HEADTYPE == 8) - sect = addsection(&segrodata, ".rodata", 04); - else - sect = addsection(&segtext, ".rodata", 04); - sect->vaddr = rodata; - sect->len = erodata - rodata; + + // Adjust everything now that we know INITDAT. + // This will get simpler when everything is relocatable + // and we can run span before dodata. segdata.vaddr += INITDAT; for(sect=segdata.sect; sect!=nil; sect=sect->next) sect->vaddr += INITDAT; + + xdefine("data", SBSS, INITDAT); + xdefine("edata", SBSS, INITDAT+segdata.filelen); + xdefine("end", SBSS, INITDAT+segdata.len); + + for(s=datap; s!=nil; s=s->next) { + switch(s->type) { + case SELFDATA: + case SRODATA: + s->value += rosect->vaddr; + break; + case SDATA: + case SBSS: + s->value += INITDAT; + break; + } + } + + // TODO(rsc): if HEADTYPE == NACL fix up segrodata. } void @@ -484,6 +478,8 @@ put4(int32 v) andptr += 4; } +static int32 vaddr(Adr*); + int32 symaddr(Sym *s) { @@ -496,7 +492,7 @@ symaddr(Sym *s) return vaddr(&a); } -int32 +static int32 vaddr(Adr *a) { int t; @@ -513,25 +509,17 @@ vaddr(Adr *a) s = a->sym; if(s != nil) { switch(s->type) { - case STEXT: - case SCONST: - case SRODATA: - if(!s->reachable) - sysfatal("unreachable symbol in vaddr - %s", s->name); + case SFIXED: v += s->value; break; case SMACHO: - if(!s->reachable) - sysfatal("unreachable symbol in vaddr - %s", s->name); - v += INITDAT + datsize + s->value; - break; - case SFIXED: - v += s->value; + v += INITDAT + segdata.filelen - dynptrsize + s->value; break; default: if(!s->reachable) sysfatal("unreachable symbol in vaddr - %s", s->name); - v += INITDAT + s->value; + v += s->value; + break; } } } diff --git a/src/cmd/8l/symtab.c b/src/cmd/8l/symtab.c index 89a6457c44..be8636a2d5 100644 --- a/src/cmd/8l/symtab.c +++ b/src/cmd/8l/symtab.c @@ -104,22 +104,17 @@ asmsym(void) switch(s->type) { case SCONST: case SRODATA: - if(!s->reachable) - continue; - putsymb(s->name, 'D', s->value, s->version, s->gotype); - continue; - case SDATA: case SELFDATA: if(!s->reachable) continue; - putsymb(s->name, 'D', s->value+INITDAT, s->version, s->gotype); + putsymb(s->name, 'D', symaddr(s), s->version, s->gotype); continue; case SMACHO: if(!s->reachable) continue; - putsymb(s->name, 'D', s->value+INITDAT+datsize+bsssize, s->version, s->gotype); + putsymb(s->name, 'D', s->value+INITDAT+segdata.filelen-dynptrsize, s->version, s->gotype); continue; case SBSS: diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c new file mode 100644 index 0000000000..353277a74d --- /dev/null +++ b/src/cmd/ld/data.c @@ -0,0 +1,641 @@ +// Inferno utils/8l/asm.c +// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Data layout and relocation. + +#include "l.h" +#include "../ld/lib.h" +#include "../ld/elf.h" + +/* + * divide-and-conquer list-link + * sort of Sym* structures. + * Used for the data block. + */ +int +datcmp(Sym *s1, Sym *s2) +{ + if(s1->type != s2->type) + return (int)s1->type - (int)s2->type; + if(s1->size != s2->size) { + if(s1->size < s2->size) + return -1; + return +1; + } + return strcmp(s1->name, s2->name); +} + +Sym* +datsort(Sym *l) +{ + Sym *l1, *l2, *le; + + if(l == 0 || l->next == 0) + return l; + + l1 = l; + l2 = l; + for(;;) { + l2 = l2->next; + if(l2 == 0) + break; + l2 = l2->next; + if(l2 == 0) + break; + l1 = l1->next; + } + + l2 = l1->next; + l1->next = 0; + l1 = datsort(l); + l2 = datsort(l2); + + /* set up lead element */ + if(datcmp(l1, l2) < 0) { + l = l1; + l1 = l1->next; + } else { + l = l2; + l2 = l2->next; + } + le = l; + + for(;;) { + if(l1 == 0) { + while(l2) { + le->next = l2; + le = l2; + l2 = l2->next; + } + le->next = 0; + break; + } + if(l2 == 0) { + while(l1) { + le->next = l1; + le = l1; + l1 = l1->next; + } + break; + } + if(datcmp(l1, l2) < 0) { + le->next = l1; + le = l1; + l1 = l1->next; + } else { + le->next = l2; + le = l2; + l2 = l2->next; + } + } + le->next = 0; + return l; +} + +Reloc* +addrel(Sym *s) +{ + if(s->nr >= s->maxr) { + if(s->maxr == 0) + s->maxr = 4; + else + s->maxr <<= 1; + s->r = realloc(s->r, s->maxr*sizeof s->r[0]); + if(s->r == 0) { + diag("out of memory"); + errorexit(); + } + memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]); + } + return &s->r[s->nr++]; +} + +void +relocsym(Sym *s) +{ + Reloc *r; + Prog p; + int32 i, off, siz, fl; + vlong o; + uchar *cast; + + memset(&p, 0, sizeof p); + for(r=s->r; rr+s->nr; r++) { + off = r->off; + siz = r->siz; + switch(r->type) { + default: + diag("unknown reloc %d", r->type); + case D_ADDR: + o = symaddr(r->sym); + break; + case D_SIZE: + o = r->sym->size; + break; + } + o += r->add; + switch(siz) { + default: + diag("bad reloc size %d", siz); + case 4: + fl = o; + cast = (uchar*)&fl; + for(i=0; i<4; i++) + s->p[off+i] = cast[inuxi4[i]]; + break; + case 8: + cast = (uchar*)&o; + for(i=0; i<8; i++) + s->p[off+i] = cast[inuxi8[i]]; + break; + } + } +} + +void +reloc(void) +{ + Sym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f reloc\n", cputime()); + Bflush(&bso); + + for(s=textp; s!=S; s=s->next) + relocsym(s); + for(s=datap; s!=S; s=s->next) { + if(!s->reachable) + diag("unerachable? %s", s->name); + relocsym(s); + } +} + +void +symgrow(Sym *s, int32 siz) +{ + if(s->np >= siz) + return; + + if(s->maxp < siz) { + if(s->maxp == 0) + s->maxp = 8; + while(s->maxp < siz) + s->maxp <<= 1; + s->p = realloc(s->p, s->maxp); + if(s->p == nil) { + diag("out of memory"); + errorexit(); + } + memset(s->p+s->np, 0, s->maxp-s->np); + } + s->np = siz; +} + +void +savedata(Sym *s, Prog *p) +{ + int32 off, siz, i, fl; + uchar *cast; + vlong o; + Reloc *r; + + off = p->from.offset; + siz = p->datasize; + symgrow(s, off+siz); + + switch(p->to.type) { + default: + diag("bad data: %P", p); + break; + + case D_FCONST: + switch(siz) { + default: + case 4: + fl = ieeedtof(&p->to.ieee); + cast = (uchar*)&fl; + for(i=0; i<4; i++) + s->p[off+i] = cast[fnuxi4[i]]; + break; + case 8: + cast = (uchar*)&p->to.ieee; + for(i=0; i<8; i++) + s->p[off+i] = cast[fnuxi8[i]]; + break; + } + break; + + case D_SCONST: + for(i=0; ip[off+i] = p->to.scon[i]; + break; + + case D_CONST: + if(p->to.sym) + goto Addr; + o = p->to.offset; + fl = o; + cast = (uchar*)&fl; + switch(siz) { + default: + diag("bad nuxi %d\n%P", siz, p); + break; + case 1: + s->p[off] = cast[inuxi1[0]]; + break; + case 2: + for(i=0; i<2; i++) + s->p[off+i] = cast[inuxi2[i]]; + break; + case 4: + for(i=0; i<4; i++) + s->p[off+i] = cast[inuxi4[i]]; + break; + case 8: + cast = (uchar*)&o; + for(i=0; i<8; i++) + s->p[off+i] = cast[inuxi8[i]]; + break; + } + break; + + case D_ADDR: + case D_SIZE: + Addr: + r = addrel(s); + r->off = off; + r->siz = siz; + r->sym = p->to.sym; + r->type = p->to.type; + if(r->type != D_SIZE) + r->type = D_ADDR; + r->add = p->to.offset; + break; + } +} + +static void +blk(Sym *allsym, int32 addr, int32 size) +{ + Sym *sym; + int32 eaddr; + uchar *p, *ep; + + for(sym = allsym; sym != nil; sym = sym->next) + if(sym->value >= addr) + break; + + eaddr = addr+size; + for(; sym != nil; sym = sym->next) { + if(sym->value >= eaddr) + break; + if(sym->value < addr) { + diag("phase error: addr=%#llx but sym=%#llx type=%d", addr, sym->value, sym->type); + errorexit(); + } + cursym = sym; + for(; addr < sym->value; addr++) + cput(0); + p = sym->p; + ep = p + sym->np; + while(p < ep) + cput(*p++); + addr += sym->np; + for(; addr < sym->value+sym->size; addr++) + cput(0); + if(addr != sym->value+sym->size) { + diag("phase error: addr=%#llx value+size=%#llx", addr, sym->value+sym->size); + errorexit(); + } + } + + for(; addr < eaddr; addr++) + cput(0); + cflush(); +} + +void +datblk(int32 addr, int32 size) +{ + Sym *sym; + int32 eaddr; + uchar *p, *ep; + + blk(datap, addr, size); + + /* again for printing */ + if(!debug['a']) + return; + + for(sym = datap; sym != nil; sym = sym->next) + if(sym->value >= addr) + break; + + eaddr = addr + size; + for(; sym != nil; sym = sym->next) { + if(sym->value >= eaddr) + break; + if(addr < sym->value) { + Bprint(&bso, "%-20s %.8ux|", "(pre-pad)", addr); + for(; addr < sym->value; addr++) + Bprint(&bso, " %.2ux", 0); + Bprint(&bso, "\n"); + } + Bprint(&bso, "%-20s %.8ux|", sym->name, addr); + p = sym->p; + ep = p + sym->np; + while(p < ep) + Bprint(&bso, " %.2ux", *p++); + addr += sym->np; + for(; addr < sym->value+sym->size; addr++) + Bprint(&bso, " %.2ux", 0); + Bprint(&bso, "\n"); + } + + if(addr < eaddr) { + Bprint(&bso, "%-20s %.8ux|", "(post-pad)", addr); + for(; addr < eaddr; addr++) + Bprint(&bso, " %.2ux", 0); + } +} + +void +strnput(char *s, int n) +{ + for(; *s && n > 0; s++) { + cput(*s); + n--; + } + while(n > 0) { + cput(0); + n--; + } +} + +vlong +addstring(Sym *s, char *str) +{ + int n; + int32 r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + r = s->size; + n = strlen(str)+1; + if(strcmp(s->name, ".shstrtab") == 0) + elfsetstring(str, r); + symgrow(s, r+n); + memmove(s->p+r, str, n); + s->size += n; + return r; +} + +vlong +adduintxx(Sym *s, uint64 v, int wid) +{ + int32 i, r, fl; + vlong o; + uchar *cast; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + r = s->size; + s->size += wid; + symgrow(s, s->size); + fl = v; + cast = (uchar*)&fl; + switch(wid) { + case 1: + s->p[r] = cast[inuxi1[0]]; + break; + case 2: + for(i=0; i<2; i++) + s->p[r+i] = cast[inuxi2[i]]; + break; + case 4: + for(i=0; i<4; i++) + s->p[r+i] = cast[inuxi4[i]]; + break; + case 8: + o = v; + cast = (uchar*)&o; + for(i=0; i<8; i++) + s->p[r+i] = cast[inuxi8[i]]; + break; + } + return r; +} + +vlong +adduint8(Sym *s, uint8 v) +{ + return adduintxx(s, v, 1); +} + +vlong +adduint16(Sym *s, uint16 v) +{ + return adduintxx(s, v, 2); +} + +vlong +adduint32(Sym *s, uint32 v) +{ + return adduintxx(s, v, 4); +} + +vlong +adduint64(Sym *s, uint64 v) +{ + return adduintxx(s, v, 8); +} + +vlong +addaddr(Sym *s, Sym *t) +{ + vlong i; + Reloc *r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + i = s->size; + s->size += PtrSize; + symgrow(s, s->size); + r = addrel(s); + r->sym = t; + r->off = i; + r->siz = PtrSize; + r->type = D_ADDR; + return i; +} + +vlong +addsize(Sym *s, Sym *t) +{ + vlong i; + Reloc *r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + i = s->size; + s->size += PtrSize; + symgrow(s, s->size); + r = addrel(s); + r->sym = t; + r->off = i; + r->siz = PtrSize; + r->type = D_SIZE; + return i; +} + +void +dodata(void) +{ + int32 h, t, datsize; + Section *sect; + Sym *s, *last; + + if(debug['v']) + Bprint(&bso, "%5.2f dodata\n", cputime()); + Bflush(&bso); + + segdata.rwx = 06; + segdata.vaddr = 0; /* span will += INITDAT */ + + last = nil; + datap = nil; + for(h=0; hhash){ + if(!s->reachable) + continue; + if(STEXT < s->type && s->type < SXREF) { + if(last == nil) + datap = s; + else + last->next = s; + s->next = nil; + last = s; + } + } + } + + for(s = datap; s != nil; s = s->next) { + if(s->np > 0 && s->type == SBSS) // TODO: necessary? + s->type = SDATA; + if(s->np > s->size) + diag("%s: initialize bounds (%lld < %d)", + s->name, s->size, s->np); + } + datap = datsort(datap); + + /* + * allocate data sections. list is sorted by type, + * so we can just walk it for each piece we want to emit. + */ + + sect = addsection(&segtext, ".text", 05); // set up for span TODO(rsc): clumsy + + /* read-only data */ + sect = addsection(&segtext, ".rodata", 06); + sect->vaddr = 0; + datsize = 0; + s = datap; + for(; s != nil && s->type < SDATA; s = s->next) { + s->type = SRODATA; + t = rnd(s->size, 4); + s->size = t; + s->value = datsize; + datsize += t; + } + sect->len = datsize - sect->vaddr; + + /* data */ + datsize = 0; + sect = addsection(&segdata, ".data", 06); + sect->vaddr = 0; + for(; s != nil && s->type < SBSS; s = s->next) { + s->type = SDATA; + t = s->size; + if(t == 0 && s->name[0] != '.') { + diag("%s: no size", s->name); + t = 1; + } + if(t & 1) + ; + else if(t & 2) + datsize = rnd(datsize, 2); + else if(t & 4) + datsize = rnd(datsize, 4); + else + datsize = rnd(datsize, 8); + s->value = datsize; + datsize += t; + } + sect->len = datsize - sect->vaddr; + segdata.filelen = datsize; + + /* bss */ + sect = addsection(&segdata, ".bss", 06); + sect->vaddr = datsize; + for(; s != nil; s = s->next) { + if(s->type != SBSS) { + cursym = s; + diag("unexpected symbol type %d", s->type); + } + t = s->size; + if(t & 1) + ; + else if(t & 2) + datsize = rnd(datsize, 2); + else if(t & 4) + datsize = rnd(datsize, 4); + else + datsize = rnd(datsize, 8); + s->size = t; + s->value = datsize; + datsize += t; + } + sect->len = datsize - sect->vaddr; + segdata.len = datsize; + + xdefine("data", SBSS, 0); + xdefine("edata", SBSS, segdata.filelen); + xdefine("end", SBSS, segdata.len); + + if(debug['s'] || HEADTYPE == 8) + xdefine("symdat", SFIXED, 0); + else + xdefine("symdat", SFIXED, SYMDATVA); +} + diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c index 3672d4cdca..aecbe8612a 100644 --- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -511,18 +511,6 @@ err: static int markdepth; -static void -markdata(Prog *p, Sym *s) -{ - markdepth++; - if(p != P && debug['v'] > 1) - Bprint(&bso, "%d markdata %s\n", markdepth, s->name); - for(; p != P; p=p->dlink) - if(p->to.sym) - mark(p->to.sym); - markdepth--; -} - static void marktext(Sym *s) { @@ -548,47 +536,19 @@ marktext(Sym *s) void mark(Sym *s) { + int i; + if(s == S || s->reachable) return; s->reachable = 1; if(s->text) marktext(s); - if(s->data) - markdata(s->data, s); + for(i=0; inr; i++) + mark(s->r[i].sym); if(s->gotype) mark(s->gotype); } -static void -sweeplist(Prog **first, Prog **last) -{ - int reachable; - Prog *p, *q; - - reachable = 1; - q = P; - for(p=*first; p != P; p=p->link) { - switch(p->as) { - case ATEXT: - case ADATA: - case AGLOBL: - reachable = p->from.sym->reachable; - } - if(reachable) { - if(q == P) - *first = p; - else - q->link = p; - q = p; - } - } - if(q == P) - *first = P; - else - q->link = P; - *last = q; -} - static char* morename[] = { @@ -680,7 +640,4 @@ deadcode(void) textp = nil; else last->next = nil; - - // remove dead data - sweeplist(&datap, &edatap); } diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index dae22f2816..49d398a3c5 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -775,8 +775,7 @@ mal(uint32 n) { void *v; - while(n & 7) - n++; + n = (n+7)&~7; if(n > NHUNK) { v = malloc(n); memset(v, 0, n); @@ -795,6 +794,16 @@ mal(uint32 n) return v; } +void +unmal(void *v, uint32 n) +{ + n = (n+7)&~7; + if(hunk - n == v) { + hunk -= n; + nhunk += n; + } +} + // Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync. /* * Convert raw string to the prefix that will be used in the symbol table. @@ -999,4 +1008,3 @@ mkfwd(void) } } } - diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index 8688a75b2c..f9557e3835 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -131,9 +131,24 @@ void mkfwd(void); char* expandpkg(char*, char*); void deadcode(void); void ewrite(int, void*, int); +Reloc* addrel(Sym*); +void datblk(int32, int32); +Sym* datsort(Sym*); +void reloc(void); +void savedata(Sym*, Prog*); +void symgrow(Sym*, int32); +vlong addstring(Sym*, char*); +vlong adduint32(Sym*, uint32); +vlong adduint64(Sym*, uint64); +vlong addaddr(Sym*, Sym*); +vlong addsize(Sym*, Sym*); +vlong adduint8(Sym*, uint8); +vlong adduint16(Sym*, uint16); +void strnput(char*, int); int pathchar(void); void* mal(uint32); +void unmal(void*, uint32); void mywhatsys(void); /* set by call to mywhatsys() */ diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c index b3f608c438..863fff3c35 100644 --- a/src/cmd/ld/macho.c +++ b/src/cmd/ld/macho.c @@ -411,13 +411,13 @@ domacholink(void) linkoff = 0; if(nlinkdata > 0 || nstrtab > 0) { - linkoff = rnd(HEADR+textsize, INITRND) + rnd(datsize, INITRND); + linkoff = rnd(HEADR+textsize, INITRND) + rnd(segdata.filelen - dynptrsize, INITRND); seek(cout, linkoff, 0); for(i = 0; ivalue; - if(s->type == SUNDEF) + if(s->type == SXREF) diag("export of undefined symbol %s", s->name); if (s->type != STEXT) val += INITDAT; @@ -492,25 +492,25 @@ asmbmacho(vlong symdatva, vlong symo) msect->flag = 0x400; /* flag - some instructions */ /* data */ - w = datsize+dynptrsize+bsssize; + w = segdata.len; ms = newMachoSeg("__DATA", 2+(dynptrsize>0)); ms->vaddr = va+v; ms->vsize = w; ms->fileoffset = v; - ms->filesize = datsize+dynptrsize; + ms->filesize = segdata.filelen; ms->prot1 = 7; ms->prot2 = 3; msect = newMachoSect(ms, "__data"); msect->addr = va+v; - msect->size = datsize; + msect->size = segdata.filelen - dynptrsize; msect->off = v; if(dynptrsize > 0) { msect = newMachoSect(ms, "__nl_symbol_ptr"); - msect->addr = va+v+datsize; + msect->addr = va+v+segdata.filelen - dynptrsize; msect->size = dynptrsize; - msect->off = v+datsize; + msect->off = v+segdata.filelen - dynptrsize; msect->align = 2; msect->flag = 6; /* section with nonlazy symbol pointers */ /* @@ -525,8 +525,8 @@ asmbmacho(vlong symdatva, vlong symo) } msect = newMachoSect(ms, "__bss"); - msect->addr = va+v+datsize+dynptrsize; - msect->size = bsssize; + msect->addr = va+v+segdata.filelen; + msect->size = segdata.len - segdata.filelen; msect->flag = 1; /* flag - zero fill */ switch(thechar) { @@ -554,7 +554,7 @@ asmbmacho(vlong symdatva, vlong symo) nsym = dynptrsize/ptrsize; ms = newMachoSeg("__LINKEDIT", 0); - ms->vaddr = va+v+rnd(datsize+dynptrsize+bsssize, INITRND); + ms->vaddr = va+v+rnd(segdata.len, INITRND); ms->vsize = nlinkdata+nstrtab; ms->fileoffset = linkoff; ms->filesize = nlinkdata+nstrtab; diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c index d3439abfb1..6faa515d30 100644 --- a/src/cmd/ld/pe.c +++ b/src/cmd/ld/pe.c @@ -86,7 +86,7 @@ pewrite(void) { int i, j; - write(cout, dosstub, sizeof dosstub); + ewrite(cout, dosstub, sizeof dosstub); strnput("PE", 4); for (i=0; iCharacteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; INITDAT = PEBASE+datsect->VirtualAddress; - bsssect = new_section(".bss", bsssize, 1); + bsssect = new_section(".bss", segdata.len - segdata.filelen, 1); bsssect->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; }