ref: 7b65afc1ad13f3859eca6eadaa2c45d864320304
dir: /objfile.c/
#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}, };