aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--amd64/isel.c2
-rw-r--r--c.c2
-rw-r--r--elf.c62
-rw-r--r--ir.c30
-rw-r--r--ir.h5
-rw-r--r--irdump.c2
-rw-r--r--obj.c5
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)) {
diff --git a/c.c b/c.c
index fb9ef7d..021080d 100644
--- a/c.c
+++ b/c.c
@@ -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:
diff --git a/elf.c b/elf.c
index 653dac5..68bce2a 100644
--- a/elf.c
+++ b/elf.c
@@ -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,
diff --git a/ir.c b/ir.c
index 1351f02..d214f55 100644
--- a/ir.c
+++ b/ir.c
@@ -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
diff --git a/ir.h b/ir.h
index 5187e4b..ca4fe47 100644
--- a/ir.h
+++ b/ir.h
@@ -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);
diff --git a/irdump.c b/irdump.c
index 362c17d..3736826 100644
--- a/irdump.c
+++ b/irdump.c
@@ -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 ");
diff --git a/obj.c b/obj.c
index 68d183f..f2b0623 100644
--- a/obj.c
+++ b/obj.c
@@ -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;
}