shithub: apl10

ref: 7b65afc1ad13f3859eca6eadaa2c45d864320304
dir: /objfile.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include "dat.h"
#include "fns.h"

static Rune
nextrune(Biobuf *b)
{
	Rune r = Bgetrune(b);
	Bungetrune(b);
	return r;
}

static void
skipspace(Biobuf *b)
{
	while(isspacerune(nextrune(b)))
		Bgetrune(b);
}

static uvlong
emitconst(Module *m, u8int *d, uvlong n)
{
	uvlong o = m->constsize;
	m->constsize += n;
	m->consts = realloc(m->consts, m->constsize);
	memcpy(m->consts+o, d, n);
	return o;
}

static void
rheader(Module *m, Biobuf *b, int text)
{
	if(text){
	}else{
		u8int buf[8];

		Bread(b, buf, sizeof(buf));
		m->codesize = read8u(buf);
		m->code = malloc(m->codesize);

		Bread(b, buf, sizeof(buf));
		m->constsize = read8u(buf);
		m->consts = malloc(m->constsize);

		Bread(b, buf, sizeof(buf));
		m->nlabels = read8u(buf);
		m->labels = malloc(sizeof(*m->labels) * m->nlabels);
	}
}

static void
wheader(Module *m, Biobuf *b, int text)
{
	if(text){
	}else{
		u8int buf[8];

		write8u(buf, m->codesize);
		Bwrite(b, buf, sizeof(buf));

		write8u(buf, m->constsize);
		Bwrite(b, buf, sizeof(buf));

		write8u(buf, m->nlabels);
		Bwrite(b, buf, sizeof(buf));
	}
}

static void
rconsts(Module *m, Biobuf *b, int text)
{
	if(text){
	}else{
		Bread(b, m->consts, m->constsize);
	}
}

static void
wconsts(Module *m, Biobuf *b, int text)
{
	if(text){
	}else{
		Bwrite(b, m->consts, m->constsize);
	}
}

static OpArg
roparg(char *s)
{
	OpArg arg;
	arg.tag = OAinvalid;

	char c = s[0];
	if(c == '$'){ /* register */
		for(int i = 0; i < Reg_max; i++){
			if(strcmp(s+1, regnames[i]) == 0){
				arg.tag = OAreg;
				arg.u64 = i;
				break;
			}
		}
	}else if(c == '%'){ /* local variable/tmp */
		char *r;
		arg.u64 = strtoull(s+1, &r, 10);
		if(*r == 0){
			if(arg.u64 < (1<<8))
				arg.tag = OAlocal1;
			else if(arg.u64 < (1<<16))
				arg.tag = OAlocal2;
			else if(arg.u64 < ((uvlong)1<<32))
				arg.tag = OAlocal4;
			else
				arg.tag = OAlocal8;
		}
	}else if(isalpha(c)){ /* label */
		arg.tag = OAlabel;
		for(char *p = s; *p; p++){
			if(!isalnum(*p)){
				arg.tag = OAinvalid;
				break;
			}
		}
		if(arg.tag != OAinvalid)
			arg.cp = strdup(s);
	}else{ /* number */
		char *r;
		arg.s64 = strtoll(s, &r, 0);
		if(*r == 0){
			/* TODO: deal with this, so it uses the smallest possible size */
			arg.tag = OAnum8;
		}
	}

	if(arg.tag == OAinvalid)
		sysfatal("can't parse instruction operand: %s\n", s);
	return arg;
}

static void
rinstr(Module *m, char *iline)
{
	int ok = 0;

	OpArg args[O_maxargs]; 
	char *parts[O_maxargs+2]; /* one larger than it needs to be */
	char *line = strdup(iline);

	int n = getfields(line, parts, nelem(parts), 1, " \t");
	if(n == 1 && parts[0][strlen(parts[0])-1] == ':'){
		parts[0][strlen(parts[0])-1] = 0;
		m->nlabels++;
		m->labels = realloc(m->labels, sizeof(*m->labels) * m->nlabels);
		m->labels[m->nlabels-1].name = strdup(parts[0]);
		m->labels[m->nlabels-1].ioffset = m->ninstrs;
		m->labels[m->nlabels-1].nameoffset = emitconst(m, (u8int*)(parts[0]), strlen(parts[0])+1);
		ok = 1;
	}else if(n > 0 && n < nelem(parts)){
		n--;
		for(int i = 1; i < n; i++){
			if(parts[i][strlen(parts[i])-1] != ',')
				goto end;
			else{
				parts[i][strlen(parts[i])-1] = 0;
			
			}
		}
		char *op = parts[0];
		int opcode;
		for(opcode = 0; opcode < O_max; opcode++)
			if(strcmp(op, optab[opcode].name) == 0)
				break;
		if(opcode == O_max)
			goto end;
		if(n != optab[opcode].args)
			sysfatal("'%s' instruction expected %d args, but got %d", op, optab[opcode].args, n);
		for(int i = 0; i < n; i++)
			args[i] = roparg(parts[i+1]);

		m->ninstrs++;
		m->instrs = realloc(m->instrs, sizeof(*m->instrs) * m->ninstrs);
		memset(&m->instrs[m->ninstrs-1], 0, sizeof(*m->instrs));
		m->instrs[m->ninstrs-1].opcode = opcode;
		memcpy(m->instrs[m->ninstrs-1].args, args, sizeof(args));
		ok = 1;
	}
end:
	free(line);
	if(!ok)
		sysfatal("can't parse: %s\n", iline);
	return;
}

