summaryrefslogtreecommitdiff
path: root/utils/5coff/coff.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/5coff/coff.c')
-rw-r--r--utils/5coff/coff.c642
1 files changed, 642 insertions, 0 deletions
diff --git a/utils/5coff/coff.c b/utils/5coff/coff.c
new file mode 100644
index 00000000..7a057ea5
--- /dev/null
+++ b/utils/5coff/coff.c
@@ -0,0 +1,642 @@
+#include "auxi.h"
+
+/*
+ * in some embedded coff files, edata and end have type 0 not 4,
+ * and file value is pointer to next file sym (as here), but the last one
+ * points to an external symbol, not 0 as here.
+ */
+
+#define C_NULL 0
+#define C_AUTO 1
+#define C_EXT 2
+#define C_STAT 3
+#define C_ARG 9
+#define C_FCN 101
+#define C_FILE 103
+
+#define T_VOID 0
+#define T_CHAR 2
+#define T_SHORT 3
+#define T_INT 4
+#define T_LONG 5
+
+#define DT_NON 0
+#define DT_PTR 1
+#define DT_FCN 2
+#define DT_ARY 3
+
+#define T(a, b) (((a)<<4)|b)
+
+#define DOTTEXT ".text"
+#define DOTDATA ".data"
+#define DOTBSS ".bss"
+#define DOTBF ".bf"
+#define DOTEF ".ef"
+
+#define SINDEX(s) (*((long*)(&s->become)))
+#define LINDEX(s) (*((long*)(&s->used)))
+
+typedef struct Hist Hist;
+
+struct Hist{
+ Auto *a;
+ Hist *n;
+};
+
+static int nsym, nlc, lines;
+
+static void cofflcsz(void);
+
+static Hist *freeh, *curh;
+
+static void
+dohist(Auto *a)
+{
+ Hist *h, **ha;
+
+ if(a->aoffset == 1){ /* new file */
+ for(ha = &curh; *ha != nil; ha = &((*ha)->n))
+ ;
+ *ha = freeh;
+ freeh = curh;
+ curh = nil;
+ }
+ if(freeh != nil){
+ h = freeh;
+ freeh = freeh->n;
+ }
+ else
+ h = malloc(sizeof(Hist));
+ h->a = a;
+ h->n = nil;
+ for(ha = &curh; *ha != nil; ha = &((*ha)->n))
+ ;
+ *ha = h;
+}
+
+static long
+lineno(long n)
+{
+ long o, d;
+ Hist *h;
+
+ if(1)
+ return n; /* now using fileline() not pc2line() */
+
+ if(curh == nil)
+ return 0;
+ o = curh->a->aoffset-1;
+ d = 1;
+ for(h = curh->n; d && h != nil; h = h->n){
+ if(h->a->asym->name[1] || h->a->asym->name[2]){
+ if(h->a->type == D_FILE1) {
+ ;
+ }
+ else if(d == 1 && n < h->a->aoffset)
+ break;
+ else if(d++ == 1)
+ o -= h->a->aoffset;
+ }
+ else if(--d == 1)
+ o += h->a->aoffset;
+ }
+ return n-o;
+}
+
+static char *
+filelookup(int k)
+{
+ int i;
+ Symx *s;
+
+ for(i = 0; i < NHASH; i++){
+ for(s = hash[i]; s != nil; s = s->link){
+ if(s->type == SFILE && k == s->value)
+ return s->name+1;
+ }
+ }
+ return "";
+}
+
+static char*
+filename(char *s)
+{
+ int j, k, l;
+ static char buf[256];
+
+ buf[0] = '\0';
+ if(s[0] != 0)
+ diag("bad filename");
+ for(j = 1; ; j += 2){
+ k = (s[j]<<8)|s[j+1];
+ if(k == 0)
+ break;
+ l = strlen(buf);
+ if(l != 0 && buf[l-1] != '/')
+ strcat(buf, "/");
+ strcat(buf, filelookup(k));
+ }
+ return buf;
+}
+
+static void
+sput(char *s, int n)
+{
+ int i;
+
+ for(i = 0; i < n && s != nil && *s != '\0'; i++, s++)
+ cput(*s);
+ for( ; i < n; i++)
+ cput(0);
+}
+
+static void
+coffsect(char *s, long a, long sz, long o, long lp, long nl, long f)
+{
+ if(0)
+ print("sect %s pa=%lux va=%lux sz=%lux\n", s, a, a, sz);
+ sput(s, 8); /* name <= 8 chars in len */
+ lputl(a); /* pa */
+ lputl(a); /* va */
+ lputl(sz); /* size */
+ lputl(o); /* file offset */
+ lputl(0); /* reloc */
+ lputl(lp); /* line nos */
+ lputl(0); /* no reloc entries */
+ lputl(nl); /* no line no entries */
+ lputl(f); /* flags */
+ hputl(0); /* reserved */
+ hputl(0); /* mem page no */
+}
+
+void
+coffhdr(void)
+{
+ if(0){
+ print("H=%lux t=%lux d=%lux b=%lux\n", HEADR, textsize, datsize, bsssize);
+ print("e=%lux ts=%lux ds=%lux\n", entryvalue(), INITTEXT, INITDAT);
+ }
+
+ /*
+ * file header
+ */
+ hputl(0xc2); /* version ID */
+ hputl(3); /* no section hdrs */
+ lputl(0); /* date stamp */
+ lputl(HEADR+textsize+datsize+6*nlc); /* sym table */
+ lputl(nsym); /* no sym table entries */
+ hputl(28); /* size optional hdr */
+ hputl(0x0103); /* flags */
+ hputl(0x97); /* target ID */
+ /*
+ * optional file header
+ */
+ hputl(0x108); /* magic */
+ hputl(0); /* version stamp */
+ lputl(textsize); /* text size */
+ lputl(datsize); /* data size */
+ lputl(bsssize); /* bss size */
+ lputl(entryvalue()); /* entry pt */
+ lputl(INITTEXT); /* text start */
+ lputl(INITDAT); /* data start */
+ /*
+ * sections
+ */
+ coffsect(DOTTEXT, INITTEXT, textsize, HEADR, HEADR+textsize+datsize, nlc, 0x20);
+ coffsect(DOTDATA, INITDAT, datsize, HEADR+textsize, 0, 0, 0x40);
+ coffsect(DOTBSS, INITDAT+datsize, bsssize, 0, 0, 0, 0x80);
+}
+
+static int
+private(char *s)
+{
+ return strcmp(s, "safe") == 0 || strcmp(s, "ret") == 0 || strcmp(s, "string") == 0;
+}
+
+static long stoff = 4;
+
+static long
+stput(char *s)
+{
+ long r;
+
+ r = stoff;
+ stoff += strlen(s)+1;
+ return r;
+}
+
+static long
+strput(char *s)
+{
+ int l;
+
+ if((l = strlen(s)) > 8){
+ if(*s == '.' && private(s+1))
+ return 0;
+ while(*s)
+ cput(*s++);
+ cput(*s);
+ return l+1;
+ }
+ return 0;
+}
+
+static void
+stflush(void)
+{
+ int i;
+ long o;
+ Prog *p;
+ Auto *a, *f;
+ Symx *s;
+ char *fn, file[256];
+
+ lputl(stoff);
+ o = 4;
+ for(p = firstp; p != P; p = p->link){
+ if(p->as == ATEXT){
+ f = nil;
+ fn = nil;
+ for(a = p->to.autom; a != nil; a = a->link){
+ if(a->type == D_FILE){
+ f = a;
+ break;
+ }
+ }
+ if(f != nil)
+ fn = filename(f->asym->name);
+ if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){
+ strcpy(file, fn);
+ o += strput(file);
+ }
+ o += strput(p->from.sym->name);
+ for(a = p->to.autom; a != nil; a = a->link){
+ if(a->type == D_AUTO || a->type == D_PARAM)
+ o += strput(a->asym->name);
+ }
+ }
+ }
+ for(i = 0; i < NHASH; i++){
+ for(s = hash[i]; s != nil; s = s->link){
+ if(s->version > 0 && (s->type == SDATA || s->type == SBSS))
+ o += strput(s->name);
+ }
+ }
+ for(i = 0; i < NHASH; i++){
+ for(s = hash[i]; s != nil; s = s->link){
+ if(s->version == 0 && (s->type == SDATA || s->type == SBSS))
+ o += strput(s->name);
+ }
+ }
+ if(o != stoff)
+ diag("bad stflush offset");
+}
+
+static int
+putsect(Symx *s)
+{
+ int sz, ln;
+
+ sz = ln = 0;
+ // isn't this repetition ?
+ if(strcmp(s->name, DOTTEXT) == 0){
+ sz = textsize;
+ ln = nlc;
+ }
+ else if(strcmp(s->name, DOTDATA) == 0)
+ sz = datsize;
+ else if(strcmp(s->name, DOTBSS) == 0)
+ sz = bsssize;
+ else
+ diag("bad putsect sym");
+ lputl(sz);
+ hputl(0);
+ hputl(ln);
+ sput(nil, 10);
+ return 1;
+}
+
+static int
+putfun(Symx *s)
+{
+ /* lputl(SINDEX(s)+2); */
+ lputl(0);
+ lputl(0); /* patched later */
+ lputl(HEADR+textsize+datsize+LINDEX(s));
+ lputl(0); /* patched later */
+ sput(nil, 2);
+ return 1;
+}
+
+static int
+putbf(int lno)
+{
+ lputl(0);
+ hputl(lno);
+ hputl(lines);
+ lputl(autosize);
+ lputl(0); /* patched later */
+ sput(nil, 2);
+ return 1;
+}
+
+static int
+putef(int lno)
+{
+ sput(nil, 4);
+ hputl(lno);
+ sput(nil, 12);
+ return 1;
+}
+
+static int
+putsym(Symx *s, int sc, int t, int lno)
+{
+ long v;
+
+ if(s == nil || s->name == nil || s->name[0] == '\0' || (s->name[0] == '.' && private(s->name+1)))
+ return 0;
+ if(0)
+ print("putsym %s %d %ld %d %d\n", s->name, s->type, s->value, sc, t);
+ if(strlen(s->name) <= 8)
+ sput(s->name, 8);
+ else{
+ lputl(0);
+ lputl(stput(s->name));
+ }
+ /* value */
+ v = s->value;
+ if(s->type == SDATA || s->type == SDATA1 || s->type == SBSS)
+ lputl(INITDAT+v);
+ else if(sc == C_AUTO)
+ lputl(autosize+v);
+ else if(sc == C_ARG)
+ lputl(autosize+v+4);
+ else
+ lputl(v);
+ switch(s->type){ /* section number */
+ case STEXT:
+ case SLEAF:
+ hputl(1);
+ break;
+ case SDATA:
+ case SDATA1:
+ hputl(2);
+ break;
+ case SBSS:
+ hputl(3);
+ break;
+ case SFILE:
+ hputl(-2);
+ break;
+ default:
+ diag("type %d in putsym", s->type);
+ break;
+ }
+ hputl(t); /* type */
+ cput(sc); /* storage class */
+ /* aux entries */
+ if(sc == C_STAT && t == T_VOID && s->name[0] == '.'){ /* section */
+ cput(1);
+ return 1+putsect(s);
+ }
+ else if((t>>4) == DT_FCN){ /* function */
+ cput(1);
+ return 1+putfun(s);
+ }
+ else if(sc == C_FCN && strcmp(s->name, DOTBF) == 0){ /* bf */
+ cput(1);
+ return 1+putbf(lno);
+ }
+ else if(sc == C_FCN && strcmp(s->name, DOTEF) == 0){ /* ef */
+ cput(1);
+ return 1+putef(lno);
+ }
+ cput(0); /* 0 aux entry */
+ return 1;
+}
+
+static Symx*
+defsym(char *p, int t, long v)
+{
+ Symx *s;
+
+ s = lookupsym(p, 0);
+ if(s->type == SDATA || s->type == SBSS)
+ return nil; /* already output */
+ if(s->type == 0 || s->type == SXREF){
+ s->type = t;
+ s->value = v;
+ }
+ return s;
+}
+
+static int
+specsym(char *p, int t, long v, int c)
+{
+ return putsym(defsym(p, t, v), c, T_VOID, 0);
+}
+
+static int
+cclass(Symx *s)
+{
+/*
+ if(s->version > 0 && dclass == D_EXTERN)
+ diag("%s: version %d dclass EXTERN", s->name, s->version);
+ if(s->version == 0 && dclass == D_STATIC)
+ diag("%s: version %d dclass STATIC", s->name, s->version);
+*/
+ return s->version > 0 ? C_STAT : C_EXT;
+}
+
+static void
+patchsym(long i, long o, long v)
+{
+ long oo;
+
+ cflush();
+ oo = seek(cout, 0, 1);
+ seek(cout, HEADR+textsize+datsize+6*nlc+18*i+o, 0);
+ lputl(v);
+ cflush();
+ seek(cout, oo, 0);
+}
+
+void
+coffsym(void)
+{
+ int i;
+ long ns, lno, lpc, v, vs, lastf;
+ Prog *p;
+ Auto *a, *f;
+ Symx *s, *bf, *ef, ts;
+ char *fn, file[256];
+
+ file[0] = '\0';
+ cofflcsz();
+ seek(cout, 6*nlc, 1); /* advance over line table */
+ ns = 0;
+ lpc = -1;
+ lno = -1;
+ lastf = -1;
+ bf = defsym(DOTBF, STEXT, 0);
+ ef = defsym(DOTEF, STEXT, 0);
+ for(p = firstp; p != P; p = p->link){
+ setarch(p);
+ if(p->as != ATEXT){
+ if(p->line != 0)
+ lno = lineno(p->line);
+ }
+ if(p->as == ATEXT){
+ curtext = p;
+ autosize = p->to.offset+4;
+ if(lpc >= 0){
+ ef->value = lpc;
+ ns += putsym(ef, C_FCN, T_VOID, lno);
+ }
+ f = nil;
+ fn = nil;
+ for(a = p->to.autom; a != nil; a = a->link){
+ if(a->type == D_FILE || a->type == D_FILE1)
+ dohist(a);
+ if(f == nil && a->type == D_FILE)
+ f = a; /* main filename */
+ }
+ if(f != nil)
+ fn = filename(f->asym->name);
+ if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){
+ strcpy(file, fn);
+ ts.name = file;
+ ts.type = SFILE;
+ ts.value = 0;
+ if(lastf >= 0)
+ patchsym(lastf, 8, ns);
+ lastf = ns;
+ ns += putsym(&ts, C_FILE, T_VOID, 0);
+ }
+ if(p->link != P && p->link->line != 0)
+ lno = lineno(p->link->line);
+ else if(p->line != 0)
+ lno = lineno(p->line);
+ s = p->from.sym;
+ SINDEX(s) = ns;
+ ns += putsym(s, cclass(s), T(DT_FCN, T_INT), 0);
+ if(p->cond != P)
+ lines = LINDEX(p->cond->from.sym)-LINDEX(s)-1;
+ else
+ lines = 0;
+ bf->value = p->pc;
+ ns += putsym(bf, C_FCN, T_VOID, lno);
+ for(a = p->to.autom; a != nil; a = a->link){
+ if(a->type == D_AUTO || a->type == D_PARAM){
+ ts.name = a->asym->name;
+ ts.type = STEXT;
+ ts.value = a->aoffset;
+ ns += putsym(&ts, a->type == D_AUTO ? C_AUTO : C_ARG, T_INT, 0);
+ }
+ }
+ }
+ lpc = p->pc;
+ }
+ if(lpc >= 0){
+ ef->value = lpc;
+ ns += putsym(ef, C_FCN, T_VOID, lno);
+ }
+ /* patch up */
+ for(p = textp; p != P; p = p->cond){
+ s = p->from.sym;
+ if(p->cond != P){
+ v = SINDEX(p->cond->from.sym);
+ vs = p->cond->pc - p->pc;
+ }
+ else{
+ v = 0;
+ vs = INITTEXT+textsize-p->pc;
+ }
+ patchsym(SINDEX(s)+1, 4, 8*vs);
+ patchsym(SINDEX(s)+1, 12, v);
+ patchsym(SINDEX(s)+3, 12, v);
+ }
+ for(i = 0; i < NHASH; i++){
+ for(s = hash[i]; s != nil; s = s->link){
+ if(s->version > 0 && (s->type == SDATA || s->type == SBSS))
+ ns += putsym(s, cclass(s), T_INT, 0);
+ }
+ }
+ for(i = 0; i < NHASH; i++){
+ for(s = hash[i]; s != nil; s = s->link){
+ if(s->version == 0 && (s->type == SDATA || s->type == SBSS))
+ ns += putsym(s, cclass(s), T_INT, 0);
+ }
+ }
+ ns += specsym(DOTTEXT, STEXT, INITTEXT, C_STAT);
+ ns += specsym(DOTDATA, SDATA, 0, C_STAT);
+ ns += specsym(DOTBSS, SBSS, datsize, C_STAT);
+ ns += specsym("etext", STEXT, INITTEXT+textsize, C_EXT);
+ ns += specsym("edata", SDATA, datsize, C_EXT);
+ ns += specsym("end", SBSS, datsize+bsssize, C_EXT);
+ nsym = ns;
+ stflush();
+}
+
+void
+cofflc(void)
+{
+ long olc, nl;
+ Symx *s;
+ Prog *p;
+ Auto *a;
+
+ cflush();
+ seek(cout, HEADR+textsize+datsize, 0);
+ nl = 0;
+ /* opc = INITTEXT; */
+ olc = 0;
+ for(p = firstp; p != P; p = p->link){
+ setarch(p);
+ if(p->as == ATEXT){
+ curtext = p;
+ s = p->from.sym;
+ /* opc = p->pc; */
+ for(a = p->to.autom; a != nil; a = a->link){
+ if(a->type == D_FILE || a->type == D_FILE1)
+ dohist(a);
+ }
+ lputl(SINDEX(s));
+ hputl(0);
+ nl++;
+ continue;
+ }
+ if(p->line == 0 || p->line == olc || p->as == ANOP)
+ continue;
+ lputl(p->pc);
+ hputl(lineno(p->line));
+ nl++;
+ olc = p->line;
+ }
+ if(nl != nlc)
+ diag("bad line count in cofflc()");
+ nlc = nl;
+}
+
+static void
+cofflcsz(void)
+{
+ long olc, nl;
+ Prog *p;
+
+ nl = 0;
+ olc = 0;
+ for(p = firstp; p != P; p = p->link){
+ if(p->as == ATEXT){
+ LINDEX(p->from.sym) = nl;
+ nl++;
+ continue;
+ }
+ if(p->line == 0 || p->line == olc || p->as == ANOP)
+ continue;
+ nl++;
+ olc = p->line;
+ }
+ nlc = nl;
+}