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},
};