static void
fixlabels(Module *m, uvlong ioffset, uvlong coffset)
{
	for(int l = 0; l < m->nlabels; l++){
		if(ioffset == m->labels[l].ioffset)
			m->labels[l].coffset = coffset;
	}
}

static void
rcode(Module *m, Biobuf *b, int text)
{
	if(text){
		int done = 0;
		while(!done){
			skipspace(b);
			if(nextrune(b) == Beof)
				break;
			char *line = Brdstr(b, '\n', 1);
			if(strlen(line) > 0)
				rinstr(m, line);
			else
				done = 1;
			free(line);
		}

		/* compute real label offsets and total code size */
		uvlong offset = 0;
		for(int i = 0; i < m->ninstrs; i++){
			fixlabels(m, i, offset);
			encodeinstr(&m->instrs[i], m->labels, m->nlabels);
			offset += m->instrs[i].len;
		}
		fixlabels(m, m->ninstrs, offset);

		m->codesize = offset;
		m->code = mallocz(m->codesize, 1);
		offset = 0;
		for(int i = 0; i < m->ninstrs; i++){
			ParsedInstr *p = &m->instrs[i];
			encodelabel(p, m->labels, m->nlabels);
			memcpy(m->code+offset, p->buf, p->len);
			offset += p->len;
		}
	}else{
		for(int i = 0; i < m->nlabels; i++){
			u8int buf[8];
			Bread(b, buf, sizeof(buf));
			m->labels[i].coffset = read8u(buf);

			Bread(b, buf, sizeof(buf));
			m->labels[i].nameoffset = read8u(buf);
			m->labels[i].name = strdup((char*)(m->consts+m->labels[i].nameoffset));
		}
		Bread(b, m->code, m->codesize);
	}
}

static void
woparg(Biobuf *b, OpArg *a)
{
	switch(a->tag){
	case OAlabel:
		Bprint(b, a->cp);
		break;
	case OAreg:
		Bprint(b, "$%s", regnames[a->u64]);
		break;
	case OAlocal1:
	case OAlocal2:
	case OAlocal4:
	case OAlocal8:
		Bprint(b, "%%%ulld", a->u64);
		break;
	case OAnum1:
	case OAnum2:
	case OAnum4:
	case OAnum8:
		Bprint(b, "0x%llx", a->s64);
		break;
	}
}

static void
winstr(Biobuf *b, ParsedInstr *p)
{
	Bprint(b, "\t%s", optab[p->opcode].name);
	for(int i = 0; i < optab[p->opcode].args; i++){
		if(i > 0)
			Bprint(b, ",");
		Bprint(b, " ");
		woparg(b, &p->args[i]);
	}
	Bprint(b, "\n");
}

static void
wlabel(Module *m, Biobuf *b, uvlong offset)
{
	for(int l = 0; l < m->nlabels; l++){
		if(offset == m->labels[l].coffset)
			Bprint(b, "%s:\n", m->labels[l].name);
	}
}

static void
wcode(Module *m, Biobuf *b, int text)
{
	if(text){
		u8int *c = m->code;
		while((c - m->code) < m->codesize){
			m->ninstrs++;
			m->instrs = realloc(m->instrs, m->ninstrs * sizeof(*m->instrs));
			ParsedInstr *p = &m->instrs[m->ninstrs-1];
			decodeinstr(c, p, m->labels, m->nlabels);
			c += p->len;
		}

		uvlong offset = 0;
		for(int i = 0; i < m->ninstrs; i++){
			wlabel(m, b, offset);
			winstr(b, &m->instrs[i]);
			offset += m->instrs[i].len;
		}
		wlabel(m, b, offset);
	}else{
		for(int i = 0; i < m->nlabels; i++){
			u8int buf[8];
			write8u(buf, m->labels[i].coffset);
			Bwrite(b, buf, sizeof(buf));

			write8u(buf, m->labels[i].nameoffset);
			Bwrite(b, buf, sizeof(buf));
		}
		Bwrite(b, m->code, m->codesize);
	}
}

ObjpartSpec objparts[Obj_max] = {
	[ObjHeader] = {"header", rheader, wheader},
	[ObjConsts] = {"constants", rconsts, wconsts},
	[ObjCode] = {"code", rcode, wcode},
};