diff options
author | Russ Cox <rsc@golang.org> | 2009-01-06 09:41:38 -0800 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-01-06 09:41:38 -0800 |
commit | 012bfad187d3a9a21ebcdbc0844b28a901b4b638 (patch) | |
tree | 2c683e103fc1c4ae0cdbf05c6631184624b5f6df /src/cmd/8l | |
parent | 4587de918b143ba48a8fd5853950626ac2ee7fd2 (diff) | |
download | golang-012bfad187d3a9a21ebcdbc0844b28a901b4b638.tar.gz |
8a, 8c, and 8l from inferno distribution
R=r
DELTA=19539 (19539 added, 0 deleted, 0 changed)
OCL=22109
CL=22109
Diffstat (limited to 'src/cmd/8l')
-rw-r--r-- | src/cmd/8l/asm.c | 532 | ||||
-rw-r--r-- | src/cmd/8l/l.h | 379 | ||||
-rw-r--r-- | src/cmd/8l/list.c | 322 | ||||
-rw-r--r-- | src/cmd/8l/obj.c | 1522 | ||||
-rw-r--r-- | src/cmd/8l/optab.c | 684 | ||||
-rw-r--r-- | src/cmd/8l/pass.c | 793 | ||||
-rw-r--r-- | src/cmd/8l/span.c | 1417 |
7 files changed, 5649 insertions, 0 deletions
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c new file mode 100644 index 000000000..87188967f --- /dev/null +++ b/src/cmd/8l/asm.c @@ -0,0 +1,532 @@ +// Inferno utils/8l/asm.c +// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "l.h" + +#define Dbufslop 100 + +long +entryvalue(void) +{ + char *a; + Sym *s; + + a = INITENTRY; + if(*a >= '0' && *a <= '9') + return atolwhex(a); + s = lookup(a, 0); + if(s->type == 0) + return INITTEXT; + switch(s->type) { + case STEXT: + break; + case SDATA: + if(dlm) + return s->value+INITDAT; + default: + diag("entry not text: %s", s->name); + } + return s->value; +} + +void +wput(ushort w) +{ + cput(w); + cput(w>>8); +} + +void +wputb(ushort w) +{ + cput(w>>8); + cput(w); +} + +void +asmb(void) +{ + Prog *p; + long v, magic; + int a; + uchar *op1; + + if(debug['v']) + Bprint(&bso, "%5.2f asmb\n", cputime()); + Bflush(&bso); + + seek(cout, HEADR, 0); + pc = INITTEXT; + curp = firstp; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->pc != pc) { + if(!debug['a']) + print("%P\n", curp); + diag("phase error %lux sb %lux in %s", p->pc, pc, TNAME); + pc = p->pc; + } + curp = p; + asmins(p); + if(cbc < sizeof(and)) + cflush(); + a = (andptr - and); + if(debug['a']) { + Bprint(&bso, pcstr, pc); + for(op1 = and; op1 < andptr; op1++) + Bprint(&bso, "%.2ux", *op1 & 0xff); + Bprint(&bso, "\t%P\n", curp); + } + if(dlm) { + if(p->as == ATEXT) + reloca = nil; + else if(reloca != nil) + diag("reloc failure: %P", curp); + } + memmove(cbp, and, a); + cbp += a; + pc += a; + cbc -= a; + } + cflush(); + switch(HEADTYPE) { + default: + diag("unknown header type %d", HEADTYPE); + case 0: + seek(cout, rnd(HEADR+textsize, 8192), 0); + break; + case 1: + textsize = rnd(HEADR+textsize, 4096)-HEADR; + seek(cout, textsize+HEADR, 0); + break; + case 2: + seek(cout, HEADR+textsize, 0); + break; + case 3: + case 4: + seek(cout, HEADR+rnd(textsize, INITRND), 0); + break; + } + + if(debug['v']) + Bprint(&bso, "%5.2f datblk\n", cputime()); + Bflush(&bso); + + if(dlm){ + char buf[8]; + + write(cout, buf, INITDAT-textsize); + textsize = INITDAT; + } + + for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) { + if(datsize-v > sizeof(buf)-Dbufslop) + datblk(v, sizeof(buf)-Dbufslop); + else + datblk(v, datsize-v); + } + + symsize = 0; + spsize = 0; + lcsize = 0; + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sym\n", cputime()); + Bflush(&bso); + switch(HEADTYPE) { + default: + case 0: + seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0); + break; + case 1: + seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0); + break; + case 2: + seek(cout, HEADR+textsize+datsize, 0); + break; + case 3: + case 4: + debug['s'] = 1; + break; + } + if(!debug['s']) + asmsym(); + if(debug['v']) + Bprint(&bso, "%5.2f sp\n", cputime()); + Bflush(&bso); + if(debug['v']) + Bprint(&bso, "%5.2f pc\n", cputime()); + Bflush(&bso); + if(!debug['s']) + asmlc(); + if(dlm) + asmdyn(); + cflush(); + } + else if(dlm){ + seek(cout, HEADR+textsize+datsize, 0); + asmdyn(); + cflush(); + } + if(debug['v']) + Bprint(&bso, "%5.2f headr\n", cputime()); + Bflush(&bso); + seek(cout, 0L, 0); + switch(HEADTYPE) { + default: + case 0: /* garbage */ + lput(0x160L<<16); /* magic and sections */ + lput(0L); /* time and date */ + lput(rnd(HEADR+textsize, 4096)+datsize); + lput(symsize); /* nsyms */ + lput((0x38L<<16)|7L); /* size of optional hdr and flags */ + lput((0413<<16)|0437L); /* magic and version */ + lput(rnd(HEADR+textsize, 4096)); /* sizes */ + lput(datsize); + lput(bsssize); + lput(entryvalue()); /* va of entry */ + lput(INITTEXT-HEADR); /* va of base of text */ + lput(INITDAT); /* va of base of data */ + lput(INITDAT+datsize); /* va of base of bss */ + lput(~0L); /* gp reg mask */ + lput(0L); + lput(0L); + lput(0L); + lput(0L); + lput(~0L); /* gp value ?? */ + break; + lputl(0); /* x */ + case 1: /* unix coff */ + /* + * file header + */ + lputl(0x0004014c); /* 4 sections, magic */ + lputl(0); /* unix time stamp */ + lputl(0); /* symbol table */ + lputl(0); /* nsyms */ + lputl(0x0003001c); /* flags, sizeof a.out header */ + /* + * a.out header + */ + lputl(0x10b); /* magic, version stamp */ + lputl(rnd(textsize, INITRND)); /* text sizes */ + lputl(datsize); /* data sizes */ + lputl(bsssize); /* bss sizes */ + lput(entryvalue()); /* va of entry */ + lputl(INITTEXT); /* text start */ + lputl(INITDAT); /* data start */ + /* + * text section header + */ + s8put(".text"); + lputl(HEADR); /* pa */ + lputl(HEADR); /* va */ + lputl(textsize); /* text size */ + lputl(HEADR); /* file offset */ + lputl(0); /* relocation */ + lputl(0); /* line numbers */ + lputl(0); /* relocation, line numbers */ + lputl(0x20); /* flags text only */ + /* + * data section header + */ + s8put(".data"); + lputl(INITDAT); /* pa */ + lputl(INITDAT); /* va */ + lputl(datsize); /* data size */ + lputl(HEADR+textsize); /* file offset */ + lputl(0); /* relocation */ + lputl(0); /* line numbers */ + lputl(0); /* relocation, line numbers */ + lputl(0x40); /* flags data only */ + /* + * bss section header + */ + s8put(".bss"); + lputl(INITDAT+datsize); /* pa */ + lputl(INITDAT+datsize); /* va */ + lputl(bsssize); /* bss size */ + lputl(0); /* file offset */ + lputl(0); /* relocation */ + lputl(0); /* line numbers */ + lputl(0); /* relocation, line numbers */ + lputl(0x80); /* flags bss only */ + /* + * comment section header + */ + s8put(".comment"); + lputl(0); /* pa */ + lputl(0); /* va */ + lputl(symsize+lcsize); /* comment size */ + lputl(HEADR+textsize+datsize); /* file offset */ + lputl(HEADR+textsize+datsize); /* offset of syms */ + lputl(HEADR+textsize+datsize+symsize);/* offset of line numbers */ + lputl(0); /* relocation, line numbers */ + lputl(0x200); /* flags comment only */ + break; + case 2: /* plan9 */ + magic = 4*11*11+7; + if(dlm) + magic |= 0x80000000; + lput(magic); /* magic */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(spsize); /* sp offsets */ + lput(lcsize); /* line offsets */ + break; + case 3: + /* MS-DOS .COM */ + break; + case 4: + /* fake MS-DOS .EXE */ + v = rnd(HEADR+textsize, INITRND)+datsize; + wput(0x5A4D); /* 'MZ' */ + wput(v % 512); /* bytes in last page */ + wput(rnd(v, 512)/512); /* total number of pages */ + wput(0x0000); /* number of reloc items */ + v = rnd(HEADR-(INITTEXT & 0xFFFF), 16); + wput(v/16); /* size of header */ + wput(0x0000); /* minimum allocation */ + wput(0xFFFF); /* maximum allocation */ + wput(0x0000); /* initial ss value */ + wput(0x0100); /* initial sp value */ + wput(0x0000); /* complemented checksum */ + v = entryvalue(); + wput(v); /* initial ip value (!) */ + wput(0x0000); /* initial cs value */ + wput(0x0000); + wput(0x0000); + wput(0x003E); /* reloc table offset */ + wput(0x0000); /* overlay number */ + break; + } + cflush(); +} + +void +lput(long l) +{ + cput(l>>24); + cput(l>>16); + cput(l>>8); + cput(l); +} + +void +lputl(long l) +{ + cput(l); + cput(l>>8); + cput(l>>16); + cput(l>>24); +} + +void +s8put(char *n) +{ + char name[8]; + int i; + + strncpy(name, n, sizeof(name)); + for(i=0; i<sizeof(name); i++) + cput(name[i]); +} + +void +cflush(void) +{ + int n; + + n = sizeof(buf.cbuf) - cbc; + if(n) + write(cout, buf.cbuf, n); + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); +} + +void +datblk(long s, long n) +{ + Prog *p; + char *cast; + long l, fl, j; + int i, c; + + memset(buf.dbuf, 0, n+Dbufslop); + for(p = datap; p != P; p = p->link) { + curp = p; + l = p->from.sym->value + p->from.offset - s; + c = p->from.scale; + i = 0; + if(l < 0) { + if(l+c <= 0) + continue; + while(l < 0) { + l++; + i++; + } + } + if(l >= n) + continue; + if(p->as != AINIT && p->as != ADYNT) { + for(j=l+(c-i)-1; j>=l; j--) + if(buf.dbuf[j]) { + print("%P\n", p); + diag("multiple initialization"); + break; + } + } + switch(p->to.type) { + case D_FCONST: + switch(c) { + default: + case 4: + fl = ieeedtof(&p->to.ieee); + cast = (char*)&fl; + if(debug['a'] && i == 0) { + Bprint(&bso, pcstr, l+s+INITDAT); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux", cast[fnuxi4[j]] & 0xff); + Bprint(&bso, "\t%P\n", curp); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi4[i]]; + l++; + } + break; + case 8: + cast = (char*)&p->to.ieee; + if(debug['a'] && i == 0) { + Bprint(&bso, pcstr, l+s+INITDAT); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff); + Bprint(&bso, "\t%P\n", curp); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i]]; + l++; + } + break; + } + break; + + case D_SCONST: + if(debug['a'] && i == 0) { + Bprint(&bso, pcstr, l+s+INITDAT); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff); + Bprint(&bso, "\t%P\n", curp); + } + for(; i<c; i++) { + buf.dbuf[l] = p->to.scon[i]; + l++; + } + break; + default: + fl = p->to.offset; + if(p->to.type == D_ADDR) { + if(p->to.index != D_STATIC && p->to.index != D_EXTERN) + diag("DADDR type%P", p); + if(p->to.sym) { + if(p->to.sym->type == SUNDEF) + ckoff(p->to.sym, fl); + fl += p->to.sym->value; + if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF) + fl += INITDAT; + if(dlm) + dynreloc(p->to.sym, l+s+INITDAT, 1); + } + } + cast = (char*)&fl; + switch(c) { + default: + diag("bad nuxi %d %d\n%P", c, i, curp); + break; + case 1: + if(debug['a'] && i == 0) { + Bprint(&bso, pcstr, l+s+INITDAT); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux", cast[inuxi1[j]] & 0xff); + Bprint(&bso, "\t%P\n", curp); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi1[i]]; + l++; + } + break; + case 2: + if(debug['a'] && i == 0) { + Bprint(&bso, pcstr, l+s+INITDAT); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux", cast[inuxi2[j]] & 0xff); + Bprint(&bso, "\t%P\n", curp); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi2[i]]; + l++; + } + break; + case 4: + if(debug['a'] && i == 0) { + Bprint(&bso, pcstr, l+s+INITDAT); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux", cast[inuxi4[j]] & 0xff); + Bprint(&bso, "\t%P\n", curp); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi4[i]]; + l++; + } + break; + } + break; + } + } + write(cout, buf.dbuf, n); +} + +long +rnd(long v, long r) +{ + long c; + + if(r <= 0) + return v; + v += r - 1; + c = v % r; + if(c < 0) + c += r; + v -= c; + return v; +} diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h new file mode 100644 index 000000000..199811685 --- /dev/null +++ b/src/cmd/8l/l.h @@ -0,0 +1,379 @@ +// Inferno utils/8l/l.h +// http://code.google.com/p/inferno-os/source/browse/utils/8l/l.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include <lib9.h> +#include <bio.h> +#include "../8c/8.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +#define P ((Prog*)0) +#define S ((Sym*)0) +#define TNAME (curtext?curtext->from.sym->name:noname) +#define cput(c)\ + { *cbp++ = c;\ + if(--cbc <= 0)\ + cflush(); } + +typedef struct Adr Adr; +typedef struct Prog Prog; +typedef struct Sym Sym; +typedef struct Auto Auto; +typedef struct Optab Optab; + +struct Adr +{ + union + { + long u0offset; + char u0scon[8]; + Prog *u0cond; /* not used, but should be D_BRANCH */ + Ieee u0ieee; + } u0; + union + { + Auto* u1autom; + Sym* u1sym; + } u1; + short type; + char index; + char scale; +}; + +#define offset u0.u0offset +#define scon u0.u0scon +#define cond u0.u0cond +#define ieee u0.u0ieee + +#define autom u1.u1autom +#define sym u1.u1sym + +struct Prog +{ + Adr from; + Adr to; + Prog *forwd; + Prog* link; + Prog* pcond; /* work on this */ + long pc; + long line; + uchar mark; /* work on these */ + uchar back; + + short as; + char width; /* fake for DATA */ +}; +struct Auto +{ + Sym* asym; + Auto* link; + long aoffset; + short type; +}; +struct Sym +{ + char *name; + short type; + short version; + short become; + short frame; + uchar subtype; + ushort file; + long value; + long sig; + Sym* link; +}; +struct Optab +{ + short as; + uchar* ytab; + uchar prefix; + uchar op[10]; +}; + +enum +{ + STEXT = 1, + SDATA, + SBSS, + SDATA1, + SXREF, + SFILE, + SCONST, + SUNDEF, + + SIMPORT, + SEXPORT, + + NHASH = 10007, + NHUNK = 100000, + MINSIZ = 4, + STRINGSZ = 200, + MINLC = 1, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ + + Yxxx = 0, + Ynone, + Yi0, + Yi1, + Yi8, + Yi32, + Yiauto, + Yal, + Ycl, + Yax, + Ycx, + Yrb, + Yrl, + Yrf, + Yf0, + Yrx, + Ymb, + Yml, + Ym, + Ybr, + Ycol, + + Ycs, Yss, Yds, Yes, Yfs, Ygs, + Ygdtr, Yidtr, Yldtr, Ymsw, Ytask, + Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, + Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7, + Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, + Ymax, + + Zxxx = 0, + + Zlit, + Z_rp, + Zbr, + Zcall, + Zib_, + Zib_rp, + Zibo_m, + Zil_, + Zil_rp, + Zilo_m, + Zjmp, + Zloop, + Zm_o, + Zm_r, + Zaut_r, + Zo_m, + Zpseudo, + Zr_m, + Zrp_, + Z_ib, + Z_il, + Zm_ibo, + Zm_ilo, + Zib_rr, + Zil_rr, + Zclr, + Zbyte, + Zmov, + Zmax, + + Px = 0, + Pe = 0x66, /* operand escape */ + Pm = 0x0f, /* 2byte opcode escape */ + Pq = 0xff, /* both escape */ + Pb = 0xfe, /* byte operands */ + + Roffset = 22, /* no. bits for offset in relocation address */ + Rindex = 10, /* no. bits for index in relocation address */ +}; + +EXTERN union +{ + struct + { + char obuf[MAXIO]; /* output buffer */ + uchar ibuf[MAXIO]; /* input buffer */ + } u; + char dbuf[1]; +} buf; + +#define cbuf u.obuf +#define xbuf u.ibuf + +#pragma varargck type "A" uint +#pragma varargck type "D" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int +#pragma varargck type "S" char* + +EXTERN long HEADR; +EXTERN long HEADTYPE; +EXTERN long INITDAT; +EXTERN long INITRND; +EXTERN long INITTEXT; +EXTERN char* INITENTRY; /* entry point */ +EXTERN Biobuf bso; +EXTERN long bsssize; +EXTERN long casepc; +EXTERN int cbc; +EXTERN char* cbp; +EXTERN char* pcstr; +EXTERN int cout; +EXTERN Auto* curauto; +EXTERN Auto* curhist; +EXTERN Prog* curp; +EXTERN Prog* curtext; +EXTERN Prog* datap; +EXTERN Prog* edatap; +EXTERN long datsize; +EXTERN char debug[128]; +EXTERN char literal[32]; +EXTERN Prog* etextp; +EXTERN Prog* firstp; +EXTERN char fnuxi8[8]; +EXTERN char fnuxi4[4]; +EXTERN Sym* hash[NHASH]; +EXTERN Sym* histfrog[MAXHIST]; +EXTERN int histfrogp; +EXTERN int histgen; +EXTERN char* library[50]; +EXTERN char* libraryobj[50]; +EXTERN int libraryp; +EXTERN int xrefresolv; +EXTERN char* hunk; +EXTERN char inuxi1[1]; +EXTERN char inuxi2[2]; +EXTERN char inuxi4[4]; +EXTERN char ycover[Ymax*Ymax]; +EXTERN uchar* andptr; +EXTERN uchar and[30]; +EXTERN char reg[D_NONE]; +EXTERN Prog* lastp; +EXTERN long lcsize; +EXTERN int maxop; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN long nsymbol; +EXTERN char* noname; +EXTERN char* outfile; +EXTERN long pc; +EXTERN long spsize; +EXTERN Sym* symlist; +EXTERN long symsize; +EXTERN Prog* textp; +EXTERN long textsize; +EXTERN long thunk; +EXTERN int version; +EXTERN Prog zprg; +EXTERN int dtype; + +EXTERN Adr* reloca; +EXTERN int doexp, dlm; +EXTERN int imports, nimports; +EXTERN int exports, nexports; +EXTERN char* EXPTAB; +EXTERN Prog undefp; + +#define UP (&undefp) + +extern Optab optab[]; +extern char* anames[]; + +int Aconv(Fmt*); +int Dconv(Fmt*); +int Pconv(Fmt*); +int Rconv(Fmt*); +int Sconv(Fmt*); +void addhist(long, int); +Prog* appendp(Prog*); +void asmb(void); +void asmdyn(void); +void asmins(Prog*); +void asmlc(void); +void asmsp(void); +void asmsym(void); +long atolwhex(char*); +Prog* brchain(Prog*); +Prog* brloop(Prog*); +void cflush(void); +void ckoff(Sym*, long); +Prog* copyp(Prog*); +double cputime(void); +void datblk(long, long); +void diag(char*, ...); +void dodata(void); +void doinit(void); +void doprof1(void); +void doprof2(void); +void dostkoff(void); +void dynreloc(Sym*, ulong, int); +long entryvalue(void); +void errorexit(void); +void export(void); +int find1(long, int); +int find2(long, int); +void follow(void); +void gethunk(void); +void histtoauto(void); +double ieeedtod(Ieee*); +long ieeedtof(Ieee*); +void import(void); +void ldobj(int, long, char*); +void loadlib(void); +void listinit(void); +Sym* lookup(char*, int); +void lput(long); +void lputl(long); +void main(int, char*[]); +void mkfwd(void); +void* mysbrk(ulong); +void nuxiinit(void); +void objfile(char*); +int opsize(Prog*); +void patch(void); +Prog* prg(void); +void readundefs(char*, int); +int relinv(int); +long reuse(Prog*, Sym*); +long rnd(long, long); +void s8put(char*); +void span(void); +void undef(void); +void undefsym(Sym*); +long vaddr(Adr*); +void wputb(ushort); +void xdefine(char*, int, long); +void xfol(Prog*); +int zaddr(uchar*, Adr*, Sym*[]); +void zerosig(char*); + +#pragma varargck type "D" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int +#pragma varargck type "A" int diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c new file mode 100644 index 000000000..ebd8b864b --- /dev/null +++ b/src/cmd/8l/list.c @@ -0,0 +1,322 @@ +// Inferno utils/8l/list.c +// http://code.google.com/p/inferno-os/source/browse/utils/8l/list.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "l.h" + +void +listinit(void) +{ + + fmtinstall('R', Rconv); + fmtinstall('A', Aconv); + fmtinstall('D', Dconv); + fmtinstall('S', Sconv); + fmtinstall('P', Pconv); +} + +static Prog *bigP; + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ]; + Prog *p; + + p = va_arg(fp->args, Prog*); + bigP = p; + switch(p->as) { + case ATEXT: + if(p->from.scale) { + sprint(str, "(%ld) %A %D,%d,%D", + p->line, p->as, &p->from, p->from.scale, &p->to); + break; + } + default: + sprint(str, "(%ld) %A %D,%D", + p->line, p->as, &p->from, &p->to); + break; + case ADATA: + case AINIT: + case ADYNT: + sprint(str, "(%ld) %A %D/%d,%D", + p->line, p->as, &p->from, p->from.scale, &p->to); + break; + } + bigP = P; + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + int i; + + i = va_arg(fp->args, int); + return fmtstrcpy(fp, anames[i]); +} + +int +Dconv(Fmt *fp) +{ + char str[40], s[20]; + Adr *a; + int i; + + a = va_arg(fp->args, Adr*); + i = a->type; + if(i >= D_INDIR) { + if(a->offset) + sprint(str, "%ld(%R)", a->offset, i-D_INDIR); + else + sprint(str, "(%R)", i-D_INDIR); + goto brk; + } + switch(i) { + + default: + sprint(str, "%R", i); + break; + + case D_NONE: + str[0] = 0; + break; + + case D_BRANCH: + if(bigP != P && bigP->pcond != P) + if(a->sym != S) + sprint(str, "%lux+%s", bigP->pcond->pc, + a->sym->name); + else + sprint(str, "%lux", bigP->pcond->pc); + else + sprint(str, "%ld(PC)", a->offset); + break; + + case D_EXTERN: + sprint(str, "%s+%ld(SB)", a->sym->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<%d>+%ld(SB)", a->sym->name, + a->sym->version, a->offset); + break; + + case D_AUTO: + sprint(str, "%s+%ld(SP)", a->sym->name, a->offset); + break; + + case D_PARAM: + if(a->sym) + sprint(str, "%s+%ld(FP)", a->sym->name, a->offset); + else + sprint(str, "%ld(FP)", a->offset); + break; + + case D_CONST: + sprint(str, "$%ld", a->offset); + break; + + case D_FCONST: + sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->scon); + break; + + case D_ADDR: + a->type = a->index; + a->index = D_NONE; + sprint(str, "$%D", a); + a->index = a->type; + a->type = D_ADDR; + goto conv; + } +brk: + if(a->index != D_NONE) { + sprint(s, "(%R*%d)", a->index, a->scale); + strcat(str, s); + } +conv: + return fmtstrcpy(fp, str); +} + +char* regstr[] = +{ + "AL", /* [D_AL] */ + "CL", + "DL", + "BL", + "AH", + "CH", + "DH", + "BH", + + "AX", /* [D_AX] */ + "CX", + "DX", + "BX", + "SP", + "BP", + "SI", + "DI", + + "F0", /* [D_F0] */ + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + + "CS", /* [D_CS] */ + "SS", + "DS", + "ES", + "FS", + "GS", + + "GDTR", /* [D_GDTR] */ + "IDTR", /* [D_IDTR] */ + "LDTR", /* [D_LDTR] */ + "MSW", /* [D_MSW] */ + "TASK", /* [D_TASK] */ + + "CR0", /* [D_CR] */ + "CR1", + "CR2", + "CR3", + "CR4", + "CR5", + "CR6", + "CR7", + + "DR0", /* [D_DR] */ + "DR1", + "DR2", + "DR3", + "DR4", + "DR5", + "DR6", + "DR7", + + "TR0", /* [D_TR] */ + "TR1", + "TR2", + "TR3", + "TR4", + "TR5", + "TR6", + "TR7", + + "NONE", /* [D_NONE] */ +}; + +int +Rconv(Fmt *fp) +{ + char str[20]; + int r; + + r = va_arg(fp->args, int); + if(r >= D_AL && r <= D_NONE) + sprint(str, "%s", regstr[r-D_AL]); + else + sprint(str, "gok(%d)", r); + + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[30], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<sizeof(double); i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + default: + if(c < 040 || c >= 0177) + break; /* not portable */ + p[-1] = c; + continue; + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +void +diag(char *fmt, ...) +{ + char buf[STRINGSZ], *tn; + va_list arg; + + tn = "??none??"; + if(curtext != P && curtext->from.sym != S) + tn = curtext->from.sym->name; + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + print("%s: %s\n", tn, buf); + + nerrors++; + if(nerrors > 20) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c new file mode 100644 index 000000000..9bdf55638 --- /dev/null +++ b/src/cmd/8l/obj.c @@ -0,0 +1,1522 @@ +// Inferno utils/8l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define EXTERN +#include "l.h" +#include <ar.h> + +#ifndef DEFAULT +#define DEFAULT '9' +#endif + +char *noname = "<none>"; +char symname[] = SYMDEF; +char thechar = '8'; +char *thestring = "386"; + +/* + * -H0 -T0x40004C -D0x10000000 is garbage unix + * -H1 -T0xd0 -R4 is unix coff + * -H2 -T4128 -R4096 is plan9 format + * -H3 -Tx -Rx is MS-DOS .COM + * -H4 -Tx -Rx is fake MS-DOS .EXE + */ + +static int +isobjfile(char *f) +{ + int n, v; + Biobuf *b; + char buf1[5], buf2[SARMAG]; + + b = Bopen(f, OREAD); + if(b == nil) + return 0; + n = Bread(b, buf1, 5); + if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<')) + v = 1; /* good enough for our purposes */ + else{ + Bseek(b, 0, 0); + n = Bread(b, buf2, SARMAG); + v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0; + } + Bterm(b); + return v; +} + +void +main(int argc, char *argv[]) +{ + int i, c; + char *a; + + Binit(&bso, 1, OWRITE); + cout = -1; + listinit(); + memset(debug, 0, sizeof(debug)); + nerrors = 0; + outfile = "8.out"; + HEADTYPE = -1; + INITTEXT = -1; + INITDAT = -1; + INITRND = -1; + INITENTRY = 0; + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 && c < sizeof(debug)) + debug[c]++; + break; + case 'o': /* output to (next arg) */ + outfile = ARGF(); + break; + case 'E': + a = ARGF(); + if(a) + INITENTRY = a; + break; + case 'H': + a = ARGF(); + if(a) + HEADTYPE = atolwhex(a); + break; + case 'T': + a = ARGF(); + if(a) + INITTEXT = atolwhex(a); + break; + case 'D': + a = ARGF(); + if(a) + INITDAT = atolwhex(a); + break; + case 'R': + a = ARGF(); + if(a) + INITRND = atolwhex(a); + break; + case 'x': /* produce export table */ + doexp = 1; + if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) + readundefs(ARGF(), SEXPORT); + break; + case 'u': /* produce dynamically loadable module */ + dlm = 1; + debug['l']++; + if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) + readundefs(ARGF(), SIMPORT); + break; + } ARGEND + USED(argc); + if(*argv == 0) { + diag("usage: 8l [-options] objects"); + errorexit(); + } + if(!debug['9'] && !debug['U'] && !debug['B']) + debug[DEFAULT] = 1; + if(HEADTYPE == -1) { + if(debug['U']) + HEADTYPE = 1; + if(debug['B']) + HEADTYPE = 2; + if(debug['9']) + HEADTYPE = 2; + } + switch(HEADTYPE) { + default: + diag("unknown -H option"); + errorexit(); + + case 0: /* this is garbage */ + HEADR = 20L+56L; + if(INITTEXT == -1) + INITTEXT = 0x40004CL; + if(INITDAT == -1) + INITDAT = 0x10000000L; + if(INITRND == -1) + INITRND = 0; + break; + case 1: /* is unix coff */ + HEADR = 0xd0L; + if(INITTEXT == -1) + INITTEXT = 0xd0; + if(INITDAT == -1) + INITDAT = 0x400000; + if(INITRND == -1) + INITRND = 0; + break; + case 2: /* plan 9 */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 4096+32; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case 3: /* MS-DOS .COM */ + HEADR = 0; + if(INITTEXT == -1) + INITTEXT = 0x0100; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4; + break; + case 4: /* fake MS-DOS .EXE */ + HEADR = 0x200; + if(INITTEXT == -1) + INITTEXT = 0x0100; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4; + HEADR += (INITTEXT & 0xFFFF); + if(debug['v']) + Bprint(&bso, "HEADR = 0x%ld\n", HEADR); + break; + } + if(INITDAT != 0 && INITRND != 0) + print("warning: -D0x%lux is ignored because of -R0x%lux\n", + INITDAT, INITRND); + if(debug['v']) + Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n", + HEADTYPE, INITTEXT, INITDAT, INITRND); + Bflush(&bso); + for(i=1; optab[i].as; i++) + if(i != optab[i].as) { + diag("phase error in optab: %d", i); + errorexit(); + } + maxop = i; + + for(i=0; i<Ymax; i++) + ycover[i*Ymax + i] = 1; + + ycover[Yi0*Ymax + Yi8] = 1; + ycover[Yi1*Ymax + Yi8] = 1; + + ycover[Yi0*Ymax + Yi32] = 1; + ycover[Yi1*Ymax + Yi32] = 1; + ycover[Yi8*Ymax + Yi32] = 1; + + ycover[Yal*Ymax + Yrb] = 1; + ycover[Ycl*Ymax + Yrb] = 1; + ycover[Yax*Ymax + Yrb] = 1; + ycover[Ycx*Ymax + Yrb] = 1; + ycover[Yrx*Ymax + Yrb] = 1; + + ycover[Yax*Ymax + Yrx] = 1; + ycover[Ycx*Ymax + Yrx] = 1; + + ycover[Yax*Ymax + Yrl] = 1; + ycover[Ycx*Ymax + Yrl] = 1; + ycover[Yrx*Ymax + Yrl] = 1; + + ycover[Yf0*Ymax + Yrf] = 1; + + ycover[Yal*Ymax + Ymb] = 1; + ycover[Ycl*Ymax + Ymb] = 1; + ycover[Yax*Ymax + Ymb] = 1; + ycover[Ycx*Ymax + Ymb] = 1; + ycover[Yrx*Ymax + Ymb] = 1; + ycover[Yrb*Ymax + Ymb] = 1; + ycover[Ym*Ymax + Ymb] = 1; + + ycover[Yax*Ymax + Yml] = 1; + ycover[Ycx*Ymax + Yml] = 1; + ycover[Yrx*Ymax + Yml] = 1; + ycover[Yrl*Ymax + Yml] = 1; + ycover[Ym*Ymax + Yml] = 1; + + for(i=0; i<D_NONE; i++) { + reg[i] = -1; + if(i >= D_AL && i <= D_BH) + reg[i] = (i-D_AL) & 7; + if(i >= D_AX && i <= D_DI) + reg[i] = (i-D_AX) & 7; + if(i >= D_F0 && i <= D_F0+7) + reg[i] = (i-D_F0) & 7; + } + + zprg.link = P; + zprg.pcond = P; + zprg.back = 2; + zprg.as = AGOK; + zprg.from.type = D_NONE; + zprg.from.index = D_NONE; + zprg.from.scale = 1; + zprg.to = zprg.from; + + pcstr = "%.6lux "; + nuxiinit(); + histgen = 0; + textp = P; + datap = P; + edatap = P; + pc = 0; + dtype = 4; + cout = create(outfile, 1, 0775); + if(cout < 0) { + diag("cannot create %s", outfile); + errorexit(); + } + version = 0; + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); + firstp = prg(); + lastp = firstp; + + if(INITENTRY == 0) { + INITENTRY = "_main"; + if(debug['p']) + INITENTRY = "_mainp"; + if(!debug['l']) + lookup(INITENTRY, 0)->type = SXREF; + } else + lookup(INITENTRY, 0)->type = SXREF; + + while(*argv) + objfile(*argv++); + if(!debug['l']) + loadlib(); + firstp = firstp->link; + if(firstp == P) + errorexit(); + if(doexp || dlm){ + EXPTAB = "_exporttab"; + zerosig(EXPTAB); + zerosig("etext"); + zerosig("edata"); + zerosig("end"); + if(dlm){ + import(); + HEADTYPE = 2; + INITTEXT = INITDAT = 0; + INITRND = 8; + INITENTRY = EXPTAB; + } + export(); + } + patch(); + follow(); + dodata(); + dostkoff(); + if(debug['p']) + if(debug['1']) + doprof1(); + else + doprof2(); + span(); + doinit(); + asmb(); + undef(); + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + Bprint(&bso, "%ld symbols\n", nsymbol); + Bprint(&bso, "%ld memory used\n", thunk); + Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); + Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); + } + Bflush(&bso); + + errorexit(); +} + +void +loadlib(void) +{ + int i; + long h; + Sym *s; + +loop: + xrefresolv = 0; + for(i=0; i<libraryp; i++) { + if(debug['v']) + Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]); + objfile(library[i]); + } + if(xrefresolv) + for(h=0; h<nelem(hash); h++) + for(s = hash[h]; s != S; s = s->link) + if(s->type == SXREF) + goto loop; +} + +void +errorexit(void) +{ + + if(nerrors) { + if(cout >= 0) + remove(outfile); + exits("error"); + } + exits(0); +} + +void +objfile(char *file) +{ + long off, esym, cnt, l; + int f, work; + Sym *s; + char magbuf[SARMAG]; + char name[100], pname[150]; + struct ar_hdr arhdr; + char *e, *start, *stop; + + if(file[0] == '-' && file[1] == 'l') { + if(debug['9']) + sprint(name, "/%s/lib/lib", thestring); + else + sprint(name, "/usr/%clib/lib", thechar); + strcat(name, file+2); + strcat(name, ".a"); + file = name; + } + if(debug['v']) + Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file); + Bflush(&bso); + f = open(file, 0); + if(f < 0) { + diag("cannot open file: %s", file); + errorexit(); + } + l = read(f, magbuf, SARMAG); + if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){ + /* load it as a regular file */ + l = seek(f, 0L, 2); + seek(f, 0L, 0); + ldobj(f, l, file); + close(f); + return; + } + + l = read(f, &arhdr, SAR_HDR); + if(l != SAR_HDR) { + diag("%s: short read on archive file symbol header", file); + goto out; + } + if(strncmp(arhdr.name, symname, strlen(symname))) { + diag("%s: first entry not symbol header", file); + goto out; + } + + esym = SARMAG + SAR_HDR + atolwhex(arhdr.size); + off = SARMAG + SAR_HDR; + + /* + * just bang the whole symbol file into memory + */ + seek(f, off, 0); + cnt = esym - off; + start = malloc(cnt + 10); + cnt = read(f, start, cnt); + if(cnt <= 0){ + close(f); + return; + } + stop = &start[cnt]; + memset(stop, 0, 10); + + work = 1; + while(work) { + if(debug['v']) + Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file); + Bflush(&bso); + work = 0; + for(e = start; e < stop; e = strchr(e+5, 0) + 1) { + s = lookup(e+5, 0); + if(s->type != SXREF) + continue; + sprint(pname, "%s(%s)", file, s->name); + if(debug['v']) + Bprint(&bso, "%5.2f library: %s\n", cputime(), pname); + Bflush(&bso); + l = e[1] & 0xff; + l |= (e[2] & 0xff) << 8; + l |= (e[3] & 0xff) << 16; + l |= (e[4] & 0xff) << 24; + seek(f, l, 0); + l = read(f, &arhdr, SAR_HDR); + if(l != SAR_HDR) + goto bad; + if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag))) + goto bad; + l = atolwhex(arhdr.size); + ldobj(f, l, pname); + if(s->type == SXREF) { + diag("%s: failed to load: %s", file, s->name); + errorexit(); + } + work = 1; + xrefresolv = 1; + } + } + return; + +bad: + diag("%s: bad or out of date archive", file); +out: + close(f); +} + +int +zaddr(uchar *p, Adr *a, Sym *h[]) +{ + int c, t, i; + long l; + Sym *s; + Auto *u; + + t = p[0]; + + c = 1; + if(t & T_INDEX) { + a->index = p[c]; + a->scale = p[c+1]; + c += 2; + } else { + a->index = D_NONE; + a->scale = 0; + } + a->offset = 0; + if(t & T_OFFSET) { + a->offset = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); + c += 4; + } + a->sym = S; + if(t & T_SYM) { + a->sym = h[p[c]]; + c++; + } + a->type = D_NONE; + if(t & T_FCONST) { + a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); + a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24); + c += 8; + a->type = D_FCONST; + } else + if(t & T_SCONST) { + for(i=0; i<NSNAME; i++) + a->scon[i] = p[c+i]; + c += NSNAME; + a->type = D_SCONST; + } + if(t & T_TYPE) { + a->type = p[c]; + c++; + } + s = a->sym; + if(s == S) + return c; + + t = a->type; + if(t != D_AUTO && t != D_PARAM) + return c; + l = a->offset; + for(u=curauto; u; u=u->link) { + if(u->asym == s) + if(u->type == t) { + if(u->aoffset > l) + u->aoffset = l; + return c; + } + } + + while(nhunk < sizeof(Auto)) + gethunk(); + u = (Auto*)hunk; + nhunk -= sizeof(Auto); + hunk += sizeof(Auto); + + u->link = curauto; + curauto = u; + u->asym = s; + u->aoffset = l; + u->type = t; + return c; +} + +void +addlib(char *obj) +{ + char name[1024], comp[256], *p; + int i; + + if(histfrogp <= 0) + return; + + if(histfrog[0]->name[1] == '/') { + sprint(name, ""); + i = 1; + } else + if(histfrog[0]->name[1] == '.') { + sprint(name, "."); + i = 0; + } else { + if(debug['9']) + sprint(name, "/%s/lib", thestring); + else + sprint(name, "/usr/%clib", thechar); + i = 0; + } + + for(; i<histfrogp; i++) { + snprint(comp, sizeof comp, histfrog[i]->name+1); + for(;;) { + p = strstr(comp, "$O"); + if(p == 0) + break; + memmove(p+1, p+2, strlen(p+2)+1); + p[0] = thechar; + } + for(;;) { + p = strstr(comp, "$M"); + if(p == 0) + break; + if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) { + diag("library component too long"); + return; + } + memmove(p+strlen(thestring), p+2, strlen(p+2)+1); + memmove(p, thestring, strlen(thestring)); + } + if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) { + diag("library component too long"); + return; + } + strcat(name, "/"); + strcat(name, comp); + } + for(i=0; i<libraryp; i++) + if(strcmp(name, library[i]) == 0) + return; + if(libraryp == nelem(library)){ + diag("too many autolibs; skipping %s", name); + return; + } + + p = malloc(strlen(name) + 1); + strcpy(p, name); + library[libraryp] = p; + p = malloc(strlen(obj) + 1); + strcpy(p, obj); + libraryobj[libraryp] = p; + libraryp++; +} + +void +addhist(long line, int type) +{ + Auto *u; + Sym *s; + int i, j, k; + + u = malloc(sizeof(Auto)); + s = malloc(sizeof(Sym)); + s->name = malloc(2*(histfrogp+1) + 1); + + u->asym = s; + u->type = type; + u->aoffset = line; + u->link = curhist; + curhist = u; + + j = 1; + for(i=0; i<histfrogp; i++) { + k = histfrog[i]->value; + s->name[j+0] = k>>8; + s->name[j+1] = k; + j += 2; + } +} + +void +histtoauto(void) +{ + Auto *l; + + while(l = curhist) { + curhist = l->link; + l->link = curauto; + curauto = l; + } +} + +void +collapsefrog(Sym *s) +{ + int i; + + /* + * bad encoding of path components only allows + * MAXHIST components. if there is an overflow, + * first try to collapse xxx/.. + */ + for(i=1; i<histfrogp; i++) + if(strcmp(histfrog[i]->name+1, "..") == 0) { + memmove(histfrog+i-1, histfrog+i+1, + (histfrogp-i-1)*sizeof(histfrog[0])); + histfrogp--; + goto out; + } + + /* + * next try to collapse . + */ + for(i=0; i<histfrogp; i++) + if(strcmp(histfrog[i]->name+1, ".") == 0) { + memmove(histfrog+i, histfrog+i+1, + (histfrogp-i-1)*sizeof(histfrog[0])); + goto out; + } + + /* + * last chance, just truncate from front + */ + memmove(histfrog+0, histfrog+1, + (histfrogp-1)*sizeof(histfrog[0])); + +out: + histfrog[histfrogp-1] = s; +} + +void +nopout(Prog *p) +{ + p->as = ANOP; + p->from.type = D_NONE; + p->to.type = D_NONE; +} + +uchar* +readsome(int f, uchar *buf, uchar *good, uchar *stop, int max) +{ + int n; + + n = stop - good; + memmove(buf, good, stop - good); + stop = buf + n; + n = MAXIO - n; + if(n > max) + n = max; + n = read(f, stop, n); + if(n <= 0) + return 0; + return stop + n; +} + +void +ldobj(int f, long c, char *pn) +{ + long ipc; + Prog *p, *t; + uchar *bloc, *bsize, *stop; + int v, o, r, skip; + Sym *h[NSYM], *s, *di; + ulong sig; + static int files; + static char **filen; + char **nfilen; + + if((files&15) == 0){ + nfilen = malloc((files+16)*sizeof(char*)); + memmove(nfilen, filen, files*sizeof(char*)); + free(filen); + filen = nfilen; + } + filen[files++] = strdup(pn); + + bsize = buf.xbuf; + bloc = buf.xbuf; + di = S; + +newloop: + memset(h, 0, sizeof(h)); + version++; + histfrogp = 0; + ipc = pc; + skip = 0; + +loop: + if(c <= 0) + goto eof; + r = bsize - bloc; + if(r < 100 && r < c) { /* enough for largest prog */ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + goto loop; + } + o = bloc[0] | (bloc[1] << 8); + if(o <= AXXX || o >= ALAST) { + if(o < 0) + goto eof; + diag("%s: opcode out of range %d", pn, o); + print(" probably not a .8 file\n"); + errorexit(); + } + + if(o == ANAME || o == ASIGNAME) { + sig = 0; + if(o == ASIGNAME) { + sig = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24); + bloc += 4; + c -= 4; + } + stop = memchr(&bloc[4], 0, bsize-&bloc[4]); + if(stop == 0){ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + stop = memchr(&bloc[4], 0, bsize-&bloc[4]); + if(stop == 0){ + fprint(2, "%s: name too long\n", pn); + errorexit(); + } + } + v = bloc[2]; /* type */ + o = bloc[3]; /* sym */ + bloc += 4; + c -= 4; + + r = 0; + if(v == D_STATIC) + r = version; + s = lookup((char*)bloc, r); + c -= &stop[1] - bloc; + bloc = stop + 1; + + if(debug['S'] && r == 0) + sig = 1729; + if(sig != 0){ + if(s->sig != 0 && s->sig != sig) + diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name); + s->sig = sig; + s->file = files-1; + } + + if(debug['W']) + print(" ANAME %s\n", s->name); + h[o] = s; + if((v == D_EXTERN || v == D_STATIC) && s->type == 0) + s->type = SXREF; + if(v == D_FILE) { + if(s->type != SFILE) { + histgen++; + s->type = SFILE; + s->value = histgen; + } + if(histfrogp < MAXHIST) { + histfrog[histfrogp] = s; + histfrogp++; + } else + collapsefrog(s); + } + goto loop; + } + + while(nhunk < sizeof(Prog)) + gethunk(); + p = (Prog*)hunk; + nhunk -= sizeof(Prog); + hunk += sizeof(Prog); + + p->as = o; + p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24); + p->back = 2; + r = zaddr(bloc+6, &p->from, h) + 6; + r += zaddr(bloc+r, &p->to, h); + bloc += r; + c -= r; + + if(debug['W']) + print("%P\n", p); + + switch(p->as) { + case AHISTORY: + if(p->to.offset == -1) { + addlib(pn); + histfrogp = 0; + goto loop; + } + addhist(p->line, D_FILE); /* 'z' */ + if(p->to.offset) + addhist(p->to.offset, D_FILE1); /* 'Z' */ + histfrogp = 0; + goto loop; + + case AEND: + histtoauto(); + if(curtext != P) + curtext->to.autom = curauto; + curauto = 0; + curtext = P; + if(c) + goto newloop; + return; + + case AGLOBL: + s = p->from.sym; + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->value = 0; + } + if(s->type != SBSS) { + diag("%s: redefinition: %s in %s", + pn, s->name, TNAME); + s->type = SBSS; + s->value = 0; + } + if(p->to.offset > s->value) + s->value = p->to.offset; + goto loop; + + case ADYNT: + if(p->to.sym == S) { + diag("DYNT without a sym\n%P", p); + break; + } + di = p->to.sym; + p->from.scale = 4; + if(di->type == SXREF) { + if(debug['z']) + Bprint(&bso, "%P set to %d\n", p, dtype); + di->type = SCONST; + di->value = dtype; + dtype += 4; + } + if(p->from.sym == S) + break; + + p->from.offset = di->value; + p->from.sym->type = SDATA; + if(curtext == P) { + diag("DYNT not in text: %P", p); + break; + } + p->to.sym = curtext->from.sym; + p->to.type = D_ADDR; + p->to.index = D_EXTERN; + goto data; + + case AINIT: + if(p->from.sym == S) { + diag("INIT without a sym\n%P", p); + break; + } + if(di == S) { + diag("INIT without previous DYNT\n%P", p); + break; + } + p->from.offset = di->value; + p->from.sym->type = SDATA; + goto data; + + case ADATA: + data: + if(edatap == P) + datap = p; + else + edatap->link = p; + edatap = p; + p->link = P; + goto loop; + + case AGOK: + diag("%s: GOK opcode in %s", pn, TNAME); + pc++; + goto loop; + + case ATEXT: + if(curtext != P) { + histtoauto(); + curtext->to.autom = curauto; + curauto = 0; + } + skip = 0; + curtext = p; + s = p->from.sym; + if(s == S) { + diag("%s: no TEXT symbol: %P", pn, p); + errorexit(); + } + if(s->type != 0 && s->type != SXREF) { + if(p->from.scale & DUPOK) { + skip = 1; + goto casdef; + } + diag("%s: redefinition: %s\n%P", pn, s->name, p); + } + s->type = STEXT; + s->value = pc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + if(textp == P) { + textp = p; + etextp = p; + goto loop; + } + etextp->pcond = p; + etextp = p; + goto loop; + + case AFMOVF: + case AFADDF: + case AFSUBF: + case AFSUBRF: + case AFMULF: + case AFDIVF: + case AFDIVRF: + case AFCOMF: + case AFCOMFP: + if(skip) + goto casdef; + if(p->from.type == D_FCONST) { + /* size sb 9 max */ + sprint(literal, "$%lux", ieeedtof(&p->from.ieee)); + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SBSS; + s->value = 4; + t = prg(); + t->as = ADATA; + t->line = p->line; + t->from.type = D_EXTERN; + t->from.sym = s; + t->from.scale = 4; + t->to = p->from; + if(edatap == P) + datap = t; + else + edatap->link = t; + edatap = t; + t->link = P; + } + p->from.type = D_EXTERN; + p->from.sym = s; + p->from.offset = 0; + } + goto casdef; + + case AFMOVD: + case AFADDD: + case AFSUBD: + case AFSUBRD: + case AFMULD: + case AFDIVD: + case AFDIVRD: + case AFCOMD: + case AFCOMDP: + if(skip) + goto casdef; + if(p->from.type == D_FCONST) { + /* size sb 18 max */ + sprint(literal, "$%lux.%lux", + p->from.ieee.l, p->from.ieee.h); + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SBSS; + s->value = 8; + t = prg(); + t->as = ADATA; + t->line = p->line; + t->from.type = D_EXTERN; + t->from.sym = s; + t->from.scale = 8; + t->to = p->from; + if(edatap == P) + datap = t; + else + edatap->link = t; + edatap = t; + t->link = P; + } + p->from.type = D_EXTERN; + p->from.sym = s; + p->from.offset = 0; + } + goto casdef; + + casdef: + default: + if(skip) + nopout(p); + + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + goto loop; + } + goto loop; + +eof: + diag("truncated object file: %s", pn); +} + +Sym* +lookup(char *symb, int v) +{ + Sym *s; + char *p; + long h; + int l, c; + + h = v; + for(p=symb; c = *p; p++) + h = h+h+h + c; + l = (p - symb) + 1; + if(h < 0) + h = ~h; + h %= NHASH; + for(s = hash[h]; s != S; s = s->link) + if(s->version == v) + if(memcmp(s->name, symb, l) == 0) + return s; + + while(nhunk < sizeof(Sym)) + gethunk(); + s = (Sym*)hunk; + nhunk -= sizeof(Sym); + hunk += sizeof(Sym); + + s->name = malloc(l + 1); + memmove(s->name, symb, l); + + s->link = hash[h]; + s->type = 0; + s->version = v; + s->value = 0; + s->sig = 0; + hash[h] = s; + nsymbol++; + return s; +} + +Prog* +prg(void) +{ + Prog *p; + + while(nhunk < sizeof(Prog)) + gethunk(); + p = (Prog*)hunk; + nhunk -= sizeof(Prog); + hunk += sizeof(Prog); + + *p = zprg; + return p; +} + +Prog* +copyp(Prog *q) +{ + Prog *p; + + p = prg(); + *p = *q; + return p; +} + +Prog* +appendp(Prog *q) +{ + Prog *p; + + p = prg(); + p->link = q->link; + q->link = p; + p->line = q->line; + return p; +} + +void +gethunk(void) +{ + char *h; + long nh; + + nh = NHUNK; + if(thunk >= 5L*NHUNK) { + nh = 5L*NHUNK; + if(thunk >= 25L*NHUNK) + nh = 25L*NHUNK; + } + h = mysbrk(nh); + if(h == (char*)-1) { + diag("out of memory"); + errorexit(); + } + hunk = h; + nhunk = nh; + thunk += nh; +} + +void +doprof1(void) +{ + Sym *s; + long n; + Prog *p, *q; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 1\n", cputime()); + Bflush(&bso); + s = lookup("__mcount", 0); + n = 1; + for(p = firstp->link; p != P; p = p->link) { + if(p->as == ATEXT) { + q = prg(); + q->line = p->line; + q->link = datap; + datap = q; + q->as = ADATA; + q->from.type = D_EXTERN; + q->from.offset = n*4; + q->from.sym = s; + q->from.scale = 4; + q->to = p->from; + q->to.type = D_CONST; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AADDL; + p->from.type = D_CONST; + p->from.offset = 1; + p->to.type = D_EXTERN; + p->to.sym = s; + p->to.offset = n*4 + 4; + + n += 2; + continue; + } + } + q = prg(); + q->line = 0; + q->link = datap; + datap = q; + + q->as = ADATA; + q->from.type = D_EXTERN; + q->from.sym = s; + q->from.scale = 4; + q->to.type = D_CONST; + q->to.offset = n; + + s->type = SBSS; + s->value = n*4; +} + +void +doprof2(void) +{ + Sym *s2, *s4; + Prog *p, *q, *ps2, *ps4; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 2\n", cputime()); + Bflush(&bso); + + s2 = lookup("_profin", 0); + s4 = lookup("_profout", 0); + if(s2->type != STEXT || s4->type != STEXT) { + diag("_profin/_profout not defined"); + return; + } + + ps2 = P; + ps4 = P; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + if(p->from.sym == s2) { + p->from.scale = 1; + ps2 = p; + } + if(p->from.sym == s4) { + p->from.scale = 1; + ps4 = p; + } + } + } + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + curtext = p; + + if(p->from.scale & NOPROF) { /* dont profile */ + for(;;) { + q = p->link; + if(q == P) + break; + if(q->as == ATEXT) + break; + p = q; + } + continue; + } + + /* + * JMPL profin + */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = ps2; + p->to.sym = s2; + + continue; + } + if(p->as == ARET) { + /* + * RET + */ + q = prg(); + q->as = ARET; + q->from = p->from; + q->to = p->to; + q->link = p->link; + p->link = q; + + /* + * JAL profout + */ + p->as = ACALL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->pcond = ps4; + p->to.sym = s4; + + p = q; + + continue; + } + } +} + +void +nuxiinit(void) +{ + int i, c; + + for(i=0; i<4; i++) { + c = find1(0x04030201L, i+1); + if(i < 2) + inuxi2[i] = c; + if(i < 1) + inuxi1[i] = c; + inuxi4[i] = c; + fnuxi4[i] = c; + fnuxi8[i] = c; + fnuxi8[i+4] = c+4; + } + if(debug['v']) { + Bprint(&bso, "inuxi = "); + for(i=0; i<1; i++) + Bprint(&bso, "%d", inuxi1[i]); + Bprint(&bso, " "); + for(i=0; i<2; i++) + Bprint(&bso, "%d", inuxi2[i]); + Bprint(&bso, " "); + for(i=0; i<4; i++) + Bprint(&bso, "%d", inuxi4[i]); + Bprint(&bso, "\nfnuxi = "); + for(i=0; i<4; i++) + Bprint(&bso, "%d", fnuxi4[i]); + Bprint(&bso, " "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", fnuxi8[i]); + Bprint(&bso, "\n"); + } + Bflush(&bso); +} + +int +find1(long l, int c) +{ + char *p; + int i; + + p = (char*)&l; + for(i=0; i<4; i++) + if(*p++ == c) + return i; + return 0; +} + +int +find2(long l, int c) +{ + short *p; + int i; + + p = (short*)&l; + for(i=0; i<4; i+=2) { + if(((*p >> 8) & 0xff) == c) + return i; + if((*p++ & 0xff) == c) + return i+1; + } + return 0; +} + +long +ieeedtof(Ieee *e) +{ + int exp; + long v; + + if(e->h == 0) + return 0; + exp = (e->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + v = (e->h & 0xfffffL) << 3; + v |= (e->l >> 29) & 0x7L; + if((e->l >> 28) & 1) { + v++; + if(v & 0x800000L) { + v = (v & 0x7fffffL) >> 1; + exp++; + } + } + if(exp <= -126 || exp >= 130) + diag("double fp to single fp overflow"); + v |= ((exp + 126) & 0xffL) << 23; + v |= e->h & 0x80000000L; + return v; +} + +double +ieeedtod(Ieee *ieeep) +{ + Ieee e; + double fr; + int exp; + + if(ieeep->h & (1L<<31)) { + e.h = ieeep->h & ~(1L<<31); + e.l = ieeep->l; + return -ieeedtod(&e); + } + if(ieeep->l == 0 && ieeep->h == 0) + return 0; + fr = ieeep->l & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (ieeep->l>>16) & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (ieeep->h & (1L<<20)-1L) | (1L<<20); + fr /= 1L<<21; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + return ldexp(fr, exp); +} + +void +undefsym(Sym *s) +{ + int n; + + n = imports; + if(s->value != 0) + diag("value != 0 on SXREF"); + if(n >= 1<<Rindex) + diag("import index %d out of range", n); + s->value = n<<Roffset; + s->type = SUNDEF; + imports++; +} + +void +zerosig(char *sp) +{ + Sym *s; + + s = lookup(sp, 0); + s->sig = 0; +} + +void +readundefs(char *f, int t) +{ + int i, n; + Sym *s; + Biobuf *b; + char *l, buf[256], *fields[64]; + + if(f == nil) + return; + b = Bopen(f, OREAD); + if(b == nil){ + diag("could not open %s: %r", f); + errorexit(); + } + while((l = Brdline(b, '\n')) != nil){ + n = Blinelen(b); + if(n >= sizeof(buf)){ + diag("%s: line too long", f); + errorexit(); + } + memmove(buf, l, n); + buf[n-1] = '\0'; + n = getfields(buf, fields, nelem(fields), 1, " \t\r\n"); + if(n == nelem(fields)){ + diag("%s: bad format", f); + errorexit(); + } + for(i = 0; i < n; i++){ + s = lookup(fields[i], 0); + s->type = SXREF; + s->subtype = t; + if(t == SIMPORT) + nimports++; + else + nexports++; + } + } + Bterm(b); +} diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c new file mode 100644 index 000000000..d88e861c5 --- /dev/null +++ b/src/cmd/8l/optab.c @@ -0,0 +1,684 @@ +// Inferno utils/8l/optab.c +// http://code.google.com/p/inferno-os/source/browse/utils/8l/optab.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "l.h" + +uchar ynone[] = +{ + Ynone, Ynone, Zlit, 1, + 0 +}; +uchar ytext[] = +{ + Ymb, Yi32, Zpseudo,1, + 0 +}; +uchar ynop[] = +{ + Ynone, Ynone, Zpseudo,1, + Ynone, Yml, Zpseudo,1, + Ynone, Yrf, Zpseudo,1, + Yml, Ynone, Zpseudo,1, + Yrf, Ynone, Zpseudo,1, + 0 +}; +uchar yxorb[] = +{ + Yi32, Yal, Zib_, 1, + Yi32, Ymb, Zibo_m, 2, + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +uchar yxorl[] = +{ + Yi8, Yml, Zibo_m, 2, + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar yaddl[] = +{ + Yi8, Yml, Zibo_m, 2, + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar yincb[] = +{ + Ynone, Ymb, Zo_m, 2, + 0 +}; +uchar yincl[] = +{ + Ynone, Yrl, Z_rp, 1, + Ynone, Yml, Zo_m, 2, + 0 +}; +uchar ycmpb[] = +{ + Yal, Yi32, Z_ib, 1, + Ymb, Yi32, Zm_ibo, 2, + Ymb, Yrb, Zm_r, 1, + Yrb, Ymb, Zr_m, 1, + 0 +}; +uchar ycmpl[] = +{ + Yml, Yi8, Zm_ibo, 2, + Yax, Yi32, Z_il, 1, + Yml, Yi32, Zm_ilo, 2, + Yml, Yrl, Zm_r, 1, + Yrl, Yml, Zr_m, 1, + 0 +}; +uchar yshb[] = +{ + Yi1, Ymb, Zo_m, 2, + Yi32, Ymb, Zibo_m, 2, + Ycx, Ymb, Zo_m, 2, + 0 +}; +uchar yshl[] = +{ + Yi1, Yml, Zo_m, 2, + Yi32, Yml, Zibo_m, 2, + Ycl, Yml, Zo_m, 2, + Ycx, Yml, Zo_m, 2, + 0 +}; +uchar ytestb[] = +{ + Yi32, Yal, Zib_, 1, + Yi32, Ymb, Zibo_m, 2, + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +uchar ytestl[] = +{ + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar ymovb[] = +{ + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + Yi32, Yrb, Zib_rp, 1, + Yi32, Ymb, Zibo_m, 2, + 0 +}; +uchar ymovl[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + Yi0, Yrl, Zclr, 1+2, +// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst + Yi32, Yrl, Zil_rp, 1, + Yi32, Yml, Zilo_m, 2, + Yiauto, Yrl, Zaut_r, 2, + 0 +}; +uchar ym_rl[] = +{ + Ym, Yrl, Zm_r, 1, + 0 +}; +uchar yrl_m[] = +{ + Yrl, Ym, Zr_m, 1, + 0 +}; +uchar ymb_rl[] = +{ + Ymb, Yrl, Zm_r, 1, + 0 +}; +uchar yml_rl[] = +{ + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar yrl_ml[] = +{ + Yrl, Yml, Zr_m, 1, + 0 +}; +uchar yml_mb[] = +{ + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +uchar yml_ml[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar ydivl[] = +{ + Yml, Ynone, Zm_o, 2, + 0 +}; +uchar ydivb[] = +{ + Ymb, Ynone, Zm_o, 2, + 0 +}; +uchar yimul[] = +{ + Yml, Ynone, Zm_o, 2, + Yi8, Yrl, Zib_rr, 1, + Yi32, Yrl, Zil_rr, 1, + 0 +}; +uchar ybyte[] = +{ + Yi32, Ynone, Zbyte, 1, + 0 +}; +uchar yin[] = +{ + Yi32, Ynone, Zib_, 1, + Ynone, Ynone, Zlit, 1, + 0 +}; +uchar yint[] = +{ + Yi32, Ynone, Zib_, 1, + 0 +}; +uchar ypushl[] = +{ + Yrl, Ynone, Zrp_, 1, + Ym, Ynone, Zm_o, 2, + Yi8, Ynone, Zib_, 1, + Yi32, Ynone, Zil_, 1, + 0 +}; +uchar ypopl[] = +{ + Ynone, Yrl, Z_rp, 1, + Ynone, Ym, Zo_m, 2, + 0 +}; +uchar yscond[] = +{ + Ynone, Ymb, Zo_m, 2, + 0 +}; +uchar yjcond[] = +{ + Ynone, Ybr, Zbr, 1, + 0 +}; +uchar yloop[] = +{ + Ynone, Ybr, Zloop, 1, + 0 +}; +uchar ycall[] = +{ + Ynone, Yml, Zo_m, 2, + Ynone, Ybr, Zcall, 1, + 0 +}; +uchar yjmp[] = +{ + Ynone, Yml, Zo_m, 2, + Ynone, Ybr, Zjmp, 1, + 0 +}; + +uchar yfmvd[] = +{ + Ym, Yf0, Zm_o, 2, + Yf0, Ym, Zo_m, 2, + Yrf, Yf0, Zm_o, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfmvdp[] = +{ + Yf0, Ym, Zo_m, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfmvf[] = +{ + Ym, Yf0, Zm_o, 2, + Yf0, Ym, Zo_m, 2, + 0 +}; +uchar yfmvx[] = +{ + Ym, Yf0, Zm_o, 2, + 0 +}; +uchar yfmvp[] = +{ + Yf0, Ym, Zo_m, 2, + 0 +}; +uchar yfadd[] = +{ + Ym, Yf0, Zm_o, 2, + Yrf, Yf0, Zm_o, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfaddp[] = +{ + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfxch[] = +{ + Yf0, Yrf, Zo_m, 2, + Yrf, Yf0, Zm_o, 2, + 0 +}; +uchar ycompp[] = +{ + Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */ + 0 +}; +uchar ystsw[] = +{ + Ynone, Ym, Zo_m, 2, + Ynone, Yax, Zlit, 1, + 0 +}; +uchar ystcw[] = +{ + Ynone, Ym, Zo_m, 2, + Ym, Ynone, Zm_o, 2, + 0 +}; +uchar ysvrs[] = +{ + Ynone, Ym, Zo_m, 2, + Ym, Ynone, Zm_o, 2, + 0 +}; + +Optab optab[] = +/* as, ytab, andproto, opcode */ +{ + { AXXX }, + { AAAA, ynone, Px, 0x37 }, + { AAAD, ynone, Px, 0xd5,0x0a }, + { AAAM, ynone, Px, 0xd4,0x0a }, + { AAAS, ynone, Px, 0x3f }, + { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 }, + { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADDB, yxorb, Px, 0x04,0x80,(00),0x00,0x02 }, + { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADJSP }, + { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 }, + { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AARPL, yrl_ml, Px, 0x63 }, + { ABOUNDL, yrl_m, Px, 0x62 }, + { ABOUNDW, yrl_m, Pe, 0x62 }, + { ABSFL, yml_rl, Pm, 0xbc }, + { ABSFW, yml_rl, Pq, 0xbc }, + { ABSRL, yml_rl, Pm, 0xbd }, + { ABSRW, yml_rl, Pq, 0xbd }, + { ABTL, yml_rl, Pm, 0xa3 }, + { ABTW, yml_rl, Pq, 0xa3 }, + { ABTCL, yml_rl, Pm, 0xbb }, + { ABTCW, yml_rl, Pq, 0xbb }, + { ABTRL, yml_rl, Pm, 0xb3 }, + { ABTRW, yml_rl, Pq, 0xb3 }, + { ABTSL, yml_rl, Pm, 0xab }, + { ABTSW, yml_rl, Pq, 0xab }, + { ABYTE, ybyte, Px, 1 }, + { ACALL, ycall, Px, 0xff,(02),0xe8 }, + { ACLC, ynone, Px, 0xf8 }, + { ACLD, ynone, Px, 0xfc }, + { ACLI, ynone, Px, 0xfa }, + { ACLTS, ynone, Pm, 0x06 }, + { ACMC, ynone, Px, 0xf5 }, + { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a }, + { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACMPSB, ynone, Pb, 0xa6 }, + { ACMPSL, ynone, Px, 0xa7 }, + { ACMPSW, ynone, Pe, 0xa7 }, + { ADAA, ynone, Px, 0x27 }, + { ADAS, ynone, Px, 0x2f }, + { ADATA }, + { ADECB, yincb, Pb, 0xfe,(01) }, + { ADECL, yincl, Px, 0x48,0xff,(01) }, + { ADECW, yincl, Pe, 0x48,0xff,(01) }, + { ADIVB, ydivb, Pb, 0xf6,(06) }, + { ADIVL, ydivl, Px, 0xf7,(06) }, + { ADIVW, ydivl, Pe, 0xf7,(06) }, + { AENTER }, /* botch */ + { AGLOBL }, + { AGOK }, + { AHISTORY }, + { AHLT, ynone, Px, 0xf4 }, + { AIDIVB, ydivb, Pb, 0xf6,(07) }, + { AIDIVL, ydivl, Px, 0xf7,(07) }, + { AIDIVW, ydivl, Pe, 0xf7,(07) }, + { AIMULB, ydivb, Pb, 0xf6,(05) }, + { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69 }, + { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69 }, + { AINB, yin, Pb, 0xe4,0xec }, + { AINL, yin, Px, 0xe5,0xed }, + { AINW, yin, Pe, 0xe5,0xed }, + { AINCB, yincb, Pb, 0xfe,(00) }, + { AINCL, yincl, Px, 0x40,0xff,(00) }, + { AINCW, yincl, Pe, 0x40,0xff,(00) }, + { AINSB, ynone, Pb, 0x6c }, + { AINSL, ynone, Px, 0x6d }, + { AINSW, ynone, Pe, 0x6d }, + { AINT, yint, Px, 0xcd }, + { AINTO, ynone, Px, 0xce }, + { AIRETL, ynone, Px, 0xcf }, + { AIRETW, ynone, Pe, 0xcf }, + { AJCC, yjcond, Px, 0x73,0x83,(00) }, + { AJCS, yjcond, Px, 0x72,0x82 }, + { AJCXZ, yloop, Px, 0xe3 }, + { AJEQ, yjcond, Px, 0x74,0x84 }, + { AJGE, yjcond, Px, 0x7d,0x8d }, + { AJGT, yjcond, Px, 0x7f,0x8f }, + { AJHI, yjcond, Px, 0x77,0x87 }, + { AJLE, yjcond, Px, 0x7e,0x8e }, + { AJLS, yjcond, Px, 0x76,0x86 }, + { AJLT, yjcond, Px, 0x7c,0x8c }, + { AJMI, yjcond, Px, 0x78,0x88 }, + { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 }, + { AJNE, yjcond, Px, 0x75,0x85 }, + { AJOC, yjcond, Px, 0x71,0x81,(00) }, + { AJOS, yjcond, Px, 0x70,0x80,(00) }, + { AJPC, yjcond, Px, 0x7b,0x8b }, + { AJPL, yjcond, Px, 0x79,0x89 }, + { AJPS, yjcond, Px, 0x7a,0x8a }, + { ALAHF, ynone, Px, 0x9f }, + { ALARL, yml_rl, Pm, 0x02 }, + { ALARW, yml_rl, Pq, 0x02 }, + { ALEAL, ym_rl, Px, 0x8d }, + { ALEAW, ym_rl, Pe, 0x8d }, + { ALEAVEL, ynone, Px, 0xc9 }, + { ALEAVEW, ynone, Pe, 0xc9 }, + { ALOCK, ynone, Px, 0xf0 }, + { ALODSB, ynone, Pb, 0xac }, + { ALODSL, ynone, Px, 0xad }, + { ALODSW, ynone, Pe, 0xad }, + { ALONG, ybyte, Px, 4 }, + { ALOOP, yloop, Px, 0xe2 }, + { ALOOPEQ, yloop, Px, 0xe1 }, + { ALOOPNE, yloop, Px, 0xe0 }, + { ALSLL, yml_rl, Pm, 0x03 }, + { ALSLW, yml_rl, Pq, 0x03 }, + { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) }, + { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) }, + { AMOVW, ymovl, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) }, + { AMOVBLSX, ymb_rl, Pm, 0xbe }, + { AMOVBLZX, ymb_rl, Pm, 0xb6 }, + { AMOVBWSX, ymb_rl, Pq, 0xbe }, + { AMOVBWZX, ymb_rl, Pq, 0xb6 }, + { AMOVWLSX, yml_rl, Pm, 0xbf }, + { AMOVWLZX, yml_rl, Pm, 0xb7 }, + { AMOVSB, ynone, Pb, 0xa4 }, + { AMOVSL, ynone, Px, 0xa5 }, + { AMOVSW, ynone, Pe, 0xa5 }, + { AMULB, ydivb, Pb, 0xf6,(04) }, + { AMULL, ydivl, Px, 0xf7,(04) }, + { AMULW, ydivl, Pe, 0xf7,(04) }, + { ANAME }, + { ANEGB, yscond, Px, 0xf6,(03) }, + { ANEGL, yscond, Px, 0xf7,(03) }, + { ANEGW, yscond, Pe, 0xf7,(03) }, + { ANOP, ynop, Px,0,0 }, + { ANOTB, yscond, Px, 0xf6,(02) }, + { ANOTL, yscond, Px, 0xf7,(02) }, + { ANOTW, yscond, Pe, 0xf7,(02) }, + { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a }, + { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, + { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, + { AOUTB, yin, Pb, 0xe6,0xee }, + { AOUTL, yin, Px, 0xe7,0xef }, + { AOUTW, yin, Pe, 0xe7,0xef }, + { AOUTSB, ynone, Pb, 0x6e }, + { AOUTSL, ynone, Px, 0x6f }, + { AOUTSW, ynone, Pe, 0x6f }, + { APOPAL, ynone, Px, 0x61 }, + { APOPAW, ynone, Pe, 0x61 }, + { APOPFL, ynone, Px, 0x9d }, + { APOPFW, ynone, Pe, 0x9d }, + { APOPL, ypopl, Px, 0x58,0x8f,(00) }, + { APOPW, ypopl, Pe, 0x58,0x8f,(00) }, + { APUSHAL, ynone, Px, 0x60 }, + { APUSHAW, ynone, Pe, 0x60 }, + { APUSHFL, ynone, Px, 0x9c }, + { APUSHFW, ynone, Pe, 0x9c }, + { APUSHL, ypushl, Px, 0x50,0xff,(06),0x6a,0x68 }, + { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 }, + { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) }, + { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) }, + { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, + { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, + { AREP, ynone, Px, 0xf3 }, + { AREPN, ynone, Px, 0xf2 }, + { ARET, ynone, Px, 0xc3 }, + { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) }, + { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, + { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, + { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) }, + { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ASAHF, ynone, Px, 0x9e }, + { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, + { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) }, + { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, + { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, + { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a }, + { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, + { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, + { ASCASB, ynone, Pb, 0xae }, + { ASCASL, ynone, Px, 0xaf }, + { ASCASW, ynone, Pe, 0xaf }, + { ASETCC, yscond, Pm, 0x93,(00) }, + { ASETCS, yscond, Pm, 0x92,(00) }, + { ASETEQ, yscond, Pm, 0x94,(00) }, + { ASETGE, yscond, Pm, 0x9d,(00) }, + { ASETGT, yscond, Pm, 0x9f,(00) }, + { ASETHI, yscond, Pm, 0x97,(00) }, + { ASETLE, yscond, Pm, 0x9e,(00) }, + { ASETLS, yscond, Pm, 0x96,(00) }, + { ASETLT, yscond, Pm, 0x9c,(00) }, + { ASETMI, yscond, Pm, 0x98,(00) }, + { ASETNE, yscond, Pm, 0x95,(00) }, + { ASETOC, yscond, Pm, 0x91,(00) }, + { ASETOS, yscond, Pm, 0x90,(00) }, + { ASETPC, yscond, Pm, 0x96,(00) }, + { ASETPL, yscond, Pm, 0x99,(00) }, + { ASETPS, yscond, Pm, 0x9a,(00) }, + { ACDQ, ynone, Px, 0x99 }, + { ACWD, ynone, Pe, 0x99 }, + { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, + { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) }, + { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASTC, ynone, Px, 0xf9 }, + { ASTD, ynone, Px, 0xfd }, + { ASTI, ynone, Px, 0xfb }, + { ASTOSB, ynone, Pb, 0xaa }, + { ASTOSL, ynone, Px, 0xab }, + { ASTOSW, ynone, Pe, 0xab }, + { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a }, + { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, + { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, + { ASYSCALL, ynone, Px, 0xcd,100 }, + { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 }, + { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 }, + { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 }, + { ATEXT, ytext, Px }, + { AVERR, ydivl, Pm, 0x00,(04) }, + { AVERW, ydivl, Pm, 0x00,(05) }, + { AWAIT, ynone, Px, 0x9b }, + { AWORD, ybyte, Px, 2 }, + { AXCHGB, yml_mb, Pb, 0x86,0x86 }, + { AXCHGL, yml_ml, Px, 0x87,0x87 }, + { AXCHGW, yml_ml, Pe, 0x87,0x87 }, + { AXLAT, ynone, Px, 0xd7 }, + { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 }, + { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, + { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, + + { AFMOVB, yfmvx, Px, 0xdf,(04) }, + { AFMOVBP, yfmvp, Px, 0xdf,(06) }, + { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) }, + { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) }, + { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) }, + { AFMOVFP, yfmvp, Px, 0xd9,(03) }, + { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) }, + { AFMOVLP, yfmvp, Px, 0xdb,(03) }, + { AFMOVV, yfmvx, Px, 0xdf,(05) }, + { AFMOVVP, yfmvp, Px, 0xdf,(07) }, + { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) }, + { AFMOVWP, yfmvp, Px, 0xdf,(03) }, + { AFMOVX, yfmvx, Px, 0xdb,(05) }, + { AFMOVXP, yfmvp, Px, 0xdb,(07) }, + + { AFCOMB }, + { AFCOMBP }, + { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */ + { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */ + { AFCOMDPP, ycompp, Px, 0xde,(03) }, + { AFCOMF, yfmvx, Px, 0xd8,(02) }, + { AFCOMFP, yfmvx, Px, 0xd8,(03) }, + { AFCOML, yfmvx, Px, 0xda,(02) }, + { AFCOMLP, yfmvx, Px, 0xda,(03) }, + { AFCOMW, yfmvx, Px, 0xde,(02) }, + { AFCOMWP, yfmvx, Px, 0xde,(03) }, + + { AFUCOM, ycompp, Px, 0xdd,(04) }, + { AFUCOMP, ycompp, Px, 0xdd,(05) }, + { AFUCOMPP, ycompp, Px, 0xda,(13) }, + + { AFADDDP, yfaddp, Px, 0xde,(00) }, + { AFADDW, yfmvx, Px, 0xde,(00) }, + { AFADDL, yfmvx, Px, 0xda,(00) }, + { AFADDF, yfmvx, Px, 0xd8,(00) }, + { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) }, + + { AFMULDP, yfaddp, Px, 0xde,(01) }, + { AFMULW, yfmvx, Px, 0xde,(01) }, + { AFMULL, yfmvx, Px, 0xda,(01) }, + { AFMULF, yfmvx, Px, 0xd8,(01) }, + { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) }, + + { AFSUBDP, yfaddp, Px, 0xde,(05) }, + { AFSUBW, yfmvx, Px, 0xde,(04) }, + { AFSUBL, yfmvx, Px, 0xda,(04) }, + { AFSUBF, yfmvx, Px, 0xd8,(04) }, + { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) }, + + { AFSUBRDP, yfaddp, Px, 0xde,(04) }, + { AFSUBRW, yfmvx, Px, 0xde,(05) }, + { AFSUBRL, yfmvx, Px, 0xda,(05) }, + { AFSUBRF, yfmvx, Px, 0xd8,(05) }, + { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) }, + + { AFDIVDP, yfaddp, Px, 0xde,(07) }, + { AFDIVW, yfmvx, Px, 0xde,(06) }, + { AFDIVL, yfmvx, Px, 0xda,(06) }, + { AFDIVF, yfmvx, Px, 0xd8,(06) }, + { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) }, + + { AFDIVRDP, yfaddp, Px, 0xde,(06) }, + { AFDIVRW, yfmvx, Px, 0xde,(07) }, + { AFDIVRL, yfmvx, Px, 0xda,(07) }, + { AFDIVRF, yfmvx, Px, 0xd8,(07) }, + { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) }, + + { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) }, + { AFFREE }, + { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) }, + { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) }, + { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) }, + { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) }, + { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) }, + { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) }, + { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 }, + { AF2XM1, ynone, Px, 0xd9, 0xf0 }, + { AFABS, ynone, Px, 0xd9, 0xe1 }, + { AFCHS, ynone, Px, 0xd9, 0xe0 }, + { AFCLEX, ynone, Px, 0xdb, 0xe2 }, + { AFCOS, ynone, Px, 0xd9, 0xff }, + { AFDECSTP, ynone, Px, 0xd9, 0xf6 }, + { AFINCSTP, ynone, Px, 0xd9, 0xf7 }, + { AFINIT, ynone, Px, 0xdb, 0xe3 }, + { AFLD1, ynone, Px, 0xd9, 0xe8 }, + { AFLDL2E, ynone, Px, 0xd9, 0xea }, + { AFLDL2T, ynone, Px, 0xd9, 0xe9 }, + { AFLDLG2, ynone, Px, 0xd9, 0xec }, + { AFLDLN2, ynone, Px, 0xd9, 0xed }, + { AFLDPI, ynone, Px, 0xd9, 0xeb }, + { AFLDZ, ynone, Px, 0xd9, 0xee }, + { AFNOP, ynone, Px, 0xd9, 0xd0 }, + { AFPATAN, ynone, Px, 0xd9, 0xf3 }, + { AFPREM, ynone, Px, 0xd9, 0xf8 }, + { AFPREM1, ynone, Px, 0xd9, 0xf5 }, + { AFPTAN, ynone, Px, 0xd9, 0xf2 }, + { AFRNDINT, ynone, Px, 0xd9, 0xfc }, + { AFSCALE, ynone, Px, 0xd9, 0xfd }, + { AFSIN, ynone, Px, 0xd9, 0xfe }, + { AFSINCOS, ynone, Px, 0xd9, 0xfb }, + { AFSQRT, ynone, Px, 0xd9, 0xfa }, + { AFTST, ynone, Px, 0xd9, 0xe4 }, + { AFXAM, ynone, Px, 0xd9, 0xe5 }, + { AFXTRACT, ynone, Px, 0xd9, 0xf4 }, + { AFYL2X, ynone, Px, 0xd9, 0xf1 }, + { AFYL2XP1, ynone, Px, 0xd9, 0xf9 }, + { AEND }, + 0 +}; diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c new file mode 100644 index 000000000..7f756b495 --- /dev/null +++ b/src/cmd/8l/pass.c @@ -0,0 +1,793 @@ +// Inferno utils/8l/pass.c +// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "l.h" + +void +dodata(void) +{ + int i; + Sym *s; + Prog *p; + long t, u; + + if(debug['v']) + Bprint(&bso, "%5.2f dodata\n", cputime()); + Bflush(&bso); + for(p = datap; p != P; p = p->link) { + s = p->from.sym; + if(p->as == ADYNT || p->as == AINIT) + s->value = dtype; + if(s->type == SBSS) + s->type = SDATA; + if(s->type != SDATA) + diag("initialize non-data (%d): %s\n%P", + s->type, s->name, p); + t = p->from.offset + p->width; + if(t > s->value) + diag("initialize bounds (%ld): %s\n%P", + s->value, s->name, p); + } + /* allocate small guys */ + datsize = 0; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type != SDATA) + if(s->type != SBSS) + continue; + t = s->value; + if(t == 0) { + diag("%s: no size", s->name); + t = 1; + } + t = rnd(t, 4);; + s->value = t; + if(t > MINSIZ) + continue; + s->value = datsize; + datsize += t; + s->type = SDATA1; + } + + /* allocate the rest of the data */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type != SDATA) { + if(s->type == SDATA1) + s->type = SDATA; + continue; + } + t = s->value; + s->value = datsize; + datsize += t; + } + + if(debug['j']) { + /* + * pad data with bss that fits up to next + * 8k boundary, then push data to 8k + */ + u = rnd(datsize, 8192); + u -= datsize; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type != SBSS) + continue; + t = s->value; + if(t > u) + continue; + u -= t; + s->value = datsize; + s->type = SDATA; + datsize += t; + } + datsize += u; + } + + /* now the bss */ + bsssize = 0; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type != SBSS) + continue; + t = s->value; + s->value = bsssize + datsize; + bsssize += t; + } + xdefine("edata", SBSS, datsize); + xdefine("end", SBSS, bsssize + datsize); +} + +Prog* +brchain(Prog *p) +{ + int i; + + for(i=0; i<20; i++) { + if(p == P || p->as != AJMP) + return p; + p = p->pcond; + } + return P; +} + +void +follow(void) +{ + + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + firstp = prg(); + lastp = firstp; + xfol(textp); + lastp->link = P; + firstp = firstp->link; +} + +void +xfol(Prog *p) +{ + Prog *q; + int i; + enum as a; + +loop: + if(p == P) + return; + if(p->as == ATEXT) + curtext = p; + if(p->as == AJMP) + if((q = p->pcond) != P) { + p->mark = 1; + p = q; + if(p->mark == 0) + goto loop; + } + if(p->mark) { + /* copy up to 4 instructions to avoid branch */ + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == P) + break; + if(q == lastp) + break; + a = q->as; + if(a == ANOP) { + i--; + continue; + } + switch(a) { + case AJMP: + case ARET: + case AIRETL: + + case APUSHL: + case APUSHFL: + case APUSHW: + case APUSHFW: + case APOPL: + case APOPFL: + case APOPW: + case APOPFW: + goto brk; + } + if(q->pcond == P || q->pcond->mark) + continue; + if(a == ACALL || a == ALOOP) + continue; + for(;;) { + if(p->as == ANOP) { + p = p->link; + continue; + } + q = copyp(p); + p = p->link; + q->mark = 1; + lastp->link = q; + lastp = q; + if(q->as != a || q->pcond == P || q->pcond->mark) + continue; + + q->as = relinv(q->as); + p = q->pcond; + q->pcond = q->link; + q->link = p; + xfol(q->link); + p = q->link; + if(p->mark) + return; + goto loop; + } + } /* */ + brk:; + q = prg(); + q->as = AJMP; + q->line = p->line; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->pcond = p; + p = q; + } + p->mark = 1; + lastp->link = p; + lastp = p; + a = p->as; + if(a == AJMP || a == ARET || a == AIRETL) + return; + if(p->pcond != P) + if(a != ACALL) { + q = brchain(p->link); + if(q != P && q->mark) + if(a != ALOOP) { + p->as = relinv(a); + p->link = p->pcond; + p->pcond = q; + } + xfol(p->link); + q = brchain(p->pcond); + if(q->mark) { + p->pcond = q; + return; + } + p = q; + goto loop; + } + p = p->link; + goto loop; +} + +int +relinv(int a) +{ + + switch(a) { + case AJEQ: return AJNE; + case AJNE: return AJEQ; + case AJLE: return AJGT; + case AJLS: return AJHI; + case AJLT: return AJGE; + case AJMI: return AJPL; + case AJGE: return AJLT; + case AJPL: return AJMI; + case AJGT: return AJLE; + case AJHI: return AJLS; + case AJCS: return AJCC; + case AJCC: return AJCS; + case AJPS: return AJPC; + case AJPC: return AJPS; + case AJOS: return AJOC; + case AJOC: return AJOS; + } + diag("unknown relation: %s in %s", anames[a], TNAME); + return a; +} + +void +doinit(void) +{ + Sym *s; + Prog *p; + int x; + + for(p = datap; p != P; p = p->link) { + x = p->to.type; + if(x != D_EXTERN && x != D_STATIC) + continue; + s = p->to.sym; + if(s->type == 0 || s->type == SXREF) + diag("undefined %s initializer of %s", + s->name, p->from.sym->name); + p->to.offset += s->value; + p->to.type = D_CONST; + if(s->type == SDATA || s->type == SBSS) + p->to.offset += INITDAT; + } +} + +void +patch(void) +{ + long c; + Prog *p, *q; + Sym *s; + long vexit; + + if(debug['v']) + Bprint(&bso, "%5.2f mkfwd\n", cputime()); + Bflush(&bso); + mkfwd(); + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + s = lookup("exit", 0); + vexit = s->value; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->as == ACALL || p->as == ARET) { + s = p->to.sym; + if(s) { + if(debug['c']) + Bprint(&bso, "%s calls %s\n", TNAME, s->name); + switch(s->type) { + default: + diag("undefined: %s in %s", s->name, TNAME); + s->type = STEXT; + s->value = vexit; + break; /* or fall through to set offset? */ + case STEXT: + p->to.offset = s->value; + break; + case SUNDEF: + p->pcond = UP; + p->to.offset = 0; + break; + } + p->to.type = D_BRANCH; + } + } + if(p->to.type != D_BRANCH || p->pcond == UP) + continue; + c = p->to.offset; + for(q = firstp; q != P;) { + if(q->forwd != P) + if(c >= q->forwd->pc) { + q = q->forwd; + continue; + } + if(c == q->pc) + break; + q = q->link; + } + if(q == P) { + diag("branch out of range in %s\n%P", TNAME, p); + p->to.type = D_NONE; + } + p->pcond = q; + } + + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + p->mark = 0; /* initialization for follow */ + if(p->pcond != P && p->pcond != UP) { + p->pcond = brloop(p->pcond); + if(p->pcond != P) + if(p->to.type == D_BRANCH) + p->to.offset = p->pcond->pc; + } + } +} + +#define LOG 5 +void +mkfwd(void) +{ + Prog *p; + int i; + long dwn[LOG], cnt[LOG]; + Prog *lst[LOG]; + + for(i=0; i<LOG; i++) { + if(i == 0) + cnt[i] = 1; else + cnt[i] = LOG * cnt[i-1]; + dwn[i] = 1; + lst[i] = P; + } + i = 0; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + i--; + if(i < 0) + i = LOG-1; + p->forwd = P; + dwn[i]--; + if(dwn[i] <= 0) { + dwn[i] = cnt[i]; + if(lst[i] != P) + lst[i]->forwd = p; + lst[i] = p; + } + } +} + +Prog* +brloop(Prog *p) +{ + int c; + Prog *q; + + c = 0; + for(q = p; q != P; q = q->pcond) { + if(q->as != AJMP) + break; + c++; + if(c >= 5000) + return P; + } + return q; +} + +void +dostkoff(void) +{ + Prog *p, *q; + long autoffset, deltasp; + int a, f, curframe, curbecome, maxbecome; + + curframe = 0; + curbecome = 0; + maxbecome = 0; + curtext = 0; + for(p = firstp; p != P; p = p->link) { + + /* find out how much arg space is used in this TEXT */ + if(p->to.type == (D_INDIR+D_SP)) + if(p->to.offset > curframe) + curframe = p->to.offset; + + switch(p->as) { + case ATEXT: + if(curtext && curtext->from.sym) { + curtext->from.sym->frame = curframe; + curtext->from.sym->become = curbecome; + if(curbecome > maxbecome) + maxbecome = curbecome; + } + curframe = 0; + curbecome = 0; + + curtext = p; + break; + + case ARET: + /* special form of RET is BECOME */ + if(p->from.type == D_CONST) + if(p->from.offset > curbecome) + curbecome = p->from.offset; + break; + } + } + if(curtext && curtext->from.sym) { + curtext->from.sym->frame = curframe; + curtext->from.sym->become = curbecome; + if(curbecome > maxbecome) + maxbecome = curbecome; + } + + if(debug['b']) + print("max become = %d\n", maxbecome); + xdefine("ALEFbecome", STEXT, maxbecome); + + curtext = 0; + for(p = firstp; p != P; p = p->link) { + switch(p->as) { + case ATEXT: + curtext = p; + break; + case ACALL: + if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { + f = maxbecome - curtext->from.sym->frame; + if(f <= 0) + break; + /* calling a become or calling a variable */ + if(p->to.sym == S || p->to.sym->become) { + curtext->to.offset += f; + if(debug['b']) { + curp = p; + print("%D calling %D increase %d\n", + &curtext->from, &p->to, f); + } + } + } + break; + } + } + + autoffset = 0; + deltasp = 0; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + curtext = p; + autoffset = p->to.offset; + if(autoffset < 0) + autoffset = 0; + if(autoffset) { + p = appendp(p); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = autoffset; + } + deltasp = autoffset; + } + a = p->from.type; + if(a == D_AUTO) + p->from.offset += deltasp; + if(a == D_PARAM) + p->from.offset += deltasp + 4; + a = p->to.type; + if(a == D_AUTO) + p->to.offset += deltasp; + if(a == D_PARAM) + p->to.offset += deltasp + 4; + + switch(p->as) { + default: + continue; + case APUSHL: + case APUSHFL: + deltasp += 4; + continue; + case APUSHW: + case APUSHFW: + deltasp += 2; + continue; + case APOPL: + case APOPFL: + deltasp -= 4; + continue; + case APOPW: + case APOPFW: + deltasp -= 2; + continue; + case ARET: + break; + } + + if(autoffset != deltasp) + diag("unbalanced PUSH/POP"); + if(p->from.type == D_CONST) + goto become; + + if(autoffset) { + q = p; + p = appendp(p); + p->as = ARET; + + q->as = AADJSP; + q->from.type = D_CONST; + q->from.offset = -autoffset; + } + continue; + + become: + q = p; + p = appendp(p); + p->as = AJMP; + p->to = q->to; + p->pcond = q->pcond; + + q->as = AADJSP; + q->from = zprg.from; + q->from.type = D_CONST; + q->from.offset = -autoffset; + q->to = zprg.to; + continue; + } +} + +long +atolwhex(char *s) +{ + long n; + int f; + + n = 0; + f = 0; + while(*s == ' ' || *s == '\t') + s++; + if(*s == '-' || *s == '+') { + if(*s++ == '-') + f = 1; + while(*s == ' ' || *s == '\t') + s++; + } + if(s[0]=='0' && s[1]){ + if(s[1]=='x' || s[1]=='X'){ + s += 2; + for(;;){ + if(*s >= '0' && *s <= '9') + n = n*16 + *s++ - '0'; + else if(*s >= 'a' && *s <= 'f') + n = n*16 + *s++ - 'a' + 10; + else if(*s >= 'A' && *s <= 'F') + n = n*16 + *s++ - 'A' + 10; + else + break; + } + } else + while(*s >= '0' && *s <= '7') + n = n*8 + *s++ - '0'; + } else + while(*s >= '0' && *s <= '9') + n = n*10 + *s++ - '0'; + if(f) + n = -n; + return n; +} + +void +undef(void) +{ + int i; + Sym *s; + + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->type == SXREF) + diag("%s: not defined", s->name); +} + +void +import(void) +{ + int i; + Sym *s; + + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){ + if(s->value != 0) + diag("value != 0 on SXREF"); + undefsym(s); + Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value); + if(debug['S']) + s->sig = 0; + } +} + +void +ckoff(Sym *s, long v) +{ + if(v < 0 || v >= 1<<Roffset) + diag("relocation offset %ld for %s out of range", v, s->name); +} + +static Prog* +newdata(Sym *s, int o, int w, int t) +{ + Prog *p; + + p = prg(); + if(edatap == P) + datap = p; + else + edatap->link = p; + edatap = p; + p->as = ADATA; + p->width = w; + p->from.scale = w; + p->from.type = t; + p->from.sym = s; + p->from.offset = o; + p->to.type = D_CONST; + return p; +} + +void +export(void) +{ + int i, j, n, off, nb, sv, ne; + Sym *s, *et, *str, **esyms; + Prog *p; + char buf[NSNAME], *t; + + n = 0; + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT)) + n++; + esyms = malloc(n*sizeof(Sym*)); + ne = n; + n = 0; + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT)) + esyms[n++] = s; + for(i = 0; i < ne-1; i++) + for(j = i+1; j < ne; j++) + if(strcmp(esyms[i]->name, esyms[j]->name) > 0){ + s = esyms[i]; + esyms[i] = esyms[j]; + esyms[j] = s; + } + + nb = 0; + off = 0; + et = lookup(EXPTAB, 0); + if(et->type != 0 && et->type != SXREF) + diag("%s already defined", EXPTAB); + et->type = SDATA; + str = lookup(".string", 0); + if(str->type == 0) + str->type = SDATA; + sv = str->value; + for(i = 0; i < ne; i++){ + s = esyms[i]; + if(debug['S']) + s->sig = 0; + /* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */ + + /* signature */ + p = newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + p->to.offset = s->sig; + + /* address */ + p = newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + p->to.type = D_ADDR; + p->to.index = D_EXTERN; + p->to.sym = s; + + /* string */ + t = s->name; + n = strlen(t)+1; + for(;;){ + buf[nb++] = *t; + sv++; + if(nb >= NSNAME){ + p = newdata(str, sv-NSNAME, NSNAME, D_STATIC); + p->to.type = D_SCONST; + memmove(p->to.scon, buf, NSNAME); + nb = 0; + } + if(*t++ == 0) + break; + } + + /* name */ + p = newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + p->to.type = D_ADDR; + p->to.index = D_STATIC; + p->to.sym = str; + p->to.offset = sv-n; + } + + if(nb > 0){ + p = newdata(str, sv-nb, nb, D_STATIC); + p->to.type = D_SCONST; + memmove(p->to.scon, buf, nb); + } + + for(i = 0; i < 3; i++){ + newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + } + et->value = off; + if(sv == 0) + sv = 1; + str->value = sv; + exports = ne; + free(esyms); +} diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c new file mode 100644 index 000000000..a6f15772f --- /dev/null +++ b/src/cmd/8l/span.c @@ -0,0 +1,1417 @@ +// Inferno utils/8l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/8l/span.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "l.h" + +void +span(void) +{ + Prog *p, *q; + long v, c, idat; + int m, n, again; + + xdefine("etext", STEXT, 0L); + idat = INITDAT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + n = 0; + if(p->to.type == D_BRANCH) + if(p->pcond == P) + p->pcond = p; + if((q = p->pcond) != P) + if(q->back != 2) + n = 1; + p->back = n; + if(p->as == AADJSP) { + p->to.type = D_SP; + v = -p->from.offset; + p->from.offset = v; + p->as = AADDL; + if(v < 0) { + p->as = ASUBL; + v = -v; + p->from.offset = v; + } + if(v == 0) + p->as = ANOP; + } + } + n = 0; + +start: + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + Bflush(&bso); + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->to.type == D_BRANCH) + if(p->back) + p->pc = c; + asmins(p); + p->pc = c; + m = andptr-and; + p->mark = m; + c += m; + } + +loop: + n++; + if(debug['v']) + Bprint(&bso, "%5.2f span %d\n", cputime(), n); + Bflush(&bso); + if(n > 50) { + print("span must be looping\n"); + errorexit(); + } + again = 0; + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->to.type == D_BRANCH) { + if(p->back) + p->pc = c; + asmins(p); + m = andptr-and; + if(m != p->mark) { + p->mark = m; + again++; + } + } + p->pc = c; + c += p->mark; + } + if(again) { + textsize = c; + goto loop; + } + if(INITRND) { + INITDAT = rnd(c, INITRND); + if(INITDAT != idat) { + idat = INITDAT; + goto start; + } + } + xdefine("etext", STEXT, c); + if(debug['v']) + Bprint(&bso, "etext = %lux\n", c); + Bflush(&bso); + for(p = textp; p != P; p = p->pcond) + p->from.sym->value = p->pc; + textsize = c - INITTEXT; +} + +void +xdefine(char *p, int t, long v) +{ + Sym *s; + + s = lookup(p, 0); + if(s->type == 0 || s->type == SXREF) { + s->type = t; + s->value = v; + } + if(s->type == STEXT && s->value == 0) + s->value = v; +} + +void +putsymb(char *s, int t, long v, int ver) +{ + int i, f; + + if(t == 'f') + s++; + lput(v); + if(ver) + t += 'a' - 'A'; + cput(t+0x80); /* 0x80 is variable length */ + + if(t == 'Z' || t == 'z') { + cput(s[0]); + for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) { + cput(s[i]); + cput(s[i+1]); + } + cput(0); + cput(0); + i++; + } + else { + for(i=0; s[i]; i++) + cput(s[i]); + cput(0); + } + symsize += 4 + 1 + i + 1; + + if(debug['n']) { + if(t == 'z' || t == 'Z') { + Bprint(&bso, "%c %.8lux ", t, v); + for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) { + f = ((s[i]&0xff) << 8) | (s[i+1]&0xff); + Bprint(&bso, "/%x", f); + } + Bprint(&bso, "\n"); + return; + } + if(ver) + Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver); + else + Bprint(&bso, "%c %.8lux %s\n", t, v, s); + } +} + +void +asmsym(void) +{ + Prog *p; + Auto *a; + Sym *s; + int h; + + s = lookup("etext", 0); + if(s->type == STEXT) + putsymb(s->name, 'T', s->value, s->version); + + for(h=0; h<NHASH; h++) + for(s=hash[h]; s!=S; s=s->link) + switch(s->type) { + case SCONST: + putsymb(s->name, 'D', s->value, s->version); + continue; + + case SDATA: + putsymb(s->name, 'D', s->value+INITDAT, s->version); + continue; + + case SBSS: + putsymb(s->name, 'B', s->value+INITDAT, s->version); + continue; + + case SFILE: + putsymb(s->name, 'f', s->value, s->version); + continue; + } + + for(p=textp; p!=P; p=p->pcond) { + s = p->from.sym; + if(s->type != STEXT) + continue; + + /* filenames first */ + for(a=p->to.autom; a; a=a->link) + if(a->type == D_FILE) + putsymb(a->asym->name, 'z', a->aoffset, 0); + else + if(a->type == D_FILE1) + putsymb(a->asym->name, 'Z', a->aoffset, 0); + + putsymb(s->name, 'T', s->value, s->version); + + /* frame, auto and param after */ + putsymb(".frame", 'm', p->to.offset+4, 0); + + for(a=p->to.autom; a; a=a->link) + if(a->type == D_AUTO) + putsymb(a->asym->name, 'a', -a->aoffset, 0); + else + if(a->type == D_PARAM) + putsymb(a->asym->name, 'p', a->aoffset, 0); + } + if(debug['v'] || debug['n']) + Bprint(&bso, "symsize = %lud\n", symsize); + Bflush(&bso); +} + +void +asmlc(void) +{ + long oldpc, oldlc; + Prog *p; + long v, s; + + oldpc = INITTEXT; + oldlc = 0; + for(p = firstp; p != P; p = p->link) { + if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) { + if(p->as == ATEXT) + curtext = p; + if(debug['L']) + Bprint(&bso, "%6lux %P\n", + p->pc, p); + continue; + } + if(debug['L']) + Bprint(&bso, "\t\t%6ld", lcsize); + v = (p->pc - oldpc) / MINLC; + while(v) { + s = 127; + if(v < 127) + s = v; + cput(s+128); /* 129-255 +pc */ + if(debug['L']) + Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128); + v -= s; + lcsize++; + } + s = p->line - oldlc; + oldlc = p->line; + oldpc = p->pc + MINLC; + if(s > 64 || s < -64) { + cput(0); /* 0 vv +lc */ + cput(s>>24); + cput(s>>16); + cput(s>>8); + cput(s); + if(debug['L']) { + if(s > 0) + Bprint(&bso, " lc+%ld(%d,%ld)\n", + s, 0, s); + else + Bprint(&bso, " lc%ld(%d,%ld)\n", + s, 0, s); + Bprint(&bso, "%6lux %P\n", + p->pc, p); + } + lcsize += 5; + continue; + } + if(s > 0) { + cput(0+s); /* 1-64 +lc */ + if(debug['L']) { + Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s); + Bprint(&bso, "%6lux %P\n", + p->pc, p); + } + } else { + cput(64-s); /* 65-128 -lc */ + if(debug['L']) { + Bprint(&bso, " lc%ld(%ld)\n", s, 64-s); + Bprint(&bso, "%6lux %P\n", + p->pc, p); + } + } + lcsize++; + } + while(lcsize & 1) { + s = 129; + cput(s); + lcsize++; + } + if(debug['v'] || debug['L']) + Bprint(&bso, "lcsize = %ld\n", lcsize); + Bflush(&bso); +} + +int +oclass(Adr *a) +{ + long v; + + if(a->type >= D_INDIR || a->index != D_NONE) { + if(a->index != D_NONE && a->scale == 0) { + if(a->type == D_ADDR) { + switch(a->index) { + case D_EXTERN: + case D_STATIC: + return Yi32; + case D_AUTO: + case D_PARAM: + return Yiauto; + } + return Yxxx; + } + return Ycol; + } + return Ym; + } + switch(a->type) + { + case D_AL: + return Yal; + + case D_AX: + return Yax; + + case D_CL: + case D_DL: + case D_BL: + case D_AH: + case D_CH: + case D_DH: + case D_BH: + return Yrb; + + case D_CX: + return Ycx; + + case D_DX: + case D_BX: + return Yrx; + + case D_SP: + case D_BP: + case D_SI: + case D_DI: + return Yrl; + + case D_F0+0: + return Yf0; + + case D_F0+1: + case D_F0+2: + case D_F0+3: + case D_F0+4: + case D_F0+5: + case D_F0+6: + case D_F0+7: + return Yrf; + + case D_NONE: + return Ynone; + + case D_CS: return Ycs; + case D_SS: return Yss; + case D_DS: return Yds; + case D_ES: return Yes; + case D_FS: return Yfs; + case D_GS: return Ygs; + + case D_GDTR: return Ygdtr; + case D_IDTR: return Yidtr; + case D_LDTR: return Yldtr; + case D_MSW: return Ymsw; + case D_TASK: return Ytask; + + case D_CR+0: return Ycr0; + case D_CR+1: return Ycr1; + case D_CR+2: return Ycr2; + case D_CR+3: return Ycr3; + case D_CR+4: return Ycr4; + case D_CR+5: return Ycr5; + case D_CR+6: return Ycr6; + case D_CR+7: return Ycr7; + + case D_DR+0: return Ydr0; + case D_DR+1: return Ydr1; + case D_DR+2: return Ydr2; + case D_DR+3: return Ydr3; + case D_DR+4: return Ydr4; + case D_DR+5: return Ydr5; + case D_DR+6: return Ydr6; + case D_DR+7: return Ydr7; + + case D_TR+0: return Ytr0; + case D_TR+1: return Ytr1; + case D_TR+2: return Ytr2; + case D_TR+3: return Ytr3; + case D_TR+4: return Ytr4; + case D_TR+5: return Ytr5; + case D_TR+6: return Ytr6; + case D_TR+7: return Ytr7; + + case D_EXTERN: + case D_STATIC: + case D_AUTO: + case D_PARAM: + return Ym; + + case D_CONST: + case D_ADDR: + if(a->sym == S) { + v = a->offset; + if(v == 0) + return Yi0; + if(v == 1) + return Yi1; + if(v >= -128 && v <= 127) + return Yi8; + } + return Yi32; + + case D_BRANCH: + return Ybr; + } + return Yxxx; +} + +void +asmidx(Adr *a, int base) +{ + int i; + + switch(a->index) { + default: + goto bad; + + case D_NONE: + i = 4 << 3; + goto bas; + + case D_AX: + case D_CX: + case D_DX: + case D_BX: + case D_BP: + case D_SI: + case D_DI: + i = reg[a->index] << 3; + break; + } + switch(a->scale) { + default: + goto bad; + case 1: + break; + case 2: + i |= (1<<6); + break; + case 4: + i |= (2<<6); + break; + case 8: + i |= (3<<6); + break; + } +bas: + switch(base) { + default: + goto bad; + case D_NONE: /* must be mod=00 */ + i |= 5; + break; + case D_AX: + case D_CX: + case D_DX: + case D_BX: + case D_SP: + case D_BP: + case D_SI: + case D_DI: + i |= reg[base]; + break; + } + *andptr++ = i; + return; +bad: + diag("asmidx: bad address %D", a); + *andptr++ = 0; + return; +} + +static void +put4(long v) +{ + if(dlm && curp != P && reloca != nil){ + dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); + reloca = nil; + } + andptr[0] = v; + andptr[1] = v>>8; + andptr[2] = v>>16; + andptr[3] = v>>24; + andptr += 4; +} + +long +vaddr(Adr *a) +{ + int t; + long v; + Sym *s; + + t = a->type; + v = a->offset; + if(t == D_ADDR) + t = a->index; + switch(t) { + case D_STATIC: + case D_EXTERN: + s = a->sym; + if(s != nil) { + if(dlm && curp != P) + reloca = a; + switch(s->type) { + case SUNDEF: + ckoff(s, v); + case STEXT: + case SCONST: + v += s->value; + break; + default: + v += INITDAT + s->value; + } + } + } + return v; +} + +void +asmand(Adr *a, int r) +{ + long v; + int t; + Adr aa; + + v = a->offset; + t = a->type; + if(a->index != D_NONE) { + if(t >= D_INDIR) { + t -= D_INDIR; + if(t == D_NONE) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a, t); + put4(v); + return; + } + if(v == 0 && t != D_BP) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a, t); + return; + } + if(v >= -128 && v < 128) { + *andptr++ = (1 << 6) | (4 << 0) | (r << 3); + asmidx(a, t); + *andptr++ = v; + return; + } + *andptr++ = (2 << 6) | (4 << 0) | (r << 3); + asmidx(a, t); + put4(v); + return; + } + switch(t) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + aa.type = D_NONE+D_INDIR; + break; + case D_AUTO: + case D_PARAM: + aa.type = D_SP+D_INDIR; + break; + } + aa.offset = vaddr(a); + aa.index = a->index; + aa.scale = a->scale; + asmand(&aa, r); + return; + } + if(t >= D_AL && t <= D_F0+7) { + if(v) + goto bad; + *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); + return; + } + if(t >= D_INDIR) { + t -= D_INDIR; + if(t == D_NONE) { + *andptr++ = (0 << 6) | (5 << 0) | (r << 3); + put4(v); + return; + } + if(t == D_SP) { + if(v == 0) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a, D_SP); + return; + } + if(v >= -128 && v < 128) { + *andptr++ = (1 << 6) | (4 << 0) | (r << 3); + asmidx(a, D_SP); + *andptr++ = v; + return; + } + *andptr++ = (2 << 6) | (4 << 0) | (r << 3); + asmidx(a, D_SP); + put4(v); + return; + } + if(t >= D_AX && t <= D_DI) { + if(v == 0 && t != D_BP) { + *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); + return; + } + if(v >= -128 && v < 128) { + andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3); + andptr[1] = v; + andptr += 2; + return; + } + *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + put4(v); + return; + } + goto bad; + } + switch(a->type) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + aa.type = D_NONE+D_INDIR; + break; + case D_AUTO: + case D_PARAM: + aa.type = D_SP+D_INDIR; + break; + } + aa.index = D_NONE; + aa.scale = 1; + aa.offset = vaddr(a); + asmand(&aa, r); + return; +bad: + diag("asmand: bad address %D", a); + return; +} + +#define E 0xff +uchar ymovtab[] = +{ +/* push */ + APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0, + APUSHL, Yss, Ynone, 0, 0x16,E,0,0, + APUSHL, Yds, Ynone, 0, 0x1e,E,0,0, + APUSHL, Yes, Ynone, 0, 0x06,E,0,0, + APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0, + APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0, + + APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0, + APUSHW, Yss, Ynone, 0, Pe,0x16,E,0, + APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0, + APUSHW, Yes, Ynone, 0, Pe,0x06,E,0, + APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E, + APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E, + +/* pop */ + APOPL, Ynone, Yds, 0, 0x1f,E,0,0, + APOPL, Ynone, Yes, 0, 0x07,E,0,0, + APOPL, Ynone, Yss, 0, 0x17,E,0,0, + APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0, + APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0, + + APOPW, Ynone, Yds, 0, Pe,0x1f,E,0, + APOPW, Ynone, Yes, 0, Pe,0x07,E,0, + APOPW, Ynone, Yss, 0, Pe,0x17,E,0, + APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E, + APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E, + +/* mov seg */ + AMOVW, Yes, Yml, 1, 0x8c,0,0,0, + AMOVW, Ycs, Yml, 1, 0x8c,1,0,0, + AMOVW, Yss, Yml, 1, 0x8c,2,0,0, + AMOVW, Yds, Yml, 1, 0x8c,3,0,0, + AMOVW, Yfs, Yml, 1, 0x8c,4,0,0, + AMOVW, Ygs, Yml, 1, 0x8c,5,0,0, + + AMOVW, Yml, Yes, 2, 0x8e,0,0,0, + AMOVW, Yml, Ycs, 2, 0x8e,1,0,0, + AMOVW, Yml, Yss, 2, 0x8e,2,0,0, + AMOVW, Yml, Yds, 2, 0x8e,3,0,0, + AMOVW, Yml, Yfs, 2, 0x8e,4,0,0, + AMOVW, Yml, Ygs, 2, 0x8e,5,0,0, + +/* mov cr */ + AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0, + AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0, + AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0, + AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0, + + AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0, + AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0, + AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0, + AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0, + +/* mov dr */ + AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0, + AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0, + AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0, + + AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0, + AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0, + AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0, + +/* mov tr */ + AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0, + AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0, + + AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E, + AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E, + +/* lgdt, sgdt, lidt, sidt */ + AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0, + AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0, + AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0, + AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0, + +/* lldt, sldt */ + AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0, + AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0, + +/* lmsw, smsw */ + AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0, + AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0, + +/* ltr, str */ + AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0, + AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0, + +/* load full pointer */ + AMOVL, Yml, Ycol, 5, 0,0,0,0, + AMOVW, Yml, Ycol, 5, Pe,0,0,0, + +/* double shift */ + ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0, + ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0, + +/* extra imul */ + AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0, + 0 +}; + +int +isax(Adr *a) +{ + + switch(a->type) { + case D_AX: + case D_AL: + case D_AH: + case D_INDIR+D_AX: + return 1; + } + if(a->index == D_AX) + return 1; + return 0; +} + +void +subreg(Prog *p, int from, int to) +{ + + if(debug['Q']) + print("\n%P s/%R/%R/\n", p, from, to); + + if(p->from.type == from) + p->from.type = to; + if(p->to.type == from) + p->to.type = to; + + if(p->from.index == from) + p->from.index = to; + if(p->to.index == from) + p->to.index = to; + + from += D_INDIR; + if(p->from.type == from) + p->from.type = to+D_INDIR; + if(p->to.type == from) + p->to.type = to+D_INDIR; + + if(debug['Q']) + print("%P\n", p); +} + +void +doasm(Prog *p) +{ + Optab *o; + Prog *q, pp; + uchar *t; + int z, op, ft, tt; + long v; + + o = &optab[p->as]; + ft = oclass(&p->from) * Ymax; + tt = oclass(&p->to) * Ymax; + t = o->ytab; + if(t == 0) { + diag("asmins: noproto %P", p); + return; + } + for(z=0; *t; z+=t[3],t+=4) + if(ycover[ft+t[0]]) + if(ycover[tt+t[1]]) + goto found; + goto domov; + +found: + switch(o->prefix) { + case Pq: /* 16 bit escape and opcode escape */ + *andptr++ = Pe; + *andptr++ = Pm; + break; + + case Pm: /* opcode escape */ + *andptr++ = Pm; + break; + + case Pe: /* 16 bit escape */ + *andptr++ = Pe; + break; + + case Pb: /* botch */ + break; + } + v = vaddr(&p->from); + op = o->op[z]; + switch(t[2]) { + default: + diag("asmins: unknown z %d %P", t[2], p); + return; + + case Zpseudo: + break; + + case Zlit: + for(; op = o->op[z]; z++) + *andptr++ = op; + break; + + case Zm_r: + *andptr++ = op; + asmand(&p->from, reg[p->to.type]); + break; + + case Zaut_r: + *andptr++ = 0x8d; /* leal */ + if(p->from.type != D_ADDR) + diag("asmins: Zaut sb type ADDR"); + p->from.type = p->from.index; + p->from.index = D_NONE; + asmand(&p->from, reg[p->to.type]); + p->from.index = p->from.type; + p->from.type = D_ADDR; + break; + + case Zm_o: + *andptr++ = op; + asmand(&p->from, o->op[z+1]); + break; + + case Zr_m: + *andptr++ = op; + asmand(&p->to, reg[p->from.type]); + break; + + case Zo_m: + *andptr++ = op; + asmand(&p->to, o->op[z+1]); + break; + + case Zm_ibo: + v = vaddr(&p->to); + *andptr++ = op; + asmand(&p->from, o->op[z+1]); + *andptr++ = v; + break; + + case Zibo_m: + *andptr++ = op; + asmand(&p->to, o->op[z+1]); + *andptr++ = v; + break; + + case Z_ib: + v = vaddr(&p->to); + case Zib_: + *andptr++ = op; + *andptr++ = v; + break; + + case Zib_rp: + *andptr++ = op + reg[p->to.type]; + *andptr++ = v; + break; + + case Zil_rp: + *andptr++ = op + reg[p->to.type]; + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Zib_rr: + *andptr++ = op; + asmand(&p->to, reg[p->to.type]); + *andptr++ = v; + break; + + case Z_il: + v = vaddr(&p->to); + case Zil_: + *andptr++ = op; + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Zm_ilo: + v = vaddr(&p->to); + *andptr++ = op; + asmand(&p->from, o->op[z+1]); + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Zilo_m: + *andptr++ = op; + asmand(&p->to, o->op[z+1]); + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Zil_rr: + *andptr++ = op; + asmand(&p->to, reg[p->to.type]); + if(o->prefix == Pe) { + *andptr++ = v; + *andptr++ = v>>8; + } + else + put4(v); + break; + + case Z_rp: + *andptr++ = op + reg[p->to.type]; + break; + + case Zrp_: + *andptr++ = op + reg[p->from.type]; + break; + + case Zclr: + *andptr++ = op; + asmand(&p->to, reg[p->to.type]); + break; + + case Zbr: + q = p->pcond; + if(q) { + v = q->pc - p->pc - 2; + if(v >= -128 && v <= 127) { + *andptr++ = op; + *andptr++ = v; + } else { + v -= 6-2; + *andptr++ = 0x0f; + *andptr++ = o->op[z+1]; + *andptr++ = v; + *andptr++ = v>>8; + *andptr++ = v>>16; + *andptr++ = v>>24; + } + } + break; + + case Zcall: + q = p->pcond; + if(q) { + v = q->pc - p->pc - 5; + if(dlm && curp != P && p->to.sym->type == SUNDEF){ + /* v = 0 - p->pc - 5; */ + v = 0; + ckoff(p->to.sym, v); + v += p->to.sym->value; + dynreloc(p->to.sym, p->pc+1, 0); + } + *andptr++ = op; + *andptr++ = v; + *andptr++ = v>>8; + *andptr++ = v>>16; + *andptr++ = v>>24; + } + break; + + case Zjmp: + q = p->pcond; + if(q) { + v = q->pc - p->pc - 2; + if(v >= -128 && v <= 127) { + *andptr++ = op; + *andptr++ = v; + } else { + v -= 5-2; + *andptr++ = o->op[z+1]; + *andptr++ = v; + *andptr++ = v>>8; + *andptr++ = v>>16; + *andptr++ = v>>24; + } + } + break; + + case Zloop: + q = p->pcond; + if(q) { + v = q->pc - p->pc - 2; + if(v < -128 && v > 127) + diag("loop too far: %P", p); + *andptr++ = op; + *andptr++ = v; + } + break; + + case Zbyte: + *andptr++ = v; + if(op > 1) { + *andptr++ = v>>8; + if(op > 2) { + *andptr++ = v>>16; + *andptr++ = v>>24; + } + } + break; + + case Zmov: + goto domov; + } + return; + +domov: + for(t=ymovtab; *t; t+=8) + if(p->as == t[0]) + if(ycover[ft+t[1]]) + if(ycover[tt+t[2]]) + goto mfound; +bad: + /* + * here, the assembly has failed. + * if its a byte instruction that has + * unaddressable registers, try to + * exchange registers and reissue the + * instruction with the operands renamed. + */ + pp = *p; + z = p->from.type; + if(z >= D_BP && z <= D_DI) { + if(isax(&p->to)) { + *andptr++ = 0x87; /* xchg lhs,bx */ + asmand(&p->from, reg[D_BX]); + subreg(&pp, z, D_BX); + doasm(&pp); + *andptr++ = 0x87; /* xchg lhs,bx */ + asmand(&p->from, reg[D_BX]); + } else { + *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ + subreg(&pp, z, D_AX); + doasm(&pp); + *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ + } + return; + } + z = p->to.type; + if(z >= D_BP && z <= D_DI) { + if(isax(&p->from)) { + *andptr++ = 0x87; /* xchg rhs,bx */ + asmand(&p->to, reg[D_BX]); + subreg(&pp, z, D_BX); + doasm(&pp); + *andptr++ = 0x87; /* xchg rhs,bx */ + asmand(&p->to, reg[D_BX]); + } else { + *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ + subreg(&pp, z, D_AX); + doasm(&pp); + *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ + } + return; + } + diag("doasm: notfound t2=%lux from=%lux to=%lux %P", t[2], p->from.type, p->to.type, p); + return; + +mfound: + switch(t[3]) { + default: + diag("asmins: unknown mov %d %P", t[3], p); + break; + + case 0: /* lit */ + for(z=4; t[z]!=E; z++) + *andptr++ = t[z]; + break; + + case 1: /* r,m */ + *andptr++ = t[4]; + asmand(&p->to, t[5]); + break; + + case 2: /* m,r */ + *andptr++ = t[4]; + asmand(&p->from, t[5]); + break; + + case 3: /* r,m - 2op */ + *andptr++ = t[4]; + *andptr++ = t[5]; + asmand(&p->to, t[6]); + break; + + case 4: /* m,r - 2op */ + *andptr++ = t[4]; + *andptr++ = t[5]; + asmand(&p->from, t[6]); + break; + + case 5: /* load full pointer, trash heap */ + if(t[4]) + *andptr++ = t[4]; + switch(p->to.index) { + default: + goto bad; + case D_DS: + *andptr++ = 0xc5; + break; + case D_SS: + *andptr++ = 0x0f; + *andptr++ = 0xb2; + break; + case D_ES: + *andptr++ = 0xc4; + break; + case D_FS: + *andptr++ = 0x0f; + *andptr++ = 0xb4; + break; + case D_GS: + *andptr++ = 0x0f; + *andptr++ = 0xb5; + break; + } + asmand(&p->from, reg[p->to.type]); + break; + + case 6: /* double shift */ + z = p->from.type; + switch(z) { + default: + goto bad; + case D_CONST: + *andptr++ = 0x0f; + *andptr++ = t[4]; + asmand(&p->to, reg[p->from.index]); + *andptr++ = p->from.offset; + break; + case D_CL: + case D_CX: + *andptr++ = 0x0f; + *andptr++ = t[5]; + asmand(&p->to, reg[p->from.index]); + break; + } + break; + + case 7: /* imul rm,r */ + *andptr++ = t[4]; + *andptr++ = t[5]; + asmand(&p->from, reg[p->to.type]); + break; + } +} + +void +asmins(Prog *p) +{ + + andptr = and; + doasm(p); +} + +enum{ + ABSD = 0, + ABSU = 1, + RELD = 2, + RELU = 3, +}; + +int modemap[4] = { 0, 1, -1, 2, }; + +typedef struct Reloc Reloc; + +struct Reloc +{ + int n; + int t; + uchar *m; + ulong *a; +}; + +Reloc rels; + +static void +grow(Reloc *r) +{ + int t; + uchar *m, *nm; + ulong *a, *na; + + t = r->t; + r->t += 64; + m = r->m; + a = r->a; + r->m = nm = malloc(r->t*sizeof(uchar)); + r->a = na = malloc(r->t*sizeof(ulong)); + memmove(nm, m, t*sizeof(uchar)); + memmove(na, a, t*sizeof(ulong)); + free(m); + free(a); +} + +void +dynreloc(Sym *s, ulong v, int abs) +{ + int i, k, n; + uchar *m; + ulong *a; + Reloc *r; + + if(s->type == SUNDEF) + k = abs ? ABSU : RELU; + else + k = abs ? ABSD : RELD; + /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */ + k = modemap[k]; + r = &rels; + n = r->n; + if(n >= r->t) + grow(r); + m = r->m; + a = r->a; + for(i = n; i > 0; i--){ + if(v < a[i-1]){ /* happens occasionally for data */ + m[i] = m[i-1]; + a[i] = a[i-1]; + } + else + break; + } + m[i] = k; + a[i] = v; + r->n++; +} + +static int +sput(char *s) +{ + char *p; + + p = s; + while(*s) + cput(*s++); + cput(0); + return s-p+1; +} + +void +asmdyn() +{ + int i, n, t, c; + Sym *s; + ulong la, ra, *a; + vlong off; + uchar *m; + Reloc *r; + + cflush(); + off = seek(cout, 0, 1); + lput(0); + t = 0; + lput(imports); + t += 4; + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->type == SUNDEF){ + lput(s->sig); + t += 4; + t += sput(s->name); + } + + la = 0; + r = &rels; + n = r->n; + m = r->m; + a = r->a; + lput(n); + t += 4; + for(i = 0; i < n; i++){ + ra = *a-la; + if(*a < la) + diag("bad relocation order"); + if(ra < 256) + c = 0; + else if(ra < 65536) + c = 1; + else + c = 2; + cput((c<<6)|*m++); + t++; + if(c == 0){ + cput(ra); + t++; + } + else if(c == 1){ + wputb(ra); + t += 2; + } + else{ + lput(ra); + t += 4; + } + la = *a++; + } + + cflush(); + seek(cout, off, 0); + lput(t); + + if(debug['v']){ + Bprint(&bso, "import table entries = %d\n", imports); + Bprint(&bso, "export table entries = %d\n", exports); + } +} |