diff options
| -rw-r--r-- | amd64/isel.c | 2 | ||||
| -rw-r--r-- | c.c | 2 | ||||
| -rw-r--r-- | elf.c | 62 | ||||
| -rw-r--r-- | ir.c | 30 | ||||
| -rw-r--r-- | ir.h | 5 | ||||
| -rw-r--r-- | irdump.c | 2 | ||||
| -rw-r--r-- | obj.c | 5 |
7 files changed, 82 insertions, 26 deletions
diff --git a/amd64/isel.c b/amd64/isel.c index 0205313..4c0656a 100644 --- a/amd64/isel.c +++ b/amd64/isel.c @@ -29,7 +29,7 @@ fixarg(struct function *fn, union ref *r, struct instr *ins, struct block *blk, union { float f; int i; } pun = { con->f }; wr32le(data, pun.i); } - *r = mkdatref(siz, /*align*/siz, data, siz, /*deref*/1); + *r = mkdatref(NULL, siz, /*align*/siz, data, siz, /*deref*/1); } else if (in_range(op, Odiv, Ourem) && kisint(ins->cls)) goto DivImm; } else if (r->t == RICON && in_range(op, Odiv, Ourem) && kisint(ins->cls)) { @@ -1025,7 +1025,7 @@ expraddr(struct function *fn, const struct expr *ex) } break; case ESTRLIT: - return mkdatref(ex->s.n+1, /*align*/ 1, ex->s.p, ex->s.n, /*deref*/0); + return mkdatref(NULL, ex->s.n+1, /*align*/ 1, ex->s.p, ex->s.n, /*deref*/0); case EDEREF: return exprvalue(fn, ex->sub); case EGETF: @@ -15,6 +15,9 @@ struct reloc { uint off; vlong addend; }; +uchar dataalign = 1, rodataalign = 1, bssalign = 1; +uint nbss; +static vec_of(uchar) data, rodata; static uint ntextrel, nrodatarel, ndatarel; static vec_of(struct reloc) relocs; @@ -113,6 +116,49 @@ elfreloc(const char *sym, enum relockind kind, enum section section, uint off, v vpush(&relocs, ((struct reloc) { section, relktab[mctarg->isa][kind], snam, off, addend})); } +void +elfputdat(const struct irdat *dat) +{ + static const char zero[8]; + enum section s; + uint off; + uint ndat = dat->siz < 8 ? dat->siz : dat->dat.n; + uint nzr = dat->siz - ndat; + const uchar *d = dat->siz < 8 ? dat->sdat : dat->dat.p; + + assert(dat->siz); + if (!dat->syms && (dat->siz >= 8 ? !d : !memcmp(d, zero, dat->siz))) { + /* all zeroes */ + s = Sbss; + } else { + s = dat->mut ? Sdata : Srodata; + } + + switch (s) { + default: assert(0); + case Srodata: + if (dat->align > rodataalign) rodataalign = dat->align; + while (rodata.n & (dat->align - 1)) vpush(&rodata, 0); + off = rodata.n; + vpushn(&rodata, d, ndat); + while (nzr--) vpush(&rodata, 0); + break; + case Sdata: + if (dat->align > dataalign) dataalign = dat->align; + while (data.n & (dat->align - 1)) vpush(&data, 0); + off = data.n; + vpushn(&data, d, ndat); + while (nzr--) vpush(&data, 0); + break; + case Sbss: + if (dat->align > bssalign) bssalign = dat->align; + off = alignup(nbss, dat->align); + nbss = off + dat->siz; + break; + } + elfaddsym(dat->name, ELF_S_INFO(dat->globl, STT_OBJECT), s, off, dat->siz); +} + static void put16le(struct wbuf *out, ushort x) { @@ -247,17 +293,17 @@ elffini(struct wbuf *out) sym = findsym(rel->sym); if (sym) rel->sym = sym - symtab.p; else { - sym = &(struct elfsym) { rel->sym, ELF_S_INFO(STB_GLOBAL, STT_FUNC), 0, SHN_UND }; + sym = &(struct elfsym) { rel->sym, ELF_S_INFO(STB_GLOBAL, STT_NOTYPE), 0, SHN_UND }; rel->sym = symtab.n; vpush(&symtab, *sym); } } size_t codesize = alignup(objout.code - objout.textbegin, align), rodataoff = hdr.ehsize + codesize, - rodatasize = 0, + rodatasize = rodata.n, dataoff = rodataoff + rodatasize, - datasize = 0, - bsssize = 0, + datasize = data.n, + bsssize = nbss, shstrsoff = dataoff + datasize, shstrssize = sizeof(shstrs), strsoff = shstrsoff + shstrssize, @@ -301,8 +347,10 @@ elffini(struct wbuf *out) iowrite(out, objout.textbegin, codesize); /* .rodata progbits */ + iowrite(out, rodata.p, rodata.n); /* .data progbits */ + iowrite(out, data.p, data.n); /* section names */ iowrite(out, shstrs, sizeof shstrs); @@ -343,19 +391,19 @@ elffini(struct wbuf *out) .name = shnam_rodata, .type = SHT_PROGBITS, .flags = SHF_ALLOC, .offset = rodataoff, .size = rodatasize, - .addralign = 1,}); + .addralign = rodataalign,}); /* §3 .data */ elfputshdr(out, &(struct elfshdr){ .name = shnam_data, .type = SHT_PROGBITS, .flags = SHF_ALLOC | SHF_WRITE, .offset = dataoff, .size = datasize, - .addralign = 1,}); + .addralign = dataalign,}); /* §4 .bss */ elfputshdr(out, &(struct elfshdr){ .name = shnam_bss, .type = SHT_NOBITS, .size = bsssize, .flags = SHF_ALLOC | SHF_WRITE, - .addralign = 1,}); + .addralign = bssalign,}); /* §5 .shstrtab */ elfputshdr(out, &(struct elfshdr){ .name = shnam_shstrtab, .type = SHT_STRTAB, @@ -180,13 +180,23 @@ mksymref(const char *s) } union ref -mkdatref(uint siz, uint align, const void *bytes, uint n, bool deref) +mkdatref(const char *name, uint siz, uint align, const void *bytes, uint n, bool deref) { - struct irdat dat = { align, 0, siz }; + struct irdat dat = { .align = align, .siz = siz, .name = name }; if (siz <= 8) memcpy(dat.sdat, bytes, n < siz ? n : siz); else { while (((uchar *)bytes)[n-1] == 0) --n; /* nip trailing zeroes */ - vpushn(&dat.dat, bytes, n); + if (n) vpushn(&dat.dat, bytes, n); + } + if (!name) { + extern const char *intern(const char *); + char buf[32]; + struct wbuf wbuf = MEMBUF(buf, sizeof buf); + + bfmt(&wbuf, ".L.%d", dattab.n); + ioputc(&wbuf, 0); + assert(!wbuf.err); + dat.name = intern(buf); } vpush(&dattab, dat); return mkref(RXCON, addcon(&(struct xcon){.isdat = 1, .deref = deref, .dat = dattab.n - 1})); @@ -195,17 +205,9 @@ mkdatref(uint siz, uint align, const void *bytes, uint n, bool deref) const char * xcon2sym(int ref) { - extern const char *intern(const char *); - char buf[32]; - struct wbuf wbuf = MEMBUF(buf, sizeof buf); - struct xcon *con = &conht[ref]; - - assert(con->isdat || con->issym); - if (con->issym) return con->sym; - bfmt(&wbuf, ".L.%d", con->dat); - ioputc(&wbuf, 0); - assert(!wbuf.err); - return intern(buf); + struct xcon con = conht[ref]; + assert(con.issym ^ con.isdat); + return con.issym ? con.sym : dattab.p[con.dat].name; } struct instr @@ -16,12 +16,13 @@ union irtype { }; struct irdat { - uchar align : 7, mut : 1; + uchar align : 6, mut : 1, globl : 1; uint siz; union { vec_of(uchar) dat; uchar sdat[8]; }; + const char *name; struct symref { struct symref *next; const char *sym; @@ -207,7 +208,7 @@ union ref mkfltcon(enum irclass, double); #define intconval(r) ((r).t == RICON ? (r).i : conht[(r).i].i) #define fltconval(r) (conht[(r).i].f) union ref mksymref(const char *); -union ref mkdatref(uint siz, uint align, const void *, uint n, bool deref); +union ref mkdatref(const char *name, uint siz, uint align, const void *, uint n, bool deref); const char *xcon2sym(int ref); struct instr mkalloca(uint siz, uint align); void conputdat(struct irdat *, uint off, enum typetag t, const void *dat); @@ -7,7 +7,7 @@ static int nextdat; static void pridat(const struct irdat *dat) { - efmt("%s .%d(align %d, size %d):\n\t", dat->mut ? "dat" : "rodat", dat - dattab.p, dat->align, dat->siz); + efmt("%s %'s(align %d, size %d):\n\t", dat->mut ? "dat" : "rodat", dat->name, dat->align, dat->siz); assert(!dat->syms); if (dat->siz <= 8) { efmt("b "); @@ -8,6 +8,7 @@ void elfinit(void); void elfaddsym(const char *, int info, enum section, uvlong value, uvlong size); void elfreloc(const char *sym, enum relockind, enum section, uint off, vlong addend); +void elfputdat(const struct irdat *); void elffini(struct wbuf *); struct objfile objout; @@ -54,6 +55,10 @@ objfini(void) struct wbuf out = FDBUF(buf, sizeof buf, open(objout.file, O_WRONLY | O_CREAT | O_TRUNC, 0666)); if (out.fd < 0) fatal(NULL, "could not open %'s for writing: %s", objout.file, strerror(errno)); + for (int i = 0; i < dattab.n; ++i) { + elfputdat(&dattab.p[i]); + } + switch (mctarg->objkind) { case OBJELF: elffini(&out); break; } |