diff options
Diffstat (limited to 'emit.c')
-rw-r--r-- | emit.c | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/emit.c b/emit.c new file mode 100644 index 0000000..372ce3d --- /dev/null +++ b/emit.c @@ -0,0 +1,172 @@ +#include "all.h" + +void +emitlnk(char *n, Lnk *l, char *s, FILE *f) +{ + char *p; + + if (l->sec) { + fprintf(f, ".section %s", l->sec); + if (l->secf) + fprintf(f, ", %s", l->secf); + } else { + fputs(s, f); + } + fputc('\n', f); + if (l->align) + fprintf(f, ".balign %d\n", l->align); + p = n[0] == '"' ? "" : T.assym; + if (l->export) + fprintf(f, ".globl %s%s\n", p, n); + fprintf(f, "%s%s:\n", p, n); +} + +void +emitdat(Dat *d, FILE *f) +{ + static char *dtoa[] = { + [DB] = "\t.byte", + [DH] = "\t.short", + [DW] = "\t.int", + [DL] = "\t.quad" + }; + static int64_t zero; + char *p; + + switch (d->type) { + case DStart: + zero = 0; + break; + case DEnd: + if (zero != -1) { + emitlnk(d->name, d->lnk, ".bss", f); + fprintf(f, "\t.fill %"PRId64",1,0\n", zero); + } + break; + case DZ: + if (zero != -1) + zero += d->u.num; + else + fprintf(f, "\t.fill %"PRId64",1,0\n", d->u.num); + break; + default: + if (zero != -1) { + emitlnk(d->name, d->lnk, ".data", f); + if (zero > 0) + fprintf(f, "\t.fill %"PRId64",1,0\n", zero); + zero = -1; + } + if (d->isstr) { + if (d->type != DB) + err("strings only supported for 'b' currently"); + fprintf(f, "\t.ascii %s\n", d->u.str); + } + else if (d->isref) { + p = d->u.ref.name[0] == '"' ? "" : T.assym; + fprintf(f, "%s %s%s%+"PRId64"\n", + dtoa[d->type], p, d->u.ref.name, + d->u.ref.off); + } + else { + fprintf(f, "%s %"PRId64"\n", + dtoa[d->type], d->u.num); + } + break; + } +} + +typedef struct Asmbits Asmbits; + +struct Asmbits { + char bits[16]; + int size; + Asmbits *link; +}; + +static Asmbits *stash; + +int +stashbits(void *bits, int size) +{ + Asmbits **pb, *b; + int i; + + assert(size == 4 || size == 8 || size == 16); + for (pb=&stash, i=0; (b=*pb); pb=&b->link, i++) + if (size <= b->size) + if (memcmp(bits, b->bits, size) == 0) + return i; + b = emalloc(sizeof *b); + memcpy(b->bits, bits, size); + b->size = size; + b->link = 0; + *pb = b; + return i; +} + +static void +emitfin(FILE *f, char *sec[3]) +{ + Asmbits *b; + char *p; + int lg, i; + double d; + + if (!stash) + return; + fprintf(f, "/* floating point constants */\n"); + for (lg=4; lg>=2; lg--) + for (b=stash, i=0; b; b=b->link, i++) { + if (b->size == (1<<lg)) { + fprintf(f, + ".section %s\n" + ".p2align %d\n" + "%sfp%d:", + sec[lg-2], lg, T.asloc, i + ); + for (p=b->bits; p<&b->bits[b->size]; p+=4) + fprintf(f, "\n\t.int %"PRId32, + *(int32_t *)p); + if (lg <= 3) { + if (lg == 2) + d = *(float *)b->bits; + else + d = *(double *)b->bits; + fprintf(f, " /* %f */\n\n", d); + } else + fprintf(f, "\n\n"); + } + } + while ((b=stash)) { + stash = b->link; + free(b); + } +} + +void +elf_emitfin(FILE *f) +{ + static char *sec[3] = { ".rodata", ".rodata", ".rodata" }; + + emitfin(f ,sec); + fprintf(f, ".section .note.GNU-stack,\"\",@progbits\n"); +} + +void +elf_emitfnfin(char *fn, FILE *f) +{ + fprintf(f, ".type %s, @function\n", fn); + fprintf(f, ".size %s, .-%s\n", fn, fn); +} + +void +macho_emitfin(FILE *f) +{ + static char *sec[3] = { + "__TEXT,__literal4,4byte_literals", + "__TEXT,__literal8,8byte_literals", + ".rodata", /* should not happen */ + }; + + emitfin(f, sec); +} |