summary refs log tree commit diff
path: root/emit.c
diff options
context:
space:
mode:
Diffstat (limited to 'emit.c')
-rw-r--r--emit.c172
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);
+}