diff options
67 files changed, 17383 insertions, 17703 deletions
diff --git a/include/link.h b/include/link.h new file mode 100644 index 000000000..1d6aec49e --- /dev/null +++ b/include/link.h @@ -0,0 +1,567 @@ +// Derived from Inferno utils/6l/l.h and related files. +// http://code.google.com/p/inferno-os/source/browse/utils/6l/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. + +typedef struct Addr Addr; +typedef struct Prog Prog; +typedef struct LSym LSym; +typedef struct Reloc Reloc; +typedef struct Auto Auto; +typedef struct Hist Hist; +typedef struct Hist2 Hist2; +typedef struct Link Link; +typedef struct Plist Plist; +typedef struct LinkArch LinkArch; +typedef struct Library Library; + +typedef struct Pcln Pcln; +typedef struct Pcdata Pcdata; + +struct Addr +{ + vlong offset; + + union + { + char sval[8]; + float64 dval; + Prog* branch; // for 5g, 6g, 8g + } u; + + LSym* sym; + LSym* gotype; + short type; + uint8 index; + int8 scale; + int8 reg; // for 5l + int8 name; // for 5l + int8 class; // for 5l + uint8 etype; // for 5g, 6g, 8g + int32 offset2; // for 5l, 8l + struct Node* node; // for 5g, 6g, 8g + int64 width; // for 5g, 6g, 8g +}; + +struct Reloc +{ + int32 off; + uchar siz; + uchar done; + int32 type; + int64 add; + int64 xadd; + LSym* sym; + LSym* xsym; +}; + +struct Prog +{ + vlong pc; + int32 lineno; + Prog* link; + short as; + uchar reg; // arm only + uchar scond; // arm only + Addr from; + Addr to; + + // for 5g, 6g, 8g internal use + uint32 loc; // TODO: merge with pc? + void* opt; + + // for 5l, 6l, 8l internal use + Prog* forwd; + Prog* pcond; + Prog* comefrom; // 6l, 8l + Prog* pcrel; // 5l + int32 spadj; + uchar mark; + uchar back; // 6l, 8l + char ft; /* 6l, 8l oclass cache */ + char tt; // 6l, 8l + uchar optab; // 5l + + char width; /* fake for DATA */ + char mode; /* 16, 32, or 64 */ +}; + +struct LSym +{ + char* name; + char* extname; // name used in external object files + short type; + short version; + uchar dupok; + uchar reachable; + uchar cgoexport; + uchar special; + uchar stkcheck; + uchar hide; + uchar leaf; // arm only + uchar fnptr; // arm only + int16 symid; // for writing .5/.6/.8 files + int32 dynid; + int32 sig; + int32 plt; + int32 got; + int32 align; // if non-zero, required alignment in bytes + int32 elfsym; + int32 args; // size of stack frame incoming arguments area + int32 locals; // size of stack frame locals area (arm only?) + vlong value; + vlong size; + LSym* hash; // in hash table + LSym* allsym; // in all symbol list + LSym* next; // in text or data list + LSym* sub; // in SSUB list + LSym* outer; // container of sub + LSym* gotype; + LSym* reachparent; + LSym* queue; + char* file; + char* dynimplib; + char* dynimpvers; + struct Section* sect; + Hist2* hist; // for ATEXT + + // STEXT + Auto* autom; + Prog* text; + Pcln* pcln; + + // SDATA, SBSS + uchar* p; + int32 np; + int32 maxp; + Reloc* r; + int32 nr; + int32 maxr; +}; + +// LSym.type +enum +{ + Sxxx, + + /* order here is order in output file */ + /* readonly, executable */ + STEXT, + SELFRXSECT, + + /* readonly, non-executable */ + STYPE, + SSTRING, + SGOSTRING, + SGOFUNC, + SRODATA, + SFUNCTAB, + STYPELINK, + SSYMTAB, // TODO: move to unmapped section + SPCLNTAB, + SELFROSECT, + + /* writable, non-executable */ + SMACHOPLT, + SELFSECT, + SMACHO, /* Mach-O __nl_symbol_ptr */ + SMACHOGOT, + SNOPTRDATA, + SINITARR, + SDATA, + SWINDOWS, + SBSS, + SNOPTRBSS, + STLSBSS, + + /* not mapped */ + SXREF, + SMACHOSYMSTR, + SMACHOSYMTAB, + SMACHOINDIRECTPLT, + SMACHOINDIRECTGOT, + SFILE, + SFILEPATH, + SCONST, + SDYNIMPORT, + SHOSTOBJ, + + SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */ + SMASK = SSUB - 1, + SHIDDEN = 1<<9, // hidden or local symbol +}; + +struct Auto +{ + LSym* asym; + Auto* link; + int32 aoffset; + int16 type; + LSym* gotype; +}; + +enum +{ + LINKHASH = 100003, +}; + +struct Hist +{ + Hist* link; + char* name; + int32 line; + int32 offset; +}; + +struct Plist +{ + LSym* name; + Prog* firstpc; + int recur; + Plist* link; +}; + +struct Library +{ + char *objref; // object where we found the reference + char *srcref; // src file where we found the reference + char *file; // object file + char *pkg; // import path +}; + +struct Pcdata +{ + uchar *p; + int n; + int m; +}; + +struct Pcln +{ + Pcdata pcsp; + Pcdata pcfile; + Pcdata pcline; + Pcdata *pcdata; + int npcdata; + LSym **funcdata; + int64 *funcdataoff; + int nfuncdata; + + LSym **file; + int nfile; + int mfile; + + LSym *lastfile; + int lastindex; +}; + +enum +{ + LinkMaxHist = 40, +}; + +// TODO: Replace uses of Hist2 with Hist and delete this. +struct Hist2 +{ + int32 line; + int32 off; + LSym *file; +}; + +// symbol version, incremented each time a file is loaded. +// version==1 is reserved for savehist. +enum +{ + HistVersion = 1, +}; + +// Link holds the context for writing object code from a compiler +// to be linker input or for reading that input into the linker. +struct Link +{ + int32 thechar; // '5' (arm), '6' (amd64), etc. + char* thestring; // full name of architecture ("arm", "amd64", ..) + int32 goarm; // for arm only, GOARM setting + int headtype; + int linkmode; + + LinkArch* arch; + int32 (*ignore)(char*); // do not emit names satisfying this function + int32 debugasm; // -S flag in compiler + int32 debugline; // -L flag in compiler + int32 debughist; // -O flag in linker + int32 debugread; // -W flag in linker + int32 debugvlog; // -v flag in linker + int32 debugstack; // -K flag in linker + int32 debugzerostack; // -Z flag in linker + int32 debugdivmod; // -M flag in 5l + int32 debugfloat; // -F flag in 5l + int32 debugpcln; // -O flag in linker + int32 flag_shared; // -shared flag in linker + int32 iself; + Biobuf* bso; // for -v flag + char* pathname; + int32 windows; + + // hash table of all symbols + LSym* hash[LINKHASH]; + LSym* allsym; + int32 nsymbol; + + // file-line history + Hist* hist; + Hist* ehist; + + // all programs + Plist* plist; + Plist* plast; + + // code generation + LSym* sym_div; + LSym* sym_divu; + LSym* sym_mod; + LSym* sym_modu; + LSym* symmorestack[10]; + LSym* gmsym; + LSym* plan9tos; + Prog* curp; + Prog* printp; + Prog* blitrl; + Prog* elitrl; + int rexflag; + int asmode; + uchar* andptr; + uchar and[100]; + int32 instoffset; + int32 autosize; + int32 armsize; + + // for reading input files (during linker) + vlong pc; + char** libdir; + int32 nlibdir; + int32 maxlibdir; + Library* library; + int libraryp; + int nlibrary; + int tlsoffset; + void (*diag)(char*, ...); + void (*dwarfaddfrag)(int, char*); + LSym* histfrog[LinkMaxHist]; + int histfrogp; + int histgen; + Auto* curauto; + Auto* curhist; + LSym* cursym; + int version; + LSym* textp; + LSym* etextp; + Hist2* histcopy; + Hist2* hist2; + int32 nhist2; + int32 maxhist2; + int32 histdepth; + int32 nhistfile; + LSym* filesyms; +}; + +// LinkArch is the definition of a single architecture. +struct LinkArch +{ + char* name; // "arm", "amd64", and so on + + void (*addstacksplit)(Link*, LSym*); + void (*assemble)(Link*, LSym*); + int (*datasize)(Prog*); + void (*follow)(Link*, LSym*); + int (*iscall)(Prog*); + int (*isdata)(Prog*); + void (*ldobj)(Link*, Biobuf*, char*, int64, char*); + void (*nopout)(Prog*); + Prog* (*prg)(void); + void (*progedit)(Link*, Prog*); + void (*settextflag)(Prog*, int); + int (*symtype)(Addr*); + int (*textflag)(Prog*); + void (*zfile)(Biobuf*, char*, int); + void (*zhist)(Biobuf*, int, vlong); + void (*zprog)(Link*, Biobuf*, Prog*, int, int, int, int); + void (*zname)(Biobuf*, LSym*, int); + + int minlc; + int ptrsize; + + // TODO: Give these the same values on all systems. + int D_ADDR; + int D_BRANCH; + int D_CONST; + int D_EXTERN; + int D_FCONST; + int D_NONE; + int D_PCREL; + int D_SCONST; + int D_SIZE; + + int ACALL; + int AFUNCDATA; + int AJMP; + int ANOP; + int APCDATA; + int ARET; + int ATEXT; + int AUSEFIELD; +}; + +/* executable header types */ +enum { + Hunknown = 0, + Hdarwin, + Hdragonfly, + Helf, + Hfreebsd, + Hlinux, + Hnetbsd, + Hopenbsd, + Hplan9, + Hwindows, +}; + +enum +{ + LinkAuto = 0, + LinkInternal, + LinkExternal, +}; + +extern uchar fnuxi8[8]; +extern uchar fnuxi4[4]; +extern uchar inuxi1[1]; +extern uchar inuxi2[2]; +extern uchar inuxi4[4]; +extern uchar inuxi8[8]; + +// asm5.c +void span5(Link *ctxt, LSym *s); + +// asm6.c +void span6(Link *ctxt, LSym *s); + +// asm8.c +void span8(Link *ctxt, LSym *s); + +// data.c +vlong addaddr(Link *ctxt, LSym *s, LSym *t); +vlong addaddrplus(Link *ctxt, LSym *s, LSym *t, vlong add); +vlong addaddrplus4(Link *ctxt, LSym *s, LSym *t, vlong add); +vlong addpcrelplus(Link *ctxt, LSym *s, LSym *t, vlong add); +Reloc* addrel(LSym *s); +vlong addsize(Link *ctxt, LSym *s, LSym *t); +vlong adduint16(Link *ctxt, LSym *s, uint16 v); +vlong adduint32(Link *ctxt, LSym *s, uint32 v); +vlong adduint64(Link *ctxt, LSym *s, uint64 v); +vlong adduint8(Link *ctxt, LSym *s, uint8 v); +vlong adduintxx(Link *ctxt, LSym *s, uint64 v, int wid); +void mangle(char *file); +void savedata(Link *ctxt, LSym *s, Prog *p, char *pn); +vlong setaddr(Link *ctxt, LSym *s, vlong off, LSym *t); +vlong setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add); +vlong setuint16(Link *ctxt, LSym *s, vlong r, uint16 v); +vlong setuint32(Link *ctxt, LSym *s, vlong r, uint32 v); +vlong setuint64(Link *ctxt, LSym *s, vlong r, uint64 v); +vlong setuint8(Link *ctxt, LSym *s, vlong r, uint8 v); +vlong setuintxx(Link *ctxt, LSym *s, vlong off, uint64 v, vlong wid); +void symgrow(Link *ctxt, LSym *s, int32 siz); + +// go.c +void* emallocz(long n); +void* erealloc(void *p, long n); +char* estrdup(char *p); +char* expandpkg(char *t0, char *pkg); + +// ieee.c +void double2ieee(uint64 *ieee, double native); + +// ld.c +void addhist(Link *ctxt, int32 line, int type); +void addlib(Link *ctxt, char *src, char *obj); +void addlibpath(Link *ctxt, char *srcref, char *objref, char *file, char *pkg); +void collapsefrog(Link *ctxt, LSym *s); +void copyhistfrog(Link *ctxt, char *buf, int nbuf); +int find1(int32 l, int c); +Hist2* gethist(Link *ctxt); +void linkgetline(Link *ctxt, Hist2 *h, int32 line, LSym **f, int32 *l); +void histtoauto(Link *ctxt); +void mkfwd(LSym*); +void nuxiinit(void); +void savehist(Link *ctxt, int32 line, int32 off); +Prog* copyp(Link*, Prog*); +Prog* appendp(Link*, Prog*); +vlong atolwhex(char*); + +// obj.c +int linklinefmt(Link *ctxt, Fmt *fp); +void linklinehist(Link *ctxt, int lineno, char *f, int offset); +Plist* linknewplist(Link *ctxt); +void linkouthist(Link *ctxt, Biobuf *b); +void linkprfile(Link *ctxt, int32 l); +void linkwritefuncs(Link *ctxt, Biobuf *b); + +// pass.c +Prog* brchain(Link *ctxt, Prog *p); +Prog* brloop(Link *ctxt, Prog *p); +void linkpatch(Link *ctxt, LSym *sym); + +// pcln.c +void linkpcln(Link*, LSym*); + +// rdobj5.c +void ldobj5(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn); +void nopout5(Prog *p); + +// rdobj6.c +void ldobj6(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn); +void nopout6(Prog *p); + +// rdobj8.c +void ldobj8(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn); +void nopout8(Prog *p); + +// sym.c +LSym* linklookup(Link *ctxt, char *name, int v); +Link* linknew(LinkArch*); +LSym* linknewsym(Link *ctxt, char *symb, int v); +LSym* linkrlookup(Link *ctxt, char *name, int v); +int linksymfmt(Fmt *f); + +extern char* anames5[]; +extern char* anames6[]; +extern char* anames8[]; + +extern LinkArch link386; +extern LinkArch linkamd64; +extern LinkArch linkarm; diff --git a/include/u.h b/include/u.h index 44bfcd63b..6b2d50cc1 100644 --- a/include/u.h +++ b/include/u.h @@ -188,6 +188,8 @@ typedef u32int uint32; typedef s64int int64; typedef u64int uint64; +typedef float float32; +typedef double float64; #undef _NEEDUCHAR #undef _NEEDUSHORT diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h index ebbadde2c..f832f2af8 100644 --- a/src/cmd/5l/5.out.h +++ b/src/cmd/5l/5.out.h @@ -234,62 +234,53 @@ enum as #define SHIFT_AR 2<<5 #define SHIFT_RR 3<<5 +enum +{ /* type/name */ -#define D_GOK 0 -#define D_NONE 1 + D_GOK = 0, + D_NONE = 1, /* type */ -#define D_BRANCH (D_NONE+1) -#define D_OREG (D_NONE+2) -#define D_CONST (D_NONE+7) -#define D_FCONST (D_NONE+8) -#define D_SCONST (D_NONE+9) -#define D_PSR (D_NONE+10) -#define D_REG (D_NONE+12) -#define D_FREG (D_NONE+13) -#define D_FILE (D_NONE+16) -#define D_OCONST (D_NONE+17) -#define D_FILE1 (D_NONE+18) - -#define D_SHIFT (D_NONE+19) -#define D_FPCR (D_NONE+20) -#define D_REGREG (D_NONE+21) // (reg, reg) -#define D_ADDR (D_NONE+22) - -#define D_SBIG (D_NONE+23) -#define D_CONST2 (D_NONE+24) - -#define D_REGREG2 (D_NONE+25) // reg, reg + D_BRANCH = (D_NONE+1), + D_OREG = (D_NONE+2), + D_CONST = (D_NONE+7), + D_FCONST = (D_NONE+8), + D_SCONST = (D_NONE+9), + D_PSR = (D_NONE+10), + D_REG = (D_NONE+12), + D_FREG = (D_NONE+13), + D_FILE = (D_NONE+16), + D_OCONST = (D_NONE+17), + D_FILE1 = (D_NONE+18), + + D_SHIFT = (D_NONE+19), + D_FPCR = (D_NONE+20), + D_REGREG = (D_NONE+21), // (reg, reg) + D_ADDR = (D_NONE+22), + + D_SBIG = (D_NONE+23), + D_CONST2 = (D_NONE+24), + + D_REGREG2 = (D_NONE+25), // reg, reg /* name */ -#define D_EXTERN (D_NONE+3) -#define D_STATIC (D_NONE+4) -#define D_AUTO (D_NONE+5) -#define D_PARAM (D_NONE+6) + D_EXTERN = (D_NONE+3), + D_STATIC = (D_NONE+4), + D_AUTO = (D_NONE+5), + D_PARAM = (D_NONE+6), /* internal only */ -#define D_SIZE (D_NONE+40) -#define D_PCREL (D_NONE+41) -#define D_GOTOFF (D_NONE+42) // R_ARM_GOTOFF -#define D_PLT0 (D_NONE+43) // R_ARM_PLT32, 1st inst: add ip, pc, #0xNN00000 -#define D_PLT1 (D_NONE+44) // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000 -#define D_PLT2 (D_NONE+45) // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]! -#define D_CALL (D_NONE+46) // R_ARM_PLT32/R_ARM_CALL/R_ARM_JUMP24, bl xxxxx or b yyyyy -#define D_TLS (D_NONE+47) // R_ARM_TLS_LE32 + D_SIZE = (D_NONE+40), + D_PCREL = (D_NONE+41), + D_GOTOFF = (D_NONE+42), // R_ARM_GOTOFF + D_PLT0 = (D_NONE+43), // R_ARM_PLT32, 1st inst: add ip, pc, #0xNN00000 + D_PLT1 = (D_NONE+44), // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000 + D_PLT2 = (D_NONE+45), // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]! + D_CALL = (D_NONE+46), // R_ARM_PLT32/R_ARM_CALL/R_ARM_JUMP24, bl xxxxx or b yyyyy + D_TLS = (D_NONE+47), // R_ARM_TLS_LE32 +}; /* * this is the ranlib header */ #define SYMDEF "__.GOSYMDEF" - -/* - * this is the simulated IEEE floating point - */ -typedef struct ieee Ieee; -struct ieee -{ - int32 l; /* contains ls-man 0xffffffff */ - int32 h; /* contains sign 0x80000000 - exp 0x7ff00000 - ms-man 0x000fffff */ -}; diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c index 33cdf8096..85600cabf 100644 --- a/src/cmd/5l/asm.c +++ b/src/cmd/5l/asm.c @@ -35,7 +35,6 @@ #include "../ld/elf.h" #include "../ld/dwarf.h" -static Prog *PP; char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI char freebsddynld[] = "/usr/libexec/ld-elf.so.1"; @@ -43,35 +42,18 @@ char openbsddynld[] = "XXX"; char netbsddynld[] = "/libexec/ld.elf_so"; char dragonflydynld[] = "XXX"; -int32 -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; - if(s->type != STEXT) - diag("entry not text: %s", s->name); - return s->value; -} - static int needlib(char *name) { char *p; - Sym *s; + LSym *s; if(*name == '\0') return 0; /* reuse hash code in symbol table */ p = smprint(".dynlib.%s", name); - s = lookup(p, 0); + s = linklookup(ctxt, p, 0); free(p); if(s->type == 0) { s->type = 100; // avoid SDATA, etc. @@ -82,9 +64,9 @@ needlib(char *name) int nelfsym = 1; -static void addpltsym(Sym*); -static void addgotsym(Sym*); -static void addgotsyminternal(Sym*); +static void addpltsym(Link*, LSym*); +static void addgotsym(Link*, LSym*); +static void addgotsyminternal(Link*, LSym*); // Preserve highest 8 bits of a, and do addition to lower 24-bit // of a and b; used to adjust ARM branch intruction's target @@ -95,19 +77,19 @@ braddoff(int32 a, int32 b) } void -adddynrela(Sym *rel, Sym *s, Reloc *r) +adddynrela(LSym *rel, LSym *s, Reloc *r) { - addaddrplus(rel, s, r->off); - adduint32(rel, R_ARM_RELATIVE); + addaddrplus(ctxt, rel, s, r->off); + adduint32(ctxt, rel, R_ARM_RELATIVE); } void -adddynrel(Sym *s, Reloc *r) +adddynrel(LSym *s, Reloc *r) { - Sym *targ, *rel; + LSym *targ, *rel; targ = r->sym; - cursym = s; + ctxt->cursym = s; switch(r->type) { default: @@ -121,8 +103,8 @@ adddynrel(Sym *s, Reloc *r) case 256 + R_ARM_PLT32: r->type = D_CALL; if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = braddoff(r->add, targ->plt / 4); } return; @@ -134,9 +116,9 @@ adddynrel(Sym *s, Reloc *r) case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL if(targ->type != SDYNIMPORT) { - addgotsyminternal(targ); + addgotsyminternal(ctxt, targ); } else { - addgotsym(targ); + addgotsym(ctxt, targ); } r->type = D_CONST; // write r->add during relocsym r->sym = S; @@ -145,12 +127,12 @@ adddynrel(Sym *s, Reloc *r) case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P if(targ->type != SDYNIMPORT) { - addgotsyminternal(targ); + addgotsyminternal(ctxt, targ); } else { - addgotsym(targ); + addgotsym(ctxt, targ); } r->type = D_PCREL; - r->sym = lookup(".got", 0); + r->sym = linklookup(ctxt, ".got", 0); r->add += targ->got + 4; return; @@ -160,15 +142,15 @@ adddynrel(Sym *s, Reloc *r) case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL r->type = D_PCREL; - r->sym = lookup(".got", 0); + r->sym = linklookup(ctxt, ".got", 0); r->add += 4; return; case 256 + R_ARM_CALL: r->type = D_CALL; if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = braddoff(r->add, targ->plt / 4); } return; @@ -197,8 +179,8 @@ adddynrel(Sym *s, Reloc *r) case 256 + R_ARM_JUMP24: r->type = D_CALL; if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = braddoff(r->add, targ->plt / 4); } return; @@ -210,8 +192,8 @@ adddynrel(Sym *s, Reloc *r) switch(r->type) { case D_PCREL: - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = targ->plt; return; @@ -219,10 +201,10 @@ adddynrel(Sym *s, Reloc *r) if(s->type != SDATA) break; if(iself) { - adddynsym(targ); - rel = lookup(".rel", 0); - addaddrplus(rel, s, r->off); - adduint32(rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc + adddynsym(ctxt, targ); + rel = linklookup(ctxt, ".rel", 0); + addaddrplus(ctxt, rel, s, r->off); + adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc r->type = D_CONST; // write r->add during relocsym r->sym = S; return; @@ -230,7 +212,7 @@ adddynrel(Sym *s, Reloc *r) break; } - cursym = s; + ctxt->cursym = s; diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); } @@ -287,26 +269,26 @@ elfreloc1(Reloc *r, vlong sectoff) void elfsetupplt(void) { - Sym *plt, *got; + LSym *plt, *got; - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); if(plt->size == 0) { // str lr, [sp, #-4]! - adduint32(plt, 0xe52de004); + adduint32(ctxt, plt, 0xe52de004); // ldr lr, [pc, #4] - adduint32(plt, 0xe59fe004); + adduint32(ctxt, plt, 0xe59fe004); // add lr, pc, lr - adduint32(plt, 0xe08fe00e); + adduint32(ctxt, plt, 0xe08fe00e); // ldr pc, [lr, #8]! - adduint32(plt, 0xe5bef008); + adduint32(ctxt, plt, 0xe5bef008); // .word &GLOBAL_OFFSET_TABLE[0] - . - addpcrelplus(plt, got, 4); + addpcrelplus(ctxt, plt, got, 4); // the first .plt entry requires 3 .plt.got entries - adduint32(got, 0); - adduint32(got, 0); - adduint32(got, 0); + adduint32(ctxt, got, 0); + adduint32(ctxt, got, 0); + adduint32(ctxt, got, 0); } } @@ -321,9 +303,9 @@ machoreloc1(Reloc *r, vlong sectoff) int -archreloc(Reloc *r, Sym *s, vlong *val) +archreloc(Reloc *r, LSym *s, vlong *val) { - Sym *rs; + LSym *rs; if(linkmode == LinkExternal) { switch(r->type) { @@ -356,23 +338,23 @@ archreloc(Reloc *r, Sym *s, vlong *val) *val = r->add; return 0; case D_GOTOFF: - *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0)); + *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0)); return 0; // The following three arch specific relocations are only for generation of // Linux/ARM ELF's PLT entry (3 assembler instruction) case D_PLT0: // add ip, pc, #0xXX00000 - if (symaddr(lookup(".got.plt", 0)) < symaddr(lookup(".plt", 0))) + if (symaddr(linklookup(ctxt, ".got.plt", 0)) < symaddr(linklookup(ctxt, ".plt", 0))) diag(".got.plt should be placed after .plt section."); *val = 0xe28fc600U + - (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add) >> 20)); + (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add) >> 20)); return 0; case D_PLT1: // add ip, ip, #0xYY000 *val = 0xe28cca00U + - (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 4) >> 12)); + (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 4) >> 12)); return 0; case D_PLT2: // ldr pc, [ip, #0xZZZ]! *val = 0xe5bcf000U + - (0xfff & (uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 8)); + (0xfff & (uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 8)); return 0; case D_CALL: // bl XXXXXX or b YYYYYY *val = braddoff((0xff000000U & (uint32)r->add), @@ -384,7 +366,7 @@ archreloc(Reloc *r, Sym *s, vlong *val) } static Reloc * -addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ) +addpltreloc(Link *ctxt, LSym *plt, LSym *got, LSym *sym, int typ) { Reloc *r; @@ -397,25 +379,25 @@ addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ) plt->reachable = 1; plt->size += 4; - symgrow(plt, plt->size); + symgrow(ctxt, plt, plt->size); return r; } static void -addpltsym(Sym *s) +addpltsym(Link *ctxt, LSym *s) { - Sym *plt, *got, *rel; + LSym *plt, *got, *rel; if(s->plt >= 0) return; - adddynsym(s); + adddynsym(ctxt, s); if(iself) { - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); - rel = lookup(".rel.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); + rel = linklookup(ctxt, ".rel.plt", 0); if(plt->size == 0) elfsetupplt(); @@ -424,34 +406,34 @@ addpltsym(Sym *s) // In theory, all GOT should point to the first PLT entry, // Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's // dynamic linker won't, so we'd better do it ourselves. - addaddrplus(got, plt, 0); + addaddrplus(ctxt, got, plt, 0); // .plt entry, this depends on the .got entry s->plt = plt->size; - addpltreloc(plt, got, s, D_PLT0); // add lr, pc, #0xXX00000 - addpltreloc(plt, got, s, D_PLT1); // add lr, lr, #0xYY000 - addpltreloc(plt, got, s, D_PLT2); // ldr pc, [lr, #0xZZZ]! + addpltreloc(ctxt, plt, got, s, D_PLT0); // add lr, pc, #0xXX00000 + addpltreloc(ctxt, plt, got, s, D_PLT1); // add lr, lr, #0xYY000 + addpltreloc(ctxt, plt, got, s, D_PLT2); // ldr pc, [lr, #0xZZZ]! // rel - addaddrplus(rel, got, s->got); - adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT)); + addaddrplus(ctxt, rel, got, s->got); + adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT)); } else { diag("addpltsym: unsupported binary format"); } } static void -addgotsyminternal(Sym *s) +addgotsyminternal(Link *ctxt, LSym *s) { - Sym *got; + LSym *got; if(s->got >= 0) return; - got = lookup(".got", 0); + got = linklookup(ctxt, ".got", 0); s->got = got->size; - addaddrplus(got, s, 0); + addaddrplus(ctxt, got, s, 0); if(iself) { ; @@ -461,31 +443,31 @@ addgotsyminternal(Sym *s) } static void -addgotsym(Sym *s) +addgotsym(Link *ctxt, LSym *s) { - Sym *got, *rel; + LSym *got, *rel; if(s->got >= 0) return; - adddynsym(s); - got = lookup(".got", 0); + adddynsym(ctxt, s); + got = linklookup(ctxt, ".got", 0); s->got = got->size; - adduint32(got, 0); + adduint32(ctxt, got, 0); if(iself) { - rel = lookup(".rel", 0); - addaddrplus(rel, got, s->got); - adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT)); + rel = linklookup(ctxt, ".rel", 0); + addaddrplus(ctxt, rel, got, s->got); + adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT)); } else { diag("addgotsym: unsupported binary format"); } } void -adddynsym(Sym *s) +adddynsym(Link *ctxt, LSym *s) { - Sym *d; + LSym *d; int t; char *name; @@ -495,20 +477,20 @@ adddynsym(Sym *s) if(iself) { s->dynid = nelfsym++; - d = lookup(".dynsym", 0); + d = linklookup(ctxt, ".dynsym", 0); /* name */ name = s->extname; - adduint32(d, addstring(lookup(".dynstr", 0), name)); + adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); /* value */ if(s->type == SDYNIMPORT) - adduint32(d, 0); + adduint32(ctxt, d, 0); else - addaddr(d, s); + addaddr(ctxt, d, s); /* size */ - adduint32(d, 0); + adduint32(ctxt, d, 0); /* type */ t = STB_GLOBAL << 4; @@ -516,12 +498,12 @@ adddynsym(Sym *s) t |= STT_FUNC; else t |= STT_OBJECT; - adduint8(d, t); - adduint8(d, 0); + adduint8(ctxt, d, t); + adduint8(ctxt, d, 0); /* shndx */ if(s->type == SDYNIMPORT) - adduint16(d, SHN_UNDEF); + adduint16(ctxt, d, SHN_UNDEF); else { switch(s->type) { default: @@ -538,7 +520,7 @@ adddynsym(Sym *s) t = 14; break; } - adduint16(d, t); + adduint16(ctxt, d, t); } } else { diag("adddynsym: unsupported binary format"); @@ -548,39 +530,27 @@ adddynsym(Sym *s) void adddynlib(char *lib) { - Sym *s; + LSym *s; if(!needlib(lib)) return; if(iself) { - s = lookup(".dynstr", 0); + s = linklookup(ctxt, ".dynstr", 0); if(s->size == 0) addstring(s, ""); - elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); + elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); } else { diag("adddynlib: unsupported binary format"); } } -vlong -datoff(vlong addr) -{ - if(addr >= segdata.vaddr) - return addr - segdata.vaddr + segdata.fileoff; - if(addr >= segtext.vaddr) - return addr - segtext.vaddr + segtext.fileoff; - diag("datoff %#x", addr); - return 0; -} - void asmb(void) { - int32 t; uint32 symo; Section *sect; - Sym *sym; + LSym *sym; int i; if(debug['v']) @@ -627,13 +597,7 @@ asmb(void) default: if(iself) goto ElfSym; - case Hnoheader: - case Hrisc: - case Hixp1200: - case Hipaq: - debug['s'] = 1; - break; - case Hplan9x32: + case Hplan9: symo = HEADR+segtext.len+segdata.filelen; break; ElfSym: @@ -659,11 +623,11 @@ asmb(void) elfemitreloc(); } break; - case Hplan9x32: + case Hplan9: asmplan9sym(); cflush(); - sym = lookup("pclntab", 0); + sym = linklookup(ctxt, "pclntab", 0); if(sym != nil) { lcsize = sym->np; for(i=0; i < lcsize; i++) @@ -675,46 +639,14 @@ asmb(void) } } - cursym = nil; + ctxt->cursym = nil; if(debug['v']) Bprint(&bso, "%5.2f header\n", cputime()); Bflush(&bso); cseek(0L); switch(HEADTYPE) { default: - case Hnoheader: /* no header */ - break; - case Hrisc: /* aif for risc os */ - lputl(0xe1a00000); /* NOP - decompress code */ - lputl(0xe1a00000); /* NOP - relocation code */ - lputl(0xeb000000 + 12); /* BL - zero init code */ - lputl(0xeb000000 + - (entryvalue() - - INITTEXT - + HEADR - - 12 - - 8) / 4); /* BL - entry code */ - - lputl(0xef000011); /* SWI - exit code */ - lputl(segtext.filelen+HEADR); /* text size */ - lputl(segdata.filelen); /* data size */ - lputl(0); /* sym size */ - - lputl(segdata.len - segdata.filelen); /* bss size */ - lputl(0); /* sym type */ - lputl(INITTEXT-HEADR); /* text addr */ - lputl(0); /* workspace - ignored */ - - lputl(32); /* addr mode / data addr flag */ - lputl(0); /* data addr */ - for(t=0; t<2; t++) - lputl(0); /* reserved */ - - for(t=0; t<15; t++) - lputl(0xe1a00000); /* NOP - zero init code */ - lputl(0xe1a0f00e); /* B (R14) - zero init return */ - break; - case Hplan9x32: /* plan 9 */ + case Hplan9: /* plan 9 */ lput(0x647); /* magic */ lput(segtext.filelen); /* sizes */ lput(segdata.filelen); @@ -724,14 +656,6 @@ asmb(void) lput(0L); lput(lcsize); break; - case Hixp1200: /* boot for IXP1200 */ - break; - case Hipaq: /* boot for ipaq */ - lputl(0xe3300000); /* nop */ - lputl(0xe3300000); /* nop */ - lputl(0xe3300000); /* nop */ - lputl(0xe3300000); /* nop */ - break; case Hlinux: case Hfreebsd: case Hnetbsd: @@ -808,1224 +732,17 @@ nopstat(char *f, Count *c) (double)(c->outof - c->count)/c->outof); } -void -asmout(Prog *p, Optab *o, int32 *out, Sym *gmsym) -{ - int32 o1, o2, o3, o4, o5, o6, v; - int r, rf, rt, rt2; - Reloc *rel; - -PP = p; - o1 = 0; - o2 = 0; - o3 = 0; - o4 = 0; - o5 = 0; - o6 = 0; - armsize += o->size; -if(debug['P']) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type); - switch(o->type) { - default: - diag("unknown asm %d", o->type); - prasm(p); - break; - - case 0: /* pseudo ops */ -if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr); - break; - - case 1: /* op R,[R],R */ - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - r = p->reg; - if(p->to.type == D_NONE) - rt = 0; - if(p->as == AMOVB || p->as == AMOVH || p->as == AMOVW || p->as == AMVN) - r = 0; - else - if(r == NREG) - r = rt; - o1 |= rf | (r<<16) | (rt<<12); - break; - - case 2: /* movbu $I,[R],R */ - aclass(&p->from); - o1 = oprrr(p->as, p->scond); - o1 |= immrot(instoffset); - rt = p->to.reg; - r = p->reg; - if(p->to.type == D_NONE) - rt = 0; - if(p->as == AMOVW || p->as == AMVN) - r = 0; - else if(r == NREG) - r = rt; - o1 |= (r<<16) | (rt<<12); - break; - - case 3: /* add R<<[IR],[R],R */ - mov: - aclass(&p->from); - o1 = oprrr(p->as, p->scond); - o1 |= p->from.offset; - rt = p->to.reg; - r = p->reg; - if(p->to.type == D_NONE) - rt = 0; - if(p->as == AMOVW || p->as == AMVN) - r = 0; - else if(r == NREG) - r = rt; - o1 |= (r<<16) | (rt<<12); - break; - - case 4: /* add $I,[R],R */ - aclass(&p->from); - o1 = oprrr(AADD, p->scond); - o1 |= immrot(instoffset); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 |= r << 16; - o1 |= p->to.reg << 12; - break; - - case 5: /* bra s */ - o1 = opbra(p->as, p->scond); - v = -8; - if(p->to.sym != S && p->to.sym->type != 0) { - rel = addrel(cursym); - rel->off = pc - cursym->value; - rel->siz = 4; - rel->sym = p->to.sym; - rel->add = o1 | ((v >> 2) & 0xffffff); - rel->type = D_CALL; - break; - } - if(p->cond != P) - v = (p->cond->pc - pc) - 8; - o1 |= (v >> 2) & 0xffffff; - break; - - case 6: /* b ,O(R) -> add $O,R,PC */ - aclass(&p->to); - o1 = oprrr(AADD, p->scond); - o1 |= immrot(instoffset); - o1 |= p->to.reg << 16; - o1 |= REGPC << 12; - break; - - case 7: /* bl (R) -> blx R */ - aclass(&p->to); - if(instoffset != 0) - diag("%P: doesn't support BL offset(REG) where offset != 0", p); - o1 = oprrr(ABL, p->scond); - o1 |= p->to.reg; - break; - - case 8: /* sll $c,[R],R -> mov (R<<$c),R */ - aclass(&p->from); - o1 = oprrr(p->as, p->scond); - r = p->reg; - if(r == NREG) - r = p->to.reg; - o1 |= r; - o1 |= (instoffset&31) << 7; - o1 |= p->to.reg << 12; - break; - - case 9: /* sll R,[R],R -> mov (R<<R),R */ - o1 = oprrr(p->as, p->scond); - r = p->reg; - if(r == NREG) - r = p->to.reg; - o1 |= r; - o1 |= (p->from.reg << 8) | (1<<4); - o1 |= p->to.reg << 12; - break; - - case 10: /* swi [$con] */ - o1 = oprrr(p->as, p->scond); - if(p->to.type != D_NONE) { - aclass(&p->to); - o1 |= instoffset & 0xffffff; - } - break; - - case 11: /* word */ - aclass(&p->to); - o1 = instoffset; - if(p->to.sym != S) { - rel = addrel(cursym); - rel->off = pc - cursym->value; - rel->siz = 4; - rel->sym = p->to.sym; - rel->add = p->to.offset; - if(rel->sym == gmsym) { - rel->type = D_TLS; - if(flag_shared) - rel->add += pc - p->pcrel->pc - 8 - rel->siz; - rel->xadd = rel->add; - rel->xsym = rel->sym; - } else if(flag_shared) { - rel->type = D_PCREL; - rel->add += pc - p->pcrel->pc - 8; - } else - rel->type = D_ADDR; - o1 = 0; - } - break; - - case 12: /* movw $lcon, reg */ - o1 = omvl(p, &p->from, p->to.reg); - if(o->flag & LPCREL) { - o2 = oprrr(AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12; - } - break; - - case 13: /* op $lcon, [R], R */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - o2 = oprrr(p->as, p->scond); - o2 |= REGTMP; - r = p->reg; - if(p->as == AMOVW || p->as == AMVN) - r = 0; - else if(r == NREG) - r = p->to.reg; - o2 |= r << 16; - if(p->to.type != D_NONE) - o2 |= p->to.reg << 12; - break; - - case 14: /* movb/movbu/movh/movhu R,R */ - o1 = oprrr(ASLL, p->scond); - - if(p->as == AMOVBU || p->as == AMOVHU) - o2 = oprrr(ASRL, p->scond); - else - o2 = oprrr(ASRA, p->scond); - - r = p->to.reg; - o1 |= (p->from.reg)|(r<<12); - o2 |= (r)|(r<<12); - if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) { - o1 |= (24<<7); - o2 |= (24<<7); - } else { - o1 |= (16<<7); - o2 |= (16<<7); - } - break; - - case 15: /* mul r,[r,]r */ - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - r = p->reg; - if(r == NREG) - r = rt; - if(rt == r) { - r = rf; - rf = rt; - } - if(0) - if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) { - diag("bad registers in MUL"); - prasm(p); - } - o1 |= (rf<<8) | r | (rt<<16); - break; - - - case 16: /* div r,[r,]r */ - o1 = 0xf << 28; - o2 = 0; - break; - - case 17: - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - rt2 = p->to.offset; - r = p->reg; - o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12); - break; - - case 20: /* mov/movb/movbu R,O(R) */ - aclass(&p->to); - r = p->to.reg; - if(r == NREG) - r = o->param; - o1 = osr(p->as, p->from.reg, instoffset, r, p->scond); - break; - - case 21: /* mov/movbu O(R),R -> lr */ - aclass(&p->from); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 = olr(instoffset, r, p->to.reg, p->scond); - if(p->as != AMOVW) - o1 |= 1<<22; - break; - - case 30: /* mov/movb/movbu R,L(R) */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - r = p->to.reg; - if(r == NREG) - r = o->param; - o2 = osrr(p->from.reg, REGTMP,r, p->scond); - if(p->as != AMOVW) - o2 |= 1<<22; - break; - - case 31: /* mov/movbu L(R),R -> lr[b] */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - r = p->from.reg; - if(r == NREG) - r = o->param; - o2 = olrr(REGTMP,r, p->to.reg, p->scond); - if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB) - o2 |= 1<<22; - break; - - case 34: /* mov $lacon,R */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - - o2 = oprrr(AADD, p->scond); - o2 |= REGTMP; - r = p->from.reg; - if(r == NREG) - r = o->param; - o2 |= r << 16; - if(p->to.type != D_NONE) - o2 |= p->to.reg << 12; - break; - - case 35: /* mov PSR,R */ - o1 = (2<<23) | (0xf<<16) | (0<<0); - o1 |= (p->scond & C_SCOND) << 28; - o1 |= (p->from.reg & 1) << 22; - o1 |= p->to.reg << 12; - break; - - case 36: /* mov R,PSR */ - o1 = (2<<23) | (0x29f<<12) | (0<<4); - if(p->scond & C_FBIT) - o1 ^= 0x010 << 12; - o1 |= (p->scond & C_SCOND) << 28; - o1 |= (p->to.reg & 1) << 22; - o1 |= p->from.reg << 0; - break; - - case 37: /* mov $con,PSR */ - aclass(&p->from); - o1 = (2<<23) | (0x29f<<12) | (0<<4); - if(p->scond & C_FBIT) - o1 ^= 0x010 << 12; - o1 |= (p->scond & C_SCOND) << 28; - o1 |= immrot(instoffset); - o1 |= (p->to.reg & 1) << 22; - o1 |= p->from.reg << 0; - break; - - case 38: /* movm $con,oreg -> stm */ - o1 = (0x4 << 25); - o1 |= p->from.offset & 0xffff; - o1 |= p->to.reg << 16; - aclass(&p->to); - goto movm; - - case 39: /* movm oreg,$con -> ldm */ - o1 = (0x4 << 25) | (1 << 20); - o1 |= p->to.offset & 0xffff; - o1 |= p->from.reg << 16; - aclass(&p->from); - movm: - if(instoffset != 0) - diag("offset must be zero in MOVM"); - o1 |= (p->scond & C_SCOND) << 28; - if(p->scond & C_PBIT) - o1 |= 1 << 24; - if(p->scond & C_UBIT) - o1 |= 1 << 23; - if(p->scond & C_SBIT) - o1 |= 1 << 22; - if(p->scond & C_WBIT) - o1 |= 1 << 21; - break; - - case 40: /* swp oreg,reg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in SWP"); - o1 = (0x2<<23) | (0x9<<4); - if(p->as != ASWPW) - o1 |= 1 << 22; - o1 |= p->from.reg << 16; - o1 |= p->reg << 0; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - - case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ - o1 = 0xe8fd8000; - break; - - case 50: /* floating point store */ - v = regoff(&p->to); - r = p->to.reg; - if(r == NREG) - r = o->param; - o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p); - break; - - case 51: /* floating point load */ - v = regoff(&p->from); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20); - break; - - case 52: /* floating point store, int32 offset UGLY */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - r = p->to.reg; - if(r == NREG) - r = o->param; - o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; - o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); - break; - - case 53: /* floating point load, int32 offset UGLY */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - r = p->from.reg; - if(r == NREG) - r = o->param; - o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; - o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); - break; - - case 54: /* floating point arith */ - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - r = p->reg; - if(r == NREG) { - r = rt; - if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD) - r = 0; - } - o1 |= rf | (r<<16) | (rt<<12); - break; - - case 56: /* move to FP[CS]R */ - o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); - o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12); - break; - - case 57: /* move from FP[CS]R */ - o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); - o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20); - break; - case 58: /* movbu R,R */ - o1 = oprrr(AAND, p->scond); - o1 |= immrot(0xff); - rt = p->to.reg; - r = p->from.reg; - if(p->to.type == D_NONE) - rt = 0; - if(r == NREG) - r = rt; - o1 |= (r<<16) | (rt<<12); - break; - - case 59: /* movw/bu R<<I(R),R -> ldr indexed */ - if(p->from.reg == NREG) { - if(p->as != AMOVW) - diag("byte MOV from shifter operand"); - goto mov; - } - if(p->from.offset&(1<<4)) - diag("bad shift in LDR"); - o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond); - if(p->as == AMOVBU) - o1 |= 1<<22; - break; - - case 60: /* movb R(R),R -> ldrsb indexed */ - if(p->from.reg == NREG) { - diag("byte MOV from shifter operand"); - goto mov; - } - if(p->from.offset&(~0xf)) - diag("bad shift in LDRSB"); - o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond); - o1 ^= (1<<5)|(1<<6); - break; - - case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ - if(p->to.reg == NREG) - diag("MOV to shifter operand"); - o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond); - if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) - o1 |= 1<<22; - break; - - case 62: /* case R -> movw R<<2(PC),PC */ - if(o->flag & LPCREL) { - o1 = oprrr(AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12; - o2 = olrr(REGTMP, REGPC, REGTMP, p->scond); - o2 |= 2<<7; - o3 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12; - } else { - o1 = olrr(p->from.reg, REGPC, REGPC, p->scond); - o1 |= 2<<7; - } - break; - - case 63: /* bcase */ - if(p->cond != P) { - rel = addrel(cursym); - rel->off = pc - cursym->value; - rel->siz = 4; - if(p->to.sym != S && p->to.sym->type != 0) { - rel->sym = p->to.sym; - rel->add = p->to.offset; - } else { - rel->sym = cursym; - rel->add = p->cond->pc - cursym->value; - } - if(o->flag & LPCREL) { - rel->type = D_PCREL; - rel->add += pc - p->pcrel->pc - 16 + rel->siz; - } else - rel->type = D_ADDR; - o1 = 0; - } - break; - - /* reloc ops */ - case 64: /* mov/movb/movbu R,addr */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - - case 65: /* mov/movbu addr,R */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - o2 = olr(0, REGTMP, p->to.reg, p->scond); - if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB) - o2 |= 1<<22; - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - - case 68: /* floating point store -> ADDR */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - - case 69: /* floating point load <- ADDR */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - - /* ArmV4 ops: */ - case 70: /* movh/movhu R,O(R) -> strh */ - aclass(&p->to); - r = p->to.reg; - if(r == NREG) - r = o->param; - o1 = oshr(p->from.reg, instoffset, r, p->scond); - break; - case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ - aclass(&p->from); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 = olhr(instoffset, r, p->to.reg, p->scond); - if(p->as == AMOVB || p->as == AMOVBS) - o1 ^= (1<<5)|(1<<6); - else if(p->as == AMOVH || p->as == AMOVHS) - o1 ^= (1<<6); - break; - case 72: /* movh/movhu R,L(R) -> strh */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - r = p->to.reg; - if(r == NREG) - r = o->param; - o2 = oshrr(p->from.reg, REGTMP,r, p->scond); - break; - case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - r = p->from.reg; - if(r == NREG) - r = o->param; - o2 = olhrr(REGTMP, r, p->to.reg, p->scond); - if(p->as == AMOVB || p->as == AMOVBS) - o2 ^= (1<<5)|(1<<6); - else if(p->as == AMOVH || p->as == AMOVHS) - o2 ^= (1<<6); - break; - case 74: /* bx $I */ - diag("ABX $I"); - break; - case 75: /* bx O(R) */ - aclass(&p->to); - if(instoffset != 0) - diag("non-zero offset in ABX"); -/* - o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR - o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R -*/ - // p->to.reg may be REGLINK - o1 = oprrr(AADD, p->scond); - o1 |= immrot(instoffset); - o1 |= p->to.reg << 16; - o1 |= REGTMP << 12; - o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR - o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp - break; - case 76: /* bx O(R) when returning from fn*/ - diag("ABXRET"); - break; - case 77: /* ldrex oreg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in LDREX"); - o1 = (0x19<<20) | (0xf9f); - o1 |= p->from.reg << 16; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - case 78: /* strex reg,oreg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in STREX"); - o1 = (0x18<<20) | (0xf90); - o1 |= p->from.reg << 16; - o1 |= p->reg << 0; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - case 80: /* fmov zfcon,freg */ - if(p->as == AMOVD) { - o1 = 0xeeb00b00; // VMOV imm 64 - o2 = oprrr(ASUBD, p->scond); - } else { - o1 = 0x0eb00a00; // VMOV imm 32 - o2 = oprrr(ASUBF, p->scond); - } - v = 0x70; // 1.0 - r = p->to.reg; - - // movf $1.0, r - o1 |= (p->scond & C_SCOND) << 28; - o1 |= r << 12; - o1 |= (v&0xf) << 0; - o1 |= (v&0xf0) << 12; - - // subf r,r,r - o2 |= r | (r<<16) | (r<<12); - break; - case 81: /* fmov sfcon,freg */ - o1 = 0x0eb00a00; // VMOV imm 32 - if(p->as == AMOVD) - o1 = 0xeeb00b00; // VMOV imm 64 - o1 |= (p->scond & C_SCOND) << 28; - o1 |= p->to.reg << 12; - v = chipfloat(&p->from.ieee); - o1 |= (v&0xf) << 0; - o1 |= (v&0xf0) << 12; - break; - case 82: /* fcmp freg,freg, */ - o1 = oprrr(p->as, p->scond); - o1 |= (p->reg<<12) | (p->from.reg<<0); - o2 = 0x0ef1fa10; // VMRS R15 - o2 |= (p->scond & C_SCOND) << 28; - break; - case 83: /* fcmp freg,, */ - o1 = oprrr(p->as, p->scond); - o1 |= (p->from.reg<<12) | (1<<16); - o2 = 0x0ef1fa10; // VMRS R15 - o2 |= (p->scond & C_SCOND) << 28; - break; - case 84: /* movfw freg,freg - truncate float-to-fix */ - o1 = oprrr(p->as, p->scond); - o1 |= (p->from.reg<<0); - o1 |= (p->to.reg<<12); - break; - case 85: /* movwf freg,freg - fix-to-float */ - o1 = oprrr(p->as, p->scond); - o1 |= (p->from.reg<<0); - o1 |= (p->to.reg<<12); - break; - case 86: /* movfw freg,reg - truncate float-to-fix */ - // macro for movfw freg,FTMP; movw FTMP,reg - o1 = oprrr(p->as, p->scond); - o1 |= (p->from.reg<<0); - o1 |= (FREGTMP<<12); - o2 = oprrr(AMOVFW+AEND, p->scond); - o2 |= (FREGTMP<<16); - o2 |= (p->to.reg<<12); - break; - case 87: /* movwf reg,freg - fix-to-float */ - // macro for movw reg,FTMP; movwf FTMP,freg - o1 = oprrr(AMOVWF+AEND, p->scond); - o1 |= (p->from.reg<<12); - o1 |= (FREGTMP<<16); - o2 = oprrr(p->as, p->scond); - o2 |= (FREGTMP<<0); - o2 |= (p->to.reg<<12); - break; - case 88: /* movw reg,freg */ - o1 = oprrr(AMOVWF+AEND, p->scond); - o1 |= (p->from.reg<<12); - o1 |= (p->to.reg<<16); - break; - case 89: /* movw freg,reg */ - o1 = oprrr(AMOVFW+AEND, p->scond); - o1 |= (p->from.reg<<16); - o1 |= (p->to.reg<<12); - break; - case 90: /* tst reg */ - o1 = oprrr(ACMP+AEND, p->scond); - o1 |= p->from.reg<<16; - break; - case 91: /* ldrexd oreg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in LDREX"); - o1 = (0x1b<<20) | (0xf9f); - o1 |= p->from.reg << 16; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - case 92: /* strexd reg,oreg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in STREX"); - o1 = (0x1a<<20) | (0xf90); - o1 |= p->from.reg << 16; - o1 |= p->reg << 0; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - o2 = olhr(0, REGTMP, p->to.reg, p->scond); - if(p->as == AMOVB || p->as == AMOVBS) - o2 ^= (1<<5)|(1<<6); - else if(p->as == AMOVH || p->as == AMOVHS) - o2 ^= (1<<6); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - case 94: /* movh/movhu R,addr -> strh */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - o2 = oshr(p->from.reg, 0, REGTMP, p->scond); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - case 95: /* PLD off(reg) */ - o1 = 0xf5d0f000; - o1 |= p->from.reg << 16; - if(p->from.offset < 0) { - o1 &= ~(1 << 23); - o1 |= (-p->from.offset) & 0xfff; - } else - o1 |= p->from.offset & 0xfff; - break; - case 96: /* UNDEF */ - // This is supposed to be something that stops execution. - // It's not supposed to be reached, ever, but if it is, we'd - // like to be able to tell how we got there. Assemble as - // 0xf7fabcfd which is guranteed to raise undefined instruction - // exception. - o1 = 0xf7fabcfd; - break; - case 97: /* CLZ Rm, Rd */ - o1 = oprrr(p->as, p->scond); - o1 |= p->to.reg << 12; - o1 |= p->from.reg; - break; - case 98: /* MULW{T,B} Rs, Rm, Rd */ - o1 = oprrr(p->as, p->scond); - o1 |= p->to.reg << 16; - o1 |= p->from.reg << 8; - o1 |= p->reg; - break; - case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */ - o1 = oprrr(p->as, p->scond); - o1 |= p->to.reg << 12; - o1 |= p->from.reg << 8; - o1 |= p->reg; - o1 |= p->to.offset << 16; - break; - } - - out[0] = o1; - out[1] = o2; - out[2] = o3; - out[3] = o4; - out[4] = o5; - out[5] = o6; - return; - -#ifdef NOTDEF - v = p->pc; - switch(o->size) { - default: - if(debug['a']) - Bprint(&bso, " %.8ux:\t\t%P\n", v, p); - break; - case 4: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p); - lputl(o1); - break; - case 8: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p); - lputl(o1); - lputl(o2); - break; - case 12: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p); - lputl(o1); - lputl(o2); - lputl(o3); - break; - case 16: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n", - v, o1, o2, o3, o4, p); - lputl(o1); - lputl(o2); - lputl(o3); - lputl(o4); - break; - case 20: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n", - v, o1, o2, o3, o4, o5, p); - lputl(o1); - lputl(o2); - lputl(o3); - lputl(o4); - lputl(o5); - break; - case 24: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n", - v, o1, o2, o3, o4, o5, o6, p); - lputl(o1); - lputl(o2); - lputl(o3); - lputl(o4); - lputl(o5); - lputl(o6); - break; - } -#endif -} - -int32 -oprrr(int a, int sc) -{ - int32 o; - - o = (sc & C_SCOND) << 28; - if(sc & C_SBIT) - o |= 1 << 20; - if(sc & (C_PBIT|C_WBIT)) - diag(".P/.W on dp instruction"); - switch(a) { - case AMULU: - case AMUL: return o | (0x0<<21) | (0x9<<4); - case AMULA: return o | (0x1<<21) | (0x9<<4); - case AMULLU: return o | (0x4<<21) | (0x9<<4); - case AMULL: return o | (0x6<<21) | (0x9<<4); - case AMULALU: return o | (0x5<<21) | (0x9<<4); - case AMULAL: return o | (0x7<<21) | (0x9<<4); - case AAND: return o | (0x0<<21); - case AEOR: return o | (0x1<<21); - case ASUB: return o | (0x2<<21); - case ARSB: return o | (0x3<<21); - case AADD: return o | (0x4<<21); - case AADC: return o | (0x5<<21); - case ASBC: return o | (0x6<<21); - case ARSC: return o | (0x7<<21); - case ATST: return o | (0x8<<21) | (1<<20); - case ATEQ: return o | (0x9<<21) | (1<<20); - case ACMP: return o | (0xa<<21) | (1<<20); - case ACMN: return o | (0xb<<21) | (1<<20); - case AORR: return o | (0xc<<21); - case AMOVB: - case AMOVH: - case AMOVW: return o | (0xd<<21); - case ABIC: return o | (0xe<<21); - case AMVN: return o | (0xf<<21); - case ASLL: return o | (0xd<<21) | (0<<5); - case ASRL: return o | (0xd<<21) | (1<<5); - case ASRA: return o | (0xd<<21) | (2<<5); - case ASWI: return o | (0xf<<24); - - case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4); - case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4); - case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4); - case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4); - case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4); - case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4); - case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4); - case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4); - case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4); - case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4); - case AABSD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (0xc<<4); - case AABSF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (0xc<<4); - case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4); - case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4); - - case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4); - case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4); - - case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) | - (1<<8); // dtof - case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) | - (0<<8); // dtof - - case AMOVWF: - if((sc & C_UBIT) == 0) - o |= 1<<7; /* signed */ - return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | - (0<<18) | (0<<8); // toint, double - case AMOVWD: - if((sc & C_UBIT) == 0) - o |= 1<<7; /* signed */ - return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | - (0<<18) | (1<<8); // toint, double - - case AMOVFW: - if((sc & C_UBIT) == 0) - o |= 1<<16; /* signed */ - return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | - (1<<18) | (0<<8) | (1<<7); // toint, double, trunc - case AMOVDW: - if((sc & C_UBIT) == 0) - o |= 1<<16; /* signed */ - return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | - (1<<18) | (1<<8) | (1<<7); // toint, double, trunc - - case AMOVWF+AEND: // copy WtoF - return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4); - case AMOVFW+AEND: // copy FtoW - return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4); - case ACMP+AEND: // cmp imm - return o | (0x3<<24) | (0x5<<20); - - case ACLZ: - // CLZ doesn't support .S - return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4); - - case AMULWT: - return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4); - case AMULWB: - return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4); - case AMULAWT: - return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4); - case AMULAWB: - return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4); - - case ABL: // BLX REG - return (o & (0xf<<28)) | (0x12fff3 << 4); - } - diag("bad rrr %d", a); - prasm(curp); - return 0; -} - -int32 -opbra(int a, int sc) -{ - - if(sc & (C_SBIT|C_PBIT|C_WBIT)) - diag(".S/.P/.W on bra instruction"); - sc &= C_SCOND; - if(a == ABL) - return (sc<<28)|(0x5<<25)|(0x1<<24); - if(sc != 0xe) - diag(".COND on bcond instruction"); - switch(a) { - case ABEQ: return (0x0<<28)|(0x5<<25); - case ABNE: return (0x1<<28)|(0x5<<25); - case ABCS: return (0x2<<28)|(0x5<<25); - case ABHS: return (0x2<<28)|(0x5<<25); - case ABCC: return (0x3<<28)|(0x5<<25); - case ABLO: return (0x3<<28)|(0x5<<25); - case ABMI: return (0x4<<28)|(0x5<<25); - case ABPL: return (0x5<<28)|(0x5<<25); - case ABVS: return (0x6<<28)|(0x5<<25); - case ABVC: return (0x7<<28)|(0x5<<25); - case ABHI: return (0x8<<28)|(0x5<<25); - case ABLS: return (0x9<<28)|(0x5<<25); - case ABGE: return (0xa<<28)|(0x5<<25); - case ABLT: return (0xb<<28)|(0x5<<25); - case ABGT: return (0xc<<28)|(0x5<<25); - case ABLE: return (0xd<<28)|(0x5<<25); - case AB: return (0xe<<28)|(0x5<<25); - } - diag("bad bra %A", a); - prasm(curp); - return 0; -} - int32 -olr(int32 v, int b, int r, int sc) -{ - int32 o; - - if(sc & C_SBIT) - diag(".S on LDR/STR instruction"); - o = (sc & C_SCOND) << 28; - if(!(sc & C_PBIT)) - o |= 1 << 24; - if(!(sc & C_UBIT)) - o |= 1 << 23; - if(sc & C_WBIT) - o |= 1 << 21; - o |= (1<<26) | (1<<20); - if(v < 0) { - if(sc & C_UBIT) diag(".U on neg offset"); - v = -v; - o ^= 1 << 23; - } - if(v >= (1<<12) || v < 0) - diag("literal span too large: %d (R%d)\n%P", v, b, PP); - o |= v; - o |= b << 16; - o |= r << 12; - return o; -} - -int32 -olhr(int32 v, int b, int r, int sc) -{ - int32 o; - - if(sc & C_SBIT) - diag(".S on LDRH/STRH instruction"); - o = (sc & C_SCOND) << 28; - if(!(sc & C_PBIT)) - o |= 1 << 24; - if(sc & C_WBIT) - o |= 1 << 21; - o |= (1<<23) | (1<<20)|(0xb<<4); - if(v < 0) { - v = -v; - o ^= 1 << 23; - } - if(v >= (1<<8) || v < 0) - diag("literal span too large: %d (R%d)\n%P", v, b, PP); - o |= (v&0xf)|((v>>4)<<8)|(1<<22); - o |= b << 16; - o |= r << 12; - return o; -} - -int32 -osr(int a, int r, int32 v, int b, int sc) -{ - int32 o; - - o = olr(v, b, r, sc) ^ (1<<20); - if(a != AMOVW) - o |= 1<<22; - return o; -} - -int32 -oshr(int r, int32 v, int b, int sc) -{ - int32 o; - - o = olhr(v, b, r, sc) ^ (1<<20); - return o; -} - - -int32 -osrr(int r, int i, int b, int sc) -{ - - return olr(i, b, r, sc) ^ ((1<<25) | (1<<20)); -} - -int32 -oshrr(int r, int i, int b, int sc) -{ - return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20)); -} - -int32 -olrr(int i, int b, int r, int sc) -{ - - return olr(i, b, r, sc) ^ (1<<25); -} - -int32 -olhrr(int i, int b, int r, int sc) -{ - return olhr(i, b, r, sc) ^ (1<<22); -} - -int32 -ofsr(int a, int r, int32 v, int b, int sc, Prog *p) -{ - int32 o; - - if(sc & C_SBIT) - diag(".S on FLDR/FSTR instruction"); - o = (sc & C_SCOND) << 28; - if(!(sc & C_PBIT)) - o |= 1 << 24; - if(sc & C_WBIT) - o |= 1 << 21; - o |= (6<<25) | (1<<24) | (1<<23) | (10<<8); - if(v < 0) { - v = -v; - o ^= 1 << 23; - } - if(v & 3) - diag("odd offset for floating point op: %d\n%P", v, p); - else - if(v >= (1<<10) || v < 0) - diag("literal span too large: %d\n%P", v, p); - o |= (v>>2) & 0xFF; - o |= b << 16; - o |= r << 12; - - switch(a) { - default: - diag("bad fst %A", a); - case AMOVD: - o |= 1 << 8; - case AMOVF: - break; - } - return o; -} - -int32 -omvl(Prog *p, Adr *a, int dr) -{ - int32 v, o1; - if(!p->cond) { - aclass(a); - v = immrot(~instoffset); - if(v == 0) { - diag("missing literal"); - prasm(p); - return 0; - } - o1 = oprrr(AMVN, p->scond&C_SCOND); - o1 |= v; - o1 |= dr << 12; - } else { - v = p->cond->pc - p->pc - 8; - o1 = olr(v, REGPC, dr, p->scond&C_SCOND); - } - return o1; -} - -int -chipzero(Ieee *e) -{ - // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. - if(goarm < 7 || e->l != 0 || e->h != 0) - return -1; - return 0; -} - -int -chipfloat(Ieee *e) -{ - int n; - ulong h; - - // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. - if(goarm < 7) - goto no; - - if(e->l != 0 || (e->h&0xffff) != 0) - goto no; - h = e->h & 0x7fc00000; - if(h != 0x40000000 && h != 0x3fc00000) - goto no; - n = 0; - - // sign bit (a) - if(e->h & 0x80000000) - n |= 1<<7; - - // exp sign bit (b) - if(h == 0x3fc00000) - n |= 1<<6; - - // rest of exp and mantissa (cd-efgh) - n |= (e->h >> 16) & 0x3f; - -//print("match %.8lux %.8lux %d\n", e->l, e->h, n); - return n; - -no: - return -1; +rnd(int32 v, int32 r) +{ + int32 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/5l/l.h b/src/cmd/5l/l.h index ae4b05ba1..25f581047 100644 --- a/src/cmd/5l/l.h +++ b/src/cmd/5l/l.h @@ -31,6 +31,7 @@ #include <u.h> #include <libc.h> #include <bio.h> +#include <link.h> #include "5.out.h" enum @@ -51,167 +52,13 @@ enum #define dynptrsize 0 -typedef struct Adr Adr; -typedef struct Sym Sym; -typedef struct Autom Auto; -typedef struct Prog Prog; -typedef struct Reloc Reloc; -typedef struct Optab Optab; -typedef struct Oprang Oprang; -typedef uchar Opcross[32][2][32]; -typedef struct Count Count; - #define P ((Prog*)0) -#define S ((Sym*)0) -#define TNAME (cursym?cursym->name:noname) - -struct Adr -{ - union - { - struct { - int32 u0offset; - int32 u0offset2; // argsize - } u0off; - char* u0sval; - Ieee u0ieee; - char* u0sbig; - } u0; - Sym* sym; - Sym* gotype; - char type; - char reg; - char name; - char class; -}; - -#define offset u0.u0off.u0offset -#define offset2 u0.u0off.u0offset2 -#define sval u0.u0sval -#define scon sval -#define ieee u0.u0ieee -#define sbig u0.u0sbig - -struct Reloc -{ - int32 off; - uchar siz; - uchar done; - int16 type; - int32 add; - int32 xadd; - Sym* sym; - Sym* xsym; -}; - -struct Prog -{ - Adr from; - Adr to; - union - { - int32 u0regused; - Prog* u0forwd; - } u0; - Prog* cond; - Prog* link; - Prog* pcrel; - int32 pc; - int32 line; - int32 spadj; - uchar mark; - uchar optab; - uchar as; - uchar scond; - uchar reg; - uchar align; // unused -}; - -#define regused u0.u0regused -#define forwd u0.u0forwd -#define datasize reg -#define textflag reg - -#define iscall(p) ((p)->as == ABL) - -struct Sym -{ - char* name; - char* extname; // name used in external object files - short type; - short version; - uchar dupok; - uchar reachable; - uchar cgoexport; - uchar leaf; - int32 dynid; - int32 plt; - int32 got; - int32 value; - int32 sig; - int32 size; - int32 align; // if non-zero, required alignment in bytes - int32 elfsym; - int32 locals; // size of stack frame locals area - int32 args; // size of stack frame incoming arguments area - uchar special; - uchar fnptr; // used as fn ptr - uchar stkcheck; - uchar hide; - Sym* hash; // in hash table - Sym* allsym; // in all symbol list - Sym* next; // in text or data list - Sym* sub; // in SSUB list - Sym* outer; // container of sub - Sym* gotype; - Sym* reachparent; - Sym* queue; - char* file; - char* dynimplib; - char* dynimpvers; - struct Section* sect; - struct Hist* hist; - - // STEXT - Auto* autom; - Prog* text; - - // SDATA, SBSS - uchar* p; - int32 np; - int32 maxp; - Reloc* r; - int32 nr; - int32 maxr; -}; +#define S ((LSym*)0) +#define TNAME (ctxt->cursym?ctxt->cursym->name:noname) #define SIGNINTERN (1729*325*1729) -struct Autom -{ - Sym* asym; - Auto* link; - int32 aoffset; - short type; - Sym* gotype; -}; -struct Optab -{ - char as; - uchar a1; - char a2; - uchar a3; - uchar type; - char size; - char param; - char flag; - uchar pcrelsiz; -}; -struct Oprang -{ - Optab* start; - Optab* stop; -}; +typedef struct Count Count; struct Count { int32 count; @@ -220,10 +67,17 @@ struct Count enum { - LFROM = 1<<0, - LTO = 1<<1, - LPOOL = 1<<2, - LPCREL = 1<<3, +/* mark flags */ + FOLL = 1<<0, + LABEL = 1<<1, + LEAF = 1<<2, + + STRINGSZ = 200, + MINSIZ = 64, + NENT = 100, + MAXIO = 8192, + MAXHIST = 40, /* limit of path elements for history symbols */ + MINLC = 4, C_NONE = 0, C_REG, @@ -260,7 +114,7 @@ enum C_HFOREG, C_SOREG, C_ROREG, - C_SROREG, /* both S and R */ + C_SROREG, /* both nil and R */ C_LOREG, C_PC, @@ -270,179 +124,61 @@ enum C_ADDR, /* reference to relocatable address */ C_GOK, - -/* mark flags */ - FOLL = 1<<0, - LABEL = 1<<1, - LEAF = 1<<2, - - STRINGSZ = 200, - MINSIZ = 64, - NENT = 100, - MAXIO = 8192, - MAXHIST = 40, /* limit of path elements for history symbols */ - MINLC = 4, }; #ifndef COFFCVT -EXTERN int32 HEADR; /* length of header */ -EXTERN int HEADTYPE; /* type of header */ -EXTERN int32 INITDAT; /* data location */ -EXTERN int32 INITRND; /* data round above text location */ -EXTERN int32 INITTEXT; /* text location */ -EXTERN char* INITENTRY; /* entry point */ EXTERN int32 autosize; -EXTERN Auto* curauto; -EXTERN Auto* curhist; -EXTERN Prog* curp; -EXTERN Sym* cursym; -EXTERN Sym* datap; +EXTERN LSym* datap; EXTERN int debug[128]; -EXTERN Sym* etextp; EXTERN char* noname; EXTERN Prog* lastp; EXTERN int32 lcsize; EXTERN char literal[32]; EXTERN int nerrors; EXTERN int32 instoffset; -EXTERN Opcross opcross[8]; -EXTERN Oprang oprange[ALAST]; -EXTERN char* outfile; -EXTERN int32 pc; -EXTERN uchar repop[ALAST]; -EXTERN char* interpreter; EXTERN char* rpath; EXTERN uint32 stroffset; EXTERN int32 symsize; -EXTERN Sym* textp; -EXTERN char xcmp[C_GOK+1][C_GOK+1]; -EXTERN Prog zprg; -EXTERN int dtype; -EXTERN int tlsoffset; EXTERN int armsize; -EXTERN int goarm; -EXTERN Sym* adrgotype; // type symbol on last Adr read -EXTERN Sym* fromgotype; // type symbol on last p->from read - -extern char* anames[]; -extern Optab optab[]; - -void addpool(Prog*, Adr*); -EXTERN Prog* blitrl; -EXTERN Prog* elitrl; - -EXTERN int goarm; - -void initdiv(void); -EXTERN Prog* prog_div; -EXTERN Prog* prog_divu; -EXTERN Prog* prog_mod; -EXTERN Prog* prog_modu; #pragma varargck type "A" int #pragma varargck type "C" int -#pragma varargck type "D" Adr* +#pragma varargck type "D" Addr* #pragma varargck type "I" uchar* -#pragma varargck type "N" Adr* +#pragma varargck type "N" Addr* #pragma varargck type "P" Prog* #pragma varargck type "S" char* #pragma varargck type "Z" char* #pragma varargck type "i" char* -int Aconv(Fmt*); -int Cconv(Fmt*); -int Dconv(Fmt*); -int Iconv(Fmt*); -int Nconv(Fmt*); -int Oconv(Fmt*); -int Pconv(Fmt*); -int Sconv(Fmt*); -int aclass(Adr*); -void addhist(int32, int); -Prog* appendp(Prog*); +int Aconv(Fmt *fp); +int Cconv(Fmt *fp); +int Dconv(Fmt *fp); +int Iconv(Fmt *fp); +int Nconv(Fmt *fp); +int Oconv(Fmt *fp); +int Pconv(Fmt *fp); +int Sconv(Fmt *fp); +void adddynlib(char *lib); +void adddynrel(LSym *s, Reloc *r); +void adddynrela(LSym *rel, LSym *s, Reloc *r); +void adddynsym(Link *ctxt, LSym *s); +int archreloc(Reloc *r, LSym *s, vlong *val); void asmb(void); -void asmout(Prog*, Optab*, int32*, Sym*); -int32 atolwhex(char*); -Prog* brloop(Prog*); -void buildop(void); -void buildrep(int, int); -void cflush(void); -int chipzero(Ieee*); -int chipfloat(Ieee*); -int cmp(int, int); -int compound(Prog*); -double cputime(void); -void diag(char*, ...); -void divsig(void); -void dodata(void); -void doprof1(void); -void doprof2(void); -int32 entryvalue(void); -void exchange(Prog*); -void follow(void); -void hputl(int); -int isnop(Prog*); +void cput(int32 c); +void diag(char *fmt, ...); +int elfreloc1(Reloc *r, vlong sectoff); +void elfsetupplt(void); +void hput(int32 l); void listinit(void); -Sym* lookup(char*, int); -void cput(int); -void hput(int32); -void lput(int32); -void lputb(int32); -void lputl(int32); -void* mysbrk(uint32); -void names(void); -void nocache(Prog*); -int ocmp(const void*, const void*); -int32 opirr(int); -Optab* oplook(Prog*); -int32 oprrr(int, int); -int32 olr(int32, int, int, int); -int32 olhr(int32, int, int, int); -int32 olrr(int, int, int, int); -int32 olhrr(int, int, int, int); -int32 osr(int, int, int32, int, int); -int32 oshr(int, int32, int, int); -int32 ofsr(int, int, int32, int, int, Prog*); -int32 osrr(int, int, int, int); -int32 oshrr(int, int, int, int); -int32 omvl(Prog*, Adr*, int); -void patch(void); -void prasm(Prog*); -void prepend(Prog*, Prog*); -Prog* prg(void); -int pseudo(Prog*); -int32 regoff(Adr*); -int relinv(int); -int32 rnd(int32, int32); -void softfloat(void); -void span(void); -void strnput(char*, int); -int32 symaddr(Sym*); -void undef(void); -void vputb(uint64); -void vputl(uint64); -void wputb(uint16); -void wput(int32); -void wputl(ushort w); -void xdefine(char*, int, int32); +void lput(int32 l); +int machoreloc1(Reloc *r, vlong sectoff); +void main(int argc, char *argv[]); void noops(void); -int32 immrot(uint32); -int32 immaddr(int32); -int32 opbra(int, int); -int brextra(Prog*); -int isbranch(Prog*); -void doelf(void); -void dozerostk(void); // used by -Z - -vlong addaddr(Sym *s, Sym *t); -vlong addsize(Sym *s, Sym *t); -vlong addstring(Sym *s, char *str); -vlong adduint16(Sym *s, uint16 v); -vlong adduint32(Sym *s, uint32 v); -vlong adduint64(Sym *s, uint64 v); -vlong adduint8(Sym *s, uint8 v); -vlong adduintxx(Sym *s, uint64 v, int wid); +void nopstat(char *f, Count *c); +int32 rnd(int32 v, int32 r); +void wput(int32 l); /* Native is little-endian */ #define LPUT(a) lputl(a) diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c index 7502a3b81..02a957579 100644 --- a/src/cmd/5l/list.c +++ b/src/cmd/5l/list.c @@ -47,11 +47,7 @@ listinit(void) fmtinstall('I', Iconv); } -void -prasm(Prog *p) -{ - print("%P\n", p); -} +static Prog *curp; int Pconv(Fmt *fp) @@ -64,7 +60,7 @@ Pconv(Fmt *fp) a = p->as; switch(a) { default: - fmtprint(fp, "(%d)", p->line); + fmtprint(fp, "(%d)", p->lineno); if(p->reg == NREG && p->as != AGLOBL) fmtprint(fp, " %A%C %D,%D", a, p->scond, &p->from, &p->to); @@ -80,22 +76,22 @@ Pconv(Fmt *fp) case ASWPW: case ASWPBU: fmtprint(fp, "(%d) %A%C R%d,%D,%D", - p->line, a, p->scond, p->reg, &p->from, &p->to); + p->lineno, a, p->scond, p->reg, &p->from, &p->to); break; case ADATA: case AINIT_: case ADYNT_: fmtprint(fp, "(%d) %A%C %D/%d,%D", - p->line, a, p->scond, &p->from, p->reg, &p->to); + p->lineno, a, p->scond, &p->from, p->reg, &p->to); break; case AWORD: - fmtprint(fp, "(%d) WORD %D", p->line, &p->to); + fmtprint(fp, "(%d) WORD %D", p->lineno, &p->to); break; case ADWORD: - fmtprint(fp, "(%d) DWORD %D %D", p->line, &p->from, &p->to); + fmtprint(fp, "(%d) DWORD %D %D", p->lineno, &p->from, &p->to); break; } @@ -114,7 +110,7 @@ Aconv(Fmt *fp) a = va_arg(fp->args, int); s = "???"; if(a >= AXXX && a < ALAST) - s = anames[a]; + s = anames5[a]; return fmtstrcpy(fp, s); } @@ -162,10 +158,10 @@ Dconv(Fmt *fp) { char str[STRINGSZ]; const char *op; - Adr *a; + Addr *a; int32 v; - a = va_arg(fp->args, Adr*); + a = va_arg(fp->args, Addr*); switch(a->type) { default: @@ -271,8 +267,8 @@ Dconv(Fmt *fp) break; case D_BRANCH: /* botch */ - if(curp->cond != P) { - v = curp->cond->pc; + if(curp->pcond != P) { + v = curp->pcond->pc; if(a->sym != S) snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v); else @@ -285,11 +281,11 @@ Dconv(Fmt *fp) break; case D_FCONST: - snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee)); + snprint(str, sizeof str, "$%.17g", a->u.dval); break; case D_SCONST: - snprint(str, sizeof str, "$\"%S\"", a->sval); + snprint(str, sizeof str, "$\"%S\"", a->u.sval); break; } return fmtstrcpy(fp, str); @@ -299,10 +295,10 @@ int Nconv(Fmt *fp) { char str[STRINGSZ]; - Adr *a; - Sym *s; + Addr *a; + LSym *s; - a = va_arg(fp->args, Adr*); + a = va_arg(fp->args, Addr*); s = a->sym; switch(a->name) { default: @@ -478,8 +474,8 @@ diag(char *fmt, ...) tn = ""; sep = ""; - if(cursym != S) { - tn = cursym->name; + if(ctxt->cursym != S) { + tn = ctxt->cursym->name; sep = ": "; } va_start(arg, fmt); diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c index 305ed684e..d42c86289 100644 --- a/src/cmd/5l/noop.c +++ b/src/cmd/5l/noop.c @@ -32,677 +32,12 @@ #include "l.h" #include "../ld/lib.h" -#include "../../pkg/runtime/stack.h" - -static Sym* sym_div; -static Sym* sym_divu; -static Sym* sym_mod; -static Sym* sym_modu; -static Sym* symmorestack; -static Prog* pmorestack; - -static Prog* stacksplit(Prog*, int32); - -static void -linkcase(Prog *casep) -{ - Prog *p; - - for(p = casep; p != P; p = p->link){ - if(p->as == ABCASE) { - for(; p != P && p->as == ABCASE; p = p->link) - p->pcrel = casep; - break; - } - } -} void noops(void) { - Prog *p, *q, *q1, *q2; - int o; - Sym *tlsfallback, *gmsym; - - /* - * find leaf subroutines - * strip NOPs - * expand RET - * expand BECOME pseudo - * fixup TLS - */ - - if(debug['v']) - Bprint(&bso, "%5.2f noops\n", cputime()); - Bflush(&bso); - - symmorestack = lookup("runtime.morestack", 0); - if(symmorestack->type != STEXT) { - diag("runtime·morestack not defined"); - errorexit(); - } - pmorestack = symmorestack->text; - pmorestack->reg |= NOSPLIT; - - tlsfallback = lookup("runtime.read_tls_fallback", 0); - gmsym = S; - if(linkmode == LinkExternal) - gmsym = lookup("runtime.tlsgm", 0); - q = P; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - switch(p->as) { - case ACASE: - if(flag_shared) - linkcase(p); - break; - - case ATEXT: - p->mark |= LEAF; - break; - - case ARET: - break; - - case ADIV: - case ADIVU: - case AMOD: - case AMODU: - q = p; - if(prog_div == P) - initdiv(); - cursym->text->mark &= ~LEAF; - continue; - - case ANOP: - q1 = p->link; - q->link = q1; /* q is non-nop */ - if(q1 != P) - q1->mark |= p->mark; - continue; - - case ABL: - case ABX: - cursym->text->mark &= ~LEAF; - - case ABCASE: - case AB: - - case ABEQ: - case ABNE: - case ABCS: - case ABHS: - case ABCC: - case ABLO: - case ABMI: - case ABPL: - case ABVS: - case ABVC: - case ABHI: - case ABLS: - case ABGE: - case ABLT: - case ABGT: - case ABLE: - q1 = p->cond; - if(q1 != P) { - while(q1->as == ANOP) { - q1 = q1->link; - p->cond = q1; - } - } - break; - case AWORD: - // Rewrite TLS register fetch: MRC 15, 0, <reg>, C13, C0, 3 - if((p->to.offset & 0xffff0fff) == 0xee1d0f70) { - if(HEADTYPE == Hopenbsd) { - p->as = ARET; - } else if(goarm < 7) { - if(tlsfallback->type != STEXT) { - diag("runtime·read_tls_fallback not defined"); - errorexit(); - } - // BL runtime.read_tls_fallback(SB) - p->as = ABL; - p->to.type = D_BRANCH; - p->to.sym = tlsfallback; - p->cond = tlsfallback->text; - p->to.offset = 0; - cursym->text->mark &= ~LEAF; - } - if(linkmode == LinkExternal) { - // runtime.tlsgm is relocated with R_ARM_TLS_LE32 - // and $runtime.tlsgm will contain the TLS offset. - // - // MOV $runtime.tlsgm+tlsoffset(SB), REGTMP - // ADD REGTMP, <reg> - // - // In shared mode, runtime.tlsgm is relocated with - // R_ARM_TLS_IE32 and runtime.tlsgm(SB) will point - // to the GOT entry containing the TLS offset. - // - // MOV runtime.tlsgm(SB), REGTMP - // ADD REGTMP, <reg> - // SUB -tlsoffset, <reg> - // - // The SUB compensates for tlsoffset - // used in runtime.save_gm and runtime.load_gm. - q = p; - p = appendp(p); - p->as = AMOVW; - p->scond = 14; - p->reg = NREG; - if(flag_shared) { - p->from.type = D_OREG; - p->from.offset = 0; - } else { - p->from.type = D_CONST; - p->from.offset = tlsoffset; - } - p->from.sym = gmsym; - p->from.name = D_EXTERN; - p->to.type = D_REG; - p->to.reg = REGTMP; - p->to.offset = 0; - - p = appendp(p); - p->as = AADD; - p->scond = 14; - p->reg = NREG; - p->from.type = D_REG; - p->from.reg = REGTMP; - p->to.type = D_REG; - p->to.reg = (q->to.offset & 0xf000) >> 12; - p->to.offset = 0; - - if(flag_shared) { - p = appendp(p); - p->as = ASUB; - p->scond = 14; - p->reg = NREG; - p->from.type = D_CONST; - p->from.offset = -tlsoffset; - p->to.type = D_REG; - p->to.reg = (q->to.offset & 0xf000) >> 12; - p->to.offset = 0; - } - } - } - } - q = p; - } - } - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - o = p->as; - switch(o) { - case ATEXT: - autosize = p->to.offset + 4; - if(autosize <= 4) - if(cursym->text->mark & LEAF) { - p->to.offset = -4; - autosize = 0; - } - - if(!autosize && !(cursym->text->mark & LEAF)) { - if(debug['v']) - Bprint(&bso, "save suppressed in: %s\n", - cursym->name); - Bflush(&bso); - cursym->text->mark |= LEAF; - } - if(cursym->text->mark & LEAF) { - cursym->leaf = 1; - if(!autosize) - break; - } - - if(!(p->reg & NOSPLIT)) - p = stacksplit(p, autosize); // emit split check - - // MOVW.W R14,$-autosize(SP) - p = appendp(p); - p->as = AMOVW; - p->scond |= C_WBIT; - p->from.type = D_REG; - p->from.reg = REGLINK; - p->to.type = D_OREG; - p->to.offset = -autosize; - p->to.reg = REGSP; - p->spadj = autosize; - - if(cursym->text->reg & WRAPPER) { - // g->panicwrap += autosize; - // MOVW panicwrap_offset(g), R3 - // ADD $autosize, R3 - // MOVW R3 panicwrap_offset(g) - p = appendp(p); - p->as = AMOVW; - p->from.type = D_OREG; - p->from.reg = REGG; - p->from.offset = 2*PtrSize; - p->to.type = D_REG; - p->to.reg = 3; - - p = appendp(p); - p->as = AADD; - p->from.type = D_CONST; - p->from.offset = autosize; - p->to.type = D_REG; - p->to.reg = 3; - - p = appendp(p); - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = 3; - p->to.type = D_OREG; - p->to.reg = REGG; - p->to.offset = 2*PtrSize; - } - break; - - case ARET: - nocache(p); - if(cursym->text->mark & LEAF) { - if(!autosize) { - p->as = AB; - p->from = zprg.from; - if(p->to.sym) { // retjmp - p->to.type = D_BRANCH; - p->cond = p->to.sym->text; - } else { - p->to.type = D_OREG; - p->to.offset = 0; - p->to.reg = REGLINK; - } - break; - } - } - - if(cursym->text->reg & WRAPPER) { - int cond; - - // Preserve original RET's cond, to allow RET.EQ - // in the implementation of reflect.call. - cond = p->scond; - p->scond = C_SCOND_NONE; - - // g->panicwrap -= autosize; - // MOVW panicwrap_offset(g), R3 - // SUB $autosize, R3 - // MOVW R3 panicwrap_offset(g) - p->as = AMOVW; - p->from.type = D_OREG; - p->from.reg = REGG; - p->from.offset = 2*PtrSize; - p->to.type = D_REG; - p->to.reg = 3; - p = appendp(p); - - p->as = ASUB; - p->from.type = D_CONST; - p->from.offset = autosize; - p->to.type = D_REG; - p->to.reg = 3; - p = appendp(p); - - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = 3; - p->to.type = D_OREG; - p->to.reg = REGG; - p->to.offset = 2*PtrSize; - p = appendp(p); - - p->scond = cond; - } - - p->as = AMOVW; - p->scond |= C_PBIT; - p->from.type = D_OREG; - p->from.offset = autosize; - p->from.reg = REGSP; - p->to.type = D_REG; - p->to.reg = REGPC; - // If there are instructions following - // this ARET, they come from a branch - // with the same stackframe, so no spadj. - - if(p->to.sym) { // retjmp - p->to.reg = REGLINK; - q2 = appendp(p); - q2->as = AB; - q2->to.type = D_BRANCH; - q2->to.sym = p->to.sym; - q2->cond = p->to.sym->text; - p->to.sym = nil; - p = q2; - } - break; - - case AADD: - if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) - p->spadj = -p->from.offset; - break; - - case ASUB: - if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) - p->spadj = p->from.offset; - break; - - case ADIV: - case ADIVU: - case AMOD: - case AMODU: - if(debug['M']) - break; - if(p->from.type != D_REG) - break; - if(p->to.type != D_REG) - break; - q1 = p; - - /* MOV a,4(SP) */ - p = appendp(p); - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = q1->from.reg; - p->to.type = D_OREG; - p->to.reg = REGSP; - p->to.offset = 4; - - /* MOV b,REGTMP */ - p = appendp(p); - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = q1->reg; - if(q1->reg == NREG) - p->from.reg = q1->to.reg; - p->to.type = D_REG; - p->to.reg = REGTMP; - p->to.offset = 0; - - /* CALL appropriate */ - p = appendp(p); - p->as = ABL; - p->line = q1->line; - p->to.type = D_BRANCH; - p->cond = p; - switch(o) { - case ADIV: - p->cond = prog_div; - p->to.sym = sym_div; - break; - case ADIVU: - p->cond = prog_divu; - p->to.sym = sym_divu; - break; - case AMOD: - p->cond = prog_mod; - p->to.sym = sym_mod; - break; - case AMODU: - p->cond = prog_modu; - p->to.sym = sym_modu; - break; - } + LSym *s; - /* MOV REGTMP, b */ - p = appendp(p); - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = REGTMP; - p->from.offset = 0; - p->to.type = D_REG; - p->to.reg = q1->to.reg; - - /* ADD $8,SP */ - p = appendp(p); - p->as = AADD; - p->line = q1->line; - p->from.type = D_CONST; - p->from.reg = NREG; - p->from.offset = 8; - p->reg = NREG; - p->to.type = D_REG; - p->to.reg = REGSP; - p->spadj = -8; - - /* Keep saved LR at 0(SP) after SP change. */ - /* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */ - /* TODO: Remove SP adjustments; see issue 6699. */ - q1->as = AMOVW; - q1->from.type = D_OREG; - q1->from.reg = REGSP; - q1->from.offset = 0; - q1->reg = NREG; - q1->to.type = D_REG; - q1->to.reg = REGTMP; - - /* SUB $8,SP */ - q1 = appendp(q1); - q1->as = AMOVW; - q1->from.type = D_REG; - q1->from.reg = REGTMP; - q1->reg = NREG; - q1->to.type = D_OREG; - q1->to.reg = REGSP; - q1->to.offset = -8; - q1->scond |= C_WBIT; - q1->spadj = 8; - - break; - case AMOVW: - if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP) - p->spadj = -p->to.offset; - if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC) - p->spadj = -p->from.offset; - if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP) - p->spadj = -p->from.offset; - break; - } - } - } -} - -static Prog* -stacksplit(Prog *p, int32 framesize) -{ - int32 arg; - - // MOVW g_stackguard(g), R1 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_OREG; - p->from.reg = REGG; - p->to.type = D_REG; - p->to.reg = 1; - - if(framesize <= StackSmall) { - // small stack: SP < stackguard - // CMP stackguard, SP - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 1; - p->reg = REGSP; - } else if(framesize <= StackBig) { - // large stack: SP-framesize < stackguard-StackSmall - // MOVW $-framesize(SP), R2 - // CMP stackguard, R2 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = REGSP; - p->from.offset = -framesize; - p->to.type = D_REG; - p->to.reg = 2; - - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 1; - p->reg = 2; - } else { - // Such a large stack we need to protect against wraparound - // if SP is close to zero. - // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall) - // The +StackGuard on both sides is required to keep the left side positive: - // SP is allowed to be slightly below stackguard. See stack.h. - // CMP $StackPreempt, R1 - // MOVW.NE $StackGuard(SP), R2 - // SUB.NE R1, R2 - // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3 - // CMP.NE R3, R2 - p = appendp(p); - p->as = ACMP; - p->from.type = D_CONST; - p->from.offset = (uint32)StackPreempt; - p->reg = 1; - - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = REGSP; - p->from.offset = StackGuard; - p->to.type = D_REG; - p->to.reg = 2; - p->scond = C_SCOND_NE; - - p = appendp(p); - p->as = ASUB; - p->from.type = D_REG; - p->from.reg = 1; - p->to.type = D_REG; - p->to.reg = 2; - p->scond = C_SCOND_NE; - - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.offset = framesize + (StackGuard - StackSmall); - p->to.type = D_REG; - p->to.reg = 3; - p->scond = C_SCOND_NE; - - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 3; - p->reg = 2; - p->scond = C_SCOND_NE; - } - - // MOVW.LS $framesize, R1 - p = appendp(p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_CONST; - p->from.offset = framesize; - p->to.type = D_REG; - p->to.reg = 1; - - // MOVW.LS $args, R2 - p = appendp(p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_CONST; - arg = cursym->text->to.offset2; - if(arg == 1) // special marker for known 0 - arg = 0; - if(arg&3) - diag("misaligned argument size in stack split"); - p->from.offset = arg; - p->to.type = D_REG; - p->to.reg = 2; - - // MOVW.LS R14, R3 - p = appendp(p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_REG; - p->from.reg = REGLINK; - p->to.type = D_REG; - p->to.reg = 3; - - // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted - p = appendp(p); - p->as = ABL; - p->scond = C_SCOND_LS; - p->to.type = D_BRANCH; - p->to.sym = symmorestack; - p->cond = pmorestack; - - // BLS start - p = appendp(p); - p->as = ABLS; - p->to.type = D_BRANCH; - p->cond = cursym->text->link; - - return p; -} - -static void -sigdiv(char *n) -{ - Sym *s; - - s = lookup(n, 0); - if(s->type == STEXT) - if(s->sig == 0) - s->sig = SIGNINTERN; -} - -void -divsig(void) -{ - sigdiv("_div"); - sigdiv("_divu"); - sigdiv("_mod"); - sigdiv("_modu"); -} - -void -initdiv(void) -{ - Sym *s2, *s3, *s4, *s5; - - if(prog_div != P) - return; - sym_div = s2 = lookup("_div", 0); - sym_divu = s3 = lookup("_divu", 0); - sym_mod = s4 = lookup("_mod", 0); - sym_modu = s5 = lookup("_modu", 0); - prog_div = s2->text; - prog_divu = s3->text; - prog_mod = s4->text; - prog_modu = s5->text; - if(prog_div == P) { - diag("undefined: %s", s2->name); - prog_div = cursym->text; - } - if(prog_divu == P) { - diag("undefined: %s", s3->name); - prog_divu = cursym->text; - } - if(prog_mod == P) { - diag("undefined: %s", s4->name); - prog_mod = cursym->text; - } - if(prog_modu == P) { - diag("undefined: %s", s5->name); - prog_modu = cursym->text; - } -} - -void -nocache(Prog *p) -{ - p->optab = 0; - p->from.class = 0; - p->to.class = 0; + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->addstacksplit(ctxt, s); } diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c index 80f5787dc..96198f99c 100644 --- a/src/cmd/5l/obj.c +++ b/src/cmd/5l/obj.c @@ -30,120 +30,19 @@ // Reading object files. -#define EXTERN #include "l.h" #include "../ld/lib.h" #include "../ld/elf.h" #include "../ld/dwarf.h" #include <ar.h> -#ifndef DEFAULT -#define DEFAULT '9' -#endif - -char *noname = "<none>"; -char *thestring = "arm"; - -Header headers[] = { - "noheader", Hnoheader, - "risc", Hrisc, - "plan9", Hplan9x32, - "ixp1200", Hixp1200, - "ipaq", Hipaq, - "linux", Hlinux, - "freebsd", Hfreebsd, - "netbsd", Hnetbsd, - 0, 0 -}; - -/* - * -Hrisc -T0x10005000 -R4 is aif for risc os - * -Hplan9 -T4128 -R4096 is plan9 format - * -Hixp1200 is IXP1200 (raw) - * -Hipaq -T0xC0008010 -R1024 is ipaq - * -Hlinux -Tx -Rx is linux elf - * -Hfreebsd is freebsd elf - * -Hnetbsd is netbsd elf - */ +char *thestring = "arm"; +LinkArch *thelinkarch = &linkarm; void -main(int argc, char *argv[]) +archinit(void) { - char *p; - Sym *s; - - Binit(&bso, 1, OWRITE); - listinit(); - nerrors = 0; - outfile = "5.out"; - HEADTYPE = -1; - INITTEXT = -1; - INITDAT = -1; - INITRND = -1; - INITENTRY = 0; - linkmode = LinkAuto; - nuxiinit(); - - p = getgoarm(); - if(p != nil) - goarm = atoi(p); - else - goarm = 6; - if(goarm == 5) - debug['F'] = 1; - - flagcount("1", "use alternate profiling code", &debug['1']); - flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); - flagstr("E", "sym: entry symbol", &INITENTRY); - flagint32("D", "addr: data address", &INITDAT); - flagcount("G", "debug pseudo-ops", &debug['G']); - flagfn1("I", "interp: set ELF interp", setinterp); - flagfn1("L", "dir: add dir to library path", Lflag); - flagfn1("H", "head: header type", setheadtype); - flagcount("K", "add stack underflow checks", &debug['K']); - flagcount("M", "disable software div/mod", &debug['M']); - flagcount("O", "print pc-line tables", &debug['O']); - flagcount("P", "debug code generation", &debug['P']); - flagint32("R", "rnd: address rounding", &INITRND); - flagint32("T", "addr: text address", &INITTEXT); - flagfn0("V", "print version and exit", doversion); - flagcount("W", "disassemble input", &debug['W']); - flagfn2("X", "name value: define string data", addstrdata); - flagcount("Z", "clear stack frame on entry", &debug['Z']); - flagcount("a", "disassemble output", &debug['a']); - flagcount("c", "dump call graph", &debug['c']); - flagcount("d", "disable dynamic executable", &debug['d']); - flagstr("extld", "linker to run in external mode", &extld); - flagstr("extldflags", "flags for external linker", &extldflags); - flagcount("f", "ignore version mismatch", &debug['f']); - flagcount("g", "disable go package data checks", &debug['g']); - flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); - flagstr("k", "sym: set field tracking symbol", &tracksym); - flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode); - flagcount("n", "dump symbol table", &debug['n']); - flagstr("o", "outfile: set output file", &outfile); - flagcount("p", "insert profiling code", &debug['p']); - flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); - flagcount("race", "enable race detector", &flag_race); - flagcount("s", "disable symbol table", &debug['s']); - flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared); - flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); - flagcount("u", "reject unsafe packages", &debug['u']); - flagcount("v", "print link trace", &debug['v']); - flagcount("w", "disable DWARF generation", &debug['w']); - - flagparse(&argc, &argv, usage); - - if(argc != 1) - usage(); - - if(flag_shared) - linkmode = LinkExternal; - - mywhatsys(); - - if(HEADTYPE == -1) - HEADTYPE = headtype(goos); + LSym *s; // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // Go was built; see ../../make.bash. @@ -161,31 +60,11 @@ main(int argc, char *argv[]) break; } - libinit(); - switch(HEADTYPE) { default: diag("unknown -H option"); errorexit(); - case Hnoheader: /* no header */ - HEADR = 0L; - if(INITTEXT == -1) - INITTEXT = 0; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4; - break; - case Hrisc: /* aif for risc os */ - HEADR = 128L; - if(INITTEXT == -1) - INITTEXT = 0x10005000 + HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4; - break; - case Hplan9x32: /* plan 9 */ + case Hplan9: /* plan 9 */ HEADR = 32L; if(INITTEXT == -1) INITTEXT = 4128; @@ -194,29 +73,11 @@ main(int argc, char *argv[]) if(INITRND == -1) INITRND = 4096; break; - case Hixp1200: /* boot for IXP1200 */ - HEADR = 0L; - if(INITTEXT == -1) - INITTEXT = 0x0; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4; - break; - case Hipaq: /* boot for ipaq */ - HEADR = 16L; - if(INITTEXT == -1) - INITTEXT = 0xC0008010; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 1024; - break; case Hlinux: /* arm elf */ case Hfreebsd: case Hnetbsd: debug['d'] = 0; // with dynamic linking - tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m + ctxt->tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m // this number is known to ../../pkg/runtime/rt0_*_arm.s elfinit(); HEADR = ELFRESERVE; @@ -231,578 +92,9 @@ main(int argc, char *argv[]) if(INITDAT != 0 && INITRND != 0) print("warning: -D0x%ux is ignored because of -R0x%ux\n", INITDAT, INITRND); - if(debug['v']) - Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n", - HEADTYPE, INITTEXT, INITDAT, INITRND); - Bflush(&bso); - zprg.as = AGOK; - zprg.scond = 14; - zprg.reg = NREG; - zprg.from.name = D_NONE; - zprg.from.type = D_NONE; - zprg.from.reg = NREG; - zprg.to = zprg.from; - buildop(); - histgen = 0; - pc = 0; - dtype = 4; - - version = 0; - cbp = buf.cbuf; - cbc = sizeof(buf.cbuf); // embed goarm to runtime.goarm - s = lookup("runtime.goarm", 0); + s = linklookup(ctxt, "runtime.goarm", 0); s->dupok = 1; - adduint8(s, goarm); - - addlibpath("command line", "command line", argv[0], "main"); - loadlib(); - - // mark some functions that are only referenced after linker code editing - if(debug['F']) - mark(rlookup("_sfloat", 0)); - mark(lookup("runtime.read_tls_fallback", 0)); - deadcode(); - if(textp == nil) { - diag("no code"); - errorexit(); - } - - patch(); - if(debug['p']) - if(debug['1']) - doprof1(); - else - doprof2(); - doelf(); - follow(); - softfloat(); - // 5l -Z means zero the stack frame on entry. - // This slows down function calls but can help avoid - // false positives in garbage collection. - if(debug['Z']) - dozerostk(); - noops(); // generate stack split prolog, handle div/mod, etc. - dostkcheck(); - span(); - addexport(); - // textaddress() functionality is handled in span() - pclntab(); - symtab(); - dodata(); - address(); - doweak(); - reloc(); - asmb(); - undef(); - hostlink(); - - if(debug['c']) - print("ARM size = %d\n", armsize); - if(debug['v']) { - Bprint(&bso, "%5.2f cpu time\n", cputime()); - Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); - Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); - } - Bflush(&bso); - errorexit(); -} - -static Sym* -zsym(char *pn, Biobuf *f, Sym *h[]) -{ - int o; - - o = BGETC(f); - if(o == 0) - return S; - if(o < 0 || o >= NSYM || h[o] == nil) - mangle(pn); - return h[o]; -} - -static void -zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[]) -{ - int i, c; - int32 l; - Sym *s; - Auto *u; - - a->type = BGETC(f); - a->reg = BGETC(f); - c = BGETC(f); - if(c < 0 || c > NSYM){ - print("sym out of range: %d\n", c); - BPUTC(f, ALAST+1); - return; - } - a->sym = h[c]; - a->name = BGETC(f); - adrgotype = zsym(pn, f, h); - - if((schar)a->reg < 0 || a->reg > NREG) { - print("register out of range %d\n", a->reg); - BPUTC(f, ALAST+1); - return; /* force real diagnostic */ - } - - if(a->type == D_CONST || a->type == D_OCONST) { - if(a->name == D_EXTERN || a->name == D_STATIC) { - s = a->sym; - if(s != S && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) { - if(0 && !s->fnptr && s->name[0] != '.') - print("%s used as function pointer\n", s->name); - s->fnptr = 1; // over the top cos of SXREF - } - } - } - - switch(a->type) { - default: - print("unknown type %d\n", a->type); - BPUTC(f, ALAST+1); - return; /* force real diagnostic */ - - case D_NONE: - case D_REG: - case D_FREG: - case D_PSR: - case D_FPCR: - break; - - case D_REGREG: - case D_REGREG2: - a->offset = BGETC(f); - break; - - case D_CONST2: - a->offset2 = BGETLE4(f); // fall through - case D_BRANCH: - case D_OREG: - case D_CONST: - case D_OCONST: - case D_SHIFT: - a->offset = BGETLE4(f); - break; - - case D_SCONST: - a->sval = mal(NSNAME); - Bread(f, a->sval, NSNAME); - break; - - case D_FCONST: - a->ieee.l = BGETLE4(f); - a->ieee.h = BGETLE4(f); - break; - } - s = a->sym; - if(s == S) - return; - i = a->name; - if(i != D_AUTO && i != D_PARAM) { - if(s && adrgotype) - s->gotype = adrgotype; - return; - } - - l = a->offset; - for(u=curauto; u; u=u->link) - if(u->asym == s) - if(u->type == i) { - if(u->aoffset > l) - u->aoffset = l; - if(adrgotype) - u->gotype = adrgotype; - return; - } - - u = mal(sizeof(Auto)); - u->link = curauto; - curauto = u; - u->asym = s; - u->aoffset = l; - u->type = i; - u->gotype = adrgotype; -} - -void -nopout(Prog *p) -{ - p->as = ANOP; - p->from.type = D_NONE; - p->to.type = D_NONE; -} - -void -ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) -{ - int32 ipc; - Prog *p; - Sym *h[NSYM], *s; - int v, o, r, skip; - uint32 sig; - char *name; - int ntext; - int32 eof; - char src[1024], *x; - Prog *lastp; - - lastp = nil; - ntext = 0; - eof = Boffset(f) + len; - src[0] = 0; - pn = estrdup(pn); // we keep it in Sym* references - -newloop: - memset(h, 0, sizeof(h)); - version++; - histfrogp = 0; - ipc = pc; - skip = 0; - -loop: - if(f->state == Bracteof || Boffset(f) >= eof) - goto eof; - o = BGETC(f); - if(o == Beof) - goto eof; - - if(o <= AXXX || o >= ALAST) { - diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); - print(" probably not a .5 file\n"); - errorexit(); - } - if(o == ANAME || o == ASIGNAME) { - sig = 0; - if(o == ASIGNAME) - sig = BGETLE4(f); - v = BGETC(f); /* type */ - o = BGETC(f); /* sym */ - r = 0; - if(v == D_STATIC) - r = version; - name = Brdline(f, '\0'); - if(name == nil) { - if(Blinelen(f) > 0) { - fprint(2, "%s: name too long\n", pn); - errorexit(); - } - goto eof; - } - x = expandpkg(name, pkg); - s = lookup(x, r); - if(x != name) - free(x); - - if(sig != 0){ - if(s->sig != 0 && s->sig != sig) - diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name); - s->sig = sig; - s->file = pn; - } - - if(debug['W']) - print(" ANAME %s\n", s->name); - if(o < 0 || o >= nelem(h)) { - fprint(2, "%s: mangled input file\n", pn); - errorexit(); - } - 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); - dwarfaddfrag(s->value, s->name); - } - goto loop; - } - - p = mal(sizeof(Prog)); - p->as = o; - p->scond = BGETC(f); - p->reg = BGETC(f); - p->line = BGETLE4(f); - - zaddr(pn, f, &p->from, h); - fromgotype = adrgotype; - zaddr(pn, f, &p->to, h); - - if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG) - diag("register out of range %A %d", p->as, p->reg); - - p->link = P; - p->cond = P; - - if(debug['W']) - print("%P\n", p); - - switch(o) { - case AHISTORY: - if(p->to.offset == -1) { - addlib(src, pn); - histfrogp = 0; - goto loop; - } - if(src[0] == '\0') - copyhistfrog(src, sizeof src); - addhist(p->line, D_FILE); /* 'z' */ - if(p->to.offset) - addhist(p->to.offset, D_FILE1); /* 'Z' */ - savehist(p->line, p->to.offset); - histfrogp = 0; - goto loop; - - case AEND: - histtoauto(); - if(cursym != nil && cursym->text) - cursym->autom = curauto; - curauto = 0; - cursym = nil; - if(Boffset(f) == eof) - return; - goto newloop; - - case AGLOBL: - s = p->from.sym; - if(s == S) { - diag("GLOBL must have a name\n%P", p); - errorexit(); - } - if(s->type == 0 || s->type == SXREF) { - s->type = SBSS; - s->value = 0; - } - if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) { - diag("redefinition: %s\n%P", s->name, p); - s->type = SBSS; - s->value = 0; - } - if(p->to.offset > s->size) - s->size = p->to.offset; - if(p->reg & DUPOK) - s->dupok = 1; - if(p->reg & RODATA) - s->type = SRODATA; - else if(p->reg & NOPTR) - s->type = SNOPTRBSS; - break; - - case ADATA: - // Assume that AGLOBL comes after ADATA. - // If we've seen an AGLOBL that said this sym was DUPOK, - // ignore any more ADATA we see, which must be - // redefinitions. - s = p->from.sym; - if(s->dupok) { -// if(debug['v']) -// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); - goto loop; - } - if(s->file == nil) - s->file = pn; - else if(s->file != pn) { - diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); - errorexit(); - } - savedata(s, p, pn); - unmal(p, sizeof *p); - break; - - case AGOK: - diag("unknown opcode\n%P", p); - p->pc = pc; - pc++; - break; - - case ATYPE: - if(skip) - goto casedef; - pc++; - goto loop; - - case ATEXT: - if(cursym != nil && cursym->text) { - histtoauto(); - cursym->autom = curauto; - curauto = 0; - } - s = p->from.sym; - if(s == S) { - diag("TEXT must have a name\n%P", p); - errorexit(); - } - cursym = s; - if(s->type != 0 && s->type != SXREF && (p->reg & DUPOK)) { - skip = 1; - goto casedef; - } - if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { - /* redefinition, so file has probably been seen before */ - if(debug['v']) - Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name); - return; - } - skip = 0; - if(s->type != 0 && s->type != SXREF) - diag("redefinition: %s\n%P", s->name, p); - if(etextp) - etextp->next = s; - else - textp = s; - if(fromgotype) { - if(s->gotype && s->gotype != fromgotype) - diag("%s: type mismatch for %s", pn, s->name); - s->gotype = fromgotype; - } - etextp = s; - p->align = 4; - autosize = (p->to.offset+3L) & ~3L; - p->to.offset = autosize; - autosize += 4; - s->type = STEXT; - s->hist = gethist(); - s->text = p; - s->value = pc; - s->args = p->to.offset2; - lastp = p; - p->pc = pc; - pc++; - break; - - case ASUB: - if(p->from.type == D_CONST) - if(p->from.name == D_NONE) - if(p->from.offset < 0) { - p->from.offset = -p->from.offset; - p->as = AADD; - } - goto casedef; - - case AADD: - if(p->from.type == D_CONST) - if(p->from.name == D_NONE) - if(p->from.offset < 0) { - p->from.offset = -p->from.offset; - p->as = ASUB; - } - goto casedef; - - case AMOVWD: - case AMOVWF: - case AMOVDW: - case AMOVFW: - case AMOVFD: - case AMOVDF: - // case AMOVF: - // case AMOVD: - case ACMPF: - case ACMPD: - case AADDF: - case AADDD: - case ASUBF: - case ASUBD: - case AMULF: - case AMULD: - case ADIVF: - case ADIVD: - goto casedef; - - case AMOVF: - if(skip) - goto casedef; - - if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 && - (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) { - /* size sb 9 max */ - sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, ieeedtof(&p->from.ieee)); - s->reachable = 0; - } - p->from.type = D_OREG; - p->from.sym = s; - p->from.name = D_EXTERN; - p->from.offset = 0; - } - goto casedef; - - case AMOVD: - if(skip) - goto casedef; - - if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 && - (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) { - /* size sb 18 max */ - sprint(literal, "$%ux.%ux", - p->from.ieee.l, p->from.ieee.h); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, p->from.ieee.l); - adduint32(s, p->from.ieee.h); - s->reachable = 0; - } - p->from.type = D_OREG; - p->from.sym = s; - p->from.name = D_EXTERN; - p->from.offset = 0; - } - goto casedef; - - default: - casedef: - if(skip) - nopout(p); - p->pc = pc; - pc++; - if(p->to.type == D_BRANCH) - p->to.offset += ipc; - if(lastp == nil) { - if(p->as != ANOP) - diag("unexpected instruction: %P", p); - break; - } - lastp->link = p; - lastp = p; - break; - } - goto loop; - -eof: - diag("truncated object file: %s", pn); -} - -Prog* -prg(void) -{ - Prog *p; - - p = mal(sizeof(Prog)); - *p = zprg; - return p; -} - -Prog* -appendp(Prog *q) -{ - Prog *p; - - p = prg(); - p->link = q->link; - q->link = p; - p->line = q->line; - return p; + adduint8(ctxt, s, goarm); } diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c deleted file mode 100644 index 3d05d6d09..000000000 --- a/src/cmd/5l/optab.c +++ /dev/null @@ -1,277 +0,0 @@ -// Inferno utils/5l/optab.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/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" - -Optab optab[] = -{ - /* struct Optab: - OPCODE, from, prog->reg, to, type,size,param,flag */ - { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 }, - { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 }, - - { AADD, C_REG, C_REG, C_REG, 1, 4, 0 }, - { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 }, - - { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 }, - { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 }, - { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 }, - { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 }, - { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 }, - - { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 }, - { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, - { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, - { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 }, - - { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP }, - - { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL }, - { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, - { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 }, - { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, - - { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL }, - { ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0 }, - { ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0 }, - { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 }, - { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 }, - - { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 }, - { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 }, - - { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 }, - { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 }, - - { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 }, - { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 }, - { ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 }, - - { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 }, - { AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0 }, - { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 }, - - { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 }, - { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM }, - { AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4}, - - { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 }, - { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 }, - { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 }, - { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 }, - { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM }, - { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM }, - { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM }, - { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM }, - - { AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0 }, - { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 }, - { AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0 }, - { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 }, - - { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 }, - { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 }, - - { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 }, - { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 }, - - { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 }, - { AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0 }, - - { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, - { AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - { AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, - { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - { AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, - { AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, - { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - - { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, - { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, - { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, - { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, - - { AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, - { AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, - { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, - { AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, - { AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, - { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, - { AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, - { AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, - { AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, - { AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, - { AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, - { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, - - { AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM }, - { AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM }, - { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 }, - { AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM }, - { AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM }, - { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 }, - - { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM }, - - { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 }, - { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 }, - { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 }, - - { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 }, - { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 }, - - { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 }, - - { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 }, - - { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP }, - { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 }, - - { AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP }, - { AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 }, - - { AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO }, - { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO }, - - { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM }, - { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM }, - - { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4 }, - { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4}, - - { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, - { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 }, - { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, - - { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 }, - { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 }, - - { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 }, - { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 }, - - { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 }, - { AMOVBS, C_SHIFT,C_NONE, C_REG, 60, 4, 0 }, - - { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, - { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, - { AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, - { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, - - { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8 }, - { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, LPCREL, 0 }, - - { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, - { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, - { AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, - { AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, - { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, - { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, - - { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVBS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVBS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVHS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVHS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - - { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, - { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, - { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, - { AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, - { AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, - { AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, - { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, - { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, - { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, - - { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - { AMOVBS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVBS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - { AMOVHS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVHS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - - { ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 }, - { ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 }, - - { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 8, 0 }, - { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 }, - - { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 }, - { ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0 }, - - { AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0 }, - { AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0 }, - - { AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0 }, - { AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0 }, - - { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 }, - { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 }, - - { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 }, - - { ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 }, - { ASTREXD, C_SOREG,C_REG, C_REG, 92, 4, 0 }, - - { APLD, C_SOREG,C_NONE, C_NONE, 95, 4, 0 }, - - { AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0 }, - - { ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0 }, - - { AMULWT, C_REG, C_REG, C_REG, 98, 4, 0 }, - { AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0 }, - - { AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0 }, - { APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0 }, - { AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0 }, - - { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 }, -}; diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c deleted file mode 100644 index cd8897989..000000000 --- a/src/cmd/5l/pass.c +++ /dev/null @@ -1,409 +0,0 @@ -// Inferno utils/5l/pass.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/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. - -// Code and data passes. - -#include "l.h" -#include "../ld/lib.h" - -static void xfol(Prog*, Prog**); - -Prog* -brchain(Prog *p) -{ - int i; - - for(i=0; i<20; i++) { - if(p == P || p->as != AB) - return p; - p = p->cond; - } - return P; -} - -int -relinv(int a) -{ - switch(a) { - case ABEQ: return ABNE; - case ABNE: return ABEQ; - case ABCS: return ABCC; - case ABHS: return ABLO; - case ABCC: return ABCS; - case ABLO: return ABHS; - case ABMI: return ABPL; - case ABPL: return ABMI; - case ABVS: return ABVC; - case ABVC: return ABVS; - case ABHI: return ABLS; - case ABLS: return ABHI; - case ABGE: return ABLT; - case ABLT: return ABGE; - case ABGT: return ABLE; - case ABLE: return ABGT; - } - diag("unknown relation: %s", anames[a]); - return a; -} - -void -follow(void) -{ - Prog *firstp, *lastp; - - if(debug['v']) - Bprint(&bso, "%5.2f follow\n", cputime()); - Bflush(&bso); - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - firstp = prg(); - lastp = firstp; - xfol(cursym->text, &lastp); - lastp->link = nil; - cursym->text = firstp->link; - } -} - -static void -xfol(Prog *p, Prog **last) -{ - Prog *q, *r; - int a, i; - -loop: - if(p == P) - return; - a = p->as; - if(a == AB) { - q = p->cond; - if(q != P && q->as != ATEXT) { - p->mark |= FOLL; - p = q; - if(!(p->mark & FOLL)) - goto loop; - } - } - if(p->mark & FOLL) { - for(i=0,q=p; i<4; i++,q=q->link) { - if(q == *last || q == nil) - break; - a = q->as; - if(a == ANOP) { - i--; - continue; - } - if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF) - goto copy; - if(q->cond == P || (q->cond->mark&FOLL)) - continue; - if(a != ABEQ && a != ABNE) - continue; - copy: - for(;;) { - r = prg(); - *r = *p; - if(!(r->mark&FOLL)) - print("can't happen 1\n"); - r->mark |= FOLL; - if(p != q) { - p = p->link; - (*last)->link = r; - *last = r; - continue; - } - (*last)->link = r; - *last = r; - if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF) - return; - r->as = ABNE; - if(a == ABNE) - r->as = ABEQ; - r->cond = p->link; - r->link = p->cond; - if(!(r->link->mark&FOLL)) - xfol(r->link, last); - if(!(r->cond->mark&FOLL)) - print("can't happen 2\n"); - return; - } - } - a = AB; - q = prg(); - q->as = a; - q->line = p->line; - q->to.type = D_BRANCH; - q->to.offset = p->pc; - q->cond = p; - p = q; - } - p->mark |= FOLL; - (*last)->link = p; - *last = p; - if(a == AB || (a == ARET && p->scond == 14) || a == ARFE || a == AUNDEF){ - return; - } - if(p->cond != P) - if(a != ABL && a != ABX && p->link != P) { - q = brchain(p->link); - if(a != ATEXT && a != ABCASE) - if(q != P && (q->mark&FOLL)) { - p->as = relinv(a); - p->link = p->cond; - p->cond = q; - } - xfol(p->link, last); - q = brchain(p->cond); - if(q == P) - q = p->cond; - if(q->mark&FOLL) { - p->cond = q; - return; - } - p = q; - goto loop; - } - p = p->link; - goto loop; -} - -void -patch(void) -{ - int32 c, vexit; - Prog *p, *q; - Sym *s; - int a; - - if(debug['v']) - Bprint(&bso, "%5.2f patch\n", cputime()); - Bflush(&bso); - mkfwd(); - s = lookup("exit", 0); - vexit = s->value; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - a = p->as; - if((a == ABL || a == ABX || a == AB || a == ARET) && - p->to.type != D_BRANCH && p->to.sym != S) { - s = p->to.sym; - if(s->text == nil) - continue; - switch(s->type&SMASK) { - default: - diag("undefined: %s", s->name); - s->type = STEXT; - s->value = vexit; - continue; // avoid more error messages - case STEXT: - p->to.offset = s->value; - p->to.type = D_BRANCH; - p->cond = s->text; - continue; - } - } - if(p->to.type != D_BRANCH) - continue; - c = p->to.offset; - for(q = cursym->text; q != P;) { - if(c == q->pc) - break; - if(q->forwd != P && c >= q->forwd->pc) - q = q->forwd; - else - q = q->link; - } - if(q == P) { - diag("branch out of range %d\n%P", c, p); - p->to.type = D_NONE; - } - p->cond = q; - } - } - if(flag_shared) { - s = lookup("init_array", 0); - s->type = SINITARR; - s->reachable = 1; - s->hide = 1; - addaddr(s, lookup(INITENTRY, 0)); - } - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - if(p->cond != P) { - p->cond = brloop(p->cond); - if(p->cond != P) - if(p->to.type == D_BRANCH) - p->to.offset = p->cond->pc; - } - } - } -} - -Prog* -brloop(Prog *p) -{ - Prog *q; - int c; - - for(c=0; p!=P;) { - if(p->as != AB) - return p; - q = p->cond; - if(q <= p) { - c++; - if(q == p || c > 5000) - break; - } - p = q; - } - return P; -} - -int32 -atolwhex(char *s) -{ - int32 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; -} - -int32 -rnd(int32 v, int32 r) -{ - int32 c; - - if(r <= 0) - return v; - v += r - 1; - c = v % r; - if(c < 0) - c += r; - v -= c; - return v; -} - -void -dozerostk(void) -{ - Prog *p, *pl; - int32 autoffset; - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(cursym->text == nil || cursym->text->link == nil) - continue; - p = cursym->text; - autoffset = p->to.offset; - if(autoffset < 0) - autoffset = 0; - if(autoffset && !(p->reg&NOSPLIT)) { - // MOVW $4(R13), R1 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = 13; - p->from.offset = 4; - p->to.type = D_REG; - p->to.reg = 1; - - // MOVW $n(R13), R2 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = 13; - p->from.offset = 4 + autoffset; - p->to.type = D_REG; - p->to.reg = 2; - - // MOVW $0, R3 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.offset = 0; - p->to.type = D_REG; - p->to.reg = 3; - - // L: - // MOVW.P R3, 0(R1) +4 - // CMP R1, R2 - // BNE L - p = pl = appendp(p); - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = 3; - p->to.type = D_OREG; - p->to.reg = 1; - p->to.offset = 4; - p->scond |= C_PBIT; - - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 1; - p->reg = 2; - - p = appendp(p); - p->as = ABNE; - p->to.type = D_BRANCH; - p->cond = pl; - } - } -} diff --git a/src/cmd/5l/prof.c b/src/cmd/5l/prof.c deleted file mode 100644 index 225a52435..000000000 --- a/src/cmd/5l/prof.c +++ /dev/null @@ -1,211 +0,0 @@ -// Inferno utils/5l/obj.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/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. - -// Profiling. - -#include "l.h" -#include "../ld/lib.h" - -void -doprof1(void) -{ -#ifdef NOTDEF // TODO(rsc) - Sym *s; - int32 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_OREG; - q->from.name = D_EXTERN; - q->from.offset = n*4; - q->from.sym = s; - q->reg = 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 = AMOVW; - p->from.type = D_OREG; - p->from.name = D_EXTERN; - p->from.sym = s; - p->from.offset = n*4 + 4; - p->to.type = D_REG; - p->to.reg = REGTMP; - - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - p->as = AADD; - p->from.type = D_CONST; - p->from.offset = 1; - p->to.type = D_REG; - p->to.reg = REGTMP; - - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = REGTMP; - p->to.type = D_OREG; - p->to.name = 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_OREG; - q->from.name = D_EXTERN; - q->from.sym = s; - q->reg = 4; - q->to.type = D_CONST; - q->to.offset = n; - - s->type = SBSS; - s->value = n*4; -#endif -} - -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(cursym = textp; cursym != nil; cursym = cursym->next) { - p = cursym->text; - if(cursym == s2) { - ps2 = p; - p->reg = 1; - } - if(cursym == s4) { - ps4 = p; - p->reg = 1; - } - } - for(cursym = textp; cursym != nil; cursym = cursym->next) - for(p = cursym->text; p != P; p = p->link) { - if(p->as == ATEXT) { - if(p->reg & NOPROF) { - for(;;) { - q = p->link; - if(q == P) - break; - if(q->as == ATEXT) - break; - p = q; - } - continue; - } - - /* - * BL profin, R2 - */ - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - p->as = ABL; - p->to.type = D_BRANCH; - p->cond = 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; - - /* - * BL profout - */ - p->as = ABL; - p->from = zprg.from; - p->to = zprg.to; - p->to.type = D_BRANCH; - p->cond = ps4; - p->to.sym = s4; - - p = q; - - continue; - } - } -} diff --git a/src/cmd/5l/softfloat.c b/src/cmd/5l/softfloat.c deleted file mode 100644 index de6481c71..000000000 --- a/src/cmd/5l/softfloat.c +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "l.h" -#include "../ld/lib.h" - -// Software floating point. - -void -softfloat(void) -{ - Prog *p, *next, *psfloat; - Sym *symsfloat; - int wasfloat; - - if(!debug['F']) - return; - - symsfloat = lookup("_sfloat", 0); - psfloat = P; - if(symsfloat->type == STEXT) - psfloat = symsfloat->text; - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - wasfloat = 0; - for(p = cursym->text; p != P; p = p->link) - if(p->cond != P) - p->cond->mark |= LABEL; - for(p = cursym->text; p != P; p = p->link) { - switch(p->as) { - case AMOVW: - if(p->to.type == D_FREG || p->from.type == D_FREG) - goto soft; - goto notsoft; - - case AMOVWD: - case AMOVWF: - case AMOVDW: - case AMOVFW: - case AMOVFD: - case AMOVDF: - case AMOVF: - case AMOVD: - - case ACMPF: - case ACMPD: - case AADDF: - case AADDD: - case ASUBF: - case ASUBD: - case AMULF: - case AMULD: - case ADIVF: - case ADIVD: - case ASQRTF: - case ASQRTD: - case AABSF: - case AABSD: - goto soft; - - default: - goto notsoft; - - soft: - if (psfloat == P) - diag("floats used with _sfloat not defined"); - if (!wasfloat || (p->mark&LABEL)) { - next = prg(); - *next = *p; - - // BL _sfloat(SB) - *p = zprg; - p->link = next; - p->as = ABL; - p->to.type = D_BRANCH; - p->to.sym = symsfloat; - p->cond = psfloat; - p->line = next->line; - - p = next; - wasfloat = 1; - } - break; - - notsoft: - wasfloat = 0; - } - } - } -} diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c deleted file mode 100644 index e7cc0b4b1..000000000 --- a/src/cmd/5l/span.c +++ /dev/null @@ -1,937 +0,0 @@ -// Inferno utils/5l/span.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/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. - -// Instruction layout. - -#include "l.h" -#include "../ld/lib.h" - -static struct { - uint32 start; - uint32 size; - uint32 extra; -} pool; - -int checkpool(Prog*, int); -int flushpool(Prog*, int, int); - -int -isbranch(Prog *p) -{ - int as = p->as; - return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX; -} - -static int -scan(Prog *op, Prog *p, int c) -{ - Prog *q; - - for(q = op->link; q != p && q != P; q = q->link){ - q->pc = c; - c += oplook(q)->size; - nocache(q); - } - return c; -} - -/* size of a case statement including jump table */ -static int32 -casesz(Prog *p) -{ - int jt = 0; - int32 n = 0; - Optab *o; - - for( ; p != P; p = p->link){ - if(p->as == ABCASE) - jt = 1; - else if(jt) - break; - o = oplook(p); - n += o->size; - } - return n; -} - -void -span(void) -{ - Prog *p, *op; - Optab *o; - int m, bflag, i, v; - int32 c, otxt, out[6]; - Section *sect; - uchar *bp; - Sym *sub, *gmsym; - - if(debug['v']) - Bprint(&bso, "%5.2f span\n", cputime()); - Bflush(&bso); - - sect = addsection(&segtext, ".text", 05); - lookup("text", 0)->sect = sect; - lookup("etext", 0)->sect = sect; - - bflag = 0; - c = INITTEXT; - otxt = c; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - cursym->sect = sect; - p = cursym->text; - if(p == P || p->link == P) { // handle external functions and ELF section symbols - if(cursym->type & SSUB) - continue; - if(cursym->align != 0) - c = rnd(c, cursym->align); - cursym->value = 0; - for(sub = cursym; sub != S; sub = sub->sub) { - sub->value += c; - for(p = sub->text; p != P; p = p->link) - p->pc += sub->value; - } - c += cursym->size; - continue; - } - p->pc = c; - cursym->value = c; - - autosize = p->to.offset + 4; - if(p->from.sym != S) - p->from.sym->value = c; - /* need passes to resolve branches */ - if(c-otxt >= 1L<<17) - bflag = 1; - otxt = c; - - for(op = p, p = p->link; p != P; op = p, p = p->link) { - curp = p; - p->pc = c; - o = oplook(p); - m = o->size; - // must check literal pool here in case p generates many instructions - if(blitrl){ - if(checkpool(op, p->as == ACASE ? casesz(p) : m)) - c = p->pc = scan(op, p, c); - } - if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) { - diag("zero-width instruction\n%P", p); - continue; - } - switch(o->flag & (LFROM|LTO|LPOOL)) { - case LFROM: - addpool(p, &p->from); - break; - case LTO: - addpool(p, &p->to); - break; - case LPOOL: - if ((p->scond&C_SCOND) == 14) - flushpool(p, 0, 0); - break; - } - if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14) - flushpool(p, 0, 0); - c += m; - } - if(blitrl){ - if(checkpool(op, 0)) - c = scan(op, P, c); - } - cursym->size = c - cursym->value; - } - - /* - * if any procedure is large enough to - * generate a large SBRA branch, then - * generate extra passes putting branches - * around jmps to fix. this is rare. - */ - while(bflag) { - if(debug['v']) - Bprint(&bso, "%5.2f span1\n", cputime()); - bflag = 0; - c = INITTEXT; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(!cursym->text || !cursym->text->link) - continue; - cursym->value = c; - for(p = cursym->text; p != P; p = p->link) { - curp = p; - p->pc = c; - o = oplook(p); -/* very large branches - if(o->type == 6 && p->cond) { - otxt = p->cond->pc - c; - if(otxt < 0) - otxt = -otxt; - if(otxt >= (1L<<17) - 10) { - q = prg(); - q->link = p->link; - p->link = q; - q->as = AB; - q->to.type = D_BRANCH; - q->cond = p->cond; - p->cond = q; - q = prg(); - q->link = p->link; - p->link = q; - q->as = AB; - q->to.type = D_BRANCH; - q->cond = q->link->link; - bflag = 1; - } - } - */ - m = o->size; - if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) { - if(p->as == ATEXT) { - autosize = p->to.offset + 4; - if(p->from.sym != S) - p->from.sym->value = c; - continue; - } - diag("zero-width instruction\n%P", p); - continue; - } - c += m; - } - cursym->size = c - cursym->value; - } - } - - c = rnd(c, 8); - - /* - * lay out the code. all the pc-relative code references, - * even cross-function, are resolved now; - * only data references need to be relocated. - * with more work we could leave cross-function - * code references to be relocated too, and then - * perhaps we'd be able to parallelize the span loop above. - */ - gmsym = S; - if(linkmode == LinkExternal) - gmsym = lookup("runtime.tlsgm", 0); - for(cursym = textp; cursym != nil; cursym = cursym->next) { - p = cursym->text; - if(p == P || p->link == P) - continue; - autosize = p->to.offset + 4; - symgrow(cursym, cursym->size); - - bp = cursym->p; - for(p = p->link; p != P; p = p->link) { - pc = p->pc; - curp = p; - o = oplook(p); - asmout(p, o, out, gmsym); - for(i=0; i<o->size/4; i++) { - v = out[i]; - *bp++ = v; - *bp++ = v>>8; - *bp++ = v>>16; - *bp++ = v>>24; - } - } - } - sect->vaddr = INITTEXT; - sect->len = c - INITTEXT; -} - -/* - * when the first reference to the literal pool threatens - * to go out of range of a 12-bit PC-relative offset, - * drop the pool now, and branch round it. - * this happens only in extended basic blocks that exceed 4k. - */ -int -checkpool(Prog *p, int sz) -{ - if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0) - return flushpool(p, 1, 0); - else if(p->link == P) - return flushpool(p, 2, 0); - return 0; -} - -int -flushpool(Prog *p, int skip, int force) -{ - Prog *q; - - if(blitrl) { - if(skip){ - if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start); - q = prg(); - q->as = AB; - q->to.type = D_BRANCH; - q->cond = p->link; - q->link = blitrl; - q->line = p->line; - blitrl = q; - } - else if(!force && (p->pc+pool.size-pool.start < 2048)) - return 0; - elitrl->link = p->link; - p->link = blitrl; - // BUG(minux): how to correctly handle line number for constant pool entries? - // for now, we set line number to the last instruction preceding them at least - // this won't bloat the .debug_line tables - while(blitrl) { - blitrl->line = p->line; - blitrl = blitrl->link; - } - blitrl = 0; /* BUG: should refer back to values until out-of-range */ - elitrl = 0; - pool.size = 0; - pool.start = 0; - pool.extra = 0; - return 1; - } - return 0; -} - -void -addpool(Prog *p, Adr *a) -{ - Prog *q, t; - int c; - - c = aclass(a); - - t = zprg; - t.as = AWORD; - - switch(c) { - default: - t.to = *a; - if(flag_shared && t.to.sym != S) - t.pcrel = p; - break; - - case C_SROREG: - case C_LOREG: - case C_ROREG: - case C_FOREG: - case C_SOREG: - case C_HOREG: - case C_FAUTO: - case C_SAUTO: - case C_LAUTO: - case C_LACON: - t.to.type = D_CONST; - t.to.offset = instoffset; - break; - } - - if(t.pcrel == P) { - for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */ - if(q->pcrel == P && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) { - p->cond = q; - return; - } - } - - q = prg(); - *q = t; - q->pc = pool.size; - - if(blitrl == P) { - blitrl = q; - pool.start = p->pc; - q->align = 4; - } else - elitrl->link = q; - elitrl = q; - pool.size += 4; - - p->cond = q; -} - -void -xdefine(char *p, int t, int32 v) -{ - Sym *s; - - s = lookup(p, 0); - s->type = t; - s->value = v; - s->reachable = 1; - s->special = 1; -} - -int32 -regoff(Adr *a) -{ - - instoffset = 0; - aclass(a); - return instoffset; -} - -int32 -immrot(uint32 v) -{ - int i; - - for(i=0; i<16; i++) { - if((v & ~0xff) == 0) - return (i<<8) | v | (1<<25); - v = (v<<2) | (v>>30); - } - return 0; -} - -int32 -immaddr(int32 v) -{ - if(v >= 0 && v <= 0xfff) - return (v & 0xfff) | - (1<<24) | /* pre indexing */ - (1<<23); /* pre indexing, up */ - if(v >= -0xfff && v < 0) - return (-v & 0xfff) | - (1<<24); /* pre indexing */ - return 0; -} - -int -immfloat(int32 v) -{ - return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */ -} - -int -immhalf(int32 v) -{ - if(v >= 0 && v <= 0xff) - return v| - (1<<24)| /* pre indexing */ - (1<<23); /* pre indexing, up */ - if(v >= -0xff && v < 0) - return (-v & 0xff)| - (1<<24); /* pre indexing */ - return 0; -} - -int32 -symaddr(Sym *s) -{ - if(!s->reachable) - diag("unreachable symbol in symaddr - %s", s->name); - return s->value; -} - -int -aclass(Adr *a) -{ - Sym *s; - int t; - - switch(a->type) { - case D_NONE: - return C_NONE; - - case D_REG: - return C_REG; - - case D_REGREG: - return C_REGREG; - - case D_REGREG2: - return C_REGREG2; - - case D_SHIFT: - return C_SHIFT; - - case D_FREG: - return C_FREG; - - case D_FPCR: - return C_FCR; - - case D_OREG: - switch(a->name) { - case D_EXTERN: - case D_STATIC: - if(a->sym == 0 || a->sym->name == 0) { - print("null sym external\n"); - print("%D\n", a); - return C_GOK; - } - instoffset = 0; // s.b. unused but just in case - return C_ADDR; - - case D_AUTO: - instoffset = autosize + a->offset; - t = immaddr(instoffset); - if(t){ - if(immhalf(instoffset)) - return immfloat(t) ? C_HFAUTO : C_HAUTO; - if(immfloat(t)) - return C_FAUTO; - return C_SAUTO; - } - return C_LAUTO; - - case D_PARAM: - instoffset = autosize + a->offset + 4L; - t = immaddr(instoffset); - if(t){ - if(immhalf(instoffset)) - return immfloat(t) ? C_HFAUTO : C_HAUTO; - if(immfloat(t)) - return C_FAUTO; - return C_SAUTO; - } - return C_LAUTO; - case D_NONE: - instoffset = a->offset; - t = immaddr(instoffset); - if(t) { - if(immhalf(instoffset)) /* n.b. that it will also satisfy immrot */ - return immfloat(t) ? C_HFOREG : C_HOREG; - if(immfloat(t)) - return C_FOREG; /* n.b. that it will also satisfy immrot */ - t = immrot(instoffset); - if(t) - return C_SROREG; - if(immhalf(instoffset)) - return C_HOREG; - return C_SOREG; - } - t = immrot(instoffset); - if(t) - return C_ROREG; - return C_LOREG; - } - return C_GOK; - - case D_PSR: - return C_PSR; - - case D_OCONST: - switch(a->name) { - case D_EXTERN: - case D_STATIC: - instoffset = 0; // s.b. unused but just in case - return C_ADDR; - } - return C_GOK; - - case D_FCONST: - if(chipzero(&a->ieee) >= 0) - return C_ZFCON; - if(chipfloat(&a->ieee) >= 0) - return C_SFCON; - return C_LFCON; - - case D_CONST: - case D_CONST2: - switch(a->name) { - - case D_NONE: - instoffset = a->offset; - if(a->reg != NREG) - goto aconsize; - - t = immrot(instoffset); - if(t) - return C_RCON; - t = immrot(~instoffset); - if(t) - return C_NCON; - return C_LCON; - - case D_EXTERN: - case D_STATIC: - s = a->sym; - if(s == S) - break; - instoffset = 0; // s.b. unused but just in case - return C_LCONADDR; - - case D_AUTO: - instoffset = autosize + a->offset; - goto aconsize; - - case D_PARAM: - instoffset = autosize + a->offset + 4L; - aconsize: - t = immrot(instoffset); - if(t) - return C_RACON; - return C_LACON; - } - return C_GOK; - - case D_BRANCH: - return C_SBRA; - } - return C_GOK; -} - -Optab* -oplook(Prog *p) -{ - int a1, a2, a3, r; - char *c1, *c3; - Optab *o, *e; - - a1 = p->optab; - if(a1) - return optab+(a1-1); - a1 = p->from.class; - if(a1 == 0) { - a1 = aclass(&p->from) + 1; - p->from.class = a1; - } - a1--; - a3 = p->to.class; - if(a3 == 0) { - a3 = aclass(&p->to) + 1; - p->to.class = a3; - } - a3--; - a2 = C_NONE; - if(p->reg != NREG) - a2 = C_REG; - r = p->as; - o = oprange[r].start; - if(o == 0) { - a1 = opcross[repop[r]][a1][a2][a3]; - if(a1) { - p->optab = a1+1; - return optab+a1; - } - o = oprange[r].stop; /* just generate an error */ - } - if(debug['O']) { - print("oplook %A %O %O %O\n", - (int)p->as, a1, a2, a3); - print(" %d %d\n", p->from.type, p->to.type); - } - e = oprange[r].stop; - c1 = xcmp[a1]; - c3 = xcmp[a3]; - for(; o<e; o++) - if(o->a2 == a2) - if(c1[o->a1]) - if(c3[o->a3]) { - p->optab = (o-optab)+1; - return o; - } - diag("illegal combination %A %O %O %O, %d %d", - p->as, a1, a2, a3, p->from.type, p->to.type); - prasm(p); - if(o == 0) - o = optab; - return o; -} - -int -cmp(int a, int b) -{ - - if(a == b) - return 1; - switch(a) { - case C_LCON: - if(b == C_RCON || b == C_NCON) - return 1; - break; - case C_LACON: - if(b == C_RACON) - return 1; - break; - case C_LFCON: - if(b == C_ZFCON || b == C_SFCON) - return 1; - break; - - case C_HFAUTO: - return b == C_HAUTO || b == C_FAUTO; - case C_FAUTO: - case C_HAUTO: - return b == C_HFAUTO; - case C_SAUTO: - return cmp(C_HFAUTO, b); - case C_LAUTO: - return cmp(C_SAUTO, b); - - case C_HFOREG: - return b == C_HOREG || b == C_FOREG; - case C_FOREG: - case C_HOREG: - return b == C_HFOREG; - case C_SROREG: - return cmp(C_SOREG, b) || cmp(C_ROREG, b); - case C_SOREG: - case C_ROREG: - return b == C_SROREG || cmp(C_HFOREG, b); - case C_LOREG: - return cmp(C_SROREG, b); - - case C_LBRA: - if(b == C_SBRA) - return 1; - break; - - case C_HREG: - return cmp(C_SP, b) || cmp(C_PC, b); - - } - return 0; -} - -int -ocmp(const void *a1, const void *a2) -{ - Optab *p1, *p2; - int n; - - p1 = (Optab*)a1; - p2 = (Optab*)a2; - n = p1->as - p2->as; - if(n) - return n; - n = p1->a1 - p2->a1; - if(n) - return n; - n = p1->a2 - p2->a2; - if(n) - return n; - n = p1->a3 - p2->a3; - if(n) - return n; - return 0; -} - -void -buildop(void) -{ - int i, n, r; - - for(i=0; i<C_GOK; i++) - for(n=0; n<C_GOK; n++) - xcmp[i][n] = cmp(n, i); - for(n=0; optab[n].as != AXXX; n++) { - if((optab[n].flag & LPCREL) != 0) { - if(flag_shared) - optab[n].size += optab[n].pcrelsiz; - else - optab[n].flag &= ~LPCREL; - } - } - qsort(optab, n, sizeof(optab[0]), ocmp); - for(i=0; i<n; i++) { - r = optab[i].as; - oprange[r].start = optab+i; - while(optab[i].as == r) - i++; - oprange[r].stop = optab+i; - i--; - - switch(r) - { - default: - diag("unknown op in build: %A", r); - errorexit(); - case AADD: - oprange[AAND] = oprange[r]; - oprange[AEOR] = oprange[r]; - oprange[ASUB] = oprange[r]; - oprange[ARSB] = oprange[r]; - oprange[AADC] = oprange[r]; - oprange[ASBC] = oprange[r]; - oprange[ARSC] = oprange[r]; - oprange[AORR] = oprange[r]; - oprange[ABIC] = oprange[r]; - break; - case ACMP: - oprange[ATEQ] = oprange[r]; - oprange[ACMN] = oprange[r]; - break; - case AMVN: - break; - case ABEQ: - oprange[ABNE] = oprange[r]; - oprange[ABCS] = oprange[r]; - oprange[ABHS] = oprange[r]; - oprange[ABCC] = oprange[r]; - oprange[ABLO] = oprange[r]; - oprange[ABMI] = oprange[r]; - oprange[ABPL] = oprange[r]; - oprange[ABVS] = oprange[r]; - oprange[ABVC] = oprange[r]; - oprange[ABHI] = oprange[r]; - oprange[ABLS] = oprange[r]; - oprange[ABGE] = oprange[r]; - oprange[ABLT] = oprange[r]; - oprange[ABGT] = oprange[r]; - oprange[ABLE] = oprange[r]; - break; - case ASLL: - oprange[ASRL] = oprange[r]; - oprange[ASRA] = oprange[r]; - break; - case AMUL: - oprange[AMULU] = oprange[r]; - break; - case ADIV: - oprange[AMOD] = oprange[r]; - oprange[AMODU] = oprange[r]; - oprange[ADIVU] = oprange[r]; - break; - case AMOVW: - case AMOVB: - case AMOVBS: - case AMOVBU: - case AMOVH: - case AMOVHS: - case AMOVHU: - break; - case ASWPW: - oprange[ASWPBU] = oprange[r]; - break; - case AB: - case ABL: - case ABX: - case ABXRET: - case ASWI: - case AWORD: - case AMOVM: - case ARFE: - case ATEXT: - case AUSEFIELD: - case ACASE: - case ABCASE: - case ATYPE: - break; - case AADDF: - oprange[AADDD] = oprange[r]; - oprange[ASUBF] = oprange[r]; - oprange[ASUBD] = oprange[r]; - oprange[AMULF] = oprange[r]; - oprange[AMULD] = oprange[r]; - oprange[ADIVF] = oprange[r]; - oprange[ADIVD] = oprange[r]; - oprange[ASQRTF] = oprange[r]; - oprange[ASQRTD] = oprange[r]; - oprange[AMOVFD] = oprange[r]; - oprange[AMOVDF] = oprange[r]; - oprange[AABSF] = oprange[r]; - oprange[AABSD] = oprange[r]; - break; - - case ACMPF: - oprange[ACMPD] = oprange[r]; - break; - - case AMOVF: - oprange[AMOVD] = oprange[r]; - break; - - case AMOVFW: - oprange[AMOVDW] = oprange[r]; - break; - - case AMOVWF: - oprange[AMOVWD] = oprange[r]; - break; - - case AMULL: - oprange[AMULAL] = oprange[r]; - oprange[AMULLU] = oprange[r]; - oprange[AMULALU] = oprange[r]; - break; - - case AMULWT: - oprange[AMULWB] = oprange[r]; - break; - - case AMULAWT: - oprange[AMULAWB] = oprange[r]; - break; - - case AMULA: - case ALDREX: - case ASTREX: - case ALDREXD: - case ASTREXD: - case ATST: - case APLD: - case AUNDEF: - case ACLZ: - case AFUNCDATA: - case APCDATA: - break; - } - } -} - -/* -void -buildrep(int x, int as) -{ - Opcross *p; - Optab *e, *s, *o; - int a1, a2, a3, n; - - if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) { - diag("assumptions fail in buildrep"); - errorexit(); - } - repop[as] = x; - p = (opcross + x); - s = oprange[as].start; - e = oprange[as].stop; - for(o=e-1; o>=s; o--) { - n = o-optab; - for(a2=0; a2<2; a2++) { - if(a2) { - if(o->a2 == C_NONE) - continue; - } else - if(o->a2 != C_NONE) - continue; - for(a1=0; a1<32; a1++) { - if(!xcmp[a1][o->a1]) - continue; - for(a3=0; a3<32; a3++) - if(xcmp[a3][o->a3]) - (*p)[a1][a2][a3] = n; - } - } - } - oprange[as].start = 0; -} -*/ diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h index 64c8ac2fe..f5ade5a34 100644 --- a/src/cmd/6l/6.out.h +++ b/src/cmd/6l/6.out.h @@ -891,15 +891,3 @@ enum * this is the ranlib header */ #define SYMDEF "__.GOSYMDEF" - -/* - * this is the simulated IEEE floating point - */ -typedef struct ieee Ieee; -struct ieee -{ - int32 l; /* contains ls-man 0xffffffff */ - int32 h; /* contains sign 0x80000000 - exp 0x7ff00000 - ms-man 0x000fffff */ -}; diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index a09cc9727..084e2cc6a 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -47,46 +47,18 @@ char dragonflydynld[] = "/usr/libexec/ld-elf.so.2"; char zeroes[32]; -vlong -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; - if(s->type != STEXT) - diag("entry not text: %s", s->name); - return s->value; -} - -vlong -datoff(vlong addr) -{ - if(addr >= segdata.vaddr) - return addr - segdata.vaddr + segdata.fileoff; - if(addr >= segtext.vaddr) - return addr - segtext.vaddr + segtext.fileoff; - diag("datoff %#llx", addr); - return 0; -} - static int needlib(char *name) { char *p; - Sym *s; + LSym *s; if(*name == '\0') return 0; /* reuse hash code in symbol table */ p = smprint(".elfload.%s", name); - s = lookup(p, 0); + s = linklookup(ctxt, p, 0); free(p); if(s->type == 0) { s->type = 100; // avoid SDATA, etc. @@ -97,24 +69,24 @@ needlib(char *name) int nelfsym = 1; -static void addpltsym(Sym*); -static void addgotsym(Sym*); +static void addpltsym(LSym*); +static void addgotsym(LSym*); void -adddynrela(Sym *rela, Sym *s, Reloc *r) +adddynrela(LSym *rela, LSym *s, Reloc *r) { - addaddrplus(rela, s, r->off); - adduint64(rela, R_X86_64_RELATIVE); - addaddrplus(rela, r->sym, r->add); // Addend + addaddrplus(ctxt, rela, s, r->off); + adduint64(ctxt, rela, R_X86_64_RELATIVE); + addaddrplus(ctxt, rela, r->sym, r->add); // Addend } void -adddynrel(Sym *s, Reloc *r) +adddynrel(LSym *s, Reloc *r) { - Sym *targ, *rela, *got; + LSym *targ, *rela, *got; targ = r->sym; - cursym = s; + ctxt->cursym = s; switch(r->type) { default: @@ -139,7 +111,7 @@ adddynrel(Sym *s, Reloc *r) r->add += 4; if(targ->type == SDYNIMPORT) { addpltsym(targ); - r->sym = lookup(".plt", 0); + r->sym = linklookup(ctxt, ".plt", 0); r->add += targ->plt; } return; @@ -159,7 +131,7 @@ adddynrel(Sym *s, Reloc *r) } addgotsym(targ); r->type = D_PCREL; - r->sym = lookup(".got", 0); + r->sym = linklookup(ctxt, ".got", 0); r->add += 4; r->add += targ->got; return; @@ -183,7 +155,7 @@ adddynrel(Sym *s, Reloc *r) case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1: if(targ->type == SDYNIMPORT) { addpltsym(targ); - r->sym = lookup(".plt", 0); + r->sym = linklookup(ctxt, ".plt", 0); r->add = targ->plt; r->type = D_PCREL; return; @@ -217,7 +189,7 @@ adddynrel(Sym *s, Reloc *r) diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); addgotsym(targ); r->type = D_PCREL; - r->sym = lookup(".got", 0); + r->sym = linklookup(ctxt, ".got", 0); r->add += targ->got; return; } @@ -229,7 +201,7 @@ adddynrel(Sym *s, Reloc *r) switch(r->type) { case D_PCREL: addpltsym(targ); - r->sym = lookup(".plt", 0); + r->sym = linklookup(ctxt, ".plt", 0); r->add = targ->plt; return; @@ -237,14 +209,14 @@ adddynrel(Sym *s, Reloc *r) if(s->type != SDATA) break; if(iself) { - adddynsym(targ); - rela = lookup(".rela", 0); - addaddrplus(rela, s, r->off); + adddynsym(ctxt, targ); + rela = linklookup(ctxt, ".rela", 0); + addaddrplus(ctxt, rela, s, r->off); if(r->siz == 8) - adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64)); + adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_64)); else - adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32)); - adduint64(rela, r->add); + adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_32)); + adduint64(ctxt, rela, r->add); r->type = 256; // ignore during relocsym return; } @@ -259,22 +231,22 @@ adddynrel(Sym *s, Reloc *r) // just in case the C code assigns to the variable, // and of course it only works for single pointers, // but we only need to support cgo and that's all it needs. - adddynsym(targ); - got = lookup(".got", 0); + adddynsym(ctxt, targ); + got = linklookup(ctxt, ".got", 0); s->type = got->type | SSUB; s->outer = got; s->sub = got->sub; got->sub = s; s->value = got->size; - adduint64(got, 0); - adduint32(lookup(".linkedit.got", 0), targ->dynid); + adduint64(ctxt, got, 0); + adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid); r->type = 256; // ignore during relocsym return; } break; } - cursym = s; + ctxt->cursym = s; diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); } @@ -325,7 +297,7 @@ int machoreloc1(Reloc *r, vlong sectoff) { uint32 v; - Sym *rs; + LSym *rs; rs = r->xsym; @@ -379,7 +351,7 @@ machoreloc1(Reloc *r, vlong sectoff) } int -archreloc(Reloc *r, Sym *s, vlong *val) +archreloc(Reloc *r, LSym *s, vlong *val) { USED(r); USED(s); @@ -390,68 +362,68 @@ archreloc(Reloc *r, Sym *s, vlong *val) void elfsetupplt(void) { - Sym *plt, *got; + LSym *plt, *got; - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); if(plt->size == 0) { // pushq got+8(IP) - adduint8(plt, 0xff); - adduint8(plt, 0x35); - addpcrelplus(plt, got, 8); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x35); + addpcrelplus(ctxt, plt, got, 8); // jmpq got+16(IP) - adduint8(plt, 0xff); - adduint8(plt, 0x25); - addpcrelplus(plt, got, 16); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x25); + addpcrelplus(ctxt, plt, got, 16); // nopl 0(AX) - adduint32(plt, 0x00401f0f); + adduint32(ctxt, plt, 0x00401f0f); // assume got->size == 0 too - addaddrplus(got, lookup(".dynamic", 0), 0); - adduint64(got, 0); - adduint64(got, 0); + addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0); + adduint64(ctxt, got, 0); + adduint64(ctxt, got, 0); } } static void -addpltsym(Sym *s) +addpltsym(LSym *s) { if(s->plt >= 0) return; - adddynsym(s); + adddynsym(ctxt, s); if(iself) { - Sym *plt, *got, *rela; + LSym *plt, *got, *rela; - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); - rela = lookup(".rela.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); + rela = linklookup(ctxt, ".rela.plt", 0); if(plt->size == 0) elfsetupplt(); // jmpq *got+size(IP) - adduint8(plt, 0xff); - adduint8(plt, 0x25); - addpcrelplus(plt, got, got->size); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x25); + addpcrelplus(ctxt, plt, got, got->size); // add to got: pointer to current pos in plt - addaddrplus(got, plt, plt->size); + addaddrplus(ctxt, got, plt, plt->size); // pushq $x - adduint8(plt, 0x68); - adduint32(plt, (got->size-24-8)/8); + adduint8(ctxt, plt, 0x68); + adduint32(ctxt, plt, (got->size-24-8)/8); // jmpq .plt - adduint8(plt, 0xe9); - adduint32(plt, -(plt->size+4)); + adduint8(ctxt, plt, 0xe9); + adduint32(ctxt, plt, -(plt->size+4)); // rela - addaddrplus(rela, got, got->size-8); - adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT)); - adduint64(rela, 0); + addaddrplus(ctxt, rela, got, got->size-8); + adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT)); + adduint64(ctxt, rela, 0); s->plt = plt->size - 16; } else if(HEADTYPE == Hdarwin) { @@ -465,53 +437,53 @@ addpltsym(Sym *s) // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html // has details about what we're avoiding. - Sym *plt; + LSym *plt; addgotsym(s); - plt = lookup(".plt", 0); + plt = linklookup(ctxt, ".plt", 0); - adduint32(lookup(".linkedit.plt", 0), s->dynid); + adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid); // jmpq *got+size(IP) s->plt = plt->size; - adduint8(plt, 0xff); - adduint8(plt, 0x25); - addpcrelplus(plt, lookup(".got", 0), s->got); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x25); + addpcrelplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got); } else { diag("addpltsym: unsupported binary format"); } } static void -addgotsym(Sym *s) +addgotsym(LSym *s) { - Sym *got, *rela; + LSym *got, *rela; if(s->got >= 0) return; - adddynsym(s); - got = lookup(".got", 0); + adddynsym(ctxt, s); + got = linklookup(ctxt, ".got", 0); s->got = got->size; - adduint64(got, 0); + adduint64(ctxt, got, 0); if(iself) { - rela = lookup(".rela", 0); - addaddrplus(rela, got, s->got); - adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT)); - adduint64(rela, 0); + rela = linklookup(ctxt, ".rela", 0); + addaddrplus(ctxt, rela, got, s->got); + adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT)); + adduint64(ctxt, rela, 0); } else if(HEADTYPE == Hdarwin) { - adduint32(lookup(".linkedit.got", 0), s->dynid); + adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid); } else { diag("addgotsym: unsupported binary format"); } } void -adddynsym(Sym *s) +adddynsym(Link *ctxt, LSym *s) { - Sym *d; + LSym *d; int t; char *name; @@ -521,24 +493,24 @@ adddynsym(Sym *s) if(iself) { s->dynid = nelfsym++; - d = lookup(".dynsym", 0); + d = linklookup(ctxt, ".dynsym", 0); name = s->extname; - adduint32(d, addstring(lookup(".dynstr", 0), name)); + adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); /* type */ t = STB_GLOBAL << 4; if(s->cgoexport && (s->type&SMASK) == STEXT) t |= STT_FUNC; else t |= STT_OBJECT; - adduint8(d, t); + adduint8(ctxt, d, t); /* reserved */ - adduint8(d, 0); + adduint8(ctxt, d, 0); /* section where symbol is defined */ if(s->type == SDYNIMPORT) - adduint16(d, SHN_UNDEF); + adduint16(ctxt, d, SHN_UNDEF); else { switch(s->type) { default: @@ -555,21 +527,21 @@ adddynsym(Sym *s) t = 14; break; } - adduint16(d, t); + adduint16(ctxt, d, t); } /* value */ if(s->type == SDYNIMPORT) - adduint64(d, 0); + adduint64(ctxt, d, 0); else - addaddr(d, s); + addaddr(ctxt, d, s); /* size of object */ - adduint64(d, s->size); + adduint64(ctxt, d, s->size); if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) { - elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, - addstring(lookup(".dynstr", 0), s->dynimplib)); + elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, + addstring(linklookup(ctxt, ".dynstr", 0), s->dynimplib)); } } else if(HEADTYPE == Hdarwin) { diag("adddynsym: missed symbol %s (%s)", s->name, s->extname); @@ -583,16 +555,16 @@ adddynsym(Sym *s) void adddynlib(char *lib) { - Sym *s; + LSym *s; if(!needlib(lib)) return; if(iself) { - s = lookup(".dynstr", 0); + s = linklookup(ctxt, ".dynstr", 0); if(s->size == 0) addstring(s, ""); - elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); + elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); } else if(HEADTYPE == Hdarwin) { machoadddynlib(lib); } else { @@ -607,7 +579,7 @@ asmb(void) int i; vlong vl, symo, dwarfoff, machlink; Section *sect; - Sym *sym; + LSym *sym; if(debug['v']) Bprint(&bso, "%5.2f asmb\n", cputime()); @@ -662,8 +634,7 @@ asmb(void) switch(HEADTYPE) { default: diag("unknown header type %d", HEADTYPE); - case Hplan9x32: - case Hplan9x64: + case Hplan9: case Helf: break; case Hdarwin: @@ -690,7 +661,7 @@ asmb(void) Bflush(&bso); switch(HEADTYPE) { default: - case Hplan9x64: + case Hplan9: case Helf: debug['s'] = 1; symo = HEADR+segtext.len+segdata.filelen; @@ -729,11 +700,11 @@ asmb(void) elfemitreloc(); } break; - case Hplan9x64: + case Hplan9: asmplan9sym(); cflush(); - sym = lookup("pclntab", 0); + sym = linklookup(ctxt, "pclntab", 0); if(sym != nil) { lcsize = sym->np; for(i=0; i < lcsize; i++) @@ -761,7 +732,7 @@ asmb(void) cseek(0L); switch(HEADTYPE) { default: - case Hplan9x64: /* plan9 */ + case Hplan9: /* plan9 */ magic = 4*26*26+7; magic |= 0x00008000; /* fat header */ lputb(magic); /* magic */ @@ -775,17 +746,6 @@ asmb(void) lputb(lcsize); /* line offsets */ vputb(vl); /* va of entry */ break; - case Hplan9x32: /* plan9 */ - magic = 4*26*26+7; - lputb(magic); /* magic */ - lputb(segtext.filelen); /* sizes */ - lputb(segdata.filelen); - lputb(segdata.len - segdata.filelen); - lputb(symsize); /* nsyms */ - lputb(entryvalue()); /* va of entry */ - lputb(spsize); /* sp offsets */ - lputb(lcsize); /* line offsets */ - break; case Hdarwin: asmbmacho(); break; diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index ecab867e4..d2a8d94b1 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -31,6 +31,7 @@ #include <u.h> #include <libc.h> #include <bio.h> +#include <link.h> #include "6.out.h" #ifndef EXTERN @@ -64,146 +65,8 @@ enum }; #define P ((Prog*)0) -#define S ((Sym*)0) -#define TNAME (cursym?cursym->name:noname) - -typedef struct Adr Adr; -typedef struct Prog Prog; -typedef struct Sym Sym; -typedef struct Auto Auto; -typedef struct Optab Optab; -typedef struct Movtab Movtab; -typedef struct Reloc Reloc; - -struct Adr -{ - union - { - vlong u0offset; - char u0scon[8]; - Prog *u0cond; /* not used, but should be D_BRANCH */ - Ieee u0ieee; - char *u0sbig; - } u0; - Sym* sym; - short type; - char index; - char scale; -}; - -#define offset u0.u0offset -#define scon u0.u0scon -#define cond u0.u0cond -#define ieee u0.u0ieee -#define sbig u0.u0sbig - -struct Reloc -{ - int32 off; - uchar siz; - uchar done; - int32 type; - int64 add; - int64 xadd; - Sym* sym; - Sym* xsym; -}; - -struct Prog -{ - Adr from; - Adr to; - Prog* forwd; - Prog* comefrom; - Prog* link; - Prog* pcond; /* work on this */ - vlong pc; - int32 spadj; - int32 line; - short as; - char ft; /* oclass cache */ - char tt; - uchar mark; /* work on these */ - uchar back; - - char width; /* fake for DATA */ - char mode; /* 16, 32, or 64 */ -}; -#define datasize from.scale -#define textflag from.scale -#define iscall(p) ((p)->as == ACALL) - -struct Auto -{ - Sym* asym; - Auto* link; - int32 aoffset; - short type; - Sym* gotype; -}; -struct Sym -{ - char* name; - char* extname; // name used in external object files - short type; - short version; - uchar dupok; - uchar reachable; - uchar cgoexport; - uchar special; - uchar stkcheck; - uchar hide; - int32 dynid; - int32 sig; - int32 plt; - int32 got; - int32 align; // if non-zero, required alignment in bytes - int32 elfsym; - int32 args; // size of stack frame incoming arguments area - Sym* hash; // in hash table - Sym* allsym; // in all symbol list - Sym* next; // in text or data list - Sym* sub; // in SSUB list - Sym* outer; // container of sub - Sym* reachparent; - Sym* queue; - vlong value; - vlong size; - Sym* gotype; - char* file; - char* dynimplib; - char* dynimpvers; - struct Section* sect; - struct Hist* hist; // for ATEXT - - // STEXT - Auto* autom; - Prog* text; - - // SDATA, SBSS - uchar* p; - int32 np; - int32 maxp; - Reloc* r; - int32 nr; - int32 maxr; -}; -struct Optab -{ - short as; - uchar* ytab; - uchar prefix; - uchar op[23]; -}; -struct Movtab -{ - short as; - uchar ft; - uchar tt; - uchar code; - uchar op[4]; -}; - +#define S ((LSym*)0) +#define TNAME (ctxt->cursym?ctxt->cursym->name:noname) enum { MINSIZ = 8, @@ -211,233 +74,55 @@ enum MINLC = 1, MAXIO = 8192, MAXHIST = 40, /* limit of path elements for history symbols */ - - Yxxx = 0, - Ynone, - Yi0, - Yi1, - Yi8, - Ys32, - Yi32, - Yi64, - 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, Ycr8, - Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7, - Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64, - Ymr, Ymm, - Yxr, Yxm, - Ymax, - - Zxxx = 0, - - Zlit, - Zlitm_r, - Z_rp, - Zbr, - Zcall, - Zib_, - Zib_rp, - Zibo_m, - Zibo_m_xm, - Zil_, - Zil_rp, - Ziq_rp, - Zilo_m, - Ziqo_m, - Zjmp, - Zloop, - Zo_iw, - Zm_o, - Zm_r, - Zm2_r, - Zm_r_xm, - Zm_r_i_xm, - Zm_r_3d, - Zm_r_xm_nr, - Zr_m_xm_nr, - Zibm_r, /* mmx1,mmx2/mem64,imm8 */ - Zmb_r, - Zaut_r, - Zo_m, - Zo_m64, - Zpseudo, - Zr_m, - Zr_m_xm, - Zr_m_i_xm, - Zrp_, - Z_ib, - Z_il, - Zm_ibo, - Zm_ilo, - Zib_rr, - Zil_rr, - Zclr, - Zbyte, - Zmax, - - Px = 0, - P32 = 0x32, /* 32-bit only */ - Pe = 0x66, /* operand escape */ - Pm = 0x0f, /* 2byte opcode escape */ - Pq = 0xff, /* both escapes: 66 0f */ - Pb = 0xfe, /* byte operands */ - Pf2 = 0xf2, /* xmm escape 1: f2 0f */ - Pf3 = 0xf3, /* xmm escape 2: f3 0f */ - Pq3 = 0x67, /* xmm escape 3: 66 48 0f */ - Pw = 0x48, /* Rex.w */ - Py = 0x80, /* defaults to 64-bit mode */ - - Rxf = 1<<9, /* internal flag for Rxr on from */ - Rxt = 1<<8, /* internal flag for Rxr on to */ - Rxw = 1<<3, /* =1, 64-bit operand size */ - Rxr = 1<<2, /* extend modrm reg */ - Rxx = 1<<1, /* extend sib index */ - Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */ - - Maxand = 10, /* in -a output width of the byte codes */ }; #pragma varargck type "A" uint -#pragma varargck type "D" Adr* +#pragma varargck type "D" Addr* #pragma varargck type "I" uchar* #pragma varargck type "P" Prog* #pragma varargck type "R" int #pragma varargck type "S" char* #pragma varargck type "i" char* -EXTERN int32 HEADR; -EXTERN int32 HEADTYPE; -EXTERN int32 INITRND; -EXTERN int64 INITTEXT; -EXTERN int64 INITDAT; -EXTERN char* INITENTRY; /* entry point */ -EXTERN char* pcstr; -EXTERN Auto* curauto; -EXTERN Auto* curhist; -EXTERN Prog* curp; -EXTERN Sym* cursym; -EXTERN Sym* datap; +EXTERN LSym* datap; EXTERN int debug[128]; EXTERN char literal[32]; -EXTERN Sym* textp; -EXTERN Sym* etextp; -EXTERN char ycover[Ymax*Ymax]; -EXTERN uchar* andptr; -EXTERN uchar* rexptr; -EXTERN uchar and[30]; -EXTERN int reg[D_NONE]; -EXTERN int regrex[D_NONE+1]; EXTERN int32 lcsize; -EXTERN int nerrors; -EXTERN char* noname; -EXTERN char* outfile; -EXTERN vlong pc; -EXTERN char* interpreter; EXTERN char* rpath; EXTERN int32 spsize; -EXTERN Sym* symlist; +EXTERN LSym* symlist; EXTERN int32 symsize; -EXTERN int tlsoffset; -EXTERN Prog zprg; -EXTERN int dtype; -EXTERN char* paramspace; -EXTERN Sym* adrgotype; // type symbol on last Adr read -EXTERN Sym* fromgotype; // type symbol on last p->from read EXTERN vlong textstksiz; EXTERN vlong textarg; -extern Optab optab[]; -extern Optab* opindex[]; -extern char* anames[]; - -int Aconv(Fmt*); -int Dconv(Fmt*); -int Iconv(Fmt*); -int Pconv(Fmt*); -int Rconv(Fmt*); -int Sconv(Fmt*); -void addhist(int32, int); -void addstackmark(void); -Prog* appendp(Prog*); +int Aconv(Fmt *fp); +int Dconv(Fmt *fp); +int Iconv(Fmt *fp); +int Pconv(Fmt *fp); +int Rconv(Fmt *fp); +int Sconv(Fmt *fp); +void adddynlib(char *lib); +void adddynrel(LSym *s, Reloc *r); +void adddynrela(LSym *rela, LSym *s, Reloc *r); +void adddynsym(Link *ctxt, LSym *s); +int archreloc(Reloc *r, LSym *s, vlong *val); void asmb(void); -void asmdyn(void); -void asmins(Prog*); -void asmsym(void); -void asmelfsym(void); -vlong atolwhex(char*); -Prog* brchain(Prog*); -Prog* brloop(Prog*); -void buildop(void); -Prog* copyp(Prog*); -double cputime(void); -void datblk(int32, int32); -void deadcode(void); -void diag(char*, ...); -void dodata(void); -void doelf(void); -void domacho(void); -void doprof1(void); -void doprof2(void); -void dostkoff(void); -vlong entryvalue(void); -void follow(void); -void gethunk(void); -void gotypestrings(void); +void diag(char *fmt, ...); +int elfreloc1(Reloc *r, vlong sectoff); +void elfsetupplt(void); void listinit(void); -Sym* lookup(char*, int); -void lputb(int32); -void lputl(int32); -void instinit(void); -void main(int, char*[]); -void* mysbrk(uint32); -Prog* newtext(Prog*, Sym*); -void nopout(Prog*); -int opsize(Prog*); -void patch(void); -Prog* prg(void); -void parsetextconst(vlong); -int relinv(int); -vlong rnd(vlong, vlong); -void span(void); -void undef(void); -vlong symaddr(Sym*); -void vputb(uint64); -void vputl(uint64); -void wputb(uint16); -void wputl(uint16); -void xdefine(char*, int, vlong); - -void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32); -void machsymseg(uint32, uint32); -void machsect(char*, char*, vlong, vlong, uint32, uint32, uint32, uint32, uint32); -void machstack(vlong); -void machdylink(void); -uint32 machheadr(void); +int machoreloc1(Reloc *r, vlong sectoff); +void main(int argc, char *argv[]); +void parsetextconst(vlong arg); +vlong rnd(vlong v, vlong r); /* Native is little-endian */ #define LPUT(a) lputl(a) #define WPUT(a) wputl(a) #define VPUT(a) vputl(a) -#pragma varargck type "D" Adr* +#pragma varargck type "D" Addr* #pragma varargck type "P" Prog* #pragma varargck type "R" int #pragma varargck type "Z" char* diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c index 5040e4327..4a7b0d04a 100644 --- a/src/cmd/6l/list.c +++ b/src/cmd/6l/list.c @@ -58,21 +58,21 @@ Pconv(Fmt *fp) case ATEXT: if(p->from.scale) { fmtprint(fp, "(%d) %A %D,%d,%lD", - p->line, p->as, &p->from, p->from.scale, &p->to); + p->lineno, p->as, &p->from, p->from.scale, &p->to); break; } fmtprint(fp, "(%d) %A %D,%lD", - p->line, p->as, &p->from, &p->to); + p->lineno, p->as, &p->from, &p->to); break; default: fmtprint(fp, "(%d) %A %D,%D", - p->line, p->as, &p->from, &p->to); + p->lineno, p->as, &p->from, &p->to); break; case ADATA: case AINIT_: case ADYNT_: fmtprint(fp, "(%d) %A %D/%d,%D", - p->line, p->as, &p->from, p->from.scale, &p->to); + p->lineno, p->as, &p->from, p->from.scale, &p->to); break; } bigP = P; @@ -85,17 +85,17 @@ Aconv(Fmt *fp) int i; i = va_arg(fp->args, int); - return fmtstrcpy(fp, anames[i]); + return fmtstrcpy(fp, anames6[i]); } int Dconv(Fmt *fp) { char str[STRINGSZ], s[STRINGSZ]; - Adr *a; + Addr *a; int i; - a = va_arg(fp->args, Adr*); + a = va_arg(fp->args, Addr*); i = a->type; if(fp->flags & FmtLong) { @@ -182,11 +182,11 @@ Dconv(Fmt *fp) break; case D_FCONST: - snprint(str, sizeof(str), "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l); + snprint(str, sizeof(str), "$(%.17g)", a->u.dval); break; case D_SCONST: - snprint(str, sizeof(str), "$\"%S\"", a->scon); + snprint(str, sizeof(str), "$\"%S\"", a->u.sval); break; case D_ADDR: @@ -431,8 +431,8 @@ diag(char *fmt, ...) tn = ""; sep = ""; - if(cursym != S) { - tn = cursym->name; + if(ctxt->cursym != S) { + tn = ctxt->cursym->name; sep = ": "; } va_start(arg, fmt); diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index ae649a74b..ac3273f93 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -30,7 +30,6 @@ // Reading object files. -#define EXTERN #include "l.h" #include "../ld/lib.h" #include "../ld/elf.h" @@ -39,104 +38,12 @@ #include "../ld/pe.h" #include <ar.h> -char *noname = "<none>"; char* thestring = "amd64"; -char* paramspace = "FP"; - -Header headers[] = { - "plan9x32", Hplan9x32, - "plan9", Hplan9x64, - "elf", Helf, - "darwin", Hdarwin, - "dragonfly", Hdragonfly, - "linux", Hlinux, - "freebsd", Hfreebsd, - "netbsd", Hnetbsd, - "openbsd", Hopenbsd, - "windows", Hwindows, - "windowsgui", Hwindows, - 0, 0 -}; - -/* - * -Hplan9x32 -T4128 -R4096 is plan9 32-bit format - * -Hplan9 -T0x200028 -R0x200000 is plan9 64-bit format - * -Helf -T0x80110000 -R4096 is ELF32 - * -Hdarwin -Tx -Rx is apple MH-exec - * -Hdragonfly -Tx -Rx is DragonFly elf-exec - * -Hlinux -Tx -Rx is linux elf-exec - * -Hfreebsd -Tx -Rx is FreeBSD elf-exec - * -Hnetbsd -Tx -Rx is NetBSD elf-exec - * -Hopenbsd -Tx -Rx is OpenBSD elf-exec - * -Hwindows -Tx -Rx is MS Windows PE32+ - */ +LinkArch* thelinkarch = &linkamd64; void -main(int argc, char *argv[]) +archinit(void) { - Binit(&bso, 1, OWRITE); - listinit(); - memset(debug, 0, sizeof(debug)); - nerrors = 0; - outfile = nil; - HEADTYPE = -1; - INITTEXT = -1; - INITDAT = -1; - INITRND = -1; - INITENTRY = 0; - linkmode = LinkAuto; - nuxiinit(); - - flagcount("1", "use alternate profiling code", &debug['1']); - flagcount("8", "assume 64-bit addresses", &debug['8']); - flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); - flagint64("D", "addr: data address", &INITDAT); - flagstr("E", "sym: entry symbol", &INITENTRY); - flagfn1("I", "interp: set ELF interp", setinterp); - flagfn1("L", "dir: add dir to library path", Lflag); - flagfn1("H", "head: header type", setheadtype); - flagcount("K", "add stack underflow checks", &debug['K']); - flagcount("O", "print pc-line tables", &debug['O']); - flagcount("Q", "debug byte-register code gen", &debug['Q']); - flagint32("R", "rnd: address rounding", &INITRND); - flagcount("S", "check type signatures", &debug['S']); - flagint64("T", "addr: text address", &INITTEXT); - flagfn0("V", "print version and exit", doversion); - flagcount("W", "disassemble input", &debug['W']); - flagfn2("X", "name value: define string data", addstrdata); - flagcount("Z", "clear stack frame on entry", &debug['Z']); - flagcount("a", "disassemble output", &debug['a']); - flagcount("c", "dump call graph", &debug['c']); - flagcount("d", "disable dynamic executable", &debug['d']); - flagstr("extld", "linker to run in external mode", &extld); - flagstr("extldflags", "flags for external linker", &extldflags); - flagcount("f", "ignore version mismatch", &debug['f']); - flagcount("g", "disable go package data checks", &debug['g']); - flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); - flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode); - flagstr("k", "sym: set field tracking symbol", &tracksym); - flagcount("n", "dump symbol table", &debug['n']); - flagstr("o", "outfile: set output file", &outfile); - flagcount("p", "insert profiling code", &debug['p']); - flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); - flagcount("race", "enable race detector", &flag_race); - flagcount("s", "disable symbol table", &debug['s']); - flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared); - flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); - flagcount("u", "reject unsafe packages", &debug['u']); - flagcount("v", "print link trace", &debug['v']); - flagcount("w", "disable DWARF generation", &debug['w']); - - flagparse(&argc, &argv, usage); - - if(argc != 1) - usage(); - - mywhatsys(); // get goos - - if(HEADTYPE == -1) - HEADTYPE = headtype(goos); - // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // Go was built; see ../../make.bash. if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0) @@ -160,30 +67,13 @@ main(int argc, char *argv[]) case Hopenbsd: break; } - - if(outfile == nil) { - if(HEADTYPE == Hwindows) - outfile = "6.out.exe"; - else - outfile = "6.out"; - } - - libinit(); + ctxt->linkmode = linkmode; switch(HEADTYPE) { default: diag("unknown -H option"); errorexit(); - case Hplan9x32: /* plan 9 */ - HEADR = 32L; - if(INITTEXT == -1) - INITTEXT = 4096+HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4096; - break; - case Hplan9x64: /* plan 9 */ + case Hplan9: /* plan 9 */ HEADR = 32L + 8L; if(INITTEXT == -1) INITTEXT = 0x200000+HEADR; @@ -206,7 +96,7 @@ main(int argc, char *argv[]) * OS X system constant - offset from 0(GS) to our TLS. * Explained in ../../pkg/runtime/cgo/gcc_darwin_amd64.c. */ - tlsoffset = 0x8a0; + ctxt->tlsoffset = 0x8a0; machoinit(); HEADR = INITIAL_MACHO_HEADR; if(INITRND == -1) @@ -227,7 +117,7 @@ main(int argc, char *argv[]) * Also known to ../../pkg/runtime/sys_linux_amd64.s * and ../../pkg/runtime/cgo/gcc_linux_amd64.c. */ - tlsoffset = -16; + ctxt->tlsoffset = -16; elfinit(); HEADR = ELFRESERVE; if(INITTEXT == -1) @@ -251,552 +141,4 @@ main(int argc, char *argv[]) if(INITDAT != 0 && INITRND != 0) print("warning: -D0x%llux is ignored because of -R0x%ux\n", INITDAT, INITRND); - if(debug['v']) - Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n", - HEADTYPE, INITTEXT, INITDAT, INITRND); - Bflush(&bso); - instinit(); - - 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; - zprg.mode = 64; - - pcstr = "%.6llux "; - histgen = 0; - pc = 0; - dtype = 4; - version = 0; - cbp = buf.cbuf; - cbc = sizeof(buf.cbuf); - - addlibpath("command line", "command line", argv[0], "main"); - loadlib(); - deadcode(); - patch(); - follow(); - doelf(); - if(HEADTYPE == Hdarwin) - domacho(); - dostkoff(); - dostkcheck(); - paramspace = "SP"; /* (FP) now (SP) on output */ - if(debug['p']) - if(debug['1']) - doprof1(); - else - doprof2(); - span(); - if(HEADTYPE == Hwindows) - dope(); - addexport(); - textaddress(); - pclntab(); - symtab(); - dodata(); - address(); - doweak(); - reloc(); - asmb(); - undef(); - hostlink(); - if(debug['v']) { - Bprint(&bso, "%5.2f cpu time\n", cputime()); - Bprint(&bso, "%d symbols\n", nsymbol); - Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); - Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); - } - Bflush(&bso); - - errorexit(); -} - -static Sym* -zsym(char *pn, Biobuf *f, Sym *h[]) -{ - int o; - - o = BGETC(f); - if(o < 0 || o >= NSYM || h[o] == nil) - mangle(pn); - return h[o]; -} - -static void -zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[]) -{ - int t; - int32 l; - Sym *s; - Auto *u; - - t = BGETC(f); - a->index = D_NONE; - a->scale = 0; - if(t & T_INDEX) { - a->index = BGETC(f); - a->scale = BGETC(f); - } - a->offset = 0; - if(t & T_OFFSET) { - a->offset = BGETLE4(f); - if(t & T_64) { - a->offset &= 0xFFFFFFFFULL; - a->offset |= (uvlong)BGETLE4(f) << 32; - } - } - a->sym = S; - if(t & T_SYM) - a->sym = zsym(pn, f, h); - a->type = D_NONE; - if(t & T_FCONST) { - a->ieee.l = BGETLE4(f); - a->ieee.h = BGETLE4(f); - a->type = D_FCONST; - } else - if(t & T_SCONST) { - Bread(f, a->scon, NSNAME); - a->type = D_SCONST; - } - if(t & T_TYPE) - a->type = BGETC(f); - if(a->type < 0 || a->type >= D_SIZE) - mangle(pn); - adrgotype = S; - if(t & T_GOTYPE) - adrgotype = zsym(pn, f, h); - s = a->sym; - t = a->type; - if(t == D_INDIR+D_GS || a->index == D_GS) - a->offset += tlsoffset; - if(t != D_AUTO && t != D_PARAM) { - if(s && adrgotype) - s->gotype = adrgotype; - return; - } - 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; - if(adrgotype) - u->gotype = adrgotype; - return; - } - } - - switch(t) { - case D_FILE: - case D_FILE1: - case D_AUTO: - case D_PARAM: - if(s == S) - mangle(pn); - } - - u = mal(sizeof(*u)); - u->link = curauto; - curauto = u; - u->asym = s; - u->aoffset = l; - u->type = t; - u->gotype = adrgotype; -} - -void -nopout(Prog *p) -{ - p->as = ANOP; - p->from.type = D_NONE; - p->to.type = D_NONE; -} - -void -ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) -{ - vlong ipc; - Prog *p; - int v, o, r, skip, mode; - Sym *h[NSYM], *s; - uint32 sig; - char *name, *x; - int ntext; - vlong eof; - char src[1024]; - Prog *lastp; - - lastp = nil; - ntext = 0; - eof = Boffset(f) + len; - src[0] = 0; - pn = estrdup(pn); // we keep it in Sym* references - -newloop: - memset(h, 0, sizeof(h)); - version++; - histfrogp = 0; - ipc = pc; - skip = 0; - mode = 64; - -loop: - if(f->state == Bracteof || Boffset(f) >= eof) - goto eof; - o = BGETC(f); - if(o == Beof) - goto eof; - o |= BGETC(f) << 8; - if(o <= AXXX || o >= ALAST) { - if(o < 0) - goto eof; - diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); - print(" probably not a .6 file\n"); - errorexit(); - } - - if(o == ANAME || o == ASIGNAME) { - sig = 0; - if(o == ASIGNAME) - sig = BGETLE4(f); - v = BGETC(f); /* type */ - o = BGETC(f); /* sym */ - r = 0; - if(v == D_STATIC) - r = version; - name = Brdline(f, '\0'); - if(name == nil) { - if(Blinelen(f) > 0) { - fprint(2, "%s: name too long\n", pn); - errorexit(); - } - goto eof; - } - x = expandpkg(name, pkg); - s = lookup(x, r); - if(x != name) - free(x); - - if(debug['S'] && r == 0) - sig = 1729; - if(sig != 0){ - if(s->sig != 0 && s->sig != sig) - diag("incompatible type signatures " - "%ux(%s) and %ux(%s) for %s", - s->sig, s->file, sig, pn, s->name); - s->sig = sig; - s->file = pn; - } - - if(debug['W']) - print(" ANAME %s\n", s->name); - if(o < 0 || o >= nelem(h)) - mangle(pn); - 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); - dwarfaddfrag(s->value, s->name); - } - goto loop; - } - - p = mal(sizeof(*p)); - p->as = o; - p->line = BGETLE4(f); - p->back = 2; - p->mode = mode; - zaddr(pn, f, &p->from, h); - fromgotype = adrgotype; - zaddr(pn, f, &p->to, h); - - switch(p->as) { - case ATEXT: - case ADATA: - case AGLOBL: - if(p->from.sym == S) - mangle(pn); - break; - } - - if(debug['W']) - print("%P\n", p); - - switch(p->as) { - case AHISTORY: - if(p->to.offset == -1) { - addlib(src, pn); - histfrogp = 0; - goto loop; - } - if(src[0] == '\0') - copyhistfrog(src, sizeof src); - addhist(p->line, D_FILE); /* 'z' */ - if(p->to.offset) - addhist(p->to.offset, D_FILE1); /* 'Z' */ - savehist(p->line, p->to.offset); - histfrogp = 0; - goto loop; - - case AEND: - histtoauto(); - if(cursym != nil && cursym->text) - cursym->autom = curauto; - curauto = 0; - cursym = nil; - if(Boffset(f) == eof) - return; - goto newloop; - - case AGLOBL: - s = p->from.sym; - if(s->type == 0 || s->type == SXREF) { - s->type = SBSS; - s->size = 0; - } - if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) { - diag("%s: redefinition: %s in %s", - pn, s->name, TNAME); - s->type = SBSS; - s->size = 0; - } - if(p->to.offset > s->size) - s->size = p->to.offset; - if(p->from.scale & DUPOK) - s->dupok = 1; - if(p->from.scale & RODATA) - s->type = SRODATA; - else if(p->from.scale & NOPTR) - s->type = SNOPTRBSS; - goto loop; - - case ADATA: - // Assume that AGLOBL comes after ADATA. - // If we've seen an AGLOBL that said this sym was DUPOK, - // ignore any more ADATA we see, which must be - // redefinitions. - s = p->from.sym; - if(s->dupok) { -// if(debug['v']) -// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); - goto loop; - } - if(s->file == nil) - s->file = pn; - else if(s->file != pn) { - diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); - errorexit(); - } - savedata(s, p, pn); - unmal(p, sizeof *p); - goto loop; - - case AGOK: - diag("%s: GOK opcode in %s", pn, TNAME); - pc++; - goto loop; - - case ATYPE: - if(skip) - goto casdef; - pc++; - goto loop; - - case ATEXT: - s = p->from.sym; - if(s->text != nil) { - if(p->from.scale & DUPOK) { - skip = 1; - goto casdef; - } - diag("%s: %s: redefinition", pn, s->name); - return; - } - if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { - /* redefinition, so file has probably been seen before */ - if(debug['v']) - Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name); - return; - } - if(cursym != nil && cursym->text) { - histtoauto(); - cursym->autom = curauto; - curauto = 0; - } - skip = 0; - if(etextp) - etextp->next = s; - else - textp = s; - etextp = s; - s->text = p; - cursym = s; - 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); - } - if(fromgotype) { - if(s->gotype && s->gotype != fromgotype) - diag("%s: type mismatch for %s", pn, s->name); - s->gotype = fromgotype; - } - s->type = STEXT; - s->hist = gethist(); - s->value = pc; - s->args = p->to.offset >> 32; - lastp = p; - p->pc = pc++; - goto loop; - - case AMODE: - if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){ - switch((int)p->from.offset){ - case 16: case 32: case 64: - mode = p->from.offset; - break; - } - } - goto loop; - - case AFMOVF: - case AFADDF: - case AFSUBF: - case AFSUBRF: - case AFMULF: - case AFDIVF: - case AFDIVRF: - case AFCOMF: - case AFCOMFP: - case AMOVSS: - case AADDSS: - case ASUBSS: - case AMULSS: - case ADIVSS: - case ACOMISS: - case AUCOMISS: - if(skip) - goto casdef; - if(p->from.type == D_FCONST) { - /* size sb 9 max */ - sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, ieeedtof(&p->from.ieee)); - s->reachable = 0; - } - 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: - case AMOVSD: - case AADDSD: - case ASUBSD: - case AMULSD: - case ADIVSD: - case ACOMISD: - case AUCOMISD: - if(skip) - goto casdef; - if(p->from.type == D_FCONST) { - /* size sb 18 max */ - sprint(literal, "$%ux.%ux", - p->from.ieee.l, p->from.ieee.h); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, p->from.ieee.l); - adduint32(s, p->from.ieee.h); - s->reachable = 0; - } - p->from.type = D_EXTERN; - p->from.sym = s; - p->from.offset = 0; - } - goto casdef; - - casdef: - default: - if(skip) - nopout(p); - p->pc = pc; - pc++; - - if(p->to.type == D_BRANCH) - p->to.offset += ipc; - if(lastp == nil) { - if(p->as != ANOP) - diag("unexpected instruction: %P", p); - goto loop; - } - lastp->link = p; - lastp = p; - goto loop; - } - -eof: - diag("truncated object file: %s", pn); -} - -Prog* -prg(void) -{ - Prog *p; - - p = mal(sizeof(*p)); - - *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; - p->mode = q->mode; - return p; } diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c deleted file mode 100644 index f48c6c329..000000000 --- a/src/cmd/6l/optab.c +++ /dev/null @@ -1,1372 +0,0 @@ -// Inferno utils/6l/optab.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/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, Yi64, Zpseudo,1, - 0 -}; -uchar ynop[] = -{ - Ynone, Ynone, Zpseudo,0, - Ynone, Yiauto, Zpseudo,0, - Ynone, Yml, Zpseudo,0, - Ynone, Yrf, Zpseudo,0, - Ynone, Yxr, Zpseudo,0, - Yiauto, Ynone, Zpseudo,0, - Yml, Ynone, Zpseudo,0, - Yrf, Ynone, Zpseudo,0, - Yxr, Ynone, Zpseudo,1, - 0 -}; -uchar yfuncdata[] = -{ - Yi32, Ym, Zpseudo, 0, - 0 -}; -uchar ypcdata[] = -{ - Yi32, Yi32, Zpseudo, 0, - 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 yincw[] = -{ - Ynone, Yml, Zo_m, 2, - 0 -}; -uchar yincl[] = -{ - 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 ymbs[] = -{ - Ymb, Ynone, Zm_o, 2, - 0 -}; -uchar ybtl[] = -{ - Yi8, Yml, Zibo_m, 2, - Yrl, Yml, Zr_m, 1, - 0 -}; -uchar ymovw[] = -{ - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - Yi0, Yrl, Zclr, 1, - Yi32, Yrl, Zil_rp, 1, - Yi32, Yml, Zilo_m, 2, - Yiauto, Yrl, Zaut_r, 2, - 0 -}; -uchar ymovl[] = -{ - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - Yi0, Yrl, Zclr, 1, - Yi32, Yrl, Zil_rp, 1, - Yi32, Yml, Zilo_m, 2, - Yml, Ymr, Zm_r_xm, 1, // MMX MOVD - Ymr, Yml, Zr_m_xm, 1, // MMX MOVD - Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit) - Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit) - Yiauto, Yrl, Zaut_r, 2, - 0 -}; -uchar yret[] = -{ - Ynone, Ynone, Zo_iw, 1, - Yi32, Ynone, Zo_iw, 1, - 0 -}; -uchar ymovq[] = -{ - Yrl, Yml, Zr_m, 1, // 0x89 - Yml, Yrl, Zm_r, 1, // 0x8b - Yi0, Yrl, Zclr, 1, // 0x31 - Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0) - Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate - Yi32, Yml, Zilo_m, 2, // 0xc7,(0) - Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding) - Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ - Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD - Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD - Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q - Yxm, Yxr, Zm_r_xm_nr, 2, // MOVQ xmm1/m64 -> xmm2 - Yxr, Yxm, Zr_m_xm_nr, 2, // MOVQ xmm1 -> xmm2/m64 - Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load - Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store - Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ - 0 -}; -uchar ym_rl[] = -{ - Ym, Yrl, Zm_r, 1, - 0 -}; -uchar yrl_m[] = -{ - Yrl, Ym, Zr_m, 1, - 0 -}; -uchar ymb_rl[] = -{ - Ymb, Yrl, Zmb_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 yrb_mb[] = -{ - Yrb, Ymb, Zr_m, 1, - 0 -}; -uchar yxchg[] = -{ - Yax, Yrl, Z_rp, 1, - Yrl, Yax, Zrp_, 1, - 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, - Yml, Yrl, Zm_r, 2, - 0 -}; -uchar yimul3[] = -{ - Yml, Yrl, Zibm_r, 2, - 0 -}; -uchar ybyte[] = -{ - Yi64, 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 ybswap[] = -{ - Ynone, Yrl, Z_rp, 2, - 0, -}; -uchar yscond[] = -{ - Ynone, Ymb, Zo_m, 2, - 0 -}; -uchar yjcond[] = -{ - Ynone, Ybr, Zbr, 0, - Yi0, Ybr, Zbr, 0, - Yi1, Ybr, Zbr, 1, - 0 -}; -uchar yloop[] = -{ - Ynone, Ybr, Zloop, 1, - 0 -}; -uchar ycall[] = -{ - Ynone, Yml, Zo_m64, 0, - Yrx, Yrx, Zo_m64, 2, - Ynone, Ybr, Zcall, 1, - 0 -}; -uchar yjmp[] = -{ - Ynone, Yml, Zo_m64, 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 -}; -uchar ymm[] = -{ - Ymm, Ymr, Zm_r_xm, 1, - Yxm, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yxm[] = -{ - Yxm, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxcvm1[] = -{ - Yxm, Yxr, Zm_r_xm, 2, - Yxm, Ymr, Zm_r_xm, 2, - 0 -}; -uchar yxcvm2[] = -{ - Yxm, Yxr, Zm_r_xm, 2, - Ymm, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yxmq[] = -{ - Yxm, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yxr[] = -{ - Yxr, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxr_ml[] = -{ - Yxr, Yml, Zr_m_xm, 1, - 0 -}; -uchar ymr[] = -{ - Ymr, Ymr, Zm_r, 1, - 0 -}; -uchar ymr_ml[] = -{ - Ymr, Yml, Zr_m_xm, 1, - 0 -}; -uchar yxcmp[] = -{ - Yxm, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxcmpi[] = -{ - Yxm, Yxr, Zm_r_i_xm, 2, - 0 -}; -uchar yxmov[] = -{ - Yxm, Yxr, Zm_r_xm, 1, - Yxr, Yxm, Zr_m_xm, 1, - 0 -}; -uchar yxcvfl[] = -{ - Yxm, Yrl, Zm_r_xm, 1, - 0 -}; -uchar yxcvlf[] = -{ - Yml, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxcvfq[] = -{ - Yxm, Yrl, Zm_r_xm, 2, - 0 -}; -uchar yxcvqf[] = -{ - Yml, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yps[] = -{ - Ymm, Ymr, Zm_r_xm, 1, - Yi8, Ymr, Zibo_m_xm, 2, - Yxm, Yxr, Zm_r_xm, 2, - Yi8, Yxr, Zibo_m_xm, 3, - 0 -}; -uchar yxrrl[] = -{ - Yxr, Yrl, Zm_r, 1, - 0 -}; -uchar ymfp[] = -{ - Ymm, Ymr, Zm_r_3d, 1, - 0, -}; -uchar ymrxr[] = -{ - Ymr, Yxr, Zm_r, 1, - Yxm, Yxr, Zm_r_xm, 1, - 0 -}; -uchar ymshuf[] = -{ - Ymm, Ymr, Zibm_r, 2, - 0 -}; -uchar ymshufb[] = -{ - Yxm, Yxr, Zm2_r, 2, - 0 -}; -uchar yxshuf[] = -{ - Yxm, Yxr, Zibm_r, 2, - 0 -}; -uchar yextrw[] = -{ - Yxr, Yrl, Zibm_r, 2, - 0 -}; -uchar yinsrw[] = -{ - Yml, Yxr, Zibm_r, 2, - 0 -}; -uchar yinsr[] = -{ - Ymm, Yxr, Zibm_r, 3, - 0 -}; -uchar ypsdq[] = -{ - Yi8, Yxr, Zibo_m, 2, - 0 -}; -uchar ymskb[] = -{ - Yxr, Yrl, Zm_r_xm, 2, - Ymr, Yrl, Zm_r_xm, 1, - 0 -}; -uchar ycrc32l[] = -{ - Yml, Yrl, Zlitm_r, 0, -}; -uchar yprefetch[] = -{ - Ym, Ynone, Zm_o, 2, - 0, -}; -uchar yaes[] = -{ - Yxm, Yxr, Zlitm_r, 2, - 0 -}; -uchar yaes2[] = -{ - Yxm, Yxr, Zibm_r, 2, - 0 -}; - -/* - * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32, - * and p->from and p->to as operands (Adr*). The linker scans optab to find - * the entry with the given p->as and then looks through the ytable for that - * instruction (the second field in the optab struct) for a line whose first - * two values match the Ytypes of the p->from and p->to operands. The function - * oclass in span.c computes the specific Ytype of an operand and then the set - * of more general Ytypes that it satisfies is implied by the ycover table, set - * up in instinit. For example, oclass distinguishes the constants 0 and 1 - * from the more general 8-bit constants, but instinit says - * - * ycover[Yi0*Ymax + Ys32] = 1; - * ycover[Yi1*Ymax + Ys32] = 1; - * ycover[Yi8*Ymax + Ys32] = 1; - * - * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32) - * if that's what an instruction can handle. - * - * In parallel with the scan through the ytable for the appropriate line, there - * is a z pointer that starts out pointing at the strange magic byte list in - * the Optab struct. With each step past a non-matching ytable line, z - * advances by the 4th entry in the line. When a matching line is found, that - * z pointer has the extra data to use in laying down the instruction bytes. - * The actual bytes laid down are a function of the 3rd entry in the line (that - * is, the Ztype) and the z bytes. - * - * For example, let's look at AADDL. The optab line says: - * { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, - * - * and yaddl says - * 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 - * }; - * - * so there are 5 possible types of ADDL instruction that can be laid down, and - * possible states used to lay them down (Ztype and z pointer, assuming z - * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are: - * - * Yi8, Yml -> Zibo_m, z (0x83, 00) - * Yi32, Yax -> Zil_, z+2 (0x05) - * Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00) - * Yrl, Yml -> Zr_m, z+2+1+2 (0x01) - * Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03) - * - * The Pconstant in the optab line controls the prefix bytes to emit. That's - * relatively straightforward as this program goes. - * - * The switch on t[2] in doasm implements the various Z cases. Zibo_m, for - * example, is an opcode byte (z[0]) then an asmando (which is some kind of - * encoded addressing mode for the Yml arg), and then a single immediate byte. - * Zilo_m is the same but a long (32-bit) immediate. - */ -Optab optab[] = -/* as, ytab, andproto, opcode */ -{ - { AXXX }, - { AAAA, ynone, P32, 0x37 }, - { AAAD, ynone, P32, 0xd5,0x0a }, - { AAAM, ynone, P32, 0xd4,0x0a }, - { AAAS, ynone, P32, 0x3f }, - { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 }, - { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, - { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, - { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, - { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 }, - { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, - { AADDPD, yxm, Pq, 0x58 }, - { AADDPS, yxm, Pm, 0x58 }, - { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, - { AADDSD, yxm, Pf2, 0x58 }, - { AADDSS, yxm, Pf3, 0x58 }, - { 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 }, - { AANDNPD, yxm, Pq, 0x55 }, - { AANDNPS, yxm, Pm, 0x55 }, - { AANDPD, yxm, Pq, 0x54 }, - { AANDPS, yxm, Pq, 0x54 }, - { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, - { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, - { AARPL, yrl_ml, P32, 0x63 }, - { ABOUNDL, yrl_m, P32, 0x62 }, - { ABOUNDW, yrl_m, Pe, 0x62 }, - { ABSFL, yml_rl, Pm, 0xbc }, - { ABSFQ, yml_rl, Pw, 0x0f,0xbc }, - { ABSFW, yml_rl, Pq, 0xbc }, - { ABSRL, yml_rl, Pm, 0xbd }, - { ABSRQ, yml_rl, Pw, 0x0f,0xbd }, - { ABSRW, yml_rl, Pq, 0xbd }, - { ABSWAPL, ybswap, Px, 0x0f,0xc8 }, - { ABSWAPQ, ybswap, Pw, 0x0f,0xc8 }, - { ABTCL, ybtl, Pm, 0xba,(07),0xbb }, - { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb }, - { ABTCW, ybtl, Pq, 0xba,(07),0xbb }, - { ABTL, ybtl, Pm, 0xba,(04),0xa3 }, - { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3}, - { ABTRL, ybtl, Pm, 0xba,(06),0xb3 }, - { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 }, - { ABTRW, ybtl, Pq, 0xba,(06),0xb3 }, - { ABTSL, ybtl, Pm, 0xba,(05),0xab }, - { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab }, - { ABTSW, ybtl, Pq, 0xba,(05),0xab }, - { ABTW, ybtl, Pq, 0xba,(04),0xa3 }, - { ABYTE, ybyte, Px, 1 }, - { ACALL, ycall, Px, 0xff,(02),0xe8 }, - { ACDQ, ynone, Px, 0x99 }, - { ACLC, ynone, Px, 0xf8 }, - { ACLD, ynone, Px, 0xfc }, - { ACLI, ynone, Px, 0xfa }, - { ACLTS, ynone, Pm, 0x06 }, - { ACMC, ynone, Px, 0xf5 }, - { ACMOVLCC, yml_rl, Pm, 0x43 }, - { ACMOVLCS, yml_rl, Pm, 0x42 }, - { ACMOVLEQ, yml_rl, Pm, 0x44 }, - { ACMOVLGE, yml_rl, Pm, 0x4d }, - { ACMOVLGT, yml_rl, Pm, 0x4f }, - { ACMOVLHI, yml_rl, Pm, 0x47 }, - { ACMOVLLE, yml_rl, Pm, 0x4e }, - { ACMOVLLS, yml_rl, Pm, 0x46 }, - { ACMOVLLT, yml_rl, Pm, 0x4c }, - { ACMOVLMI, yml_rl, Pm, 0x48 }, - { ACMOVLNE, yml_rl, Pm, 0x45 }, - { ACMOVLOC, yml_rl, Pm, 0x41 }, - { ACMOVLOS, yml_rl, Pm, 0x40 }, - { ACMOVLPC, yml_rl, Pm, 0x4b }, - { ACMOVLPL, yml_rl, Pm, 0x49 }, - { ACMOVLPS, yml_rl, Pm, 0x4a }, - { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 }, - { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 }, - { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 }, - { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d }, - { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f }, - { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 }, - { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e }, - { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 }, - { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c }, - { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 }, - { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 }, - { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 }, - { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 }, - { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b }, - { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 }, - { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a }, - { ACMOVWCC, yml_rl, Pq, 0x43 }, - { ACMOVWCS, yml_rl, Pq, 0x42 }, - { ACMOVWEQ, yml_rl, Pq, 0x44 }, - { ACMOVWGE, yml_rl, Pq, 0x4d }, - { ACMOVWGT, yml_rl, Pq, 0x4f }, - { ACMOVWHI, yml_rl, Pq, 0x47 }, - { ACMOVWLE, yml_rl, Pq, 0x4e }, - { ACMOVWLS, yml_rl, Pq, 0x46 }, - { ACMOVWLT, yml_rl, Pq, 0x4c }, - { ACMOVWMI, yml_rl, Pq, 0x48 }, - { ACMOVWNE, yml_rl, Pq, 0x45 }, - { ACMOVWOC, yml_rl, Pq, 0x41 }, - { ACMOVWOS, yml_rl, Pq, 0x40 }, - { ACMOVWPC, yml_rl, Pq, 0x4b }, - { ACMOVWPL, yml_rl, Pq, 0x49 }, - { ACMOVWPS, yml_rl, Pq, 0x4a }, - { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a }, - { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, - { ACMPPD, yxcmpi, Px, Pe,0xc2 }, - { ACMPPS, yxcmpi, Pm, 0xc2,0 }, - { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, - { ACMPSB, ynone, Pb, 0xa6 }, - { ACMPSD, yxcmpi, Px, Pf2,0xc2 }, - { ACMPSL, ynone, Px, 0xa7 }, - { ACMPSQ, ynone, Pw, 0xa7 }, - { ACMPSS, yxcmpi, Px, Pf3,0xc2 }, - { ACMPSW, ynone, Pe, 0xa7 }, - { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, - { ACOMISD, yxcmp, Pe, 0x2f }, - { ACOMISS, yxcmp, Pm, 0x2f }, - { ACPUID, ynone, Pm, 0xa2 }, - { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a }, - { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, }, - { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d }, - { ACVTPD2PS, yxm, Pe, 0x5a }, - { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d }, - { ACVTPS2PD, yxm, Pm, 0x5a }, - { API2FW, ymfp, Px, 0x0c }, - { ACVTSD2SL, yxcvfl, Pf2, 0x2d }, - { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d }, - { ACVTSD2SS, yxm, Pf2, 0x5a }, - { ACVTSL2SD, yxcvlf, Pf2, 0x2a }, - { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a }, - { ACVTSL2SS, yxcvlf, Pf3, 0x2a }, - { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a }, - { ACVTSS2SD, yxm, Pf3, 0x5a }, - { ACVTSS2SL, yxcvfl, Pf3, 0x2d }, - { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d }, - { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c }, - { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c }, - { ACVTTSD2SL, yxcvfl, Pf2, 0x2c }, - { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c }, - { ACVTTSS2SL, yxcvfl, Pf3, 0x2c }, - { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c }, - { ACWD, ynone, Pe, 0x99 }, - { ACQO, ynone, Pw, 0x99 }, - { ADAA, ynone, P32, 0x27 }, - { ADAS, ynone, P32, 0x2f }, - { ADATA }, - { ADECB, yincb, Pb, 0xfe,(01) }, - { ADECL, yincl, Px, 0xff,(01) }, - { ADECQ, yincl, Pw, 0xff,(01) }, - { ADECW, yincw, Pe, 0xff,(01) }, - { ADIVB, ydivb, Pb, 0xf6,(06) }, - { ADIVL, ydivl, Px, 0xf7,(06) }, - { ADIVPD, yxm, Pe, 0x5e }, - { ADIVPS, yxm, Pm, 0x5e }, - { ADIVQ, ydivl, Pw, 0xf7,(06) }, - { ADIVSD, yxm, Pf2, 0x5e }, - { ADIVSS, yxm, Pf3, 0x5e }, - { ADIVW, ydivl, Pe, 0xf7,(06) }, - { AEMMS, ynone, Pm, 0x77 }, - { AENTER }, /* botch */ - { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) }, - { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) }, - { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) }, - { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) }, - { AGLOBL }, - { AGOK }, - { AHISTORY }, - { AHLT, ynone, Px, 0xf4 }, - { AIDIVB, ydivb, Pb, 0xf6,(07) }, - { AIDIVL, ydivl, Px, 0xf7,(07) }, - { AIDIVQ, ydivl, Pw, 0xf7,(07) }, - { AIDIVW, ydivl, Pe, 0xf7,(07) }, - { AIMULB, ydivb, Pb, 0xf6,(05) }, - { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf }, - { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf }, - { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf }, - { AIMUL3Q, yimul3, Pw, 0x6b,(00) }, - { AINB, yin, Pb, 0xe4,0xec }, - { AINCB, yincb, Pb, 0xfe,(00) }, - { AINCL, yincl, Px, 0xff,(00) }, - { AINCQ, yincl, Pw, 0xff,(00) }, - { AINCW, yincw, Pe, 0xff,(00) }, - { AINL, yin, Px, 0xe5,0xed }, - { AINSB, ynone, Pb, 0x6c }, - { AINSL, ynone, Px, 0x6d }, - { AINSW, ynone, Pe, 0x6d }, - { AINT, yint, Px, 0xcd }, - { AINTO, ynone, P32, 0xce }, - { AINW, yin, Pe, 0xe5,0xed }, - { AIRETL, ynone, Px, 0xcf }, - { AIRETQ, ynone, Pw, 0xcf }, - { AIRETW, ynone, Pe, 0xcf }, - { AJCC, yjcond, Px, 0x73,0x83,(00) }, - { AJCS, yjcond, Px, 0x72,0x82 }, - { AJCXZL, yloop, Px, 0xe3 }, - { AJCXZQ, 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 }, - { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) }, - { ALEAL, ym_rl, Px, 0x8d }, - { ALEAQ, ym_rl, Pw, 0x8d }, - { ALEAVEL, ynone, P32, 0xc9 }, - { ALEAVEQ, ynone, Py, 0xc9 }, - { ALEAVEW, ynone, Pe, 0xc9 }, - { ALEAW, ym_rl, Pe, 0x8d }, - { ALOCK, ynone, Px, 0xf0 }, - { ALODSB, ynone, Pb, 0xac }, - { ALODSL, ynone, Px, 0xad }, - { ALODSQ, ynone, Pw, 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 }, - { AMASKMOVOU, yxr, Pe, 0xf7 }, - { AMASKMOVQ, ymr, Pm, 0xf7 }, - { AMAXPD, yxm, Pe, 0x5f }, - { AMAXPS, yxm, Pm, 0x5f }, - { AMAXSD, yxm, Pf2, 0x5f }, - { AMAXSS, yxm, Pf3, 0x5f }, - { AMINPD, yxm, Pe, 0x5d }, - { AMINPS, yxm, Pm, 0x5d }, - { AMINSD, yxm, Pf2, 0x5d }, - { AMINSS, yxm, Pf3, 0x5d }, - { AMOVAPD, yxmov, Pe, 0x28,0x29 }, - { AMOVAPS, yxmov, Pm, 0x28,0x29 }, - { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) }, - { AMOVBLSX, ymb_rl, Pm, 0xbe }, - { AMOVBLZX, ymb_rl, Pm, 0xb6 }, - { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe }, - { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 }, - { AMOVBWSX, ymb_rl, Pq, 0xbe }, - { AMOVBWZX, ymb_rl, Pq, 0xb6 }, - { AMOVO, yxmov, Pe, 0x6f,0x7f }, - { AMOVOU, yxmov, Pf3, 0x6f,0x7f }, - { AMOVHLPS, yxr, Pm, 0x12 }, - { AMOVHPD, yxmov, Pe, 0x16,0x17 }, - { AMOVHPS, yxmov, Pm, 0x16,0x17 }, - { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e,0 }, - { AMOVLHPS, yxr, Pm, 0x16 }, - { AMOVLPD, yxmov, Pe, 0x12,0x13 }, - { AMOVLPS, yxmov, Pm, 0x12,0x13 }, - { AMOVLQSX, yml_rl, Pw, 0x63 }, - { AMOVLQZX, yml_rl, Px, 0x8b }, - { AMOVMSKPD, yxrrl, Pq, 0x50 }, - { AMOVMSKPS, yxrrl, Pm, 0x50 }, - { AMOVNTO, yxr_ml, Pe, 0xe7 }, - { AMOVNTPD, yxr_ml, Pe, 0x2b }, - { AMOVNTPS, yxr_ml, Pm, 0x2b }, - { AMOVNTQ, ymr_ml, Pm, 0xe7 }, - { AMOVQ, ymovq, Pw, 0x89, 0x8b, 0x31, 0xc7,(00), 0xb8, 0xc7,(00), 0x6f, 0x7f, 0x6e, 0x7e, Pf2,0xd6, Pf3,0x7e, Pe,0xd6, Pe,0x6e, Pe,0x7e,0 }, - { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e }, - { AMOVSB, ynone, Pb, 0xa4 }, - { AMOVSD, yxmov, Pf2, 0x10,0x11 }, - { AMOVSL, ynone, Px, 0xa5 }, - { AMOVSQ, ynone, Pw, 0xa5 }, - { AMOVSS, yxmov, Pf3, 0x10,0x11 }, - { AMOVSW, ynone, Pe, 0xa5 }, - { AMOVUPD, yxmov, Pe, 0x10,0x11 }, - { AMOVUPS, yxmov, Pm, 0x10,0x11 }, - { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00),0 }, - { AMOVWLSX, yml_rl, Pm, 0xbf }, - { AMOVWLZX, yml_rl, Pm, 0xb7 }, - { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf }, - { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 }, - { AMULB, ydivb, Pb, 0xf6,(04) }, - { AMULL, ydivl, Px, 0xf7,(04) }, - { AMULPD, yxm, Pe, 0x59 }, - { AMULPS, yxm, Ym, 0x59 }, - { AMULQ, ydivl, Pw, 0xf7,(04) }, - { AMULSD, yxm, Pf2, 0x59 }, - { AMULSS, yxm, Pf3, 0x59 }, - { AMULW, ydivl, Pe, 0xf7,(04) }, - { ANAME }, - { ANEGB, yscond, Pb, 0xf6,(03) }, - { ANEGL, yscond, Px, 0xf7,(03) }, - { ANEGQ, yscond, Pw, 0xf7,(03) }, - { ANEGW, yscond, Pe, 0xf7,(03) }, - { ANOP, ynop, Px, 0,0 }, - { ANOTB, yscond, Pb, 0xf6,(02) }, - { ANOTL, yscond, Px, 0xf7,(02) }, - { ANOTQ, yscond, Pw, 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 }, - { AORPD, yxm, Pq, 0x56 }, - { AORPS, yxm, Pm, 0x56 }, - { AORQ, yxorl, Pw, 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 }, - { AOUTSB, ynone, Pb, 0x6e }, - { AOUTSL, ynone, Px, 0x6f }, - { AOUTSW, ynone, Pe, 0x6f }, - { AOUTW, yin, Pe, 0xe7,0xef }, - { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b }, - { APACKSSWB, ymm, Py, 0x63,Pe,0x63 }, - { APACKUSWB, ymm, Py, 0x67,Pe,0x67 }, - { APADDB, ymm, Py, 0xfc,Pe,0xfc }, - { APADDL, ymm, Py, 0xfe,Pe,0xfe }, - { APADDQ, yxm, Pe, 0xd4 }, - { APADDSB, ymm, Py, 0xec,Pe,0xec }, - { APADDSW, ymm, Py, 0xed,Pe,0xed }, - { APADDUSB, ymm, Py, 0xdc,Pe,0xdc }, - { APADDUSW, ymm, Py, 0xdd,Pe,0xdd }, - { APADDW, ymm, Py, 0xfd,Pe,0xfd }, - { APAND, ymm, Py, 0xdb,Pe,0xdb }, - { APANDN, ymm, Py, 0xdf,Pe,0xdf }, - { APAUSE, ynone, Px, 0xf3,0x90 }, - { APAVGB, ymm, Py, 0xe0,Pe,0xe0 }, - { APAVGW, ymm, Py, 0xe3,Pe,0xe3 }, - { APCMPEQB, ymm, Py, 0x74,Pe,0x74 }, - { APCMPEQL, ymm, Py, 0x76,Pe,0x76 }, - { APCMPEQW, ymm, Py, 0x75,Pe,0x75 }, - { APCMPGTB, ymm, Py, 0x64,Pe,0x64 }, - { APCMPGTL, ymm, Py, 0x66,Pe,0x66 }, - { APCMPGTW, ymm, Py, 0x65,Pe,0x65 }, - { APEXTRW, yextrw, Pq, 0xc5,(00) }, - { APF2IL, ymfp, Px, 0x1d }, - { APF2IW, ymfp, Px, 0x1c }, - { API2FL, ymfp, Px, 0x0d }, - { APFACC, ymfp, Px, 0xae }, - { APFADD, ymfp, Px, 0x9e }, - { APFCMPEQ, ymfp, Px, 0xb0 }, - { APFCMPGE, ymfp, Px, 0x90 }, - { APFCMPGT, ymfp, Px, 0xa0 }, - { APFMAX, ymfp, Px, 0xa4 }, - { APFMIN, ymfp, Px, 0x94 }, - { APFMUL, ymfp, Px, 0xb4 }, - { APFNACC, ymfp, Px, 0x8a }, - { APFPNACC, ymfp, Px, 0x8e }, - { APFRCP, ymfp, Px, 0x96 }, - { APFRCPIT1, ymfp, Px, 0xa6 }, - { APFRCPI2T, ymfp, Px, 0xb6 }, - { APFRSQIT1, ymfp, Px, 0xa7 }, - { APFRSQRT, ymfp, Px, 0x97 }, - { APFSUB, ymfp, Px, 0x9a }, - { APFSUBR, ymfp, Px, 0xaa }, - { APINSRW, yinsrw, Pq, 0xc4,(00) }, - { APINSRD, yinsr, Pq, 0x3a, 0x22, (00) }, - { APINSRQ, yinsr, Pq3, 0x3a, 0x22, (00) }, - { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 }, - { APMAXSW, yxm, Pe, 0xee }, - { APMAXUB, yxm, Pe, 0xde }, - { APMINSW, yxm, Pe, 0xea }, - { APMINUB, yxm, Pe, 0xda }, - { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 }, - { APMULHRW, ymfp, Px, 0xb7 }, - { APMULHUW, ymm, Py, 0xe4,Pe,0xe4 }, - { APMULHW, ymm, Py, 0xe5,Pe,0xe5 }, - { APMULLW, ymm, Py, 0xd5,Pe,0xd5 }, - { APMULULQ, ymm, Py, 0xf4,Pe,0xf4 }, - { APOPAL, ynone, P32, 0x61 }, - { APOPAW, ynone, Pe, 0x61 }, - { APOPFL, ynone, P32, 0x9d }, - { APOPFQ, ynone, Py, 0x9d }, - { APOPFW, ynone, Pe, 0x9d }, - { APOPL, ypopl, P32, 0x58,0x8f,(00) }, - { APOPQ, ypopl, Py, 0x58,0x8f,(00) }, - { APOPW, ypopl, Pe, 0x58,0x8f,(00) }, - { APOR, ymm, Py, 0xeb,Pe,0xeb }, - { APSADBW, yxm, Pq, 0xf6 }, - { APSHUFHW, yxshuf, Pf3, 0x70,(00) }, - { APSHUFL, yxshuf, Pq, 0x70,(00) }, - { APSHUFLW, yxshuf, Pf2, 0x70,(00) }, - { APSHUFW, ymshuf, Pm, 0x70,(00) }, - { APSHUFB, ymshufb,Pq, 0x38, 0x00 }, - { APSLLO, ypsdq, Pq, 0x73,(07) }, - { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) }, - { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06) }, - { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) }, - { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) }, - { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) }, - { APSRLO, ypsdq, Pq, 0x73,(03) }, - { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) }, - { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) }, - { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) }, - { APSUBB, yxm, Pe, 0xf8 }, - { APSUBL, yxm, Pe, 0xfa }, - { APSUBQ, yxm, Pe, 0xfb }, - { APSUBSB, yxm, Pe, 0xe8 }, - { APSUBSW, yxm, Pe, 0xe9 }, - { APSUBUSB, yxm, Pe, 0xd8 }, - { APSUBUSW, yxm, Pe, 0xd9 }, - { APSUBW, yxm, Pe, 0xf9 }, - { APSWAPL, ymfp, Px, 0xbb }, - { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 }, - { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a }, - { APUNPCKHQDQ, yxm, Pe, 0x6d }, - { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 }, - { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 }, - { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 }, - { APUNPCKLQDQ, yxm, Pe, 0x6c }, - { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 }, - { APUSHAL, ynone, P32, 0x60 }, - { APUSHAW, ynone, Pe, 0x60 }, - { APUSHFL, ynone, P32, 0x9c }, - { APUSHFQ, ynone, Py, 0x9c }, - { APUSHFW, ynone, Pe, 0x9c }, - { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 }, - { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 }, - { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 }, - { APXOR, ymm, Py, 0xef,Pe,0xef }, - { AQUAD, ybyte, Px, 8 }, - { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) }, - { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, - { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, - { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, - { ARCPPS, yxm, Pm, 0x53 }, - { ARCPSS, yxm, Pf3, 0x53 }, - { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) }, - { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, - { ARCRQ, yshl, Pw, 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 }, - { ARETFW, yret, Pe, 0xcb,0xca }, - { ARETFL, yret, Px, 0xcb,0xca }, - { ARETFQ, yret, Pw, 0xcb,0xca }, - { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) }, - { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, - { AROLQ, yshl, Pw, 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) }, - { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, - { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, - { ARSQRTPS, yxm, Pm, 0x52 }, - { ARSQRTSS, yxm, Pf3, 0x52 }, - { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */ - { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, - { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, - { ASALQ, yshl, Pw, 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) }, - { ASARQ, yshl, Pw, 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 }, - { ASBBQ, yxorl, Pw, 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 }, - { ASCASQ, ynone, Pw, 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) }, - { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, - { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, - { ASHLQ, yshl, Pw, 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) }, - { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, - { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, - { ASHUFPD, yxshuf, Pq, 0xc6,(00) }, - { ASHUFPS, yxshuf, Pm, 0xc6,(00) }, - { ASQRTPD, yxm, Pe, 0x51 }, - { ASQRTPS, yxm, Pm, 0x51 }, - { ASQRTSD, yxm, Pf2, 0x51 }, - { ASQRTSS, yxm, Pf3, 0x51 }, - { ASTC, ynone, Px, 0xf9 }, - { ASTD, ynone, Px, 0xfd }, - { ASTI, ynone, Px, 0xfb }, - { ASTMXCSR, ysvrs, Pm, 0xae,(03),0xae,(03) }, - { ASTOSB, ynone, Pb, 0xaa }, - { ASTOSL, ynone, Px, 0xab }, - { ASTOSQ, ynone, Pw, 0xab }, - { ASTOSW, ynone, Pe, 0xab }, - { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a }, - { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, - { ASUBPD, yxm, Pe, 0x5c }, - { ASUBPS, yxm, Pm, 0x5c }, - { ASUBQ, yaddl, Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, - { ASUBSD, yxm, Pf2, 0x5c }, - { ASUBSS, yxm, Pf3, 0x5c }, - { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, - { ASWAPGS, ynone, Pm, 0x01,0xf8 }, - { ASYSCALL, ynone, Px, 0x0f,0x05 }, /* fast syscall */ - { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 }, - { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 }, - { ATESTQ, ytestl, Pw, 0xa9,0xf7,(00),0x85,0x85 }, - { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 }, - { ATEXT, ytext, Px }, - { AUCOMISD, yxcmp, Pe, 0x2e }, - { AUCOMISS, yxcmp, Pm, 0x2e }, - { AUNPCKHPD, yxm, Pe, 0x15 }, - { AUNPCKHPS, yxm, Pm, 0x15 }, - { AUNPCKLPD, yxm, Pe, 0x14 }, - { AUNPCKLPS, yxm, Pm, 0x14 }, - { 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, yxchg, Px, 0x90,0x90,0x87,0x87 }, - { AXCHGQ, yxchg, Pw, 0x90,0x90,0x87,0x87 }, - { AXCHGW, yxchg, Pe, 0x90,0x90,0x87,0x87 }, - { AXLAT, ynone, Px, 0xd7 }, - { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 }, - { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, - { AXORPD, yxm, Pe, 0x57 }, - { AXORPS, yxm, Pm, 0x57 }, - { AXORQ, yxorl, Pw, 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 }, - - { ACMPXCHGB, yrb_mb, Pb, 0x0f,0xb0 }, - { ACMPXCHGL, yrl_ml, Px, 0x0f,0xb1 }, - { ACMPXCHGW, yrl_ml, Pe, 0x0f,0xb1 }, - { ACMPXCHGQ, yrl_ml, Pw, 0x0f,0xb1 }, - { ACMPXCHG8B, yscond, Pm, 0xc7,(01) }, - { AINVD, ynone, Pm, 0x08 }, - { AINVLPG, ymbs, Pm, 0x01,(07) }, - { ALFENCE, ynone, Pm, 0xae,0xe8 }, - { AMFENCE, ynone, Pm, 0xae,0xf0 }, - { AMOVNTIL, yrl_ml, Pm, 0xc3 }, - { AMOVNTIQ, yrl_ml, Pw, 0x0f,0xc3 }, - { ARDMSR, ynone, Pm, 0x32 }, - { ARDPMC, ynone, Pm, 0x33 }, - { ARDTSC, ynone, Pm, 0x31 }, - { ARSM, ynone, Pm, 0xaa }, - { ASFENCE, ynone, Pm, 0xae,0xf8 }, - { ASYSRET, ynone, Pm, 0x07 }, - { AWBINVD, ynone, Pm, 0x09 }, - { AWRMSR, ynone, Pm, 0x30 }, - - { AXADDB, yrb_mb, Pb, 0x0f,0xc0 }, - { AXADDL, yrl_ml, Px, 0x0f,0xc1 }, - { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 }, - { AXADDW, yrl_ml, Pe, 0x0f,0xc1 }, - - { ACRC32B, ycrc32l,Px, 0xf2,0x0f,0x38,0xf0,0 }, - { ACRC32Q, ycrc32l,Pw, 0xf2,0x0f,0x38,0xf1,0 }, - - { APREFETCHT0, yprefetch, Pm, 0x18,(01) }, - { APREFETCHT1, yprefetch, Pm, 0x18,(02) }, - { APREFETCHT2, yprefetch, Pm, 0x18,(03) }, - { APREFETCHNTA, yprefetch, Pm, 0x18,(00) }, - - { AMOVQL, yrl_ml, Px, 0x89 }, - - { AUNDEF, ynone, Px, 0x0f, 0x0b }, - - { AAESENC, yaes, Pq, 0x38,0xdc,(0) }, - { AAESENCLAST, yaes, Pq, 0x38,0xdd,(0) }, - { AAESDEC, yaes, Pq, 0x38,0xde,(0) }, - { AAESDECLAST, yaes, Pq, 0x38,0xdf,(0) }, - { AAESIMC, yaes, Pq, 0x38,0xdb,(0) }, - { AAESKEYGENASSIST, yaes2, Pq, 0x3a,0xdf,(0) }, - - { APSHUFD, yaes2, Pq, 0x70,(0) }, - { APCLMULQDQ, yxshuf, Pq, 0x3a,0x44,0 }, - - { AUSEFIELD, ynop, Px, 0,0 }, - { ATYPE }, - { AFUNCDATA, yfuncdata, Px, 0,0 }, - { APCDATA, ypcdata, Px, 0,0 }, - { ACHECKNIL }, - { AFATVARDEF }, - - { AEND }, - 0 -}; - -Optab* opindex[ALAST+1]; - -/* -AMOVD 0f 6e/r mmx,reg/mem32[mem64-rex?] -AMOVD 0f 7e/r reg/mem32[64],mmx STORE -AMOVQ 0f 6f/r mmx1,mmx2/mem64 -AMOVQ 0f 7f/r mmx1/mem64,mmx2 -*/ diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c deleted file mode 100644 index 1be3c18fe..000000000 --- a/src/cmd/6l/pass.c +++ /dev/null @@ -1,991 +0,0 @@ -// Inferno utils/6l/pass.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/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. - -// Code and data passes. - -#include "l.h" -#include "../ld/lib.h" -#include "../../pkg/runtime/stack.h" - -static void xfol(Prog*, Prog**); - -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) -{ - Prog *firstp, *lastp; - - if(debug['v']) - Bprint(&bso, "%5.2f follow\n", cputime()); - Bflush(&bso); - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - firstp = prg(); - lastp = firstp; - xfol(cursym->text, &lastp); - lastp->link = nil; - cursym->text = firstp->link; - } -} - -static int -nofollow(int a) -{ - switch(a) { - case AJMP: - case ARET: - case AIRETL: - case AIRETQ: - case AIRETW: - case ARETFL: - case ARETFQ: - case ARETFW: - case AUNDEF: - return 1; - } - return 0; -} - -static int -pushpop(int a) -{ - switch(a) { - case APUSHL: - case APUSHFL: - case APUSHQ: - case APUSHFQ: - case APUSHW: - case APUSHFW: - case APOPL: - case APOPFL: - case APOPQ: - case APOPFQ: - case APOPW: - case APOPFW: - return 1; - } - return 0; -} - -static void -xfol(Prog *p, Prog **last) -{ - Prog *q; - int i; - enum as a; - -loop: - if(p == P) - return; - if(p->as == AJMP) - if((q = p->pcond) != P && q->as != ATEXT) { - /* mark instruction as done and continue layout at target of jump */ - p->mark = 1; - p = q; - if(p->mark == 0) - goto loop; - } - if(p->mark) { - /* - * p goes here, but already used it elsewhere. - * copy up to 4 instructions or else branch to other copy. - */ - for(i=0,q=p; i<4; i++,q=q->link) { - if(q == P) - break; - if(q == *last) - break; - a = q->as; - if(a == ANOP) { - i--; - continue; - } - if(nofollow(a) || pushpop(a)) - break; // NOTE(rsc): arm does goto copy - 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; - (*last)->link = q; - *last = 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, last); - p = q->link; - if(p->mark) - return; - goto loop; - } - } /* */ - q = prg(); - q->as = AJMP; - q->line = p->line; - q->to.type = D_BRANCH; - q->to.offset = p->pc; - q->pcond = p; - p = q; - } - - /* emit p */ - p->mark = 1; - (*last)->link = p; - *last = p; - a = p->as; - - /* continue loop with what comes after p */ - if(nofollow(a)) - return; - if(p->pcond != P && a != ACALL) { - /* - * some kind of conditional branch. - * recurse to follow one path. - * continue loop on the other. - */ - if((q = brchain(p->pcond)) != P) - p->pcond = q; - if((q = brchain(p->link)) != P) - p->link = q; - if(p->from.type == D_CONST) { - if(p->from.offset == 1) { - /* - * expect conditional jump to be taken. - * rewrite so that's the fall-through case. - */ - p->as = relinv(a); - q = p->link; - p->link = p->pcond; - p->pcond = q; - } - } else { - q = p->link; - if(q->mark) - if(a != ALOOP) { - p->as = relinv(a); - p->link = p->pcond; - p->pcond = q; - } - } - xfol(p->link, last); - if(p->pcond->mark) - return; - p = p->pcond; - goto loop; - } - p = p->link; - goto loop; -} - -Prog* -byteq(int v) -{ - Prog *p; - - p = prg(); - p->as = ABYTE; - p->from.type = D_CONST; - p->from.offset = v&0xff; - return p; -} - -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); - errorexit(); - return a; -} - -void -patch(void) -{ - int32 c; - Prog *p, *q; - Sym *s; - int32 vexit; - Sym *gmsym; - - 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); - - if(flag_shared) { - s = lookup("init_array", 0); - s->type = SINITARR; - s->reachable = 1; - s->hide = 1; - addaddr(s, lookup(INITENTRY, 0)); - } - - gmsym = lookup("runtime.tlsgm", 0); - if(linkmode != LinkExternal) - gmsym->reachable = 0; - s = lookup("exit", 0); - vexit = s->value; - for(cursym = textp; cursym != nil; cursym = cursym->next) - for(p = cursym->text; p != P; p = p->link) { - if(HEADTYPE == Hwindows) { - // Windows - // Convert - // op n(GS), reg - // to - // MOVL 0x28(GS), reg - // op n(reg), reg - // The purpose of this patch is to fix some accesses - // to extern register variables (TLS) on Windows, as - // a different method is used to access them. - if(p->from.type == D_INDIR+D_GS - && p->to.type >= D_AX && p->to.type <= D_DI - && p->from.offset <= 8) { - q = appendp(p); - q->from = p->from; - q->from.type = D_INDIR + p->to.type; - q->to = p->to; - q->as = p->as; - p->as = AMOVQ; - p->from.type = D_INDIR+D_GS; - p->from.offset = 0x28; - } - } - if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd - || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd - || HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) { - // ELF uses FS instead of GS. - if(p->from.type == D_INDIR+D_GS) - p->from.type = D_INDIR+D_FS; - if(p->to.type == D_INDIR+D_GS) - p->to.type = D_INDIR+D_FS; - if(p->from.index == D_GS) - p->from.index = D_FS; - if(p->to.index == D_GS) - p->to.index = D_FS; - } - if(!flag_shared) { - // Convert g() or m() accesses of the form - // op n(reg)(GS*1), reg - // to - // op n(GS*1), reg - if(p->from.index == D_FS || p->from.index == D_GS) { - p->from.type = D_INDIR + p->from.index; - p->from.index = D_NONE; - } - // Convert g() or m() accesses of the form - // op reg, n(reg)(GS*1) - // to - // op reg, n(GS*1) - if(p->to.index == D_FS || p->to.index == D_GS) { - p->to.type = D_INDIR + p->to.index; - p->to.index = D_NONE; - } - // Convert get_tls access of the form - // op runtime.tlsgm(SB), reg - // to - // NOP - if(gmsym != S && p->from.sym == gmsym) { - p->as = ANOP; - p->from.type = D_NONE; - p->to.type = D_NONE; - p->from.sym = nil; - p->to.sym = nil; - continue; - } - } else { - // Convert TLS reads of the form - // op n(GS), reg - // to - // MOVQ $runtime.tlsgm(SB), reg - // op n(reg)(GS*1), reg - if((p->from.type == D_INDIR+D_FS || p->from.type == D_INDIR + D_GS) && p->to.type >= D_AX && p->to.type <= D_DI) { - q = appendp(p); - q->to = p->to; - q->as = p->as; - q->from.type = D_INDIR+p->to.type; - q->from.index = p->from.type - D_INDIR; - q->from.scale = 1; - q->from.offset = p->from.offset; - p->as = AMOVQ; - p->from.type = D_EXTERN; - p->from.sym = gmsym; - p->from.offset = 0; - } - } - if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) { - s = p->to.sym; - if(s) { - if(debug['c']) - Bprint(&bso, "%s calls %s\n", TNAME, s->name); - if((s->type&SMASK) != STEXT) { - /* diag prints TNAME first */ - diag("undefined: %s", s->name); - s->type = STEXT; - s->value = vexit; - continue; // avoid more error messages - } - if(s->text == nil) - continue; - p->to.type = D_BRANCH; - p->to.offset = s->text->pc; - p->pcond = s->text; - continue; - } - } - if(p->to.type != D_BRANCH) - continue; - c = p->to.offset; - for(q = cursym->text; q != P;) { - if(c == q->pc) - break; - if(q->forwd != P && c >= q->forwd->pc) - q = q->forwd; - else - q = q->link; - } - if(q == P) { - diag("branch out of range in %s (%#ux)\n%P [%s]", - TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>"); - p->to.type = D_NONE; - } - p->pcond = q; - } - - for(cursym = textp; cursym != nil; cursym = cursym->next) - for(p = cursym->text; p != P; p = p->link) { - p->mark = 0; /* initialization for follow */ - if(p->pcond != P) { - p->pcond = brloop(p->pcond); - if(p->pcond != P) - if(p->to.type == D_BRANCH) - p->to.offset = p->pcond->pc; - } - } -} - -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; -} - -static char* -morename[] = -{ - "runtime.morestack00", - "runtime.morestack10", - "runtime.morestack01", - "runtime.morestack11", - - "runtime.morestack8", - "runtime.morestack16", - "runtime.morestack24", - "runtime.morestack32", - "runtime.morestack40", - "runtime.morestack48", -}; -Prog* pmorestack[nelem(morename)]; -Sym* symmorestack[nelem(morename)]; -Sym* gmsym; - -static Prog* load_g_cx(Prog*); -static Prog* stacksplit(Prog*, int32, Prog**); - -void -dostkoff(void) -{ - Prog *p, *q, *q1; - int32 autoffset, deltasp; - int a, pcsize; - uint32 i; - - gmsym = lookup("runtime.tlsgm", 0); - for(i=0; i<nelem(morename); i++) { - symmorestack[i] = lookup(morename[i], 0); - if(symmorestack[i]->type != STEXT) - diag("morestack trampoline not defined - %s", morename[i]); - pmorestack[i] = symmorestack[i]->text; - } - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(cursym->text == nil || cursym->text->link == nil) - continue; - - p = cursym->text; - parsetextconst(p->to.offset); - autoffset = textstksiz; - if(autoffset < 0) - autoffset = 0; - - if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) { - for(q = p; q != P; q = q->link) - if(q->as == ACALL) - goto noleaf; - p->from.scale |= NOSPLIT; - noleaf:; - } - - if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) - diag("nosplit func likely to overflow stack"); - - q = P; - if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) { - p = appendp(p); - p = load_g_cx(p); // load g into CX - } - if(!(cursym->text->from.scale & NOSPLIT)) - p = stacksplit(p, autoffset, &q); // emit split check - - if(autoffset) { - p = appendp(p); - p->as = AADJSP; - p->from.type = D_CONST; - p->from.offset = autoffset; - p->spadj = autoffset; - } else { - // zero-byte stack adjustment. - // Insert a fake non-zero adjustment so that stkcheck can - // recognize the end of the stack-splitting prolog. - p = appendp(p); - p->as = ANOP; - p->spadj = -PtrSize; - p = appendp(p); - p->as = ANOP; - p->spadj = PtrSize; - } - if(q != P) - q->pcond = p; - deltasp = autoffset; - - if(cursym->text->from.scale & WRAPPER) { - // g->panicwrap += autoffset + PtrSize; - p = appendp(p); - p->as = AADDL; - p->from.type = D_CONST; - p->from.offset = autoffset + PtrSize; - p->to.type = D_INDIR+D_CX; - p->to.offset = 2*PtrSize; - } - - if(debug['K'] > 1 && autoffset) { - // 6l -KK means double-check for stack overflow - // even after calling morestack and even if the - // function is marked as nosplit. - p = appendp(p); - p->as = AMOVQ; - p->from.type = D_INDIR+D_CX; - p->from.offset = 0; - p->to.type = D_BX; - - p = appendp(p); - p->as = ASUBQ; - p->from.type = D_CONST; - p->from.offset = StackSmall+32; - p->to.type = D_BX; - - p = appendp(p); - p->as = ACMPQ; - p->from.type = D_SP; - p->to.type = D_BX; - - p = appendp(p); - p->as = AJHI; - p->to.type = D_BRANCH; - q1 = p; - - p = appendp(p); - p->as = AINT; - p->from.type = D_CONST; - p->from.offset = 3; - - p = appendp(p); - p->as = ANOP; - q1->pcond = p; - } - - if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) { - // 6l -Z means zero the stack frame on entry. - // This slows down function calls but can help avoid - // false positives in garbage collection. - p = appendp(p); - p->as = AMOVQ; - p->from.type = D_SP; - p->to.type = D_DI; - - p = appendp(p); - p->as = AMOVQ; - p->from.type = D_CONST; - p->from.offset = autoffset/8; - p->to.type = D_CX; - - p = appendp(p); - p->as = AMOVQ; - p->from.type = D_CONST; - p->from.offset = 0; - p->to.type = D_AX; - - p = appendp(p); - p->as = AREP; - - p = appendp(p); - p->as = ASTOSQ; - } - - for(; p != P; p = p->link) { - pcsize = p->mode/8; - a = p->from.type; - if(a == D_AUTO) - p->from.offset += deltasp; - if(a == D_PARAM) - p->from.offset += deltasp + pcsize; - a = p->to.type; - if(a == D_AUTO) - p->to.offset += deltasp; - if(a == D_PARAM) - p->to.offset += deltasp + pcsize; - - switch(p->as) { - default: - continue; - case APUSHL: - case APUSHFL: - deltasp += 4; - p->spadj = 4; - continue; - case APUSHQ: - case APUSHFQ: - deltasp += 8; - p->spadj = 8; - continue; - case APUSHW: - case APUSHFW: - deltasp += 2; - p->spadj = 2; - continue; - case APOPL: - case APOPFL: - deltasp -= 4; - p->spadj = -4; - continue; - case APOPQ: - case APOPFQ: - deltasp -= 8; - p->spadj = -8; - continue; - case APOPW: - case APOPFW: - deltasp -= 2; - p->spadj = -2; - continue; - case ARET: - break; - } - - if(autoffset != deltasp) - diag("unbalanced PUSH/POP"); - - if(cursym->text->from.scale & WRAPPER) { - p = load_g_cx(p); - p = appendp(p); - // g->panicwrap -= autoffset + PtrSize; - p->as = ASUBL; - p->from.type = D_CONST; - p->from.offset = autoffset + PtrSize; - p->to.type = D_INDIR+D_CX; - p->to.offset = 2*PtrSize; - p = appendp(p); - p->as = ARET; - } - - if(autoffset) { - p->as = AADJSP; - p->from.type = D_CONST; - p->from.offset = -autoffset; - p->spadj = -autoffset; - p = appendp(p); - p->as = ARET; - // If there are instructions following - // this ARET, they come from a branch - // with the same stackframe, so undo - // the cleanup. - p->spadj = +autoffset; - } - if(p->to.sym) // retjmp - p->as = AJMP; - } - } -} - -// Append code to p to load g into cx. -// Overwrites p with the first instruction (no first appendp). -// Overwriting p is unusual but it lets use this in both the -// prologue (caller must call appendp first) and in the epilogue. -// Returns last new instruction. -static Prog* -load_g_cx(Prog *p) -{ - if(flag_shared) { - // Load TLS offset with MOVQ $runtime.tlsgm(SB), CX - p->as = AMOVQ; - p->from.type = D_EXTERN; - p->from.sym = gmsym; - p->to.type = D_CX; - p = appendp(p); - } - p->as = AMOVQ; - if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd - || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd - || HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) - // ELF uses FS - p->from.type = D_INDIR+D_FS; - else - p->from.type = D_INDIR+D_GS; - if(flag_shared) { - // Add TLS offset stored in CX - p->from.index = p->from.type - D_INDIR; - p->from.type = D_INDIR + D_CX; - } - p->from.offset = tlsoffset+0; - p->to.type = D_CX; - if(HEADTYPE == Hwindows) { - // movq %gs:0x28, %rcx - // movq (%rcx), %rcx - p->as = AMOVQ; - p->from.type = D_INDIR+D_GS; - p->from.offset = 0x28; - p->to.type = D_CX; - - p = appendp(p); - p->as = AMOVQ; - p->from.type = D_INDIR+D_CX; - p->from.offset = 0; - p->to.type = D_CX; - } - return p; -} - -// Append code to p to check for stack split. -// Appends to (does not overwrite) p. -// Assumes g is in CX. -// Returns last new instruction. -// On return, *jmpok is the instruction that should jump -// to the stack frame allocation if no split is needed. -static Prog* -stacksplit(Prog *p, int32 framesize, Prog **jmpok) -{ - Prog *q, *q1; - uint32 moreconst1, moreconst2, i; - - if(debug['K']) { - // 6l -K means check not only for stack - // overflow but stack underflow. - // On underflow, INT 3 (breakpoint). - // Underflow itself is rare but this also - // catches out-of-sync stack guard info - - p = appendp(p); - p->as = ACMPQ; - p->from.type = D_INDIR+D_CX; - p->from.offset = 8; - p->to.type = D_SP; - - p = appendp(p); - p->as = AJHI; - p->to.type = D_BRANCH; - p->to.offset = 4; - q1 = p; - - p = appendp(p); - p->as = AINT; - p->from.type = D_CONST; - p->from.offset = 3; - - p = appendp(p); - p->as = ANOP; - q1->pcond = p; - } - - q = P; - q1 = P; - if(framesize <= StackSmall) { - // small stack: SP <= stackguard - // CMPQ SP, stackguard - p = appendp(p); - p->as = ACMPQ; - p->from.type = D_SP; - p->to.type = D_INDIR+D_CX; - } else if(framesize <= StackBig) { - // large stack: SP-framesize <= stackguard-StackSmall - // LEAQ -xxx(SP), AX - // CMPQ AX, stackguard - p = appendp(p); - p->as = ALEAQ; - p->from.type = D_INDIR+D_SP; - p->from.offset = -(framesize-StackSmall); - p->to.type = D_AX; - - p = appendp(p); - p->as = ACMPQ; - p->from.type = D_AX; - p->to.type = D_INDIR+D_CX; - } else { - // Such a large stack we need to protect against wraparound. - // If SP is close to zero: - // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) - // The +StackGuard on both sides is required to keep the left side positive: - // SP is allowed to be slightly below stackguard. See stack.h. - // - // Preemption sets stackguard to StackPreempt, a very large value. - // That breaks the math above, so we have to check for that explicitly. - // MOVQ stackguard, CX - // CMPQ CX, $StackPreempt - // JEQ label-of-call-to-morestack - // LEAQ StackGuard(SP), AX - // SUBQ CX, AX - // CMPQ AX, $(framesize+(StackGuard-StackSmall)) - - p = appendp(p); - p->as = AMOVQ; - p->from.type = D_INDIR+D_CX; - p->from.offset = 0; - p->to.type = D_SI; - - p = appendp(p); - p->as = ACMPQ; - p->from.type = D_SI; - p->to.type = D_CONST; - p->to.offset = StackPreempt; - - p = appendp(p); - p->as = AJEQ; - p->to.type = D_BRANCH; - q1 = p; - - p = appendp(p); - p->as = ALEAQ; - p->from.type = D_INDIR+D_SP; - p->from.offset = StackGuard; - p->to.type = D_AX; - - p = appendp(p); - p->as = ASUBQ; - p->from.type = D_SI; - p->to.type = D_AX; - - p = appendp(p); - p->as = ACMPQ; - p->from.type = D_AX; - p->to.type = D_CONST; - p->to.offset = framesize+(StackGuard-StackSmall); - } - - // common - p = appendp(p); - p->as = AJHI; - p->to.type = D_BRANCH; - q = p; - - // If we ask for more stack, we'll get a minimum of StackMin bytes. - // We need a stack frame large enough to hold the top-of-stack data, - // the function arguments+results, our caller's PC, our frame, - // a word for the return PC of the next call, and then the StackLimit bytes - // that must be available on entry to any function called from a function - // that did a stack check. If StackMin is enough, don't ask for a specific - // amount: then we can use the custom functions and save a few - // instructions. - moreconst1 = 0; - if(StackTop + textarg + PtrSize + framesize + PtrSize + StackLimit >= StackMin) - moreconst1 = framesize; - moreconst2 = textarg; - if(moreconst2 == 1) // special marker - moreconst2 = 0; - if((moreconst2&7) != 0) - diag("misaligned argument size in stack split"); - // 4 varieties varieties (const1==0 cross const2==0) - // and 6 subvarieties of (const1==0 and const2!=0) - p = appendp(p); - if(moreconst1 == 0 && moreconst2 == 0) { - p->as = ACALL; - p->to.type = D_BRANCH; - p->pcond = pmorestack[0]; - p->to.sym = symmorestack[0]; - } else - if(moreconst1 != 0 && moreconst2 == 0) { - p->as = AMOVL; - p->from.type = D_CONST; - p->from.offset = moreconst1; - p->to.type = D_AX; - - p = appendp(p); - p->as = ACALL; - p->to.type = D_BRANCH; - p->pcond = pmorestack[1]; - p->to.sym = symmorestack[1]; - } else - if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { - i = moreconst2/8 + 3; - p->as = ACALL; - p->to.type = D_BRANCH; - p->pcond = pmorestack[i]; - p->to.sym = symmorestack[i]; - } else - if(moreconst1 == 0 && moreconst2 != 0) { - p->as = AMOVL; - p->from.type = D_CONST; - p->from.offset = moreconst2; - p->to.type = D_AX; - - p = appendp(p); - p->as = ACALL; - p->to.type = D_BRANCH; - p->pcond = pmorestack[2]; - p->to.sym = symmorestack[2]; - } else { - p->as = AMOVQ; - p->from.type = D_CONST; - p->from.offset = (uint64)moreconst2 << 32; - p->from.offset |= moreconst1; - p->to.type = D_AX; - - p = appendp(p); - p->as = ACALL; - p->to.type = D_BRANCH; - p->pcond = pmorestack[3]; - p->to.sym = symmorestack[3]; - } - - p = appendp(p); - p->as = AJMP; - p->to.type = D_BRANCH; - p->pcond = cursym->text->link; - - if(q != P) - q->pcond = p->link; - if(q1 != P) - q1->pcond = q->link; - - *jmpok = q; - return p; -} - -vlong -atolwhex(char *s) -{ - vlong 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; -} diff --git a/src/cmd/6l/prof.c b/src/cmd/6l/prof.c deleted file mode 100644 index 862ce080c..000000000 --- a/src/cmd/6l/prof.c +++ /dev/null @@ -1,171 +0,0 @@ -// Inferno utils/6l/obj.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/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. - -// Profiling. - -#include "l.h" -#include "../ld/lib.h" - -void -doprof1(void) -{ -#ifdef NOTDEF - Sym *s; - int32 n; - Prog *p, *q; - - if(debug['v']) - Bprint(&bso, "%5.2f profile 1\n", cputime()); - Bflush(&bso); - s = lookup("__mcount", 0); - n = 1; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - p = cursym->text; - 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; - } - 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->size = n*4; -#endif -} - -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(cursym = textp; cursym != nil; cursym = cursym->next) { - p = cursym->text; - if(p->from.sym == s2) { - p->from.scale = 1; - ps2 = p; - } - if(p->from.sym == s4) { - p->from.scale = 1; - ps4 = p; - } - } - for(cursym = textp; cursym != nil; cursym = cursym->next) { - p = cursym->text; - - if(p->from.scale & NOPROF) /* dont profile */ - 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; - - for(; p; p=p->link) { - 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; - } - } - } -} diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c deleted file mode 100644 index 74f11d635..000000000 --- a/src/cmd/6l/span.c +++ /dev/null @@ -1,1846 +0,0 @@ -// Inferno utils/6l/span.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/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. - -// Instruction layout. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" - -static int rexflag; -static int asmode; -static vlong vaddr(Adr*, Reloc*); - -// single-instruction no-ops of various lengths. -// constructed by hand and disassembled with gdb to verify. -// see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion. -static uchar nop[][16] = { - {0x90}, - {0x66, 0x90}, - {0x0F, 0x1F, 0x00}, - {0x0F, 0x1F, 0x40, 0x00}, - {0x0F, 0x1F, 0x44, 0x00, 0x00}, - {0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00}, - {0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00}, - {0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, -}; - -static void -fillnop(uchar *p, int n) -{ - int m; - - while(n > 0) { - m = n; - if(m > nelem(nop)) - m = nelem(nop); - memmove(p, nop[m-1], m); - p += m; - n -= m; - } -} - -void -span1(Sym *s) -{ - Prog *p, *q; - int32 c, v, loop; - uchar *bp; - int n, m, i; - - cursym = s; - - if(s->p != nil) - return; - - for(p = s->text; p != P; p = p->link) { - p->back = 2; // use short branches first time through - if((q = p->pcond) != P && (q->back & 2)) { - p->back |= 1; // backward jump - q->back |= 4; // loop head - } - - if(p->as == AADJSP) { - p->to.type = D_SP; - v = -p->from.offset; - p->from.offset = v; - p->as = p->mode != 64? AADDL: AADDQ; - if(v < 0) { - p->as = p->mode != 64? ASUBL: ASUBQ; - v = -v; - p->from.offset = v; - } - if(v == 0) - p->as = ANOP; - } - } - - n = 0; - do { - loop = 0; - memset(s->r, 0, s->nr*sizeof s->r[0]); - s->nr = 0; - s->np = 0; - c = 0; - for(p = s->text; p != P; p = p->link) { - if((p->back & 4) && (c&(LoopAlign-1)) != 0) { - // pad with NOPs - v = -c&(LoopAlign-1); - if(v <= MaxLoopPad) { - symgrow(s, c+v); - fillnop(s->p+c, v); - c += v; - } - } - - p->pc = c; - - // process forward jumps to p - for(q = p->comefrom; q != P; q = q->forwd) { - v = p->pc - (q->pc + q->mark); - if(q->back & 2) { // short - if(v > 127) { - loop++; - q->back ^= 2; - } - if(q->as == AJCXZL) - s->p[q->pc+2] = v; - else - s->p[q->pc+1] = v; - } else { - bp = s->p + q->pc + q->mark - 4; - *bp++ = v; - *bp++ = v>>8; - *bp++ = v>>16; - *bp = v>>24; - } - } - p->comefrom = P; - - asmins(p); - p->pc = c; - m = andptr-and; - symgrow(s, p->pc+m); - memmove(s->p+p->pc, and, m); - p->mark = m; - c += m; - } - if(++n > 20) { - diag("span must be looping"); - errorexit(); - } - } while(loop); - s->size = c; - - if(debug['a'] > 1) { - print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0); - for(i=0; i<s->np; i++) { - print(" %.2ux", s->p[i]); - if(i%16 == 15) - print("\n %.6ux", i+1); - } - if(i%16) - print("\n"); - - for(i=0; i<s->nr; i++) { - Reloc *r; - - r = &s->r[i]; - print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add); - } - } -} - -void -span(void) -{ - Prog *p, *q; - int32 v; - int n; - - if(debug['v']) - Bprint(&bso, "%5.2f span\n", cputime()); - - // NOTE(rsc): If we get rid of the globals we should - // be able to parallelize these iterations. - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(cursym->p != nil) - continue; - // TODO: move into span1 - for(p = cursym->text; p != P; p = p->link) { - 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 = p->mode != 64? AADDL: AADDQ; - if(v < 0) { - p->as = p->mode != 64? ASUBL: ASUBQ; - v = -v; - p->from.offset = v; - } - if(v == 0) - p->as = ANOP; - } - } - span1(cursym); - } -} - -void -xdefine(char *p, int t, vlong v) -{ - Sym *s; - - s = lookup(p, 0); - s->type = t; - s->value = v; - s->reachable = 1; - s->special = 1; -} - -void -instinit(void) -{ - int c, i; - - for(i=1; optab[i].as; i++) { - c = optab[i].as; - if(opindex[c] != nil) { - diag("phase error in optab: %d (%A)", i, c); - errorexit(); - } - opindex[c] = &optab[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 + Ys32] = 1; - ycover[Yi1*Ymax + Ys32] = 1; - ycover[Yi8*Ymax + Ys32] = 1; - - ycover[Yi0*Ymax + Yi32] = 1; - ycover[Yi1*Ymax + Yi32] = 1; - ycover[Yi8*Ymax + Yi32] = 1; - ycover[Ys32*Ymax + Yi32] = 1; - - ycover[Yi0*Ymax + Yi64] = 1; - ycover[Yi1*Ymax + Yi64] = 1; - ycover[Yi8*Ymax + Yi64] = 1; - ycover[Ys32*Ymax + Yi64] = 1; - ycover[Yi32*Ymax + Yi64] = 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[Yrl*Ymax + Yrb] = 1; - - ycover[Ycl*Ymax + Ycx] = 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[Yrl*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; - - ycover[Yax*Ymax + Ymm] = 1; - ycover[Ycx*Ymax + Ymm] = 1; - ycover[Yrx*Ymax + Ymm] = 1; - ycover[Yrl*Ymax + Ymm] = 1; - ycover[Ym*Ymax + Ymm] = 1; - ycover[Ymr*Ymax + Ymm] = 1; - - ycover[Ym*Ymax + Yxm] = 1; - ycover[Yxr*Ymax + Yxm] = 1; - - for(i=0; i<D_NONE; i++) { - reg[i] = -1; - if(i >= D_AL && i <= D_R15B) { - reg[i] = (i-D_AL) & 7; - if(i >= D_SPB && i <= D_DIB) - regrex[i] = 0x40; - if(i >= D_R8B && i <= D_R15B) - regrex[i] = Rxr | Rxx | Rxb; - } - if(i >= D_AH && i<= D_BH) - reg[i] = 4 + ((i-D_AH) & 7); - if(i >= D_AX && i <= D_R15) { - reg[i] = (i-D_AX) & 7; - if(i >= D_R8) - regrex[i] = Rxr | Rxx | Rxb; - } - if(i >= D_F0 && i <= D_F0+7) - reg[i] = (i-D_F0) & 7; - if(i >= D_M0 && i <= D_M0+7) - reg[i] = (i-D_M0) & 7; - if(i >= D_X0 && i <= D_X0+15) { - reg[i] = (i-D_X0) & 7; - if(i >= D_X0+8) - regrex[i] = Rxr | Rxx | Rxb; - } - if(i >= D_CR+8 && i <= D_CR+15) - regrex[i] = Rxr; - } -} - -int -prefixof(Adr *a) -{ - switch(a->type) { - case D_INDIR+D_CS: - return 0x2e; - case D_INDIR+D_DS: - return 0x3e; - case D_INDIR+D_ES: - return 0x26; - case D_INDIR+D_FS: - return 0x64; - case D_INDIR+D_GS: - return 0x65; - } - switch(a->index) { - case D_CS: - return 0x2e; - case D_DS: - return 0x3e; - case D_ES: - return 0x26; - case D_FS: - return 0x64; - case D_GS: - return 0x65; - } - return 0; -} - -int -oclass(Adr *a) -{ - vlong v; - int32 l; - - 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: - if(flag_shared) - return Yiauto; - else - return Yi32; /* TO DO: Yi64 */ - 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_SPB: -*/ - case D_BPB: - case D_SIB: - case D_DIB: - case D_R8B: - case D_R9B: - case D_R10B: - case D_R11B: - case D_R12B: - case D_R13B: - case D_R14B: - case D_R15B: - if(asmode != 64) - return Yxxx; - case D_DL: - case D_BL: - case D_AH: - case D_CH: - case D_DH: - case D_BH: - return Yrb; - - case D_CL: - return Ycl; - - case D_CX: - return Ycx; - - case D_DX: - case D_BX: - return Yrx; - - case D_R8: /* not really Yrl */ - case D_R9: - case D_R10: - case D_R11: - case D_R12: - case D_R13: - case D_R14: - case D_R15: - if(asmode != 64) - return Yxxx; - 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_M0+0: - case D_M0+1: - case D_M0+2: - case D_M0+3: - case D_M0+4: - case D_M0+5: - case D_M0+6: - case D_M0+7: - return Ymr; - - case D_X0+0: - case D_X0+1: - case D_X0+2: - case D_X0+3: - case D_X0+4: - case D_X0+5: - case D_X0+6: - case D_X0+7: - case D_X0+8: - case D_X0+9: - case D_X0+10: - case D_X0+11: - case D_X0+12: - case D_X0+13: - case D_X0+14: - case D_X0+15: - return Yxr; - - 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_CR+8: return Ycr8; - - 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; - l = v; - if((vlong)l == v) - return Ys32; /* can sign extend */ - if((v>>32) == 0) - return Yi32; /* unsigned */ - return Yi64; - } - return Yi32; /* TO DO: D_ADDR as Yi64 */ - - case D_BRANCH: - return Ybr; - } - return Yxxx; -} - -void -asmidx(int scale, int index, int base) -{ - int i; - - switch(index) { - default: - goto bad; - - case D_NONE: - i = 4 << 3; - goto bas; - - case D_R8: - case D_R9: - case D_R10: - case D_R11: - case D_R12: - case D_R13: - case D_R14: - case D_R15: - if(asmode != 64) - goto bad; - case D_AX: - case D_CX: - case D_DX: - case D_BX: - case D_BP: - case D_SI: - case D_DI: - i = reg[index] << 3; - break; - } - switch(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_R8: - case D_R9: - case D_R10: - case D_R11: - case D_R12: - case D_R13: - case D_R14: - case D_R15: - if(asmode != 64) - goto bad; - 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/%d/%d", scale, index, base); - *andptr++ = 0; - return; -} - -static void -put4(int32 v) -{ - andptr[0] = v; - andptr[1] = v>>8; - andptr[2] = v>>16; - andptr[3] = v>>24; - andptr += 4; -} - -static void -relput4(Prog *p, Adr *a) -{ - vlong v; - Reloc rel, *r; - - v = vaddr(a, &rel); - if(rel.siz != 0) { - if(rel.siz != 4) - diag("bad reloc"); - r = addrel(cursym); - *r = rel; - r->off = p->pc + andptr - and; - } - put4(v); -} - -static void -put8(vlong v) -{ - andptr[0] = v; - andptr[1] = v>>8; - andptr[2] = v>>16; - andptr[3] = v>>24; - andptr[4] = v>>32; - andptr[5] = v>>40; - andptr[6] = v>>48; - andptr[7] = v>>56; - andptr += 8; -} - -/* -static void -relput8(Prog *p, Adr *a) -{ - vlong v; - Reloc rel, *r; - - v = vaddr(a, &rel); - if(rel.siz != 0) { - r = addrel(cursym); - *r = rel; - r->siz = 8; - r->off = p->pc + andptr - and; - } - put8(v); -} -*/ - -vlong -symaddr(Sym *s) -{ - if(!s->reachable) - diag("unreachable symbol in symaddr - %s", s->name); - return s->value; -} - -static vlong -vaddr(Adr *a, Reloc *r) -{ - int t; - vlong v; - Sym *s; - - if(r != nil) - memset(r, 0, sizeof *r); - - 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->reachable) - diag("unreachable symbol in vaddr - %s", s->name); - if(r == nil) { - diag("need reloc for %D", a); - errorexit(); - } - r->siz = 4; // TODO: 8 for external symbols - r->off = -1; // caller must fill in - r->sym = s; - r->add = v; - v = 0; - if(flag_shared) { - if(s->type == STLSBSS) { - r->xadd = r->add - r->siz; - r->type = D_TLS; - r->xsym = s; - } else - r->type = D_PCREL; - } else - r->type = D_ADDR; - } - return v; -} - -static void -asmandsz(Adr *a, int r, int rex, int m64) -{ - int32 v; - int t, scale; - Reloc rel; - - USED(m64); - rex &= (0x40 | Rxr); - v = a->offset; - t = a->type; - rel.siz = 0; - if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) { - if(t < D_INDIR) { - switch(t) { - default: - goto bad; - case D_STATIC: - case D_EXTERN: - if(flag_shared) - goto bad; - t = D_NONE; - v = vaddr(a, &rel); - break; - case D_AUTO: - case D_PARAM: - t = D_SP; - break; - } - } else - t -= D_INDIR; - rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex; - if(t == D_NONE) { - *andptr++ = (0 << 6) | (4 << 0) | (r << 3); - asmidx(a->scale, a->index, t); - goto putrelv; - } - if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) { - *andptr++ = (0 << 6) | (4 << 0) | (r << 3); - asmidx(a->scale, a->index, t); - return; - } - if(v >= -128 && v < 128 && rel.siz == 0) { - *andptr++ = (1 << 6) | (4 << 0) | (r << 3); - asmidx(a->scale, a->index, t); - *andptr++ = v; - return; - } - *andptr++ = (2 << 6) | (4 << 0) | (r << 3); - asmidx(a->scale, a->index, t); - goto putrelv; - } - if(t >= D_AL && t <= D_X0+15) { - if(v) - goto bad; - *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); - rexflag |= (regrex[t] & (0x40 | Rxb)) | rex; - return; - } - - scale = a->scale; - if(t < D_INDIR) { - switch(a->type) { - default: - goto bad; - case D_STATIC: - case D_EXTERN: - t = D_NONE; - v = vaddr(a, &rel); - break; - case D_AUTO: - case D_PARAM: - t = D_SP; - break; - } - scale = 1; - } else - t -= D_INDIR; - - rexflag |= (regrex[t] & Rxb) | rex; - if(t == D_NONE || (D_CS <= t && t <= D_GS)) { - if(flag_shared && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || asmode != 64) { - *andptr++ = (0 << 6) | (5 << 0) | (r << 3); - goto putrelv; - } - /* temporary */ - *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */ - *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */ - goto putrelv; - } - if(t == D_SP || t == D_R12) { - if(v == 0) { - *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); - asmidx(scale, D_NONE, t); - return; - } - if(v >= -128 && v < 128) { - *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3); - asmidx(scale, D_NONE, t); - *andptr++ = v; - return; - } - *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); - asmidx(scale, D_NONE, t); - goto putrelv; - } - if(t >= D_AX && t <= D_R15) { - if(v == 0 && t != D_BP && t != D_R13) { - *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); - goto putrelv; - } - goto bad; - -putrelv: - if(rel.siz != 0) { - Reloc *r; - - if(rel.siz != 4) { - diag("bad rel"); - goto bad; - } - r = addrel(cursym); - *r = rel; - r->off = curp->pc + andptr - and; - } else if(iself && linkmode == LinkExternal && a->type == D_INDIR+D_FS - && HEADTYPE != Hopenbsd) { - Reloc *r; - Sym *s; - - r = addrel(cursym); - r->off = curp->pc + andptr - and; - r->add = a->offset-tlsoffset; - r->xadd = r->add; - r->siz = 4; - r->type = D_TLS; - s = lookup("runtime.tlsgm", 0); - r->sym = s; - r->xsym = s; - v = 0; - } - - put4(v); - return; - -bad: - diag("asmand: bad address %D", a); - return; -} - -void -asmand(Adr *a, Adr *ra) -{ - asmandsz(a, reg[ra->type], regrex[ra->type], 0); -} - -void -asmando(Adr *a, int o) -{ - asmandsz(a, o, 0, 0); -} - -static void -bytereg(Adr *a, char *t) -{ - if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) { - a->type = D_AL + (a->type-D_AX); - *t = 0; - } -} - -#define E 0xff -Movtab 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}, - {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0}, - {APUSHQ, 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}, - {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0}, - {APOPQ, 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, Ycr8, Yml, 3, 0x0f,0x20,8,0}, - {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0}, - {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0}, - {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0}, - {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0}, - {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,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}, - {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0}, - {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0}, - {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0}, - {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0}, - {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0}, - {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,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}, - {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0}, - {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0}, - {AMOVQ, 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}, - {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0}, - {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0}, - {AMOVQ, 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}, - {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0}, - {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0}, - {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0}, - {AMOVQ, 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}, - {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0}, - {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0}, - {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0}, - {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,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); -} - -static int -mediaop(Optab *o, int op, int osize, int z) -{ - switch(op){ - case Pm: - case Pe: - case Pf2: - case Pf3: - if(osize != 1){ - if(op != Pm) - *andptr++ = op; - *andptr++ = Pm; - op = o->op[++z]; - break; - } - default: - if(andptr == and || andptr[-1] != Pm) - *andptr++ = Pm; - break; - } - *andptr++ = op; - return z; -} - -void -doasm(Prog *p) -{ - Optab *o; - Prog *q, pp; - uchar *t; - Movtab *mo; - int z, op, ft, tt, xo, l, pre; - vlong v; - Reloc rel, *r; - Adr *a; - - curp = p; // TODO - - o = opindex[p->as]; - if(o == nil) { - diag("asmins: missing op %P", p); - return; - } - - pre = prefixof(&p->from); - if(pre) - *andptr++ = pre; - pre = prefixof(&p->to); - if(pre) - *andptr++ = pre; - - if(p->ft == 0) - p->ft = oclass(&p->from); - if(p->tt == 0) - p->tt = oclass(&p->to); - - ft = p->ft * Ymax; - tt = p->tt * Ymax; - - t = o->ytab; - if(t == 0) { - diag("asmins: noproto %P", p); - return; - } - xo = o->op[0] == 0x0f; - for(z=0; *t; z+=t[3]+xo,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 Pq3: /* 16 bit escape, Rex.w, and opcode escape */ - *andptr++ = Pe; - *andptr++ = Pw; - *andptr++ = Pm; - break; - - case Pf2: /* xmm opcode escape */ - case Pf3: - *andptr++ = o->prefix; - *andptr++ = Pm; - break; - - case Pm: /* opcode escape */ - *andptr++ = Pm; - break; - - case Pe: /* 16 bit escape */ - *andptr++ = Pe; - break; - - case Pw: /* 64-bit escape */ - if(p->mode != 64) - diag("asmins: illegal 64: %P", p); - rexflag |= Pw; - break; - - case Pb: /* botch */ - bytereg(&p->from, &p->ft); - bytereg(&p->to, &p->tt); - break; - - case P32: /* 32 bit but illegal if 64-bit mode */ - if(p->mode == 64) - diag("asmins: illegal in 64-bit mode: %P", p); - break; - - case Py: /* 64-bit only, no prefix */ - if(p->mode != 64) - diag("asmins: illegal in %d-bit mode: %P", p->mode, p); - break; - } - - if(z >= nelem(o->op)) - sysfatal("asmins bad table %P", p); - op = o->op[z]; - if(op == 0x0f) { - *andptr++ = op; - 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 Zlitm_r: - for(; op = o->op[z]; z++) - *andptr++ = op; - asmand(&p->from, &p->to); - break; - - case Zmb_r: - bytereg(&p->from, &p->ft); - /* fall through */ - case Zm_r: - *andptr++ = op; - asmand(&p->from, &p->to); - break; - case Zm2_r: - *andptr++ = op; - *andptr++ = o->op[z+1]; - asmand(&p->from, &p->to); - break; - - case Zm_r_xm: - mediaop(o, op, t[3], z); - asmand(&p->from, &p->to); - break; - - case Zm_r_xm_nr: - rexflag = 0; - mediaop(o, op, t[3], z); - asmand(&p->from, &p->to); - break; - - case Zm_r_i_xm: - mediaop(o, op, t[3], z); - asmand(&p->from, &p->to); - *andptr++ = p->to.offset; - break; - - case Zm_r_3d: - *andptr++ = 0x0f; - *andptr++ = 0x0f; - asmand(&p->from, &p->to); - *andptr++ = op; - break; - - case Zibm_r: - while ((op = o->op[z++]) != 0) - *andptr++ = op; - asmand(&p->from, &p->to); - *andptr++ = p->to.offset; - 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, &p->to); - p->from.index = p->from.type; - p->from.type = D_ADDR; - break; - - case Zm_o: - *andptr++ = op; - asmando(&p->from, o->op[z+1]); - break; - - case Zr_m: - *andptr++ = op; - asmand(&p->to, &p->from); - break; - - case Zr_m_xm: - mediaop(o, op, t[3], z); - asmand(&p->to, &p->from); - break; - - case Zr_m_xm_nr: - rexflag = 0; - mediaop(o, op, t[3], z); - asmand(&p->to, &p->from); - break; - - case Zr_m_i_xm: - mediaop(o, op, t[3], z); - asmand(&p->to, &p->from); - *andptr++ = p->from.offset; - break; - - case Zo_m: - *andptr++ = op; - asmando(&p->to, o->op[z+1]); - break; - - case Zo_m64: - *andptr++ = op; - asmandsz(&p->to, o->op[z+1], 0, 1); - break; - - case Zm_ibo: - *andptr++ = op; - asmando(&p->from, o->op[z+1]); - *andptr++ = vaddr(&p->to, nil); - break; - - case Zibo_m: - *andptr++ = op; - asmando(&p->to, o->op[z+1]); - *andptr++ = vaddr(&p->from, nil); - break; - - case Zibo_m_xm: - z = mediaop(o, op, t[3], z); - asmando(&p->to, o->op[z+1]); - *andptr++ = vaddr(&p->from, nil); - break; - - case Z_ib: - case Zib_: - if(t[2] == Zib_) - a = &p->from; - else - a = &p->to; - *andptr++ = op; - *andptr++ = vaddr(a, nil); - break; - - case Zib_rp: - rexflag |= regrex[p->to.type] & (Rxb|0x40); - *andptr++ = op + reg[p->to.type]; - *andptr++ = vaddr(&p->from, nil); - break; - - case Zil_rp: - rexflag |= regrex[p->to.type] & Rxb; - *andptr++ = op + reg[p->to.type]; - if(o->prefix == Pe) { - v = vaddr(&p->from, nil); - *andptr++ = v; - *andptr++ = v>>8; - } - else - relput4(p, &p->from); - break; - - case Zo_iw: - *andptr++ = op; - if(p->from.type != D_NONE){ - v = vaddr(&p->from, nil); - *andptr++ = v; - *andptr++ = v>>8; - } - break; - - case Ziq_rp: - v = vaddr(&p->from, &rel); - l = v>>32; - if(l == 0 && rel.siz != 8){ - //p->mark |= 0100; - //print("zero: %llux %P\n", v, p); - rexflag &= ~(0x40|Rxw); - rexflag |= regrex[p->to.type] & Rxb; - *andptr++ = 0xb8 + reg[p->to.type]; - if(rel.type != 0) { - r = addrel(cursym); - *r = rel; - r->off = p->pc + andptr - and; - } - put4(v); - }else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */ - //p->mark |= 0100; - //print("sign: %llux %P\n", v, p); - *andptr ++ = 0xc7; - asmando(&p->to, 0); - put4(v); - }else{ /* need all 8 */ - //print("all: %llux %P\n", v, p); - rexflag |= regrex[p->to.type] & Rxb; - *andptr++ = op + reg[p->to.type]; - if(rel.type != 0) { - r = addrel(cursym); - *r = rel; - r->off = p->pc + andptr - and; - } - put8(v); - } - break; - - case Zib_rr: - *andptr++ = op; - asmand(&p->to, &p->to); - *andptr++ = vaddr(&p->from, nil); - break; - - case Z_il: - case Zil_: - if(t[2] == Zil_) - a = &p->from; - else - a = &p->to; - *andptr++ = op; - if(o->prefix == Pe) { - v = vaddr(a, nil); - *andptr++ = v; - *andptr++ = v>>8; - } - else - relput4(p, a); - break; - - case Zm_ilo: - case Zilo_m: - *andptr++ = op; - if(t[2] == Zilo_m) { - a = &p->from; - asmando(&p->to, o->op[z+1]); - } else { - a = &p->to; - asmando(&p->from, o->op[z+1]); - } - if(o->prefix == Pe) { - v = vaddr(a, nil); - *andptr++ = v; - *andptr++ = v>>8; - } - else - relput4(p, a); - break; - - case Zil_rr: - *andptr++ = op; - asmand(&p->to, &p->to); - if(o->prefix == Pe) { - v = vaddr(&p->from, nil); - *andptr++ = v; - *andptr++ = v>>8; - } - else - relput4(p, &p->from); - break; - - case Z_rp: - rexflag |= regrex[p->to.type] & (Rxb|0x40); - *andptr++ = op + reg[p->to.type]; - break; - - case Zrp_: - rexflag |= regrex[p->from.type] & (Rxb|0x40); - *andptr++ = op + reg[p->from.type]; - break; - - case Zclr: - *andptr++ = op; - asmand(&p->to, &p->to); - break; - - case Zcall: - q = p->pcond; - if(q == nil) { - diag("call without target"); - errorexit(); - } - if(q->as != ATEXT) { - // Could handle this case by making D_PCREL - // record the Prog* instead of the Sym*, but let's - // wait until the need arises. - diag("call of non-TEXT %P", q); - errorexit(); - } - *andptr++ = op; - r = addrel(cursym); - r->off = p->pc + andptr - and; - r->sym = q->from.sym; - r->type = D_PCREL; - r->siz = 4; - put4(0); - break; - - case Zbr: - case Zjmp: - case Zloop: - // TODO: jump across functions needs reloc - q = p->pcond; - if(q == nil) { - diag("jmp/branch/loop without target"); - errorexit(); - } - if(q->as == ATEXT) { - if(t[2] == Zbr) { - diag("branch to ATEXT"); - errorexit(); - } - *andptr++ = o->op[z+1]; - r = addrel(cursym); - r->off = p->pc + andptr - and; - r->sym = q->from.sym; - r->type = D_PCREL; - r->siz = 4; - put4(0); - break; - } - // Assumes q is in this function. - // TODO: Check in input, preserve in brchain. - - // Fill in backward jump now. - if(p->back & 1) { - v = q->pc - (p->pc + 2); - if(v >= -128) { - if(p->as == AJCXZL) - *andptr++ = 0x67; - *andptr++ = op; - *andptr++ = v; - } else if(t[2] == Zloop) { - diag("loop too far: %P", p); - } else { - v -= 5-2; - if(t[2] == Zbr) { - *andptr++ = 0x0f; - v--; - } - *andptr++ = o->op[z+1]; - *andptr++ = v; - *andptr++ = v>>8; - *andptr++ = v>>16; - *andptr++ = v>>24; - } - break; - } - - // Annotate target; will fill in later. - p->forwd = q->comefrom; - q->comefrom = p; - if(p->back & 2) { // short - if(p->as == AJCXZL) - *andptr++ = 0x67; - *andptr++ = op; - *andptr++ = 0; - } else if(t[2] == Zloop) { - diag("loop too far: %P", p); - } else { - if(t[2] == Zbr) - *andptr++ = 0x0f; - *andptr++ = o->op[z+1]; - *andptr++ = 0; - *andptr++ = 0; - *andptr++ = 0; - *andptr++ = 0; - } - break; - -/* - v = q->pc - p->pc - 2; - if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) { - *andptr++ = op; - *andptr++ = v; - } else { - v -= 5-2; - if(t[2] == Zbr) { - *andptr++ = 0x0f; - v--; - } - *andptr++ = o->op[z+1]; - *andptr++ = v; - *andptr++ = v>>8; - *andptr++ = v>>16; - *andptr++ = v>>24; - } -*/ - break; - - case Zbyte: - v = vaddr(&p->from, &rel); - if(rel.siz != 0) { - rel.siz = op; - r = addrel(cursym); - *r = rel; - r->off = p->pc + andptr - and; - } - *andptr++ = v; - if(op > 1) { - *andptr++ = v>>8; - if(op > 2) { - *andptr++ = v>>16; - *andptr++ = v>>24; - if(op > 4) { - *andptr++ = v>>32; - *andptr++ = v>>40; - *andptr++ = v>>48; - *andptr++ = v>>56; - } - } - } - break; - } - return; - -domov: - for(mo=ymovtab; mo->as; mo++) - if(p->as == mo->as) - if(ycover[ft+mo->ft]) - if(ycover[tt+mo->tt]){ - t = mo->op; - goto mfound; - } -bad: - if(p->mode != 64){ - /* - * 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) || p->to.type == D_NONE) { - // We certainly don't want to exchange - // with AX if the op is MUL or DIV. - *andptr++ = 0x87; /* xchg lhs,bx */ - asmando(&p->from, reg[D_BX]); - subreg(&pp, z, D_BX); - doasm(&pp); - *andptr++ = 0x87; /* xchg lhs,bx */ - asmando(&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 */ - asmando(&p->to, reg[D_BX]); - subreg(&pp, z, D_BX); - doasm(&pp); - *andptr++ = 0x87; /* xchg rhs,bx */ - asmando(&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 from=%ux to=%ux %P", p->from.type, p->to.type, p); - return; - -mfound: - switch(mo->code) { - default: - diag("asmins: unknown mov %d %P", mo->code, p); - break; - - case 0: /* lit */ - for(z=0; t[z]!=E; z++) - *andptr++ = t[z]; - break; - - case 1: /* r,m */ - *andptr++ = t[0]; - asmando(&p->to, t[1]); - break; - - case 2: /* m,r */ - *andptr++ = t[0]; - asmando(&p->from, t[1]); - break; - - case 3: /* r,m - 2op */ - *andptr++ = t[0]; - *andptr++ = t[1]; - asmando(&p->to, t[2]); - rexflag |= regrex[p->from.type] & (Rxr|0x40); - break; - - case 4: /* m,r - 2op */ - *andptr++ = t[0]; - *andptr++ = t[1]; - asmando(&p->from, t[2]); - rexflag |= regrex[p->to.type] & (Rxr|0x40); - break; - - case 5: /* load full pointer, trash heap */ - if(t[0]) - *andptr++ = t[0]; - 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, &p->to); - break; - - case 6: /* double shift */ - if(t[0] == Pw){ - if(p->mode != 64) - diag("asmins: illegal 64: %P", p); - rexflag |= Pw; - t++; - }else if(t[0] == Pe){ - *andptr++ = Pe; - t++; - } - z = p->from.type; - switch(z) { - default: - goto bad; - case D_CONST: - *andptr++ = 0x0f; - *andptr++ = t[0]; - asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0); - *andptr++ = p->from.offset; - break; - case D_CL: - case D_CX: - *andptr++ = 0x0f; - *andptr++ = t[1]; - asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0); - break; - } - break; - } -} - -void -asmins(Prog *p) -{ - int n, np, c; - Reloc *r; - - rexflag = 0; - andptr = and; - asmode = p->mode; - doasm(p); - if(rexflag){ - /* - * as befits the whole approach of the architecture, - * the rex prefix must appear before the first opcode byte - * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but - * before the 0f opcode escape!), or it might be ignored. - * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'. - */ - if(p->mode != 64) - diag("asmins: illegal in mode %d: %P", p->mode, p); - n = andptr - and; - for(np = 0; np < n; np++) { - c = and[np]; - if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26) - break; - } - memmove(and+np+1, and+np, n-np); - and[np] = 0x40 | rexflag; - andptr++; - } - n = andptr - and; - for(r=cursym->r+cursym->nr; r-- > cursym->r; ) { - if(r->off < p->pc) - break; - if(rexflag) - r->off++; - if(r->type == D_PCREL) - r->add -= p->pc + n - (r->off + r->siz); - } -} diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h index a28115eb4..8319482ca 100644 --- a/src/cmd/8l/8.out.h +++ b/src/cmd/8l/8.out.h @@ -677,15 +677,3 @@ enum * this is the ranlib header */ #define SYMDEF "__.GOSYMDEF" - -/* - * this is the simulated IEEE floating point - */ -typedef struct ieee Ieee; -struct ieee -{ - int32 l; /* contains ls-man 0xffffffff */ - int32 h; /* contains sign 0x80000000 - exp 0x7ff00000 - ms-man 0x000fffff */ -}; diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index 3be37ea22..46e8e47ec 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -43,46 +43,18 @@ char openbsddynld[] = "/usr/libexec/ld.so"; char netbsddynld[] = "/usr/libexec/ld.elf_so"; char dragonflydynld[] = "/usr/libexec/ld-elf.so.2"; -int32 -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; - if(s->type != STEXT) - diag("entry not text: %s", s->name); - return s->value; -} - -vlong -datoff(vlong addr) -{ - if(addr >= segdata.vaddr) - return addr - segdata.vaddr + segdata.fileoff; - if(addr >= segtext.vaddr) - return addr - segtext.vaddr + segtext.fileoff; - diag("datoff %#llx", addr); - return 0; -} - static int needlib(char *name) { char *p; - Sym *s; + LSym *s; if(*name == '\0') return 0; /* reuse hash code in symbol table */ p = smprint(".dynlib.%s", name); - s = lookup(p, 0); + s = linklookup(ctxt, p, 0); free(p); if(s->type == 0) { s->type = 100; // avoid SDATA, etc. @@ -93,11 +65,11 @@ needlib(char *name) int nelfsym = 1; -static void addpltsym(Sym*); -static void addgotsym(Sym*); +static void addpltsym(Link*, LSym*); +static void addgotsym(Link*, LSym*); void -adddynrela(Sym *rela, Sym *s, Reloc *r) +adddynrela(LSym *rela, LSym *s, Reloc *r) { USED(rela); USED(s); @@ -106,12 +78,12 @@ adddynrela(Sym *rela, Sym *s, Reloc *r) } void -adddynrel(Sym *s, Reloc *r) +adddynrel(LSym *s, Reloc *r) { - Sym *targ, *rel, *got; + LSym *targ, *rel, *got; targ = r->sym; - cursym = s; + ctxt->cursym = s; switch(r->type) { default: @@ -135,8 +107,8 @@ adddynrel(Sym *s, Reloc *r) r->type = D_PCREL; r->add += 4; if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add += targ->plt; } return; @@ -153,7 +125,7 @@ adddynrel(Sym *s, Reloc *r) r->type = D_GOTOFF; return; } - addgotsym(targ); + addgotsym(ctxt, targ); r->type = D_CONST; // write r->add during relocsym r->sym = S; r->add += targ->got; @@ -165,7 +137,7 @@ adddynrel(Sym *s, Reloc *r) case 256 + R_386_GOTPC: r->type = D_PCREL; - r->sym = lookup(".got", 0); + r->sym = linklookup(ctxt, ".got", 0); r->add += 4; return; @@ -183,8 +155,8 @@ adddynrel(Sym *s, Reloc *r) case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1: if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = targ->plt; r->type = D_PCREL; return; @@ -204,8 +176,8 @@ adddynrel(Sym *s, Reloc *r) r->type = D_PCREL; return; } - addgotsym(targ); - r->sym = lookup(".got", 0); + addgotsym(ctxt, targ); + r->sym = linklookup(ctxt, ".got", 0); r->add += targ->got; r->type = D_PCREL; return; @@ -217,8 +189,8 @@ adddynrel(Sym *s, Reloc *r) switch(r->type) { case D_PCREL: - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = targ->plt; return; @@ -226,10 +198,10 @@ adddynrel(Sym *s, Reloc *r) if(s->type != SDATA) break; if(iself) { - adddynsym(targ); - rel = lookup(".rel", 0); - addaddrplus(rel, s, r->off); - adduint32(rel, ELF32_R_INFO(targ->dynid, R_386_32)); + adddynsym(ctxt, targ); + rel = linklookup(ctxt, ".rel", 0); + addaddrplus(ctxt, rel, s, r->off); + adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_386_32)); r->type = D_CONST; // write r->add during relocsym r->sym = S; return; @@ -245,22 +217,22 @@ adddynrel(Sym *s, Reloc *r) // just in case the C code assigns to the variable, // and of course it only works for single pointers, // but we only need to support cgo and that's all it needs. - adddynsym(targ); - got = lookup(".got", 0); + adddynsym(ctxt, targ); + got = linklookup(ctxt, ".got", 0); s->type = got->type | SSUB; s->outer = got; s->sub = got->sub; got->sub = s; s->value = got->size; - adduint32(got, 0); - adduint32(lookup(".linkedit.got", 0), targ->dynid); + adduint32(ctxt, got, 0); + adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid); r->type = 256; // ignore during relocsym return; } break; } - cursym = s; + ctxt->cursym = s; diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); } @@ -304,7 +276,7 @@ int machoreloc1(Reloc *r, vlong sectoff) { uint32 v; - Sym *rs; + LSym *rs; rs = r->xsym; @@ -358,7 +330,7 @@ machoreloc1(Reloc *r, vlong sectoff) } int -archreloc(Reloc *r, Sym *s, vlong *val) +archreloc(Reloc *r, LSym *s, vlong *val) { USED(s); if(linkmode == LinkExternal) @@ -368,7 +340,7 @@ archreloc(Reloc *r, Sym *s, vlong *val) *val = r->add; return 0; case D_GOTOFF: - *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0)); + *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0)); return 0; } return -1; @@ -377,119 +349,119 @@ archreloc(Reloc *r, Sym *s, vlong *val) void elfsetupplt(void) { - Sym *plt, *got; + LSym *plt, *got; - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); if(plt->size == 0) { // pushl got+4 - adduint8(plt, 0xff); - adduint8(plt, 0x35); - addaddrplus(plt, got, 4); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x35); + addaddrplus(ctxt, plt, got, 4); // jmp *got+8 - adduint8(plt, 0xff); - adduint8(plt, 0x25); - addaddrplus(plt, got, 8); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x25); + addaddrplus(ctxt, plt, got, 8); // zero pad - adduint32(plt, 0); + adduint32(ctxt, plt, 0); // assume got->size == 0 too - addaddrplus(got, lookup(".dynamic", 0), 0); - adduint32(got, 0); - adduint32(got, 0); + addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0); + adduint32(ctxt, got, 0); + adduint32(ctxt, got, 0); } } static void -addpltsym(Sym *s) +addpltsym(Link *ctxt, LSym *s) { - Sym *plt, *got, *rel; + LSym *plt, *got, *rel; if(s->plt >= 0) return; - adddynsym(s); + adddynsym(ctxt, s); if(iself) { - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); - rel = lookup(".rel.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); + rel = linklookup(ctxt, ".rel.plt", 0); if(plt->size == 0) elfsetupplt(); // jmpq *got+size - adduint8(plt, 0xff); - adduint8(plt, 0x25); - addaddrplus(plt, got, got->size); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x25); + addaddrplus(ctxt, plt, got, got->size); // add to got: pointer to current pos in plt - addaddrplus(got, plt, plt->size); + addaddrplus(ctxt, got, plt, plt->size); // pushl $x - adduint8(plt, 0x68); - adduint32(plt, rel->size); + adduint8(ctxt, plt, 0x68); + adduint32(ctxt, plt, rel->size); // jmp .plt - adduint8(plt, 0xe9); - adduint32(plt, -(plt->size+4)); + adduint8(ctxt, plt, 0xe9); + adduint32(ctxt, plt, -(plt->size+4)); // rel - addaddrplus(rel, got, got->size-4); - adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT)); + addaddrplus(ctxt, rel, got, got->size-4); + adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT)); s->plt = plt->size - 16; } else if(HEADTYPE == Hdarwin) { // Same laziness as in 6l. - Sym *plt; + LSym *plt; - plt = lookup(".plt", 0); + plt = linklookup(ctxt, ".plt", 0); - addgotsym(s); + addgotsym(ctxt, s); - adduint32(lookup(".linkedit.plt", 0), s->dynid); + adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid); // jmpq *got+size(IP) s->plt = plt->size; - adduint8(plt, 0xff); - adduint8(plt, 0x25); - addaddrplus(plt, lookup(".got", 0), s->got); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x25); + addaddrplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got); } else { diag("addpltsym: unsupported binary format"); } } static void -addgotsym(Sym *s) +addgotsym(Link *ctxt, LSym *s) { - Sym *got, *rel; + LSym *got, *rel; if(s->got >= 0) return; - adddynsym(s); - got = lookup(".got", 0); + adddynsym(ctxt, s); + got = linklookup(ctxt, ".got", 0); s->got = got->size; - adduint32(got, 0); + adduint32(ctxt, got, 0); if(iself) { - rel = lookup(".rel", 0); - addaddrplus(rel, got, s->got); - adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT)); + rel = linklookup(ctxt, ".rel", 0); + addaddrplus(ctxt, rel, got, s->got); + adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT)); } else if(HEADTYPE == Hdarwin) { - adduint32(lookup(".linkedit.got", 0), s->dynid); + adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid); } else { diag("addgotsym: unsupported binary format"); } } void -adddynsym(Sym *s) +adddynsym(Link *ctxt, LSym *s) { - Sym *d; + LSym *d; int t; char *name; @@ -499,20 +471,20 @@ adddynsym(Sym *s) if(iself) { s->dynid = nelfsym++; - d = lookup(".dynsym", 0); + d = linklookup(ctxt, ".dynsym", 0); /* name */ name = s->extname; - adduint32(d, addstring(lookup(".dynstr", 0), name)); + adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); /* value */ if(s->type == SDYNIMPORT) - adduint32(d, 0); + adduint32(ctxt, d, 0); else - addaddr(d, s); + addaddr(ctxt, d, s); /* size */ - adduint32(d, 0); + adduint32(ctxt, d, 0); /* type */ t = STB_GLOBAL << 4; @@ -520,12 +492,12 @@ adddynsym(Sym *s) t |= STT_FUNC; else t |= STT_OBJECT; - adduint8(d, t); - adduint8(d, 0); + adduint8(ctxt, d, t); + adduint8(ctxt, d, 0); /* shndx */ if(s->type == SDYNIMPORT) - adduint16(d, SHN_UNDEF); + adduint16(ctxt, d, SHN_UNDEF); else { switch(s->type) { default: @@ -542,7 +514,7 @@ adddynsym(Sym *s) t = 14; break; } - adduint16(d, t); + adduint16(ctxt, d, t); } } else if(HEADTYPE == Hdarwin) { diag("adddynsym: missed symbol %s (%s)", s->name, s->extname); @@ -556,16 +528,16 @@ adddynsym(Sym *s) void adddynlib(char *lib) { - Sym *s; + LSym *s; if(!needlib(lib)) return; if(iself) { - s = lookup(".dynstr", 0); + s = linklookup(ctxt, ".dynstr", 0); if(s->size == 0) addstring(s, ""); - elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); + elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); } else if(HEADTYPE == Hdarwin) { machoadddynlib(lib); } else if(HEADTYPE != Hwindows) { @@ -576,10 +548,10 @@ adddynlib(char *lib) void asmb(void) { - int32 v, magic; + int32 magic; uint32 symo, dwarfoff, machlink; Section *sect; - Sym *sym; + LSym *sym; int i; if(debug['v']) @@ -641,18 +613,7 @@ asmb(void) default: if(iself) goto Elfsym; - case Hgarbunix: - symo = rnd(HEADR+segtext.filelen, 8192)+segdata.filelen; - break; - case Hunixcoff: - symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen; - break; - case Hplan9x32: - symo = HEADR+segtext.filelen+segdata.filelen; - break; - case Hmsdoscom: - case Hmsdosexe: - debug['s'] = 1; + case Hplan9: symo = HEADR+segtext.filelen+segdata.filelen; break; case Hdarwin: @@ -685,11 +646,11 @@ asmb(void) elfemitreloc(); } break; - case Hplan9x32: + case Hplan9: asmplan9sym(); cflush(); - sym = lookup("pclntab", 0); + sym = linklookup(ctxt, "pclntab", 0); if(sym != nil) { lcsize = sym->np; for(i=0; i < lcsize; i++) @@ -715,96 +676,7 @@ asmb(void) cseek(0L); switch(HEADTYPE) { default: - case Hgarbunix: /* garbage */ - lputb(0x160L<<16); /* magic and sections */ - lputb(0L); /* time and date */ - lputb(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen); - lputb(symsize); /* nsyms */ - lputb((0x38L<<16)|7L); /* size of optional hdr and flags */ - lputb((0413<<16)|0437L); /* magic and version */ - lputb(rnd(HEADR+segtext.filelen, 4096)); /* sizes */ - lputb(segdata.filelen); - lputb(segdata.len - segdata.filelen); - lputb(entryvalue()); /* va of entry */ - lputb(INITTEXT-HEADR); /* va of base of text */ - lputb(segdata.vaddr); /* va of base of data */ - lputb(segdata.vaddr+segdata.filelen); /* va of base of bss */ - lputb(~0L); /* gp reg mask */ - lputb(0L); - lputb(0L); - lputb(0L); - lputb(0L); - lputb(~0L); /* gp value ?? */ - break; - case Hunixcoff: /* 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(segtext.filelen, INITRND)); /* text sizes */ - lputl(segdata.filelen); /* data sizes */ - lputl(segdata.len - segdata.filelen); /* bss sizes */ - lputb(entryvalue()); /* va of entry */ - lputl(INITTEXT); /* text start */ - lputl(segdata.vaddr); /* data start */ - /* - * text section header - */ - s8put(".text"); - lputl(HEADR); /* pa */ - lputl(HEADR); /* va */ - lputl(segtext.filelen); /* 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(segdata.vaddr); /* pa */ - lputl(segdata.vaddr); /* va */ - lputl(segdata.filelen); /* data size */ - lputl(HEADR+segtext.filelen); /* 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(segdata.vaddr+segdata.filelen); /* pa */ - lputl(segdata.vaddr+segdata.filelen); /* va */ - lputl(segdata.len - segdata.filelen); /* 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+segtext.filelen+segdata.filelen); /* file offset */ - lputl(HEADR+segtext.filelen+segdata.filelen); /* offset of syms */ - lputl(HEADR+segtext.filelen+segdata.filelen+symsize);/* offset of line numbers */ - lputl(0); /* relocation, line numbers */ - lputl(0x200); /* flags comment only */ - break; - case Hplan9x32: /* plan9 */ + case Hplan9: /* plan9 */ magic = 4*11*11+7; lputb(magic); /* magic */ lputb(segtext.filelen); /* sizes */ @@ -815,31 +687,6 @@ asmb(void) lputb(spsize); /* sp offsets */ lputb(lcsize); /* line offsets */ break; - case Hmsdoscom: - /* MS-DOS .COM */ - break; - case Hmsdosexe: - /* fake MS-DOS .EXE */ - v = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen; - wputl(0x5A4D); /* 'MZ' */ - wputl(v % 512); /* bytes in last page */ - wputl(rnd(v, 512)/512); /* total number of pages */ - wputl(0x0000); /* number of reloc items */ - v = rnd(HEADR-(INITTEXT & 0xFFFF), 16); - wputl(v/16); /* size of header */ - wputl(0x0000); /* minimum allocation */ - wputl(0xFFFF); /* maximum allocation */ - wputl(0x0000); /* initial ss value */ - wputl(0x0100); /* initial sp value */ - wputl(0x0000); /* complemented checksum */ - v = entryvalue(); - wputl(v); /* initial ip value (!) */ - wputl(0x0000); /* initial cs value */ - wputl(0x0000); - wputl(0x0000); - wputl(0x003E); /* reloc table offset */ - wputl(0x0000); /* overlay number */ - break; case Hdarwin: asmbmacho(); break; diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h index 814aa1458..928e2e49a 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -31,6 +31,7 @@ #include <u.h> #include <libc.h> #include <bio.h> +#include <link.h> #include "8.out.h" #ifndef EXTERN @@ -47,136 +48,8 @@ enum }; #define P ((Prog*)0) -#define S ((Sym*)0) -#define TNAME (cursym?cursym->name:noname) - -typedef struct Adr Adr; -typedef struct Prog Prog; -typedef struct Sym Sym; -typedef struct Auto Auto; -typedef struct Optab Optab; -typedef struct Reloc Reloc; - -struct Adr -{ - union - { - int32 u0offset; - char u0scon[8]; - Prog *u0cond; /* not used, but should be D_BRANCH */ - Ieee u0ieee; - char *u0sbig; - } u0; - Sym* sym; - short type; - uchar index; - char scale; - int32 offset2; -}; - -#define offset u0.u0offset -#define scon u0.u0scon -#define cond u0.u0cond -#define ieee u0.u0ieee -#define sbig u0.u0sbig - -struct Reloc -{ - int32 off; - uchar siz; - uchar done; - int32 type; - int32 add; - int32 xadd; - Sym* sym; - Sym* xsym; -}; - -struct Prog -{ - Adr from; - Adr to; - Prog* forwd; - Prog* comefrom; - Prog* link; - Prog* pcond; /* work on this */ - int32 pc; - int32 spadj; - int32 line; - short as; - char width; /* fake for DATA */ - char ft; /* oclass cache */ - char tt; - uchar mark; /* work on these */ - uchar back; - uchar bigjmp; -}; -#define datasize from.scale -#define textflag from.scale -#define iscall(p) ((p)->as == ACALL) - -struct Auto -{ - Sym* asym; - Auto* link; - int32 aoffset; - short type; - Sym* gotype; -}; -struct Sym -{ - char* name; - char* extname; // name used in external object files - short type; - short version; - uchar dupok; - uchar reachable; - uchar cgoexport; - uchar special; - uchar stkcheck; - uchar hide; - int32 value; - int32 size; - int32 sig; - int32 dynid; - int32 plt; - int32 got; - int32 align; // if non-zero, required alignment in bytes - int32 elfsym; - int32 args; // size of stack frame incoming arguments area - Sym* hash; // in hash table - Sym* allsym; // in all symbol list - Sym* next; // in text or data list - Sym* sub; // in sub list - Sym* outer; // container of sub - Sym* gotype; - Sym* reachparent; - Sym* queue; - char* file; - char* dynimplib; - char* dynimpvers; - struct Section* sect; - struct Hist* hist; // for ATEXT - - // STEXT - Auto* autom; - Prog* text; - - // SDATA, SBSS - uchar* p; - int32 np; - int32 maxp; - Reloc* r; - int32 nr; - int32 maxr; -}; -struct Optab -{ - short as; - uchar* ytab; - uchar prefix; - uchar op[13]; -}; +#define S ((LSym*)0) +#define TNAME (ctxt->cursym?ctxt->cursym->name:noname) enum { @@ -185,202 +58,50 @@ enum MINLC = 1, MAXIO = 8192, MAXHIST = 40, /* 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, - Ymr, Ymm, - Yxr, Yxm, - Ymax, - - Zxxx = 0, - - Zlit, - Zlitm_r, - Z_rp, - Zbr, - Zcall, - Zcallcon, - Zcallind, - Zib_, - Zib_rp, - Zibo_m, - Zil_, - Zil_rp, - Zilo_m, - Zjmp, - Zjmpcon, - Zloop, - Zm_o, - Zm_r, - Zm2_r, - Zm_r_xm, - Zm_r_i_xm, - Zaut_r, - Zo_m, - Zpseudo, - Zr_m, - Zr_m_xm, - Zr_m_i_xm, - Zrp_, - Z_ib, - Z_il, - Zm_ibo, - Zm_ilo, - Zib_rr, - Zil_rr, - Zclr, - Zibm_r, /* mmx1,mmx2/mem64,imm8 */ - Zbyte, - Zmov, - Zmax, - - Px = 0, - Pe = 0x66, /* operand escape */ - Pm = 0x0f, /* 2byte opcode escape */ - Pq = 0xff, /* both escape */ - Pb = 0xfe, /* byte operands */ - Pf2 = 0xf2, /* xmm escape 1 */ - Pf3 = 0xf3, /* xmm escape 2 */ }; #pragma varargck type "A" int -#pragma varargck type "D" Adr* +#pragma varargck type "D" Addr* #pragma varargck type "I" uchar* #pragma varargck type "P" Prog* #pragma varargck type "R" int #pragma varargck type "S" char* -#pragma varargck type "Y" Sym* +#pragma varargck type "Y" LSym* #pragma varargck type "Z" char* #pragma varargck type "i" char* -EXTERN int32 HEADR; -EXTERN int32 HEADTYPE; -EXTERN int32 INITRND; -EXTERN int32 INITTEXT; -EXTERN int32 INITDAT; -EXTERN char* INITENTRY; /* entry point */ -EXTERN char* pcstr; -EXTERN Auto* curauto; -EXTERN Auto* curhist; -EXTERN Prog* curp; -EXTERN Sym* cursym; -EXTERN Sym* datap; +EXTERN LSym* datap; EXTERN int debug[128]; EXTERN char literal[32]; -EXTERN Sym* etextp; EXTERN Prog* firstp; -EXTERN uchar ycover[Ymax*Ymax]; -EXTERN uchar* andptr; -EXTERN uchar and[100]; -EXTERN char reg[D_NONE]; EXTERN int32 lcsize; -EXTERN int maxop; -EXTERN int nerrors; -EXTERN char* noname; -EXTERN int32 pc; EXTERN char* rpath; EXTERN int32 spsize; -EXTERN Sym* symlist; +EXTERN LSym* symlist; EXTERN int32 symsize; -EXTERN Sym* textp; EXTERN int32 textsize; -EXTERN Prog zprg; -EXTERN int dtype; -EXTERN int tlsoffset; -EXTERN Sym* adrgotype; // type symbol on last Adr read -EXTERN Sym* fromgotype; // type symbol on last p->from read -extern Optab optab[]; -extern char* anames[]; - -int Aconv(Fmt*); -int Dconv(Fmt*); -int Iconv(Fmt*); -int Pconv(Fmt*); -int Rconv(Fmt*); -int Sconv(Fmt*); -void addhist(int32, int); -Prog* appendp(Prog*); +int Aconv(Fmt *fp); +int Dconv(Fmt *fp); +int Iconv(Fmt *fp); +int Pconv(Fmt *fp); +int Rconv(Fmt *fp); +int Sconv(Fmt *fp); +void adddynlib(char *lib); +void adddynrel(LSym *s, Reloc *r); +void adddynrela(LSym *rela, LSym *s, Reloc *r); +void adddynsym(Link *ctxt, LSym *s); +int archreloc(Reloc *r, LSym *s, vlong *val); void asmb(void); -void asmdyn(void); -void asmins(Prog*); -void asmsym(void); -int32 atolwhex(char*); -Prog* brchain(Prog*); -Prog* brloop(Prog*); -void cflush(void); -Prog* copyp(Prog*); -vlong cpos(void); -double cputime(void); -void diag(char*, ...); -void dodata(void); -void doelf(void); -void doprof1(void); -void doprof2(void); -void dostkoff(void); -int32 entryvalue(void); -void follow(void); -void instinit(void); +void diag(char *fmt, ...); +int elfreloc1(Reloc *r, vlong sectoff); +void elfsetupplt(void); void listinit(void); -Sym* lookup(char*, int); -void lputb(int32); -void lputl(int32); -void vputl(uint64); -void strnput(char*, int); -void main(int, char*[]); -void* mal(uint32); -int opsize(Prog*); -void patch(void); -Prog* prg(void); -int relinv(int); -int32 rnd(int32, int32); -void s8put(char*); -void span(void); -void undef(void); -int32 symaddr(Sym*); -void wput(ushort); -void wputl(ushort); -void xdefine(char*, int, int32); - -uint32 machheadr(void); -vlong addaddr(Sym *s, Sym *t); -vlong addsize(Sym *s, Sym *t); -vlong addstring(Sym *s, char *str); -vlong adduint16(Sym *s, uint16 v); -vlong adduint32(Sym *s, uint32 v); -vlong adduint64(Sym *s, uint64 v); -vlong adduint8(Sym *s, uint8 v); -vlong adduintxx(Sym *s, uint64 v, int wid); - -/* - * go.c - */ -void deadcode(void); +int machoreloc1(Reloc *r, vlong sectoff); +void main(int argc, char *argv[]); +int32 rnd(int32 v, int32 r); +void s8put(char *n); +char* xsymname(LSym *s); /* Native is little-endian */ #define LPUT(a) lputl(a) diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c index e2a2ec5ed..8e57b4af1 100644 --- a/src/cmd/8l/list.c +++ b/src/cmd/8l/list.c @@ -58,18 +58,18 @@ Pconv(Fmt *fp) case ATEXT: if(p->from.scale) { fmtprint(fp, "(%d) %A %D,%d,%D", - p->line, p->as, &p->from, p->from.scale, &p->to); + p->lineno, p->as, &p->from, p->from.scale, &p->to); break; } default: fmtprint(fp, "(%d) %A %D,%D", - p->line, p->as, &p->from, &p->to); + p->lineno, p->as, &p->from, &p->to); break; case ADATA: case AINIT_: case ADYNT_: fmtprint(fp, "(%d) %A %D/%d,%D", - p->line, p->as, &p->from, p->from.scale, &p->to); + p->lineno, p->as, &p->from, p->from.scale, &p->to); break; } bigP = P; @@ -82,11 +82,11 @@ Aconv(Fmt *fp) int i; i = va_arg(fp->args, int); - return fmtstrcpy(fp, anames[i]); + return fmtstrcpy(fp, anames8[i]); } char* -xsymname(Sym *s) +xsymname(LSym *s) { if(s == nil) return "!!noname!!"; @@ -97,10 +97,10 @@ int Dconv(Fmt *fp) { char str[STRINGSZ], s[STRINGSZ]; - Adr *a; + Addr *a; int i; - a = va_arg(fp->args, Adr*); + a = va_arg(fp->args, Addr*); i = a->type; if(i >= D_INDIR && i < 2*D_INDIR) { if(a->offset) @@ -159,11 +159,11 @@ Dconv(Fmt *fp) break; case D_FCONST: - snprint(str, sizeof str, "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l); + snprint(str, sizeof str, "$(%.17g)", a->u.dval); break; case D_SCONST: - snprint(str, sizeof str, "$\"%S\"", a->scon); + snprint(str, sizeof str, "$\"%S\"", a->u.sval); break; case D_ADDR: @@ -361,8 +361,8 @@ diag(char *fmt, ...) tn = ""; sep = ""; - if(cursym != S) { - tn = cursym->name; + if(ctxt->cursym != S) { + tn = ctxt->cursym->name; sep = ": "; } va_start(arg, fmt); diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c index 3fdc41381..e588060be 100644 --- a/src/cmd/8l/obj.c +++ b/src/cmd/8l/obj.c @@ -30,7 +30,6 @@ // Reading object files. -#define EXTERN #include "l.h" #include "../ld/lib.h" #include "../ld/elf.h" @@ -39,110 +38,12 @@ #include "../ld/pe.h" #include <ar.h> -#ifndef DEFAULT -#define DEFAULT '9' -#endif - -char *noname = "<none>"; -char *thestring = "386"; - -Header headers[] = { - "garbunix", Hgarbunix, - "unixcoff", Hunixcoff, - "plan9", Hplan9x32, - "msdoscom", Hmsdoscom, - "msdosexe", Hmsdosexe, - "darwin", Hdarwin, - "dragonfly", Hdragonfly, - "linux", Hlinux, - "freebsd", Hfreebsd, - "netbsd", Hnetbsd, - "openbsd", Hopenbsd, - "windows", Hwindows, - "windowsgui", Hwindows, - 0, 0 -}; - -/* - * -Hgarbunix -T0x40004C -D0x10000000 is garbage unix - * -Hunixcoff -T0xd0 -R4 is unix coff - * -Hplan9 -T4128 -R4096 is plan9 format - * -Hmsdoscom -Tx -Rx is MS-DOS .COM - * -Hmsdosexe -Tx -Rx is fake MS-DOS .EXE - * -Hdarwin -Tx -Rx is Apple Mach-O - * -Hdragonfly -Tx -Rx is DragonFly ELF32 - * -Hlinux -Tx -Rx is Linux ELF32 - * -Hfreebsd -Tx -Rx is FreeBSD ELF32 - * -Hnetbsd -Tx -Rx is NetBSD ELF32 - * -Hopenbsd -Tx -Rx is OpenBSD ELF32 - * -Hwindows -Tx -Rx is MS Windows PE32 - */ +char* thestring = "386"; +LinkArch* thelinkarch = &link386; void -main(int argc, char *argv[]) +archinit(void) { - Binit(&bso, 1, OWRITE); - listinit(); - memset(debug, 0, sizeof(debug)); - nerrors = 0; - outfile = nil; - HEADTYPE = -1; - INITTEXT = -1; - INITDAT = -1; - INITRND = -1; - INITENTRY = 0; - linkmode = LinkAuto; - nuxiinit(); - - flagcount("1", "use alternate profiling code", &debug['1']); - flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); - flagstr("E", "sym: entry symbol", &INITENTRY); - flagint32("D", "addr: data address", &INITDAT); - flagfn1("I", "interp: set ELF interp", setinterp); - flagfn1("L", "dir: add dir to library path", Lflag); - flagfn1("H", "head: header type", setheadtype); - flagcount("K", "add stack underflow checks", &debug['K']); - flagcount("O", "print pc-line tables", &debug['O']); - flagcount("Q", "debug byte-register code gen", &debug['Q']); - flagint32("R", "rnd: address rounding", &INITRND); - flagcount("S", "check type signatures", &debug['S']); - flagint32("T", "addr: text address", &INITTEXT); - flagfn0("V", "print version and exit", doversion); - flagcount("W", "disassemble input", &debug['W']); - flagfn2("X", "name value: define string data", addstrdata); - flagcount("Z", "clear stack frame on entry", &debug['Z']); - flagcount("a", "disassemble output", &debug['a']); - flagcount("c", "dump call graph", &debug['c']); - flagcount("d", "disable dynamic executable", &debug['d']); - flagstr("extld", "linker to run in external mode", &extld); - flagstr("extldflags", "flags for external linker", &extldflags); - flagcount("f", "ignore version mismatch", &debug['f']); - flagcount("g", "disable go package data checks", &debug['g']); - flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); - flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode); - flagstr("k", "sym: set field tracking symbol", &tracksym); - flagstr("o", "outfile: set output file", &outfile); - flagcount("p", "insert profiling code", &debug['p']); - flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); - flagcount("race", "enable race detector", &flag_race); - flagcount("s", "disable symbol table", &debug['s']); - flagcount("n", "dump symbol table", &debug['n']); - flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); - flagcount("u", "reject unsafe packages", &debug['u']); - flagcount("v", "print link trace", &debug['v']); - flagcount("w", "disable DWARF generation", &debug['w']); - // TODO: link mode flag - - flagparse(&argc, &argv, usage); - - if(argc != 1) - usage(); - - mywhatsys(); // get goos - - if(HEADTYPE == -1) - HEADTYPE = headtype(goos); - // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // Go was built; see ../../make.bash. if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0) @@ -163,41 +64,15 @@ main(int argc, char *argv[]) case Hopenbsd: break; } - - if(outfile == nil) { - if(HEADTYPE == Hwindows) - outfile = "8.out.exe"; - else - outfile = "8.out"; - } - - libinit(); + ctxt->linkmode = linkmode; switch(HEADTYPE) { default: diag("unknown -H option"); errorexit(); - case Hgarbunix: /* this is garbage */ - HEADR = 20L+56L; - if(INITTEXT == -1) - INITTEXT = 0x40004CL; - if(INITDAT == -1) - INITDAT = 0x10000000L; - if(INITRND == -1) - INITRND = 0; - break; - case Hunixcoff: /* is unix coff */ - HEADR = 0xd0L; - if(INITTEXT == -1) - INITTEXT = 0xd0; - if(INITDAT == -1) - INITDAT = 0x400000; - if(INITRND == -1) - INITRND = 0; - break; - case Hplan9x32: /* plan 9 */ - tlsoffset = -8; + case Hplan9: /* plan 9 */ + ctxt->tlsoffset = -8; HEADR = 32L; if(INITTEXT == -1) INITTEXT = 4096+32; @@ -206,33 +81,12 @@ main(int argc, char *argv[]) if(INITRND == -1) INITRND = 4096; break; - case Hmsdoscom: /* MS-DOS .COM */ - HEADR = 0; - if(INITTEXT == -1) - INITTEXT = 0x0100; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4; - break; - case Hmsdosexe: /* 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%d\n", HEADR); - break; case Hdarwin: /* apple MACH */ /* * OS X system constant - offset from %gs to our TLS. * Explained in ../../pkg/runtime/cgo/gcc_darwin_386.c. */ - tlsoffset = 0x468; + ctxt->tlsoffset = 0x468; machoinit(); HEADR = INITIAL_MACHO_HEADR; if(INITTEXT == -1) @@ -253,7 +107,7 @@ main(int argc, char *argv[]) * Also known to ../../pkg/runtime/sys_linux_386.s * and ../../pkg/runtime/cgo/gcc_linux_386.c. */ - tlsoffset = -8; + ctxt->tlsoffset = -8; elfinit(); HEADR = ELFRESERVE; if(INITTEXT == -1) @@ -277,516 +131,4 @@ main(int argc, char *argv[]) if(INITDAT != 0 && INITRND != 0) print("warning: -D0x%ux is ignored because of -R0x%ux\n", INITDAT, INITRND); - if(debug['v']) - Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n", - HEADTYPE, INITTEXT, INITDAT, INITRND); - Bflush(&bso); - - instinit(); - 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 = "%.6ux "; - histgen = 0; - pc = 0; - dtype = 4; - version = 0; - cbp = buf.cbuf; - cbc = sizeof(buf.cbuf); - - addlibpath("command line", "command line", argv[0], "main"); - loadlib(); - deadcode(); - patch(); - follow(); - doelf(); - if(HEADTYPE == Hdarwin) - domacho(); - if(HEADTYPE == Hwindows) - dope(); - dostkoff(); - dostkcheck(); - if(debug['p']) - if(debug['1']) - doprof1(); - else - doprof2(); - span(); - addexport(); - textaddress(); - pclntab(); - symtab(); - dodata(); - address(); - doweak(); - reloc(); - asmb(); - undef(); - hostlink(); - - if(debug['v']) { - Bprint(&bso, "%5.2f cpu time\n", cputime()); - Bprint(&bso, "%d symbols\n", nsymbol); - Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); - Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); - } - Bflush(&bso); - - errorexit(); -} - -static Sym* -zsym(char *pn, Biobuf *f, Sym *h[]) -{ - int o; - - o = BGETC(f); - if(o < 0 || o >= NSYM || h[o] == nil) - mangle(pn); - return h[o]; -} - -static void -zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[]) -{ - int t; - int32 l; - Sym *s; - Auto *u; - - t = BGETC(f); - a->index = D_NONE; - a->scale = 0; - if(t & T_INDEX) { - a->index = BGETC(f); - a->scale = BGETC(f); - } - a->type = D_NONE; - a->offset = 0; - if(t & T_OFFSET) - a->offset = BGETLE4(f); - a->offset2 = 0; - if(t & T_OFFSET2) { - a->offset2 = BGETLE4(f); - a->type = D_CONST2; - } - a->sym = S; - if(t & T_SYM) - a->sym = zsym(pn, f, h); - if(t & T_FCONST) { - a->ieee.l = BGETLE4(f); - a->ieee.h = BGETLE4(f); - a->type = D_FCONST; - } else - if(t & T_SCONST) { - Bread(f, a->scon, NSNAME); - a->type = D_SCONST; - } - if(t & T_TYPE) - a->type = BGETC(f); - adrgotype = S; - if(t & T_GOTYPE) - adrgotype = zsym(pn, f, h); - - t = a->type; - if(t == D_INDIR+D_GS) - a->offset += tlsoffset; - - s = a->sym; - if(s == S) - return; - if(t != D_AUTO && t != D_PARAM) { - if(adrgotype) - s->gotype = adrgotype; - return; - } - 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; - if(adrgotype) - u->gotype = adrgotype; - return; - } - } - - u = mal(sizeof(*u)); - u->link = curauto; - curauto = u; - u->asym = s; - u->aoffset = l; - u->type = t; - u->gotype = adrgotype; -} - -void -nopout(Prog *p) -{ - p->as = ANOP; - p->from.type = D_NONE; - p->to.type = D_NONE; -} - -void -ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) -{ - int32 ipc; - Prog *p; - int v, o, r, skip; - Sym *h[NSYM], *s; - uint32 sig; - int ntext; - int32 eof; - char *name, *x; - char src[1024]; - Prog *lastp; - - lastp = nil; - ntext = 0; - eof = Boffset(f) + len; - src[0] = 0; - pn = estrdup(pn); // we keep it in Sym* references - -newloop: - memset(h, 0, sizeof(h)); - version++; - histfrogp = 0; - ipc = pc; - skip = 0; - -loop: - if(f->state == Bracteof || Boffset(f) >= eof) - goto eof; - o = BGETC(f); - if(o == Beof) - goto eof; - o |= BGETC(f) << 8; - if(o <= AXXX || o >= ALAST) { - if(o < 0) - goto eof; - diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); - print(" probably not a .%c file\n", thechar); - errorexit(); - } - - if(o == ANAME || o == ASIGNAME) { - sig = 0; - if(o == ASIGNAME) - sig = BGETLE4(f); - v = BGETC(f); /* type */ - o = BGETC(f); /* sym */ - r = 0; - if(v == D_STATIC) - r = version; - name = Brdline(f, '\0'); - if(name == nil) { - if(Blinelen(f) > 0) { - fprint(2, "%s: name too long\n", pn); - errorexit(); - } - goto eof; - } - x = expandpkg(name, pkg); - s = lookup(x, r); - if(x != name) - free(x); - - if(debug['S'] && r == 0) - sig = 1729; - if(sig != 0){ - if(s->sig != 0 && s->sig != sig) - diag("incompatible type signatures " - "%ux(%s) and %ux(%s) for %s", - s->sig, s->file, sig, pn, s->name); - s->sig = sig; - s->file = pn; - } - - if(debug['W']) - print(" ANAME %s\n", s->name); - if(o < 0 || o >= nelem(h)) - mangle(pn); - 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); - dwarfaddfrag(s->value, s->name); - } - goto loop; - } - - p = mal(sizeof(*p)); - p->as = o; - p->line = BGETLE4(f); - p->back = 2; - zaddr(pn, f, &p->from, h); - fromgotype = adrgotype; - zaddr(pn, f, &p->to, h); - - if(debug['W']) - print("%P\n", p); - - switch(p->as) { - case AHISTORY: - if(p->to.offset == -1) { - addlib(src, pn); - histfrogp = 0; - goto loop; - } - if(src[0] == '\0') - copyhistfrog(src, sizeof src); - addhist(p->line, D_FILE); /* 'z' */ - if(p->to.offset) - addhist(p->to.offset, D_FILE1); /* 'Z' */ - savehist(p->line, p->to.offset); - histfrogp = 0; - goto loop; - - case AEND: - histtoauto(); - if(cursym != nil && cursym->text) - cursym->autom = curauto; - curauto = 0; - cursym = nil; - if(Boffset(f) == eof) - return; - goto newloop; - - case AGLOBL: - s = p->from.sym; - if(s->type == 0 || s->type == SXREF) { - s->type = SBSS; - s->size = 0; - } - if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) { - diag("%s: redefinition: %s in %s", - pn, s->name, TNAME); - s->type = SBSS; - s->size = 0; - } - if(p->to.offset > s->size) - s->size = p->to.offset; - if(p->from.scale & DUPOK) - s->dupok = 1; - if(p->from.scale & RODATA) - s->type = SRODATA; - else if(p->from.scale & NOPTR) - s->type = SNOPTRBSS; - goto loop; - - case ADATA: - // Assume that AGLOBL comes after ADATA. - // If we've seen an AGLOBL that said this sym was DUPOK, - // ignore any more ADATA we see, which must be - // redefinitions. - s = p->from.sym; - if(s->dupok) { -// if(debug['v']) -// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); - goto loop; - } - if(s->file == nil) - s->file = pn; - else if(s->file != pn) { - diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); - errorexit(); - } - savedata(s, p, pn); - unmal(p, sizeof *p); - goto loop; - - case AGOK: - diag("%s: GOK opcode in %s", pn, TNAME); - pc++; - goto loop; - - case ATYPE: - if(skip) - goto casdef; - pc++; - goto loop; - - case ATEXT: - s = p->from.sym; - if(s->text != nil) { - if(p->from.scale & DUPOK) { - skip = 1; - goto casdef; - } - diag("%s: %s: redefinition", pn, s->name); - return; - } - if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { - /* redefinition, so file has probably been seen before */ - if(debug['v']) - diag("skipping: %s: redefinition: %s", pn, s->name); - return; - } - if(cursym != nil && cursym->text) { - histtoauto(); - cursym->autom = curauto; - curauto = 0; - } - skip = 0; - if(etextp) - etextp->next = s; - else - textp = s; - etextp = s; - s->text = p; - cursym = s; - 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->hist = gethist(); - s->value = pc; - s->args = p->to.offset2; - lastp = p; - p->pc = pc++; - goto loop; - - case AFMOVF: - case AFADDF: - case AFSUBF: - case AFSUBRF: - case AFMULF: - case AFDIVF: - case AFDIVRF: - case AFCOMF: - case AFCOMFP: - case AMOVSS: - case AADDSS: - case ASUBSS: - case AMULSS: - case ADIVSS: - case ACOMISS: - case AUCOMISS: - if(skip) - goto casdef; - if(p->from.type == D_FCONST) { - /* size sb 9 max */ - sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, ieeedtof(&p->from.ieee)); - s->reachable = 0; - } - 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: - case AMOVSD: - case AADDSD: - case ASUBSD: - case AMULSD: - case ADIVSD: - case ACOMISD: - case AUCOMISD: - if(skip) - goto casdef; - if(p->from.type == D_FCONST) { - /* size sb 18 max */ - sprint(literal, "$%ux.%ux", - p->from.ieee.l, p->from.ieee.h); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, p->from.ieee.l); - adduint32(s, p->from.ieee.h); - s->reachable = 0; - } - p->from.type = D_EXTERN; - p->from.sym = s; - p->from.offset = 0; - } - goto casdef; - - casdef: - default: - if(skip) - nopout(p); - p->pc = pc; - pc++; - - if(p->to.type == D_BRANCH) - p->to.offset += ipc; - if(lastp == nil) { - if(p->as != ANOP) - diag("unexpected instruction: %P", p); - goto loop; - } - lastp->link = p; - lastp = p; - goto loop; - } - -eof: - diag("truncated object file: %s", pn); -} - -Prog* -prg(void) -{ - Prog *p; - - p = mal(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; } diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c deleted file mode 100644 index 19952e5f9..000000000 --- a/src/cmd/8l/optab.c +++ /dev/null @@ -1,1032 +0,0 @@ -// 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 yfuncdata[] = -{ - Yi32, Ym, Zpseudo, 0, - 0 -}; -uchar ypcdata[] = -{ - Yi32, Yi32, Zpseudo, 0, - 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 ymovw[] = -{ - 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, 1, - 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, - Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit) - Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit) - Yiauto, Yrl, Zaut_r, 1, - 0 -}; -uchar ymovq[] = -{ - Yml, Yxr, Zm_r_xm, 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 yrb_mb[] = -{ - Yrb, Ymb, Zr_m, 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 yxchg[] = -{ - Yax, Yrl, Z_rp, 1, - Yrl, Yax, Zrp_, 1, - 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 ybswap[] = -{ - Ynone, Yrl, Z_rp, 1, - 0, -}; -uchar yscond[] = -{ - Ynone, Ymb, Zo_m, 2, - 0 -}; -uchar yjcond[] = -{ - Ynone, Ybr, Zbr, 0, - Yi0, Ybr, Zbr, 0, - Yi1, Ybr, Zbr, 1, - 0 -}; -uchar yloop[] = -{ - Ynone, Ybr, Zloop, 1, - 0 -}; -uchar ycall[] = -{ - Ynone, Yml, Zo_m, 0, - Yrx, Yrx, Zo_m, 2, - Ynone, Ycol, Zcallind, 2, - Ynone, Ybr, Zcall, 0, - Ynone, Yi32, Zcallcon, 1, - 0 -}; -uchar yjmp[] = -{ - Ynone, Yml, Zo_m, 2, - Ynone, Ybr, Zjmp, 0, - Ynone, Yi32, Zjmpcon, 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 yfcmv[] = -{ - Yrf, Yf0, Zm_o, 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 -}; -uchar ymskb[] = -{ - Yxr, Yrl, Zm_r_xm, 2, - Ymr, Yrl, Zm_r_xm, 1, - 0 -}; -uchar yxm[] = -{ - Yxm, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxcvm1[] = -{ - Yxm, Yxr, Zm_r_xm, 2, - Yxm, Ymr, Zm_r_xm, 2, - 0 -}; -uchar yxcvm2[] = -{ - Yxm, Yxr, Zm_r_xm, 2, - Ymm, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yxmq[] = -{ - Yxm, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yxr[] = -{ - Yxr, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxr_ml[] = -{ - Yxr, Yml, Zr_m_xm, 1, - 0 -}; -uchar yxcmp[] = -{ - Yxm, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxcmpi[] = -{ - Yxm, Yxr, Zm_r_i_xm, 2, - 0 -}; -uchar yxmov[] = -{ - Yxm, Yxr, Zm_r_xm, 1, - Yxr, Yxm, Zr_m_xm, 1, - 0 -}; -uchar yxcvfl[] = -{ - Yxm, Yrl, Zm_r_xm, 1, - 0 -}; -uchar yxcvlf[] = -{ - Yml, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxcvfq[] = -{ - Yxm, Yrl, Zm_r_xm, 2, - 0 -}; -uchar yxcvqf[] = -{ - Yml, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yxrrl[] = -{ - Yxr, Yrl, Zm_r, 1, - 0 -}; -uchar yprefetch[] = -{ - Ym, Ynone, Zm_o, 2, - 0, -}; -uchar yaes[] = -{ - Yxm, Yxr, Zlitm_r, 2, - 0 -}; -uchar yinsrd[] = -{ - Yml, Yxr, Zibm_r, 2, - 0 -}; -uchar ymshufb[] = -{ - Yxm, Yxr, Zm2_r, 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),0xff,(0x15),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 }, - { AJCXZL, yloop, Px, 0xe3 }, - { AJCXZW, 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),Pe,0x6e,Pe,0x7e,0 }, - { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),0 }, - { AMOVQ, ymovq, Pf3, 0x7e }, - { 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 }, - { APAUSE, ynone, Px, 0xf3,0x90 }, - { 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, yxchg, Px, 0x90,0x90,0x87,0x87 }, - { AXCHGW, yxchg, Pe, 0x90,0x90,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) }, - { AFCOMI, yfmvx, Px, 0xdb,(06) }, - { AFCOMIP, yfmvx, Px, 0xdf,(06) }, - { 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) }, - { AFUCOMI, ycompp, Px, 0xdb,(05) }, - { AFUCOMIP, ycompp, Px, 0xdf,(05) }, - { 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 }, - { ADYNT_ }, - { AINIT_ }, - { ASIGNAME }, - { ACMPXCHGB, yrb_mb, Pm, 0xb0 }, - { ACMPXCHGL, yrl_ml, Pm, 0xb1 }, - { ACMPXCHGW, yrl_ml, Pm, 0xb1 }, - { ACMPXCHG8B, yscond, Pm, 0xc7,(01) }, - - { ACPUID, ynone, Pm, 0xa2 }, - { ARDTSC, ynone, Pm, 0x31 }, - - { AXADDB, yrb_mb, Pb, 0x0f,0xc0 }, - { AXADDL, yrl_ml, Pm, 0xc1 }, - { AXADDW, yrl_ml, Pe, 0x0f,0xc1 }, - - { ACMOVLCC, yml_rl, Pm, 0x43 }, - { ACMOVLCS, yml_rl, Pm, 0x42 }, - { ACMOVLEQ, yml_rl, Pm, 0x44 }, - { ACMOVLGE, yml_rl, Pm, 0x4d }, - { ACMOVLGT, yml_rl, Pm, 0x4f }, - { ACMOVLHI, yml_rl, Pm, 0x47 }, - { ACMOVLLE, yml_rl, Pm, 0x4e }, - { ACMOVLLS, yml_rl, Pm, 0x46 }, - { ACMOVLLT, yml_rl, Pm, 0x4c }, - { ACMOVLMI, yml_rl, Pm, 0x48 }, - { ACMOVLNE, yml_rl, Pm, 0x45 }, - { ACMOVLOC, yml_rl, Pm, 0x41 }, - { ACMOVLOS, yml_rl, Pm, 0x40 }, - { ACMOVLPC, yml_rl, Pm, 0x4b }, - { ACMOVLPL, yml_rl, Pm, 0x49 }, - { ACMOVLPS, yml_rl, Pm, 0x4a }, - { ACMOVWCC, yml_rl, Pq, 0x43 }, - { ACMOVWCS, yml_rl, Pq, 0x42 }, - { ACMOVWEQ, yml_rl, Pq, 0x44 }, - { ACMOVWGE, yml_rl, Pq, 0x4d }, - { ACMOVWGT, yml_rl, Pq, 0x4f }, - { ACMOVWHI, yml_rl, Pq, 0x47 }, - { ACMOVWLE, yml_rl, Pq, 0x4e }, - { ACMOVWLS, yml_rl, Pq, 0x46 }, - { ACMOVWLT, yml_rl, Pq, 0x4c }, - { ACMOVWMI, yml_rl, Pq, 0x48 }, - { ACMOVWNE, yml_rl, Pq, 0x45 }, - { ACMOVWOC, yml_rl, Pq, 0x41 }, - { ACMOVWOS, yml_rl, Pq, 0x40 }, - { ACMOVWPC, yml_rl, Pq, 0x4b }, - { ACMOVWPL, yml_rl, Pq, 0x49 }, - { ACMOVWPS, yml_rl, Pq, 0x4a }, - - { AFCMOVCC, yfcmv, Px, 0xdb,(00) }, - { AFCMOVCS, yfcmv, Px, 0xda,(00) }, - { AFCMOVEQ, yfcmv, Px, 0xda,(01) }, - { AFCMOVHI, yfcmv, Px, 0xdb,(02) }, - { AFCMOVLS, yfcmv, Px, 0xda,(02) }, - { AFCMOVNE, yfcmv, Px, 0xdb,(01) }, - { AFCMOVNU, yfcmv, Px, 0xdb,(03) }, - { AFCMOVUN, yfcmv, Px, 0xda,(03) }, - - { ALFENCE, ynone, Pm, 0xae,0xe8 }, - { AMFENCE, ynone, Pm, 0xae,0xf0 }, - { ASFENCE, ynone, Pm, 0xae,0xf8 }, - - { AEMMS, ynone, Pm, 0x77 }, - - { APREFETCHT0, yprefetch, Pm, 0x18,(01) }, - { APREFETCHT1, yprefetch, Pm, 0x18,(02) }, - { APREFETCHT2, yprefetch, Pm, 0x18,(03) }, - { APREFETCHNTA, yprefetch, Pm, 0x18,(00) }, - - { ABSWAPL, ybswap, Pm, 0xc8 }, - - { AUNDEF, ynone, Px, 0x0f, 0x0b }, - - { AADDPD, yxm, Pq, 0x58 }, - { AADDPS, yxm, Pm, 0x58 }, - { AADDSD, yxm, Pf2, 0x58 }, - { AADDSS, yxm, Pf3, 0x58 }, - { AANDNPD, yxm, Pq, 0x55 }, - { AANDNPS, yxm, Pm, 0x55 }, - { AANDPD, yxm, Pq, 0x54 }, - { AANDPS, yxm, Pq, 0x54 }, - { ACMPPD, yxcmpi, Px, Pe,0xc2 }, - { ACMPPS, yxcmpi, Pm, 0xc2,0 }, - { ACMPSD, yxcmpi, Px, Pf2,0xc2 }, - { ACMPSS, yxcmpi, Px, Pf3,0xc2 }, - { ACOMISD, yxcmp, Pe, 0x2f }, - { ACOMISS, yxcmp, Pm, 0x2f }, - { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a }, - { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, }, - { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d }, - { ACVTPD2PS, yxm, Pe, 0x5a }, - { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d }, - { ACVTPS2PD, yxm, Pm, 0x5a }, - { ACVTSD2SL, yxcvfl, Pf2, 0x2d }, - { ACVTSD2SS, yxm, Pf2, 0x5a }, - { ACVTSL2SD, yxcvlf, Pf2, 0x2a }, - { ACVTSL2SS, yxcvlf, Pf3, 0x2a }, - { ACVTSS2SD, yxm, Pf3, 0x5a }, - { ACVTSS2SL, yxcvfl, Pf3, 0x2d }, - { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c }, - { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c }, - { ACVTTSD2SL, yxcvfl, Pf2, 0x2c }, - { ACVTTSS2SL, yxcvfl, Pf3, 0x2c }, - { ADIVPD, yxm, Pe, 0x5e }, - { ADIVPS, yxm, Pm, 0x5e }, - { ADIVSD, yxm, Pf2, 0x5e }, - { ADIVSS, yxm, Pf3, 0x5e }, - { AMASKMOVOU, yxr, Pe, 0xf7 }, - { AMAXPD, yxm, Pe, 0x5f }, - { AMAXPS, yxm, Pm, 0x5f }, - { AMAXSD, yxm, Pf2, 0x5f }, - { AMAXSS, yxm, Pf3, 0x5f }, - { AMINPD, yxm, Pe, 0x5d }, - { AMINPS, yxm, Pm, 0x5d }, - { AMINSD, yxm, Pf2, 0x5d }, - { AMINSS, yxm, Pf3, 0x5d }, - { AMOVAPD, yxmov, Pe, 0x28,0x29 }, - { AMOVAPS, yxmov, Pm, 0x28,0x29 }, - { AMOVO, yxmov, Pe, 0x6f,0x7f }, - { AMOVOU, yxmov, Pf3, 0x6f,0x7f }, - { AMOVHLPS, yxr, Pm, 0x12 }, - { AMOVHPD, yxmov, Pe, 0x16,0x17 }, - { AMOVHPS, yxmov, Pm, 0x16,0x17 }, - { AMOVLHPS, yxr, Pm, 0x16 }, - { AMOVLPD, yxmov, Pe, 0x12,0x13 }, - { AMOVLPS, yxmov, Pm, 0x12,0x13 }, - { AMOVMSKPD, yxrrl, Pq, 0x50 }, - { AMOVMSKPS, yxrrl, Pm, 0x50 }, - { AMOVNTO, yxr_ml, Pe, 0xe7 }, - { AMOVNTPD, yxr_ml, Pe, 0x2b }, - { AMOVNTPS, yxr_ml, Pm, 0x2b }, - { AMOVSD, yxmov, Pf2, 0x10,0x11 }, - { AMOVSS, yxmov, Pf3, 0x10,0x11 }, - { AMOVUPD, yxmov, Pe, 0x10,0x11 }, - { AMOVUPS, yxmov, Pm, 0x10,0x11 }, - { AMULPD, yxm, Pe, 0x59 }, - { AMULPS, yxm, Ym, 0x59 }, - { AMULSD, yxm, Pf2, 0x59 }, - { AMULSS, yxm, Pf3, 0x59 }, - { AORPD, yxm, Pq, 0x56 }, - { AORPS, yxm, Pm, 0x56 }, - { APADDQ, yxm, Pe, 0xd4 }, - { APAND, yxm, Pe, 0xdb }, - { APCMPEQB, yxmq, Pe ,0x74 }, - { APMAXSW, yxm, Pe, 0xee }, - { APMAXUB, yxm, Pe, 0xde }, - { APMINSW, yxm, Pe, 0xea }, - { APMINUB, yxm, Pe, 0xda }, - { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 }, - { APSADBW, yxm, Pq, 0xf6 }, - { APSUBB, yxm, Pe, 0xf8 }, - { APSUBL, yxm, Pe, 0xfa }, - { APSUBQ, yxm, Pe, 0xfb }, - { APSUBSB, yxm, Pe, 0xe8 }, - { APSUBSW, yxm, Pe, 0xe9 }, - { APSUBUSB, yxm, Pe, 0xd8 }, - { APSUBUSW, yxm, Pe, 0xd9 }, - { APSUBW, yxm, Pe, 0xf9 }, - { APUNPCKHQDQ, yxm, Pe, 0x6d }, - { APUNPCKLQDQ, yxm, Pe, 0x6c }, - { ARCPPS, yxm, Pm, 0x53 }, - { ARCPSS, yxm, Pf3, 0x53 }, - { ARSQRTPS, yxm, Pm, 0x52 }, - { ARSQRTSS, yxm, Pf3, 0x52 }, - { ASQRTPD, yxm, Pe, 0x51 }, - { ASQRTPS, yxm, Pm, 0x51 }, - { ASQRTSD, yxm, Pf2, 0x51 }, - { ASQRTSS, yxm, Pf3, 0x51 }, - { ASUBPD, yxm, Pe, 0x5c }, - { ASUBPS, yxm, Pm, 0x5c }, - { ASUBSD, yxm, Pf2, 0x5c }, - { ASUBSS, yxm, Pf3, 0x5c }, - { AUCOMISD, yxcmp, Pe, 0x2e }, - { AUCOMISS, yxcmp, Pm, 0x2e }, - { AUNPCKHPD, yxm, Pe, 0x15 }, - { AUNPCKHPS, yxm, Pm, 0x15 }, - { AUNPCKLPD, yxm, Pe, 0x14 }, - { AUNPCKLPS, yxm, Pm, 0x14 }, - { AXORPD, yxm, Pe, 0x57 }, - { AXORPS, yxm, Pm, 0x57 }, - - { AAESENC, yaes, Pq, 0x38,0xdc,(0) }, - { APINSRD, yinsrd, Pq, 0x3a, 0x22, (00) }, - { APSHUFB, ymshufb,Pq, 0x38, 0x00 }, - - { AUSEFIELD, ynop, Px, 0,0 }, - { ATYPE }, - { AFUNCDATA, yfuncdata, Px, 0,0 }, - { APCDATA, ypcdata, Px, 0,0 }, - { ACHECKNIL }, - { AFATVARDEF }, - - 0 -}; diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c deleted file mode 100644 index 1eaf78fe0..000000000 --- a/src/cmd/8l/pass.c +++ /dev/null @@ -1,858 +0,0 @@ -// 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. - -// Code and data passes. - -#include "l.h" -#include "../ld/lib.h" -#include "../../pkg/runtime/stack.h" - -static void xfol(Prog*, Prog**); - -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) -{ - Prog *firstp, *lastp; - - if(debug['v']) - Bprint(&bso, "%5.2f follow\n", cputime()); - Bflush(&bso); - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - firstp = prg(); - lastp = firstp; - xfol(cursym->text, &lastp); - lastp->link = nil; - cursym->text = firstp->link; - } -} - -static int -nofollow(int a) -{ - switch(a) { - case AJMP: - case ARET: - case AIRETL: - case AIRETW: - case AUNDEF: - return 1; - } - return 0; -} - -static int -pushpop(int a) -{ - switch(a) { - case APUSHL: - case APUSHFL: - case APUSHW: - case APUSHFW: - case APOPL: - case APOPFL: - case APOPW: - case APOPFW: - return 1; - } - return 0; -} - -static void -xfol(Prog *p, Prog **last) -{ - Prog *q; - int i; - enum as a; - -loop: - if(p == P) - return; - if(p->as == AJMP) - if((q = p->pcond) != P && q->as != ATEXT) { - /* mark instruction as done and continue layout at target of jump */ - p->mark = 1; - p = q; - if(p->mark == 0) - goto loop; - } - if(p->mark) { - /* - * p goes here, but already used it elsewhere. - * copy up to 4 instructions or else branch to other copy. - */ - for(i=0,q=p; i<4; i++,q=q->link) { - if(q == P) - break; - if(q == *last) - break; - a = q->as; - if(a == ANOP) { - i--; - continue; - } - if(nofollow(a) || pushpop(a)) - break; // NOTE(rsc): arm does goto copy - 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; - (*last)->link = q; - *last = 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, last); - p = q->link; - if(p->mark) - return; - goto loop; - } - } /* */ - q = prg(); - q->as = AJMP; - q->line = p->line; - q->to.type = D_BRANCH; - q->to.offset = p->pc; - q->pcond = p; - p = q; - } - - /* emit p */ - p->mark = 1; - (*last)->link = p; - *last = p; - a = p->as; - - /* continue loop with what comes after p */ - if(nofollow(a)) - return; - if(p->pcond != P && a != ACALL) { - /* - * some kind of conditional branch. - * recurse to follow one path. - * continue loop on the other. - */ - if((q = brchain(p->pcond)) != P) - p->pcond = q; - if((q = brchain(p->link)) != P) - p->link = q; - if(p->from.type == D_CONST) { - if(p->from.offset == 1) { - /* - * expect conditional jump to be taken. - * rewrite so that's the fall-through case. - */ - p->as = relinv(a); - q = p->link; - p->link = p->pcond; - p->pcond = q; - } - } else { - q = p->link; - if(q->mark) - if(a != ALOOP) { - p->as = relinv(a); - p->link = p->pcond; - p->pcond = q; - } - } - xfol(p->link, last); - if(p->pcond->mark) - return; - p = p->pcond; - 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 -patch(void) -{ - int32 c; - Prog *p, *q; - Sym *s; - int32 vexit; - Sym *plan9_tos; - - 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; - - plan9_tos = S; - if(HEADTYPE == Hplan9x32) - plan9_tos = lookup("_tos", 0); - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - if(HEADTYPE == Hwindows) { - // Convert - // op n(GS), reg - // to - // MOVL 0x14(FS), reg - // op n(reg), reg - // The purpose of this patch is to fix some accesses - // to extern register variables (TLS) on Windows, as - // a different method is used to access them. - if(p->from.type == D_INDIR+D_GS - && p->to.type >= D_AX && p->to.type <= D_DI) { - q = appendp(p); - q->from = p->from; - q->from.type = D_INDIR + p->to.type; - q->to = p->to; - q->as = p->as; - p->as = AMOVL; - p->from.type = D_INDIR+D_FS; - p->from.offset = 0x14; - } - } - if(HEADTYPE == Hlinux) { - // Running binaries under Xen requires using - // MOVL 0(GS), reg - // and then off(reg) instead of saying off(GS) directly - // when the offset is negative. - // In external mode we just produce a reloc. - if(p->from.type == D_INDIR+D_GS && p->from.offset < 0 - && p->to.type >= D_AX && p->to.type <= D_DI) { - if(linkmode != LinkExternal) { - q = appendp(p); - q->from = p->from; - q->from.type = D_INDIR + p->to.type; - q->to = p->to; - q->as = p->as; - p->as = AMOVL; - p->from.type = D_INDIR+D_GS; - p->from.offset = 0; - } else { - // Add signals to relocate. - p->from.index = D_GS; - p->from.scale = 1; - } - } - } - if(HEADTYPE == Hplan9x32) { - if(p->from.type == D_INDIR+D_GS - && p->to.type >= D_AX && p->to.type <= D_DI) { - q = appendp(p); - q->from = p->from; - q->from.type = D_INDIR + p->to.type; - q->to = p->to; - q->as = p->as; - p->as = AMOVL; - p->from.type = D_EXTERN; - p->from.sym = plan9_tos; - p->from.offset = 0; - } - } - if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) { - s = p->to.sym; - if(p->to.type == D_INDIR+D_ADDR) { - /* skip check if this is an indirect call (CALL *symbol(SB)) */ - continue; - } else if(s) { - if(debug['c']) - Bprint(&bso, "%s calls %s\n", TNAME, s->name); - if((s->type&SMASK) != STEXT) { - /* diag prints TNAME first */ - diag("undefined: %s", s->name); - s->type = STEXT; - s->value = vexit; - continue; // avoid more error messages - } - if(s->text == nil) - continue; - p->to.type = D_BRANCH; - p->to.offset = s->text->pc; - p->pcond = s->text; - continue; - } - } - if(p->to.type != D_BRANCH) - continue; - c = p->to.offset; - for(q = cursym->text; q != P;) { - if(c == q->pc) - break; - if(q->forwd != P && c >= q->forwd->pc) - q = q->forwd; - else - q = q->link; - } - if(q == P) { - diag("branch out of range in %s (%#ux)\n%P [%s]", - TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>"); - p->to.type = D_NONE; - } - p->pcond = q; - } - } - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(cursym->text == nil || cursym->p != nil) - continue; - - for(p = cursym->text; p != P; p = p->link) { - p->mark = 0; /* initialization for follow */ - if(p->pcond != P) { - p->pcond = brloop(p->pcond); - if(p->pcond != P) - if(p->to.type == D_BRANCH) - p->to.offset = p->pcond->pc; - } - } - } -} - -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; -} - -static Prog* load_g_cx(Prog*); -static Prog* stacksplit(Prog*, int32, Prog**); - -static Sym *plan9_tos; -static Prog *pmorestack; -static Sym *symmorestack; - -void -dostkoff(void) -{ - Prog *p, *q; - int32 autoffset, deltasp; - int a; - - pmorestack = P; - symmorestack = lookup("runtime.morestack", 0); - - if(symmorestack->type != STEXT) - diag("runtime.morestack not defined"); - else { - pmorestack = symmorestack->text; - symmorestack->text->from.scale |= NOSPLIT; - } - - plan9_tos = S; - if(HEADTYPE == Hplan9x32) - plan9_tos = lookup("_tos", 0); - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(cursym->text == nil || cursym->text->link == nil) - continue; - - p = cursym->text; - autoffset = p->to.offset; - if(autoffset < 0) - autoffset = 0; - - q = P; - - if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) { - p = appendp(p); - p = load_g_cx(p); // load g into CX - } - if(!(cursym->text->from.scale & NOSPLIT)) - p = stacksplit(p, autoffset, &q); // emit split check - - if(autoffset) { - p = appendp(p); - p->as = AADJSP; - p->from.type = D_CONST; - p->from.offset = autoffset; - p->spadj = autoffset; - } else { - // zero-byte stack adjustment. - // Insert a fake non-zero adjustment so that stkcheck can - // recognize the end of the stack-splitting prolog. - p = appendp(p); - p->as = ANOP; - p->spadj = -PtrSize; - p = appendp(p); - p->as = ANOP; - p->spadj = PtrSize; - } - if(q != P) - q->pcond = p; - deltasp = autoffset; - - if(cursym->text->from.scale & WRAPPER) { - // g->panicwrap += autoffset + PtrSize; - p = appendp(p); - p->as = AADDL; - p->from.type = D_CONST; - p->from.offset = autoffset + PtrSize; - p->to.type = D_INDIR+D_CX; - p->to.offset = 2*PtrSize; - } - - if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) { - // 8l -Z means zero the stack frame on entry. - // This slows down function calls but can help avoid - // false positives in garbage collection. - p = appendp(p); - p->as = AMOVL; - p->from.type = D_SP; - p->to.type = D_DI; - - p = appendp(p); - p->as = AMOVL; - p->from.type = D_CONST; - p->from.offset = autoffset/4; - p->to.type = D_CX; - - p = appendp(p); - p->as = AMOVL; - p->from.type = D_CONST; - p->from.offset = 0; - p->to.type = D_AX; - - p = appendp(p); - p->as = AREP; - - p = appendp(p); - p->as = ASTOSL; - } - - for(; p != P; p = p->link) { - 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; - p->spadj = 4; - continue; - case APUSHW: - case APUSHFW: - deltasp += 2; - p->spadj = 2; - continue; - case APOPL: - case APOPFL: - deltasp -= 4; - p->spadj = -4; - continue; - case APOPW: - case APOPFW: - deltasp -= 2; - p->spadj = -2; - continue; - case ARET: - break; - } - - if(autoffset != deltasp) - diag("unbalanced PUSH/POP"); - - if(cursym->text->from.scale & WRAPPER) { - p = load_g_cx(p); - p = appendp(p); - // g->panicwrap -= autoffset + PtrSize; - p->as = ASUBL; - p->from.type = D_CONST; - p->from.offset = autoffset + PtrSize; - p->to.type = D_INDIR+D_CX; - p->to.offset = 2*PtrSize; - p = appendp(p); - p->as = ARET; - } - - if(autoffset) { - p->as = AADJSP; - p->from.type = D_CONST; - p->from.offset = -autoffset; - p->spadj = -autoffset; - p = appendp(p); - p->as = ARET; - // If there are instructions following - // this ARET, they come from a branch - // with the same stackframe, so undo - // the cleanup. - p->spadj = +autoffset; - } - if(p->to.sym) // retjmp - p->as = AJMP; - } - } -} - -// Append code to p to load g into cx. -// Overwrites p with the first instruction (no first appendp). -// Overwriting p is unusual but it lets use this in both the -// prologue (caller must call appendp first) and in the epilogue. -// Returns last new instruction. -static Prog* -load_g_cx(Prog *p) -{ - switch(HEADTYPE) { - case Hwindows: - p->as = AMOVL; - p->from.type = D_INDIR+D_FS; - p->from.offset = 0x14; - p->to.type = D_CX; - - p = appendp(p); - p->as = AMOVL; - p->from.type = D_INDIR+D_CX; - p->from.offset = 0; - p->to.type = D_CX; - break; - - case Hlinux: - if(linkmode != LinkExternal) { - p->as = AMOVL; - p->from.type = D_INDIR+D_GS; - p->from.offset = 0; - p->to.type = D_CX; - - p = appendp(p); - p->as = AMOVL; - p->from.type = D_INDIR+D_CX; - p->from.offset = tlsoffset + 0; - p->to.type = D_CX; - } else { - p->as = AMOVL; - p->from.type = D_INDIR+D_GS; - p->from.offset = tlsoffset + 0; - p->to.type = D_CX; - p->from.index = D_GS; - p->from.scale = 1; - } - break; - - case Hplan9x32: - p->as = AMOVL; - p->from.type = D_EXTERN; - p->from.sym = plan9_tos; - p->to.type = D_CX; - - p = appendp(p); - p->as = AMOVL; - p->from.type = D_INDIR+D_CX; - p->from.offset = tlsoffset + 0; - p->to.type = D_CX; - break; - - default: - p->as = AMOVL; - p->from.type = D_INDIR+D_GS; - p->from.offset = tlsoffset + 0; - p->to.type = D_CX; - } - return p; -} - -// Append code to p to check for stack split. -// Appends to (does not overwrite) p. -// Assumes g is in CX. -// Returns last new instruction. -// On return, *jmpok is the instruction that should jump -// to the stack frame allocation if no split is needed. -static Prog* -stacksplit(Prog *p, int32 framesize, Prog **jmpok) -{ - Prog *q, *q1; - int arg; - - if(debug['K']) { - // 8l -K means check not only for stack - // overflow but stack underflow. - // On underflow, INT 3 (breakpoint). - // Underflow itself is rare but this also - // catches out-of-sync stack guard info. - p = appendp(p); - p->as = ACMPL; - p->from.type = D_INDIR+D_CX; - p->from.offset = 4; - p->to.type = D_SP; - - p = appendp(p); - p->as = AJCC; - p->to.type = D_BRANCH; - p->to.offset = 4; - q1 = p; - - p = appendp(p); - p->as = AINT; - p->from.type = D_CONST; - p->from.offset = 3; - - p = appendp(p); - p->as = ANOP; - q1->pcond = p; - } - q1 = P; - - if(framesize <= StackSmall) { - // small stack: SP <= stackguard - // CMPL SP, stackguard - p = appendp(p); - p->as = ACMPL; - p->from.type = D_SP; - p->to.type = D_INDIR+D_CX; - } else if(framesize <= StackBig) { - // large stack: SP-framesize <= stackguard-StackSmall - // LEAL -(framesize-StackSmall)(SP), AX - // CMPL AX, stackguard - p = appendp(p); - p->as = ALEAL; - p->from.type = D_INDIR+D_SP; - p->from.offset = -(framesize-StackSmall); - p->to.type = D_AX; - - p = appendp(p); - p->as = ACMPL; - p->from.type = D_AX; - p->to.type = D_INDIR+D_CX; - } else { - // Such a large stack we need to protect against wraparound - // if SP is close to zero. - // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) - // The +StackGuard on both sides is required to keep the left side positive: - // SP is allowed to be slightly below stackguard. See stack.h. - // - // Preemption sets stackguard to StackPreempt, a very large value. - // That breaks the math above, so we have to check for that explicitly. - // MOVL stackguard, CX - // CMPL CX, $StackPreempt - // JEQ label-of-call-to-morestack - // LEAL StackGuard(SP), AX - // SUBL stackguard, AX - // CMPL AX, $(framesize+(StackGuard-StackSmall)) - p = appendp(p); - p->as = AMOVL; - p->from.type = D_INDIR+D_CX; - p->from.offset = 0; - p->to.type = D_SI; - - p = appendp(p); - p->as = ACMPL; - p->from.type = D_SI; - p->to.type = D_CONST; - p->to.offset = (uint32)StackPreempt; - - p = appendp(p); - p->as = AJEQ; - p->to.type = D_BRANCH; - q1 = p; - - p = appendp(p); - p->as = ALEAL; - p->from.type = D_INDIR+D_SP; - p->from.offset = StackGuard; - p->to.type = D_AX; - - p = appendp(p); - p->as = ASUBL; - p->from.type = D_SI; - p->from.offset = 0; - p->to.type = D_AX; - - p = appendp(p); - p->as = ACMPL; - p->from.type = D_AX; - p->to.type = D_CONST; - p->to.offset = framesize+(StackGuard-StackSmall); - } - - // common - p = appendp(p); - p->as = AJHI; - p->to.type = D_BRANCH; - p->to.offset = 4; - q = p; - - p = appendp(p); // save frame size in DI - p->as = AMOVL; - p->to.type = D_DI; - p->from.type = D_CONST; - - // If we ask for more stack, we'll get a minimum of StackMin bytes. - // We need a stack frame large enough to hold the top-of-stack data, - // the function arguments+results, our caller's PC, our frame, - // a word for the return PC of the next call, and then the StackLimit bytes - // that must be available on entry to any function called from a function - // that did a stack check. If StackMin is enough, don't ask for a specific - // amount: then we can use the custom functions and save a few - // instructions. - if(StackTop + cursym->text->to.offset2 + PtrSize + framesize + PtrSize + StackLimit >= StackMin) - p->from.offset = (framesize+7) & ~7LL; - - arg = cursym->text->to.offset2; - if(arg == 1) // special marker for known 0 - arg = 0; - if(arg&3) - diag("misaligned argument size in stack split"); - p = appendp(p); // save arg size in AX - p->as = AMOVL; - p->to.type = D_AX; - p->from.type = D_CONST; - p->from.offset = arg; - - p = appendp(p); - p->as = ACALL; - p->to.type = D_BRANCH; - p->pcond = pmorestack; - p->to.sym = symmorestack; - - p = appendp(p); - p->as = AJMP; - p->to.type = D_BRANCH; - p->pcond = cursym->text->link; - - if(q != P) - q->pcond = p->link; - if(q1 != P) - q1->pcond = q->link; - - *jmpok = q; - return p; -} - -int32 -atolwhex(char *s) -{ - int32 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; -} diff --git a/src/cmd/8l/prof.c b/src/cmd/8l/prof.c deleted file mode 100644 index d99c5e408..000000000 --- a/src/cmd/8l/prof.c +++ /dev/null @@ -1,173 +0,0 @@ -// 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. - -// Profiling. - -#include "l.h" -#include "../ld/lib.h" - -void -doprof1(void) -{ -#ifdef NOTDEF // TODO(rsc) - Sym *s; - int32 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->size = n*4; -#endif -} - -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(cursym = textp; cursym != nil; cursym = cursym->next) { - p = cursym->text; - if(p->from.sym == s2) { - p->from.scale = 1; - ps2 = p; - } - if(p->from.sym == s4) { - p->from.scale = 1; - ps4 = p; - } - } - for(cursym = textp; cursym != nil; cursym = cursym->next) { - p = cursym->text; - - if(p->from.scale & NOPROF) /* dont profile */ - 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; - - for(; p; p=p->link) { - 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; - } - } - } -} diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c deleted file mode 100644 index acf973cab..000000000 --- a/src/cmd/8l/span.c +++ /dev/null @@ -1,1507 +0,0 @@ -// 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. - -// Instruction layout. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" - -static int32 vaddr(Adr*, Reloc*); - -void -span1(Sym *s) -{ - Prog *p, *q; - int32 c, v, loop; - uchar *bp; - int n, m, i; - - cursym = s; - - for(p = s->text; p != P; p = p->link) { - p->back = 2; // use short branches first time through - if((q = p->pcond) != P && (q->back & 2)) - p->back |= 1; // backward jump - - 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; - do { - loop = 0; - memset(s->r, 0, s->nr*sizeof s->r[0]); - s->nr = 0; - s->np = 0; - c = 0; - for(p = s->text; p != P; p = p->link) { - p->pc = c; - - // process forward jumps to p - for(q = p->comefrom; q != P; q = q->forwd) { - v = p->pc - (q->pc + q->mark); - if(q->back & 2) { // short - if(v > 127) { - loop++; - q->back ^= 2; - } - if(q->as == AJCXZW) - s->p[q->pc+2] = v; - else - s->p[q->pc+1] = v; - } else { - bp = s->p + q->pc + q->mark - 4; - *bp++ = v; - *bp++ = v>>8; - *bp++ = v>>16; - *bp = v>>24; - } - } - p->comefrom = P; - - asmins(p); - p->pc = c; - m = andptr-and; - symgrow(s, p->pc+m); - memmove(s->p+p->pc, and, m); - p->mark = m; - c += m; - } - if(++n > 20) { - diag("span must be looping"); - errorexit(); - } - } while(loop); - s->size = c; - - if(debug['a'] > 1) { - print("span1 %s %d (%d tries)\n %.6ux", s->name, s->size, n, 0); - for(i=0; i<s->np; i++) { - print(" %.2ux", s->p[i]); - if(i%16 == 15) - print("\n %.6ux", i+1); - } - if(i%16) - print("\n"); - - for(i=0; i<s->nr; i++) { - Reloc *r; - - r = &s->r[i]; - print(" rel %#.4ux/%d %s%+d\n", r->off, r->siz, r->sym->name, r->add); - } - } -} - -void -span(void) -{ - Prog *p, *q; - int32 v; - int n; - - if(debug['v']) - Bprint(&bso, "%5.2f span\n", cputime()); - - // NOTE(rsc): If we get rid of the globals we should - // be able to parallelize these iterations. - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(cursym->text == nil || cursym->text->link == nil) - continue; - - // TODO: move into span1 - for(p = cursym->text; p != P; p = p->link) { - 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; - } - } - span1(cursym); - } -} - -void -xdefine(char *p, int t, int32 v) -{ - Sym *s; - - s = lookup(p, 0); - s->type = t; - s->value = v; - s->reachable = 1; - s->special = 1; -} - -void -instinit(void) -{ - int i; - - for(i=1; optab[i].as; i++) - if(i != optab[i].as) { - diag("phase error in optab: at %A found %A", i, optab[i].as); - 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; - - ycover[Yax*Ymax + Ymm] = 1; - ycover[Ycx*Ymax + Ymm] = 1; - ycover[Yrx*Ymax + Ymm] = 1; - ycover[Yrl*Ymax + Ymm] = 1; - ycover[Ym*Ymax + Ymm] = 1; - ycover[Ymr*Ymax + Ymm] = 1; - - ycover[Ym*Ymax + Yxm] = 1; - ycover[Yxr*Ymax + Yxm] = 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; - if(i >= D_X0 && i <= D_X0+7) - reg[i] = (i-D_X0) & 7; - } -} - -int -prefixof(Adr *a) -{ - switch(a->type) { - case D_INDIR+D_CS: - return 0x2e; - case D_INDIR+D_DS: - return 0x3e; - case D_INDIR+D_ES: - return 0x26; - case D_INDIR+D_FS: - return 0x64; - case D_INDIR+D_GS: - return 0x65; - } - return 0; -} - -int -oclass(Adr *a) -{ - int32 v; - - if((a->type >= D_INDIR && a->type < 2*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; - } - //if(a->type == D_INDIR+D_ADDR) - // print("*Ycol\n"); - 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_X0+0: - case D_X0+1: - case D_X0+2: - case D_X0+3: - case D_X0+4: - case D_X0+5: - case D_X0+6: - case D_X0+7: - return Yxr; - - 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_CONST2: - 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(int scale, int index, int base) -{ - int i; - - switch(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[index] << 3; - break; - } - switch(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,%d,%d", scale, index, base); - *andptr++ = 0; - return; -} - -static void -put4(int32 v) -{ - andptr[0] = v; - andptr[1] = v>>8; - andptr[2] = v>>16; - andptr[3] = v>>24; - andptr += 4; -} - -static void -relput4(Prog *p, Adr *a) -{ - vlong v; - Reloc rel, *r; - - v = vaddr(a, &rel); - if(rel.siz != 0) { - if(rel.siz != 4) - diag("bad reloc"); - r = addrel(cursym); - *r = rel; - r->off = p->pc + andptr - and; - } - put4(v); -} - -int32 -symaddr(Sym *s) -{ - if(!s->reachable) - diag("unreachable symbol in symaddr - %s", s->name); - return s->value; -} - -static int32 -vaddr(Adr *a, Reloc *r) -{ - int t; - int32 v; - Sym *s; - - if(r != nil) - memset(r, 0, sizeof *r); - - 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(!s->reachable) - sysfatal("unreachable symbol in vaddr - %s", s->name); - if(r == nil) { - diag("need reloc for %D", a); - errorexit(); - } - r->type = D_ADDR; - r->siz = 4; - r->off = -1; - r->sym = s; - r->add = v; - v = 0; - } - } - return v; -} - -static int -istls(Adr *a) -{ - if(HEADTYPE == Hlinux) - return a->index == D_GS; - return a->type == D_INDIR+D_GS; -} - -void -asmand(Adr *a, int r) -{ - int32 v; - int t, scale; - Reloc rel; - - v = a->offset; - t = a->type; - rel.siz = 0; - if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) { - if(t < D_INDIR || t >= 2*D_INDIR) { - switch(t) { - default: - goto bad; - case D_STATIC: - case D_EXTERN: - t = D_NONE; - v = vaddr(a, &rel); - break; - case D_AUTO: - case D_PARAM: - t = D_SP; - break; - } - } else - t -= D_INDIR; - - if(t == D_NONE) { - *andptr++ = (0 << 6) | (4 << 0) | (r << 3); - asmidx(a->scale, a->index, t); - goto putrelv; - } - if(v == 0 && rel.siz == 0 && t != D_BP) { - *andptr++ = (0 << 6) | (4 << 0) | (r << 3); - asmidx(a->scale, a->index, t); - return; - } - if(v >= -128 && v < 128 && rel.siz == 0) { - *andptr++ = (1 << 6) | (4 << 0) | (r << 3); - asmidx(a->scale, a->index, t); - *andptr++ = v; - return; - } - *andptr++ = (2 << 6) | (4 << 0) | (r << 3); - asmidx(a->scale, a->index, t); - goto putrelv; - } - if(t >= D_AL && t <= D_F7 || t >= D_X0 && t <= D_X7) { - if(v) - goto bad; - *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); - return; - } - - scale = a->scale; - if(t < D_INDIR || t >= 2*D_INDIR) { - switch(a->type) { - default: - goto bad; - case D_STATIC: - case D_EXTERN: - t = D_NONE; - v = vaddr(a, &rel); - break; - case D_AUTO: - case D_PARAM: - t = D_SP; - break; - } - scale = 1; - } else - t -= D_INDIR; - - if(t == D_NONE || (D_CS <= t && t <= D_GS)) { - *andptr++ = (0 << 6) | (5 << 0) | (r << 3); - goto putrelv; - } - if(t == D_SP) { - if(v == 0 && rel.siz == 0) { - *andptr++ = (0 << 6) | (4 << 0) | (r << 3); - asmidx(scale, D_NONE, t); - return; - } - if(v >= -128 && v < 128 && rel.siz == 0) { - *andptr++ = (1 << 6) | (4 << 0) | (r << 3); - asmidx(scale, D_NONE, t); - *andptr++ = v; - return; - } - *andptr++ = (2 << 6) | (4 << 0) | (r << 3); - asmidx(scale, D_NONE, t); - goto putrelv; - } - if(t >= D_AX && t <= D_DI) { - if(v == 0 && rel.siz == 0 && t != D_BP) { - *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); - return; - } - if(v >= -128 && v < 128 && rel.siz == 0 && a->index != D_FS && a->index != D_GS) { - andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3); - andptr[1] = v; - andptr += 2; - return; - } - *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); - goto putrelv; - } - goto bad; - -putrelv: - if(rel.siz != 0) { - Reloc *r; - - if(rel.siz != 4) { - diag("bad rel"); - goto bad; - } - r = addrel(cursym); - *r = rel; - r->off = curp->pc + andptr - and; - } else if(iself && linkmode == LinkExternal && istls(a) && HEADTYPE != Hopenbsd) { - Reloc *r; - Sym *s; - - r = addrel(cursym); - r->off = curp->pc + andptr - and; - r->add = a->offset-tlsoffset; - r->xadd = r->add; - r->siz = 4; - r->type = D_TLS; - s = lookup("runtime.tlsgm", 0); - r->sym = s; - r->xsym = s; - v = 0; - } - - put4(v); - 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 */ - AIMULW, Yml, Yrl, 7, Pq,0xaf,0,0, - AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0, - 0 -}; - -// byteswapreg returns a byte-addressable register (AX, BX, CX, DX) -// which is not referenced in a->type. -// If a is empty, it returns BX to account for MULB-like instructions -// that might use DX and AX. -int -byteswapreg(Adr *a) -{ - int cana, canb, canc, cand; - - cana = canb = canc = cand = 1; - - switch(a->type) { - case D_NONE: - cana = cand = 0; - break; - case D_AX: - case D_AL: - case D_AH: - case D_INDIR+D_AX: - cana = 0; - break; - case D_BX: - case D_BL: - case D_BH: - case D_INDIR+D_BX: - canb = 0; - break; - case D_CX: - case D_CL: - case D_CH: - case D_INDIR+D_CX: - canc = 0; - break; - case D_DX: - case D_DL: - case D_DH: - case D_INDIR+D_DX: - cand = 0; - break; - } - switch(a->index) { - case D_AX: - cana = 0; - break; - case D_BX: - canb = 0; - break; - case D_CX: - canc = 0; - break; - case D_DX: - cand = 0; - break; - } - if(cana) - return D_AX; - if(canb) - return D_BX; - if(canc) - return D_CX; - if(cand) - return D_DX; - - diag("impossible byte register"); - errorexit(); - 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; - p->ft = 0; - } - if(p->to.type == from) { - p->to.type = to; - p->tt = 0; - } - - if(p->from.index == from) { - p->from.index = to; - p->ft = 0; - } - if(p->to.index == from) { - p->to.index = to; - p->tt = 0; - } - - from += D_INDIR; - if(p->from.type == from) { - p->from.type = to+D_INDIR; - p->ft = 0; - } - if(p->to.type == from) { - p->to.type = to+D_INDIR; - p->tt = 0; - } - - if(debug['Q']) - print("%P\n", p); -} - -static int -mediaop(Optab *o, int op, int osize, int z) -{ - switch(op){ - case Pm: - case Pe: - case Pf2: - case Pf3: - if(osize != 1){ - if(op != Pm) - *andptr++ = op; - *andptr++ = Pm; - op = o->op[++z]; - break; - } - default: - if(andptr == and || andptr[-1] != Pm) - *andptr++ = Pm; - break; - } - *andptr++ = op; - return z; -} - -void -doasm(Prog *p) -{ - Optab *o; - Prog *q, pp; - uchar *t; - int z, op, ft, tt, breg; - int32 v, pre; - Reloc rel, *r; - Adr *a; - - curp = p; // TODO - - pre = prefixof(&p->from); - if(pre) - *andptr++ = pre; - pre = prefixof(&p->to); - if(pre) - *andptr++ = pre; - - if(p->ft == 0) - p->ft = oclass(&p->from); - if(p->tt == 0) - p->tt = oclass(&p->to); - - ft = p->ft * Ymax; - tt = p->tt * Ymax; - o = &optab[p->as]; - 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 Pf2: /* xmm opcode escape */ - case Pf3: - *andptr++ = o->prefix; - *andptr++ = Pm; - break; - - case Pm: /* opcode escape */ - *andptr++ = Pm; - break; - - case Pe: /* 16 bit escape */ - *andptr++ = Pe; - break; - - case Pb: /* botch */ - break; - } - - 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 Zlitm_r: - for(; op = o->op[z]; z++) - *andptr++ = op; - asmand(&p->from, reg[p->to.type]); - break; - - case Zm_r: - *andptr++ = op; - asmand(&p->from, reg[p->to.type]); - break; - - case Zm2_r: - *andptr++ = op; - *andptr++ = o->op[z+1]; - asmand(&p->from, reg[p->to.type]); - break; - - case Zm_r_xm: - mediaop(o, op, t[3], z); - asmand(&p->from, reg[p->to.type]); - break; - - case Zm_r_i_xm: - mediaop(o, op, t[3], z); - asmand(&p->from, reg[p->to.type]); - *andptr++ = p->to.offset; - break; - - case Zibm_r: - while ((op = o->op[z++]) != 0) - *andptr++ = op; - asmand(&p->from, reg[p->to.type]); - *andptr++ = p->to.offset; - 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; - p->ft = 0; - asmand(&p->from, reg[p->to.type]); - p->from.index = p->from.type; - p->from.type = D_ADDR; - p->ft = 0; - 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 Zr_m_xm: - mediaop(o, op, t[3], z); - asmand(&p->to, reg[p->from.type]); - break; - - case Zr_m_i_xm: - mediaop(o, op, t[3], z); - asmand(&p->to, reg[p->from.type]); - *andptr++ = p->from.offset; - break; - - case Zo_m: - *andptr++ = op; - asmand(&p->to, o->op[z+1]); - break; - - case Zm_ibo: - *andptr++ = op; - asmand(&p->from, o->op[z+1]); - *andptr++ = vaddr(&p->to, nil); - break; - - case Zibo_m: - *andptr++ = op; - asmand(&p->to, o->op[z+1]); - *andptr++ = vaddr(&p->from, nil); - break; - - case Z_ib: - case Zib_: - if(t[2] == Zib_) - a = &p->from; - else - a = &p->to; - v = vaddr(a, nil); - *andptr++ = op; - *andptr++ = v; - break; - - case Zib_rp: - *andptr++ = op + reg[p->to.type]; - *andptr++ = vaddr(&p->from, nil); - break; - - case Zil_rp: - *andptr++ = op + reg[p->to.type]; - if(o->prefix == Pe) { - v = vaddr(&p->from, nil); - *andptr++ = v; - *andptr++ = v>>8; - } - else - relput4(p, &p->from); - break; - - case Zib_rr: - *andptr++ = op; - asmand(&p->to, reg[p->to.type]); - *andptr++ = vaddr(&p->from, nil); - break; - - case Z_il: - case Zil_: - if(t[2] == Zil_) - a = &p->from; - else - a = &p->to; - *andptr++ = op; - if(o->prefix == Pe) { - v = vaddr(a, nil); - *andptr++ = v; - *andptr++ = v>>8; - } - else - relput4(p, a); - break; - - case Zm_ilo: - case Zilo_m: - *andptr++ = op; - if(t[2] == Zilo_m) { - a = &p->from; - asmand(&p->to, o->op[z+1]); - } else { - a = &p->to; - asmand(&p->from, o->op[z+1]); - } - if(o->prefix == Pe) { - v = vaddr(a, nil); - *andptr++ = v; - *andptr++ = v>>8; - } - else - relput4(p, a); - break; - - case Zil_rr: - *andptr++ = op; - asmand(&p->to, reg[p->to.type]); - if(o->prefix == Pe) { - v = vaddr(&p->from, nil); - *andptr++ = v; - *andptr++ = v>>8; - } - else - relput4(p, &p->from); - 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 Zcall: - q = p->pcond; - if(q == nil) { - diag("call without target"); - errorexit(); - } - if(q->as != ATEXT) { - // Could handle this case by making D_PCREL - // record the Prog* instead of the Sym*, but let's - // wait until the need arises. - diag("call of non-TEXT %P", q); - errorexit(); - } - *andptr++ = op; - r = addrel(cursym); - r->off = p->pc + andptr - and; - r->type = D_PCREL; - r->siz = 4; - r->sym = q->from.sym; - put4(0); - break; - - case Zbr: - case Zjmp: - case Zloop: - q = p->pcond; - if(q == nil) { - diag("jmp/branch/loop without target"); - errorexit(); - } - if(q->as == ATEXT) { - // jump out of function - if(t[2] == Zbr) { - diag("branch to ATEXT"); - errorexit(); - } - *andptr++ = o->op[z+1]; - r = addrel(cursym); - r->off = p->pc + andptr - and; - r->sym = q->from.sym; - r->type = D_PCREL; - r->siz = 4; - put4(0); - break; - } - - // Assumes q is in this function. - // TODO: Check in input, preserve in brchain. - - // Fill in backward jump now. - if(p->back & 1) { - v = q->pc - (p->pc + 2); - if(v >= -128) { - if(p->as == AJCXZW) - *andptr++ = 0x67; - *andptr++ = op; - *andptr++ = v; - } else if(t[2] == Zloop) { - diag("loop too far: %P", p); - } else { - v -= 5-2; - if(t[2] == Zbr) { - *andptr++ = 0x0f; - v--; - } - *andptr++ = o->op[z+1]; - *andptr++ = v; - *andptr++ = v>>8; - *andptr++ = v>>16; - *andptr++ = v>>24; - } - break; - } - - // Annotate target; will fill in later. - p->forwd = q->comefrom; - q->comefrom = p; - if(p->back & 2) { // short - if(p->as == AJCXZW) - *andptr++ = 0x67; - *andptr++ = op; - *andptr++ = 0; - } else if(t[2] == Zloop) { - diag("loop too far: %P", p); - } else { - if(t[2] == Zbr) - *andptr++ = 0x0f; - *andptr++ = o->op[z+1]; - *andptr++ = 0; - *andptr++ = 0; - *andptr++ = 0; - *andptr++ = 0; - } - break; - - case Zcallcon: - case Zjmpcon: - if(t[2] == Zcallcon) - *andptr++ = op; - else - *andptr++ = o->op[z+1]; - r = addrel(cursym); - r->off = p->pc + andptr - and; - r->type = D_PCREL; - r->siz = 4; - r->add = p->to.offset; - put4(0); - break; - - case Zcallind: - *andptr++ = op; - *andptr++ = o->op[z+1]; - r = addrel(cursym); - r->off = p->pc + andptr - and; - r->type = D_ADDR; - r->siz = 4; - r->add = p->to.offset; - r->sym = p->to.sym; - put4(0); - break; - - case Zbyte: - v = vaddr(&p->from, &rel); - if(rel.siz != 0) { - rel.siz = op; - r = addrel(cursym); - *r = rel; - r->off = p->pc + andptr - and; - } - *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((breg = byteswapreg(&p->to)) != D_AX) { - *andptr++ = 0x87; /* xchg lhs,bx */ - asmand(&p->from, reg[breg]); - subreg(&pp, z, breg); - doasm(&pp); - *andptr++ = 0x87; /* xchg lhs,bx */ - asmand(&p->from, reg[breg]); - } 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((breg = byteswapreg(&p->from)) != D_AX) { - *andptr++ = 0x87; /* xchg rhs,bx */ - asmand(&p->to, reg[breg]); - subreg(&pp, z, breg); - doasm(&pp); - *andptr++ = 0x87; /* xchg rhs,bx */ - asmand(&p->to, reg[breg]); - } 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=%ux from=%ux to=%ux %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 */ - if(t[4] == Pq) { - *andptr++ = Pe; - *andptr++ = Pm; - } else - *andptr++ = t[4]; - *andptr++ = t[5]; - asmand(&p->from, reg[p->to.type]); - break; - } -} - -void -asmins(Prog *p) -{ - andptr = and; - doasm(p); - if(andptr > and+sizeof and) { - print("and[] is too short - %ld byte instruction\n", andptr - and); - errorexit(); - } -} diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 30d7c8185..ac28041fb 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -38,15 +38,14 @@ #include "../../pkg/runtime/mgc0.h" void dynreloc(void); -static vlong addaddrplus4(Sym *s, Sym *t, vlong add); /* * divide-and-conquer list-link - * sort of Sym* structures. + * sort of LSym* structures. * Used for the data block. */ int -datcmp(Sym *s1, Sym *s2) +datcmp(LSym *s1, LSym *s2) { if(s1->type != s2->type) return (int)s1->type - (int)s2->type; @@ -58,11 +57,11 @@ datcmp(Sym *s1, Sym *s2) return strcmp(s1->name, s2->name); } -Sym* -listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off) +LSym* +listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off) { - Sym *l1, *l2, *le; - #define NEXT(l) (*(Sym**)((char*)(l)+off)) + LSym *l1, *l2, *le; + #define NEXT(l) (*(LSym**)((char*)(l)+off)) if(l == 0 || NEXT(l) == 0) return l; @@ -128,31 +127,17 @@ listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off) #undef NEXT } -Reloc* -addrel(Sym *s) -{ - if(s->nr >= s->maxr) { - if(s->maxr == 0) - s->maxr = 4; - else - s->maxr <<= 1; - s->r = erealloc(s->r, s->maxr*sizeof s->r[0]); - memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]); - } - return &s->r[s->nr++]; -} - void -relocsym(Sym *s) +relocsym(LSym *s) { Reloc *r; - Sym *rs; + LSym *rs; Prog p; int32 i, off, siz, fl; vlong o; uchar *cast; - cursym = s; + ctxt->cursym = s; memset(&p, 0, sizeof p); for(r=s->r; r<s->r+s->nr; r++) { r->done = 1; @@ -218,7 +203,7 @@ relocsym(Sym *s) break; case D_PCREL: // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. - if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != cursym->sect) { + if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != ctxt->cursym->sect) { r->done = 0; // set up addend for eventual relocation via outer symbol. @@ -264,7 +249,7 @@ relocsym(Sym *s) //print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "<nil>", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o); switch(siz) { default: - cursym = s; + ctxt->cursym = s; diag("bad reloc size %#ux for %s", siz, r->sym->name); case 4: if(r->type == D_PCREL) { @@ -291,27 +276,27 @@ relocsym(Sym *s) void reloc(void) { - Sym *s; + LSym *s; if(debug['v']) Bprint(&bso, "%5.2f reloc\n", cputime()); Bflush(&bso); - for(s=textp; s!=S; s=s->next) + for(s=ctxt->textp; s!=S; s=s->next) relocsym(s); for(s=datap; s!=S; s=s->next) relocsym(s); } void -dynrelocsym(Sym *s) +dynrelocsym(LSym *s) { Reloc *r; if(HEADTYPE == Hwindows) { - Sym *rel, *targ; + LSym *rel, *targ; - rel = lookup(".rel", 0); + rel = linklookup(ctxt, ".rel", 0); if(s == rel) return; for(r=s->r; r<s->r+s->nr; r++) { @@ -323,17 +308,17 @@ dynrelocsym(Sym *s) // jmp *addr if(thechar == '8') { - adduint8(rel, 0xff); - adduint8(rel, 0x25); - addaddr(rel, targ); - adduint8(rel, 0x90); - adduint8(rel, 0x90); + adduint8(ctxt, rel, 0xff); + adduint8(ctxt, rel, 0x25); + addaddr(ctxt, rel, targ); + adduint8(ctxt, rel, 0x90); + adduint8(ctxt, rel, 0x90); } else { - adduint8(rel, 0xff); - adduint8(rel, 0x24); - adduint8(rel, 0x25); - addaddrplus4(rel, targ, 0); - adduint8(rel, 0x90); + adduint8(ctxt, rel, 0xff); + adduint8(ctxt, rel, 0x24); + adduint8(ctxt, rel, 0x25); + addaddrplus4(ctxt, rel, targ, 0); + adduint8(ctxt, rel, 0x90); } } else if(r->sym->plt >= 0) { r->sym = rel; @@ -352,7 +337,7 @@ dynrelocsym(Sym *s) void dynreloc(void) { - Sym *s; + LSym *s; // -d suppresses dynamic loader format, so we may as well not // compute these sections or mark their symbols as reachable. @@ -362,7 +347,7 @@ dynreloc(void) Bprint(&bso, "%5.2f reloc\n", cputime()); Bflush(&bso); - for(s=textp; s!=S; s=s->next) + for(s=ctxt->textp; s!=S; s=s->next) dynrelocsym(s); for(s=datap; s!=S; s=s->next) dynrelocsym(s); @@ -370,118 +355,10 @@ dynreloc(void) elfdynhash(); } -void -symgrow(Sym *s, int32 siz) -{ - if(s->np >= siz) - return; - - if(s->np > s->maxp) { - cursym = s; - diag("corrupt symbol data: np=%lld > maxp=%lld", (vlong)s->np, (vlong)s->maxp); - errorexit(); - } - - if(s->maxp < siz) { - if(s->maxp == 0) - s->maxp = 8; - while(s->maxp < siz) - s->maxp <<= 1; - s->p = erealloc(s->p, s->maxp); - memset(s->p+s->np, 0, s->maxp-s->np); - } - s->np = siz; -} - -void -savedata(Sym *s, Prog *p, char *pn) -{ - int32 off, siz, i, fl; - uchar *cast; - vlong o; - Reloc *r; - - off = p->from.offset; - siz = p->datasize; - if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100) - mangle(pn); - symgrow(s, off+siz); - - switch(p->to.type) { - default: - diag("bad data: %P", p); - break; - - case D_FCONST: - switch(siz) { - default: - case 4: - fl = ieeedtof(&p->to.ieee); - cast = (uchar*)&fl; - for(i=0; i<4; i++) - s->p[off+i] = cast[fnuxi4[i]]; - break; - case 8: - cast = (uchar*)&p->to.ieee; - for(i=0; i<8; i++) - s->p[off+i] = cast[fnuxi8[i]]; - break; - } - break; - - case D_SCONST: - for(i=0; i<siz; i++) - s->p[off+i] = p->to.scon[i]; - break; - - case D_CONST: - if(p->to.sym) - goto Addr; - o = p->to.offset; - fl = o; - cast = (uchar*)&fl; - switch(siz) { - default: - diag("bad nuxi %d\n%P", siz, p); - break; - case 1: - s->p[off] = cast[inuxi1[0]]; - break; - case 2: - for(i=0; i<2; i++) - s->p[off+i] = cast[inuxi2[i]]; - break; - case 4: - for(i=0; i<4; i++) - s->p[off+i] = cast[inuxi4[i]]; - break; - case 8: - cast = (uchar*)&o; - for(i=0; i<8; i++) - s->p[off+i] = cast[inuxi8[i]]; - break; - } - break; - - case D_ADDR: - case D_SIZE: - Addr: - r = addrel(s); - r->off = off; - r->siz = siz; - r->sym = p->to.sym; - r->type = p->to.type; - if(r->type != D_SIZE) - r->type = D_ADDR; - r->add = p->to.offset; - break; - } -} - static void -blk(Sym *start, int32 addr, int32 size) +blk(LSym *start, int32 addr, int32 size) { - Sym *sym; + LSym *sym; int32 eaddr; uchar *p, *ep; @@ -499,7 +376,7 @@ blk(Sym *start, int32 addr, int32 size) diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type); errorexit(); } - cursym = sym; + ctxt->cursym = sym; for(; addr < sym->value; addr++) cput(0); p = sym->p; @@ -523,7 +400,7 @@ blk(Sym *start, int32 addr, int32 size) void codeblk(int32 addr, int32 size) { - Sym *sym; + LSym *sym; int32 eaddr, n, epc; Prog *p; uchar *q; @@ -531,13 +408,13 @@ codeblk(int32 addr, int32 size) if(debug['a']) Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); - blk(textp, addr, size); + blk(ctxt->textp, addr, size); /* again for printing */ if(!debug['a']) return; - for(sym = textp; sym != nil; sym = sym->next) { + for(sym = ctxt->textp; sym != nil; sym = sym->next) { if(!sym->reachable) continue; if(sym->value >= addr) @@ -600,7 +477,7 @@ codeblk(int32 addr, int32 size) void datblk(int32 addr, int32 size) { - Sym *sym; + LSym *sym; int32 i, eaddr; uchar *p, *ep; char *typ, *rsname; @@ -682,28 +559,28 @@ strnput(char *s, int n) void addstrdata(char *name, char *value) { - Sym *s, *sp; + LSym *s, *sp; char *p; p = smprint("%s.str", name); - sp = lookup(p, 0); + sp = linklookup(ctxt, p, 0); free(p); addstring(sp, value); - s = lookup(name, 0); + s = linklookup(ctxt, name, 0); s->size = 0; s->dupok = 1; - addaddr(s, sp); - adduint32(s, strlen(value)); + addaddr(ctxt, s, sp); + adduint32(ctxt, s, strlen(value)); if(PtrSize == 8) - adduint32(s, 0); // round struct to pointer width + adduint32(ctxt, s, 0); // round struct to pointer width // in case reachability has already been computed sp->reachable = s->reachable; } vlong -addstring(Sym *s, char *str) +addstring(LSym *s, char *str) { int n; int32 r; @@ -715,230 +592,18 @@ addstring(Sym *s, char *str) n = strlen(str)+1; if(strcmp(s->name, ".shstrtab") == 0) elfsetstring(str, r); - symgrow(s, r+n); + symgrow(ctxt, s, r+n); memmove(s->p+r, str, n); s->size += n; return r; } -vlong -setuintxx(Sym *s, vlong off, uint64 v, vlong wid) -{ - int32 i, fl; - vlong o; - uchar *cast; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - if(s->size < off+wid) { - s->size = off+wid; - symgrow(s, s->size); - } - fl = v; - cast = (uchar*)&fl; - switch(wid) { - case 1: - s->p[off] = cast[inuxi1[0]]; - break; - case 2: - for(i=0; i<2; i++) - s->p[off+i] = cast[inuxi2[i]]; - break; - case 4: - for(i=0; i<4; i++) - s->p[off+i] = cast[inuxi4[i]]; - break; - case 8: - o = v; - cast = (uchar*)&o; - for(i=0; i<8; i++) - s->p[off+i] = cast[inuxi8[i]]; - break; - } - return off+wid; -} - -vlong -adduintxx(Sym *s, uint64 v, int wid) -{ - vlong off; - - off = s->size; - setuintxx(s, off, v, wid); - return off; -} - -vlong -adduint8(Sym *s, uint8 v) -{ - return adduintxx(s, v, 1); -} - -vlong -adduint16(Sym *s, uint16 v) -{ - return adduintxx(s, v, 2); -} - -vlong -adduint32(Sym *s, uint32 v) -{ - return adduintxx(s, v, 4); -} - -vlong -adduint64(Sym *s, uint64 v) -{ - return adduintxx(s, v, 8); -} - -vlong -setuint8(Sym *s, vlong r, uint8 v) -{ - return setuintxx(s, r, v, 1); -} - -vlong -setuint16(Sym *s, vlong r, uint16 v) -{ - return setuintxx(s, r, v, 2); -} - -vlong -setuint32(Sym *s, vlong r, uint32 v) -{ - return setuintxx(s, r, v, 4); -} - -vlong -setuint64(Sym *s, vlong r, uint64 v) -{ - return setuintxx(s, r, v, 8); -} - -vlong -addaddrplus(Sym *s, Sym *t, vlong add) -{ - vlong i; - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - i = s->size; - s->size += PtrSize; - symgrow(s, s->size); - r = addrel(s); - r->sym = t; - r->off = i; - r->siz = PtrSize; - r->type = D_ADDR; - r->add = add; - return i + r->siz; -} - -static vlong -addaddrplus4(Sym *s, Sym *t, vlong add) -{ - vlong i; - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - i = s->size; - s->size += 4; - symgrow(s, s->size); - r = addrel(s); - r->sym = t; - r->off = i; - r->siz = 4; - r->type = D_ADDR; - r->add = add; - return i + r->siz; -} - -vlong -addpcrelplus(Sym *s, Sym *t, vlong add) -{ - vlong i; - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - i = s->size; - s->size += 4; - symgrow(s, s->size); - r = addrel(s); - r->sym = t; - r->off = i; - r->add = add; - r->type = D_PCREL; - r->siz = 4; - return i + r->siz; -} - -vlong -addaddr(Sym *s, Sym *t) -{ - return addaddrplus(s, t, 0); -} - -vlong -setaddrplus(Sym *s, vlong off, Sym *t, vlong add) -{ - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - if(off+PtrSize > s->size) { - s->size = off + PtrSize; - symgrow(s, s->size); - } - r = addrel(s); - r->sym = t; - r->off = off; - r->siz = PtrSize; - r->type = D_ADDR; - r->add = add; - return off + r->siz; -} - -vlong -setaddr(Sym *s, vlong off, Sym *t) -{ - return setaddrplus(s, off, t, 0); -} - -vlong -addsize(Sym *s, Sym *t) -{ - vlong i; - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - i = s->size; - s->size += PtrSize; - symgrow(s, s->size); - r = addrel(s); - r->sym = t; - r->off = i; - r->siz = PtrSize; - r->type = D_SIZE; - return i + r->siz; -} - void dosymtype(void) { - Sym *s; + LSym *s; - for(s = allsym; s != nil; s = s->allsym) { + for(s = ctxt->allsym; s != nil; s = s->allsym) { if(s->np > 0) { if(s->type == SBSS) s->type = SDATA; @@ -949,7 +614,7 @@ dosymtype(void) } static int32 -symalign(Sym *s) +symalign(LSym *s) { int32 align; @@ -965,7 +630,7 @@ symalign(Sym *s) } static vlong -aligndatsize(vlong datsize, Sym *s) +aligndatsize(vlong datsize, LSym *s) { return rnd(datsize, symalign(s)); } @@ -973,7 +638,7 @@ aligndatsize(vlong datsize, Sym *s) // maxalign returns the maximum required alignment for // the list of symbols s; the list stops when s->type exceeds type. static int32 -maxalign(Sym *s, int type) +maxalign(LSym *s, int type) { int32 align, max; @@ -987,10 +652,10 @@ maxalign(Sym *s, int type) } static void -gcaddsym(Sym *gc, Sym *s, vlong off) +gcaddsym(LSym *gc, LSym *s, vlong off) { vlong a; - Sym *gotype; + LSym *gotype; if(s->size < PtrSize) return; @@ -1000,22 +665,22 @@ gcaddsym(Sym *gc, Sym *s, vlong off) gotype = s->gotype; if(gotype != nil) { //print("gcaddsym: %s %d %s\n", s->name, s->size, gotype->name); - adduintxx(gc, GC_CALL, PtrSize); - adduintxx(gc, off, PtrSize); - addpcrelplus(gc, decodetype_gc(gotype), 3*PtrSize+4); + adduintxx(ctxt, gc, GC_CALL, PtrSize); + adduintxx(ctxt, gc, off, PtrSize); + addpcrelplus(ctxt, gc, decodetype_gc(gotype), 3*PtrSize+4); if(PtrSize == 8) - adduintxx(gc, 0, 4); + adduintxx(ctxt, gc, 0, 4); } else { //print("gcaddsym: %s %d <unknown type>\n", s->name, s->size); for(a = -off&(PtrSize-1); a+PtrSize<=s->size; a+=PtrSize) { - adduintxx(gc, GC_APTR, PtrSize); - adduintxx(gc, off+a, PtrSize); + adduintxx(ctxt, gc, GC_APTR, PtrSize); + adduintxx(ctxt, gc, off+a, PtrSize); } } } void -growdatsize(vlong *datsizep, Sym *s) +growdatsize(vlong *datsizep, LSym *s) { vlong datsize; @@ -1034,24 +699,24 @@ dodata(void) vlong datsize; Section *sect; Segment *segro; - Sym *s, *last, **l; - Sym *gcdata1, *gcbss1; + LSym *s, *last, **l; + LSym *gcdata1, *gcbss1; if(debug['v']) Bprint(&bso, "%5.2f dodata\n", cputime()); Bflush(&bso); - gcdata1 = lookup("gcdata", 0); - gcbss1 = lookup("gcbss", 0); + gcdata1 = linklookup(ctxt, "gcdata", 0); + gcbss1 = linklookup(ctxt, "gcbss", 0); // size of .data and .bss section. the zero value is later replaced by the actual size of the section. - adduintxx(gcdata1, 0, PtrSize); - adduintxx(gcbss1, 0, PtrSize); + adduintxx(ctxt, gcdata1, 0, PtrSize); + adduintxx(ctxt, gcbss1, 0, PtrSize); last = nil; datap = nil; - for(s=allsym; s!=S; s=s->allsym) { + for(s=ctxt->allsym; s!=S; s=s->allsym) { if(!s->reachable || s->special) continue; if(STEXT < s->type && s->type < SXREF) { @@ -1092,7 +757,7 @@ dodata(void) } *l = nil; - datap = listsort(datap, datcmp, offsetof(Sym, next)); + datap = listsort(datap, datcmp, offsetof(LSym, next)); /* * allocate sections. list is sorted by type, @@ -1128,8 +793,8 @@ dodata(void) sect->align = maxalign(s, SINITARR-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("noptrdata", 0)->sect = sect; - lookup("enoptrdata", 0)->sect = sect; + linklookup(ctxt, "noptrdata", 0)->sect = sect; + linklookup(ctxt, "enoptrdata", 0)->sect = sect; for(; s != nil && s->type < SINITARR; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1159,11 +824,11 @@ dodata(void) sect->align = maxalign(s, SBSS-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("data", 0)->sect = sect; - lookup("edata", 0)->sect = sect; + linklookup(ctxt, "data", 0)->sect = sect; + linklookup(ctxt, "edata", 0)->sect = sect; for(; s != nil && s->type < SBSS; s = s->next) { if(s->type == SINITARR) { - cursym = s; + ctxt->cursym = s; diag("unexpected symbol type %d", s->type); } s->sect = sect; @@ -1175,16 +840,16 @@ dodata(void) } sect->len = datsize - sect->vaddr; - adduintxx(gcdata1, GC_END, PtrSize); - setuintxx(gcdata1, 0, sect->len, PtrSize); + adduintxx(ctxt, gcdata1, GC_END, PtrSize); + setuintxx(ctxt, gcdata1, 0, sect->len, PtrSize); /* bss */ sect = addsection(&segdata, ".bss", 06); sect->align = maxalign(s, SNOPTRBSS-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("bss", 0)->sect = sect; - lookup("ebss", 0)->sect = sect; + linklookup(ctxt, "bss", 0)->sect = sect; + linklookup(ctxt, "ebss", 0)->sect = sect; for(; s != nil && s->type < SNOPTRBSS; s = s->next) { s->sect = sect; datsize = aligndatsize(datsize, s); @@ -1194,16 +859,16 @@ dodata(void) } sect->len = datsize - sect->vaddr; - adduintxx(gcbss1, GC_END, PtrSize); - setuintxx(gcbss1, 0, sect->len, PtrSize); + adduintxx(ctxt, gcbss1, GC_END, PtrSize); + setuintxx(ctxt, gcbss1, 0, sect->len, PtrSize); /* pointer-free bss */ sect = addsection(&segdata, ".noptrbss", 06); sect->align = maxalign(s, SNOPTRBSS); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("noptrbss", 0)->sect = sect; - lookup("enoptrbss", 0)->sect = sect; + linklookup(ctxt, "noptrbss", 0)->sect = sect; + linklookup(ctxt, "enoptrbss", 0)->sect = sect; for(; s != nil && s->type == SNOPTRBSS; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1211,7 +876,7 @@ dodata(void) growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; - lookup("end", 0)->sect = sect; + linklookup(ctxt, "end", 0)->sect = sect; // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. if(datsize != (uint32)datsize) { @@ -1233,7 +898,7 @@ dodata(void) } if(s != nil) { - cursym = nil; + ctxt->cursym = nil; diag("unexpected symbol type %d for %s", s->type, s->name); } @@ -1274,8 +939,8 @@ dodata(void) sect->align = maxalign(s, STYPELINK-1); datsize = rnd(datsize, sect->align); sect->vaddr = 0; - lookup("rodata", 0)->sect = sect; - lookup("erodata", 0)->sect = sect; + linklookup(ctxt, "rodata", 0)->sect = sect; + linklookup(ctxt, "erodata", 0)->sect = sect; for(; s != nil && s->type < STYPELINK; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1290,8 +955,8 @@ dodata(void) sect->align = maxalign(s, STYPELINK); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("typelink", 0)->sect = sect; - lookup("etypelink", 0)->sect = sect; + linklookup(ctxt, "typelink", 0)->sect = sect; + linklookup(ctxt, "etypelink", 0)->sect = sect; for(; s != nil && s->type == STYPELINK; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1306,8 +971,8 @@ dodata(void) sect->align = maxalign(s, SPCLNTAB-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("symtab", 0)->sect = sect; - lookup("esymtab", 0)->sect = sect; + linklookup(ctxt, "symtab", 0)->sect = sect; + linklookup(ctxt, "esymtab", 0)->sect = sect; for(; s != nil && s->type < SPCLNTAB; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1322,8 +987,8 @@ dodata(void) sect->align = maxalign(s, SELFROSECT-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("pclntab", 0)->sect = sect; - lookup("epclntab", 0)->sect = sect; + linklookup(ctxt, "pclntab", 0)->sect = sect; + linklookup(ctxt, "epclntab", 0)->sect = sect; for(; s != nil && s->type < SELFROSECT; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1368,7 +1033,7 @@ textaddress(void) uvlong va; Prog *p; Section *sect; - Sym *sym, *sub; + LSym *sym, *sub; addsection(&segtext, ".text", 05); @@ -1377,11 +1042,11 @@ textaddress(void) // and then letting threads copy down, but probably not worth it. sect = segtext.sect; sect->align = FuncAlign; - lookup("text", 0)->sect = sect; - lookup("etext", 0)->sect = sect; + linklookup(ctxt, "text", 0)->sect = sect; + linklookup(ctxt, "etext", 0)->sect = sect; va = INITTEXT; sect->vaddr = va; - for(sym = textp; sym != nil; sym = sym->next) { + for(sym = ctxt->textp; sym != nil; sym = sym->next) { sym->sect = sect; if(sym->type & SSUB) continue; @@ -1396,7 +1061,7 @@ textaddress(void) p->pc += sub->value; } if(sym->size == 0 && sym->sub != S) { - cursym = sym; + ctxt->cursym = sym; } va += sym->size; } @@ -1409,7 +1074,7 @@ address(void) { Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss; Section *typelink; - Sym *sym, *sub; + LSym *sym, *sub; uvlong va; vlong vlen; @@ -1451,7 +1116,7 @@ address(void) segdata.filelen = 0; if(HEADTYPE == Hwindows) segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); - if(HEADTYPE == Hplan9x64 || HEADTYPE == Hplan9x32) + if(HEADTYPE == Hplan9) segdata.fileoff = segtext.fileoff + segtext.filelen; data = nil; noptr = nil; @@ -1485,7 +1150,7 @@ address(void) pclntab = symtab->next; for(sym = datap; sym != nil; sym = sym->next) { - cursym = sym; + ctxt->cursym = sym; sym->value += sym->sect->vaddr; for(sub = sym->sub; sub != nil; sub = sub->sub) sub->value += sym->value; @@ -1498,13 +1163,13 @@ address(void) xdefine("typelink", SRODATA, typelink->vaddr); xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len); - sym = lookup("gcdata", 0); + sym = linklookup(ctxt, "gcdata", 0); xdefine("egcdata", SRODATA, symaddr(sym) + sym->size); - lookup("egcdata", 0)->sect = sym->sect; + linklookup(ctxt, "egcdata", 0)->sect = sym->sect; - sym = lookup("gcbss", 0); + sym = linklookup(ctxt, "gcbss", 0); xdefine("egcbss", SRODATA, symaddr(sym) + sym->size); - lookup("egcbss", 0)->sect = sym->sect; + linklookup(ctxt, "egcbss", 0)->sect = sym->sect; xdefine("symtab", SRODATA, symtab->vaddr); xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len); diff --git a/src/cmd/ld/decodesym.c b/src/cmd/ld/decodesym.c index ab3f4fbd5..3859d1c6d 100644 --- a/src/cmd/ld/decodesym.c +++ b/src/cmd/ld/decodesym.c @@ -11,7 +11,7 @@ // ../gc/reflect.c stuffs in these. static Reloc* -decode_reloc(Sym *s, int32 off) +decode_reloc(LSym *s, int32 off) { int i; @@ -21,8 +21,8 @@ decode_reloc(Sym *s, int32 off) return nil; } -static Sym* -decode_reloc_sym(Sym *s, int32 off) +static LSym* +decode_reloc_sym(LSym *s, int32 off) { Reloc *r; @@ -69,86 +69,86 @@ decode_inuxi(uchar* p, int sz) // Type.commonType.kind uint8 -decodetype_kind(Sym *s) +decodetype_kind(LSym *s) { return s->p[1*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f } // Type.commonType.size vlong -decodetype_size(Sym *s) +decodetype_size(LSym *s) { return decode_inuxi(s->p, PtrSize); // 0x8 / 0x10 } // Type.commonType.gc -Sym* -decodetype_gc(Sym *s) +LSym* +decodetype_gc(LSym *s) { return decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize); } // Type.ArrayType.elem and Type.SliceType.Elem -Sym* -decodetype_arrayelem(Sym *s) +LSym* +decodetype_arrayelem(LSym *s) { return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 } vlong -decodetype_arraylen(Sym *s) +decodetype_arraylen(LSym *s) { return decode_inuxi(s->p + CommonSize+PtrSize, PtrSize); } // Type.PtrType.elem -Sym* -decodetype_ptrelem(Sym *s) +LSym* +decodetype_ptrelem(LSym *s) { return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 } // Type.MapType.key, elem -Sym* -decodetype_mapkey(Sym *s) +LSym* +decodetype_mapkey(LSym *s) { return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 } -Sym* -decodetype_mapvalue(Sym *s) +LSym* +decodetype_mapvalue(LSym *s) { return decode_reloc_sym(s, CommonSize+PtrSize); // 0x20 / 0x38 } // Type.ChanType.elem -Sym* -decodetype_chanelem(Sym *s) +LSym* +decodetype_chanelem(LSym *s) { return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 } // Type.FuncType.dotdotdot int -decodetype_funcdotdotdot(Sym *s) +decodetype_funcdotdotdot(LSym *s) { return s->p[CommonSize]; } // Type.FuncType.in.len int -decodetype_funcincount(Sym *s) +decodetype_funcincount(LSym *s) { return decode_inuxi(s->p + CommonSize+2*PtrSize, IntSize); } int -decodetype_funcoutcount(Sym *s) +decodetype_funcoutcount(LSym *s) { return decode_inuxi(s->p + CommonSize+3*PtrSize + 2*IntSize, IntSize); } -Sym* -decodetype_funcintype(Sym *s, int i) +LSym* +decodetype_funcintype(LSym *s, int i) { Reloc *r; @@ -158,8 +158,8 @@ decodetype_funcintype(Sym *s, int i) return decode_reloc_sym(r->sym, r->add + i * PtrSize); } -Sym* -decodetype_funcouttype(Sym *s, int i) +LSym* +decodetype_funcouttype(LSym *s, int i) { Reloc *r; @@ -171,7 +171,7 @@ decodetype_funcouttype(Sym *s, int i) // Type.StructType.fields.Slice::len int -decodetype_structfieldcount(Sym *s) +decodetype_structfieldcount(LSym *s) { return decode_inuxi(s->p + CommonSize + PtrSize, IntSize); } @@ -181,7 +181,7 @@ enum { }; // Type.StructType.fields[]-> name, typ and offset. char* -decodetype_structfieldname(Sym *s, int i) +decodetype_structfieldname(LSym *s, int i) { Reloc *r; @@ -195,21 +195,21 @@ decodetype_structfieldname(Sym *s, int i) return (char*) r->sym->p + r->add; // the c-string } -Sym* -decodetype_structfieldtype(Sym *s, int i) +LSym* +decodetype_structfieldtype(LSym *s, int i) { return decode_reloc_sym(s, CommonSize + PtrSize + 2*IntSize + i*StructFieldSize + 2*PtrSize); } vlong -decodetype_structfieldoffs(Sym *s, int i) +decodetype_structfieldoffs(LSym *s, int i) { return decode_inuxi(s->p + CommonSize + PtrSize + 2*IntSize + i*StructFieldSize + 4*PtrSize, IntSize); } // InterfaceTYpe.methods.len vlong -decodetype_ifacemethodcount(Sym *s) +decodetype_ifacemethodcount(LSym *s) { return decode_inuxi(s->p + CommonSize + PtrSize, IntSize); } diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index c832bcc94..8170abe33 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -27,19 +27,19 @@ static vlong abbrevo; static vlong abbrevsize; -static Sym* abbrevsym; +static LSym* abbrevsym; static vlong abbrevsympos; static vlong lineo; static vlong linesize; -static Sym* linesym; +static LSym* linesym; static vlong linesympos; static vlong infoo; // also the base for DWDie->offs and reference attributes. static vlong infosize; -static Sym* infosym; +static LSym* infosym; static vlong infosympos; static vlong frameo; static vlong framesize; -static Sym* framesym; +static LSym* framesym; static vlong framesympos; static vlong pubnameso; static vlong pubnamessize; @@ -50,19 +50,19 @@ static vlong arangessize; static vlong gdbscripto; static vlong gdbscriptsize; -static Sym *infosec; +static LSym *infosec; static vlong inforeloco; static vlong inforelocsize; -static Sym *arangessec; +static LSym *arangessec; static vlong arangesreloco; static vlong arangesrelocsize; -static Sym *linesec; +static LSym *linesec; static vlong linereloco; static vlong linerelocsize; -static Sym *framesec; +static LSym *framesec; static vlong framereloco; static vlong framerelocsize; @@ -594,7 +594,7 @@ find_or_diag(DWDie *die, char* name) } static void -adddwarfrel(Sym* sec, Sym* sym, vlong offsetbase, int siz, vlong addend) +adddwarfrel(LSym* sec, LSym* sym, vlong offsetbase, int siz, vlong addend) { Reloc *r; @@ -639,8 +639,8 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) switch(form) { case DW_FORM_addr: // address if(linkmode == LinkExternal) { - value -= ((Sym*)data)->value; - adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value); + value -= ((LSym*)data)->value; + adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value); break; } addrput(value); @@ -651,8 +651,8 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) cput(1+PtrSize); cput(DW_OP_addr); if(linkmode == LinkExternal) { - value -= ((Sym*)data)->value; - adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value); + value -= ((LSym*)data)->value; + adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value); break; } addrput(value); @@ -847,7 +847,7 @@ newmemberoffsetattr(DWDie *die, int32 offs) // GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a // location expression that evals to a const. static void -newabslocexprattr(DWDie *die, vlong addr, Sym *sym) +newabslocexprattr(DWDie *die, vlong addr, LSym *sym) { newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, (char*)sym); } @@ -864,12 +864,12 @@ enum { static DWDie* defptrto(DWDie *dwtype); // below // Lookup predefined types -static Sym* +static LSym* lookup_or_diag(char *n) { - Sym *s; + LSym *s; - s = rlookup(n, 0); + s = linkrlookup(ctxt, n, 0); if (s == nil || s->size == 0) { diag("dwarf: missing type: %s", n); errorexit(); @@ -904,10 +904,10 @@ dotypedef(DWDie *parent, char *name, DWDie *def) // Define gotype, for composite ones recurse into constituents. static DWDie* -defgotype(Sym *gotype) +defgotype(LSym *gotype) { DWDie *die, *fld; - Sym *s; + LSym *s; char *name, *f; uint8 kind; vlong bytesize; @@ -1335,7 +1335,7 @@ synthesizechantypes(DWDie *die) // For use with pass.c::genasmsym static void -defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype) +defdwsymb(LSym* sym, char *s, int t, vlong v, vlong size, int ver, LSym *gotype) { DWDie *dv, *dt; @@ -1607,7 +1607,7 @@ inithist(Auto *a) absline = a->aoffset; } else if (a->type == D_FILE1) { // 'Z' // We could just fixup the current - // linehist->line, but there doesn't appear to + // linehist->lineno, but there doesn't appear to // be a guarantee that every 'Z' is preceded // by its own 'z', so do the safe thing and // update the stack and push a new Linehist @@ -1719,7 +1719,7 @@ mkvarname(char* name, int da) // flush previous compilation unit. static void -flushunit(DWDie *dwinfo, vlong pc, Sym *pcsym, vlong unitstart, int32 header_length) +flushunit(DWDie *dwinfo, vlong pc, LSym *pcsym, vlong unitstart, int32 header_length) { vlong here; @@ -1745,7 +1745,7 @@ static void writelines(void) { Prog *q; - Sym *s, *epcs; + LSym *s, *epcs; Auto *a; vlong unitstart, headerend, offs; vlong pc, epc, lc, llc, lline; @@ -1757,7 +1757,7 @@ writelines(void) char *n, *nn; if(linesec == S) - linesec = lookup(".dwarfline", 0); + linesec = linklookup(ctxt, ".dwarfline", 0); linesec->nr = 0; unitstart = -1; @@ -1771,8 +1771,8 @@ writelines(void) lineo = cpos(); dwinfo = nil; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - s = cursym; + for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) { + s = ctxt->cursym; if(s->text == P) continue; @@ -1859,7 +1859,7 @@ writelines(void) continue; for(q = s->text; q != P; q = q->link) { - lh = searchhist(q->line); + lh = searchhist(q->lineno); if (lh == nil) { diag("dwarf: corrupt history or bad absolute line: %P", q); continue; @@ -1870,11 +1870,11 @@ writelines(void) continue; } - lline = lh->line + q->line - lh->absline; + lline = lh->line + q->lineno - lh->absline; if (debug['v'] > 1) print("%6llux %s[%lld] %P\n", (vlong)q->pc, histfile[lh->file], lline, q); - if (q->line == lc) + if (q->lineno == lc) continue; if (currfile != lh->file) { currfile = lh->file; @@ -1883,7 +1883,7 @@ writelines(void) } putpclcdelta(q->pc - pc, lline - llc); pc = q->pc; - lc = q->line; + lc = q->lineno; llc = lline; } @@ -1971,11 +1971,11 @@ static void writeframes(void) { Prog *p, *q; - Sym *s; + LSym *s; vlong fdeo, fdesize, pad, cfa, pc; if(framesec == S) - framesec = lookup(".dwarfframe", 0); + framesec = linklookup(ctxt, ".dwarfframe", 0); framesec->nr = 0; frameo = cpos(); @@ -2003,8 +2003,8 @@ writeframes(void) } strnput("", pad); - for(cursym = textp; cursym != nil; cursym = cursym->next) { - s = cursym; + for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) { + s = ctxt->cursym; if(s->text == nil) continue; @@ -2067,11 +2067,11 @@ writeinfo(void) fwdcount = 0; if (infosec == S) - infosec = lookup(".dwarfinfo", 0); + infosec = linklookup(ctxt, ".dwarfinfo", 0); infosec->nr = 0; if(arangessec == S) - arangessec = lookup(".dwarfaranges", 0); + arangessec = linklookup(ctxt, ".dwarfaranges", 0); arangessec->nr = 0; for (compunit = dwroot.child; compunit; compunit = compunit->link) { @@ -2204,7 +2204,7 @@ writearanges(void) strnput("", headersize - (4+2+4+1+1)); // align to PtrSize if(linkmode == LinkExternal) - adddwarfrel(arangessec, (Sym*)b->data, sectionstart, PtrSize, b->value-((Sym*)b->data)->value); + adddwarfrel(arangessec, (LSym*)b->data, sectionstart, PtrSize, b->value-((LSym*)b->data)->value); else addrput(b->value); @@ -2239,7 +2239,7 @@ align(vlong size) } static vlong -writedwarfreloc(Sym* s) +writedwarfreloc(LSym* s) { int i; vlong start; @@ -2408,7 +2408,7 @@ enum vlong elfstrdbg[NElfStrDbg]; void -dwarfaddshstrings(Sym *shstrtab) +dwarfaddshstrings(LSym *shstrtab) { if(debug['w']) // disable dwarf return; @@ -2438,16 +2438,16 @@ dwarfaddshstrings(Sym *shstrtab) elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rel.debug_frame"); } - infosym = lookup(".debug_info", 0); + infosym = linklookup(ctxt, ".debug_info", 0); infosym->hide = 1; - abbrevsym = lookup(".debug_abbrev", 0); + abbrevsym = linklookup(ctxt, ".debug_abbrev", 0); abbrevsym->hide = 1; - linesym = lookup(".debug_line", 0); + linesym = linklookup(ctxt, ".debug_line", 0); linesym->hide = 1; - framesym = lookup(".debug_frame", 0); + framesym = linklookup(ctxt, ".debug_frame", 0); framesym->hide = 1; } } diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h index f0df2f9b1..7952a7436 100644 --- a/src/cmd/ld/dwarf.h +++ b/src/cmd/ld/dwarf.h @@ -19,7 +19,7 @@ void dwarfemitdebugsections(void); * s[ection]h[eader]str[ing]tab. Prerequisite for * dwarfaddelfheaders(). */ -void dwarfaddshstrings(Sym *shstrtab); +void dwarfaddshstrings(LSym *shstrtab); /* * Add section headers pointing to the sections emitted in diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c index 6b3638ec5..8c7ca8609 100644 --- a/src/cmd/ld/elf.c +++ b/src/cmd/ld/elf.c @@ -287,35 +287,35 @@ elfhash(uchar *name) } void -elfwritedynent(Sym *s, int tag, uint64 val) +elfwritedynent(LSym *s, int tag, uint64 val) { if(elf64) { - adduint64(s, tag); - adduint64(s, val); + adduint64(ctxt, s, tag); + adduint64(ctxt, s, val); } else { - adduint32(s, tag); - adduint32(s, val); + adduint32(ctxt, s, tag); + adduint32(ctxt, s, val); } } void -elfwritedynentsym(Sym *s, int tag, Sym *t) +elfwritedynentsym(LSym *s, int tag, LSym *t) { if(elf64) - adduint64(s, tag); + adduint64(ctxt, s, tag); else - adduint32(s, tag); - addaddr(s, t); + adduint32(ctxt, s, tag); + addaddr(ctxt, s, t); } void -elfwritedynentsymsize(Sym *s, int tag, Sym *t) +elfwritedynentsymsize(LSym *s, int tag, LSym *t) { if(elf64) - adduint64(s, tag); + adduint64(ctxt, s, tag); else - adduint32(s, tag); - addsize(s, t); + adduint32(ctxt, s, tag); + addsize(ctxt, s, t); } int @@ -561,7 +561,7 @@ haveaux: void elfdynhash(void) { - Sym *s, *sy, *dynstr; + LSym *s, *sy, *dynstr; int i, j, nbucket, b, nfile; uint32 hc, *chain, *buckets; int nsym; @@ -575,7 +575,7 @@ elfdynhash(void) return; nsym = nelfsym; - s = lookup(".hash", 0); + s = linklookup(ctxt, ".hash", 0); s->type = SELFROSECT; s->reachable = 1; @@ -591,14 +591,14 @@ elfdynhash(void) chain = malloc(nsym * sizeof chain[0]); buckets = malloc(nbucket * sizeof buckets[0]); if(need == nil || chain == nil || buckets == nil) { - cursym = nil; + ctxt->cursym = nil; diag("out of memory"); errorexit(); } memset(need, 0, nsym * sizeof need[0]); memset(chain, 0, nsym * sizeof chain[0]); memset(buckets, 0, nbucket * sizeof buckets[0]); - for(sy=allsym; sy!=S; sy=sy->allsym) { + for(sy=ctxt->allsym; sy!=S; sy=sy->allsym) { if (sy->dynid <= 0) continue; @@ -613,69 +613,69 @@ elfdynhash(void) buckets[b] = sy->dynid; } - adduint32(s, nbucket); - adduint32(s, nsym); + adduint32(ctxt, s, nbucket); + adduint32(ctxt, s, nsym); for(i = 0; i<nbucket; i++) - adduint32(s, buckets[i]); + adduint32(ctxt, s, buckets[i]); for(i = 0; i<nsym; i++) - adduint32(s, chain[i]); + adduint32(ctxt, s, chain[i]); free(chain); free(buckets); // version symbols - dynstr = lookup(".dynstr", 0); - s = lookup(".gnu.version_r", 0); + dynstr = linklookup(ctxt, ".dynstr", 0); + s = linklookup(ctxt, ".gnu.version_r", 0); i = 2; nfile = 0; for(l=needlib; l; l=l->next) { nfile++; // header - adduint16(s, 1); // table version + adduint16(ctxt, s, 1); // table version j = 0; for(x=l->aux; x; x=x->next) j++; - adduint16(s, j); // aux count - adduint32(s, addstring(dynstr, l->file)); // file string offset - adduint32(s, 16); // offset from header to first aux + adduint16(ctxt, s, j); // aux count + adduint32(ctxt, s, addstring(dynstr, l->file)); // file string offset + adduint32(ctxt, s, 16); // offset from header to first aux if(l->next) - adduint32(s, 16+j*16); // offset from this header to next + adduint32(ctxt, s, 16+j*16); // offset from this header to next else - adduint32(s, 0); + adduint32(ctxt, s, 0); for(x=l->aux; x; x=x->next) { x->num = i++; // aux struct - adduint32(s, elfhash((uchar*)x->vers)); // hash - adduint16(s, 0); // flags - adduint16(s, x->num); // other - index we refer to this by - adduint32(s, addstring(dynstr, x->vers)); // version string offset + adduint32(ctxt, s, elfhash((uchar*)x->vers)); // hash + adduint16(ctxt, s, 0); // flags + adduint16(ctxt, s, x->num); // other - index we refer to this by + adduint32(ctxt, s, addstring(dynstr, x->vers)); // version string offset if(x->next) - adduint32(s, 16); // offset from this aux to next + adduint32(ctxt, s, 16); // offset from this aux to next else - adduint32(s, 0); + adduint32(ctxt, s, 0); } } // version references - s = lookup(".gnu.version", 0); + s = linklookup(ctxt, ".gnu.version", 0); for(i=0; i<nsym; i++) { if(i == 0) - adduint16(s, 0); // first entry - no symbol + adduint16(ctxt, s, 0); // first entry - no symbol else if(need[i] == nil) - adduint16(s, 1); // global + adduint16(ctxt, s, 1); // global else - adduint16(s, need[i]->num); + adduint16(ctxt, s, need[i]->num); } free(need); - s = lookup(".dynamic", 0); + s = linklookup(ctxt, ".dynamic", 0); elfverneed = nfile; if(elfverneed) { - elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0)); + elfwritedynentsym(s, DT_VERNEED, linklookup(ctxt, ".gnu.version_r", 0)); elfwritedynent(s, DT_VERNEEDNUM, nfile); - elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0)); + elfwritedynentsym(s, DT_VERSYM, linklookup(ctxt, ".gnu.version", 0)); } elfwritedynent(s, DT_NULL, 0); } @@ -807,9 +807,9 @@ elfshreloc(Section *sect) } void -elfrelocsect(Section *sect, Sym *first) +elfrelocsect(Section *sect, LSym *first) { - Sym *sym; + LSym *sym; int32 eaddr; Reloc *r; @@ -834,7 +834,7 @@ elfrelocsect(Section *sect, Sym *first) continue; if(sym->value >= eaddr) break; - cursym = sym; + ctxt->cursym = sym; for(r = sym->r; r < sym->r+sym->nr; r++) { if(r->done) @@ -861,7 +861,7 @@ elfemitreloc(void) while(cpos()&7) cput(0); - elfrelocsect(segtext.sect, textp); + elfrelocsect(segtext.sect, ctxt->textp); for(sect=segtext.sect->next; sect!=nil; sect=sect->next) elfrelocsect(sect, datap); for(sect=segrodata.sect; sect!=nil; sect=sect->next) @@ -873,13 +873,13 @@ elfemitreloc(void) void doelf(void) { - Sym *s, *shstrtab, *dynstr; + LSym *s, *shstrtab, *dynstr; if(!iself) return; /* predefine strings we need for section headers */ - shstrtab = lookup(".shstrtab", 0); + shstrtab = linklookup(ctxt, ".shstrtab", 0); shstrtab->type = SELFROSECT; shstrtab->reachable = 1; @@ -969,7 +969,7 @@ doelf(void) addstring(shstrtab, ".gnu.version_r"); /* dynamic symbol table - first entry all zeros */ - s = lookup(".dynsym", 0); + s = linklookup(ctxt, ".dynsym", 0); s->type = SELFROSECT; s->reachable = 1; if(thechar == '6') @@ -978,7 +978,7 @@ doelf(void) s->size += ELF32SYMSIZE; /* dynamic string table */ - s = lookup(".dynstr", 0); + s = linklookup(ctxt, ".dynstr", 0); s->type = SELFROSECT; s->reachable = 1; if(s->size == 0) @@ -987,85 +987,85 @@ doelf(void) /* relocation table */ if(thechar == '6') - s = lookup(".rela", 0); + s = linklookup(ctxt, ".rela", 0); else - s = lookup(".rel", 0); + s = linklookup(ctxt, ".rel", 0); s->reachable = 1; s->type = SELFROSECT; /* global offset table */ - s = lookup(".got", 0); + s = linklookup(ctxt, ".got", 0); s->reachable = 1; s->type = SELFSECT; // writable /* hash */ - s = lookup(".hash", 0); + s = linklookup(ctxt, ".hash", 0); s->reachable = 1; s->type = SELFROSECT; - s = lookup(".got.plt", 0); + s = linklookup(ctxt, ".got.plt", 0); s->reachable = 1; s->type = SELFSECT; // writable - s = lookup(".plt", 0); + s = linklookup(ctxt, ".plt", 0); s->reachable = 1; s->type = SELFRXSECT; elfsetupplt(); if(thechar == '6') - s = lookup(".rela.plt", 0); + s = linklookup(ctxt, ".rela.plt", 0); else - s = lookup(".rel.plt", 0); + s = linklookup(ctxt, ".rel.plt", 0); s->reachable = 1; s->type = SELFROSECT; - s = lookup(".gnu.version", 0); + s = linklookup(ctxt, ".gnu.version", 0); s->reachable = 1; s->type = SELFROSECT; - s = lookup(".gnu.version_r", 0); + s = linklookup(ctxt, ".gnu.version_r", 0); s->reachable = 1; s->type = SELFROSECT; /* define dynamic elf table */ - s = lookup(".dynamic", 0); + s = linklookup(ctxt, ".dynamic", 0); s->reachable = 1; s->type = SELFSECT; // writable /* * .dynamic table */ - elfwritedynentsym(s, DT_HASH, lookup(".hash", 0)); - elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0)); + elfwritedynentsym(s, DT_HASH, linklookup(ctxt, ".hash", 0)); + elfwritedynentsym(s, DT_SYMTAB, linklookup(ctxt, ".dynsym", 0)); if(thechar == '6') elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE); else elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE); - elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0)); - elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0)); + elfwritedynentsym(s, DT_STRTAB, linklookup(ctxt, ".dynstr", 0)); + elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0)); if(thechar == '6') { - elfwritedynentsym(s, DT_RELA, lookup(".rela", 0)); - elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0)); + elfwritedynentsym(s, DT_RELA, linklookup(ctxt, ".rela", 0)); + elfwritedynentsymsize(s, DT_RELASZ, linklookup(ctxt, ".rela", 0)); elfwritedynent(s, DT_RELAENT, ELF64RELASIZE); } else { - elfwritedynentsym(s, DT_REL, lookup(".rel", 0)); - elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0)); + elfwritedynentsym(s, DT_REL, linklookup(ctxt, ".rel", 0)); + elfwritedynentsymsize(s, DT_RELSZ, linklookup(ctxt, ".rel", 0)); elfwritedynent(s, DT_RELENT, ELF32RELSIZE); } if(rpath) elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath)); - elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0)); + elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0)); if(thechar == '6') { elfwritedynent(s, DT_PLTREL, DT_RELA); - elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0)); - elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0)); + elfwritedynentsymsize(s, DT_PLTRELSZ, linklookup(ctxt, ".rela.plt", 0)); + elfwritedynentsym(s, DT_JMPREL, linklookup(ctxt, ".rela.plt", 0)); } else { elfwritedynent(s, DT_PLTREL, DT_REL); - elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0)); - elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0)); + elfwritedynentsymsize(s, DT_PLTRELSZ, linklookup(ctxt, ".rel.plt", 0)); + elfwritedynentsym(s, DT_JMPREL, linklookup(ctxt, ".rel.plt", 0)); } elfwritedynent(s, DT_DEBUG, 0); @@ -1075,7 +1075,7 @@ doelf(void) } void -shsym(ElfShdr *sh, Sym *s) +shsym(ElfShdr *sh, LSym *s) { vlong addr; addr = symaddr(s); @@ -1254,13 +1254,13 @@ asmbelf(vlong symo) sh->addralign = PtrSize; sh->link = elfshname(".dynstr")->shnum; // sh->info = index of first non-local symbol (number of local symbols) - shsym(sh, lookup(".dynsym", 0)); + shsym(sh, linklookup(ctxt, ".dynsym", 0)); sh = elfshname(".dynstr"); sh->type = SHT_STRTAB; sh->flags = SHF_ALLOC; sh->addralign = 1; - shsym(sh, lookup(".dynstr", 0)); + shsym(sh, linklookup(ctxt, ".dynstr", 0)); if(elfverneed) { sh = elfshname(".gnu.version"); @@ -1269,7 +1269,7 @@ asmbelf(vlong symo) sh->addralign = 2; sh->link = elfshname(".dynsym")->shnum; sh->entsize = 2; - shsym(sh, lookup(".gnu.version", 0)); + shsym(sh, linklookup(ctxt, ".gnu.version", 0)); sh = elfshname(".gnu.version_r"); sh->type = SHT_GNU_VERNEED; @@ -1277,7 +1277,7 @@ asmbelf(vlong symo) sh->addralign = PtrSize; sh->info = elfverneed; sh->link = elfshname(".dynstr")->shnum; - shsym(sh, lookup(".gnu.version_r", 0)); + shsym(sh, linklookup(ctxt, ".gnu.version_r", 0)); } switch(eh->machine) { @@ -1289,7 +1289,7 @@ asmbelf(vlong symo) sh->addralign = PtrSize; sh->link = elfshname(".dynsym")->shnum; sh->info = elfshname(".plt")->shnum; - shsym(sh, lookup(".rela.plt", 0)); + shsym(sh, linklookup(ctxt, ".rela.plt", 0)); sh = elfshname(".rela"); sh->type = SHT_RELA; @@ -1297,7 +1297,7 @@ asmbelf(vlong symo) sh->entsize = ELF64RELASIZE; sh->addralign = 8; sh->link = elfshname(".dynsym")->shnum; - shsym(sh, lookup(".rela", 0)); + shsym(sh, linklookup(ctxt, ".rela", 0)); break; default: @@ -1306,7 +1306,7 @@ asmbelf(vlong symo) sh->flags = SHF_ALLOC; sh->entsize = ELF32RELSIZE; sh->link = elfshname(".dynsym")->shnum; - shsym(sh, lookup(".rel.plt", 0)); + shsym(sh, linklookup(ctxt, ".rel.plt", 0)); sh = elfshname(".rel"); sh->type = SHT_REL; @@ -1314,7 +1314,7 @@ asmbelf(vlong symo) sh->entsize = ELF32RELSIZE; sh->addralign = 4; sh->link = elfshname(".dynsym")->shnum; - shsym(sh, lookup(".rel", 0)); + shsym(sh, linklookup(ctxt, ".rel", 0)); break; } @@ -1326,21 +1326,21 @@ asmbelf(vlong symo) else sh->entsize = 4; sh->addralign = 4; - shsym(sh, lookup(".plt", 0)); + shsym(sh, linklookup(ctxt, ".plt", 0)); sh = elfshname(".got"); sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC+SHF_WRITE; sh->entsize = PtrSize; sh->addralign = PtrSize; - shsym(sh, lookup(".got", 0)); + shsym(sh, linklookup(ctxt, ".got", 0)); sh = elfshname(".got.plt"); sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC+SHF_WRITE; sh->entsize = PtrSize; sh->addralign = PtrSize; - shsym(sh, lookup(".got.plt", 0)); + shsym(sh, linklookup(ctxt, ".got.plt", 0)); sh = elfshname(".hash"); sh->type = SHT_HASH; @@ -1348,7 +1348,7 @@ asmbelf(vlong symo) sh->entsize = 4; sh->addralign = PtrSize; sh->link = elfshname(".dynsym")->shnum; - shsym(sh, lookup(".hash", 0)); + shsym(sh, linklookup(ctxt, ".hash", 0)); /* sh and PT_DYNAMIC for .dynamic section */ sh = elfshname(".dynamic"); @@ -1357,7 +1357,7 @@ asmbelf(vlong symo) sh->entsize = 2*PtrSize; sh->addralign = PtrSize; sh->link = elfshname(".dynstr")->shnum; - shsym(sh, lookup(".dynamic", 0)); + shsym(sh, linklookup(ctxt, ".dynamic", 0)); ph = newElfPhdr(); ph->type = PT_DYNAMIC; ph->flags = PF_R + PF_W; @@ -1369,11 +1369,11 @@ asmbelf(vlong symo) // Do not emit PT_TLS for OpenBSD since ld.so(1) does // not currently support it. This is handled // appropriately in runtime/cgo. - if(tlsoffset != 0 && HEADTYPE != Hopenbsd) { + if(ctxt->tlsoffset != 0 && HEADTYPE != Hopenbsd) { ph = newElfPhdr(); ph->type = PT_TLS; ph->flags = PF_R; - ph->memsz = -tlsoffset; + ph->memsz = -ctxt->tlsoffset; ph->align = PtrSize; } } @@ -1394,7 +1394,7 @@ elfobj: sh = elfshname(".shstrtab"); sh->type = SHT_STRTAB; sh->addralign = 1; - shsym(sh, lookup(".shstrtab", 0)); + shsym(sh, linklookup(ctxt, ".shstrtab", 0)); eh->shstrndx = sh->shnum; // put these sections early in the list @@ -1430,7 +1430,7 @@ elfobj: sh = elfshname(".tbss"); sh->type = SHT_NOBITS; sh->addralign = PtrSize; - sh->size = -tlsoffset; + sh->size = -ctxt->tlsoffset; sh->flags = SHF_ALLOC | SHF_TLS | SHF_WRITE; } diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h index 5b2ff041a..76085c7c6 100644 --- a/src/cmd/ld/elf.h +++ b/src/cmd/ld/elf.h @@ -858,7 +858,7 @@ struct Elf64_Shdr { Elf64_Xword entsize; /* Size of each entry in section. */ int shnum; /* section number, not stored on disk */ - Sym* secsym; /* section symbol, if needed; not on disk */ + LSym* secsym; /* section symbol, if needed; not on disk */ }; /* @@ -968,9 +968,9 @@ ElfPhdr *newElfPhdr(void); uint32 elfwritehdr(void); uint32 elfwritephdrs(void); uint32 elfwriteshdrs(void); -void elfwritedynent(Sym*, int, uint64); -void elfwritedynentsym(Sym*, int, Sym*); -void elfwritedynentsymsize(Sym*, int, Sym*); +void elfwritedynent(LSym*, int, uint64); +void elfwritedynentsym(LSym*, int, LSym*); +void elfwritedynentsymsize(LSym*, int, LSym*); uint32 elfhash(uchar*); uint64 startelf(void); uint64 endelf(void); @@ -994,13 +994,13 @@ ElfShdr* elfshalloc(Section*); ElfShdr* elfshname(char*); ElfShdr* elfshreloc(Section*); void elfsetstring(char*, int); -void elfaddverneed(Sym*); +void elfaddverneed(LSym*); void elfemitreloc(void); -void shsym(ElfShdr*, Sym*); +void shsym(ElfShdr*, LSym*); void phsh(ElfPhdr*, ElfShdr*); void doelf(void); void elfsetupplt(void); -void dwarfaddshstrings(Sym*); +void dwarfaddshstrings(LSym*); void dwarfaddelfsectionsyms(void); void dwarfaddelfheaders(void); void asmbelf(vlong symo); diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c index 39ffa3d87..9950a3886 100644 --- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -228,39 +228,6 @@ loadpkgdata(char *file, char *pkg, char *data, int len) free(file); } -// replace all "". with pkg. -char* -expandpkg(char *t0, char *pkg) -{ - int n; - char *p; - char *w, *w0, *t; - - n = 0; - for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3) - n++; - - if(n == 0) - return estrdup(t0); - - // use malloc, not mal, so that caller can free - w0 = malloc(strlen(t0) + strlen(pkg)*n); - if(w0 == nil) { - diag("out of memory"); - errorexit(); - } - w = w0; - for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) { - memmove(w, t, p - t); - w += p-t; - strcpy(w, pkg); - w += strlen(pkg); - t = p+2; - } - strcpy(w, t); - return w0; -} - static int parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp) { @@ -413,7 +380,7 @@ loadcgo(char *file, char *pkg, char *p, int n) char *pend, *next, *p0, *q; char *f[10], *local, *remote, *lib; int nf; - Sym *s; + LSym *s; USED(file); pend = p + n; @@ -459,7 +426,7 @@ loadcgo(char *file, char *pkg, char *p, int n) q = strchr(remote, '#'); if(q) *q++ = '\0'; - s = lookup(local, 0); + s = linklookup(ctxt, local, 0); if(local != f[1]) free(local); if(s->type == 0 || s->type == SXREF || s->type == SHOSTOBJ) { @@ -477,7 +444,7 @@ loadcgo(char *file, char *pkg, char *p, int n) if(nf != 2) goto err; local = f[1]; - s = lookup(local, 0); + s = linklookup(ctxt, local, 0); s->type = SHOSTOBJ; s->size = 0; continue; @@ -496,9 +463,9 @@ loadcgo(char *file, char *pkg, char *p, int n) else remote = local; local = expandpkg(local, pkg); - s = lookup(local, 0); + s = linklookup(ctxt, local, 0); - if(flag_shared && s == lookup("main", 0)) + if(flag_shared && s == linklookup(ctxt, "main", 0)) continue; // export overrides import, for openbsd/cgo. @@ -562,11 +529,11 @@ err: nerrors++; } -static Sym *markq; -static Sym *emarkq; +static LSym *markq; +static LSym *emarkq; static void -mark1(Sym *s, Sym *parent) +mark1(LSym *s, LSym *parent) { if(s == S || s->reachable) return; @@ -582,7 +549,7 @@ mark1(Sym *s, Sym *parent) } void -mark(Sym *s) +mark(LSym *s) { mark1(s, nil); } @@ -592,7 +559,7 @@ markflood(void) { Auto *a; Prog *p; - Sym *s; + LSym *s; int i; for(s=markq; s!=S; s=s->queue) { @@ -649,7 +616,7 @@ isz(Auto *a) } static void -addz(Sym *s, Auto *z) +addz(LSym *s, Auto *z) { Auto *a, *last; @@ -674,16 +641,16 @@ void deadcode(void) { int i; - Sym *s, *last, *p; + LSym *s, *last, *p; Auto *z; Fmt fmt; if(debug['v']) Bprint(&bso, "%5.2f deadcode\n", cputime()); - mark(lookup(INITENTRY, 0)); + mark(linklookup(ctxt, INITENTRY, 0)); for(i=0; i<nelem(markextra); i++) - mark(lookup(markextra[i], 0)); + mark(linklookup(ctxt, markextra[i], 0)); for(i=0; i<ndynexp; i++) mark(dynexp[i]); @@ -691,7 +658,7 @@ deadcode(void) markflood(); // keep each beginning with 'typelink.' if the symbol it points at is being kept. - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(strncmp(s->name, "go.typelink.", 12) == 0) s->reachable = s->nr==1 && s->r[0].sym->reachable; } @@ -699,14 +666,14 @@ deadcode(void) // remove dead text but keep file information (z symbols). last = nil; z = nil; - for(s = textp; s != nil; s = s->next) { + for(s = ctxt->textp; s != nil; s = s->next) { if(!s->reachable) { if(isz(s->autom)) z = s->autom; continue; } if(last == nil) - textp = s; + ctxt->textp = s; else last->next = s; last = s; @@ -717,11 +684,11 @@ deadcode(void) } } if(last == nil) - textp = nil; + ctxt->textp = nil; else last->next = nil; - for(s = allsym; s != S; s = s->allsym) + for(s = ctxt->allsym; s != S; s = s->allsym) if(strncmp(s->name, "go.weak.", 8) == 0) { s->special = 1; // do not lay out in data segment s->reachable = 1; @@ -730,7 +697,7 @@ deadcode(void) // record field tracking references fmtstrinit(&fmt); - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(strncmp(s->name, "go.track.", 9) == 0) { s->special = 1; // do not lay out in data segment s->hide = 1; @@ -746,7 +713,7 @@ deadcode(void) } if(tracksym == nil) return; - s = lookup(tracksym, 0); + s = linklookup(ctxt, tracksym, 0); if(!s->reachable) return; addstrdata(tracksym, fmtstrflush(&fmt)); @@ -755,13 +722,13 @@ deadcode(void) void doweak(void) { - Sym *s, *t; + LSym *s, *t; // resolve weak references only if // target symbol will be in binary anyway. - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(strncmp(s->name, "go.weak.", 8) == 0) { - t = rlookup(s->name+8, s->version); + t = linkrlookup(ctxt, s->name+8, s->version); if(t && t->type != 0 && t->reachable) { s->value = t->value; s->type = t->type; @@ -784,7 +751,7 @@ addexport(void) return; for(i=0; i<ndynexp; i++) - adddynsym(dynexp[i]); + adddynsym(ctxt, dynexp[i]); } /* %Z from gc, for quoting import paths */ diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c index 27041bc47..4bc830ef3 100644 --- a/src/cmd/ld/ldelf.c +++ b/src/cmd/ld/ldelf.c @@ -258,7 +258,7 @@ struct ElfSect uint64 align; uint64 entsize; uchar *base; - Sym *sym; + LSym *sym; }; struct ElfObj @@ -301,7 +301,7 @@ struct ElfSym uchar type; uchar other; uint16 shndx; - Sym* sym; + LSym* sym; }; uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' }; @@ -312,7 +312,7 @@ static int readsym(ElfObj*, int i, ElfSym*, int); static int reltype(char*, int, uchar*); int -valuecmp(Sym *a, Sym *b) +valuecmp(LSym *a, LSym *b) { if(a->value < b->value) return -1; @@ -336,15 +336,15 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) ElfSym sym; Endian *e; Reloc *r, *rp; - Sym *s; - Sym **symbols; + LSym *s; + LSym **symbols; symbols = nil; if(debug['v']) Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn); - version++; + ctxt->version++; base = Boffset(f); if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf) @@ -529,7 +529,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) goto bad; name = smprint("%s(%s)", pkg, sect->name); - s = lookup(name, version); + s = linklookup(ctxt, name, ctxt->version); free(name); switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) { default: @@ -609,14 +609,14 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) } else { // build a TEXT instruction with a unique pc // just to make the rest of the linker happy. - p = prg(); + p = ctxt->arch->prg(); p->as = ATEXT; p->from.type = D_EXTERN; p->from.sym = s; - p->textflag = 7; + ctxt->arch->settextflag(p, 7); p->to.type = D_CONST; p->link = nil; - p->pc = pc++; + p->pc = ctxt->pc++; s->text = p; } } @@ -629,16 +629,16 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) if(s == S) continue; if(s->sub) - s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub)); + s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); if(s->type == STEXT) { - if(etextp) - etextp->next = s; + if(ctxt->etextp) + ctxt->etextp->next = s; else - textp = s; - etextp = s; + ctxt->textp = s; + ctxt->etextp = s; for(s = s->sub; s != S; s = s->sub) { - etextp->next = s; - etextp = s; + ctxt->etextp->next = s; + ctxt->etextp = s; } } } @@ -761,7 +761,7 @@ map(ElfObj *obj, ElfSect *sect) static int readsym(ElfObj *obj, int i, ElfSym *sym, int needSym) { - Sym *s; + LSym *s; if(i >= obj->nsymtab || i < 0) { werrstr("invalid elf symbol index"); @@ -808,7 +808,7 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym) switch(sym->bind) { case ElfSymBindGlobal: if(needSym) { - s = lookup(sym->name, 0); + s = linklookup(ctxt, sym->name, 0); // for global scoped hidden symbols we should insert it into // symbol hash table, but mark them as hidden. // __i686.get_pc_thunk.bx is allowed to be duplicated, to @@ -828,13 +828,13 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym) // local names and hidden visiblity global names are unique // and should only reference by its index, not name, so we // don't bother to add them into hash table - s = newsym(sym->name, version); + s = linknewsym(ctxt, sym->name, ctxt->version); s->type |= SHIDDEN; } break; case ElfSymBindWeak: if(needSym) { - s = newsym(sym->name, 0); + s = linknewsym(ctxt, sym->name, 0); if(sym->other == 2) s->type |= SHIDDEN; } diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c index e0f5405f6..7318381e3 100644 --- a/src/cmd/ld/ldmacho.c +++ b/src/cmd/ld/ldmacho.c @@ -102,7 +102,7 @@ struct MachoSect uint32 flags; uint32 res1; uint32 res2; - Sym *sym; + LSym *sym; MachoRel *rel; }; @@ -138,7 +138,7 @@ struct MachoSym uint16 desc; char kind; uint64 value; - Sym *sym; + LSym *sym; }; struct MachoDysymtab @@ -432,7 +432,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) int64 base; MachoSect *sect; MachoRel *rel; - Sym *s, *s1, *outer; + LSym *s, *s1, *outer; MachoCmd *c; MachoSymtab *symtab; MachoDysymtab *dsymtab; @@ -440,7 +440,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) Reloc *r, *rp; char *name; - version++; + ctxt->version++; base = Boffset(f); if(Bread(f, hdr, sizeof hdr) != sizeof hdr) goto bad; @@ -566,7 +566,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) if(strcmp(sect->name, "__eh_frame") == 0) continue; name = smprint("%s(%s/%s)", pkg, sect->segname, sect->name); - s = lookup(name, version); + s = linklookup(ctxt, name, ctxt->version); if(s->type != 0) { werrstr("duplicate %s/%s", sect->segname, sect->name); goto bad; @@ -609,8 +609,8 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) name++; v = 0; if(!(sym->type&N_EXT)) - v = version; - s = lookup(name, v); + v = ctxt->version; + s = linklookup(ctxt, name, v); if(!(sym->type&N_EXT)) s->dupok = 1; sym->sym = s; @@ -647,14 +647,14 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) // build a TEXT instruction with a unique pc // just to make the rest of the linker happy. // TODO: this is too 6l-specific ? - p = prg(); + p = ctxt->arch->prg(); p->as = ATEXT; p->from.type = D_EXTERN; p->from.sym = s; - p->textflag = 7; + ctxt->arch->settextflag(p, 7); p->to.type = D_CONST; p->link = nil; - p->pc = pc++; + p->pc = ctxt->pc++; s->text = p; } sym->sym = s; @@ -667,7 +667,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) if((s = sect->sym) == S) continue; if(s->sub) { - s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub)); + s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); // assign sizes, now that we know symbols in sorted order. for(s1 = s->sub; s1 != S; s1 = s1->sub) { @@ -678,14 +678,14 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) } } if(s->type == STEXT) { - if(etextp) - etextp->next = s; + if(ctxt->etextp) + ctxt->etextp->next = s; else - textp = s; - etextp = s; + ctxt->textp = s; + ctxt->etextp = s; for(s1 = s->sub; s1 != S; s1 = s1->sub) { - etextp->next = s1; - etextp = s1; + ctxt->etextp->next = s1; + ctxt->etextp = s1; } } } diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c index 6bcda2cb6..f7e4bfcdb 100644 --- a/src/cmd/ld/ldpe.c +++ b/src/cmd/ld/ldpe.c @@ -102,14 +102,14 @@ struct PeSym { uint16 type; uint8 sclass; uint8 aux; - Sym* sym; + LSym* sym; }; struct PeSect { char* name; uchar* base; uint64 size; - Sym* sym; + LSym* sym; IMAGE_SECTION_HEADER sh; }; @@ -141,7 +141,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) PeSect *sect, *rsect; IMAGE_SECTION_HEADER sh; uchar symbuf[18]; - Sym *s; + LSym *s; Reloc *r, *rp; PeSym *sym; @@ -150,7 +150,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn); sect = nil; - version++; + ctxt->version++; base = Boffset(f); obj = mal(sizeof *obj); @@ -222,7 +222,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) goto bad; name = smprint("%s(%s)", pkg, sect->name); - s = lookup(name, version); + s = linklookup(ctxt, name, ctxt->version); free(name); switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) { @@ -372,14 +372,14 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) diag("%s: duplicate definition of %s", pn, s->name); // build a TEXT instruction with a unique pc // just to make the rest of the linker happy. - p = prg(); + p = ctxt->arch->prg(); p->as = ATEXT; p->from.type = D_EXTERN; p->from.sym = s; - p->textflag = 7; + ctxt->arch->settextflag(p, 7); p->to.type = D_CONST; p->link = nil; - p->pc = pc++; + p->pc = ctxt->pc++; s->text = p; } } @@ -391,16 +391,16 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) if(s == S) continue; if(s->sub) - s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub)); + s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); if(s->type == STEXT) { - if(etextp) - etextp->next = s; + if(ctxt->etextp) + ctxt->etextp->next = s; else - textp = s; - etextp = s; + ctxt->textp = s; + ctxt->etextp = s; for(s = s->sub; s != S; s = s->sub) { - etextp->next = s; - etextp = s; + ctxt->etextp->next = s; + ctxt->etextp = s; } } } @@ -430,7 +430,7 @@ map(PeObj *obj, PeSect *sect) static int readsym(PeObj *obj, int i, PeSym **y) { - Sym *s; + LSym *s; PeSym *sym; char *name, *p; @@ -464,12 +464,12 @@ readsym(PeObj *obj, int i, PeSym **y) case IMAGE_SYM_DTYPE_NULL: switch(sym->sclass) { case IMAGE_SYM_CLASS_EXTERNAL: //global - s = lookup(name, 0); + s = linklookup(ctxt, name, 0); break; case IMAGE_SYM_CLASS_NULL: case IMAGE_SYM_CLASS_STATIC: case IMAGE_SYM_CLASS_LABEL: - s = lookup(name, version); + s = linklookup(ctxt, name, ctxt->version); s->dupok = 1; break; default: diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index da522dc0c..56e50acb9 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -32,6 +32,7 @@ #include "l.h" #include "lib.h" #include "../ld/elf.h" +#include "../ld/dwarf.h" #include "../../pkg/runtime/stack.h" #include "../../pkg/runtime/funcdata.h" @@ -48,18 +49,9 @@ int iconv(Fmt*); char symname[] = SYMDEF; char pkgname[] = "__.PKGDEF"; -char** libdir; -int nlibdir = 0; -static int maxlibdir = 0; static int cout = -1; -// symbol version, incremented each time a file is loaded. -// version==1 is reserved for savehist. -enum -{ - HistVersion = 1, -}; -int version = HistVersion; +extern int version; // Set if we see an object compiled by the host compiler that is not // from a package that is known to support internal linking mode. @@ -77,15 +69,15 @@ Lflag(char *arg) { char **p; - if(nlibdir >= maxlibdir) { - if (maxlibdir == 0) - maxlibdir = 8; + if(ctxt->nlibdir >= ctxt->maxlibdir) { + if (ctxt->maxlibdir == 0) + ctxt->maxlibdir = 8; else - maxlibdir *= 2; - p = erealloc(libdir, maxlibdir * sizeof(*p)); - libdir = p; + ctxt->maxlibdir *= 2; + p = erealloc(ctxt->libdir, ctxt->maxlibdir * sizeof(*p)); + ctxt->libdir = p; } - libdir[nlibdir++] = arg; + ctxt->libdir[ctxt->nlibdir++] = arg; } void @@ -132,7 +124,7 @@ libinit(void) sprint(INITENTRY, "_rt0_%s_%s_lib", goarch, goos); } } - lookup(INITENTRY, 0)->type = SXREF; + linklookup(ctxt, INITENTRY, 0)->type = SXREF; } void @@ -147,158 +139,18 @@ errorexit(void) } void -addlib(char *src, char *obj) -{ - char name[1024], pname[1024], comp[256], *p; - int i, search; - - if(histfrogp <= 0) - return; - - search = 0; - if(histfrog[0]->name[1] == '/') { - sprint(name, ""); - i = 1; - } else - if(isalpha((uchar)histfrog[0]->name[1]) && histfrog[0]->name[2] == ':') { - strcpy(name, histfrog[0]->name+1); - i = 1; - } else - if(histfrog[0]->name[1] == '.') { - sprint(name, "."); - i = 0; - } else { - sprint(name, ""); - i = 0; - search = 1; - } - - for(; i<histfrogp; i++) { - snprint(comp, sizeof comp, "%s", 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; - } - if(i > 0 || !search) - strcat(name, "/"); - strcat(name, comp); - } - cleanname(name); - - // runtime.a -> runtime - p = nil; - if(strlen(name) > 2 && name[strlen(name)-2] == '.') { - p = name+strlen(name)-2; - *p = '\0'; - } - - // already loaded? - for(i=0; i<libraryp; i++) - if(strcmp(library[i].pkg, name) == 0) - return; - - // runtime -> runtime.a for search - if(p != nil) - *p = '.'; - - if(search) { - // try dot, -L "libdir", and then goroot. - for(i=0; i<nlibdir; i++) { - snprint(pname, sizeof pname, "%s/%s", libdir[i], name); - if(access(pname, AEXIST) >= 0) - break; - } - }else - strcpy(pname, name); - cleanname(pname); - - /* runtime.a -> runtime */ - if(p != nil) - *p = '\0'; - - if(debug['v'] > 1) - Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname); - - addlibpath(src, obj, pname, name); -} - -/* - * add library to library list. - * srcref: src file referring to package - * objref: object file referring to package - * file: object file, e.g., /home/rsc/go/pkg/container/vector.a - * pkg: package import path, e.g. container/vector - */ -void -addlibpath(char *srcref, char *objref, char *file, char *pkg) -{ - int i; - Library *l; - char *p; - - for(i=0; i<libraryp; i++) - if(strcmp(file, library[i].file) == 0) - return; - - if(debug['v'] > 1) - Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n", - cputime(), srcref, objref, file, pkg); - - if(libraryp == nlibrary){ - nlibrary = 50 + 2*libraryp; - library = erealloc(library, sizeof library[0] * nlibrary); - } - - l = &library[libraryp++]; - - p = mal(strlen(objref) + 1); - strcpy(p, objref); - l->objref = p; - - p = mal(strlen(srcref) + 1); - strcpy(p, srcref); - l->srcref = p; - - p = mal(strlen(file) + 1); - strcpy(p, file); - l->file = p; - - p = mal(strlen(pkg) + 1); - strcpy(p, pkg); - l->pkg = p; -} - -void loadinternal(char *name) { char pname[1024]; int i, found; found = 0; - for(i=0; i<nlibdir; i++) { - snprint(pname, sizeof pname, "%s/%s.a", libdir[i], name); + for(i=0; i<ctxt->nlibdir; i++) { + snprint(pname, sizeof pname, "%s/%s.a", ctxt->libdir[i], name); if(debug['v']) Bprint(&bso, "searching for %s.a in %s\n", name, pname); if(access(pname, AEXIST) >= 0) { - addlibpath("internal", "internal", pname, name); + addlibpath(ctxt, "internal", "internal", pname, name); found = 1; break; } @@ -311,12 +163,12 @@ void loadlib(void) { int i, w, x; - Sym *s, *gmsym; + LSym *s, *gmsym; if(flag_shared) { - s = lookup("runtime.islibrary", 0); + s = linklookup(ctxt, "runtime.islibrary", 0); s->dupok = 1; - adduint8(s, 1); + adduint8(ctxt, s, 1); } loadinternal("runtime"); @@ -332,17 +184,17 @@ loadlib(void) loadinternal("runtime/cgo"); // Pretend that we really imported the package. // This will do no harm if we did in fact import it. - s = lookup("go.importpath.runtime/cgo.", 0); + s = linklookup(ctxt, "go.importpath.runtime/cgo.", 0); s->type = SDATA; s->dupok = 1; s->reachable = 1; } - for(i=0; i<libraryp; i++) { + for(i=0; i<ctxt->libraryp; i++) { if(debug['v'] > 1) - Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref); - iscgo |= strcmp(library[i].pkg, "runtime/cgo") == 0; - objfile(library[i].file, library[i].pkg); + Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), ctxt->library[i].file, ctxt->library[i].objref); + iscgo |= strcmp(ctxt->library[i].pkg, "runtime/cgo") == 0; + objfile(ctxt->library[i].file, ctxt->library[i].pkg); } if(linkmode == LinkAuto) { @@ -355,7 +207,7 @@ loadlib(void) if(linkmode == LinkInternal) { // Drop all the cgo_import_static declarations. // Turns out we won't be needing them. - for(s = allsym; s != S; s = s->allsym) + for(s = ctxt->allsym; s != S; s = s->allsym) if(s->type == SHOSTOBJ) { // If a symbol was marked both // cgo_import_static and cgo_import_dynamic, @@ -368,7 +220,7 @@ loadlib(void) } } - gmsym = lookup("runtime.tlsgm", 0); + gmsym = linklookup(ctxt, "runtime.tlsgm", 0); gmsym->type = STLSBSS; gmsym->size = 2*PtrSize; gmsym->hide = 1; @@ -539,7 +391,7 @@ dowrite(int fd, char *p, int n) while(n > 0) { m = write(fd, p, n); if(m <= 0) { - cursym = S; + ctxt->cursym = S; diag("write error: %r"); errorexit(); } @@ -628,7 +480,7 @@ hostobjs(void) h = &hostobj[i]; f = Bopen(h->file, OREAD); if(f == nil) { - cursym = S; + ctxt->cursym = S; diag("cannot reopen %s: %r", h->pn); errorexit(); } @@ -744,7 +596,7 @@ hostlink(void) h = &hostobj[i]; f = Bopen(h->file, OREAD); if(f == nil) { - cursym = S; + ctxt->cursym = S; diag("cannot reopen %s: %r", h->pn); errorexit(); } @@ -753,7 +605,7 @@ hostlink(void) argv[argc++] = p; w = create(p, 1, 0775); if(w < 0) { - cursym = S; + ctxt->cursym = S; diag("cannot create %s: %r", p); errorexit(); } @@ -765,7 +617,7 @@ hostlink(void) len -= n; } if(close(w) < 0) { - cursym = S; + ctxt->cursym = S; diag("cannot write %s: %r", p); errorexit(); } @@ -798,7 +650,7 @@ hostlink(void) } if(runcmd(argv) < 0) { - cursym = S; + ctxt->cursym = S; diag("%s: running %s failed: %r", argv0, argv[0]); errorexit(); } @@ -913,7 +765,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence) ldpkg(f, pkg, import1 - import0 - 2, pn, whence); // -2 for !\n Bseek(f, import1, 0); - ldobj1(f, pkg, eof - Boffset(f), pn); + ctxt->arch->ldobj(ctxt, f, pkg, eof - Boffset(f), pn); free(pn); return; @@ -922,318 +774,12 @@ eof: free(pn); } -Sym* -newsym(char *symb, int v) -{ - Sym *s; - int l; - - l = strlen(symb) + 1; - s = mal(sizeof(*s)); - if(debug['v'] > 1) - Bprint(&bso, "newsym %s\n", symb); - - s->dynid = -1; - s->plt = -1; - s->got = -1; - s->name = mal(l + 1); - memmove(s->name, symb, l); - - s->type = 0; - s->version = v; - s->value = 0; - s->sig = 0; - s->size = 0; - nsymbol++; - - s->allsym = allsym; - allsym = s; - - return s; -} - -static Sym* -_lookup(char *symb, int v, int creat) -{ - Sym *s; - char *p; - uint32 h; - int c; - - h = v; - for(p=symb; c = *p; p++) - h = h+h+h + c; - // not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it. - h &= 0xffffff; - h %= NHASH; - for(s = hash[h]; s != S; s = s->hash) - if(strcmp(s->name, symb) == 0) - return s; - if(!creat) - return nil; - - s = newsym(symb, v); - s->extname = s->name; - s->hash = hash[h]; - hash[h] = s; - - return s; -} - -Sym* -lookup(char *name, int v) -{ - return _lookup(name, v, 1); -} - -// read-only lookup -Sym* -rlookup(char *name, int v) -{ - return _lookup(name, v, 0); -} - -void -copyhistfrog(char *buf, int nbuf) -{ - char *p, *ep; - int i; - - p = buf; - ep = buf + nbuf; - for(i=0; i<histfrogp; i++) { - p = seprint(p, ep, "%s", histfrog[i]->name+1); - if(i+1<histfrogp && (p == buf || p[-1] != '/')) - p = seprint(p, ep, "/"); - } -} - -void -addhist(int32 line, int type) -{ - Auto *u; - Sym *s; - int i, j, k; - - u = mal(sizeof(Auto)); - s = mal(sizeof(Sym)); - s->name = mal(2*(histfrogp+1) + 1); - - u->asym = s; - u->type = type; - u->aoffset = line; - u->link = curhist; - curhist = u; - - s->name[0] = 0; - 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; - } - s->name[j] = 0; - s->name[j+1] = 0; -} - -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 -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; - if(c == i) { - inuxi8[i] = c; - inuxi8[i+4] = c+4; - } else { - inuxi8[i] = c+4; - inuxi8[i+4] = 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, " "); - for(i=0; i<8; i++) - Bprint(&bso, "%d", inuxi8[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(int32 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(int32 l, int c) -{ - union { - int32 l; - short p[2]; - } u; - short *p; - int i; - - u.l = l; - p = u.p; - for(i=0; i<4; i+=2) { - if(((*p >> 8) & 0xff) == c) - return i; - if((*p++ & 0xff) == c) - return i+1; - } - return 0; -} - -int32 -ieeedtof(Ieee *e) -{ - int exp; - int32 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(-148 <= exp && exp <= -126) { - v |= 1<<23; - v >>= -125 - exp; - exp = -126; - } - else if(exp < -148 || exp >= 130) - diag("double fp to single fp overflow: %.17g", ieeedtod(e)); - 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; - exp = (ieeep->h>>20) & ((1L<<11)-1L); - exp -= (1L<<10) - 2L; - fr = ieeep->l & ((1L<<16)-1L); - fr /= 1L<<16; - fr += (ieeep->l>>16) & ((1L<<16)-1L); - fr /= 1L<<16; - if(exp == -(1L<<10) - 2L) { - fr += (ieeep->h & (1L<<20)-1L); - exp++; - } else - fr += (ieeep->h & (1L<<20)-1L) | (1L<<20); - fr /= 1L<<21; - return ldexp(fr, exp); -} - void zerosig(char *sp) { - Sym *s; + LSym *s; - s = lookup(sp, 0); + s = linklookup(ctxt, sp, 0); s->sig = 0; } @@ -1357,13 +903,6 @@ iconv(Fmt *fp) return 0; } -void -mangle(char *file) -{ - fprint(2, "%s: mangled input file\n", file); - errorexit(); -} - Section* addsection(Segment *seg, char *name, int rwx) { @@ -1381,235 +920,6 @@ addsection(Segment *seg, char *name, int rwx) return sect; } -void -addvarint(Sym *s, uint32 val) -{ - int32 n; - uint32 v; - uchar *p; - - n = 0; - for(v = val; v >= 0x80; v >>= 7) - n++; - n++; - - symgrow(s, s->np+n); - - p = s->p + s->np - n; - for(v = val; v >= 0x80; v >>= 7) - *p++ = v | 0x80; - *p = v; -} - -// funcpctab appends to dst a pc-value table mapping the code in func to the values -// returned by valfunc parameterized by arg. The invocation of valfunc to update the -// current value is, for each p, -// -// val = valfunc(func, val, p, 0, arg); -// record val as value at p->pc; -// val = valfunc(func, val, p, 1, arg); -// -// where func is the function, val is the current value, p is the instruction being -// considered, and arg can be used to further parameterize valfunc. -void -funcpctab(Sym *dst, Sym *func, char *desc, int32 (*valfunc)(Sym*, int32, Prog*, int32, int32), int32 arg) -{ - int dbg, i, start; - int32 oldval, val, started; - uint32 delta; - vlong pc; - Prog *p; - - // To debug a specific function, uncomment second line and change name. - dbg = 0; - //dbg = strcmp(func->name, "main.main") == 0; - - debug['O'] += dbg; - - start = dst->np; - - if(debug['O']) - Bprint(&bso, "funcpctab %s -> %s [valfunc=%s]\n", func->name, dst->name, desc); - - val = -1; - oldval = val; - pc = func->value; - - if(debug['O']) - Bprint(&bso, "%6llux %6d %P\n", pc, val, func->text); - - started = 0; - for(p=func->text; p != P; p = p->link) { - // Update val. If it's not changing, keep going. - val = valfunc(func, val, p, 0, arg); - if(val == oldval && started) { - val = valfunc(func, val, p, 1, arg); - if(debug['O']) - Bprint(&bso, "%6llux %6s %P\n", (vlong)p->pc, "", p); - continue; - } - - // If the pc of the next instruction is the same as the - // pc of this instruction, this instruction is not a real - // instruction. Keep going, so that we only emit a delta - // for a true instruction boundary in the program. - if(p->link && p->link->pc == p->pc) { - val = valfunc(func, val, p, 1, arg); - if(debug['O']) - Bprint(&bso, "%6llux %6s %P\n", (vlong)p->pc, "", p); - continue; - } - - // The table is a sequence of (value, pc) pairs, where each - // pair states that the given value is in effect from the current position - // up to the given pc, which becomes the new current position. - // To generate the table as we scan over the program instructions, - // we emit a "(value" when pc == func->value, and then - // each time we observe a change in value we emit ", pc) (value". - // When the scan is over, we emit the closing ", pc)". - // - // The table is delta-encoded. The value deltas are signed and - // transmitted in zig-zag form, where a complement bit is placed in bit 0, - // and the pc deltas are unsigned. Both kinds of deltas are sent - // as variable-length little-endian base-128 integers, - // where the 0x80 bit indicates that the integer continues. - - if(debug['O']) - Bprint(&bso, "%6llux %6d %P\n", (vlong)p->pc, val, p); - - if(started) { - addvarint(dst, (p->pc - pc) / MINLC); - pc = p->pc; - } - delta = val - oldval; - if(delta>>31) - delta = 1 | ~(delta<<1); - else - delta <<= 1; - addvarint(dst, delta); - oldval = val; - started = 1; - val = valfunc(func, val, p, 1, arg); - } - - if(started) { - if(debug['O']) - Bprint(&bso, "%6llux done\n", (vlong)func->value+func->size); - addvarint(dst, (func->value+func->size - pc) / MINLC); - addvarint(dst, 0); // terminator - } - - if(debug['O']) { - Bprint(&bso, "wrote %d bytes\n", dst->np - start); - for(i=start; i<dst->np; i++) - Bprint(&bso, " %02ux", dst->p[i]); - Bprint(&bso, "\n"); - } - - debug['O'] -= dbg; -} - -// pctofileline computes either the file number (arg == 0) -// or the line number (arg == 1) to use at p. -// Because p->lineno applies to p, phase == 0 (before p) -// takes care of the update. -static int32 -pctofileline(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg) -{ - int32 f, l; - - if(p->as == ATEXT || p->as == ANOP || p->as == AUSEFIELD || p->line == 0 || phase == 1) - return oldval; - getline(sym->hist, p->line, &f, &l); - if(f == 0) { - // print("getline failed for %s %P\n", cursym->name, p); - return oldval; - } - if(arg == 0) - return f; - return l; -} - -// pctospadj computes the sp adjustment in effect. -// It is oldval plus any adjustment made by p itself. -// The adjustment by p takes effect only after p, so we -// apply the change during phase == 1. -static int32 -pctospadj(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg) -{ - USED(arg); - USED(sym); - - if(oldval == -1) // starting - oldval = 0; - if(phase == 0) - return oldval; - if(oldval + p->spadj < -10000 || oldval + p->spadj > 1100000000) { - diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj); - errorexit(); - } - return oldval + p->spadj; -} - -// pctopcdata computes the pcdata value in effect at p. -// A PCDATA instruction sets the value in effect at future -// non-PCDATA instructions. -// Since PCDATA instructions have no width in the final code, -// it does not matter which phase we use for the update. -static int32 -pctopcdata(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg) -{ - USED(sym); - - if(phase == 0 || p->as != APCDATA || p->from.offset != arg) - return oldval; - if((int32)p->to.offset != p->to.offset) { - diag("overflow in PCDATA instruction: %P", p); - errorexit(); - } - return p->to.offset; -} - -#define LOG 5 -void -mkfwd(void) -{ - Prog *p; - int i; - int32 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(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - if(p->link == P) { - if(cursym->next) - p->forwd = cursym->next->text; - break; - } - 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; - } - } - } -} - uint16 le16(uchar *b) { @@ -1652,7 +962,7 @@ Endian le = { le16, le32, le64 }; typedef struct Chain Chain; struct Chain { - Sym *sym; + LSym *sym; Chain *up; int limit; // limit on entry to sym }; @@ -1660,8 +970,8 @@ struct Chain static int stkcheck(Chain*, int); static void stkprint(Chain*, int); static void stkbroke(Chain*, int); -static Sym *morestack; -static Sym *newstack; +static LSym *morestack; +static LSym *newstack; enum { @@ -1673,16 +983,16 @@ void dostkcheck(void) { Chain ch; - Sym *s; + LSym *s; - morestack = lookup("runtime.morestack", 0); - newstack = lookup("runtime.newstack", 0); + morestack = linklookup(ctxt, "runtime.morestack", 0); + newstack = linklookup(ctxt, "runtime.newstack", 0); // First the nosplits on their own. - for(s = textp; s != nil; s = s->next) { - if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) == 0) + for(s = ctxt->textp; s != nil; s = s->next) { + if(s->text == nil || s->text->link == nil || (ctxt->arch->textflag(s->text) & NOSPLIT) == 0) continue; - cursym = s; + ctxt->cursym = s; ch.up = nil; ch.sym = s; ch.limit = StackLimit - CallSize; @@ -1695,10 +1005,10 @@ dostkcheck(void) // like newproc and deferproc. We could hard-code // that knowledge but it's more robust to look at // the actual call sites. - for(s = textp; s != nil; s = s->next) { - if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) != 0) + for(s = ctxt->textp; s != nil; s = s->next) { + if(s->text == nil || s->text->link == nil || (ctxt->arch->textflag(s->text) & NOSPLIT) != 0) continue; - cursym = s; + ctxt->cursym = s; ch.up = nil; ch.sym = s; ch.limit = StackLimit - CallSize; @@ -1711,7 +1021,7 @@ stkcheck(Chain *up, int depth) { Chain ch, ch1; Prog *p; - Sym *s; + LSym *s; int limit, prolog; limit = up->limit; @@ -1732,7 +1042,7 @@ stkcheck(Chain *up, int depth) // external function. // should never be called directly. // only diagnose the direct caller. - if(depth == 1) + if(depth == 1 && s->type != SXREF) diag("call to external function %s", s->name); return -1; } @@ -1748,7 +1058,7 @@ stkcheck(Chain *up, int depth) return 0; ch.up = up; - prolog = (s->text->textflag & NOSPLIT) == 0; + prolog = (ctxt->arch->textflag(s->text) & NOSPLIT) == 0; for(p = s->text; p != P; p = p->link) { limit -= p->spadj; if(prolog && p->spadj != 0) { @@ -1768,7 +1078,7 @@ stkcheck(Chain *up, int depth) stkbroke(up, limit); return -1; } - if(iscall(p)) { + if(ctxt->arch->iscall(p)) { limit -= CallSize; ch.limit = limit; if(p->to.type == D_BRANCH) { @@ -1814,7 +1124,7 @@ stkprint(Chain *ch, int limit) if(ch->up == nil) { // top of chain. ch->sym != nil. - if(ch->sym->text->textflag & NOSPLIT) + if(ctxt->arch->textflag(ch->sym->text) & NOSPLIT) print("\t%d\tassumed on entry to %s\n", ch->limit, name); else print("\t%d\tguaranteed after split check in %s\n", ch->limit, name); @@ -1855,25 +1165,15 @@ headstr(int v) return buf; } -void -undef(void) -{ - Sym *s; - - for(s = allsym; s != S; s = s->allsym) - if(s->type == SXREF) - diag("%s(%d): not defined", s->name, s->version); -} - int Yconv(Fmt *fp) { - Sym *s; + LSym *s; Fmt fmt; int i; char *str; - s = va_arg(fp->args, Sym*); + s = va_arg(fp->args, LSym*); if (s == S) { fmtprint(fp, "<nil>"); } else { @@ -1985,22 +1285,22 @@ doversion(void) } void -genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) +genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)) { Auto *a; - Sym *s; + LSym *s; int32 off; // These symbols won't show up in the first loop below because we // skip STEXT symbols. Normal STEXT symbols are emitted by walking textp. - s = lookup("text", 0); + s = linklookup(ctxt, "text", 0); if(s->type == STEXT) put(s, s->name, 'T', s->value, s->size, s->version, 0); - s = lookup("etext", 0); + s = linklookup(ctxt, "etext", 0); if(s->type == STEXT) put(s, s->name, 'T', s->value, s->size, s->version, 0); - for(s=allsym; s!=S; s=s->allsym) { + for(s=ctxt->allsym; s!=S; s=s->allsym) { if(s->hide || (s->name[0] == '.' && s->version == 0 && strcmp(s->name, ".rathole") != 0)) continue; switch(s->type&SMASK) { @@ -2036,7 +1336,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) } } - for(s = textp; s != nil; s = s->next) { + for(s = ctxt->textp; s != nil; s = s->next) { if(s->text == nil) continue; @@ -2075,461 +1375,83 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) Bflush(&bso); } -char* -estrdup(char *p) -{ - p = strdup(p); - if(p == nil) { - cursym = S; - diag("out of memory"); - errorexit(); - } - return p; -} - -void* -erealloc(void *p, long n) +vlong +symaddr(LSym *s) { - p = realloc(p, n); - if(p == nil) { - cursym = S; - diag("out of memory"); - errorexit(); - } - return p; + if(!s->reachable) + diag("unreachable symbol in symaddr - %s", s->name); + return s->value; } -// Saved history stacks encountered while reading archives. -// Keeping them allows us to answer virtual lineno -> file:line -// queries. -// -// The history stack is a complex data structure, described best at the -// bottom of http://plan9.bell-labs.com/magic/man2html/6/a.out. -// One of the key benefits of interpreting it here is that the runtime -// does not have to. Perhaps some day the compilers could generate -// a simpler linker input too. - -struct Hist -{ - int32 line; - int32 off; - Sym *file; -}; - -static Hist *histcopy; -static Hist *hist; -static int32 nhist; -static int32 maxhist; -static int32 histdepth; -static int32 nhistfile; -static Sym *filesyms; - -// savehist processes a single line, off history directive -// found in the input object file. void -savehist(int32 line, int32 off) +xdefine(char *p, int t, vlong v) { - char tmp[1024]; - Sym *file; - Hist *h; - - // NOTE(rsc): We used to do the copyhistfrog first and this - // condition was if(tmp[0] != '\0') to check for an empty string, - // implying that histfrogp == 0, implying that this is a history pop. - // However, on Windows in the misc/cgo test, the linker is - // presented with an ANAME corresponding to an empty string, - // that ANAME ends up being the only histfrog, and thus we have - // a situation where histfrogp > 0 (not a pop) but the path we find - // is the empty string. Really that shouldn't happen, but it doesn't - // seem to be bothering anyone yet, and it's easier to fix the condition - // to test histfrogp than to track down where that empty string is - // coming from. Probably it is coming from go tool pack's P command. - if(histfrogp > 0) { - tmp[0] = '\0'; - copyhistfrog(tmp, sizeof tmp); - file = lookup(tmp, HistVersion); - if(file->type != SFILEPATH) { - file->value = ++nhistfile; - file->type = SFILEPATH; - file->next = filesyms; - filesyms = file; - } - } else - file = nil; + LSym *s; - if(file != nil && line == 1 && off == 0) { - // start of new stack - if(histdepth != 0) { - diag("history stack phase error: unexpected start of new stack depth=%d file=%s", histdepth, tmp); - errorexit(); - } - nhist = 0; - histcopy = nil; - } - - if(nhist >= maxhist) { - if(maxhist == 0) - maxhist = 1; - maxhist *= 2; - hist = erealloc(hist, maxhist*sizeof hist[0]); - } - h = &hist[nhist++]; - h->line = line; - h->off = off; - h->file = file; - - if(file != nil) { - if(off == 0) - histdepth++; - } else { - if(off != 0) { - diag("history stack phase error: bad offset in pop"); - errorexit(); - } - histdepth--; - } + s = linklookup(ctxt, p, 0); + s->type = t; + s->value = v; + s->reachable = 1; + s->special = 1; } -// gethist returns the history stack currently in effect. -// The result is valid indefinitely. -Hist* -gethist(void) +vlong +datoff(vlong addr) { - if(histcopy == nil) { - if(nhist == 0) - return nil; - histcopy = mal((nhist+1)*sizeof hist[0]); - memmove(histcopy, hist, nhist*sizeof hist[0]); - histcopy[nhist].line = -1; - } - return histcopy; + if(addr >= segdata.vaddr) + return addr - segdata.vaddr + segdata.fileoff; + if(addr >= segtext.vaddr) + return addr - segtext.vaddr + segtext.fileoff; + diag("datoff %#llx", addr); + return 0; } -typedef struct Hstack Hstack; -struct Hstack -{ - Hist *h; - int delta; -}; - -// getline sets *f to the file number and *l to the line number -// of the virtual line number line according to the history stack h. -void -getline(Hist *h, int32 line, int32 *f, int32 *l) +vlong +entryvalue(void) { - Hstack stk[100]; - int nstk, start; - Hist *top, *h0; - static Hist *lasth; - static int32 laststart, lastend, lastdelta, lastfile; - - h0 = h; - *f = 0; - *l = 0; - start = 0; - if(h == nil || line == 0) { - print("%s: getline: h=%p line=%d\n", cursym->name, h, line); - return; - } - - // Cache span used during last lookup, so that sequential - // translation of line numbers in compiled code is efficient. - if(!debug['O'] && lasth == h && laststart <= line && line < lastend) { - *f = lastfile; - *l = line - lastdelta; - return; - } - - if(debug['O']) - print("getline %d laststart=%d lastend=%d\n", line, laststart, lastend); - - nstk = 0; - for(; h->line != -1; h++) { - if(debug['O']) - print("\t%s %d %d\n", h->file ? h->file->name : "?", h->line, h->off); - - if(h->line > line) { - if(nstk == 0) { - diag("history stack phase error: empty stack at line %d", (int)line); - errorexit(); - } - top = stk[nstk-1].h; - lasth = h; - lastfile = top->file->value; - laststart = start; - lastend = h->line; - lastdelta = stk[nstk-1].delta; - *f = lastfile; - *l = line - lastdelta; - if(debug['O']) - print("\tgot %d %d [%d %d %d]\n", *f, *l, laststart, lastend, lastdelta); - return; - } - if(h->file == nil) { - // pop included file - if(nstk == 0) { - diag("history stack phase error: stack underflow"); - errorexit(); - } - nstk--; - if(nstk > 0) - stk[nstk-1].delta += h->line - stk[nstk].h->line; - start = h->line; - } else if(h->off == 0) { - // push included file - if(nstk >= nelem(stk)) { - diag("history stack phase error: stack overflow"); - errorexit(); - } - start = h->line; - stk[nstk].h = h; - stk[nstk].delta = h->line - 1; - nstk++; - } else { - // #line directive - if(nstk == 0) { - diag("history stack phase error: stack underflow"); - errorexit(); - } - stk[nstk-1].h = h; - stk[nstk-1].delta = h->line - h->off; - start = h->line; - } - if(debug['O']) - print("\t\tnstk=%d delta=%d\n", nstk, stk[nstk].delta); - } + char *a; + LSym *s; - diag("history stack phase error: cannot find line for %d", line); - nstk = 0; - for(h = h0; h->line != -1; h++) { - print("\t%d %d %s\n", h->line, h->off, h->file ? h->file->name : ""); - if(h->file == nil) - nstk--; - else if(h->off == 0) - nstk++; - } + a = INITENTRY; + if(*a >= '0' && *a <= '9') + return atolwhex(a); + s = linklookup(ctxt, a, 0); + if(s->type == 0) + return INITTEXT; + if(s->type != STEXT) + diag("entry not text: %s", s->name); + return s->value; } -// defgostring returns a symbol for the Go string containing text. -Sym* -defgostring(char *text) +static void +undefsym(LSym *s) { - char *p; - Sym *s; - int32 n; - - n = strlen(text); - p = smprint("go.string.\"%Z\"", text); - s = lookup(p, 0); - if(s->size == 0) { - s->type = SGOSTRING; - s->reachable = 1; - s->size = 2*PtrSize+n; - symgrow(s, 2*PtrSize+n); - setaddrplus(s, 0, s, 2*PtrSize); - setuintxx(s, PtrSize, n, PtrSize); - memmove(s->p+2*PtrSize, text, n); - } - s->reachable = 1; - return s; -} + int i; + Reloc *r; -// addpctab appends to f a pc-value table, storing its offset at off. -// The pc-value table is for func and reports the value of valfunc -// parameterized by arg. -static int32 -addpctab(Sym *f, int32 off, Sym *func, char *desc, int32 (*valfunc)(Sym*, int32, Prog*, int32, int32), int32 arg) -{ - int32 start; - - start = f->np; - funcpctab(f, func, desc, valfunc, arg); - if(start == f->np) { - // no table - return setuint32(f, off, 0); - } - if((int32)start > (int32)f->np) { - diag("overflow adding pc-table: symbol too large"); - errorexit(); + ctxt->cursym = s; + for(i=0; i<s->nr; i++) { + r = &s->r[i]; + if(r->sym == nil) // happens for some external ARM relocs + continue; + if(r->sym->type == Sxxx || r->sym->type == SXREF) { + diag("undefined: %s", r->sym->name); + continue; + } + if(!r->sym->reachable) + diag("use of unreachable symbol: %s", r->sym->name); } - return setuint32(f, off, start); -} - -static int32 -ftabaddstring(Sym *ftab, char *s) -{ - int32 n, start; - - n = strlen(s)+1; - start = ftab->np; - symgrow(ftab, start+n+1); - strcpy((char*)ftab->p + start, s); - return start; } -// pclntab initializes the pclntab symbol with -// runtime function and file name information. void -pclntab(void) +undef(void) { - Prog *p; - int32 i, n, nfunc, start, funcstart; - uint32 *havepc, *havefunc; - Sym *ftab, *s; - int32 npcdata, nfuncdata, off, end; - int64 funcdata_bytes; - - funcdata_bytes = 0; - ftab = lookup("pclntab", 0); - ftab->type = SPCLNTAB; - ftab->reachable = 1; - - // See golang.org/s/go12symtab for the format. Briefly: - // 8-byte header - // nfunc [PtrSize bytes] - // function table, alternating PC and offset to func struct [each entry PtrSize bytes] - // end PC [PtrSize bytes] - // offset to file table [4 bytes] - nfunc = 0; - for(cursym = textp; cursym != nil; cursym = cursym->next) - nfunc++; - symgrow(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4); - setuint32(ftab, 0, 0xfffffffb); - setuint8(ftab, 6, MINLC); - setuint8(ftab, 7, PtrSize); - setuintxx(ftab, 8, nfunc, PtrSize); - - nfunc = 0; - for(cursym = textp; cursym != nil; cursym = cursym->next, nfunc++) { - funcstart = ftab->np; - funcstart += -ftab->np & (PtrSize-1); - - setaddr(ftab, 8+PtrSize+nfunc*2*PtrSize, cursym); - setuintxx(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize); - - npcdata = 0; - nfuncdata = 0; - for(p = cursym->text; p != P; p = p->link) { - if(p->as == APCDATA && p->from.offset >= npcdata) - npcdata = p->from.offset+1; - if(p->as == AFUNCDATA && p->from.offset >= nfuncdata) - nfuncdata = p->from.offset+1; - } - - // fixed size of struct, checked below - off = funcstart; - end = funcstart + PtrSize + 3*4 + 5*4 + npcdata*4 + nfuncdata*PtrSize; - if(nfuncdata > 0 && (end&(PtrSize-1))) - end += 4; - symgrow(ftab, end); - - // entry uintptr - off = setaddr(ftab, off, cursym); - - // name int32 - off = setuint32(ftab, off, ftabaddstring(ftab, cursym->name)); - - // args int32 - // TODO: Move into funcinfo. - if(cursym->text == nil) - off = setuint32(ftab, off, ArgsSizeUnknown); - else - off = setuint32(ftab, off, cursym->args); - - // frame int32 - // TODO: Remove entirely. The pcsp table is more precise. - // This is only used by a fallback case during stack walking - // when a called function doesn't have argument information. - // We need to make sure everything has argument information - // and then remove this. - if(cursym->text == nil) - off = setuint32(ftab, off, 0); - else - off = setuint32(ftab, off, (uint32)cursym->text->to.offset+PtrSize); - - // pcsp table (offset int32) - off = addpctab(ftab, off, cursym, "pctospadj", pctospadj, 0); - - // pcfile table (offset int32) - off = addpctab(ftab, off, cursym, "pctofileline file", pctofileline, 0); - - // pcln table (offset int32) - off = addpctab(ftab, off, cursym, "pctofileline line", pctofileline, 1); - - // npcdata int32 - off = setuint32(ftab, off, npcdata); - - // nfuncdata int32 - off = setuint32(ftab, off, nfuncdata); - - // tabulate which pc and func data we have. - n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4; - havepc = mal(n); - havefunc = havepc + (npcdata+31)/32; - for(p = cursym->text; p != P; p = p->link) { - if(p->as == AFUNCDATA) { - if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1) - diag("multiple definitions for FUNCDATA $%d", p->from.offset); - havefunc[p->from.offset/32] |= 1<<(p->from.offset%32); - } - if(p->as == APCDATA) - havepc[p->from.offset/32] |= 1<<(p->from.offset%32); - } - - // pcdata. - for(i=0; i<npcdata; i++) { - if(!(havepc[i/32]>>(i%32))&1) { - off = setuint32(ftab, off, 0); - continue; - } - off = addpctab(ftab, off, cursym, "pctopcdata", pctopcdata, i); - } - - unmal(havepc, n); - - // funcdata, must be pointer-aligned and we're only int32-aligned. - // Unlike pcdata, can gather in a single pass. - // Missing funcdata will be 0 (nil pointer). - if(nfuncdata > 0) { - if(off&(PtrSize-1)) - off += 4; - for(p = cursym->text; p != P; p = p->link) { - if(p->as == AFUNCDATA) { - i = p->from.offset; - if(p->to.type == D_CONST) - setuintxx(ftab, off+PtrSize*i, p->to.offset, PtrSize); - else { - // TODO: Dedup. - funcdata_bytes += p->to.sym->size; - setaddrplus(ftab, off+PtrSize*i, p->to.sym, p->to.offset); - } - } - } - off += nfuncdata*PtrSize; - } - - if(off != end) { - diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d)", funcstart, off, end, npcdata, nfuncdata); - errorexit(); - } - - // Final entry of table is just end pc. - if(cursym->next == nil) - setaddrplus(ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, cursym, cursym->size); - } + LSym *s; - // Start file table. - start = ftab->np; - start += -ftab->np & (PtrSize-1); - setuint32(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start); - - symgrow(ftab, start+(nhistfile+1)*4); - setuint32(ftab, start, nhistfile); - for(s = filesyms; s != S; s = s->next) - setuint32(ftab, start + s->value*4, ftabaddstring(ftab, s->name)); - - ftab->size = ftab->np; - - if(debug['v']) - Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes); -} + for(s = ctxt->textp; s != nil; s = s->next) + undefsym(s); + for(s = datap; s != nil; s = s->next) + undefsym(s); + if(nerrors > 0) + errorexit(); +} diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index be95bb46e..63e282511 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -28,68 +28,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -enum -{ - Sxxx, - - /* order here is order in output file */ - /* readonly, executable */ - STEXT, - SELFRXSECT, - - /* readonly, non-executable */ - STYPE, - SSTRING, - SGOSTRING, - SGOFUNC, - SRODATA, - SFUNCTAB, - STYPELINK, - SSYMTAB, // TODO: move to unmapped section - SPCLNTAB, - SELFROSECT, - - /* writable, non-executable */ - SMACHOPLT, - SELFSECT, - SMACHO, /* Mach-O __nl_symbol_ptr */ - SMACHOGOT, - SNOPTRDATA, - SINITARR, - SDATA, - SWINDOWS, - SBSS, - SNOPTRBSS, - STLSBSS, - - /* not mapped */ - SXREF, - SMACHOSYMSTR, - SMACHOSYMTAB, - SMACHOINDIRECTPLT, - SMACHOINDIRECTGOT, - SFILE, - SFILEPATH, - SCONST, - SDYNIMPORT, - SHOSTOBJ, - - SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */ - SMASK = SSUB - 1, - SHIDDEN = 1<<9, // hidden or local symbol - - NHASH = 100003, -}; - -typedef struct Library Library; -struct Library -{ - char *objref; // object where we found the reference - char *srcref; // src file where we found the reference - char *file; // object file - char *pkg; // import path -}; - // Terrible but standard terminology. // A segment describes a block of file to load into memory. // A section further describes the pieces of that block for @@ -125,36 +63,14 @@ struct Section uvlong rellen; }; -typedef struct Hist Hist; - -#pragma incomplete struct Hist - extern char symname[]; -extern char **libdir; -extern int nlibdir; -extern int version; EXTERN char* INITENTRY; -EXTERN char* thestring; -EXTERN Library* library; -EXTERN int libraryp; -EXTERN int nlibrary; -EXTERN Sym* hash[NHASH]; -EXTERN Sym* allsym; -EXTERN Sym* histfrog[MAXHIST]; -EXTERN uchar fnuxi8[8]; -EXTERN uchar fnuxi4[4]; -EXTERN int histfrogp; -EXTERN int histgen; -EXTERN uchar inuxi1[1]; -EXTERN uchar inuxi2[2]; -EXTERN uchar inuxi4[4]; -EXTERN uchar inuxi8[8]; +extern char* thestring; +extern LinkArch* thelinkarch; EXTERN char* outfile; -EXTERN int32 nsymbol; -EXTERN char* thestring; EXTERN int ndynexp; -EXTERN Sym** dynexp; +EXTERN LSym** dynexp; EXTERN int nldflag; EXTERN char** ldflag; EXTERN int havedynamic; @@ -169,16 +85,20 @@ EXTERN char* tmpdir; EXTERN char* extld; EXTERN char* extldflags; EXTERN int debug_s; // backup old value of debug['s'] +EXTERN Link* ctxt; +EXTERN int32 HEADR; +EXTERN int32 HEADTYPE; +EXTERN int32 INITRND; +EXTERN int64 INITTEXT; +EXTERN int64 INITDAT; +EXTERN char* INITENTRY; /* entry point */ +EXTERN char* noname; +EXTERN char* paramspace; +EXTERN int nerrors; -enum -{ - LinkAuto = 0, - LinkInternal, - LinkExternal, -}; EXTERN int linkmode; -// for dynexport field of Sym +// for dynexport field of LSym enum { CgoExportDynamic = 1<<0, @@ -190,119 +110,6 @@ EXTERN Segment segrodata; EXTERN Segment segdata; EXTERN Segment segdwarf; -void setlinkmode(char*); -void addlib(char *src, char *obj); -void addlibpath(char *srcref, char *objref, char *file, char *pkg); -Section* addsection(Segment*, char*, int); -void copyhistfrog(char *buf, int nbuf); -void addhist(int32 line, int type); -void savehist(int32 line, int32 off); -Hist* gethist(void); -void getline(Hist*, int32 line, int32 *f, int32 *l); -void asmlc(void); -void histtoauto(void); -void collapsefrog(Sym *s); -Sym* newsym(char *symb, int v); -Sym* lookup(char *symb, int v); -Sym* rlookup(char *symb, int v); -void nuxiinit(void); -int find1(int32 l, int c); -int find2(int32 l, int c); -int32 ieeedtof(Ieee *e); -double ieeedtod(Ieee *e); -void undefsym(Sym *s); -void zerosig(char *sp); -void readundefs(char *f, int t); -void loadlib(void); -void errorexit(void); -void mangle(char*); -void objfile(char *file, char *pkg); -void libinit(void); -void pclntab(void); -void symtab(void); -void Lflag(char *arg); -void usage(void); -void adddynrel(Sym*, Reloc*); -void adddynrela(Sym*, Sym*, Reloc*); -void ldobj1(Biobuf *f, char*, int64 len, char *pn); -void ldobj(Biobuf*, char*, int64, char*, char*, int); -void ldelf(Biobuf*, char*, int64, char*); -void ldmacho(Biobuf*, char*, int64, char*); -void ldpe(Biobuf*, char*, int64, char*); -void ldpkg(Biobuf*, char*, int64, char*, int); -void mark(Sym *s); -void mkfwd(void); -char* expandpkg(char*, char*); -void deadcode(void); -Reloc* addrel(Sym*); -void codeblk(int32, int32); -void datblk(int32, int32); -void reloc(void); -void relocsym(Sym*); -void savedata(Sym*, Prog*, char*); -void symgrow(Sym*, int32); -void addstrdata(char*, char*); -vlong addstring(Sym*, char*); -vlong adduint8(Sym*, uint8); -vlong adduint16(Sym*, uint16); -vlong adduint32(Sym*, uint32); -vlong adduint64(Sym*, uint64); -vlong adduintxx(Sym*, uint64, int); -vlong addaddr(Sym*, Sym*); -vlong addaddrplus(Sym*, Sym*, vlong); -vlong addpcrelplus(Sym*, Sym*, vlong); -vlong addsize(Sym*, Sym*); -vlong setaddrplus(Sym*, vlong, Sym*, vlong); -vlong setaddr(Sym*, vlong, Sym*); -vlong setuint8(Sym*, vlong, uint8); -vlong setuint16(Sym*, vlong, uint16); -vlong setuint32(Sym*, vlong, uint32); -vlong setuint64(Sym*, vlong, uint64); -vlong setuintxx(Sym*, vlong, uint64, vlong); -void asmsym(void); -void asmelfsym(void); -void asmplan9sym(void); -void putelfsectionsym(Sym*, int); -void putelfsymshndx(vlong, int); -void strnput(char*, int); -void dodata(void); -void dosymtype(void); -void address(void); -void textaddress(void); -void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)); -vlong datoff(vlong); -void adddynlib(char*); -int archreloc(Reloc*, Sym*, vlong*); -void adddynsym(Sym*); -void addexport(void); -void dostkcheck(void); -void undef(void); -void doweak(void); -void setpersrc(Sym*); -void doversion(void); -void usage(void); -void setinterp(char*); -Sym* listsort(Sym*, int(*cmp)(Sym*, Sym*), int); -int valuecmp(Sym*, Sym*); -void hostobjs(void); -void hostlink(void); -char* estrdup(char*); -void* erealloc(void*, long); -Sym* defgostring(char*); - -int pathchar(void); -void* mal(uint32); -void unmal(void*, uint32); -void mywhatsys(void); -int rbyoff(const void*, const void*); - -uint16 le16(uchar*); -uint32 le32(uchar*); -uint64 le64(uchar*); -uint16 be16(uchar*); -uint32 be32(uchar*); -uint64 be64(uchar*); - typedef struct Endian Endian; struct Endian { @@ -325,28 +132,6 @@ enum { Pkgdef }; -/* executable header types */ -enum { - Hgarbunix = 0, // garbage unix - Hnoheader, // no header - Hunixcoff, // unix coff - Hrisc, // aif for risc os - Hplan9x32, // plan 9 32-bit format - Hplan9x64, // plan 9 64-bit format - Hmsdoscom, // MS-DOS .COM - Hnetbsd, // NetBSD - Hmsdosexe, // fake MS-DOS .EXE - Hixp1200, // IXP1200 (raw) - Helf, // ELF32 - Hipaq, // ipaq - Hdarwin, // Apple Mach-O - Hlinux, // Linux ELF - Hfreebsd, // FreeBSD ELF - Hwindows, // MS Windows PE - Hopenbsd, // OpenBSD ELF - Hdragonfly, // DragonFly ELF -}; - typedef struct Header Header; struct Header { char *name; @@ -356,14 +141,8 @@ struct Header { EXTERN char* headstring; extern Header headers[]; -int headtype(char*); -char* headstr(int); -void setheadtype(char*); - -int Yconv(Fmt*); - #pragma varargck type "O" int -#pragma varargck type "Y" Sym* +#pragma varargck type "Y" LSym* // buffered output @@ -383,29 +162,115 @@ EXTERN char* cbpmax; if(--cbc <= 0)\ cflush(); } +EXTERN int goarm; + +void Lflag(char *arg); +int Yconv(Fmt *fp); +int Zconv(Fmt *fp); +void addexport(void); +void address(void); +Section*addsection(Segment *seg, char *name, int rwx); +void addstrdata(char *name, char *value); +vlong addstring(LSym *s, char *str); +void asmelfsym(void); +void asmplan9sym(void); +uint16 be16(uchar *b); +uint32 be32(uchar *b); +uint64 be64(uchar *b); void cflush(void); +void codeblk(int32 addr, int32 size); vlong cpos(void); -void cseek(vlong); -void cwrite(void*, int); +void cseek(vlong p); +void cwrite(void *buf, int n); +void datblk(int32 addr, int32 size); +int datcmp(LSym *s1, LSym *s2); +vlong datoff(vlong addr); +void deadcode(void); +LSym* decodetype_arrayelem(LSym *s); +vlong decodetype_arraylen(LSym *s); +LSym* decodetype_chanelem(LSym *s); +int decodetype_funcdotdotdot(LSym *s); +int decodetype_funcincount(LSym *s); +LSym* decodetype_funcintype(LSym *s, int i); +int decodetype_funcoutcount(LSym *s); +LSym* decodetype_funcouttype(LSym *s, int i); +LSym* decodetype_gc(LSym *s); +vlong decodetype_ifacemethodcount(LSym *s); +uint8 decodetype_kind(LSym *s); +LSym* decodetype_mapkey(LSym *s); +LSym* decodetype_mapvalue(LSym *s); +LSym* decodetype_ptrelem(LSym *s); +vlong decodetype_size(LSym *s); +int decodetype_structfieldcount(LSym *s); +char* decodetype_structfieldname(LSym *s, int i); +vlong decodetype_structfieldoffs(LSym *s, int i); +LSym* decodetype_structfieldtype(LSym *s, int i); +void dodata(void); +void dostkcheck(void); +void dostkoff(void); +void dosymtype(void); +void doversion(void); +void doweak(void); +void dynreloc(void); +void dynrelocsym(LSym *s); +vlong entryvalue(void); +void errorexit(void); +void follow(void); +void genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)); +void growdatsize(vlong *datsizep, LSym *s); +char* headstr(int v); +int headtype(char *name); +void hostlink(void); +void hostobjs(void); +int iconv(Fmt *fp); void importcycles(void); -int Zconv(Fmt*); - -uint8 decodetype_kind(Sym*); -vlong decodetype_size(Sym*); -Sym* decodetype_gc(Sym*); -Sym* decodetype_arrayelem(Sym*); -vlong decodetype_arraylen(Sym*); -Sym* decodetype_ptrelem(Sym*); -Sym* decodetype_mapkey(Sym*); -Sym* decodetype_mapvalue(Sym*); -Sym* decodetype_chanelem(Sym*); -int decodetype_funcdotdotdot(Sym*); -int decodetype_funcincount(Sym*); -int decodetype_funcoutcount(Sym*); -Sym* decodetype_funcintype(Sym*, int); -Sym* decodetype_funcouttype(Sym*, int); -int decodetype_structfieldcount(Sym*); -char* decodetype_structfieldname(Sym*, int); -Sym* decodetype_structfieldtype(Sym*, int); -vlong decodetype_structfieldoffs(Sym*, int); -vlong decodetype_ifacemethodcount(Sym*); +void ldelf(Biobuf *f, char *pkg, int64 len, char *pn); +void ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file); +void ldmacho(Biobuf *f, char *pkg, int64 len, char *pn); +void ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence); +void ldpe(Biobuf *f, char *pkg, int64 len, char *pn); +void ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence); +uint16 le16(uchar *b); +uint32 le32(uchar *b); +uint64 le64(uchar *b); +void libinit(void); +LSym* listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off); +void loadinternal(char *name); +void loadlib(void); +void lputb(int32 l); +void lputl(int32 l); +void* mal(uint32 n); +void mark(LSym *s); +void mywhatsys(void); +struct ar_hdr; +int nextar(Biobuf *bp, int off, struct ar_hdr *a); +void objfile(char *file, char *pkg); +void patch(void); +int pathchar(void); +void pcln(void); +void pclntab(void); +void putelfsectionsym(LSym* s, int shndx); +void putelfsymshndx(vlong sympos, int shndx); +void putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ); +int rbyoff(const void *va, const void *vb); +void reloc(void); +void relocsym(LSym *s); +void setheadtype(char *s); +void setinterp(char *s); +void setlinkmode(char *arg); +void span(void); +void strnput(char *s, int n); +vlong symaddr(LSym *s); +void symtab(void); +void textaddress(void); +void undef(void); +void unmal(void *v, uint32 n); +void usage(void); +void vputb(uint64 v); +int valuecmp(LSym *a, LSym *b); +void vputl(uint64 v); +void wputb(ushort w); +void wputl(ushort w); +void xdefine(char *p, int t, vlong v); +void zerosig(char *sp); +void archinit(void); diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c index d135a92da..49db83eea 100644 --- a/src/cmd/ld/macho.c +++ b/src/cmd/ld/macho.c @@ -25,7 +25,7 @@ enum }; static int nkind[NumSymKind]; -static Sym** sortsym; +static LSym** sortsym; static int nsortsym; // Amount of space left for adding load commands @@ -232,37 +232,37 @@ machowrite(void) void domacho(void) { - Sym *s; + LSym *s; if(debug['d']) return; // empirically, string table must begin with " \x00". - s = lookup(".machosymstr", 0); + s = linklookup(ctxt, ".machosymstr", 0); s->type = SMACHOSYMSTR; s->reachable = 1; - adduint8(s, ' '); - adduint8(s, '\0'); + adduint8(ctxt, s, ' '); + adduint8(ctxt, s, '\0'); - s = lookup(".machosymtab", 0); + s = linklookup(ctxt, ".machosymtab", 0); s->type = SMACHOSYMTAB; s->reachable = 1; if(linkmode != LinkExternal) { - s = lookup(".plt", 0); // will be __symbol_stub + s = linklookup(ctxt, ".plt", 0); // will be __symbol_stub s->type = SMACHOPLT; s->reachable = 1; - s = lookup(".got", 0); // will be __nl_symbol_ptr + s = linklookup(ctxt, ".got", 0); // will be __nl_symbol_ptr s->type = SMACHOGOT; s->reachable = 1; s->align = 4; - s = lookup(".linkedit.plt", 0); // indirect table for .plt + s = linklookup(ctxt, ".linkedit.plt", 0); // indirect table for .plt s->type = SMACHOINDIRECTPLT; s->reachable = 1; - s = lookup(".linkedit.got", 0); // indirect table for .got + s = linklookup(ctxt, ".linkedit.got", 0); // indirect table for .got s->type = SMACHOINDIRECTGOT; s->reachable = 1; } @@ -334,7 +334,7 @@ machoshbits(MachoSeg *mseg, Section *sect, char *segname) if(strcmp(sect->name, ".got") == 0) { msect->name = "__nl_symbol_ptr"; msect->flag = 6; /* section with nonlazy symbol pointers */ - msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ + msect->res1 = linklookup(ctxt, ".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ } } @@ -432,13 +432,13 @@ asmbmacho(void) } if(!debug['d']) { - Sym *s1, *s2, *s3, *s4; + LSym *s1, *s2, *s3, *s4; // must match domacholink below - s1 = lookup(".machosymtab", 0); - s2 = lookup(".linkedit.plt", 0); - s3 = lookup(".linkedit.got", 0); - s4 = lookup(".machosymstr", 0); + s1 = linklookup(ctxt, ".machosymtab", 0); + s2 = linklookup(ctxt, ".linkedit.plt", 0); + s3 = linklookup(ctxt, ".linkedit.got", 0); + s4 = linklookup(ctxt, ".machosymstr", 0); if(linkmode != LinkExternal) { ms = newMachoSeg("__LINKEDIT", 0); @@ -484,7 +484,7 @@ asmbmacho(void) } static int -symkind(Sym *s) +symkind(LSym *s) { if(s->type == SDYNIMPORT) return SymKindUndef; @@ -494,7 +494,7 @@ symkind(Sym *s) } static void -addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotype) +addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype) { USED(name); USED(addr); @@ -524,11 +524,11 @@ addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotyp static int scmp(const void *p1, const void *p2) { - Sym *s1, *s2; + LSym *s1, *s2; int k1, k2; - s1 = *(Sym**)p1; - s2 = *(Sym**)p2; + s1 = *(LSym**)p1; + s2 = *(LSym**)p2; k1 = symkind(s1); k2 = symkind(s2); @@ -539,12 +539,12 @@ scmp(const void *p1, const void *p2) } static void -machogenasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) +machogenasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)) { - Sym *s; + LSym *s; genasmsym(put); - for(s=allsym; s; s=s->allsym) + for(s=ctxt->allsym; s; s=s->allsym) if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) if(s->reachable) put(s, nil, 'D', 0, 0, 0, nil); @@ -573,39 +573,39 @@ static void machosymtab(void) { int i; - Sym *symtab, *symstr, *s, *o; + LSym *symtab, *symstr, *s, *o; - symtab = lookup(".machosymtab", 0); - symstr = lookup(".machosymstr", 0); + symtab = linklookup(ctxt, ".machosymtab", 0); + symstr = linklookup(ctxt, ".machosymstr", 0); for(i=0; i<nsortsym; i++) { s = sortsym[i]; - adduint32(symtab, symstr->size); + adduint32(ctxt, symtab, symstr->size); // Only add _ to C symbols. Go symbols have dot in the name. if(strstr(s->extname, ".") == nil) - adduint8(symstr, '_'); + adduint8(ctxt, symstr, '_'); addstring(symstr, s->extname); if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) { - adduint8(symtab, 0x01); // type N_EXT, external symbol - adduint8(symtab, 0); // no section - adduint16(symtab, 0); // desc - adduintxx(symtab, 0, PtrSize); // no value + adduint8(ctxt, symtab, 0x01); // type N_EXT, external symbol + adduint8(ctxt, symtab, 0); // no section + adduint16(ctxt, symtab, 0); // desc + adduintxx(ctxt, symtab, 0, PtrSize); // no value } else { if(s->cgoexport) - adduint8(symtab, 0x0f); + adduint8(ctxt, symtab, 0x0f); else - adduint8(symtab, 0x0e); + adduint8(ctxt, symtab, 0x0e); o = s; while(o->outer != nil) o = o->outer; if(o->sect == nil) { diag("missing section for %s", s->name); - adduint8(symtab, 0); + adduint8(ctxt, symtab, 0); } else - adduint8(symtab, o->sect->extnum); - adduint16(symtab, 0); // desc - adduintxx(symtab, symaddr(s), PtrSize); + adduint8(ctxt, symtab, o->sect->extnum); + adduint16(ctxt, symtab, 0); // desc + adduintxx(ctxt, symtab, symaddr(s), PtrSize); } } } @@ -615,7 +615,7 @@ machodysymtab(void) { int n; MachoLoad *ml; - Sym *s1, *s2, *s3; + LSym *s1, *s2, *s3; ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */ @@ -639,9 +639,9 @@ machodysymtab(void) ml->data[11] = 0; /* nextrefsyms */ // must match domacholink below - s1 = lookup(".machosymtab", 0); - s2 = lookup(".linkedit.plt", 0); - s3 = lookup(".linkedit.got", 0); + s1 = linklookup(ctxt, ".machosymtab", 0); + s2 = linklookup(ctxt, ".linkedit.plt", 0); + s3 = linklookup(ctxt, ".linkedit.got", 0); ml->data[12] = linkoff + s1->size; /* indirectsymoff */ ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */ @@ -655,15 +655,15 @@ vlong domacholink(void) { int size; - Sym *s1, *s2, *s3, *s4; + LSym *s1, *s2, *s3, *s4; machosymtab(); // write data that will be linkedit section - s1 = lookup(".machosymtab", 0); - s2 = lookup(".linkedit.plt", 0); - s3 = lookup(".linkedit.got", 0); - s4 = lookup(".machosymstr", 0); + s1 = linklookup(ctxt, ".machosymtab", 0); + s2 = linklookup(ctxt, ".linkedit.plt", 0); + s3 = linklookup(ctxt, ".linkedit.got", 0); + s4 = linklookup(ctxt, ".machosymstr", 0); // Force the linkedit section to end on a 16-byte // boundary. This allows pure (non-cgo) Go binaries @@ -683,7 +683,7 @@ domacholink(void) // any alignment padding itself, working around the // issue. while(s4->size%16) - adduint8(s4, 0); + adduint8(ctxt, s4, 0); size = s1->size + s2->size + s3->size + s4->size; @@ -702,9 +702,9 @@ domacholink(void) void -machorelocsect(Section *sect, Sym *first) +machorelocsect(Section *sect, LSym *first) { - Sym *sym; + LSym *sym; int32 eaddr; Reloc *r; @@ -726,7 +726,7 @@ machorelocsect(Section *sect, Sym *first) continue; if(sym->value >= eaddr) break; - cursym = sym; + ctxt->cursym = sym; for(r = sym->r; r < sym->r+sym->nr; r++) { if(r->done) @@ -747,7 +747,7 @@ machoemitreloc(void) while(cpos()&7) cput(0); - machorelocsect(segtext.sect, textp); + machorelocsect(segtext.sect, ctxt->textp); for(sect=segtext.sect->next; sect!=nil; sect=sect->next) machorelocsect(sect, datap); for(sect=segdata.sect; sect!=nil; sect=sect->next) diff --git a/src/cmd/ld/pass.c b/src/cmd/ld/pass.c new file mode 100644 index 000000000..788b7c75a --- /dev/null +++ b/src/cmd/ld/pass.c @@ -0,0 +1,104 @@ +// Inferno utils/6l/pass.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/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. + +// Code and data passes. + +#include "l.h" +#include "../ld/lib.h" +#include "../../pkg/runtime/stack.h" + +void +follow(void) +{ + LSym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->follow(ctxt, s); +} + +void +patch(void) +{ + LSym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f mkfwd\n", cputime()); + Bflush(&bso); + for(s = ctxt->textp; s != nil; s = s->next) + mkfwd(s); + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + + if(flag_shared) { + s = linklookup(ctxt, "init_array", 0); + s->type = SINITARR; + s->reachable = 1; + s->hide = 1; + addaddr(ctxt, s, linklookup(ctxt, INITENTRY, 0)); + } + + for(s = ctxt->textp; s != nil; s = s->next) + linkpatch(ctxt, s); +} + +void +dostkoff(void) +{ + LSym *s; + + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->addstacksplit(ctxt, s); +} + +void +span(void) +{ + LSym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->assemble(ctxt, s); +} + +void +pcln(void) +{ + LSym *s; + + for(s = ctxt->textp; s != nil; s = s->next) + linkpcln(ctxt, s); +} diff --git a/src/cmd/ld/pcln.c b/src/cmd/ld/pcln.c new file mode 100644 index 000000000..5934dbcdf --- /dev/null +++ b/src/cmd/ld/pcln.c @@ -0,0 +1,258 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "l.h" +#include "lib.h" +#include "../../pkg/runtime/funcdata.h" + +static void +addvarint(Pcdata *d, uint32 val) +{ + int32 n; + uint32 v; + uchar *p; + + n = 0; + for(v = val; v >= 0x80; v >>= 7) + n++; + n++; + + if(d->n + n > d->m) { + d->m = (d->n + n)*2; + d->p = erealloc(d->p, d->m); + } + + p = d->p + d->n; + for(v = val; v >= 0x80; v >>= 7) + *p++ = v | 0x80; + *p++ = v; + d->n += n; +} + +static int32 +addpctab(LSym *ftab, int32 off, Pcdata *d) +{ + int32 start; + + start = ftab->np; + symgrow(ctxt, ftab, start + d->n); + memmove(ftab->p + start, d->p, d->n); + + return setuint32(ctxt, ftab, off, start); +} + +static int32 +ftabaddstring(LSym *ftab, char *s) +{ + int32 n, start; + + n = strlen(s)+1; + start = ftab->np; + symgrow(ctxt, ftab, start+n+1); + strcpy((char*)ftab->p + start, s); + return start; +} + +static uint32 +getvarint(uchar **pp) +{ + uchar *p; + int shift; + uint32 v; + + v = 0; + p = *pp; + for(shift = 0;; shift += 7) { + v |= (*p & 0x7F) << shift; + if(!(*p++ & 0x80)) + break; + } + *pp = p; + return v; +} + +static void +renumberfiles(LSym **files, int nfiles, Pcdata *d) +{ + int i; + LSym *f; + Pcdata out; + uint32 v; + int32 oldval, newval, val, dv; + uchar *p; + + // Give files numbers. + for(i=0; i<nfiles; i++) { + f = files[i]; + if(f->type != SFILEPATH) { + f->value = ++ctxt->nhistfile; + f->type = SFILEPATH; + f->next = ctxt->filesyms; + ctxt->filesyms = f; + } + } + + oldval = -1; + newval = -1; + memset(&out, 0, sizeof out); + p = d->p; + while(p < d->p + d->n) { + // value delta + v = getvarint(&p); + if(v == 0 && p != d->p) { + addvarint(&out, 0); + break; + } + dv = (int32)(v>>1) ^ ((int32)(v<<31)>>31); + oldval += dv; + if(oldval == -1) + val = -1; + else { + if(oldval < 0 || oldval >= nfiles) + sysfatal("bad pcdata %d", oldval); + val = files[oldval]->value; + } + dv = val - newval; + v = (uint32)(dv<<1) ^ (uint32)(dv>>31); + addvarint(&out, v); + + // pc delta + v = getvarint(&p); + addvarint(&out, v); + } + + free(d->p); + *d = out; +} + + +// pclntab initializes the pclntab symbol with +// runtime function and file name information. +void +pclntab(void) +{ + int32 i, nfunc, start, funcstart; + LSym *ftab, *s; + int32 off, end; + int64 funcdata_bytes; + Pcln *pcln; + static Pcln zpcln; + + funcdata_bytes = 0; + ftab = linklookup(ctxt, "pclntab", 0); + ftab->type = SPCLNTAB; + ftab->reachable = 1; + + // See golang.org/s/go12symtab for the format. Briefly: + // 8-byte header + // nfunc [PtrSize bytes] + // function table, alternating PC and offset to func struct [each entry PtrSize bytes] + // end PC [PtrSize bytes] + // offset to file table [4 bytes] + nfunc = 0; + for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) + nfunc++; + symgrow(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4); + setuint32(ctxt, ftab, 0, 0xfffffffb); + setuint8(ctxt, ftab, 6, MINLC); + setuint8(ctxt, ftab, 7, PtrSize); + setuintxx(ctxt, ftab, 8, nfunc, PtrSize); + + nfunc = 0; + for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next, nfunc++) { + pcln = ctxt->cursym->pcln; + if(pcln == nil) + pcln = &zpcln; + + funcstart = ftab->np; + funcstart += -ftab->np & (PtrSize-1); + + setaddr(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize, ctxt->cursym); + setuintxx(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize); + + // fixed size of struct, checked below + off = funcstart; + end = funcstart + PtrSize + 3*4 + 5*4 + pcln->npcdata*4 + pcln->nfuncdata*PtrSize; + if(pcln->nfuncdata > 0 && (end&(PtrSize-1))) + end += 4; + symgrow(ctxt, ftab, end); + + // entry uintptr + off = setaddr(ctxt, ftab, off, ctxt->cursym); + + // name int32 + off = setuint32(ctxt, ftab, off, ftabaddstring(ftab, ctxt->cursym->name)); + + // args int32 + // TODO: Move into funcinfo. + if(ctxt->cursym->text == nil) + off = setuint32(ctxt, ftab, off, ArgsSizeUnknown); + else + off = setuint32(ctxt, ftab, off, ctxt->cursym->args); + + // frame int32 + // TODO: Remove entirely. The pcsp table is more precise. + // This is only used by a fallback case during stack walking + // when a called function doesn't have argument information. + // We need to make sure everything has argument information + // and then remove this. + if(ctxt->cursym->text == nil) + off = setuint32(ctxt, ftab, off, 0); + else + off = setuint32(ctxt, ftab, off, (uint32)ctxt->cursym->text->to.offset+PtrSize); + + if(pcln != &zpcln) + renumberfiles(pcln->file, pcln->nfile, &pcln->pcfile); + + // pcdata + off = addpctab(ftab, off, &pcln->pcsp); + off = addpctab(ftab, off, &pcln->pcfile); + off = addpctab(ftab, off, &pcln->pcline); + off = setuint32(ctxt, ftab, off, pcln->npcdata); + off = setuint32(ctxt, ftab, off, pcln->nfuncdata); + for(i=0; i<pcln->npcdata; i++) + off = addpctab(ftab, off, &pcln->pcdata[i]); + + // funcdata, must be pointer-aligned and we're only int32-aligned. + // Missing funcdata will be 0 (nil pointer). + if(pcln->nfuncdata > 0) { + if(off&(PtrSize-1)) + off += 4; + for(i=0; i<pcln->nfuncdata; i++) { + if(pcln->funcdata[i] == nil) + setuintxx(ctxt, ftab, off+PtrSize*i, pcln->funcdataoff[i], PtrSize); + else { + // TODO: Dedup. + funcdata_bytes += pcln->funcdata[i]->size; + setaddrplus(ctxt, ftab, off+PtrSize*i, pcln->funcdata[i], pcln->funcdataoff[i]); + } + } + off += pcln->nfuncdata*PtrSize; + } + + if(off != end) { + diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d)", funcstart, off, end, pcln->npcdata, pcln->nfuncdata); + errorexit(); + } + + // Final entry of table is just end pc. + if(ctxt->cursym->next == nil) + setaddrplus(ctxt, ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, ctxt->cursym, ctxt->cursym->size); + } + + // Start file table. + start = ftab->np; + start += -ftab->np & (PtrSize-1); + setuint32(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start); + + symgrow(ctxt, ftab, start+(ctxt->nhistfile+1)*4); + setuint32(ctxt, ftab, start, ctxt->nhistfile); + for(s = ctxt->filesyms; s != S; s = s->next) + setuint32(ctxt, ftab, start + s->value*4, ftabaddstring(ftab, s->name)); + + ftab->size = ftab->np; + + if(debug['v']) + Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes); +} diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c index 7b9a596fc..e4848643e 100644 --- a/src/cmd/ld/pe.c +++ b/src/cmd/ld/pe.c @@ -37,7 +37,7 @@ static char *symlabels[] = { "symtab", "esymtab", "pclntab", "epclntab" }; -static Sym *rsrcsym; +static LSym *rsrcsym; static char symnames[256]; static int nextsymoff; @@ -62,7 +62,7 @@ static IMAGE_DATA_DIRECTORY* dd; typedef struct Imp Imp; struct Imp { - Sym* s; + LSym* s; uvlong off; Imp* next; }; @@ -78,7 +78,7 @@ struct Dll { static Dll* dr; -static Sym *dexport[1024]; +static LSym *dexport[1024]; static int nexport; static IMAGE_SECTION_HEADER* @@ -191,11 +191,11 @@ initdynimport(void) { Imp *m; Dll *d; - Sym *s, *dynamic; + LSym *s, *dynamic; dr = nil; m = nil; - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(!s->reachable || s->type != SDYNIMPORT) continue; for(d = dr; d != nil; d = d->next) { @@ -216,7 +216,7 @@ initdynimport(void) d->ms = m; } - dynamic = lookup(".windynamic", 0); + dynamic = linklookup(ctxt, ".windynamic", 0); dynamic->reachable = 1; dynamic->type = SWINDOWS; for(d = dr; d != nil; d = d->next) { @@ -241,10 +241,10 @@ addimports(IMAGE_SECTION_HEADER *datsect) vlong startoff, endoff; Imp *m; Dll *d; - Sym* dynamic; + LSym* dynamic; startoff = cpos(); - dynamic = lookup(".windynamic", 0); + dynamic = linklookup(ctxt, ".windynamic", 0); // skip import descriptor table (will write it later) n = 0; @@ -322,20 +322,20 @@ addimports(IMAGE_SECTION_HEADER *datsect) static int scmp(const void *p1, const void *p2) { - Sym *s1, *s2; + LSym *s1, *s2; - s1 = *(Sym**)p1; - s2 = *(Sym**)p2; + s1 = *(LSym**)p1; + s2 = *(LSym**)p2; return strcmp(s1->extname, s2->extname); } static void initdynexport(void) { - Sym *s; + LSym *s; nexport = 0; - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(!s->reachable || !(s->cgoexport & CgoExportDynamic)) continue; if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) { @@ -410,10 +410,10 @@ addexports(void) void dope(void) { - Sym *rel; + LSym *rel; /* relocation table */ - rel = lookup(".rel", 0); + rel = linklookup(ctxt, ".rel", 0); rel->reachable = 1; rel->type = SELFROSECT; @@ -459,7 +459,7 @@ addsymtable(void) { IMAGE_SECTION_HEADER *h; int i, size; - Sym *s; + LSym *s; fh.NumberOfSymbols = sizeof(symlabels)/sizeof(symlabels[0]); size = nextsymoff + 4 + 18*fh.NumberOfSymbols; @@ -471,7 +471,7 @@ addsymtable(void) // put COFF symbol table for (i=0; i<fh.NumberOfSymbols; i++) { - s = rlookup(symlabels[i], 0); + s = linkrlookup(ctxt, symlabels[i], 0); strnput(s->name, 8); lputl(datoff(s->value)); wputl(textsect); @@ -488,7 +488,7 @@ addsymtable(void) } void -setpersrc(Sym *sym) +setpersrc(LSym *sym) { if(rsrcsym != nil) diag("too many .rsrc sections"); @@ -535,14 +535,14 @@ addexcept(IMAGE_SECTION_HEADER *text) IMAGE_SECTION_HEADER *pdata, *xdata; vlong startoff; uvlong n; - Sym *sym; + LSym *sym; USED(text); if(thechar != '6') return; // write unwind info - sym = lookup("runtime.sigtramp", 0); + sym = linklookup(ctxt, "runtime.sigtramp", 0); startoff = cpos(); lputl(9); // version=1, flags=UNW_FLAG_EHANDLER, rest 0 lputl(sym->value - PEBASE); diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h index 7aa938829..03ed8d830 100644 --- a/src/cmd/ld/pe.h +++ b/src/cmd/ld/pe.h @@ -176,4 +176,4 @@ typedef struct { IMAGE_DATA_DIRECTORY DataDirectory[16]; } PE64_IMAGE_OPTIONAL_HEADER; -void setpersrc(Sym *sym); +void setpersrc(LSym *sym); diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c new file mode 100644 index 000000000..8883d3786 --- /dev/null +++ b/src/cmd/ld/pobj.c @@ -0,0 +1,223 @@ +// Inferno utils/6l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/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. + +// Reading object files. + +#define EXTERN +#include "l.h" +#include "../ld/lib.h" +#include "../ld/elf.h" +#include "../ld/macho.h" +#include "../ld/dwarf.h" +#include "../ld/pe.h" +#include <ar.h> + +char *noname = "<none>"; +char* paramspace = "FP"; + +Header headers[] = { + "darwin", Hdarwin, + "dragonfly", Hdragonfly, + "elf", Helf, + "freebsd", Hfreebsd, + "linux", Hlinux, + "netbsd", Hnetbsd, + "openbsd", Hopenbsd, + "plan9", Hplan9, + "windows", Hwindows, + "windowsgui", Hwindows, + 0, 0 +}; + +void +main(int argc, char *argv[]) +{ + char *p; + + ctxt = linknew(thelinkarch); + ctxt->thechar = thechar; + ctxt->thestring = thestring; + ctxt->diag = diag; + ctxt->dwarfaddfrag = dwarfaddfrag; + ctxt->bso = &bso; + + Binit(&bso, 1, OWRITE); + listinit(); + memset(debug, 0, sizeof(debug)); + nerrors = 0; + outfile = nil; + HEADTYPE = -1; + INITTEXT = -1; + INITDAT = -1; + INITRND = -1; + INITENTRY = 0; + linkmode = LinkAuto; + nuxiinit(); + + if(thechar == '5') { + p = getgoarm(); + if(p != nil) + goarm = atoi(p); + else + goarm = 6; + if(goarm == 5) + debug['F'] = 1; + ctxt->goarm = goarm; + } + + flagcount("1", "use alternate profiling code", &debug['1']); + if(thechar == '6') + flagcount("8", "assume 64-bit addresses", &debug['8']); + flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); + flagint64("D", "addr: data address", &INITDAT); + flagstr("E", "sym: entry symbol", &INITENTRY); + if(thechar == '5') + flagcount("G", "debug pseudo-ops", &debug['G']); + flagfn1("I", "interp: set ELF interp", setinterp); + flagfn1("L", "dir: add dir to library path", Lflag); + flagfn1("H", "head: header type", setheadtype); + flagcount("K", "add stack underflow checks", &debug['K']); + if(thechar == '5') + flagcount("M", "disable software div/mod", &debug['M']); + flagcount("O", "print pc-line tables", &debug['O']); + flagcount("Q", "debug byte-register code gen", &debug['Q']); + if(thechar == '5') + flagcount("P", "debug code generation", &debug['P']); + flagint32("R", "rnd: address rounding", &INITRND); + flagcount("S", "check type signatures", &debug['S']); + flagint64("T", "addr: text address", &INITTEXT); + flagfn0("V", "print version and exit", doversion); + flagcount("W", "disassemble input", &debug['W']); + flagfn2("X", "name value: define string data", addstrdata); + flagcount("Z", "clear stack frame on entry", &debug['Z']); + flagcount("a", "disassemble output", &debug['a']); + flagcount("c", "dump call graph", &debug['c']); + flagcount("d", "disable dynamic executable", &debug['d']); + flagstr("extld", "linker to run in external mode", &extld); + flagstr("extldflags", "flags for external linker", &extldflags); + flagcount("f", "ignore version mismatch", &debug['f']); + flagcount("g", "disable go package data checks", &debug['g']); + flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); + flagstr("k", "sym: set field tracking symbol", &tracksym); + flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode); + flagcount("n", "dump symbol table", &debug['n']); + flagstr("o", "outfile: set output file", &outfile); + flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); + flagcount("race", "enable race detector", &flag_race); + flagcount("s", "disable symbol table", &debug['s']); + if(thechar == '5' || thechar == '6') + flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared); + flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); + flagcount("u", "reject unsafe packages", &debug['u']); + flagcount("v", "print link trace", &debug['v']); + flagcount("w", "disable DWARF generation", &debug['w']); + + flagparse(&argc, &argv, usage); + ctxt->bso = &bso; + ctxt->debugdivmod = debug['M']; + ctxt->debugfloat = debug['F']; + ctxt->debughist = debug['O']; + ctxt->debugpcln = debug['O']; + ctxt->debugread = debug['W']; + ctxt->debugstack = debug['K']; + ctxt->debugvlog = debug['v']; + + if(argc != 1) + usage(); + + if(outfile == nil) { + if(HEADTYPE == Hwindows) + outfile = smprint("%c.out.exe", thechar); + else + outfile = smprint("%c.out", thechar); + } + libinit(); // creates outfile + + if(HEADTYPE == -1) + HEADTYPE = headtype(goos); + ctxt->headtype = HEADTYPE; + + archinit(); + ctxt->linkmode = linkmode; + ctxt->debugfloat = debug['F']; + + if(debug['v']) + Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n", + HEADTYPE, INITTEXT, INITDAT, INITRND); + Bflush(&bso); + + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); + + addlibpath(ctxt, "command line", "command line", argv[0], "main"); + loadlib(); + + if(thechar == '5') { + // mark some functions that are only referenced after linker code editing + if(debug['F']) + mark(linkrlookup(ctxt, "_sfloat", 0)); + mark(linklookup(ctxt, "runtime.read_tls_fallback", 0)); + } + + deadcode(); + patch(); + follow(); + dostkoff(); + paramspace = "SP"; /* (FP) now (SP) on output */ + span(); + pcln(); + + doelf(); + if(HEADTYPE == Hdarwin) + domacho(); + dostkcheck(); + if(HEADTYPE == Hwindows) + dope(); + addexport(); + textaddress(); + pclntab(); + symtab(); + dodata(); + address(); + doweak(); + reloc(); + asmb(); + undef(); + hostlink(); + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + Bprint(&bso, "%d symbols\n", ctxt->nsymbol); + Bprint(&bso, "%d sizeof adr\n", sizeof(Addr)); + Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); + } + Bflush(&bso); + + errorexit(); +} diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c index c9b4657f7..54e604148 100644 --- a/src/cmd/ld/symtab.c +++ b/src/cmd/ld/symtab.c @@ -86,10 +86,10 @@ static int numelfsym = 1; // 0 is reserved static int elfbind; static void -putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) +putelfsym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go) { int bind, type, off; - Sym *xo; + LSym *xo; USED(go); switch(t) { @@ -109,12 +109,12 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) while(xo->outer != nil) xo = xo->outer; if(xo->sect == nil) { - cursym = x; + ctxt->cursym = x; diag("missing section in putelfsym"); return; } if(xo->sect->elfsect == nil) { - cursym = x; + ctxt->cursym = x; diag("missing ELF section in putelfsym"); return; } @@ -143,7 +143,7 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) } void -putelfsectionsym(Sym* s, int shndx) +putelfsectionsym(LSym* s, int shndx) { putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0); s->elfsym = numelfsym++; @@ -170,7 +170,7 @@ putelfsymshndx(vlong sympos, int shndx) void asmelfsym(void) { - Sym *s; + LSym *s; // the first symbol entry is reserved putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0); @@ -181,9 +181,9 @@ asmelfsym(void) genasmsym(putelfsym); if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) { - s = lookup("runtime.tlsgm", 0); + s = linklookup(ctxt, "runtime.tlsgm", 0); if(s->sect == nil) { - cursym = nil; + ctxt->cursym = nil; diag("missing section for %s", s->name); errorexit(); } @@ -195,7 +195,7 @@ asmelfsym(void) elfglobalsymndx = numelfsym; genasmsym(putelfsym); - for(s=allsym; s!=S; s=s->allsym) { + for(s=ctxt->allsym; s!=S; s=s->allsym) { if(s->type != SHOSTOBJ) continue; putelfsyment(putelfstr(s->name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0); @@ -204,7 +204,7 @@ asmelfsym(void) } static void -putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) +putplan9sym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go) { int i, l; @@ -226,7 +226,7 @@ putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) case 'Z': case 'm': l = 4; - if(HEADTYPE == Hplan9x64 && !debug['8']) { + if(HEADTYPE == Hplan9 && thechar == '6' && !debug['8']) { lputb(addr>>32); l = 8; } @@ -263,14 +263,14 @@ asmplan9sym(void) genasmsym(putplan9sym); } -static Sym *symt; +static LSym *symt; static void scput(int b) { uchar *p; - symgrow(symt, symt->size+1); + symgrow(ctxt, symt, symt->size+1); p = symt->p + symt->size; *p = b; symt->size++; @@ -281,7 +281,7 @@ slputb(int32 v) { uchar *p; - symgrow(symt, symt->size+4); + symgrow(ctxt, symt, symt->size+4); p = symt->p + symt->size; *p++ = v>>24; *p++ = v>>16; @@ -295,7 +295,7 @@ slputl(int32 v) { uchar *p; - symgrow(symt, symt->size+4); + symgrow(ctxt, symt, symt->size+4); p = symt->p + symt->size; *p++ = v; *p++ = v>>8; @@ -355,7 +355,7 @@ vputl(uint64 v) // Emit symbol table entry. // The table format is described at the top of ../../pkg/runtime/symtab.c. void -putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ) +putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ) { int i, f, c; vlong v1; @@ -457,7 +457,7 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ) void symtab(void) { - Sym *s, *symtype, *symtypelink, *symgostring, *symgofunc; + LSym *s, *symtype, *symtypelink, *symgostring, *symgofunc; dosymtype(); @@ -482,40 +482,40 @@ symtab(void) xdefine("esymtab", SRODATA, 0); // garbage collection symbols - s = lookup("gcdata", 0); + s = linklookup(ctxt, "gcdata", 0); s->type = SRODATA; s->size = 0; s->reachable = 1; xdefine("egcdata", SRODATA, 0); - s = lookup("gcbss", 0); + s = linklookup(ctxt, "gcbss", 0); s->type = SRODATA; s->size = 0; s->reachable = 1; xdefine("egcbss", SRODATA, 0); // pseudo-symbols to mark locations of type, string, and go string data. - s = lookup("type.*", 0); + s = linklookup(ctxt, "type.*", 0); s->type = STYPE; s->size = 0; s->reachable = 1; symtype = s; - s = lookup("go.string.*", 0); + s = linklookup(ctxt, "go.string.*", 0); s->type = SGOSTRING; s->size = 0; s->reachable = 1; symgostring = s; - s = lookup("go.func.*", 0); + s = linklookup(ctxt, "go.func.*", 0); s->type = SGOFUNC; s->size = 0; s->reachable = 1; symgofunc = s; - symtypelink = lookup("typelink", 0); + symtypelink = linklookup(ctxt, "typelink", 0); - symt = lookup("symtab", 0); + symt = linklookup(ctxt, "symtab", 0); symt->type = SSYMTAB; symt->size = 0; symt->reachable = 1; @@ -524,7 +524,7 @@ symtab(void) // within a type they sort by size, so the .* symbols // just defined above will be first. // hide the specific symbols. - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(!s->reachable || s->special || s->type != SRODATA) continue; if(strncmp(s->name, "type.", 5) == 0) { diff --git a/src/liblink/Makefile b/src/liblink/Makefile new file mode 100644 index 000000000..2a317462b --- /dev/null +++ b/src/liblink/Makefile @@ -0,0 +1,5 @@ +# Copyright 2013 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +include ../Make.dist diff --git a/src/liblink/asm5.c b/src/liblink/asm5.c new file mode 100644 index 000000000..8ed8bea57 --- /dev/null +++ b/src/liblink/asm5.c @@ -0,0 +1,2443 @@ +// Inferno utils/5l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/5l/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. + +// Instruction layout. + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> +#include "../cmd/5l/5.out.h" +#include "../pkg/runtime/stack.h" + +typedef struct Optab Optab; +typedef struct Oprang Oprang; +typedef uchar Opcross[32][2][32]; + +struct Optab +{ + char as; + uchar a1; + char a2; + uchar a3; + uchar type; + char size; + char param; + char flag; + uchar pcrelsiz; +}; +struct Oprang +{ + Optab* start; + Optab* stop; +}; + +enum +{ + LFROM = 1<<0, + LTO = 1<<1, + LPOOL = 1<<2, + LPCREL = 1<<3, + + C_NONE = 0, + C_REG, + C_REGREG, + C_REGREG2, + C_SHIFT, + C_FREG, + C_PSR, + C_FCR, + + C_RCON, /* 0xff rotated */ + C_NCON, /* ~RCON */ + C_SCON, /* 0xffff */ + C_LCON, + C_LCONADDR, + C_ZFCON, + C_SFCON, + C_LFCON, + + C_RACON, + C_LACON, + + C_SBRA, + C_LBRA, + + C_HAUTO, /* halfword insn offset (-0xff to 0xff) */ + C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */ + C_HFAUTO, /* both H and F */ + C_SAUTO, /* -0xfff to 0xfff */ + C_LAUTO, + + C_HOREG, + C_FOREG, + C_HFOREG, + C_SOREG, + C_ROREG, + C_SROREG, /* both nil and R */ + C_LOREG, + + C_PC, + C_SP, + C_HREG, + + C_ADDR, /* reference to relocatable address */ + + C_GOK, +}; + +static Optab optab[] = +{ + /* struct Optab: + OPCODE, from, prog->reg, to, type,size,param,flag */ + { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 }, + { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 }, + + { AADD, C_REG, C_REG, C_REG, 1, 4, 0 }, + { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 }, + { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 }, + { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 }, + + { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 }, + { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 }, + { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 }, + { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 }, + { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 }, + + { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 }, + { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, + { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, + { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 }, + + { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP }, + + { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL }, + { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, + { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 }, + { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, + + { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL }, + { ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0 }, + { ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0 }, + { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 }, + { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 }, + + { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 }, + { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 }, + + { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 }, + { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 }, + + { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 }, + { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 }, + { ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 }, + + { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 }, + { AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0 }, + { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 }, + + { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 }, + { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM }, + { AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4}, + + { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 }, + { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 }, + { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 }, + { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 }, + { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM }, + { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM }, + { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM }, + { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM }, + + { AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0 }, + { AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0 }, + { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 }, + { AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0 }, + { AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0 }, + { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 }, + + { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 }, + { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 }, + + { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 }, + { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 }, + + { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 }, + { AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, + { AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, + { AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, + { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, + { AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, + { AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, + { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, + { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, + + { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, + { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, + { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, + { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, + { AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, + { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, + { AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, + { AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, + { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, + { AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, + { AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, + { AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, + { AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, + { AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, + { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, + + { AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM }, + { AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM }, + { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 }, + { AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM }, + { AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM }, + { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 }, + + { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM }, + + { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 }, + { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 }, + + { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 }, + { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 }, + + { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 }, + + { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 }, + + { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP }, + { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 }, + + { AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP }, + { AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 }, + + { AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO }, + { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO }, + + { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM }, + { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM }, + + { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4 }, + { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4}, + + { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, + { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 }, + { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 }, + { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 }, + + { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 }, + { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 }, + + { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 }, + { AMOVBS, C_SHIFT,C_NONE, C_REG, 60, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, + { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, + { AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, + { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, + + { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8 }, + { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, LPCREL, 0 }, + + { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, + { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, + { AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, + { AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, + { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, + { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, + + { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, + { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, + { AMOVBS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, + { AMOVBS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, + { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, + { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, + { AMOVHS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, + { AMOVHS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, + { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, + { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, + + { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, + { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, + { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, + { AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, + { AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, + { AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, + { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, + { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, + { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, + + { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, + { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, + { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, + { AMOVBS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, + { AMOVBS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, + { AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, + { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, + { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, + { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, + { AMOVHS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, + { AMOVHS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, + { AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, + { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, + { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, + { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, + + { ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 }, + { ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 }, + + { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 8, 0 }, + { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 }, + + { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 }, + { ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0 }, + + { AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0 }, + { AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0 }, + + { AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0 }, + { AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0 }, + + { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 }, + { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 }, + + { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 }, + + { ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 }, + { ASTREXD, C_SOREG,C_REG, C_REG, 92, 4, 0 }, + + { APLD, C_SOREG,C_NONE, C_NONE, 95, 4, 0 }, + + { AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0 }, + + { ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0 }, + + { AMULWT, C_REG, C_REG, C_REG, 98, 4, 0 }, + { AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0 }, + + { AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0 }, + { APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0 }, + { AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0 }, + + { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 }, +}; + +static struct { + uint32 start; + uint32 size; + uint32 extra; +} pool; + +static int checkpool(Link*, Prog*, int); +static int flushpool(Link*, Prog*, int, int); +static void addpool(Link*, Prog*, Addr*); +static void asmout(Link*, Prog*, Optab*, int32*, LSym*); +static Optab* oplook(Link*, Prog*); +static int32 oprrr(Link*, int, int); +static int32 olr(Link*, int32, int, int, int); +static int32 olhr(Link*, int32, int, int, int); +static int32 olrr(Link*, int, int, int, int); +static int32 olhrr(Link*, int, int, int, int); +static int32 osr(Link*, int, int, int32, int, int); +static int32 oshr(Link*, int, int32, int, int); +static int32 ofsr(Link*, int, int, int32, int, int, Prog*); +static int32 osrr(Link*, int, int, int, int); +static int32 oshrr(Link*, int, int, int, int); +static int32 omvl(Link*, Prog*, Addr*, int); +static int32 immaddr(int32); +static int aclass(Link*, Addr*); +static int chipzero(Link*, float64); +static int chipfloat(Link*, float64); +static int32 immrot(uint32); +static int32 immaddr(int32); +static int32 opbra(Link*, int, int); + +static Opcross opcross[8]; +static Oprang oprange[ALAST]; +static char xcmp[C_GOK+1][C_GOK+1]; +static uchar repop[ALAST]; + +static Prog zprg = { + .as = AGOK, + .scond = 14, + .reg = NREG, + .from = { + .name = D_NONE, + .type = D_NONE, + .reg = NREG, + }, + .to = { + .name = D_NONE, + .type = D_NONE, + .reg = NREG, + }, +}; + +static void +nocache(Prog *p) +{ + p->optab = 0; + p->from.class = 0; + p->to.class = 0; +} + +static int +scan(Link *ctxt, Prog *op, Prog *p, int c) +{ + Prog *q; + + for(q = op->link; q != p && q != nil; q = q->link){ + q->pc = c; + c += oplook(ctxt, q)->size; + nocache(q); + } + return c; +} + +/* size of a case statement including jump table */ +static int32 +casesz(Link *ctxt, Prog *p) +{ + int jt = 0; + int32 n = 0; + Optab *o; + + for( ; p != nil; p = p->link){ + if(p->as == ABCASE) + jt = 1; + else if(jt) + break; + o = oplook(ctxt, p); + n += o->size; + } + return n; +} + +static void buildop(Link*); + +void +span5(Link *ctxt, LSym *cursym) +{ + Prog *p, *op; + Optab *o; + int m, bflag, i, v; + int32 c, out[6]; + uchar *bp; + LSym *gmsym; + + p = cursym->text; + if(p == nil || p->link == nil) // handle external functions and ELF section symbols + return; + + if(oprange[AAND].start == nil) + buildop(ctxt); + + ctxt->cursym = cursym; + + ctxt->autosize = p->to.offset + 4; + c = 0; + + for(op = p, p = p->link; p != nil; op = p, p = p->link) { + ctxt->curp = p; + p->pc = c; + o = oplook(ctxt, p); + m = o->size; + // must check literal pool here in case p generates many instructions + if(ctxt->blitrl){ + if(checkpool(ctxt, op, p->as == ACASE ? casesz(ctxt, p) : m)) + c = p->pc = scan(ctxt, op, p, c); + } + if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) { + ctxt->diag("zero-width instruction\n%P", p); + continue; + } + switch(o->flag & (LFROM|LTO|LPOOL)) { + case LFROM: + addpool(ctxt, p, &p->from); + break; + case LTO: + addpool(ctxt, p, &p->to); + break; + case LPOOL: + if ((p->scond&C_SCOND) == 14) + flushpool(ctxt, p, 0, 0); + break; + } + if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14) + flushpool(ctxt, p, 0, 0); + c += m; + } + if(ctxt->blitrl){ + if(checkpool(ctxt, op, 0)) + c = scan(ctxt, op, nil, c); + } + cursym->size = c; + + /* + * if any procedure is large enough to + * generate a large SBRA branch, then + * generate extra passes putting branches + * around jmps to fix. this is rare. + */ + do { + if(ctxt->debugvlog) + Bprint(ctxt->bso, "%5.2f span1\n", cputime()); + bflag = 0; + c = 0; + for(p = cursym->text; p != nil; p = p->link) { + ctxt->curp = p; + p->pc = c; + o = oplook(ctxt,p); +/* very large branches + if(o->type == 6 && p->pcond) { + otxt = p->pcond->pc - c; + if(otxt < 0) + otxt = -otxt; + if(otxt >= (1L<<17) - 10) { + q = ctxt->arch->prg(); + q->link = p->link; + p->link = q; + q->as = AB; + q->to.type = D_BRANCH; + q->pcond = p->pcond; + p->pcond = q; + q = ctxt->arch->prg(); + q->link = p->link; + p->link = q; + q->as = AB; + q->to.type = D_BRANCH; + q->pcond = q->link->link; + bflag = 1; + } + } + */ + m = o->size; + if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) { + if(p->as == ATEXT) { + ctxt->autosize = p->to.offset + 4; + continue; + } + ctxt->diag("zero-width instruction\n%P", p); + continue; + } + c += m; + } + cursym->size = c; + } while(bflag); + + c += c&4; + + /* + * lay out the code. all the pc-relative code references, + * even cross-function, are resolved now; + * only data references need to be relocated. + * with more work we could leave cross-function + * code references to be relocated too, and then + * perhaps we'd be able to parallelize the span loop above. + */ + gmsym = nil; + if(ctxt->linkmode == LinkExternal) + gmsym = linklookup(ctxt, "runtime.tlsgm", 0); + + p = cursym->text; + ctxt->autosize = p->to.offset + 4; + symgrow(ctxt, cursym, cursym->size); + + bp = cursym->p; + for(p = p->link; p != nil; p = p->link) { + ctxt->pc = p->pc; + ctxt->curp = p; + o = oplook(ctxt, p); + asmout(ctxt, p, o, out, gmsym); + for(i=0; i<o->size/4; i++) { + v = out[i]; + *bp++ = v; + *bp++ = v>>8; + *bp++ = v>>16; + *bp++ = v>>24; + } + } +} + +/* + * when the first reference to the literal pool threatens + * to go out of range of a 12-bit PC-relative offset, + * drop the pool now, and branch round it. + * this happens only in extended basic blocks that exceed 4k. + */ +static int +checkpool(Link *ctxt, Prog *p, int sz) +{ + if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0) + return flushpool(ctxt, p, 1, 0); + else if(p->link == nil) + return flushpool(ctxt, p, 2, 0); + return 0; +} + +static int +flushpool(Link *ctxt, Prog *p, int skip, int force) +{ + Prog *q; + + if(ctxt->blitrl) { + if(skip){ + if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start); + q = ctxt->arch->prg(); + q->as = AB; + q->to.type = D_BRANCH; + q->pcond = p->link; + q->link = ctxt->blitrl; + q->lineno = p->lineno; + ctxt->blitrl = q; + } + else if(!force && (p->pc+pool.size-pool.start < 2048)) + return 0; + ctxt->elitrl->link = p->link; + p->link = ctxt->blitrl; + // BUG(minux): how to correctly handle line number for constant pool entries? + // for now, we set line number to the last instruction preceding them at least + // this won't bloat the .debug_line tables + while(ctxt->blitrl) { + ctxt->blitrl->lineno = p->lineno; + ctxt->blitrl = ctxt->blitrl->link; + } + ctxt->blitrl = 0; /* BUG: should refer back to values until out-of-range */ + ctxt->elitrl = 0; + pool.size = 0; + pool.start = 0; + pool.extra = 0; + return 1; + } + return 0; +} + +static void +addpool(Link *ctxt, Prog *p, Addr *a) +{ + Prog *q, t; + int c; + + c = aclass(ctxt, a); + + t = zprg; + t.as = AWORD; + + switch(c) { + default: + t.to = *a; + if(ctxt->flag_shared && t.to.sym != nil) + t.pcrel = p; + break; + + case C_SROREG: + case C_LOREG: + case C_ROREG: + case C_FOREG: + case C_SOREG: + case C_HOREG: + case C_FAUTO: + case C_SAUTO: + case C_LAUTO: + case C_LACON: + t.to.type = D_CONST; + t.to.offset = ctxt->instoffset; + break; + } + + if(t.pcrel == nil) { + for(q = ctxt->blitrl; q != nil; q = q->link) /* could hash on t.t0.offset */ + if(q->pcrel == nil && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) { + p->pcond = q; + return; + } + } + + q = ctxt->arch->prg(); + *q = t; + q->pc = pool.size; + + if(ctxt->blitrl == nil) { + ctxt->blitrl = q; + pool.start = p->pc; + } else + ctxt->elitrl->link = q; + ctxt->elitrl = q; + pool.size += 4; + + p->pcond = q; +} + +static int32 +regoff(Link *ctxt, Addr *a) +{ + + ctxt->instoffset = 0; + aclass(ctxt, a); + return ctxt->instoffset; +} + +static int32 +immrot(uint32 v) +{ + int i; + + for(i=0; i<16; i++) { + if((v & ~0xff) == 0) + return (i<<8) | v | (1<<25); + v = (v<<2) | (v>>30); + } + return 0; +} + +static int32 +immaddr(int32 v) +{ + if(v >= 0 && v <= 0xfff) + return (v & 0xfff) | + (1<<24) | /* pre indexing */ + (1<<23); /* pre indexing, up */ + if(v >= -0xfff && v < 0) + return (-v & 0xfff) | + (1<<24); /* pre indexing */ + return 0; +} + +static int +immfloat(int32 v) +{ + return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */ +} + +static int +immhalf(int32 v) +{ + if(v >= 0 && v <= 0xff) + return v| + (1<<24)| /* pre indexing */ + (1<<23); /* pre indexing, up */ + if(v >= -0xff && v < 0) + return (-v & 0xff)| + (1<<24); /* pre indexing */ + return 0; +} + +static int +aclass(Link *ctxt, Addr *a) +{ + LSym *s; + int t; + + switch(a->type) { + case D_NONE: + return C_NONE; + + case D_REG: + return C_REG; + + case D_REGREG: + return C_REGREG; + + case D_REGREG2: + return C_REGREG2; + + case D_SHIFT: + return C_SHIFT; + + case D_FREG: + return C_FREG; + + case D_FPCR: + return C_FCR; + + case D_OREG: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + if(a->sym == 0 || a->sym->name == 0) { + print("null sym external\n"); + print("%D\n", a); + return C_GOK; + } + ctxt->instoffset = 0; // s.b. unused but just in case + return C_ADDR; + + case D_AUTO: + ctxt->instoffset = ctxt->autosize + a->offset; + t = immaddr(ctxt->instoffset); + if(t){ + if(immhalf(ctxt->instoffset)) + return immfloat(t) ? C_HFAUTO : C_HAUTO; + if(immfloat(t)) + return C_FAUTO; + return C_SAUTO; + } + return C_LAUTO; + + case D_PARAM: + ctxt->instoffset = ctxt->autosize + a->offset + 4L; + t = immaddr(ctxt->instoffset); + if(t){ + if(immhalf(ctxt->instoffset)) + return immfloat(t) ? C_HFAUTO : C_HAUTO; + if(immfloat(t)) + return C_FAUTO; + return C_SAUTO; + } + return C_LAUTO; + case D_NONE: + ctxt->instoffset = a->offset; + t = immaddr(ctxt->instoffset); + if(t) { + if(immhalf(ctxt->instoffset)) /* n.b. that it will also satisfy immrot */ + return immfloat(t) ? C_HFOREG : C_HOREG; + if(immfloat(t)) + return C_FOREG; /* n.b. that it will also satisfy immrot */ + t = immrot(ctxt->instoffset); + if(t) + return C_SROREG; + if(immhalf(ctxt->instoffset)) + return C_HOREG; + return C_SOREG; + } + t = immrot(ctxt->instoffset); + if(t) + return C_ROREG; + return C_LOREG; + } + return C_GOK; + + case D_PSR: + return C_PSR; + + case D_OCONST: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + ctxt->instoffset = 0; // s.b. unused but just in case + return C_ADDR; + } + return C_GOK; + + case D_FCONST: + if(chipzero(ctxt, a->u.dval) >= 0) + return C_ZFCON; + if(chipfloat(ctxt, a->u.dval) >= 0) + return C_SFCON; + return C_LFCON; + + case D_CONST: + case D_CONST2: + switch(a->name) { + + case D_NONE: + ctxt->instoffset = a->offset; + if(a->reg != NREG) + goto aconsize; + + t = immrot(ctxt->instoffset); + if(t) + return C_RCON; + t = immrot(~ctxt->instoffset); + if(t) + return C_NCON; + return C_LCON; + + case D_EXTERN: + case D_STATIC: + s = a->sym; + if(s == nil) + break; + ctxt->instoffset = 0; // s.b. unused but just in case + return C_LCONADDR; + + case D_AUTO: + ctxt->instoffset = ctxt->autosize + a->offset; + goto aconsize; + + case D_PARAM: + ctxt->instoffset = ctxt->autosize + a->offset + 4L; + aconsize: + t = immrot(ctxt->instoffset); + if(t) + return C_RACON; + return C_LACON; + } + return C_GOK; + + case D_BRANCH: + return C_SBRA; + } + return C_GOK; +} + +static void +prasm(Prog *p) +{ + print("%P\n", p); +} + +static Optab* +oplook(Link *ctxt, Prog *p) +{ + int a1, a2, a3, r; + char *c1, *c3; + Optab *o, *e; + + a1 = p->optab; + if(a1) + return optab+(a1-1); + a1 = p->from.class; + if(a1 == 0) { + a1 = aclass(ctxt, &p->from) + 1; + p->from.class = a1; + } + a1--; + a3 = p->to.class; + if(a3 == 0) { + a3 = aclass(ctxt, &p->to) + 1; + p->to.class = a3; + } + a3--; + a2 = C_NONE; + if(p->reg != NREG) + a2 = C_REG; + r = p->as; + o = oprange[r].start; + if(o == 0) { + a1 = opcross[repop[r]][a1][a2][a3]; + if(a1) { + p->optab = a1+1; + return optab+a1; + } + o = oprange[r].stop; /* just generate an error */ + } + if(0 /*debug['O']*/) { + print("oplook %A %O %O %O\n", + (int)p->as, a1, a2, a3); + print(" %d %d\n", p->from.type, p->to.type); + } + e = oprange[r].stop; + c1 = xcmp[a1]; + c3 = xcmp[a3]; + for(; o<e; o++) + if(o->a2 == a2) + if(c1[o->a1]) + if(c3[o->a3]) { + p->optab = (o-optab)+1; + return o; + } + ctxt->diag("illegal combination %A %O %O %O, %d %d", + p->as, a1, a2, a3, p->from.type, p->to.type); + prasm(p); + if(o == 0) + o = optab; + return o; +} + +static int +cmp(int a, int b) +{ + + if(a == b) + return 1; + switch(a) { + case C_LCON: + if(b == C_RCON || b == C_NCON) + return 1; + break; + case C_LACON: + if(b == C_RACON) + return 1; + break; + case C_LFCON: + if(b == C_ZFCON || b == C_SFCON) + return 1; + break; + + case C_HFAUTO: + return b == C_HAUTO || b == C_FAUTO; + case C_FAUTO: + case C_HAUTO: + return b == C_HFAUTO; + case C_SAUTO: + return cmp(C_HFAUTO, b); + case C_LAUTO: + return cmp(C_SAUTO, b); + + case C_HFOREG: + return b == C_HOREG || b == C_FOREG; + case C_FOREG: + case C_HOREG: + return b == C_HFOREG; + case C_SROREG: + return cmp(C_SOREG, b) || cmp(C_ROREG, b); + case C_SOREG: + case C_ROREG: + return b == C_SROREG || cmp(C_HFOREG, b); + case C_LOREG: + return cmp(C_SROREG, b); + + case C_LBRA: + if(b == C_SBRA) + return 1; + break; + + case C_HREG: + return cmp(C_SP, b) || cmp(C_PC, b); + + } + return 0; +} + +static int +ocmp(const void *a1, const void *a2) +{ + Optab *p1, *p2; + int n; + + p1 = (Optab*)a1; + p2 = (Optab*)a2; + n = p1->as - p2->as; + if(n) + return n; + n = p1->a1 - p2->a1; + if(n) + return n; + n = p1->a2 - p2->a2; + if(n) + return n; + n = p1->a3 - p2->a3; + if(n) + return n; + return 0; +} + +static void +buildop(Link *ctxt) +{ + int i, n, r; + + for(i=0; i<C_GOK; i++) + for(n=0; n<C_GOK; n++) + xcmp[i][n] = cmp(n, i); + for(n=0; optab[n].as != AXXX; n++) { + if((optab[n].flag & LPCREL) != 0) { + if(ctxt->flag_shared) + optab[n].size += optab[n].pcrelsiz; + else + optab[n].flag &= ~LPCREL; + } + } + qsort(optab, n, sizeof(optab[0]), ocmp); + for(i=0; i<n; i++) { + r = optab[i].as; + oprange[r].start = optab+i; + while(optab[i].as == r) + i++; + oprange[r].stop = optab+i; + i--; + + switch(r) + { + default: + ctxt->diag("unknown op in build: %A", r); + sysfatal("bad code"); + case AADD: + oprange[AAND] = oprange[r]; + oprange[AEOR] = oprange[r]; + oprange[ASUB] = oprange[r]; + oprange[ARSB] = oprange[r]; + oprange[AADC] = oprange[r]; + oprange[ASBC] = oprange[r]; + oprange[ARSC] = oprange[r]; + oprange[AORR] = oprange[r]; + oprange[ABIC] = oprange[r]; + break; + case ACMP: + oprange[ATEQ] = oprange[r]; + oprange[ACMN] = oprange[r]; + break; + case AMVN: + break; + case ABEQ: + oprange[ABNE] = oprange[r]; + oprange[ABCS] = oprange[r]; + oprange[ABHS] = oprange[r]; + oprange[ABCC] = oprange[r]; + oprange[ABLO] = oprange[r]; + oprange[ABMI] = oprange[r]; + oprange[ABPL] = oprange[r]; + oprange[ABVS] = oprange[r]; + oprange[ABVC] = oprange[r]; + oprange[ABHI] = oprange[r]; + oprange[ABLS] = oprange[r]; + oprange[ABGE] = oprange[r]; + oprange[ABLT] = oprange[r]; + oprange[ABGT] = oprange[r]; + oprange[ABLE] = oprange[r]; + break; + case ASLL: + oprange[ASRL] = oprange[r]; + oprange[ASRA] = oprange[r]; + break; + case AMUL: + oprange[AMULU] = oprange[r]; + break; + case ADIV: + oprange[AMOD] = oprange[r]; + oprange[AMODU] = oprange[r]; + oprange[ADIVU] = oprange[r]; + break; + case AMOVW: + case AMOVB: + case AMOVBS: + case AMOVBU: + case AMOVH: + case AMOVHS: + case AMOVHU: + break; + case ASWPW: + oprange[ASWPBU] = oprange[r]; + break; + case AB: + case ABL: + case ABX: + case ABXRET: + case ASWI: + case AWORD: + case AMOVM: + case ARFE: + case ATEXT: + case AUSEFIELD: + case ACASE: + case ABCASE: + case ATYPE: + break; + case AADDF: + oprange[AADDD] = oprange[r]; + oprange[ASUBF] = oprange[r]; + oprange[ASUBD] = oprange[r]; + oprange[AMULF] = oprange[r]; + oprange[AMULD] = oprange[r]; + oprange[ADIVF] = oprange[r]; + oprange[ADIVD] = oprange[r]; + oprange[ASQRTF] = oprange[r]; + oprange[ASQRTD] = oprange[r]; + oprange[AMOVFD] = oprange[r]; + oprange[AMOVDF] = oprange[r]; + oprange[AABSF] = oprange[r]; + oprange[AABSD] = oprange[r]; + break; + + case ACMPF: + oprange[ACMPD] = oprange[r]; + break; + + case AMOVF: + oprange[AMOVD] = oprange[r]; + break; + + case AMOVFW: + oprange[AMOVDW] = oprange[r]; + break; + + case AMOVWF: + oprange[AMOVWD] = oprange[r]; + break; + + case AMULL: + oprange[AMULAL] = oprange[r]; + oprange[AMULLU] = oprange[r]; + oprange[AMULALU] = oprange[r]; + break; + + case AMULWT: + oprange[AMULWB] = oprange[r]; + break; + + case AMULAWT: + oprange[AMULAWB] = oprange[r]; + break; + + case AMULA: + case ALDREX: + case ASTREX: + case ALDREXD: + case ASTREXD: + case ATST: + case APLD: + case AUNDEF: + case ACLZ: + case AFUNCDATA: + case APCDATA: + break; + } + } +} + +void +asmout(Link *ctxt, Prog *p, Optab *o, int32 *out, LSym *gmsym) +{ + int32 o1, o2, o3, o4, o5, o6, v; + int r, rf, rt, rt2; + Reloc *rel; + +ctxt->printp = p; + o1 = 0; + o2 = 0; + o3 = 0; + o4 = 0; + o5 = 0; + o6 = 0; + ctxt->armsize += o->size; +if(0 /*debug['P']*/) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type); + switch(o->type) { + default: + ctxt->diag("unknown asm %d", o->type); + prasm(p); + break; + + case 0: /* pseudo ops */ +if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr); + break; + + case 1: /* op R,[R],R */ + o1 = oprrr(ctxt, p->as, p->scond); + rf = p->from.reg; + rt = p->to.reg; + r = p->reg; + if(p->to.type == D_NONE) + rt = 0; + if(p->as == AMOVB || p->as == AMOVH || p->as == AMOVW || p->as == AMVN) + r = 0; + else + if(r == NREG) + r = rt; + o1 |= rf | (r<<16) | (rt<<12); + break; + + case 2: /* movbu $I,[R],R */ + aclass(ctxt, &p->from); + o1 = oprrr(ctxt, p->as, p->scond); + o1 |= immrot(ctxt->instoffset); + rt = p->to.reg; + r = p->reg; + if(p->to.type == D_NONE) + rt = 0; + if(p->as == AMOVW || p->as == AMVN) + r = 0; + else if(r == NREG) + r = rt; + o1 |= (r<<16) | (rt<<12); + break; + + case 3: /* add R<<[IR],[R],R */ + mov: + aclass(ctxt, &p->from); + o1 = oprrr(ctxt, p->as, p->scond); + o1 |= p->from.offset; + rt = p->to.reg; + r = p->reg; + if(p->to.type == D_NONE) + rt = 0; + if(p->as == AMOVW || p->as == AMVN) + r = 0; + else if(r == NREG) + r = rt; + o1 |= (r<<16) | (rt<<12); + break; + + case 4: /* add $I,[R],R */ + aclass(ctxt, &p->from); + o1 = oprrr(ctxt, AADD, p->scond); + o1 |= immrot(ctxt->instoffset); + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 |= r << 16; + o1 |= p->to.reg << 12; + break; + + case 5: /* bra s */ + o1 = opbra(ctxt, p->as, p->scond); + v = -8; + if(p->to.sym != nil) { + rel = addrel(ctxt->cursym); + rel->off = ctxt->pc; + rel->siz = 4; + rel->sym = p->to.sym; + rel->add = o1 | ((v >> 2) & 0xffffff); + rel->type = D_CALL; + break; + } + if(p->pcond != nil) + v = (p->pcond->pc - ctxt->pc) - 8; + o1 |= (v >> 2) & 0xffffff; + break; + + case 6: /* b ,O(R) -> add $O,R,PC */ + aclass(ctxt, &p->to); + o1 = oprrr(ctxt, AADD, p->scond); + o1 |= immrot(ctxt->instoffset); + o1 |= p->to.reg << 16; + o1 |= REGPC << 12; + break; + + case 7: /* bl (R) -> blx R */ + aclass(ctxt, &p->to); + if(ctxt->instoffset != 0) + ctxt->diag("%P: doesn't support BL offset(REG) where offset != 0", p); + o1 = oprrr(ctxt, ABL, p->scond); + o1 |= p->to.reg; + break; + + case 8: /* sll $c,[R],R -> mov (R<<$c),R */ + aclass(ctxt, &p->from); + o1 = oprrr(ctxt, p->as, p->scond); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 |= r; + o1 |= (ctxt->instoffset&31) << 7; + o1 |= p->to.reg << 12; + break; + + case 9: /* sll R,[R],R -> mov (R<<R),R */ + o1 = oprrr(ctxt, p->as, p->scond); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 |= r; + o1 |= (p->from.reg << 8) | (1<<4); + o1 |= p->to.reg << 12; + break; + + case 10: /* swi [$con] */ + o1 = oprrr(ctxt, p->as, p->scond); + if(p->to.type != D_NONE) { + aclass(ctxt, &p->to); + o1 |= ctxt->instoffset & 0xffffff; + } + break; + + case 11: /* word */ + aclass(ctxt, &p->to); + o1 = ctxt->instoffset; + if(p->to.sym != nil) { + rel = addrel(ctxt->cursym); + rel->off = ctxt->pc; + rel->siz = 4; + rel->sym = p->to.sym; + rel->add = p->to.offset; + if(rel->sym == gmsym) { + rel->type = D_TLS; + if(ctxt->flag_shared) + rel->add += ctxt->pc - p->pcrel->pc - 8 - rel->siz; + rel->xadd = rel->add; + rel->xsym = rel->sym; + } else if(ctxt->flag_shared) { + rel->type = D_PCREL; + rel->add += ctxt->pc - p->pcrel->pc - 8; + } else + rel->type = D_ADDR; + o1 = 0; + } + break; + + case 12: /* movw $lcon, reg */ + o1 = omvl(ctxt, p, &p->from, p->to.reg); + if(o->flag & LPCREL) { + o2 = oprrr(ctxt, AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12; + } + break; + + case 13: /* op $lcon, [R], R */ + o1 = omvl(ctxt, p, &p->from, REGTMP); + if(!o1) + break; + o2 = oprrr(ctxt, p->as, p->scond); + o2 |= REGTMP; + r = p->reg; + if(p->as == AMOVW || p->as == AMVN) + r = 0; + else if(r == NREG) + r = p->to.reg; + o2 |= r << 16; + if(p->to.type != D_NONE) + o2 |= p->to.reg << 12; + break; + + case 14: /* movb/movbu/movh/movhu R,R */ + o1 = oprrr(ctxt, ASLL, p->scond); + + if(p->as == AMOVBU || p->as == AMOVHU) + o2 = oprrr(ctxt, ASRL, p->scond); + else + o2 = oprrr(ctxt, ASRA, p->scond); + + r = p->to.reg; + o1 |= (p->from.reg)|(r<<12); + o2 |= (r)|(r<<12); + if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) { + o1 |= (24<<7); + o2 |= (24<<7); + } else { + o1 |= (16<<7); + o2 |= (16<<7); + } + break; + + case 15: /* mul r,[r,]r */ + o1 = oprrr(ctxt, p->as, p->scond); + rf = p->from.reg; + rt = p->to.reg; + r = p->reg; + if(r == NREG) + r = rt; + if(rt == r) { + r = rf; + rf = rt; + } + if(0) + if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) { + ctxt->diag("bad registers in MUL"); + prasm(p); + } + o1 |= (rf<<8) | r | (rt<<16); + break; + + + case 16: /* div r,[r,]r */ + o1 = 0xf << 28; + o2 = 0; + break; + + case 17: + o1 = oprrr(ctxt, p->as, p->scond); + rf = p->from.reg; + rt = p->to.reg; + rt2 = p->to.offset; + r = p->reg; + o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12); + break; + + case 20: /* mov/movb/movbu R,O(R) */ + aclass(ctxt, &p->to); + r = p->to.reg; + if(r == NREG) + r = o->param; + o1 = osr(ctxt, p->as, p->from.reg, ctxt->instoffset, r, p->scond); + break; + + case 21: /* mov/movbu O(R),R -> lr */ + aclass(ctxt, &p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 = olr(ctxt, ctxt->instoffset, r, p->to.reg, p->scond); + if(p->as != AMOVW) + o1 |= 1<<22; + break; + + case 30: /* mov/movb/movbu R,L(R) */ + o1 = omvl(ctxt, p, &p->to, REGTMP); + if(!o1) + break; + r = p->to.reg; + if(r == NREG) + r = o->param; + o2 = osrr(ctxt, p->from.reg, REGTMP,r, p->scond); + if(p->as != AMOVW) + o2 |= 1<<22; + break; + + case 31: /* mov/movbu L(R),R -> lr[b] */ + o1 = omvl(ctxt, p, &p->from, REGTMP); + if(!o1) + break; + r = p->from.reg; + if(r == NREG) + r = o->param; + o2 = olrr(ctxt, REGTMP,r, p->to.reg, p->scond); + if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB) + o2 |= 1<<22; + break; + + case 34: /* mov $lacon,R */ + o1 = omvl(ctxt, p, &p->from, REGTMP); + if(!o1) + break; + + o2 = oprrr(ctxt, AADD, p->scond); + o2 |= REGTMP; + r = p->from.reg; + if(r == NREG) + r = o->param; + o2 |= r << 16; + if(p->to.type != D_NONE) + o2 |= p->to.reg << 12; + break; + + case 35: /* mov PSR,R */ + o1 = (2<<23) | (0xf<<16) | (0<<0); + o1 |= (p->scond & C_SCOND) << 28; + o1 |= (p->from.reg & 1) << 22; + o1 |= p->to.reg << 12; + break; + + case 36: /* mov R,PSR */ + o1 = (2<<23) | (0x29f<<12) | (0<<4); + if(p->scond & C_FBIT) + o1 ^= 0x010 << 12; + o1 |= (p->scond & C_SCOND) << 28; + o1 |= (p->to.reg & 1) << 22; + o1 |= p->from.reg << 0; + break; + + case 37: /* mov $con,PSR */ + aclass(ctxt, &p->from); + o1 = (2<<23) | (0x29f<<12) | (0<<4); + if(p->scond & C_FBIT) + o1 ^= 0x010 << 12; + o1 |= (p->scond & C_SCOND) << 28; + o1 |= immrot(ctxt->instoffset); + o1 |= (p->to.reg & 1) << 22; + o1 |= p->from.reg << 0; + break; + + case 38: /* movm $con,oreg -> stm */ + o1 = (0x4 << 25); + o1 |= p->from.offset & 0xffff; + o1 |= p->to.reg << 16; + aclass(ctxt, &p->to); + goto movm; + + case 39: /* movm oreg,$con -> ldm */ + o1 = (0x4 << 25) | (1 << 20); + o1 |= p->to.offset & 0xffff; + o1 |= p->from.reg << 16; + aclass(ctxt, &p->from); + movm: + if(ctxt->instoffset != 0) + ctxt->diag("offset must be zero in MOVM"); + o1 |= (p->scond & C_SCOND) << 28; + if(p->scond & C_PBIT) + o1 |= 1 << 24; + if(p->scond & C_UBIT) + o1 |= 1 << 23; + if(p->scond & C_SBIT) + o1 |= 1 << 22; + if(p->scond & C_WBIT) + o1 |= 1 << 21; + break; + + case 40: /* swp oreg,reg,reg */ + aclass(ctxt, &p->from); + if(ctxt->instoffset != 0) + ctxt->diag("offset must be zero in SWP"); + o1 = (0x2<<23) | (0x9<<4); + if(p->as != ASWPW) + o1 |= 1 << 22; + o1 |= p->from.reg << 16; + o1 |= p->reg << 0; + o1 |= p->to.reg << 12; + o1 |= (p->scond & C_SCOND) << 28; + break; + + case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ + o1 = 0xe8fd8000; + break; + + case 50: /* floating point store */ + v = regoff(ctxt, &p->to); + r = p->to.reg; + if(r == NREG) + r = o->param; + o1 = ofsr(ctxt, p->as, p->from.reg, v, r, p->scond, p); + break; + + case 51: /* floating point load */ + v = regoff(ctxt, &p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 = ofsr(ctxt, p->as, p->to.reg, v, r, p->scond, p) | (1<<20); + break; + + case 52: /* floating point store, int32 offset UGLY */ + o1 = omvl(ctxt, p, &p->to, REGTMP); + if(!o1) + break; + r = p->to.reg; + if(r == NREG) + r = o->param; + o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; + o3 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p); + break; + + case 53: /* floating point load, int32 offset UGLY */ + o1 = omvl(ctxt, p, &p->from, REGTMP); + if(!o1) + break; + r = p->from.reg; + if(r == NREG) + r = o->param; + o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; + o3 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); + break; + + case 54: /* floating point arith */ + o1 = oprrr(ctxt, p->as, p->scond); + rf = p->from.reg; + rt = p->to.reg; + r = p->reg; + if(r == NREG) { + r = rt; + if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD) + r = 0; + } + o1 |= rf | (r<<16) | (rt<<12); + break; + + case 56: /* move to FP[CS]R */ + o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); + o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12); + break; + + case 57: /* move from FP[CS]R */ + o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); + o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20); + break; + case 58: /* movbu R,R */ + o1 = oprrr(ctxt, AAND, p->scond); + o1 |= immrot(0xff); + rt = p->to.reg; + r = p->from.reg; + if(p->to.type == D_NONE) + rt = 0; + if(r == NREG) + r = rt; + o1 |= (r<<16) | (rt<<12); + break; + + case 59: /* movw/bu R<<I(R),R -> ldr indexed */ + if(p->from.reg == NREG) { + if(p->as != AMOVW) + ctxt->diag("byte MOV from shifter operand"); + goto mov; + } + if(p->from.offset&(1<<4)) + ctxt->diag("bad shift in LDR"); + o1 = olrr(ctxt, p->from.offset, p->from.reg, p->to.reg, p->scond); + if(p->as == AMOVBU) + o1 |= 1<<22; + break; + + case 60: /* movb R(R),R -> ldrsb indexed */ + if(p->from.reg == NREG) { + ctxt->diag("byte MOV from shifter operand"); + goto mov; + } + if(p->from.offset&(~0xf)) + ctxt->diag("bad shift in LDRSB"); + o1 = olhrr(ctxt, p->from.offset, p->from.reg, p->to.reg, p->scond); + o1 ^= (1<<5)|(1<<6); + break; + + case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ + if(p->to.reg == NREG) + ctxt->diag("MOV to shifter operand"); + o1 = osrr(ctxt, p->from.reg, p->to.offset, p->to.reg, p->scond); + if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) + o1 |= 1<<22; + break; + + case 62: /* case R -> movw R<<2(PC),PC */ + if(o->flag & LPCREL) { + o1 = oprrr(ctxt, AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12; + o2 = olrr(ctxt, REGTMP, REGPC, REGTMP, p->scond); + o2 |= 2<<7; + o3 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12; + } else { + o1 = olrr(ctxt, p->from.reg, REGPC, REGPC, p->scond); + o1 |= 2<<7; + } + break; + + case 63: /* bcase */ + if(p->pcond != nil) { + rel = addrel(ctxt->cursym); + rel->off = ctxt->pc; + rel->siz = 4; + if(p->to.sym != nil && p->to.sym->type != 0) { + rel->sym = p->to.sym; + rel->add = p->to.offset; + } else { + rel->sym = ctxt->cursym; + rel->add = p->pcond->pc; + } + if(o->flag & LPCREL) { + rel->type = D_PCREL; + rel->add += ctxt->pc - p->pcrel->pc - 16 + rel->siz; + } else + rel->type = D_ADDR; + o1 = 0; + } + break; + + /* reloc ops */ + case 64: /* mov/movb/movbu R,addr */ + o1 = omvl(ctxt, p, &p->to, REGTMP); + if(!o1) + break; + o2 = osr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond); + if(o->flag & LPCREL) { + o3 = o2; + o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; + } + break; + + case 65: /* mov/movbu addr,R */ + o1 = omvl(ctxt, p, &p->from, REGTMP); + if(!o1) + break; + o2 = olr(ctxt, 0, REGTMP, p->to.reg, p->scond); + if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB) + o2 |= 1<<22; + if(o->flag & LPCREL) { + o3 = o2; + o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; + } + break; + + case 68: /* floating point store -> ADDR */ + o1 = omvl(ctxt, p, &p->to, REGTMP); + if(!o1) + break; + o2 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p); + if(o->flag & LPCREL) { + o3 = o2; + o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; + } + break; + + case 69: /* floating point load <- ADDR */ + o1 = omvl(ctxt, p, &p->from, REGTMP); + if(!o1) + break; + o2 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); + if(o->flag & LPCREL) { + o3 = o2; + o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; + } + break; + + /* ArmV4 ops: */ + case 70: /* movh/movhu R,O(R) -> strh */ + aclass(ctxt, &p->to); + r = p->to.reg; + if(r == NREG) + r = o->param; + o1 = oshr(ctxt, p->from.reg, ctxt->instoffset, r, p->scond); + break; + case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ + aclass(ctxt, &p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 = olhr(ctxt, ctxt->instoffset, r, p->to.reg, p->scond); + if(p->as == AMOVB || p->as == AMOVBS) + o1 ^= (1<<5)|(1<<6); + else if(p->as == AMOVH || p->as == AMOVHS) + o1 ^= (1<<6); + break; + case 72: /* movh/movhu R,L(R) -> strh */ + o1 = omvl(ctxt, p, &p->to, REGTMP); + if(!o1) + break; + r = p->to.reg; + if(r == NREG) + r = o->param; + o2 = oshrr(ctxt, p->from.reg, REGTMP,r, p->scond); + break; + case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ + o1 = omvl(ctxt, p, &p->from, REGTMP); + if(!o1) + break; + r = p->from.reg; + if(r == NREG) + r = o->param; + o2 = olhrr(ctxt, REGTMP, r, p->to.reg, p->scond); + if(p->as == AMOVB || p->as == AMOVBS) + o2 ^= (1<<5)|(1<<6); + else if(p->as == AMOVH || p->as == AMOVHS) + o2 ^= (1<<6); + break; + case 74: /* bx $I */ + ctxt->diag("ABX $I"); + break; + case 75: /* bx O(R) */ + aclass(ctxt, &p->to); + if(ctxt->instoffset != 0) + ctxt->diag("non-zero offset in ABX"); +/* + o1 = oprrr(ctxt, AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR + o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R +*/ + // p->to.reg may be REGLINK + o1 = oprrr(ctxt, AADD, p->scond); + o1 |= immrot(ctxt->instoffset); + o1 |= p->to.reg << 16; + o1 |= REGTMP << 12; + o2 = oprrr(ctxt, AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR + o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp + break; + case 76: /* bx O(R) when returning from fn*/ + ctxt->diag("ABXRET"); + break; + case 77: /* ldrex oreg,reg */ + aclass(ctxt, &p->from); + if(ctxt->instoffset != 0) + ctxt->diag("offset must be zero in LDREX"); + o1 = (0x19<<20) | (0xf9f); + o1 |= p->from.reg << 16; + o1 |= p->to.reg << 12; + o1 |= (p->scond & C_SCOND) << 28; + break; + case 78: /* strex reg,oreg,reg */ + aclass(ctxt, &p->from); + if(ctxt->instoffset != 0) + ctxt->diag("offset must be zero in STREX"); + o1 = (0x18<<20) | (0xf90); + o1 |= p->from.reg << 16; + o1 |= p->reg << 0; + o1 |= p->to.reg << 12; + o1 |= (p->scond & C_SCOND) << 28; + break; + case 80: /* fmov zfcon,freg */ + if(p->as == AMOVD) { + o1 = 0xeeb00b00; // VMOV imm 64 + o2 = oprrr(ctxt, ASUBD, p->scond); + } else { + o1 = 0x0eb00a00; // VMOV imm 32 + o2 = oprrr(ctxt, ASUBF, p->scond); + } + v = 0x70; // 1.0 + r = p->to.reg; + + // movf $1.0, r + o1 |= (p->scond & C_SCOND) << 28; + o1 |= r << 12; + o1 |= (v&0xf) << 0; + o1 |= (v&0xf0) << 12; + + // subf r,r,r + o2 |= r | (r<<16) | (r<<12); + break; + case 81: /* fmov sfcon,freg */ + o1 = 0x0eb00a00; // VMOV imm 32 + if(p->as == AMOVD) + o1 = 0xeeb00b00; // VMOV imm 64 + o1 |= (p->scond & C_SCOND) << 28; + o1 |= p->to.reg << 12; + v = chipfloat(ctxt, p->from.u.dval); + o1 |= (v&0xf) << 0; + o1 |= (v&0xf0) << 12; + break; + case 82: /* fcmp freg,freg, */ + o1 = oprrr(ctxt, p->as, p->scond); + o1 |= (p->reg<<12) | (p->from.reg<<0); + o2 = 0x0ef1fa10; // VMRS R15 + o2 |= (p->scond & C_SCOND) << 28; + break; + case 83: /* fcmp freg,, */ + o1 = oprrr(ctxt, p->as, p->scond); + o1 |= (p->from.reg<<12) | (1<<16); + o2 = 0x0ef1fa10; // VMRS R15 + o2 |= (p->scond & C_SCOND) << 28; + break; + case 84: /* movfw freg,freg - truncate float-to-fix */ + o1 = oprrr(ctxt, p->as, p->scond); + o1 |= (p->from.reg<<0); + o1 |= (p->to.reg<<12); + break; + case 85: /* movwf freg,freg - fix-to-float */ + o1 = oprrr(ctxt, p->as, p->scond); + o1 |= (p->from.reg<<0); + o1 |= (p->to.reg<<12); + break; + case 86: /* movfw freg,reg - truncate float-to-fix */ + // macro for movfw freg,FTMP; movw FTMP,reg + o1 = oprrr(ctxt, p->as, p->scond); + o1 |= (p->from.reg<<0); + o1 |= (FREGTMP<<12); + o2 = oprrr(ctxt, AMOVFW+AEND, p->scond); + o2 |= (FREGTMP<<16); + o2 |= (p->to.reg<<12); + break; + case 87: /* movwf reg,freg - fix-to-float */ + // macro for movw reg,FTMP; movwf FTMP,freg + o1 = oprrr(ctxt, AMOVWF+AEND, p->scond); + o1 |= (p->from.reg<<12); + o1 |= (FREGTMP<<16); + o2 = oprrr(ctxt, p->as, p->scond); + o2 |= (FREGTMP<<0); + o2 |= (p->to.reg<<12); + break; + case 88: /* movw reg,freg */ + o1 = oprrr(ctxt, AMOVWF+AEND, p->scond); + o1 |= (p->from.reg<<12); + o1 |= (p->to.reg<<16); + break; + case 89: /* movw freg,reg */ + o1 = oprrr(ctxt, AMOVFW+AEND, p->scond); + o1 |= (p->from.reg<<16); + o1 |= (p->to.reg<<12); + break; + case 90: /* tst reg */ + o1 = oprrr(ctxt, ACMP+AEND, p->scond); + o1 |= p->from.reg<<16; + break; + case 91: /* ldrexd oreg,reg */ + aclass(ctxt, &p->from); + if(ctxt->instoffset != 0) + ctxt->diag("offset must be zero in LDREX"); + o1 = (0x1b<<20) | (0xf9f); + o1 |= p->from.reg << 16; + o1 |= p->to.reg << 12; + o1 |= (p->scond & C_SCOND) << 28; + break; + case 92: /* strexd reg,oreg,reg */ + aclass(ctxt, &p->from); + if(ctxt->instoffset != 0) + ctxt->diag("offset must be zero in STREX"); + o1 = (0x1a<<20) | (0xf90); + o1 |= p->from.reg << 16; + o1 |= p->reg << 0; + o1 |= p->to.reg << 12; + o1 |= (p->scond & C_SCOND) << 28; + break; + case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ + o1 = omvl(ctxt, p, &p->from, REGTMP); + if(!o1) + break; + o2 = olhr(ctxt, 0, REGTMP, p->to.reg, p->scond); + if(p->as == AMOVB || p->as == AMOVBS) + o2 ^= (1<<5)|(1<<6); + else if(p->as == AMOVH || p->as == AMOVHS) + o2 ^= (1<<6); + if(o->flag & LPCREL) { + o3 = o2; + o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; + } + break; + case 94: /* movh/movhu R,addr -> strh */ + o1 = omvl(ctxt, p, &p->to, REGTMP); + if(!o1) + break; + o2 = oshr(ctxt, p->from.reg, 0, REGTMP, p->scond); + if(o->flag & LPCREL) { + o3 = o2; + o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; + } + break; + case 95: /* PLD off(reg) */ + o1 = 0xf5d0f000; + o1 |= p->from.reg << 16; + if(p->from.offset < 0) { + o1 &= ~(1 << 23); + o1 |= (-p->from.offset) & 0xfff; + } else + o1 |= p->from.offset & 0xfff; + break; + case 96: /* UNDEF */ + // This is supposed to be something that stops execution. + // It's not supposed to be reached, ever, but if it is, we'd + // like to be able to tell how we got there. Assemble as + // 0xf7fabcfd which is guranteed to raise undefined instruction + // exception. + o1 = 0xf7fabcfd; + break; + case 97: /* CLZ Rm, Rd */ + o1 = oprrr(ctxt, p->as, p->scond); + o1 |= p->to.reg << 12; + o1 |= p->from.reg; + break; + case 98: /* MULW{T,B} Rs, Rm, Rd */ + o1 = oprrr(ctxt, p->as, p->scond); + o1 |= p->to.reg << 16; + o1 |= p->from.reg << 8; + o1 |= p->reg; + break; + case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */ + o1 = oprrr(ctxt, p->as, p->scond); + o1 |= p->to.reg << 12; + o1 |= p->from.reg << 8; + o1 |= p->reg; + o1 |= p->to.offset << 16; + break; + } + + out[0] = o1; + out[1] = o2; + out[2] = o3; + out[3] = o4; + out[4] = o5; + out[5] = o6; + return; + +#ifdef NOTDEF + v = p->pc; + switch(o->size) { + default: + if(debug['a']) + Bprint(&bso, " %.8ux:\t\t%P\n", v, p); + break; + case 4: + if(debug['a']) + Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p); + lputl(o1); + break; + case 8: + if(debug['a']) + Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p); + lputl(o1); + lputl(o2); + break; + case 12: + if(debug['a']) + Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p); + lputl(o1); + lputl(o2); + lputl(o3); + break; + case 16: + if(debug['a']) + Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n", + v, o1, o2, o3, o4, p); + lputl(o1); + lputl(o2); + lputl(o3); + lputl(o4); + break; + case 20: + if(debug['a']) + Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n", + v, o1, o2, o3, o4, o5, p); + lputl(o1); + lputl(o2); + lputl(o3); + lputl(o4); + lputl(o5); + break; + case 24: + if(debug['a']) + Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n", + v, o1, o2, o3, o4, o5, o6, p); + lputl(o1); + lputl(o2); + lputl(o3); + lputl(o4); + lputl(o5); + lputl(o6); + break; + } +#endif +} + +int32 +oprrr(Link *ctxt, int a, int sc) +{ + int32 o; + + o = (sc & C_SCOND) << 28; + if(sc & C_SBIT) + o |= 1 << 20; + if(sc & (C_PBIT|C_WBIT)) + ctxt->diag(".nil/.W on dp instruction"); + switch(a) { + case AMULU: + case AMUL: return o | (0x0<<21) | (0x9<<4); + case AMULA: return o | (0x1<<21) | (0x9<<4); + case AMULLU: return o | (0x4<<21) | (0x9<<4); + case AMULL: return o | (0x6<<21) | (0x9<<4); + case AMULALU: return o | (0x5<<21) | (0x9<<4); + case AMULAL: return o | (0x7<<21) | (0x9<<4); + case AAND: return o | (0x0<<21); + case AEOR: return o | (0x1<<21); + case ASUB: return o | (0x2<<21); + case ARSB: return o | (0x3<<21); + case AADD: return o | (0x4<<21); + case AADC: return o | (0x5<<21); + case ASBC: return o | (0x6<<21); + case ARSC: return o | (0x7<<21); + case ATST: return o | (0x8<<21) | (1<<20); + case ATEQ: return o | (0x9<<21) | (1<<20); + case ACMP: return o | (0xa<<21) | (1<<20); + case ACMN: return o | (0xb<<21) | (1<<20); + case AORR: return o | (0xc<<21); + case AMOVB: + case AMOVH: + case AMOVW: return o | (0xd<<21); + case ABIC: return o | (0xe<<21); + case AMVN: return o | (0xf<<21); + case ASLL: return o | (0xd<<21) | (0<<5); + case ASRL: return o | (0xd<<21) | (1<<5); + case ASRA: return o | (0xd<<21) | (2<<5); + case ASWI: return o | (0xf<<24); + + case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4); + case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4); + case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4); + case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4); + case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4); + case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4); + case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4); + case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4); + case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4); + case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4); + case AABSD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (0xc<<4); + case AABSF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (0xc<<4); + case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4); + case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4); + + case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4); + case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4); + + case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) | + (1<<8); // dtof + case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) | + (0<<8); // dtof + + case AMOVWF: + if((sc & C_UBIT) == 0) + o |= 1<<7; /* signed */ + return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | + (0<<18) | (0<<8); // toint, double + case AMOVWD: + if((sc & C_UBIT) == 0) + o |= 1<<7; /* signed */ + return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | + (0<<18) | (1<<8); // toint, double + + case AMOVFW: + if((sc & C_UBIT) == 0) + o |= 1<<16; /* signed */ + return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | + (1<<18) | (0<<8) | (1<<7); // toint, double, trunc + case AMOVDW: + if((sc & C_UBIT) == 0) + o |= 1<<16; /* signed */ + return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | + (1<<18) | (1<<8) | (1<<7); // toint, double, trunc + + case AMOVWF+AEND: // copy WtoF + return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4); + case AMOVFW+AEND: // copy FtoW + return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4); + case ACMP+AEND: // cmp imm + return o | (0x3<<24) | (0x5<<20); + + case ACLZ: + // CLZ doesn't support .nil + return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4); + + case AMULWT: + return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4); + case AMULWB: + return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4); + case AMULAWT: + return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4); + case AMULAWB: + return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4); + + case ABL: // BLX REG + return (o & (0xf<<28)) | (0x12fff3 << 4); + } + ctxt->diag("bad rrr %d", a); + prasm(ctxt->curp); + return 0; +} + +int32 +opbra(Link *ctxt, int a, int sc) +{ + + if(sc & (C_SBIT|C_PBIT|C_WBIT)) + ctxt->diag(".nil/.nil/.W on bra instruction"); + sc &= C_SCOND; + if(a == ABL) + return (sc<<28)|(0x5<<25)|(0x1<<24); + if(sc != 0xe) + ctxt->diag(".COND on bcond instruction"); + switch(a) { + case ABEQ: return (0x0<<28)|(0x5<<25); + case ABNE: return (0x1<<28)|(0x5<<25); + case ABCS: return (0x2<<28)|(0x5<<25); + case ABHS: return (0x2<<28)|(0x5<<25); + case ABCC: return (0x3<<28)|(0x5<<25); + case ABLO: return (0x3<<28)|(0x5<<25); + case ABMI: return (0x4<<28)|(0x5<<25); + case ABPL: return (0x5<<28)|(0x5<<25); + case ABVS: return (0x6<<28)|(0x5<<25); + case ABVC: return (0x7<<28)|(0x5<<25); + case ABHI: return (0x8<<28)|(0x5<<25); + case ABLS: return (0x9<<28)|(0x5<<25); + case ABGE: return (0xa<<28)|(0x5<<25); + case ABLT: return (0xb<<28)|(0x5<<25); + case ABGT: return (0xc<<28)|(0x5<<25); + case ABLE: return (0xd<<28)|(0x5<<25); + case AB: return (0xe<<28)|(0x5<<25); + } + ctxt->diag("bad bra %A", a); + prasm(ctxt->curp); + return 0; +} + +int32 +olr(Link *ctxt, int32 v, int b, int r, int sc) +{ + int32 o; + + if(sc & C_SBIT) + ctxt->diag(".nil on LDR/STR instruction"); + o = (sc & C_SCOND) << 28; + if(!(sc & C_PBIT)) + o |= 1 << 24; + if(!(sc & C_UBIT)) + o |= 1 << 23; + if(sc & C_WBIT) + o |= 1 << 21; + o |= (1<<26) | (1<<20); + if(v < 0) { + if(sc & C_UBIT) + ctxt->diag(".U on neg offset"); + v = -v; + o ^= 1 << 23; + } + if(v >= (1<<12) || v < 0) + ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp); + o |= v; + o |= b << 16; + o |= r << 12; + return o; +} + +int32 +olhr(Link *ctxt, int32 v, int b, int r, int sc) +{ + int32 o; + + if(sc & C_SBIT) + ctxt->diag(".nil on LDRH/STRH instruction"); + o = (sc & C_SCOND) << 28; + if(!(sc & C_PBIT)) + o |= 1 << 24; + if(sc & C_WBIT) + o |= 1 << 21; + o |= (1<<23) | (1<<20)|(0xb<<4); + if(v < 0) { + v = -v; + o ^= 1 << 23; + } + if(v >= (1<<8) || v < 0) + ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp); + o |= (v&0xf)|((v>>4)<<8)|(1<<22); + o |= b << 16; + o |= r << 12; + return o; +} + +int32 +osr(Link *ctxt, int a, int r, int32 v, int b, int sc) +{ + int32 o; + + o = olr(ctxt, v, b, r, sc) ^ (1<<20); + if(a != AMOVW) + o |= 1<<22; + return o; +} + +int32 +oshr(Link *ctxt, int r, int32 v, int b, int sc) +{ + int32 o; + + o = olhr(ctxt, v, b, r, sc) ^ (1<<20); + return o; +} + + +int32 +osrr(Link *ctxt, int r, int i, int b, int sc) +{ + + return olr(ctxt, i, b, r, sc) ^ ((1<<25) | (1<<20)); +} + +int32 +oshrr(Link *ctxt, int r, int i, int b, int sc) +{ + return olhr(ctxt, i, b, r, sc) ^ ((1<<22) | (1<<20)); +} + +int32 +olrr(Link *ctxt, int i, int b, int r, int sc) +{ + + return olr(ctxt, i, b, r, sc) ^ (1<<25); +} + +int32 +olhrr(Link *ctxt, int i, int b, int r, int sc) +{ + return olhr(ctxt, i, b, r, sc) ^ (1<<22); +} + +int32 +ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p) +{ + int32 o; + + if(sc & C_SBIT) + ctxt->diag(".nil on FLDR/FSTR instruction"); + o = (sc & C_SCOND) << 28; + if(!(sc & C_PBIT)) + o |= 1 << 24; + if(sc & C_WBIT) + o |= 1 << 21; + o |= (6<<25) | (1<<24) | (1<<23) | (10<<8); + if(v < 0) { + v = -v; + o ^= 1 << 23; + } + if(v & 3) + ctxt->diag("odd offset for floating point op: %d\n%P", v, p); + else + if(v >= (1<<10) || v < 0) + ctxt->diag("literal span too large: %d\n%P", v, p); + o |= (v>>2) & 0xFF; + o |= b << 16; + o |= r << 12; + + switch(a) { + default: + ctxt->diag("bad fst %A", a); + case AMOVD: + o |= 1 << 8; + case AMOVF: + break; + } + return o; +} + +int32 +omvl(Link *ctxt, Prog *p, Addr *a, int dr) +{ + int32 v, o1; + if(!p->pcond) { + aclass(ctxt, a); + v = immrot(~ctxt->instoffset); + if(v == 0) { + ctxt->diag("missing literal"); + prasm(p); + return 0; + } + o1 = oprrr(ctxt, AMVN, p->scond&C_SCOND); + o1 |= v; + o1 |= dr << 12; + } else { + v = p->pcond->pc - p->pc - 8; + o1 = olr(ctxt, v, REGPC, dr, p->scond&C_SCOND); + } + return o1; +} + +static int +chipzero(Link *ctxt, float64 e) +{ + // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. + if(ctxt->goarm < 7 || e != 0) + return -1; + return 0; +} + +static int +chipfloat(Link *ctxt, float64 e) +{ + int n; + ulong h1; + int32 l, h; + uint64 ei; + + // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. + if(ctxt->goarm < 7) + goto no; + + memmove(&ei, &e, 8); + l = (int32)ei; + h = (int32)(ei>>32); + + if(l != 0 || (h&0xffff) != 0) + goto no; + h1 = h & 0x7fc00000; + if(h1 != 0x40000000 && h1 != 0x3fc00000) + goto no; + n = 0; + + // sign bit (a) + if(h & 0x80000000) + n |= 1<<7; + + // exp sign bit (b) + if(h1 == 0x3fc00000) + n |= 1<<6; + + // rest of exp and mantissa (cd-efgh) + n |= (h >> 16) & 0x3f; + +//print("match %.8lux %.8lux %d\n", l, h, n); + return n; + +no: + return -1; +} diff --git a/src/liblink/asm6.c b/src/liblink/asm6.c new file mode 100644 index 000000000..019ec0684 --- /dev/null +++ b/src/liblink/asm6.c @@ -0,0 +1,3289 @@ +// Inferno utils/6l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/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. ctxt->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 ctxt->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, ctxt->and/or sell +// copies of the Software, ctxt->and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice ctxt->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. + +// Instruction layout. + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> +#include "../cmd/6l/6.out.h" +#include "../pkg/runtime/stack.h" + +enum +{ + MaxAlign = 32, // max data alignment + + // Loop alignment constants: + // want to align loop entry to LoopAlign-byte boundary, + // ctxt->and willing to insert at most MaxLoopPad bytes of NOP to do so. + // We define a loop entry as the target of a backward jump. + // + // gcc uses MaxLoopPad = 10 for its 'generic x86-64' config, + // ctxt->and it aligns all jump targets, not just backward jump targets. + // + // As of 6/1/2012, the effect of setting MaxLoopPad = 10 here + // is very slight but negative, so the alignment is disabled by + // setting MaxLoopPad = 0. The code is here for reference ctxt->and + // for future experiments. + // + LoopAlign = 16, + MaxLoopPad = 0, + + FuncAlign = 16 +}; + +extern char *anames6[]; + +typedef struct Optab Optab; +typedef struct Movtab Movtab; + +struct Optab +{ + short as; + uchar* ytab; + uchar prefix; + uchar op[23]; +}; +struct Movtab +{ + short as; + uchar ft; + uchar tt; + uchar code; + uchar op[4]; +}; + +enum +{ + Yxxx = 0, + Ynone, + Yi0, + Yi1, + Yi8, + Ys32, + Yi32, + Yi64, + 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, Ycr8, + Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7, + Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64, + Ymr, Ymm, + Yxr, Yxm, + Ymax, + + Zxxx = 0, + + Zlit, + Zlitm_r, + Z_rp, + Zbr, + Zcall, + Zib_, + Zib_rp, + Zibo_m, + Zibo_m_xm, + Zil_, + Zil_rp, + Ziq_rp, + Zilo_m, + Ziqo_m, + Zjmp, + Zloop, + Zo_iw, + Zm_o, + Zm_r, + Zm2_r, + Zm_r_xm, + Zm_r_i_xm, + Zm_r_3d, + Zm_r_xm_nr, + Zr_m_xm_nr, + Zibm_r, /* mmx1,mmx2/mem64,imm8 */ + Zmb_r, + Zaut_r, + Zo_m, + Zo_m64, + Zpseudo, + Zr_m, + Zr_m_xm, + Zr_m_i_xm, + Zrp_, + Z_ib, + Z_il, + Zm_ibo, + Zm_ilo, + Zib_rr, + Zil_rr, + Zclr, + Zbyte, + Zmax, + + Px = 0, + P32 = 0x32, /* 32-bit only */ + Pe = 0x66, /* operand escape */ + Pm = 0x0f, /* 2byte opcode escape */ + Pq = 0xff, /* both escapes: 66 0f */ + Pb = 0xfe, /* byte operands */ + Pf2 = 0xf2, /* xmm escape 1: f2 0f */ + Pf3 = 0xf3, /* xmm escape 2: f3 0f */ + Pq3 = 0x67, /* xmm escape 3: 66 48 0f */ + Pw = 0x48, /* Rex.w */ + Py = 0x80, /* defaults to 64-bit mode */ + + Rxf = 1<<9, /* internal flag for Rxr on from */ + Rxt = 1<<8, /* internal flag for Rxr on to */ + Rxw = 1<<3, /* =1, 64-bit operand size */ + Rxr = 1<<2, /* extend modrm reg */ + Rxx = 1<<1, /* extend sib index */ + Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */ + + Maxand = 10, /* in -a output width of the byte codes */ +}; + +static char ycover[Ymax*Ymax]; +static int reg[D_NONE]; +static int regrex[D_NONE+1]; +static void asmins(Link *ctxt, Prog *p); + +static uchar ynone[] = +{ + Ynone, Ynone, Zlit, 1, + 0 +}; +static uchar ytext[] = +{ + Ymb, Yi64, Zpseudo,1, + 0 +}; +static uchar ynop[] = +{ + Ynone, Ynone, Zpseudo,0, + Ynone, Yiauto, Zpseudo,0, + Ynone, Yml, Zpseudo,0, + Ynone, Yrf, Zpseudo,0, + Ynone, Yxr, Zpseudo,0, + Yiauto, Ynone, Zpseudo,0, + Yml, Ynone, Zpseudo,0, + Yrf, Ynone, Zpseudo,0, + Yxr, Ynone, Zpseudo,1, + 0 +}; +static uchar yfuncdata[] = +{ + Yi32, Ym, Zpseudo, 0, + 0 +}; +static uchar ypcdata[] = +{ + Yi32, Yi32, Zpseudo, 0, + 0 +}; +static uchar yxorb[] = +{ + Yi32, Yal, Zib_, 1, + Yi32, Ymb, Zibo_m, 2, + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +static 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 +}; +static 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 +}; +static uchar yincb[] = +{ + Ynone, Ymb, Zo_m, 2, + 0 +}; +static uchar yincw[] = +{ + Ynone, Yml, Zo_m, 2, + 0 +}; +static uchar yincl[] = +{ + Ynone, Yml, Zo_m, 2, + 0 +}; +static uchar ycmpb[] = +{ + Yal, Yi32, Z_ib, 1, + Ymb, Yi32, Zm_ibo, 2, + Ymb, Yrb, Zm_r, 1, + Yrb, Ymb, Zr_m, 1, + 0 +}; +static 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 +}; +static uchar yshb[] = +{ + Yi1, Ymb, Zo_m, 2, + Yi32, Ymb, Zibo_m, 2, + Ycx, Ymb, Zo_m, 2, + 0 +}; +static uchar yshl[] = +{ + Yi1, Yml, Zo_m, 2, + Yi32, Yml, Zibo_m, 2, + Ycl, Yml, Zo_m, 2, + Ycx, Yml, Zo_m, 2, + 0 +}; +static uchar ytestb[] = +{ + Yi32, Yal, Zib_, 1, + Yi32, Ymb, Zibo_m, 2, + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +static uchar ytestl[] = +{ + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +static uchar ymovb[] = +{ + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + Yi32, Yrb, Zib_rp, 1, + Yi32, Ymb, Zibo_m, 2, + 0 +}; +static uchar ymbs[] = +{ + Ymb, Ynone, Zm_o, 2, + 0 +}; +static uchar ybtl[] = +{ + Yi8, Yml, Zibo_m, 2, + Yrl, Yml, Zr_m, 1, + 0 +}; +static uchar ymovw[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + Yi0, Yrl, Zclr, 1, + Yi32, Yrl, Zil_rp, 1, + Yi32, Yml, Zilo_m, 2, + Yiauto, Yrl, Zaut_r, 2, + 0 +}; +static uchar ymovl[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + Yi0, Yrl, Zclr, 1, + Yi32, Yrl, Zil_rp, 1, + Yi32, Yml, Zilo_m, 2, + Yml, Ymr, Zm_r_xm, 1, // MMX MOVD + Ymr, Yml, Zr_m_xm, 1, // MMX MOVD + Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit) + Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit) + Yiauto, Yrl, Zaut_r, 2, + 0 +}; +static uchar yret[] = +{ + Ynone, Ynone, Zo_iw, 1, + Yi32, Ynone, Zo_iw, 1, + 0 +}; +static uchar ymovq[] = +{ + Yrl, Yml, Zr_m, 1, // 0x89 + Yml, Yrl, Zm_r, 1, // 0x8b + Yi0, Yrl, Zclr, 1, // 0x31 + Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0) + Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate + Yi32, Yml, Zilo_m, 2, // 0xc7,(0) + Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding) + Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ + Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD + Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD + Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q + Yxm, Yxr, Zm_r_xm_nr, 2, // MOVQ xmm1/m64 -> xmm2 + Yxr, Yxm, Zr_m_xm_nr, 2, // MOVQ xmm1 -> xmm2/m64 + Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load + Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store + Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ + 0 +}; +static uchar ym_rl[] = +{ + Ym, Yrl, Zm_r, 1, + 0 +}; +static uchar yrl_m[] = +{ + Yrl, Ym, Zr_m, 1, + 0 +}; +static uchar ymb_rl[] = +{ + Ymb, Yrl, Zmb_r, 1, + 0 +}; +static uchar yml_rl[] = +{ + Yml, Yrl, Zm_r, 1, + 0 +}; +static uchar yrl_ml[] = +{ + Yrl, Yml, Zr_m, 1, + 0 +}; +static uchar yml_mb[] = +{ + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +static uchar yrb_mb[] = +{ + Yrb, Ymb, Zr_m, 1, + 0 +}; +static uchar yxchg[] = +{ + Yax, Yrl, Z_rp, 1, + Yrl, Yax, Zrp_, 1, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +static uchar ydivl[] = +{ + Yml, Ynone, Zm_o, 2, + 0 +}; +static uchar ydivb[] = +{ + Ymb, Ynone, Zm_o, 2, + 0 +}; +static uchar yimul[] = +{ + Yml, Ynone, Zm_o, 2, + Yi8, Yrl, Zib_rr, 1, + Yi32, Yrl, Zil_rr, 1, + Yml, Yrl, Zm_r, 2, + 0 +}; +static uchar yimul3[] = +{ + Yml, Yrl, Zibm_r, 2, + 0 +}; +static uchar ybyte[] = +{ + Yi64, Ynone, Zbyte, 1, + 0 +}; +static uchar yin[] = +{ + Yi32, Ynone, Zib_, 1, + Ynone, Ynone, Zlit, 1, + 0 +}; +static uchar yint[] = +{ + Yi32, Ynone, Zib_, 1, + 0 +}; +static uchar ypushl[] = +{ + Yrl, Ynone, Zrp_, 1, + Ym, Ynone, Zm_o, 2, + Yi8, Ynone, Zib_, 1, + Yi32, Ynone, Zil_, 1, + 0 +}; +static uchar ypopl[] = +{ + Ynone, Yrl, Z_rp, 1, + Ynone, Ym, Zo_m, 2, + 0 +}; +static uchar ybswap[] = +{ + Ynone, Yrl, Z_rp, 2, + 0, +}; +static uchar yscond[] = +{ + Ynone, Ymb, Zo_m, 2, + 0 +}; +static uchar yjcond[] = +{ + Ynone, Ybr, Zbr, 0, + Yi0, Ybr, Zbr, 0, + Yi1, Ybr, Zbr, 1, + 0 +}; +static uchar yloop[] = +{ + Ynone, Ybr, Zloop, 1, + 0 +}; +static uchar ycall[] = +{ + Ynone, Yml, Zo_m64, 0, + Yrx, Yrx, Zo_m64, 2, + Ynone, Ybr, Zcall, 1, + 0 +}; +static uchar yjmp[] = +{ + Ynone, Yml, Zo_m64, 2, + Ynone, Ybr, Zjmp, 1, + 0 +}; + +static uchar yfmvd[] = +{ + Ym, Yf0, Zm_o, 2, + Yf0, Ym, Zo_m, 2, + Yrf, Yf0, Zm_o, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +static uchar yfmvdp[] = +{ + Yf0, Ym, Zo_m, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +static uchar yfmvf[] = +{ + Ym, Yf0, Zm_o, 2, + Yf0, Ym, Zo_m, 2, + 0 +}; +static uchar yfmvx[] = +{ + Ym, Yf0, Zm_o, 2, + 0 +}; +static uchar yfmvp[] = +{ + Yf0, Ym, Zo_m, 2, + 0 +}; +static uchar yfadd[] = +{ + Ym, Yf0, Zm_o, 2, + Yrf, Yf0, Zm_o, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +static uchar yfaddp[] = +{ + Yf0, Yrf, Zo_m, 2, + 0 +}; +static uchar yfxch[] = +{ + Yf0, Yrf, Zo_m, 2, + Yrf, Yf0, Zm_o, 2, + 0 +}; +static uchar ycompp[] = +{ + Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */ + 0 +}; +static uchar ystsw[] = +{ + Ynone, Ym, Zo_m, 2, + Ynone, Yax, Zlit, 1, + 0 +}; +static uchar ystcw[] = +{ + Ynone, Ym, Zo_m, 2, + Ym, Ynone, Zm_o, 2, + 0 +}; +static uchar ysvrs[] = +{ + Ynone, Ym, Zo_m, 2, + Ym, Ynone, Zm_o, 2, + 0 +}; +static uchar ymm[] = +{ + Ymm, Ymr, Zm_r_xm, 1, + Yxm, Yxr, Zm_r_xm, 2, + 0 +}; +static uchar yxm[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +static uchar yxcvm1[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + Yxm, Ymr, Zm_r_xm, 2, + 0 +}; +static uchar yxcvm2[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + Ymm, Yxr, Zm_r_xm, 2, + 0 +}; +/* +static uchar yxmq[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + 0 +}; +*/ +static uchar yxr[] = +{ + Yxr, Yxr, Zm_r_xm, 1, + 0 +}; +static uchar yxr_ml[] = +{ + Yxr, Yml, Zr_m_xm, 1, + 0 +}; +static uchar ymr[] = +{ + Ymr, Ymr, Zm_r, 1, + 0 +}; +static uchar ymr_ml[] = +{ + Ymr, Yml, Zr_m_xm, 1, + 0 +}; +static uchar yxcmp[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +static uchar yxcmpi[] = +{ + Yxm, Yxr, Zm_r_i_xm, 2, + 0 +}; +static uchar yxmov[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + Yxr, Yxm, Zr_m_xm, 1, + 0 +}; +static uchar yxcvfl[] = +{ + Yxm, Yrl, Zm_r_xm, 1, + 0 +}; +static uchar yxcvlf[] = +{ + Yml, Yxr, Zm_r_xm, 1, + 0 +}; +static uchar yxcvfq[] = +{ + Yxm, Yrl, Zm_r_xm, 2, + 0 +}; +static uchar yxcvqf[] = +{ + Yml, Yxr, Zm_r_xm, 2, + 0 +}; +static uchar yps[] = +{ + Ymm, Ymr, Zm_r_xm, 1, + Yi8, Ymr, Zibo_m_xm, 2, + Yxm, Yxr, Zm_r_xm, 2, + Yi8, Yxr, Zibo_m_xm, 3, + 0 +}; +static uchar yxrrl[] = +{ + Yxr, Yrl, Zm_r, 1, + 0 +}; +static uchar ymfp[] = +{ + Ymm, Ymr, Zm_r_3d, 1, + 0, +}; +static uchar ymrxr[] = +{ + Ymr, Yxr, Zm_r, 1, + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +static uchar ymshuf[] = +{ + Ymm, Ymr, Zibm_r, 2, + 0 +}; +static uchar ymshufb[] = +{ + Yxm, Yxr, Zm2_r, 2, + 0 +}; +static uchar yxshuf[] = +{ + Yxm, Yxr, Zibm_r, 2, + 0 +}; +static uchar yextrw[] = +{ + Yxr, Yrl, Zibm_r, 2, + 0 +}; +static uchar yinsrw[] = +{ + Yml, Yxr, Zibm_r, 2, + 0 +}; +static uchar yinsr[] = +{ + Ymm, Yxr, Zibm_r, 3, + 0 +}; +static uchar ypsdq[] = +{ + Yi8, Yxr, Zibo_m, 2, + 0 +}; +static uchar ymskb[] = +{ + Yxr, Yrl, Zm_r_xm, 2, + Ymr, Yrl, Zm_r_xm, 1, + 0 +}; +static uchar ycrc32l[] = +{ + Yml, Yrl, Zlitm_r, 0, +}; +static uchar yprefetch[] = +{ + Ym, Ynone, Zm_o, 2, + 0, +}; +static uchar yaes[] = +{ + Yxm, Yxr, Zlitm_r, 2, + 0 +}; +static uchar yaes2[] = +{ + Yxm, Yxr, Zibm_r, 2, + 0 +}; + +/* + * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32, + * ctxt->and p->from ctxt->and p->to as operands (Addr*). The linker scans optab to find + * the entry with the given p->as ctxt->and then looks through the ytable for that + * instruction (the second field in the optab struct) for a line whose first + * two values match the Ytypes of the p->from ctxt->and p->to operands. The function + * oclass in span.c computes the specific Ytype of an operand ctxt->and then the set + * of more general Ytypes that it satisfies is implied by the ycover table, set + * up in instinit. For example, oclass distinguishes the constants 0 ctxt->and 1 + * from the more general 8-bit constants, but instinit says + * + * ycover[Yi0*Ymax + Ys32] = 1; + * ycover[Yi1*Ymax + Ys32] = 1; + * ycover[Yi8*Ymax + Ys32] = 1; + * + * which means that Yi0, Yi1, ctxt->and Yi8 all count as Ys32 (signed 32) + * if that's what an instruction can handle. + * + * In parallel with the scan through the ytable for the appropriate line, there + * is a z pointer that starts out pointing at the strange magic byte list in + * the Optab struct. With each step past a non-matching ytable line, z + * advances by the 4th entry in the line. When a matching line is found, that + * z pointer has the extra data to use in laying down the instruction bytes. + * The actual bytes laid down are a function of the 3rd entry in the line (that + * is, the Ztype) ctxt->and the z bytes. + * + * For example, let's look at AADDL. The optab line says: + * { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + * + * ctxt->and yaddl says + * 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 + * }; + * + * so there are 5 possible types of ADDL instruction that can be laid down, ctxt->and + * possible states used to lay them down (Ztype ctxt->and z pointer, assuming z + * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are: + * + * Yi8, Yml -> Zibo_m, z (0x83, 00) + * Yi32, Yax -> Zil_, z+2 (0x05) + * Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00) + * Yrl, Yml -> Zr_m, z+2+1+2 (0x01) + * Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03) + * + * The Pconstant in the optab line controls the prefix bytes to emit. That's + * relatively straightforward as this program goes. + * + * The switch on t[2] in doasm implements the various Z cases. Zibo_m, for + * example, is an opcode byte (z[0]) then an asmando (which is some kind of + * encoded addressing mode for the Yml arg), ctxt->and then a single immediate byte. + * Zilo_m is the same but a long (32-bit) immediate. + */ +Optab optab[] = +/* as, ytab, andproto, opcode */ +{ + { AXXX }, + { AAAA, ynone, P32, 0x37 }, + { AAAD, ynone, P32, 0xd5,0x0a }, + { AAAM, ynone, P32, 0xd4,0x0a }, + { AAAS, ynone, P32, 0x3f }, + { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 }, + { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 }, + { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADDPD, yxm, Pq, 0x58 }, + { AADDPS, yxm, Pm, 0x58 }, + { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADDSD, yxm, Pf2, 0x58 }, + { AADDSS, yxm, Pf3, 0x58 }, + { 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 }, + { AANDNPD, yxm, Pq, 0x55 }, + { AANDNPS, yxm, Pm, 0x55 }, + { AANDPD, yxm, Pq, 0x54 }, + { AANDPS, yxm, Pq, 0x54 }, + { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AARPL, yrl_ml, P32, 0x63 }, + { ABOUNDL, yrl_m, P32, 0x62 }, + { ABOUNDW, yrl_m, Pe, 0x62 }, + { ABSFL, yml_rl, Pm, 0xbc }, + { ABSFQ, yml_rl, Pw, 0x0f,0xbc }, + { ABSFW, yml_rl, Pq, 0xbc }, + { ABSRL, yml_rl, Pm, 0xbd }, + { ABSRQ, yml_rl, Pw, 0x0f,0xbd }, + { ABSRW, yml_rl, Pq, 0xbd }, + { ABSWAPL, ybswap, Px, 0x0f,0xc8 }, + { ABSWAPQ, ybswap, Pw, 0x0f,0xc8 }, + { ABTCL, ybtl, Pm, 0xba,(07),0xbb }, + { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb }, + { ABTCW, ybtl, Pq, 0xba,(07),0xbb }, + { ABTL, ybtl, Pm, 0xba,(04),0xa3 }, + { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3}, + { ABTRL, ybtl, Pm, 0xba,(06),0xb3 }, + { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 }, + { ABTRW, ybtl, Pq, 0xba,(06),0xb3 }, + { ABTSL, ybtl, Pm, 0xba,(05),0xab }, + { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab }, + { ABTSW, ybtl, Pq, 0xba,(05),0xab }, + { ABTW, ybtl, Pq, 0xba,(04),0xa3 }, + { ABYTE, ybyte, Px, 1 }, + { ACALL, ycall, Px, 0xff,(02),0xe8 }, + { ACDQ, ynone, Px, 0x99 }, + { ACLC, ynone, Px, 0xf8 }, + { ACLD, ynone, Px, 0xfc }, + { ACLI, ynone, Px, 0xfa }, + { ACLTS, ynone, Pm, 0x06 }, + { ACMC, ynone, Px, 0xf5 }, + { ACMOVLCC, yml_rl, Pm, 0x43 }, + { ACMOVLCS, yml_rl, Pm, 0x42 }, + { ACMOVLEQ, yml_rl, Pm, 0x44 }, + { ACMOVLGE, yml_rl, Pm, 0x4d }, + { ACMOVLGT, yml_rl, Pm, 0x4f }, + { ACMOVLHI, yml_rl, Pm, 0x47 }, + { ACMOVLLE, yml_rl, Pm, 0x4e }, + { ACMOVLLS, yml_rl, Pm, 0x46 }, + { ACMOVLLT, yml_rl, Pm, 0x4c }, + { ACMOVLMI, yml_rl, Pm, 0x48 }, + { ACMOVLNE, yml_rl, Pm, 0x45 }, + { ACMOVLOC, yml_rl, Pm, 0x41 }, + { ACMOVLOS, yml_rl, Pm, 0x40 }, + { ACMOVLPC, yml_rl, Pm, 0x4b }, + { ACMOVLPL, yml_rl, Pm, 0x49 }, + { ACMOVLPS, yml_rl, Pm, 0x4a }, + { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 }, + { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 }, + { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 }, + { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d }, + { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f }, + { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 }, + { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e }, + { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 }, + { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c }, + { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 }, + { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 }, + { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 }, + { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 }, + { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b }, + { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 }, + { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a }, + { ACMOVWCC, yml_rl, Pq, 0x43 }, + { ACMOVWCS, yml_rl, Pq, 0x42 }, + { ACMOVWEQ, yml_rl, Pq, 0x44 }, + { ACMOVWGE, yml_rl, Pq, 0x4d }, + { ACMOVWGT, yml_rl, Pq, 0x4f }, + { ACMOVWHI, yml_rl, Pq, 0x47 }, + { ACMOVWLE, yml_rl, Pq, 0x4e }, + { ACMOVWLS, yml_rl, Pq, 0x46 }, + { ACMOVWLT, yml_rl, Pq, 0x4c }, + { ACMOVWMI, yml_rl, Pq, 0x48 }, + { ACMOVWNE, yml_rl, Pq, 0x45 }, + { ACMOVWOC, yml_rl, Pq, 0x41 }, + { ACMOVWOS, yml_rl, Pq, 0x40 }, + { ACMOVWPC, yml_rl, Pq, 0x4b }, + { ACMOVWPL, yml_rl, Pq, 0x49 }, + { ACMOVWPS, yml_rl, Pq, 0x4a }, + { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a }, + { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACMPPD, yxcmpi, Px, Pe,0xc2 }, + { ACMPPS, yxcmpi, Pm, 0xc2,0 }, + { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACMPSB, ynone, Pb, 0xa6 }, + { ACMPSD, yxcmpi, Px, Pf2,0xc2 }, + { ACMPSL, ynone, Px, 0xa7 }, + { ACMPSQ, ynone, Pw, 0xa7 }, + { ACMPSS, yxcmpi, Px, Pf3,0xc2 }, + { ACMPSW, ynone, Pe, 0xa7 }, + { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACOMISD, yxcmp, Pe, 0x2f }, + { ACOMISS, yxcmp, Pm, 0x2f }, + { ACPUID, ynone, Pm, 0xa2 }, + { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a }, + { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, }, + { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d }, + { ACVTPD2PS, yxm, Pe, 0x5a }, + { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d }, + { ACVTPS2PD, yxm, Pm, 0x5a }, + { API2FW, ymfp, Px, 0x0c }, + { ACVTSD2SL, yxcvfl, Pf2, 0x2d }, + { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d }, + { ACVTSD2SS, yxm, Pf2, 0x5a }, + { ACVTSL2SD, yxcvlf, Pf2, 0x2a }, + { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a }, + { ACVTSL2SS, yxcvlf, Pf3, 0x2a }, + { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a }, + { ACVTSS2SD, yxm, Pf3, 0x5a }, + { ACVTSS2SL, yxcvfl, Pf3, 0x2d }, + { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d }, + { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c }, + { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c }, + { ACVTTSD2SL, yxcvfl, Pf2, 0x2c }, + { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c }, + { ACVTTSS2SL, yxcvfl, Pf3, 0x2c }, + { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c }, + { ACWD, ynone, Pe, 0x99 }, + { ACQO, ynone, Pw, 0x99 }, + { ADAA, ynone, P32, 0x27 }, + { ADAS, ynone, P32, 0x2f }, + { ADATA }, + { ADECB, yincb, Pb, 0xfe,(01) }, + { ADECL, yincl, Px, 0xff,(01) }, + { ADECQ, yincl, Pw, 0xff,(01) }, + { ADECW, yincw, Pe, 0xff,(01) }, + { ADIVB, ydivb, Pb, 0xf6,(06) }, + { ADIVL, ydivl, Px, 0xf7,(06) }, + { ADIVPD, yxm, Pe, 0x5e }, + { ADIVPS, yxm, Pm, 0x5e }, + { ADIVQ, ydivl, Pw, 0xf7,(06) }, + { ADIVSD, yxm, Pf2, 0x5e }, + { ADIVSS, yxm, Pf3, 0x5e }, + { ADIVW, ydivl, Pe, 0xf7,(06) }, + { AEMMS, ynone, Pm, 0x77 }, + { AENTER }, /* botch */ + { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) }, + { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) }, + { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) }, + { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) }, + { AGLOBL }, + { AGOK }, + { AHISTORY }, + { AHLT, ynone, Px, 0xf4 }, + { AIDIVB, ydivb, Pb, 0xf6,(07) }, + { AIDIVL, ydivl, Px, 0xf7,(07) }, + { AIDIVQ, ydivl, Pw, 0xf7,(07) }, + { AIDIVW, ydivl, Pe, 0xf7,(07) }, + { AIMULB, ydivb, Pb, 0xf6,(05) }, + { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf }, + { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf }, + { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf }, + { AIMUL3Q, yimul3, Pw, 0x6b,(00) }, + { AINB, yin, Pb, 0xe4,0xec }, + { AINCB, yincb, Pb, 0xfe,(00) }, + { AINCL, yincl, Px, 0xff,(00) }, + { AINCQ, yincl, Pw, 0xff,(00) }, + { AINCW, yincw, Pe, 0xff,(00) }, + { AINL, yin, Px, 0xe5,0xed }, + { AINSB, ynone, Pb, 0x6c }, + { AINSL, ynone, Px, 0x6d }, + { AINSW, ynone, Pe, 0x6d }, + { AINT, yint, Px, 0xcd }, + { AINTO, ynone, P32, 0xce }, + { AINW, yin, Pe, 0xe5,0xed }, + { AIRETL, ynone, Px, 0xcf }, + { AIRETQ, ynone, Pw, 0xcf }, + { AIRETW, ynone, Pe, 0xcf }, + { AJCC, yjcond, Px, 0x73,0x83,(00) }, + { AJCS, yjcond, Px, 0x72,0x82 }, + { AJCXZL, yloop, Px, 0xe3 }, + { AJCXZQ, 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 }, + { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) }, + { ALEAL, ym_rl, Px, 0x8d }, + { ALEAQ, ym_rl, Pw, 0x8d }, + { ALEAVEL, ynone, P32, 0xc9 }, + { ALEAVEQ, ynone, Py, 0xc9 }, + { ALEAVEW, ynone, Pe, 0xc9 }, + { ALEAW, ym_rl, Pe, 0x8d }, + { ALOCK, ynone, Px, 0xf0 }, + { ALODSB, ynone, Pb, 0xac }, + { ALODSL, ynone, Px, 0xad }, + { ALODSQ, ynone, Pw, 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 }, + { AMASKMOVOU, yxr, Pe, 0xf7 }, + { AMASKMOVQ, ymr, Pm, 0xf7 }, + { AMAXPD, yxm, Pe, 0x5f }, + { AMAXPS, yxm, Pm, 0x5f }, + { AMAXSD, yxm, Pf2, 0x5f }, + { AMAXSS, yxm, Pf3, 0x5f }, + { AMINPD, yxm, Pe, 0x5d }, + { AMINPS, yxm, Pm, 0x5d }, + { AMINSD, yxm, Pf2, 0x5d }, + { AMINSS, yxm, Pf3, 0x5d }, + { AMOVAPD, yxmov, Pe, 0x28,0x29 }, + { AMOVAPS, yxmov, Pm, 0x28,0x29 }, + { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) }, + { AMOVBLSX, ymb_rl, Pm, 0xbe }, + { AMOVBLZX, ymb_rl, Pm, 0xb6 }, + { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe }, + { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 }, + { AMOVBWSX, ymb_rl, Pq, 0xbe }, + { AMOVBWZX, ymb_rl, Pq, 0xb6 }, + { AMOVO, yxmov, Pe, 0x6f,0x7f }, + { AMOVOU, yxmov, Pf3, 0x6f,0x7f }, + { AMOVHLPS, yxr, Pm, 0x12 }, + { AMOVHPD, yxmov, Pe, 0x16,0x17 }, + { AMOVHPS, yxmov, Pm, 0x16,0x17 }, + { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e,0 }, + { AMOVLHPS, yxr, Pm, 0x16 }, + { AMOVLPD, yxmov, Pe, 0x12,0x13 }, + { AMOVLPS, yxmov, Pm, 0x12,0x13 }, + { AMOVLQSX, yml_rl, Pw, 0x63 }, + { AMOVLQZX, yml_rl, Px, 0x8b }, + { AMOVMSKPD, yxrrl, Pq, 0x50 }, + { AMOVMSKPS, yxrrl, Pm, 0x50 }, + { AMOVNTO, yxr_ml, Pe, 0xe7 }, + { AMOVNTPD, yxr_ml, Pe, 0x2b }, + { AMOVNTPS, yxr_ml, Pm, 0x2b }, + { AMOVNTQ, ymr_ml, Pm, 0xe7 }, + { AMOVQ, ymovq, Pw, 0x89, 0x8b, 0x31, 0xc7,(00), 0xb8, 0xc7,(00), 0x6f, 0x7f, 0x6e, 0x7e, Pf2,0xd6, Pf3,0x7e, Pe,0xd6, Pe,0x6e, Pe,0x7e,0 }, + { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e }, + { AMOVSB, ynone, Pb, 0xa4 }, + { AMOVSD, yxmov, Pf2, 0x10,0x11 }, + { AMOVSL, ynone, Px, 0xa5 }, + { AMOVSQ, ynone, Pw, 0xa5 }, + { AMOVSS, yxmov, Pf3, 0x10,0x11 }, + { AMOVSW, ynone, Pe, 0xa5 }, + { AMOVUPD, yxmov, Pe, 0x10,0x11 }, + { AMOVUPS, yxmov, Pm, 0x10,0x11 }, + { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00),0 }, + { AMOVWLSX, yml_rl, Pm, 0xbf }, + { AMOVWLZX, yml_rl, Pm, 0xb7 }, + { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf }, + { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 }, + { AMULB, ydivb, Pb, 0xf6,(04) }, + { AMULL, ydivl, Px, 0xf7,(04) }, + { AMULPD, yxm, Pe, 0x59 }, + { AMULPS, yxm, Ym, 0x59 }, + { AMULQ, ydivl, Pw, 0xf7,(04) }, + { AMULSD, yxm, Pf2, 0x59 }, + { AMULSS, yxm, Pf3, 0x59 }, + { AMULW, ydivl, Pe, 0xf7,(04) }, + { ANAME }, + { ANEGB, yscond, Pb, 0xf6,(03) }, + { ANEGL, yscond, Px, 0xf7,(03) }, + { ANEGQ, yscond, Pw, 0xf7,(03) }, + { ANEGW, yscond, Pe, 0xf7,(03) }, + { ANOP, ynop, Px, 0,0 }, + { ANOTB, yscond, Pb, 0xf6,(02) }, + { ANOTL, yscond, Px, 0xf7,(02) }, + { ANOTQ, yscond, Pw, 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 }, + { AORPD, yxm, Pq, 0x56 }, + { AORPS, yxm, Pm, 0x56 }, + { AORQ, yxorl, Pw, 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 }, + { AOUTSB, ynone, Pb, 0x6e }, + { AOUTSL, ynone, Px, 0x6f }, + { AOUTSW, ynone, Pe, 0x6f }, + { AOUTW, yin, Pe, 0xe7,0xef }, + { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b }, + { APACKSSWB, ymm, Py, 0x63,Pe,0x63 }, + { APACKUSWB, ymm, Py, 0x67,Pe,0x67 }, + { APADDB, ymm, Py, 0xfc,Pe,0xfc }, + { APADDL, ymm, Py, 0xfe,Pe,0xfe }, + { APADDQ, yxm, Pe, 0xd4 }, + { APADDSB, ymm, Py, 0xec,Pe,0xec }, + { APADDSW, ymm, Py, 0xed,Pe,0xed }, + { APADDUSB, ymm, Py, 0xdc,Pe,0xdc }, + { APADDUSW, ymm, Py, 0xdd,Pe,0xdd }, + { APADDW, ymm, Py, 0xfd,Pe,0xfd }, + { APAND, ymm, Py, 0xdb,Pe,0xdb }, + { APANDN, ymm, Py, 0xdf,Pe,0xdf }, + { APAUSE, ynone, Px, 0xf3,0x90 }, + { APAVGB, ymm, Py, 0xe0,Pe,0xe0 }, + { APAVGW, ymm, Py, 0xe3,Pe,0xe3 }, + { APCMPEQB, ymm, Py, 0x74,Pe,0x74 }, + { APCMPEQL, ymm, Py, 0x76,Pe,0x76 }, + { APCMPEQW, ymm, Py, 0x75,Pe,0x75 }, + { APCMPGTB, ymm, Py, 0x64,Pe,0x64 }, + { APCMPGTL, ymm, Py, 0x66,Pe,0x66 }, + { APCMPGTW, ymm, Py, 0x65,Pe,0x65 }, + { APEXTRW, yextrw, Pq, 0xc5,(00) }, + { APF2IL, ymfp, Px, 0x1d }, + { APF2IW, ymfp, Px, 0x1c }, + { API2FL, ymfp, Px, 0x0d }, + { APFACC, ymfp, Px, 0xae }, + { APFADD, ymfp, Px, 0x9e }, + { APFCMPEQ, ymfp, Px, 0xb0 }, + { APFCMPGE, ymfp, Px, 0x90 }, + { APFCMPGT, ymfp, Px, 0xa0 }, + { APFMAX, ymfp, Px, 0xa4 }, + { APFMIN, ymfp, Px, 0x94 }, + { APFMUL, ymfp, Px, 0xb4 }, + { APFNACC, ymfp, Px, 0x8a }, + { APFPNACC, ymfp, Px, 0x8e }, + { APFRCP, ymfp, Px, 0x96 }, + { APFRCPIT1, ymfp, Px, 0xa6 }, + { APFRCPI2T, ymfp, Px, 0xb6 }, + { APFRSQIT1, ymfp, Px, 0xa7 }, + { APFRSQRT, ymfp, Px, 0x97 }, + { APFSUB, ymfp, Px, 0x9a }, + { APFSUBR, ymfp, Px, 0xaa }, + { APINSRW, yinsrw, Pq, 0xc4,(00) }, + { APINSRD, yinsr, Pq, 0x3a, 0x22, (00) }, + { APINSRQ, yinsr, Pq3, 0x3a, 0x22, (00) }, + { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 }, + { APMAXSW, yxm, Pe, 0xee }, + { APMAXUB, yxm, Pe, 0xde }, + { APMINSW, yxm, Pe, 0xea }, + { APMINUB, yxm, Pe, 0xda }, + { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 }, + { APMULHRW, ymfp, Px, 0xb7 }, + { APMULHUW, ymm, Py, 0xe4,Pe,0xe4 }, + { APMULHW, ymm, Py, 0xe5,Pe,0xe5 }, + { APMULLW, ymm, Py, 0xd5,Pe,0xd5 }, + { APMULULQ, ymm, Py, 0xf4,Pe,0xf4 }, + { APOPAL, ynone, P32, 0x61 }, + { APOPAW, ynone, Pe, 0x61 }, + { APOPFL, ynone, P32, 0x9d }, + { APOPFQ, ynone, Py, 0x9d }, + { APOPFW, ynone, Pe, 0x9d }, + { APOPL, ypopl, P32, 0x58,0x8f,(00) }, + { APOPQ, ypopl, Py, 0x58,0x8f,(00) }, + { APOPW, ypopl, Pe, 0x58,0x8f,(00) }, + { APOR, ymm, Py, 0xeb,Pe,0xeb }, + { APSADBW, yxm, Pq, 0xf6 }, + { APSHUFHW, yxshuf, Pf3, 0x70,(00) }, + { APSHUFL, yxshuf, Pq, 0x70,(00) }, + { APSHUFLW, yxshuf, Pf2, 0x70,(00) }, + { APSHUFW, ymshuf, Pm, 0x70,(00) }, + { APSHUFB, ymshufb,Pq, 0x38, 0x00 }, + { APSLLO, ypsdq, Pq, 0x73,(07) }, + { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) }, + { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06) }, + { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) }, + { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) }, + { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) }, + { APSRLO, ypsdq, Pq, 0x73,(03) }, + { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) }, + { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) }, + { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) }, + { APSUBB, yxm, Pe, 0xf8 }, + { APSUBL, yxm, Pe, 0xfa }, + { APSUBQ, yxm, Pe, 0xfb }, + { APSUBSB, yxm, Pe, 0xe8 }, + { APSUBSW, yxm, Pe, 0xe9 }, + { APSUBUSB, yxm, Pe, 0xd8 }, + { APSUBUSW, yxm, Pe, 0xd9 }, + { APSUBW, yxm, Pe, 0xf9 }, + { APSWAPL, ymfp, Px, 0xbb }, + { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 }, + { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a }, + { APUNPCKHQDQ, yxm, Pe, 0x6d }, + { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 }, + { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 }, + { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 }, + { APUNPCKLQDQ, yxm, Pe, 0x6c }, + { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 }, + { APUSHAL, ynone, P32, 0x60 }, + { APUSHAW, ynone, Pe, 0x60 }, + { APUSHFL, ynone, P32, 0x9c }, + { APUSHFQ, ynone, Py, 0x9c }, + { APUSHFW, ynone, Pe, 0x9c }, + { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 }, + { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 }, + { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 }, + { APXOR, ymm, Py, 0xef,Pe,0xef }, + { AQUAD, ybyte, Px, 8 }, + { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) }, + { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCPPS, yxm, Pm, 0x53 }, + { ARCPSS, yxm, Pf3, 0x53 }, + { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) }, + { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, + { ARCRQ, yshl, Pw, 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 }, + { ARETFW, yret, Pe, 0xcb,0xca }, + { ARETFL, yret, Px, 0xcb,0xca }, + { ARETFQ, yret, Pw, 0xcb,0xca }, + { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) }, + { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, + { AROLQ, yshl, Pw, 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) }, + { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ARSQRTPS, yxm, Pm, 0x52 }, + { ARSQRTSS, yxm, Pf3, 0x52 }, + { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */ + { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, + { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASALQ, yshl, Pw, 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) }, + { ASARQ, yshl, Pw, 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 }, + { ASBBQ, yxorl, Pw, 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 }, + { ASCASQ, ynone, Pw, 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) }, + { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, + { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASHLQ, yshl, Pw, 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) }, + { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASHUFPD, yxshuf, Pq, 0xc6,(00) }, + { ASHUFPS, yxshuf, Pm, 0xc6,(00) }, + { ASQRTPD, yxm, Pe, 0x51 }, + { ASQRTPS, yxm, Pm, 0x51 }, + { ASQRTSD, yxm, Pf2, 0x51 }, + { ASQRTSS, yxm, Pf3, 0x51 }, + { ASTC, ynone, Px, 0xf9 }, + { ASTD, ynone, Px, 0xfd }, + { ASTI, ynone, Px, 0xfb }, + { ASTMXCSR, ysvrs, Pm, 0xae,(03),0xae,(03) }, + { ASTOSB, ynone, Pb, 0xaa }, + { ASTOSL, ynone, Px, 0xab }, + { ASTOSQ, ynone, Pw, 0xab }, + { ASTOSW, ynone, Pe, 0xab }, + { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a }, + { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, + { ASUBPD, yxm, Pe, 0x5c }, + { ASUBPS, yxm, Pm, 0x5c }, + { ASUBQ, yaddl, Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, + { ASUBSD, yxm, Pf2, 0x5c }, + { ASUBSS, yxm, Pf3, 0x5c }, + { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, + { ASWAPGS, ynone, Pm, 0x01,0xf8 }, + { ASYSCALL, ynone, Px, 0x0f,0x05 }, /* fast syscall */ + { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 }, + { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 }, + { ATESTQ, ytestl, Pw, 0xa9,0xf7,(00),0x85,0x85 }, + { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 }, + { ATEXT, ytext, Px }, + { AUCOMISD, yxcmp, Pe, 0x2e }, + { AUCOMISS, yxcmp, Pm, 0x2e }, + { AUNPCKHPD, yxm, Pe, 0x15 }, + { AUNPCKHPS, yxm, Pm, 0x15 }, + { AUNPCKLPD, yxm, Pe, 0x14 }, + { AUNPCKLPS, yxm, Pm, 0x14 }, + { 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, yxchg, Px, 0x90,0x90,0x87,0x87 }, + { AXCHGQ, yxchg, Pw, 0x90,0x90,0x87,0x87 }, + { AXCHGW, yxchg, Pe, 0x90,0x90,0x87,0x87 }, + { AXLAT, ynone, Px, 0xd7 }, + { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 }, + { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, + { AXORPD, yxm, Pe, 0x57 }, + { AXORPS, yxm, Pm, 0x57 }, + { AXORQ, yxorl, Pw, 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 }, + + { ACMPXCHGB, yrb_mb, Pb, 0x0f,0xb0 }, + { ACMPXCHGL, yrl_ml, Px, 0x0f,0xb1 }, + { ACMPXCHGW, yrl_ml, Pe, 0x0f,0xb1 }, + { ACMPXCHGQ, yrl_ml, Pw, 0x0f,0xb1 }, + { ACMPXCHG8B, yscond, Pm, 0xc7,(01) }, + { AINVD, ynone, Pm, 0x08 }, + { AINVLPG, ymbs, Pm, 0x01,(07) }, + { ALFENCE, ynone, Pm, 0xae,0xe8 }, + { AMFENCE, ynone, Pm, 0xae,0xf0 }, + { AMOVNTIL, yrl_ml, Pm, 0xc3 }, + { AMOVNTIQ, yrl_ml, Pw, 0x0f,0xc3 }, + { ARDMSR, ynone, Pm, 0x32 }, + { ARDPMC, ynone, Pm, 0x33 }, + { ARDTSC, ynone, Pm, 0x31 }, + { ARSM, ynone, Pm, 0xaa }, + { ASFENCE, ynone, Pm, 0xae,0xf8 }, + { ASYSRET, ynone, Pm, 0x07 }, + { AWBINVD, ynone, Pm, 0x09 }, + { AWRMSR, ynone, Pm, 0x30 }, + + { AXADDB, yrb_mb, Pb, 0x0f,0xc0 }, + { AXADDL, yrl_ml, Px, 0x0f,0xc1 }, + { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 }, + { AXADDW, yrl_ml, Pe, 0x0f,0xc1 }, + + { ACRC32B, ycrc32l,Px, 0xf2,0x0f,0x38,0xf0,0 }, + { ACRC32Q, ycrc32l,Pw, 0xf2,0x0f,0x38,0xf1,0 }, + + { APREFETCHT0, yprefetch, Pm, 0x18,(01) }, + { APREFETCHT1, yprefetch, Pm, 0x18,(02) }, + { APREFETCHT2, yprefetch, Pm, 0x18,(03) }, + { APREFETCHNTA, yprefetch, Pm, 0x18,(00) }, + + { AMOVQL, yrl_ml, Px, 0x89 }, + + { AUNDEF, ynone, Px, 0x0f, 0x0b }, + + { AAESENC, yaes, Pq, 0x38,0xdc,(0) }, + { AAESENCLAST, yaes, Pq, 0x38,0xdd,(0) }, + { AAESDEC, yaes, Pq, 0x38,0xde,(0) }, + { AAESDECLAST, yaes, Pq, 0x38,0xdf,(0) }, + { AAESIMC, yaes, Pq, 0x38,0xdb,(0) }, + { AAESKEYGENASSIST, yaes2, Pq, 0x3a,0xdf,(0) }, + + { APSHUFD, yaes2, Pq, 0x70,(0) }, + { APCLMULQDQ, yxshuf, Pq, 0x3a,0x44,0 }, + + { AUSEFIELD, ynop, Px, 0,0 }, + { ATYPE }, + { AFUNCDATA, yfuncdata, Px, 0,0 }, + { APCDATA, ypcdata, Px, 0,0 }, + { ACHECKNIL }, + { AFATVARDEF }, + + { AEND }, + 0 +}; + +static Optab* opindex[ALAST+1]; +static vlong vaddr(Link*, Addr*, Reloc*); + +// single-instruction no-ops of various lengths. +// constructed by hand ctxt->and disassembled with gdb to verify. +// see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion. +static uchar nop[][16] = { + {0x90}, + {0x66, 0x90}, + {0x0F, 0x1F, 0x00}, + {0x0F, 0x1F, 0x40, 0x00}, + {0x0F, 0x1F, 0x44, 0x00, 0x00}, + {0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00}, + {0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00}, + {0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, +}; + +static void +fillnop(uchar *p, int n) +{ + int m; + + while(n > 0) { + m = n; + if(m > nelem(nop)) + m = nelem(nop); + memmove(p, nop[m-1], m); + p += m; + n -= m; + } +} + +static void instinit(void); + +void +span6(Link *ctxt, LSym *s) +{ + Prog *p, *q; + int32 c, v, loop; + uchar *bp; + int n, m, i; + + ctxt->cursym = s; + + if(s->p != nil) + return; + + if(ycover[0] == 0) + instinit(); + + for(p = ctxt->cursym->text; p != nil; p = p->link) { + n = 0; + if(p->to.type == D_BRANCH) + if(p->pcond == nil) + p->pcond = p; + if((q = p->pcond) != nil) + 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 = p->mode != 64? AADDL: AADDQ; + if(v < 0) { + p->as = p->mode != 64? ASUBL: ASUBQ; + v = -v; + p->from.offset = v; + } + if(v == 0) + p->as = ANOP; + } + } + + for(p = s->text; p != nil; p = p->link) { + p->back = 2; // use short branches first time through + if((q = p->pcond) != nil && (q->back & 2)) { + p->back |= 1; // backward jump + q->back |= 4; // loop head + } + + if(p->as == AADJSP) { + p->to.type = D_SP; + v = -p->from.offset; + p->from.offset = v; + p->as = p->mode != 64? AADDL: AADDQ; + if(v < 0) { + p->as = p->mode != 64? ASUBL: ASUBQ; + v = -v; + p->from.offset = v; + } + if(v == 0) + p->as = ANOP; + } + } + + n = 0; + do { + loop = 0; + memset(s->r, 0, s->nr*sizeof s->r[0]); + s->nr = 0; + s->np = 0; + c = 0; + for(p = s->text; p != nil; p = p->link) { + if((p->back & 4) && (c&(LoopAlign-1)) != 0) { + // pad with NOPs + v = -c&(LoopAlign-1); + if(v <= MaxLoopPad) { + symgrow(ctxt, s, c+v); + fillnop(s->p+c, v); + c += v; + } + } + + p->pc = c; + + // process forward jumps to p + for(q = p->comefrom; q != nil; q = q->forwd) { + v = p->pc - (q->pc + q->mark); + if(q->back & 2) { // short + if(v > 127) { + loop++; + q->back ^= 2; + } + if(q->as == AJCXZL) + s->p[q->pc+2] = v; + else + s->p[q->pc+1] = v; + } else { + bp = s->p + q->pc + q->mark - 4; + *bp++ = v; + *bp++ = v>>8; + *bp++ = v>>16; + *bp = v>>24; + } + } + p->comefrom = nil; + + asmins(ctxt, p); + p->pc = c; + m = ctxt->andptr-ctxt->and; + symgrow(ctxt, s, p->pc+m); + memmove(s->p+p->pc, ctxt->and, m); + p->mark = m; + c += m; + } + if(++n > 20) { + ctxt->diag("span must be looping"); + sysfatal("loop"); + } + } while(loop); + s->size = c; + + if(0 /* debug['a'] > 1 */) { + print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0); + for(i=0; i<s->np; i++) { + print(" %.2ux", s->p[i]); + if(i%16 == 15) + print("\n %.6ux", i+1); + } + if(i%16) + print("\n"); + + for(i=0; i<s->nr; i++) { + Reloc *r; + + r = &s->r[i]; + print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add); + } + } +} + +static void +instinit(void) +{ + int c, i; + + for(i=1; optab[i].as; i++) { + c = optab[i].as; + if(opindex[c] != nil) + sysfatal("phase error in optab: %d (%A)", i, c); + opindex[c] = &optab[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 + Ys32] = 1; + ycover[Yi1*Ymax + Ys32] = 1; + ycover[Yi8*Ymax + Ys32] = 1; + + ycover[Yi0*Ymax + Yi32] = 1; + ycover[Yi1*Ymax + Yi32] = 1; + ycover[Yi8*Ymax + Yi32] = 1; + ycover[Ys32*Ymax + Yi32] = 1; + + ycover[Yi0*Ymax + Yi64] = 1; + ycover[Yi1*Ymax + Yi64] = 1; + ycover[Yi8*Ymax + Yi64] = 1; + ycover[Ys32*Ymax + Yi64] = 1; + ycover[Yi32*Ymax + Yi64] = 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[Yrl*Ymax + Yrb] = 1; + + ycover[Ycl*Ymax + Ycx] = 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[Yrl*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; + + ycover[Yax*Ymax + Ymm] = 1; + ycover[Ycx*Ymax + Ymm] = 1; + ycover[Yrx*Ymax + Ymm] = 1; + ycover[Yrl*Ymax + Ymm] = 1; + ycover[Ym*Ymax + Ymm] = 1; + ycover[Ymr*Ymax + Ymm] = 1; + + ycover[Ym*Ymax + Yxm] = 1; + ycover[Yxr*Ymax + Yxm] = 1; + + for(i=0; i<D_NONE; i++) { + reg[i] = -1; + if(i >= D_AL && i <= D_R15B) { + reg[i] = (i-D_AL) & 7; + if(i >= D_SPB && i <= D_DIB) + regrex[i] = 0x40; + if(i >= D_R8B && i <= D_R15B) + regrex[i] = Rxr | Rxx | Rxb; + } + if(i >= D_AH && i<= D_BH) + reg[i] = 4 + ((i-D_AH) & 7); + if(i >= D_AX && i <= D_R15) { + reg[i] = (i-D_AX) & 7; + if(i >= D_R8) + regrex[i] = Rxr | Rxx | Rxb; + } + if(i >= D_F0 && i <= D_F0+7) + reg[i] = (i-D_F0) & 7; + if(i >= D_M0 && i <= D_M0+7) + reg[i] = (i-D_M0) & 7; + if(i >= D_X0 && i <= D_X0+15) { + reg[i] = (i-D_X0) & 7; + if(i >= D_X0+8) + regrex[i] = Rxr | Rxx | Rxb; + } + if(i >= D_CR+8 && i <= D_CR+15) + regrex[i] = Rxr; + } +} + +static int +prefixof(Addr *a) +{ + switch(a->type) { + case D_INDIR+D_CS: + return 0x2e; + case D_INDIR+D_DS: + return 0x3e; + case D_INDIR+D_ES: + return 0x26; + case D_INDIR+D_FS: + return 0x64; + case D_INDIR+D_GS: + return 0x65; + } + switch(a->index) { + case D_CS: + return 0x2e; + case D_DS: + return 0x3e; + case D_ES: + return 0x26; + case D_FS: + return 0x64; + case D_GS: + return 0x65; + } + return 0; +} + +static int +oclass(Link *ctxt, Addr *a) +{ + vlong v; + int32 l; + + 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: + if(ctxt->flag_shared) + return Yiauto; + else + return Yi32; /* TO DO: Yi64 */ + 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_SPB: +*/ + case D_BPB: + case D_SIB: + case D_DIB: + case D_R8B: + case D_R9B: + case D_R10B: + case D_R11B: + case D_R12B: + case D_R13B: + case D_R14B: + case D_R15B: + if(ctxt->asmode != 64) + return Yxxx; + case D_DL: + case D_BL: + case D_AH: + case D_CH: + case D_DH: + case D_BH: + return Yrb; + + case D_CL: + return Ycl; + + case D_CX: + return Ycx; + + case D_DX: + case D_BX: + return Yrx; + + case D_R8: /* not really Yrl */ + case D_R9: + case D_R10: + case D_R11: + case D_R12: + case D_R13: + case D_R14: + case D_R15: + if(ctxt->asmode != 64) + return Yxxx; + 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_M0+0: + case D_M0+1: + case D_M0+2: + case D_M0+3: + case D_M0+4: + case D_M0+5: + case D_M0+6: + case D_M0+7: + return Ymr; + + case D_X0+0: + case D_X0+1: + case D_X0+2: + case D_X0+3: + case D_X0+4: + case D_X0+5: + case D_X0+6: + case D_X0+7: + case D_X0+8: + case D_X0+9: + case D_X0+10: + case D_X0+11: + case D_X0+12: + case D_X0+13: + case D_X0+14: + case D_X0+15: + return Yxr; + + 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_CR+8: return Ycr8; + + 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 == nil) { + v = a->offset; + if(v == 0) + return Yi0; + if(v == 1) + return Yi1; + if(v >= -128 && v <= 127) + return Yi8; + l = v; + if((vlong)l == v) + return Ys32; /* can sign extend */ + if((v>>32) == 0) + return Yi32; /* unsigned */ + return Yi64; + } + return Yi32; /* TO DO: D_ADDR as Yi64 */ + + case D_BRANCH: + return Ybr; + } + return Yxxx; +} + +static void +asmidx(Link *ctxt, int scale, int index, int base) +{ + int i; + + switch(index) { + default: + goto bad; + + case D_NONE: + i = 4 << 3; + goto bas; + + case D_R8: + case D_R9: + case D_R10: + case D_R11: + case D_R12: + case D_R13: + case D_R14: + case D_R15: + if(ctxt->asmode != 64) + goto bad; + case D_AX: + case D_CX: + case D_DX: + case D_BX: + case D_BP: + case D_SI: + case D_DI: + i = reg[index] << 3; + break; + } + switch(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_R8: + case D_R9: + case D_R10: + case D_R11: + case D_R12: + case D_R13: + case D_R14: + case D_R15: + if(ctxt->asmode != 64) + goto bad; + 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; + } + *ctxt->andptr++ = i; + return; +bad: + ctxt->diag("asmidx: bad address %d/%d/%d", scale, index, base); + *ctxt->andptr++ = 0; + return; +} + +static void +put4(Link *ctxt, int32 v) +{ + ctxt->andptr[0] = v; + ctxt->andptr[1] = v>>8; + ctxt->andptr[2] = v>>16; + ctxt->andptr[3] = v>>24; + ctxt->andptr += 4; +} + +static void +relput4(Link *ctxt, Prog *p, Addr *a) +{ + vlong v; + Reloc rel, *r; + + v = vaddr(ctxt, a, &rel); + if(rel.siz != 0) { + if(rel.siz != 4) + ctxt->diag("bad reloc"); + r = addrel(ctxt->cursym); + *r = rel; + r->off = p->pc + ctxt->andptr - ctxt->and; + } + put4(ctxt, v); +} + +static void +put8(Link *ctxt, vlong v) +{ + ctxt->andptr[0] = v; + ctxt->andptr[1] = v>>8; + ctxt->andptr[2] = v>>16; + ctxt->andptr[3] = v>>24; + ctxt->andptr[4] = v>>32; + ctxt->andptr[5] = v>>40; + ctxt->andptr[6] = v>>48; + ctxt->andptr[7] = v>>56; + ctxt->andptr += 8; +} + +/* +static void +relput8(Prog *p, Addr *a) +{ + vlong v; + Reloc rel, *r; + + v = vaddr(ctxt, a, &rel); + if(rel.siz != 0) { + r = addrel(ctxt->cursym); + *r = rel; + r->siz = 8; + r->off = p->pc + ctxt->andptr - ctxt->and; + } + put8(ctxt, v); +} +*/ + +static vlong +vaddr(Link *ctxt, Addr *a, Reloc *r) +{ + int t; + vlong v; + LSym *s; + + if(r != nil) + memset(r, 0, sizeof *r); + + 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(r == nil) { + ctxt->diag("need reloc for %D", a); + sysfatal("reloc"); + } + r->siz = 4; // TODO: 8 for external symbols + r->off = -1; // caller must fill in + r->sym = s; + r->add = v; + v = 0; + if(ctxt->flag_shared) { + if(s->type == STLSBSS) { + r->xadd = r->add - r->siz; + r->type = D_TLS; + r->xsym = s; + } else + r->type = D_PCREL; + } else + r->type = D_ADDR; + } + return v; +} + +static void +asmandsz(Link *ctxt, Addr *a, int r, int rex, int m64) +{ + int32 v; + int t, scale; + Reloc rel; + + USED(m64); + rex &= (0x40 | Rxr); + v = a->offset; + t = a->type; + rel.siz = 0; + if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) { + if(t < D_INDIR) { + switch(t) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + if(ctxt->flag_shared) + goto bad; + t = D_NONE; + v = vaddr(ctxt, a, &rel); + break; + case D_AUTO: + case D_PARAM: + t = D_SP; + break; + } + } else + t -= D_INDIR; + ctxt->rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex; + if(t == D_NONE) { + *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(ctxt, a->scale, a->index, t); + goto putrelv; + } + if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) { + *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(ctxt, a->scale, a->index, t); + return; + } + if(v >= -128 && v < 128 && rel.siz == 0) { + *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3); + asmidx(ctxt, a->scale, a->index, t); + *ctxt->andptr++ = v; + return; + } + *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3); + asmidx(ctxt, a->scale, a->index, t); + goto putrelv; + } + if(t >= D_AL && t <= D_X0+15) { + if(v) + goto bad; + *ctxt->andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); + ctxt->rexflag |= (regrex[t] & (0x40 | Rxb)) | rex; + return; + } + + scale = a->scale; + if(t < D_INDIR) { + switch(a->type) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + t = D_NONE; + v = vaddr(ctxt, a, &rel); + break; + case D_AUTO: + case D_PARAM: + t = D_SP; + break; + } + scale = 1; + } else + t -= D_INDIR; + + ctxt->rexflag |= (regrex[t] & Rxb) | rex; + if(t == D_NONE || (D_CS <= t && t <= D_GS)) { + if(ctxt->flag_shared && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || ctxt->asmode != 64) { + *ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3); + goto putrelv; + } + /* temporary */ + *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */ + *ctxt->andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */ + goto putrelv; + } + if(t == D_SP || t == D_R12) { + if(v == 0) { + *ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); + asmidx(ctxt, scale, D_NONE, t); + return; + } + if(v >= -128 && v < 128) { + *ctxt->andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3); + asmidx(ctxt, scale, D_NONE, t); + *ctxt->andptr++ = v; + return; + } + *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + asmidx(ctxt, scale, D_NONE, t); + goto putrelv; + } + if(t >= D_AX && t <= D_R15) { + if(v == 0 && t != D_BP && t != D_R13) { + *ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); + return; + } + if(v >= -128 && v < 128) { + ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3); + ctxt->andptr[1] = v; + ctxt->andptr += 2; + return; + } + *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + goto putrelv; + } + goto bad; + +putrelv: + if(rel.siz != 0) { + Reloc *r; + + if(rel.siz != 4) { + ctxt->diag("bad rel"); + goto bad; + } + r = addrel(ctxt->cursym); + *r = rel; + r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and; + } else if(ctxt->iself && ctxt->linkmode == LinkExternal && a->type == D_INDIR+D_FS + && ctxt->headtype != Hopenbsd) { + Reloc *r; + LSym *s; + + r = addrel(ctxt->cursym); + r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and; + r->add = a->offset - ctxt->tlsoffset; + r->xadd = r->add; + r->siz = 4; + r->type = D_TLS; + s = linklookup(ctxt, "runtime.tlsgm", 0); + r->sym = s; + r->xsym = s; + v = 0; + } + + put4(ctxt, v); + return; + +bad: + ctxt->diag("asmand: bad address %D", a); + return; +} + +static void +asmand(Link *ctxt, Addr *a, Addr *ra) +{ + asmandsz(ctxt, a, reg[ra->type], regrex[ra->type], 0); +} + +static void +asmando(Link *ctxt, Addr *a, int o) +{ + asmandsz(ctxt, a, o, 0, 0); +} + +static void +bytereg(Addr *a, char *t) +{ + if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) { + a->type = D_AL + (a->type-D_AX); + *t = 0; + } +} + +#define E 0xff +static Movtab 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}, + {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0}, + {APUSHQ, 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}, + {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0}, + {APOPQ, 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, Ycr8, Yml, 3, 0x0f,0x20,8,0}, + {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0}, + {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0}, + {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0}, + {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0}, + {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,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}, + {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0}, + {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0}, + {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0}, + {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0}, + {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0}, + {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,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}, + {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0}, + {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0}, + {AMOVQ, 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}, + {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0}, + {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0}, + {AMOVQ, 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}, + {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0}, + {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0}, + {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0}, + {AMOVQ, 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}, + {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0}, + {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0}, + {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0}, + {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,0}, + 0 +}; + +static int +isax(Addr *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; +} + +static void +subreg(Prog *p, int from, int to) +{ + + if(0 /*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(0 /*debug['Q']*/) + print("%P\n", p); +} + +static int +mediaop(Link *ctxt, Optab *o, int op, int osize, int z) +{ + switch(op){ + case Pm: + case Pe: + case Pf2: + case Pf3: + if(osize != 1){ + if(op != Pm) + *ctxt->andptr++ = op; + *ctxt->andptr++ = Pm; + op = o->op[++z]; + break; + } + default: + if(ctxt->andptr == ctxt->and || ctxt->andptr[-1] != Pm) + *ctxt->andptr++ = Pm; + break; + } + *ctxt->andptr++ = op; + return z; +} + +static void +doasm(Link *ctxt, Prog *p) +{ + Optab *o; + Prog *q, pp; + uchar *t; + Movtab *mo; + int z, op, ft, tt, xo, l, pre; + vlong v; + Reloc rel, *r; + Addr *a; + + ctxt->curp = p; // TODO + + o = opindex[p->as]; + if(o == nil) { + ctxt->diag("asmins: missing op %P", p); + return; + } + + pre = prefixof(&p->from); + if(pre) + *ctxt->andptr++ = pre; + pre = prefixof(&p->to); + if(pre) + *ctxt->andptr++ = pre; + + if(p->ft == 0) + p->ft = oclass(ctxt, &p->from); + if(p->tt == 0) + p->tt = oclass(ctxt, &p->to); + + ft = p->ft * Ymax; + tt = p->tt * Ymax; + + t = o->ytab; + if(t == 0) { + ctxt->diag("asmins: noproto %P", p); + return; + } + xo = o->op[0] == 0x0f; + for(z=0; *t; z+=t[3]+xo,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 ctxt->and opcode escape */ + *ctxt->andptr++ = Pe; + *ctxt->andptr++ = Pm; + break; + case Pq3: /* 16 bit escape, Rex.w, ctxt->and opcode escape */ + *ctxt->andptr++ = Pe; + *ctxt->andptr++ = Pw; + *ctxt->andptr++ = Pm; + break; + + case Pf2: /* xmm opcode escape */ + case Pf3: + *ctxt->andptr++ = o->prefix; + *ctxt->andptr++ = Pm; + break; + + case Pm: /* opcode escape */ + *ctxt->andptr++ = Pm; + break; + + case Pe: /* 16 bit escape */ + *ctxt->andptr++ = Pe; + break; + + case Pw: /* 64-bit escape */ + if(p->mode != 64) + ctxt->diag("asmins: illegal 64: %P", p); + ctxt->rexflag |= Pw; + break; + + case Pb: /* botch */ + bytereg(&p->from, &p->ft); + bytereg(&p->to, &p->tt); + break; + + case P32: /* 32 bit but illegal if 64-bit mode */ + if(p->mode == 64) + ctxt->diag("asmins: illegal in 64-bit mode: %P", p); + break; + + case Py: /* 64-bit only, no prefix */ + if(p->mode != 64) + ctxt->diag("asmins: illegal in %d-bit mode: %P", p->mode, p); + break; + } + + if(z >= nelem(o->op)) + sysfatal("asmins bad table %P", p); + op = o->op[z]; + if(op == 0x0f) { + *ctxt->andptr++ = op; + op = o->op[++z]; + } + switch(t[2]) { + default: + ctxt->diag("asmins: unknown z %d %P", t[2], p); + return; + + case Zpseudo: + break; + + case Zlit: + for(; op = o->op[z]; z++) + *ctxt->andptr++ = op; + break; + + case Zlitm_r: + for(; op = o->op[z]; z++) + *ctxt->andptr++ = op; + asmand(ctxt, &p->from, &p->to); + break; + + case Zmb_r: + bytereg(&p->from, &p->ft); + /* fall through */ + case Zm_r: + *ctxt->andptr++ = op; + asmand(ctxt, &p->from, &p->to); + break; + case Zm2_r: + *ctxt->andptr++ = op; + *ctxt->andptr++ = o->op[z+1]; + asmand(ctxt, &p->from, &p->to); + break; + + case Zm_r_xm: + mediaop(ctxt, o, op, t[3], z); + asmand(ctxt, &p->from, &p->to); + break; + + case Zm_r_xm_nr: + ctxt->rexflag = 0; + mediaop(ctxt, o, op, t[3], z); + asmand(ctxt, &p->from, &p->to); + break; + + case Zm_r_i_xm: + mediaop(ctxt, o, op, t[3], z); + asmand(ctxt, &p->from, &p->to); + *ctxt->andptr++ = p->to.offset; + break; + + case Zm_r_3d: + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = 0x0f; + asmand(ctxt, &p->from, &p->to); + *ctxt->andptr++ = op; + break; + + case Zibm_r: + while ((op = o->op[z++]) != 0) + *ctxt->andptr++ = op; + asmand(ctxt, &p->from, &p->to); + *ctxt->andptr++ = p->to.offset; + break; + + case Zaut_r: + *ctxt->andptr++ = 0x8d; /* leal */ + if(p->from.type != D_ADDR) + ctxt->diag("asmins: Zaut sb type ADDR"); + p->from.type = p->from.index; + p->from.index = D_NONE; + asmand(ctxt, &p->from, &p->to); + p->from.index = p->from.type; + p->from.type = D_ADDR; + break; + + case Zm_o: + *ctxt->andptr++ = op; + asmando(ctxt, &p->from, o->op[z+1]); + break; + + case Zr_m: + *ctxt->andptr++ = op; + asmand(ctxt, &p->to, &p->from); + break; + + case Zr_m_xm: + mediaop(ctxt, o, op, t[3], z); + asmand(ctxt, &p->to, &p->from); + break; + + case Zr_m_xm_nr: + ctxt->rexflag = 0; + mediaop(ctxt, o, op, t[3], z); + asmand(ctxt, &p->to, &p->from); + break; + + case Zr_m_i_xm: + mediaop(ctxt, o, op, t[3], z); + asmand(ctxt, &p->to, &p->from); + *ctxt->andptr++ = p->from.offset; + break; + + case Zo_m: + *ctxt->andptr++ = op; + asmando(ctxt, &p->to, o->op[z+1]); + break; + + case Zo_m64: + *ctxt->andptr++ = op; + asmandsz(ctxt, &p->to, o->op[z+1], 0, 1); + break; + + case Zm_ibo: + *ctxt->andptr++ = op; + asmando(ctxt, &p->from, o->op[z+1]); + *ctxt->andptr++ = vaddr(ctxt, &p->to, nil); + break; + + case Zibo_m: + *ctxt->andptr++ = op; + asmando(ctxt, &p->to, o->op[z+1]); + *ctxt->andptr++ = vaddr(ctxt, &p->from, nil); + break; + + case Zibo_m_xm: + z = mediaop(ctxt, o, op, t[3], z); + asmando(ctxt, &p->to, o->op[z+1]); + *ctxt->andptr++ = vaddr(ctxt, &p->from, nil); + break; + + case Z_ib: + case Zib_: + if(t[2] == Zib_) + a = &p->from; + else + a = &p->to; + *ctxt->andptr++ = op; + *ctxt->andptr++ = vaddr(ctxt, a, nil); + break; + + case Zib_rp: + ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40); + *ctxt->andptr++ = op + reg[p->to.type]; + *ctxt->andptr++ = vaddr(ctxt, &p->from, nil); + break; + + case Zil_rp: + ctxt->rexflag |= regrex[p->to.type] & Rxb; + *ctxt->andptr++ = op + reg[p->to.type]; + if(o->prefix == Pe) { + v = vaddr(ctxt, &p->from, nil); + *ctxt->andptr++ = v; + *ctxt->andptr++ = v>>8; + } + else + relput4(ctxt, p, &p->from); + break; + + case Zo_iw: + *ctxt->andptr++ = op; + if(p->from.type != D_NONE){ + v = vaddr(ctxt, &p->from, nil); + *ctxt->andptr++ = v; + *ctxt->andptr++ = v>>8; + } + break; + + case Ziq_rp: + v = vaddr(ctxt, &p->from, &rel); + l = v>>32; + if(l == 0 && rel.siz != 8){ + //p->mark |= 0100; + //print("zero: %llux %P\n", v, p); + ctxt->rexflag &= ~(0x40|Rxw); + ctxt->rexflag |= regrex[p->to.type] & Rxb; + *ctxt->andptr++ = 0xb8 + reg[p->to.type]; + if(rel.type != 0) { + r = addrel(ctxt->cursym); + *r = rel; + r->off = p->pc + ctxt->andptr - ctxt->and; + } + put4(ctxt, v); + }else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */ + //p->mark |= 0100; + //print("sign: %llux %P\n", v, p); + *ctxt->andptr ++ = 0xc7; + asmando(ctxt, &p->to, 0); + put4(ctxt, v); + }else{ /* need all 8 */ + //print("all: %llux %P\n", v, p); + ctxt->rexflag |= regrex[p->to.type] & Rxb; + *ctxt->andptr++ = op + reg[p->to.type]; + if(rel.type != 0) { + r = addrel(ctxt->cursym); + *r = rel; + r->off = p->pc + ctxt->andptr - ctxt->and; + } + put8(ctxt, v); + } + break; + + case Zib_rr: + *ctxt->andptr++ = op; + asmand(ctxt, &p->to, &p->to); + *ctxt->andptr++ = vaddr(ctxt, &p->from, nil); + break; + + case Z_il: + case Zil_: + if(t[2] == Zil_) + a = &p->from; + else + a = &p->to; + *ctxt->andptr++ = op; + if(o->prefix == Pe) { + v = vaddr(ctxt, a, nil); + *ctxt->andptr++ = v; + *ctxt->andptr++ = v>>8; + } + else + relput4(ctxt, p, a); + break; + + case Zm_ilo: + case Zilo_m: + *ctxt->andptr++ = op; + if(t[2] == Zilo_m) { + a = &p->from; + asmando(ctxt, &p->to, o->op[z+1]); + } else { + a = &p->to; + asmando(ctxt, &p->from, o->op[z+1]); + } + if(o->prefix == Pe) { + v = vaddr(ctxt, a, nil); + *ctxt->andptr++ = v; + *ctxt->andptr++ = v>>8; + } + else + relput4(ctxt, p, a); + break; + + case Zil_rr: + *ctxt->andptr++ = op; + asmand(ctxt, &p->to, &p->to); + if(o->prefix == Pe) { + v = vaddr(ctxt, &p->from, nil); + *ctxt->andptr++ = v; + *ctxt->andptr++ = v>>8; + } + else + relput4(ctxt, p, &p->from); + break; + + case Z_rp: + ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40); + *ctxt->andptr++ = op + reg[p->to.type]; + break; + + case Zrp_: + ctxt->rexflag |= regrex[p->from.type] & (Rxb|0x40); + *ctxt->andptr++ = op + reg[p->from.type]; + break; + + case Zclr: + *ctxt->andptr++ = op; + asmand(ctxt, &p->to, &p->to); + break; + + case Zcall: + if(p->to.sym == nil) { + ctxt->diag("call without target"); + sysfatal("bad code"); + } + *ctxt->andptr++ = op; + r = addrel(ctxt->cursym); + r->off = p->pc + ctxt->andptr - ctxt->and; + r->sym = p->to.sym; + r->type = D_PCREL; + r->siz = 4; + put4(ctxt, 0); + break; + + case Zbr: + case Zjmp: + case Zloop: + // TODO: jump across functions needs reloc + if(p->to.sym != nil) { + if(t[2] != Zjmp) { + ctxt->diag("branch to ATEXT"); + sysfatal("bad code"); + } + *ctxt->andptr++ = o->op[z+1]; + r = addrel(ctxt->cursym); + r->off = p->pc + ctxt->andptr - ctxt->and; + r->sym = p->to.sym; + r->type = D_PCREL; + r->siz = 4; + put4(ctxt, 0); + break; + } + // Assumes q is in this function. + // TODO: Check in input, preserve in brchain. + + // Fill in backward jump now. + q = p->pcond; + if(q == nil) { + ctxt->diag("jmp/branch/loop without target"); + sysfatal("bad code"); + } + if(p->back & 1) { + v = q->pc - (p->pc + 2); + if(v >= -128) { + if(p->as == AJCXZL) + *ctxt->andptr++ = 0x67; + *ctxt->andptr++ = op; + *ctxt->andptr++ = v; + } else if(t[2] == Zloop) { + ctxt->diag("loop too far: %P", p); + } else { + v -= 5-2; + if(t[2] == Zbr) { + *ctxt->andptr++ = 0x0f; + v--; + } + *ctxt->andptr++ = o->op[z+1]; + *ctxt->andptr++ = v; + *ctxt->andptr++ = v>>8; + *ctxt->andptr++ = v>>16; + *ctxt->andptr++ = v>>24; + } + break; + } + + // Annotate target; will fill in later. + p->forwd = q->comefrom; + q->comefrom = p; + if(p->back & 2) { // short + if(p->as == AJCXZL) + *ctxt->andptr++ = 0x67; + *ctxt->andptr++ = op; + *ctxt->andptr++ = 0; + } else if(t[2] == Zloop) { + ctxt->diag("loop too far: %P", p); + } else { + if(t[2] == Zbr) + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = o->op[z+1]; + *ctxt->andptr++ = 0; + *ctxt->andptr++ = 0; + *ctxt->andptr++ = 0; + *ctxt->andptr++ = 0; + } + break; + +/* + v = q->pc - p->pc - 2; + if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) { + *ctxt->andptr++ = op; + *ctxt->andptr++ = v; + } else { + v -= 5-2; + if(t[2] == Zbr) { + *ctxt->andptr++ = 0x0f; + v--; + } + *ctxt->andptr++ = o->op[z+1]; + *ctxt->andptr++ = v; + *ctxt->andptr++ = v>>8; + *ctxt->andptr++ = v>>16; + *ctxt->andptr++ = v>>24; + } +*/ + break; + + case Zbyte: + v = vaddr(ctxt, &p->from, &rel); + if(rel.siz != 0) { + rel.siz = op; + r = addrel(ctxt->cursym); + *r = rel; + r->off = p->pc + ctxt->andptr - ctxt->and; + } + *ctxt->andptr++ = v; + if(op > 1) { + *ctxt->andptr++ = v>>8; + if(op > 2) { + *ctxt->andptr++ = v>>16; + *ctxt->andptr++ = v>>24; + if(op > 4) { + *ctxt->andptr++ = v>>32; + *ctxt->andptr++ = v>>40; + *ctxt->andptr++ = v>>48; + *ctxt->andptr++ = v>>56; + } + } + } + break; + } + return; + +domov: + for(mo=ymovtab; mo->as; mo++) + if(p->as == mo->as) + if(ycover[ft+mo->ft]) + if(ycover[tt+mo->tt]){ + t = mo->op; + goto mfound; + } +bad: + if(p->mode != 64){ + /* + * here, the assembly has failed. + * if its a byte instruction that has + * unaddressable registers, try to + * exchange registers ctxt->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) || p->to.type == D_NONE) { + // We certainly don't want to exchange + // with AX if the op is MUL or DIV. + *ctxt->andptr++ = 0x87; /* xchg lhs,bx */ + asmando(ctxt, &p->from, reg[D_BX]); + subreg(&pp, z, D_BX); + doasm(ctxt, &pp); + *ctxt->andptr++ = 0x87; /* xchg lhs,bx */ + asmando(ctxt, &p->from, reg[D_BX]); + } else { + *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ + subreg(&pp, z, D_AX); + doasm(ctxt, &pp); + *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ + } + return; + } + z = p->to.type; + if(z >= D_BP && z <= D_DI) { + if(isax(&p->from)) { + *ctxt->andptr++ = 0x87; /* xchg rhs,bx */ + asmando(ctxt, &p->to, reg[D_BX]); + subreg(&pp, z, D_BX); + doasm(ctxt, &pp); + *ctxt->andptr++ = 0x87; /* xchg rhs,bx */ + asmando(ctxt, &p->to, reg[D_BX]); + } else { + *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ + subreg(&pp, z, D_AX); + doasm(ctxt, &pp); + *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ + } + return; + } + } + ctxt->diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p); + return; + +mfound: + switch(mo->code) { + default: + ctxt->diag("asmins: unknown mov %d %P", mo->code, p); + break; + + case 0: /* lit */ + for(z=0; t[z]!=E; z++) + *ctxt->andptr++ = t[z]; + break; + + case 1: /* r,m */ + *ctxt->andptr++ = t[0]; + asmando(ctxt, &p->to, t[1]); + break; + + case 2: /* m,r */ + *ctxt->andptr++ = t[0]; + asmando(ctxt, &p->from, t[1]); + break; + + case 3: /* r,m - 2op */ + *ctxt->andptr++ = t[0]; + *ctxt->andptr++ = t[1]; + asmando(ctxt, &p->to, t[2]); + ctxt->rexflag |= regrex[p->from.type] & (Rxr|0x40); + break; + + case 4: /* m,r - 2op */ + *ctxt->andptr++ = t[0]; + *ctxt->andptr++ = t[1]; + asmando(ctxt, &p->from, t[2]); + ctxt->rexflag |= regrex[p->to.type] & (Rxr|0x40); + break; + + case 5: /* load full pointer, trash heap */ + if(t[0]) + *ctxt->andptr++ = t[0]; + switch(p->to.index) { + default: + goto bad; + case D_DS: + *ctxt->andptr++ = 0xc5; + break; + case D_SS: + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = 0xb2; + break; + case D_ES: + *ctxt->andptr++ = 0xc4; + break; + case D_FS: + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = 0xb4; + break; + case D_GS: + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = 0xb5; + break; + } + asmand(ctxt, &p->from, &p->to); + break; + + case 6: /* double shift */ + if(t[0] == Pw){ + if(p->mode != 64) + ctxt->diag("asmins: illegal 64: %P", p); + ctxt->rexflag |= Pw; + t++; + }else if(t[0] == Pe){ + *ctxt->andptr++ = Pe; + t++; + } + z = p->from.type; + switch(z) { + default: + goto bad; + case D_CONST: + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = t[0]; + asmandsz(ctxt, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0); + *ctxt->andptr++ = p->from.offset; + break; + case D_CL: + case D_CX: + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = t[1]; + asmandsz(ctxt, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0); + break; + } + break; + } +} + +static void +asmins(Link *ctxt, Prog *p) +{ + int n, np, c; + Reloc *r; + + ctxt->rexflag = 0; + ctxt->andptr = ctxt->and; + ctxt->asmode = p->mode; + doasm(ctxt, p); + if(ctxt->rexflag){ + /* + * as befits the whole approach of the architecture, + * the rex prefix must appear before the first opcode byte + * (ctxt->and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but + * before the 0f opcode escape!), or it might be ignored. + * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'. + */ + if(p->mode != 64) + ctxt->diag("asmins: illegal in mode %d: %P", p->mode, p); + n = ctxt->andptr - ctxt->and; + for(np = 0; np < n; np++) { + c = ctxt->and[np]; + if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26) + break; + } + memmove(ctxt->and+np+1, ctxt->and+np, n-np); + ctxt->and[np] = 0x40 | ctxt->rexflag; + ctxt->andptr++; + } + n = ctxt->andptr - ctxt->and; + for(r=ctxt->cursym->r+ctxt->cursym->nr; r-- > ctxt->cursym->r; ) { + if(r->off < p->pc) + break; + if(ctxt->rexflag) + r->off++; + if(r->type == D_PCREL) + r->add -= p->pc + n - (r->off + r->siz); + } +} diff --git a/src/liblink/asm8.c b/src/liblink/asm8.c new file mode 100644 index 000000000..624627656 --- /dev/null +++ b/src/liblink/asm8.c @@ -0,0 +1,2571 @@ +// 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. + +// Instruction layout. + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> +#include "../cmd/8l/8.out.h" +#include "../pkg/runtime/stack.h" + +enum +{ + MaxAlign = 32, // max data alignment + FuncAlign = 16 +}; + +extern char *anames6[]; + +typedef struct Optab Optab; + +struct Optab +{ + short as; + uchar* ytab; + uchar prefix; + uchar op[13]; +}; + +enum +{ + 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, + Ymr, Ymm, + Yxr, Yxm, + Ymax, + + Zxxx = 0, + + Zlit, + Zlitm_r, + Z_rp, + Zbr, + Zcall, + Zcallcon, + Zcallind, + Zib_, + Zib_rp, + Zibo_m, + Zil_, + Zil_rp, + Zilo_m, + Zjmp, + Zjmpcon, + Zloop, + Zm_o, + Zm_r, + Zm2_r, + Zm_r_xm, + Zm_r_i_xm, + Zaut_r, + Zo_m, + Zpseudo, + Zr_m, + Zr_m_xm, + Zr_m_i_xm, + Zrp_, + Z_ib, + Z_il, + Zm_ibo, + Zm_ilo, + Zib_rr, + Zil_rr, + Zclr, + Zibm_r, /* mmx1,mmx2/mem64,imm8 */ + Zbyte, + Zmov, + Zmax, + + Px = 0, + Pe = 0x66, /* operand escape */ + Pm = 0x0f, /* 2byte opcode escape */ + Pq = 0xff, /* both escape */ + Pb = 0xfe, /* byte operands */ + Pf2 = 0xf2, /* xmm escape 1 */ + Pf3 = 0xf3, /* xmm escape 2 */ +}; + +static uchar ycover[Ymax*Ymax]; +static char reg[D_NONE]; +static void asmins(Link *ctxt, Prog *p); + +static uchar ynone[] = +{ + Ynone, Ynone, Zlit, 1, + 0 +}; +static uchar ytext[] = +{ + Ymb, Yi32, Zpseudo,1, + 0 +}; +static uchar ynop[] = +{ + Ynone, Ynone, Zpseudo,1, + Ynone, Yml, Zpseudo,1, + Ynone, Yrf, Zpseudo,1, + Yml, Ynone, Zpseudo,1, + Yrf, Ynone, Zpseudo,1, + 0 +}; +static uchar yfuncdata[] = +{ + Yi32, Ym, Zpseudo, 0, + 0 +}; +static uchar ypcdata[] = +{ + Yi32, Yi32, Zpseudo, 0, + 0, +}; +static uchar yxorb[] = +{ + Yi32, Yal, Zib_, 1, + Yi32, Ymb, Zibo_m, 2, + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +static 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 +}; +static 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 +}; +static uchar yincb[] = +{ + Ynone, Ymb, Zo_m, 2, + 0 +}; +static uchar yincl[] = +{ + Ynone, Yrl, Z_rp, 1, + Ynone, Yml, Zo_m, 2, + 0 +}; +static uchar ycmpb[] = +{ + Yal, Yi32, Z_ib, 1, + Ymb, Yi32, Zm_ibo, 2, + Ymb, Yrb, Zm_r, 1, + Yrb, Ymb, Zr_m, 1, + 0 +}; +static 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 +}; +static uchar yshb[] = +{ + Yi1, Ymb, Zo_m, 2, + Yi32, Ymb, Zibo_m, 2, + Ycx, Ymb, Zo_m, 2, + 0 +}; +static uchar yshl[] = +{ + Yi1, Yml, Zo_m, 2, + Yi32, Yml, Zibo_m, 2, + Ycl, Yml, Zo_m, 2, + Ycx, Yml, Zo_m, 2, + 0 +}; +static uchar ytestb[] = +{ + Yi32, Yal, Zib_, 1, + Yi32, Ymb, Zibo_m, 2, + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +static uchar ytestl[] = +{ + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +static uchar ymovb[] = +{ + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + Yi32, Yrb, Zib_rp, 1, + Yi32, Ymb, Zibo_m, 2, + 0 +}; +static uchar ymovw[] = +{ + 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, 1, + 0 +}; +static 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, + Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit) + Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit) + Yiauto, Yrl, Zaut_r, 1, + 0 +}; +static uchar ymovq[] = +{ + Yml, Yxr, Zm_r_xm, 2, + 0 +}; +static uchar ym_rl[] = +{ + Ym, Yrl, Zm_r, 1, + 0 +}; +static uchar yrl_m[] = +{ + Yrl, Ym, Zr_m, 1, + 0 +}; +static uchar ymb_rl[] = +{ + Ymb, Yrl, Zm_r, 1, + 0 +}; +static uchar yml_rl[] = +{ + Yml, Yrl, Zm_r, 1, + 0 +}; +static uchar yrb_mb[] = +{ + Yrb, Ymb, Zr_m, 1, + 0 +}; +static uchar yrl_ml[] = +{ + Yrl, Yml, Zr_m, 1, + 0 +}; +static uchar yml_mb[] = +{ + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +static uchar yxchg[] = +{ + Yax, Yrl, Z_rp, 1, + Yrl, Yax, Zrp_, 1, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +static uchar ydivl[] = +{ + Yml, Ynone, Zm_o, 2, + 0 +}; +static uchar ydivb[] = +{ + Ymb, Ynone, Zm_o, 2, + 0 +}; +static uchar yimul[] = +{ + Yml, Ynone, Zm_o, 2, + Yi8, Yrl, Zib_rr, 1, + Yi32, Yrl, Zil_rr, 1, + 0 +}; +static uchar ybyte[] = +{ + Yi32, Ynone, Zbyte, 1, + 0 +}; +static uchar yin[] = +{ + Yi32, Ynone, Zib_, 1, + Ynone, Ynone, Zlit, 1, + 0 +}; +static uchar yint[] = +{ + Yi32, Ynone, Zib_, 1, + 0 +}; +static uchar ypushl[] = +{ + Yrl, Ynone, Zrp_, 1, + Ym, Ynone, Zm_o, 2, + Yi8, Ynone, Zib_, 1, + Yi32, Ynone, Zil_, 1, + 0 +}; +static uchar ypopl[] = +{ + Ynone, Yrl, Z_rp, 1, + Ynone, Ym, Zo_m, 2, + 0 +}; +static uchar ybswap[] = +{ + Ynone, Yrl, Z_rp, 1, + 0, +}; +static uchar yscond[] = +{ + Ynone, Ymb, Zo_m, 2, + 0 +}; +static uchar yjcond[] = +{ + Ynone, Ybr, Zbr, 0, + Yi0, Ybr, Zbr, 0, + Yi1, Ybr, Zbr, 1, + 0 +}; +static uchar yloop[] = +{ + Ynone, Ybr, Zloop, 1, + 0 +}; +static uchar ycall[] = +{ + Ynone, Yml, Zo_m, 0, + Yrx, Yrx, Zo_m, 2, + Ynone, Ycol, Zcallind, 2, + Ynone, Ybr, Zcall, 0, + Ynone, Yi32, Zcallcon, 1, + 0 +}; +static uchar yjmp[] = +{ + Ynone, Yml, Zo_m, 2, + Ynone, Ybr, Zjmp, 0, + Ynone, Yi32, Zjmpcon, 1, + 0 +}; + +static uchar yfmvd[] = +{ + Ym, Yf0, Zm_o, 2, + Yf0, Ym, Zo_m, 2, + Yrf, Yf0, Zm_o, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +static uchar yfmvdp[] = +{ + Yf0, Ym, Zo_m, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +static uchar yfmvf[] = +{ + Ym, Yf0, Zm_o, 2, + Yf0, Ym, Zo_m, 2, + 0 +}; +static uchar yfmvx[] = +{ + Ym, Yf0, Zm_o, 2, + 0 +}; +static uchar yfmvp[] = +{ + Yf0, Ym, Zo_m, 2, + 0 +}; +static uchar yfcmv[] = +{ + Yrf, Yf0, Zm_o, 2, + 0 +}; +static uchar yfadd[] = +{ + Ym, Yf0, Zm_o, 2, + Yrf, Yf0, Zm_o, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +static uchar yfaddp[] = +{ + Yf0, Yrf, Zo_m, 2, + 0 +}; +static uchar yfxch[] = +{ + Yf0, Yrf, Zo_m, 2, + Yrf, Yf0, Zm_o, 2, + 0 +}; +static uchar ycompp[] = +{ + Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */ + 0 +}; +static uchar ystsw[] = +{ + Ynone, Ym, Zo_m, 2, + Ynone, Yax, Zlit, 1, + 0 +}; +static uchar ystcw[] = +{ + Ynone, Ym, Zo_m, 2, + Ym, Ynone, Zm_o, 2, + 0 +}; +static uchar ysvrs[] = +{ + Ynone, Ym, Zo_m, 2, + Ym, Ynone, Zm_o, 2, + 0 +}; +static uchar ymskb[] = +{ + Yxr, Yrl, Zm_r_xm, 2, + Ymr, Yrl, Zm_r_xm, 1, + 0 +}; +static uchar yxm[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +static uchar yxcvm1[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + Yxm, Ymr, Zm_r_xm, 2, + 0 +}; +static uchar yxcvm2[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + Ymm, Yxr, Zm_r_xm, 2, + 0 +}; +static uchar yxmq[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + 0 +}; +static uchar yxr[] = +{ + Yxr, Yxr, Zm_r_xm, 1, + 0 +}; +static uchar yxr_ml[] = +{ + Yxr, Yml, Zr_m_xm, 1, + 0 +}; +static uchar yxcmp[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +static uchar yxcmpi[] = +{ + Yxm, Yxr, Zm_r_i_xm, 2, + 0 +}; +static uchar yxmov[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + Yxr, Yxm, Zr_m_xm, 1, + 0 +}; +static uchar yxcvfl[] = +{ + Yxm, Yrl, Zm_r_xm, 1, + 0 +}; +static uchar yxcvlf[] = +{ + Yml, Yxr, Zm_r_xm, 1, + 0 +}; +/* +static uchar yxcvfq[] = +{ + Yxm, Yrl, Zm_r_xm, 2, + 0 +}; +static uchar yxcvqf[] = +{ + Yml, Yxr, Zm_r_xm, 2, + 0 +}; +*/ +static uchar yxrrl[] = +{ + Yxr, Yrl, Zm_r, 1, + 0 +}; +static uchar yprefetch[] = +{ + Ym, Ynone, Zm_o, 2, + 0, +}; +static uchar yaes[] = +{ + Yxm, Yxr, Zlitm_r, 2, + 0 +}; +static uchar yinsrd[] = +{ + Yml, Yxr, Zibm_r, 2, + 0 +}; +static uchar ymshufb[] = +{ + Yxm, Yxr, Zm2_r, 2, + 0 +}; + +static 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),0xff,(0x15),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 }, + { AJCXZL, yloop, Px, 0xe3 }, + { AJCXZW, 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),Pe,0x6e,Pe,0x7e,0 }, + { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),0 }, + { AMOVQ, ymovq, Pf3, 0x7e }, + { 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 }, + { APAUSE, ynone, Px, 0xf3,0x90 }, + { 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, yxchg, Px, 0x90,0x90,0x87,0x87 }, + { AXCHGW, yxchg, Pe, 0x90,0x90,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) }, + { AFCOMI, yfmvx, Px, 0xdb,(06) }, + { AFCOMIP, yfmvx, Px, 0xdf,(06) }, + { 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) }, + { AFUCOMI, ycompp, Px, 0xdb,(05) }, + { AFUCOMIP, ycompp, Px, 0xdf,(05) }, + { 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 }, + { ADYNT_ }, + { AINIT_ }, + { ASIGNAME }, + { ACMPXCHGB, yrb_mb, Pm, 0xb0 }, + { ACMPXCHGL, yrl_ml, Pm, 0xb1 }, + { ACMPXCHGW, yrl_ml, Pm, 0xb1 }, + { ACMPXCHG8B, yscond, Pm, 0xc7,(01) }, + + { ACPUID, ynone, Pm, 0xa2 }, + { ARDTSC, ynone, Pm, 0x31 }, + + { AXADDB, yrb_mb, Pb, 0x0f,0xc0 }, + { AXADDL, yrl_ml, Pm, 0xc1 }, + { AXADDW, yrl_ml, Pe, 0x0f,0xc1 }, + + { ACMOVLCC, yml_rl, Pm, 0x43 }, + { ACMOVLCS, yml_rl, Pm, 0x42 }, + { ACMOVLEQ, yml_rl, Pm, 0x44 }, + { ACMOVLGE, yml_rl, Pm, 0x4d }, + { ACMOVLGT, yml_rl, Pm, 0x4f }, + { ACMOVLHI, yml_rl, Pm, 0x47 }, + { ACMOVLLE, yml_rl, Pm, 0x4e }, + { ACMOVLLS, yml_rl, Pm, 0x46 }, + { ACMOVLLT, yml_rl, Pm, 0x4c }, + { ACMOVLMI, yml_rl, Pm, 0x48 }, + { ACMOVLNE, yml_rl, Pm, 0x45 }, + { ACMOVLOC, yml_rl, Pm, 0x41 }, + { ACMOVLOS, yml_rl, Pm, 0x40 }, + { ACMOVLPC, yml_rl, Pm, 0x4b }, + { ACMOVLPL, yml_rl, Pm, 0x49 }, + { ACMOVLPS, yml_rl, Pm, 0x4a }, + { ACMOVWCC, yml_rl, Pq, 0x43 }, + { ACMOVWCS, yml_rl, Pq, 0x42 }, + { ACMOVWEQ, yml_rl, Pq, 0x44 }, + { ACMOVWGE, yml_rl, Pq, 0x4d }, + { ACMOVWGT, yml_rl, Pq, 0x4f }, + { ACMOVWHI, yml_rl, Pq, 0x47 }, + { ACMOVWLE, yml_rl, Pq, 0x4e }, + { ACMOVWLS, yml_rl, Pq, 0x46 }, + { ACMOVWLT, yml_rl, Pq, 0x4c }, + { ACMOVWMI, yml_rl, Pq, 0x48 }, + { ACMOVWNE, yml_rl, Pq, 0x45 }, + { ACMOVWOC, yml_rl, Pq, 0x41 }, + { ACMOVWOS, yml_rl, Pq, 0x40 }, + { ACMOVWPC, yml_rl, Pq, 0x4b }, + { ACMOVWPL, yml_rl, Pq, 0x49 }, + { ACMOVWPS, yml_rl, Pq, 0x4a }, + + { AFCMOVCC, yfcmv, Px, 0xdb,(00) }, + { AFCMOVCS, yfcmv, Px, 0xda,(00) }, + { AFCMOVEQ, yfcmv, Px, 0xda,(01) }, + { AFCMOVHI, yfcmv, Px, 0xdb,(02) }, + { AFCMOVLS, yfcmv, Px, 0xda,(02) }, + { AFCMOVNE, yfcmv, Px, 0xdb,(01) }, + { AFCMOVNU, yfcmv, Px, 0xdb,(03) }, + { AFCMOVUN, yfcmv, Px, 0xda,(03) }, + + { ALFENCE, ynone, Pm, 0xae,0xe8 }, + { AMFENCE, ynone, Pm, 0xae,0xf0 }, + { ASFENCE, ynone, Pm, 0xae,0xf8 }, + + { AEMMS, ynone, Pm, 0x77 }, + + { APREFETCHT0, yprefetch, Pm, 0x18,(01) }, + { APREFETCHT1, yprefetch, Pm, 0x18,(02) }, + { APREFETCHT2, yprefetch, Pm, 0x18,(03) }, + { APREFETCHNTA, yprefetch, Pm, 0x18,(00) }, + + { ABSWAPL, ybswap, Pm, 0xc8 }, + + { AUNDEF, ynone, Px, 0x0f, 0x0b }, + + { AADDPD, yxm, Pq, 0x58 }, + { AADDPS, yxm, Pm, 0x58 }, + { AADDSD, yxm, Pf2, 0x58 }, + { AADDSS, yxm, Pf3, 0x58 }, + { AANDNPD, yxm, Pq, 0x55 }, + { AANDNPS, yxm, Pm, 0x55 }, + { AANDPD, yxm, Pq, 0x54 }, + { AANDPS, yxm, Pq, 0x54 }, + { ACMPPD, yxcmpi, Px, Pe,0xc2 }, + { ACMPPS, yxcmpi, Pm, 0xc2,0 }, + { ACMPSD, yxcmpi, Px, Pf2,0xc2 }, + { ACMPSS, yxcmpi, Px, Pf3,0xc2 }, + { ACOMISD, yxcmp, Pe, 0x2f }, + { ACOMISS, yxcmp, Pm, 0x2f }, + { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a }, + { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, }, + { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d }, + { ACVTPD2PS, yxm, Pe, 0x5a }, + { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d }, + { ACVTPS2PD, yxm, Pm, 0x5a }, + { ACVTSD2SL, yxcvfl, Pf2, 0x2d }, + { ACVTSD2SS, yxm, Pf2, 0x5a }, + { ACVTSL2SD, yxcvlf, Pf2, 0x2a }, + { ACVTSL2SS, yxcvlf, Pf3, 0x2a }, + { ACVTSS2SD, yxm, Pf3, 0x5a }, + { ACVTSS2SL, yxcvfl, Pf3, 0x2d }, + { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c }, + { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c }, + { ACVTTSD2SL, yxcvfl, Pf2, 0x2c }, + { ACVTTSS2SL, yxcvfl, Pf3, 0x2c }, + { ADIVPD, yxm, Pe, 0x5e }, + { ADIVPS, yxm, Pm, 0x5e }, + { ADIVSD, yxm, Pf2, 0x5e }, + { ADIVSS, yxm, Pf3, 0x5e }, + { AMASKMOVOU, yxr, Pe, 0xf7 }, + { AMAXPD, yxm, Pe, 0x5f }, + { AMAXPS, yxm, Pm, 0x5f }, + { AMAXSD, yxm, Pf2, 0x5f }, + { AMAXSS, yxm, Pf3, 0x5f }, + { AMINPD, yxm, Pe, 0x5d }, + { AMINPS, yxm, Pm, 0x5d }, + { AMINSD, yxm, Pf2, 0x5d }, + { AMINSS, yxm, Pf3, 0x5d }, + { AMOVAPD, yxmov, Pe, 0x28,0x29 }, + { AMOVAPS, yxmov, Pm, 0x28,0x29 }, + { AMOVO, yxmov, Pe, 0x6f,0x7f }, + { AMOVOU, yxmov, Pf3, 0x6f,0x7f }, + { AMOVHLPS, yxr, Pm, 0x12 }, + { AMOVHPD, yxmov, Pe, 0x16,0x17 }, + { AMOVHPS, yxmov, Pm, 0x16,0x17 }, + { AMOVLHPS, yxr, Pm, 0x16 }, + { AMOVLPD, yxmov, Pe, 0x12,0x13 }, + { AMOVLPS, yxmov, Pm, 0x12,0x13 }, + { AMOVMSKPD, yxrrl, Pq, 0x50 }, + { AMOVMSKPS, yxrrl, Pm, 0x50 }, + { AMOVNTO, yxr_ml, Pe, 0xe7 }, + { AMOVNTPD, yxr_ml, Pe, 0x2b }, + { AMOVNTPS, yxr_ml, Pm, 0x2b }, + { AMOVSD, yxmov, Pf2, 0x10,0x11 }, + { AMOVSS, yxmov, Pf3, 0x10,0x11 }, + { AMOVUPD, yxmov, Pe, 0x10,0x11 }, + { AMOVUPS, yxmov, Pm, 0x10,0x11 }, + { AMULPD, yxm, Pe, 0x59 }, + { AMULPS, yxm, Ym, 0x59 }, + { AMULSD, yxm, Pf2, 0x59 }, + { AMULSS, yxm, Pf3, 0x59 }, + { AORPD, yxm, Pq, 0x56 }, + { AORPS, yxm, Pm, 0x56 }, + { APADDQ, yxm, Pe, 0xd4 }, + { APAND, yxm, Pe, 0xdb }, + { APCMPEQB, yxmq, Pe ,0x74 }, + { APMAXSW, yxm, Pe, 0xee }, + { APMAXUB, yxm, Pe, 0xde }, + { APMINSW, yxm, Pe, 0xea }, + { APMINUB, yxm, Pe, 0xda }, + { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 }, + { APSADBW, yxm, Pq, 0xf6 }, + { APSUBB, yxm, Pe, 0xf8 }, + { APSUBL, yxm, Pe, 0xfa }, + { APSUBQ, yxm, Pe, 0xfb }, + { APSUBSB, yxm, Pe, 0xe8 }, + { APSUBSW, yxm, Pe, 0xe9 }, + { APSUBUSB, yxm, Pe, 0xd8 }, + { APSUBUSW, yxm, Pe, 0xd9 }, + { APSUBW, yxm, Pe, 0xf9 }, + { APUNPCKHQDQ, yxm, Pe, 0x6d }, + { APUNPCKLQDQ, yxm, Pe, 0x6c }, + { ARCPPS, yxm, Pm, 0x53 }, + { ARCPSS, yxm, Pf3, 0x53 }, + { ARSQRTPS, yxm, Pm, 0x52 }, + { ARSQRTSS, yxm, Pf3, 0x52 }, + { ASQRTPD, yxm, Pe, 0x51 }, + { ASQRTPS, yxm, Pm, 0x51 }, + { ASQRTSD, yxm, Pf2, 0x51 }, + { ASQRTSS, yxm, Pf3, 0x51 }, + { ASUBPD, yxm, Pe, 0x5c }, + { ASUBPS, yxm, Pm, 0x5c }, + { ASUBSD, yxm, Pf2, 0x5c }, + { ASUBSS, yxm, Pf3, 0x5c }, + { AUCOMISD, yxcmp, Pe, 0x2e }, + { AUCOMISS, yxcmp, Pm, 0x2e }, + { AUNPCKHPD, yxm, Pe, 0x15 }, + { AUNPCKHPS, yxm, Pm, 0x15 }, + { AUNPCKLPD, yxm, Pe, 0x14 }, + { AUNPCKLPS, yxm, Pm, 0x14 }, + { AXORPD, yxm, Pe, 0x57 }, + { AXORPS, yxm, Pm, 0x57 }, + + { AAESENC, yaes, Pq, 0x38,0xdc,(0) }, + { APINSRD, yinsrd, Pq, 0x3a, 0x22, (00) }, + { APSHUFB, ymshufb,Pq, 0x38, 0x00 }, + + { AUSEFIELD, ynop, Px, 0,0 }, + { ATYPE }, + { AFUNCDATA, yfuncdata, Px, 0,0 }, + { APCDATA, ypcdata, Px, 0,0 }, + { ACHECKNIL }, + { AFATVARDEF }, + + 0 +}; + +static int32 vaddr(Link*, Addr*, Reloc*); + +static void instinit(void); + +void +span8(Link *ctxt, LSym *s) +{ + Prog *p, *q; + int32 c, v, loop; + uchar *bp; + int n, m, i; + + ctxt->cursym = s; + + if(s->text == nil || s->text->link == nil) + return; + + if(ycover[0] == 0) + instinit(); + + for(p = s->text; p != nil; p = p->link) { + n = 0; + if(p->to.type == D_BRANCH) + if(p->pcond == nil) + p->pcond = p; + if((q = p->pcond) != nil) + 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; + } + } + + for(p = s->text; p != nil; p = p->link) { + p->back = 2; // use short branches first time through + if((q = p->pcond) != nil && (q->back & 2)) + p->back |= 1; // backward jump + + 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; + do { + loop = 0; + memset(s->r, 0, s->nr*sizeof s->r[0]); + s->nr = 0; + s->np = 0; + c = 0; + for(p = s->text; p != nil; p = p->link) { + p->pc = c; + + // process forward jumps to p + for(q = p->comefrom; q != nil; q = q->forwd) { + v = p->pc - (q->pc + q->mark); + if(q->back & 2) { // short + if(v > 127) { + loop++; + q->back ^= 2; + } + if(q->as == AJCXZW) + s->p[q->pc+2] = v; + else + s->p[q->pc+1] = v; + } else { + bp = s->p + q->pc + q->mark - 4; + *bp++ = v; + *bp++ = v>>8; + *bp++ = v>>16; + *bp = v>>24; + } + } + p->comefrom = nil; + + asmins(ctxt, p); + p->pc = c; + m = ctxt->andptr-ctxt->and; + symgrow(ctxt, s, p->pc+m); + memmove(s->p+p->pc, ctxt->and, m); + p->mark = m; + c += m; + } + if(++n > 20) { + ctxt->diag("span must be looping"); + sysfatal("bad code"); + } + } while(loop); + s->size = c; + + if(0 /* debug['a'] > 1 */) { + print("span1 %s %d (%d tries)\n %.6ux", s->name, s->size, n, 0); + for(i=0; i<s->np; i++) { + print(" %.2ux", s->p[i]); + if(i%16 == 15) + print("\n %.6ux", i+1); + } + if(i%16) + print("\n"); + + for(i=0; i<s->nr; i++) { + Reloc *r; + + r = &s->r[i]; + print(" rel %#.4ux/%d %s%+d\n", r->off, r->siz, r->sym->name, r->add); + } + } +} + +static void +instinit(void) +{ + int i; + + for(i=1; optab[i].as; i++) + if(i != optab[i].as) + sysfatal("phase error in optab: at %A found %A", i, optab[i].as); + + 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; + + ycover[Yax*Ymax + Ymm] = 1; + ycover[Ycx*Ymax + Ymm] = 1; + ycover[Yrx*Ymax + Ymm] = 1; + ycover[Yrl*Ymax + Ymm] = 1; + ycover[Ym*Ymax + Ymm] = 1; + ycover[Ymr*Ymax + Ymm] = 1; + + ycover[Ym*Ymax + Yxm] = 1; + ycover[Yxr*Ymax + Yxm] = 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; + if(i >= D_X0 && i <= D_X0+7) + reg[i] = (i-D_X0) & 7; + } +} + +static int +prefixof(Addr *a) +{ + switch(a->type) { + case D_INDIR+D_CS: + return 0x2e; + case D_INDIR+D_DS: + return 0x3e; + case D_INDIR+D_ES: + return 0x26; + case D_INDIR+D_FS: + return 0x64; + case D_INDIR+D_GS: + return 0x65; + } + return 0; +} + +static int +oclass(Addr *a) +{ + int32 v; + + if((a->type >= D_INDIR && a->type < 2*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; + } + //if(a->type == D_INDIR+D_ADDR) + // print("*Ycol\n"); + 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_X0+0: + case D_X0+1: + case D_X0+2: + case D_X0+3: + case D_X0+4: + case D_X0+5: + case D_X0+6: + case D_X0+7: + return Yxr; + + 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_CONST2: + case D_ADDR: + if(a->sym == nil) { + 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; +} + +static void +asmidx(Link *ctxt, int scale, int index, int base) +{ + int i; + + switch(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[index] << 3; + break; + } + switch(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; + } + *ctxt->andptr++ = i; + return; +bad: + ctxt->diag("asmidx: bad address %d,%d,%d", scale, index, base); + *ctxt->andptr++ = 0; + return; +} + +static void +put4(Link *ctxt, int32 v) +{ + ctxt->andptr[0] = v; + ctxt->andptr[1] = v>>8; + ctxt->andptr[2] = v>>16; + ctxt->andptr[3] = v>>24; + ctxt->andptr += 4; +} + +static void +relput4(Link *ctxt, Prog *p, Addr *a) +{ + vlong v; + Reloc rel, *r; + + v = vaddr(ctxt, a, &rel); + if(rel.siz != 0) { + if(rel.siz != 4) + ctxt->diag("bad reloc"); + r = addrel(ctxt->cursym); + *r = rel; + r->off = p->pc + ctxt->andptr - ctxt->and; + } + put4(ctxt, v); +} + +static int32 +vaddr(Link *ctxt, Addr *a, Reloc *r) +{ + int t; + int32 v; + LSym *s; + + if(r != nil) + memset(r, 0, sizeof *r); + + 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(r == nil) { + ctxt->diag("need reloc for %D", a); + sysfatal("bad code"); + } + r->type = D_ADDR; + r->siz = 4; + r->off = -1; + r->sym = s; + r->add = v; + v = 0; + } + } + return v; +} + +static int +istls(Link *ctxt, Addr *a) +{ + if(ctxt->headtype == Hlinux) + return a->index == D_GS; + return a->type == D_INDIR+D_GS; +} + +static void +asmand(Link *ctxt, Addr *a, int r) +{ + int32 v; + int t, scale; + Reloc rel; + + v = a->offset; + t = a->type; + rel.siz = 0; + if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) { + if(t < D_INDIR || t >= 2*D_INDIR) { + switch(t) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + t = D_NONE; + v = vaddr(ctxt, a, &rel); + break; + case D_AUTO: + case D_PARAM: + t = D_SP; + break; + } + } else + t -= D_INDIR; + + if(t == D_NONE) { + *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(ctxt, a->scale, a->index, t); + goto putrelv; + } + if(v == 0 && rel.siz == 0 && t != D_BP) { + *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(ctxt, a->scale, a->index, t); + return; + } + if(v >= -128 && v < 128 && rel.siz == 0) { + *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3); + asmidx(ctxt, a->scale, a->index, t); + *ctxt->andptr++ = v; + return; + } + *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3); + asmidx(ctxt, a->scale, a->index, t); + goto putrelv; + } + if(t >= D_AL && t <= D_F7 || t >= D_X0 && t <= D_X7) { + if(v) + goto bad; + *ctxt->andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); + return; + } + + scale = a->scale; + if(t < D_INDIR || t >= 2*D_INDIR) { + switch(a->type) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + t = D_NONE; + v = vaddr(ctxt, a, &rel); + break; + case D_AUTO: + case D_PARAM: + t = D_SP; + break; + } + scale = 1; + } else + t -= D_INDIR; + + if(t == D_NONE || (D_CS <= t && t <= D_GS)) { + *ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3); + goto putrelv; + } + if(t == D_SP) { + if(v == 0 && rel.siz == 0) { + *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(ctxt, scale, D_NONE, t); + return; + } + if(v >= -128 && v < 128 && rel.siz == 0) { + *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3); + asmidx(ctxt, scale, D_NONE, t); + *ctxt->andptr++ = v; + return; + } + *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3); + asmidx(ctxt, scale, D_NONE, t); + goto putrelv; + } + if(t >= D_AX && t <= D_DI) { + if(v == 0 && rel.siz == 0 && t != D_BP) { + *ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); + return; + } + if(v >= -128 && v < 128 && rel.siz == 0 && a->index != D_FS && a->index != D_GS) { + ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3); + ctxt->andptr[1] = v; + ctxt->andptr += 2; + return; + } + *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + goto putrelv; + } + goto bad; + +putrelv: + if(rel.siz != 0) { + Reloc *r; + + if(rel.siz != 4) { + ctxt->diag("bad rel"); + goto bad; + } + r = addrel(ctxt->cursym); + *r = rel; + r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and; + } else if(ctxt->iself && ctxt->linkmode == LinkExternal && istls(ctxt, a) && ctxt->headtype != Hopenbsd) { + Reloc *r; + LSym *s; + + r = addrel(ctxt->cursym); + r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and; + r->add = a->offset - ctxt->tlsoffset; + r->xadd = r->add; + r->siz = 4; + r->type = D_TLS; + s = linklookup(ctxt, "runtime.tlsgm", 0); + r->sym = s; + r->xsym = s; + v = 0; + } + + put4(ctxt, v); + return; + +bad: + ctxt->diag("asmand: bad address %D", a); + return; +} + +#define E 0xff +static 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 */ + AIMULW, Yml, Yrl, 7, Pq,0xaf,0,0, + AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0, + 0 +}; + +// byteswapreg returns a byte-addressable register (AX, BX, CX, DX) +// which is not referenced in a->type. +// If a is empty, it returns BX to account for MULB-like instructions +// that might use DX and AX. +static int +byteswapreg(Link *ctxt, Addr *a) +{ + int cana, canb, canc, cand; + + cana = canb = canc = cand = 1; + + switch(a->type) { + case D_NONE: + cana = cand = 0; + break; + case D_AX: + case D_AL: + case D_AH: + case D_INDIR+D_AX: + cana = 0; + break; + case D_BX: + case D_BL: + case D_BH: + case D_INDIR+D_BX: + canb = 0; + break; + case D_CX: + case D_CL: + case D_CH: + case D_INDIR+D_CX: + canc = 0; + break; + case D_DX: + case D_DL: + case D_DH: + case D_INDIR+D_DX: + cand = 0; + break; + } + switch(a->index) { + case D_AX: + cana = 0; + break; + case D_BX: + canb = 0; + break; + case D_CX: + canc = 0; + break; + case D_DX: + cand = 0; + break; + } + if(cana) + return D_AX; + if(canb) + return D_BX; + if(canc) + return D_CX; + if(cand) + return D_DX; + + ctxt->diag("impossible byte register"); + sysfatal("bad code"); + return 0; +} + +static void +subreg(Prog *p, int from, int to) +{ + + if(0 /* debug['Q'] */) + print("\n%P s/%R/%R/\n", p, from, to); + + if(p->from.type == from) { + p->from.type = to; + p->ft = 0; + } + if(p->to.type == from) { + p->to.type = to; + p->tt = 0; + } + + if(p->from.index == from) { + p->from.index = to; + p->ft = 0; + } + if(p->to.index == from) { + p->to.index = to; + p->tt = 0; + } + + from += D_INDIR; + if(p->from.type == from) { + p->from.type = to+D_INDIR; + p->ft = 0; + } + if(p->to.type == from) { + p->to.type = to+D_INDIR; + p->tt = 0; + } + + if(0 /* debug['Q'] */) + print("%P\n", p); +} + +static int +mediaop(Link *ctxt, Optab *o, int op, int osize, int z) +{ + switch(op){ + case Pm: + case Pe: + case Pf2: + case Pf3: + if(osize != 1){ + if(op != Pm) + *ctxt->andptr++ = op; + *ctxt->andptr++ = Pm; + op = o->op[++z]; + break; + } + default: + if(ctxt->andptr == ctxt->and || ctxt->andptr[-1] != Pm) + *ctxt->andptr++ = Pm; + break; + } + *ctxt->andptr++ = op; + return z; +} + +static void +doasm(Link *ctxt, Prog *p) +{ + Optab *o; + Prog *q, pp; + uchar *t; + int z, op, ft, tt, breg; + int32 v, pre; + Reloc rel, *r; + Addr *a; + + ctxt->curp = p; // TODO + + pre = prefixof(&p->from); + if(pre) + *ctxt->andptr++ = pre; + pre = prefixof(&p->to); + if(pre) + *ctxt->andptr++ = pre; + + if(p->ft == 0) + p->ft = oclass(&p->from); + if(p->tt == 0) + p->tt = oclass(&p->to); + + ft = p->ft * Ymax; + tt = p->tt * Ymax; + o = &optab[p->as]; + t = o->ytab; + if(t == 0) { + ctxt->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 */ + *ctxt->andptr++ = Pe; + *ctxt->andptr++ = Pm; + break; + + case Pf2: /* xmm opcode escape */ + case Pf3: + *ctxt->andptr++ = o->prefix; + *ctxt->andptr++ = Pm; + break; + + case Pm: /* opcode escape */ + *ctxt->andptr++ = Pm; + break; + + case Pe: /* 16 bit escape */ + *ctxt->andptr++ = Pe; + break; + + case Pb: /* botch */ + break; + } + + op = o->op[z]; + switch(t[2]) { + default: + ctxt->diag("asmins: unknown z %d %P", t[2], p); + return; + + case Zpseudo: + break; + + case Zlit: + for(; op = o->op[z]; z++) + *ctxt->andptr++ = op; + break; + + case Zlitm_r: + for(; op = o->op[z]; z++) + *ctxt->andptr++ = op; + asmand(ctxt, &p->from, reg[p->to.type]); + break; + + case Zm_r: + *ctxt->andptr++ = op; + asmand(ctxt, &p->from, reg[p->to.type]); + break; + + case Zm2_r: + *ctxt->andptr++ = op; + *ctxt->andptr++ = o->op[z+1]; + asmand(ctxt, &p->from, reg[p->to.type]); + break; + + case Zm_r_xm: + mediaop(ctxt, o, op, t[3], z); + asmand(ctxt, &p->from, reg[p->to.type]); + break; + + case Zm_r_i_xm: + mediaop(ctxt, o, op, t[3], z); + asmand(ctxt, &p->from, reg[p->to.type]); + *ctxt->andptr++ = p->to.offset; + break; + + case Zibm_r: + while ((op = o->op[z++]) != 0) + *ctxt->andptr++ = op; + asmand(ctxt, &p->from, reg[p->to.type]); + *ctxt->andptr++ = p->to.offset; + break; + + case Zaut_r: + *ctxt->andptr++ = 0x8d; /* leal */ + if(p->from.type != D_ADDR) + ctxt->diag("asmins: Zaut sb type ADDR"); + p->from.type = p->from.index; + p->from.index = D_NONE; + p->ft = 0; + asmand(ctxt, &p->from, reg[p->to.type]); + p->from.index = p->from.type; + p->from.type = D_ADDR; + p->ft = 0; + break; + + case Zm_o: + *ctxt->andptr++ = op; + asmand(ctxt, &p->from, o->op[z+1]); + break; + + case Zr_m: + *ctxt->andptr++ = op; + asmand(ctxt, &p->to, reg[p->from.type]); + break; + + case Zr_m_xm: + mediaop(ctxt, o, op, t[3], z); + asmand(ctxt, &p->to, reg[p->from.type]); + break; + + case Zr_m_i_xm: + mediaop(ctxt, o, op, t[3], z); + asmand(ctxt, &p->to, reg[p->from.type]); + *ctxt->andptr++ = p->from.offset; + break; + + case Zo_m: + *ctxt->andptr++ = op; + asmand(ctxt, &p->to, o->op[z+1]); + break; + + case Zm_ibo: + *ctxt->andptr++ = op; + asmand(ctxt, &p->from, o->op[z+1]); + *ctxt->andptr++ = vaddr(ctxt, &p->to, nil); + break; + + case Zibo_m: + *ctxt->andptr++ = op; + asmand(ctxt, &p->to, o->op[z+1]); + *ctxt->andptr++ = vaddr(ctxt, &p->from, nil); + break; + + case Z_ib: + case Zib_: + if(t[2] == Zib_) + a = &p->from; + else + a = &p->to; + v = vaddr(ctxt, a, nil); + *ctxt->andptr++ = op; + *ctxt->andptr++ = v; + break; + + case Zib_rp: + *ctxt->andptr++ = op + reg[p->to.type]; + *ctxt->andptr++ = vaddr(ctxt, &p->from, nil); + break; + + case Zil_rp: + *ctxt->andptr++ = op + reg[p->to.type]; + if(o->prefix == Pe) { + v = vaddr(ctxt, &p->from, nil); + *ctxt->andptr++ = v; + *ctxt->andptr++ = v>>8; + } + else + relput4(ctxt, p, &p->from); + break; + + case Zib_rr: + *ctxt->andptr++ = op; + asmand(ctxt, &p->to, reg[p->to.type]); + *ctxt->andptr++ = vaddr(ctxt, &p->from, nil); + break; + + case Z_il: + case Zil_: + if(t[2] == Zil_) + a = &p->from; + else + a = &p->to; + *ctxt->andptr++ = op; + if(o->prefix == Pe) { + v = vaddr(ctxt, a, nil); + *ctxt->andptr++ = v; + *ctxt->andptr++ = v>>8; + } + else + relput4(ctxt, p, a); + break; + + case Zm_ilo: + case Zilo_m: + *ctxt->andptr++ = op; + if(t[2] == Zilo_m) { + a = &p->from; + asmand(ctxt, &p->to, o->op[z+1]); + } else { + a = &p->to; + asmand(ctxt, &p->from, o->op[z+1]); + } + if(o->prefix == Pe) { + v = vaddr(ctxt, a, nil); + *ctxt->andptr++ = v; + *ctxt->andptr++ = v>>8; + } + else + relput4(ctxt, p, a); + break; + + case Zil_rr: + *ctxt->andptr++ = op; + asmand(ctxt, &p->to, reg[p->to.type]); + if(o->prefix == Pe) { + v = vaddr(ctxt, &p->from, nil); + *ctxt->andptr++ = v; + *ctxt->andptr++ = v>>8; + } + else + relput4(ctxt, p, &p->from); + break; + + case Z_rp: + *ctxt->andptr++ = op + reg[p->to.type]; + break; + + case Zrp_: + *ctxt->andptr++ = op + reg[p->from.type]; + break; + + case Zclr: + *ctxt->andptr++ = op; + asmand(ctxt, &p->to, reg[p->to.type]); + break; + + case Zcall: + if(p->to.sym == nil) { + ctxt->diag("call without target"); + sysfatal("bad code"); + } + *ctxt->andptr++ = op; + r = addrel(ctxt->cursym); + r->off = p->pc + ctxt->andptr - ctxt->and; + r->type = D_PCREL; + r->siz = 4; + r->sym = p->to.sym; + put4(ctxt, 0); + break; + + case Zbr: + case Zjmp: + case Zloop: + if(p->to.sym != nil) { + if(t[2] != Zjmp) { + ctxt->diag("branch to ATEXT"); + sysfatal("bad code"); + } + *ctxt->andptr++ = o->op[z+1]; + r = addrel(ctxt->cursym); + r->off = p->pc + ctxt->andptr - ctxt->and; + r->sym = p->to.sym; + r->type = D_PCREL; + r->siz = 4; + put4(ctxt, 0); + break; + } + + // Assumes q is in this function. + // Fill in backward jump now. + q = p->pcond; + if(q == nil) { + ctxt->diag("jmp/branch/loop without target"); + sysfatal("bad code"); + } + if(p->back & 1) { + v = q->pc - (p->pc + 2); + if(v >= -128) { + if(p->as == AJCXZW) + *ctxt->andptr++ = 0x67; + *ctxt->andptr++ = op; + *ctxt->andptr++ = v; + } else if(t[2] == Zloop) { + ctxt->diag("loop too far: %P", p); + } else { + v -= 5-2; + if(t[2] == Zbr) { + *ctxt->andptr++ = 0x0f; + v--; + } + *ctxt->andptr++ = o->op[z+1]; + *ctxt->andptr++ = v; + *ctxt->andptr++ = v>>8; + *ctxt->andptr++ = v>>16; + *ctxt->andptr++ = v>>24; + } + break; + } + + // Annotate target; will fill in later. + p->forwd = q->comefrom; + q->comefrom = p; + if(p->back & 2) { // short + if(p->as == AJCXZW) + *ctxt->andptr++ = 0x67; + *ctxt->andptr++ = op; + *ctxt->andptr++ = 0; + } else if(t[2] == Zloop) { + ctxt->diag("loop too far: %P", p); + } else { + if(t[2] == Zbr) + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = o->op[z+1]; + *ctxt->andptr++ = 0; + *ctxt->andptr++ = 0; + *ctxt->andptr++ = 0; + *ctxt->andptr++ = 0; + } + break; + + case Zcallcon: + case Zjmpcon: + if(t[2] == Zcallcon) + *ctxt->andptr++ = op; + else + *ctxt->andptr++ = o->op[z+1]; + r = addrel(ctxt->cursym); + r->off = p->pc + ctxt->andptr - ctxt->and; + r->type = D_PCREL; + r->siz = 4; + r->add = p->to.offset; + put4(ctxt, 0); + break; + + case Zcallind: + *ctxt->andptr++ = op; + *ctxt->andptr++ = o->op[z+1]; + r = addrel(ctxt->cursym); + r->off = p->pc + ctxt->andptr - ctxt->and; + r->type = D_ADDR; + r->siz = 4; + r->add = p->to.offset; + r->sym = p->to.sym; + put4(ctxt, 0); + break; + + case Zbyte: + v = vaddr(ctxt, &p->from, &rel); + if(rel.siz != 0) { + rel.siz = op; + r = addrel(ctxt->cursym); + *r = rel; + r->off = p->pc + ctxt->andptr - ctxt->and; + } + *ctxt->andptr++ = v; + if(op > 1) { + *ctxt->andptr++ = v>>8; + if(op > 2) { + *ctxt->andptr++ = v>>16; + *ctxt->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((breg = byteswapreg(ctxt, &p->to)) != D_AX) { + *ctxt->andptr++ = 0x87; /* xchg lhs,bx */ + asmand(ctxt, &p->from, reg[breg]); + subreg(&pp, z, breg); + doasm(ctxt, &pp); + *ctxt->andptr++ = 0x87; /* xchg lhs,bx */ + asmand(ctxt, &p->from, reg[breg]); + } else { + *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ + subreg(&pp, z, D_AX); + doasm(ctxt, &pp); + *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ + } + return; + } + z = p->to.type; + if(z >= D_BP && z <= D_DI) { + if((breg = byteswapreg(ctxt, &p->from)) != D_AX) { + *ctxt->andptr++ = 0x87; /* xchg rhs,bx */ + asmand(ctxt, &p->to, reg[breg]); + subreg(&pp, z, breg); + doasm(ctxt, &pp); + *ctxt->andptr++ = 0x87; /* xchg rhs,bx */ + asmand(ctxt, &p->to, reg[breg]); + } else { + *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ + subreg(&pp, z, D_AX); + doasm(ctxt, &pp); + *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ + } + return; + } + ctxt->diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p); + return; + +mfound: + switch(t[3]) { + default: + ctxt->diag("asmins: unknown mov %d %P", t[3], p); + break; + + case 0: /* lit */ + for(z=4; t[z]!=E; z++) + *ctxt->andptr++ = t[z]; + break; + + case 1: /* r,m */ + *ctxt->andptr++ = t[4]; + asmand(ctxt, &p->to, t[5]); + break; + + case 2: /* m,r */ + *ctxt->andptr++ = t[4]; + asmand(ctxt, &p->from, t[5]); + break; + + case 3: /* r,m - 2op */ + *ctxt->andptr++ = t[4]; + *ctxt->andptr++ = t[5]; + asmand(ctxt, &p->to, t[6]); + break; + + case 4: /* m,r - 2op */ + *ctxt->andptr++ = t[4]; + *ctxt->andptr++ = t[5]; + asmand(ctxt, &p->from, t[6]); + break; + + case 5: /* load full pointer, trash heap */ + if(t[4]) + *ctxt->andptr++ = t[4]; + switch(p->to.index) { + default: + goto bad; + case D_DS: + *ctxt->andptr++ = 0xc5; + break; + case D_SS: + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = 0xb2; + break; + case D_ES: + *ctxt->andptr++ = 0xc4; + break; + case D_FS: + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = 0xb4; + break; + case D_GS: + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = 0xb5; + break; + } + asmand(ctxt, &p->from, reg[p->to.type]); + break; + + case 6: /* double shift */ + z = p->from.type; + switch(z) { + default: + goto bad; + case D_CONST: + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = t[4]; + asmand(ctxt, &p->to, reg[p->from.index]); + *ctxt->andptr++ = p->from.offset; + break; + case D_CL: + case D_CX: + *ctxt->andptr++ = 0x0f; + *ctxt->andptr++ = t[5]; + asmand(ctxt, &p->to, reg[p->from.index]); + break; + } + break; + + case 7: /* imul rm,r */ + if(t[4] == Pq) { + *ctxt->andptr++ = Pe; + *ctxt->andptr++ = Pm; + } else + *ctxt->andptr++ = t[4]; + *ctxt->andptr++ = t[5]; + asmand(ctxt, &p->from, reg[p->to.type]); + break; + } +} + +static void +asmins(Link *ctxt, Prog *p) +{ + ctxt->andptr = ctxt->and; + doasm(ctxt, p); + if(ctxt->andptr > ctxt->and+sizeof ctxt->and) { + print("and[] is too short - %ld byte instruction\n", ctxt->andptr - ctxt->and); + sysfatal("bad code"); + } +} diff --git a/src/liblink/data.c b/src/liblink/data.c new file mode 100644 index 000000000..97d226041 --- /dev/null +++ b/src/liblink/data.c @@ -0,0 +1,366 @@ +// Derived from Inferno utils/6l/obj.c and utils/6l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/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 <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> + +void +mangle(char *file) +{ + sysfatal("%s: mangled input file", file); +} + +void +symgrow(Link *ctxt, LSym *s, int32 siz) +{ + USED(ctxt); + + if(s->np >= siz) + return; + + if(s->np > s->maxp) { + ctxt->cursym = s; + sysfatal("corrupt symbol data: np=%lld > maxp=%lld", (vlong)s->np, (vlong)s->maxp); + } + + if(s->maxp < siz) { + if(s->maxp == 0) + s->maxp = 8; + while(s->maxp < siz) + s->maxp <<= 1; + s->p = erealloc(s->p, s->maxp); + memset(s->p+s->np, 0, s->maxp-s->np); + } + s->np = siz; +} + +void +savedata(Link *ctxt, LSym *s, Prog *p, char *pn) +{ + int32 off, siz, i, fl; + float32 flt; + uchar *cast; + vlong o; + Reloc *r; + + off = p->from.offset; + siz = ctxt->arch->datasize(p); + if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100) + mangle(pn); + symgrow(ctxt, s, off+siz); + + if(p->to.type == ctxt->arch->D_FCONST) { + switch(siz) { + default: + case 4: + flt = p->to.u.dval; + cast = (uchar*)&flt; + for(i=0; i<4; i++) + s->p[off+i] = cast[fnuxi4[i]]; + break; + case 8: + cast = (uchar*)&p->to.u.dval; + for(i=0; i<8; i++) + s->p[off+i] = cast[fnuxi8[i]]; + break; + } + } else if(p->to.type == ctxt->arch->D_SCONST) { + for(i=0; i<siz; i++) + s->p[off+i] = p->to.u.sval[i]; + } else if(p->to.type == ctxt->arch->D_CONST) { + if(p->to.sym) + goto Addr; + o = p->to.offset; + fl = o; + cast = (uchar*)&fl; + switch(siz) { + default: + ctxt->diag("bad nuxi %d\n%P", siz, p); + break; + case 1: + s->p[off] = cast[inuxi1[0]]; + break; + case 2: + for(i=0; i<2; i++) + s->p[off+i] = cast[inuxi2[i]]; + break; + case 4: + for(i=0; i<4; i++) + s->p[off+i] = cast[inuxi4[i]]; + break; + case 8: + cast = (uchar*)&o; + for(i=0; i<8; i++) + s->p[off+i] = cast[inuxi8[i]]; + break; + } + } else if(p->to.type == ctxt->arch->D_ADDR || p->to.type == ctxt->arch->D_SIZE) { + Addr: + r = addrel(s); + r->off = off; + r->siz = siz; + r->sym = p->to.sym; + r->type = p->to.type; + if(r->type != ctxt->arch->D_SIZE) + r->type = ctxt->arch->D_ADDR; + r->add = p->to.offset; + } else { + ctxt->diag("bad data: %P", p); + } +} + +Reloc* +addrel(LSym *s) +{ + if(s->nr >= s->maxr) { + if(s->maxr == 0) + s->maxr = 4; + else + s->maxr <<= 1; + s->r = erealloc(s->r, s->maxr*sizeof s->r[0]); + memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]); + } + return &s->r[s->nr++]; +} + +vlong +setuintxx(Link *ctxt, LSym *s, vlong off, uint64 v, vlong wid) +{ + int32 i, fl; + vlong o; + uchar *cast; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + if(s->size < off+wid) { + s->size = off+wid; + symgrow(ctxt, s, s->size); + } + fl = v; + cast = (uchar*)&fl; + switch(wid) { + case 1: + s->p[off] = cast[inuxi1[0]]; + break; + case 2: + for(i=0; i<2; i++) + s->p[off+i] = cast[inuxi2[i]]; + break; + case 4: + for(i=0; i<4; i++) + s->p[off+i] = cast[inuxi4[i]]; + break; + case 8: + o = v; + cast = (uchar*)&o; + for(i=0; i<8; i++) + s->p[off+i] = cast[inuxi8[i]]; + break; + } + return off+wid; +} + +vlong +adduintxx(Link *ctxt, LSym *s, uint64 v, int wid) +{ + vlong off; + + off = s->size; + setuintxx(ctxt, s, off, v, wid); + return off; +} + +vlong +adduint8(Link *ctxt, LSym *s, uint8 v) +{ + return adduintxx(ctxt, s, v, 1); +} + +vlong +adduint16(Link *ctxt, LSym *s, uint16 v) +{ + return adduintxx(ctxt, s, v, 2); +} + +vlong +adduint32(Link *ctxt, LSym *s, uint32 v) +{ + return adduintxx(ctxt, s, v, 4); +} + +vlong +adduint64(Link *ctxt, LSym *s, uint64 v) +{ + return adduintxx(ctxt, s, v, 8); +} + +vlong +setuint8(Link *ctxt, LSym *s, vlong r, uint8 v) +{ + return setuintxx(ctxt, s, r, v, 1); +} + +vlong +setuint16(Link *ctxt, LSym *s, vlong r, uint16 v) +{ + return setuintxx(ctxt, s, r, v, 2); +} + +vlong +setuint32(Link *ctxt, LSym *s, vlong r, uint32 v) +{ + return setuintxx(ctxt, s, r, v, 4); +} + +vlong +setuint64(Link *ctxt, LSym *s, vlong r, uint64 v) +{ + return setuintxx(ctxt, s, r, v, 8); +} + +vlong +addaddrplus(Link *ctxt, LSym *s, LSym *t, vlong add) +{ + vlong i; + Reloc *r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + i = s->size; + s->size += ctxt->arch->ptrsize; + symgrow(ctxt, s, s->size); + r = addrel(s); + r->sym = t; + r->off = i; + r->siz = ctxt->arch->ptrsize; + r->type = ctxt->arch->D_ADDR; + r->add = add; + return i + r->siz; +} + +vlong +addpcrelplus(Link *ctxt, LSym *s, LSym *t, vlong add) +{ + vlong i; + Reloc *r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + i = s->size; + s->size += 4; + symgrow(ctxt, s, s->size); + r = addrel(s); + r->sym = t; + r->off = i; + r->add = add; + r->type = ctxt->arch->D_PCREL; + r->siz = 4; + return i + r->siz; +} + +vlong +addaddr(Link *ctxt, LSym *s, LSym *t) +{ + return addaddrplus(ctxt, s, t, 0); +} + +vlong +setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add) +{ + Reloc *r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + if(off+ctxt->arch->ptrsize > s->size) { + s->size = off + ctxt->arch->ptrsize; + symgrow(ctxt, s, s->size); + } + r = addrel(s); + r->sym = t; + r->off = off; + r->siz = ctxt->arch->ptrsize; + r->type = ctxt->arch->D_ADDR; + r->add = add; + return off + r->siz; +} + +vlong +setaddr(Link *ctxt, LSym *s, vlong off, LSym *t) +{ + return setaddrplus(ctxt, s, off, t, 0); +} + +vlong +addsize(Link *ctxt, LSym *s, LSym *t) +{ + vlong i; + Reloc *r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + i = s->size; + s->size += ctxt->arch->ptrsize; + symgrow(ctxt, s, s->size); + r = addrel(s); + r->sym = t; + r->off = i; + r->siz = ctxt->arch->ptrsize; + r->type = ctxt->arch->D_SIZE; + return i + r->siz; +} + +vlong +addaddrplus4(Link *ctxt, LSym *s, LSym *t, vlong add) +{ + vlong i; + Reloc *r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + i = s->size; + s->size += 4; + symgrow(ctxt, s, s->size); + r = addrel(s); + r->sym = t; + r->off = i; + r->siz = 4; + r->type = ctxt->arch->D_ADDR; + r->add = add; + return i + r->siz; +} diff --git a/src/liblink/go.c b/src/liblink/go.c new file mode 100644 index 000000000..9f5a423d3 --- /dev/null +++ b/src/liblink/go.c @@ -0,0 +1,74 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// go-specific code shared across loaders (5l, 6l, 8l). + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> + +// replace all "". with pkg. +char* +expandpkg(char *t0, char *pkg) +{ + int n; + char *p; + char *w, *w0, *t; + + n = 0; + for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3) + n++; + + if(n == 0) + return estrdup(t0); + + w0 = emallocz(strlen(t0) + strlen(pkg)*n); + w = w0; + for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) { + memmove(w, t, p - t); + w += p-t; + strcpy(w, pkg); + w += strlen(pkg); + t = p+2; + } + strcpy(w, t); + return w0; +} + +void* +emallocz(long n) +{ + void *p; + + p = malloc(n); + if(p == nil) + sysfatal("out of memory"); + memset(p, 0, n); + return p; +} + +char* +estrdup(char *p) +{ + p = strdup(p); + if(p == nil) + sysfatal("out of memory"); + return p; +} + +void* +erealloc(void *p, long n) +{ + p = realloc(p, n); + if(p == nil) + sysfatal("out of memory"); + return p; +} + +void +double2ieee(uint64 *ieee, float64 f) +{ + memmove(ieee, &f, 8); +} diff --git a/src/liblink/ld.c b/src/liblink/ld.c new file mode 100644 index 000000000..f6632877b --- /dev/null +++ b/src/liblink/ld.c @@ -0,0 +1,572 @@ +// Derived from Inferno utils/6l/obj.c and utils/6l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/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 <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> + +void +copyhistfrog(Link *ctxt, char *buf, int nbuf) +{ + char *p, *ep; + int i; + + p = buf; + ep = buf + nbuf; + for(i=0; i<ctxt->histfrogp; i++) { + p = seprint(p, ep, "%s", ctxt->histfrog[i]->name+1); + if(i+1<ctxt->histfrogp && (p == buf || p[-1] != '/')) + p = seprint(p, ep, "/"); + } +} + +void +addhist(Link *ctxt, int32 line, int type) +{ + Auto *u; + LSym *s; + int i, j, k; + + u = emallocz(sizeof(Auto)); + s = emallocz(sizeof(LSym)); + s->name = emallocz(2*(ctxt->histfrogp+1) + 1); + + u->asym = s; + u->type = type; + u->aoffset = line; + u->link = ctxt->curhist; + ctxt->curhist = u; + + s->name[0] = 0; + j = 1; + for(i=0; i<ctxt->histfrogp; i++) { + k = ctxt->histfrog[i]->value; + s->name[j+0] = k>>8; + s->name[j+1] = k; + j += 2; + } + s->name[j] = 0; + s->name[j+1] = 0; +} + +void +histtoauto(Link *ctxt) +{ + Auto *l; + + while(l = ctxt->curhist) { + ctxt->curhist = l->link; + l->link = ctxt->curauto; + ctxt->curauto = l; + } +} + +void +collapsefrog(Link *ctxt, LSym *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<ctxt->histfrogp; i++) + if(strcmp(ctxt->histfrog[i]->name+1, "..") == 0) { + memmove(ctxt->histfrog+i-1, ctxt->histfrog+i+1, + (ctxt->histfrogp-i-1)*sizeof(ctxt->histfrog[0])); + ctxt->histfrogp--; + goto out; + } + + /* + * next try to collapse . + */ + for(i=0; i<ctxt->histfrogp; i++) + if(strcmp(ctxt->histfrog[i]->name+1, ".") == 0) { + memmove(ctxt->histfrog+i, ctxt->histfrog+i+1, + (ctxt->histfrogp-i-1)*sizeof(ctxt->histfrog[0])); + goto out; + } + + /* + * last chance, just truncate from front + */ + memmove(ctxt->histfrog+0, ctxt->histfrog+1, + (ctxt->histfrogp-1)*sizeof(ctxt->histfrog[0])); + +out: + ctxt->histfrog[ctxt->histfrogp-1] = s; +} + +// Saved history stacks encountered while reading archives. +// Keeping them allows us to answer virtual lineno -> file:line +// queries. +// +// The history stack is a complex data structure, described best at the +// bottom of http://plan9.bell-labs.com/magic/man2html/6/a.out. +// One of the key benefits of interpreting it here is that the runtime +// does not have to. Perhaps some day the compilers could generate +// a simpler linker input too. + +// savehist processes a single line, off history directive +// found in the input object file. +void +savehist(Link *ctxt, int32 line, int32 off) +{ + char tmp[1024]; + LSym *file; + Hist2 *h; + + // NOTE(rsc): We used to do the copyctxt->histfrog first and this + // condition was if(tmp[0] != '\0') to check for an empty string, + // implying that ctxt->histfrogp == 0, implying that this is a history pop. + // However, on Windows in the misc/cgo test, the linker is + // presented with an ANAME corresponding to an empty string, + // that ANAME ends up being the only ctxt->histfrog, and thus we have + // a situation where ctxt->histfrogp > 0 (not a pop) but the path we find + // is the empty string. Really that shouldn't happen, but it doesn't + // seem to be bothering anyone yet, and it's easier to fix the condition + // to test ctxt->histfrogp than to track down where that empty string is + // coming from. Probably it is coming from go tool pack's P command. + if(ctxt->histfrogp > 0) { + tmp[0] = '\0'; + copyhistfrog(ctxt, tmp, sizeof tmp); + file = linklookup(ctxt, tmp, HistVersion); + } else + file = nil; + + if(file != nil && line == 1 && off == 0) { + // start of new stack + if(ctxt->histdepth != 0) + sysfatal("history stack phase error: unexpected start of new stack depth=%d file=%s", ctxt->histdepth, tmp); + ctxt->nhist2 = 0; + ctxt->histcopy = nil; + } + + if(ctxt->nhist2 >= ctxt->maxhist2) { + if(ctxt->maxhist2 == 0) + ctxt->maxhist2 = 1; + ctxt->maxhist2 *= 2; + ctxt->hist2 = erealloc(ctxt->hist2, ctxt->maxhist2*sizeof ctxt->hist2[0]); + } + h = &ctxt->hist2[ctxt->nhist2++]; + h->line = line; + h->off = off; + h->file = file; + + if(file != nil) { + if(off == 0) + ctxt->histdepth++; + } else { + if(off != 0) + sysfatal("history stack phase error: bad offset in pop"); + ctxt->histdepth--; + } +} + +// gethist returns the history stack currently in effect. +// The result is valid indefinitely. +Hist2* +gethist(Link *ctxt) +{ + if(ctxt->histcopy == nil) { + if(ctxt->nhist2 == 0) + return nil; + ctxt->histcopy = emallocz((ctxt->nhist2+1)*sizeof ctxt->hist2[0]); + memmove(ctxt->histcopy, ctxt->hist2, ctxt->nhist2*sizeof ctxt->hist2[0]); + ctxt->histcopy[ctxt->nhist2].line = -1; + } + return ctxt->histcopy; +} + +typedef struct Hstack Hstack; +struct Hstack +{ + Hist2 *h; + int delta; +}; + +// getline sets *f to the file number and *l to the line number +// of the virtual line number line according to the history stack h. +void +linkgetline(Link *ctxt, Hist2 *h, int32 line, LSym **f, int32 *l) +{ + Hstack stk[100]; + int nstk, start; + Hist2 *top, *h0; + static Hist2 *lasth; + static int32 laststart, lastend, lastdelta; + static LSym *lastfile; + + h0 = h; + *f = 0; + *l = 0; + start = 0; + if(h == nil || line == 0) { + print("%s: getline: h=%p line=%d\n", ctxt->cursym->name, h, line); + return; + } + + // Cache span used during last lookup, so that sequential + // translation of line numbers in compiled code is efficient. + if(!ctxt->debughist && lasth == h && laststart <= line && line < lastend) { + *f = lastfile; + *l = line - lastdelta; + return; + } + + if(ctxt->debughist) + print("getline %d laststart=%d lastend=%d\n", line, laststart, lastend); + + nstk = 0; + for(; h->line != -1; h++) { + if(ctxt->debughist) + print("\t%s %d %d\n", h->file ? h->file->name : "?", h->line, h->off); + + if(h->line > line) { + if(nstk == 0) + sysfatal("history stack phase error: empty stack at line %d", (int)line); + top = stk[nstk-1].h; + lasth = h; + lastfile = top->file; + laststart = start; + lastend = h->line; + lastdelta = stk[nstk-1].delta; + *f = lastfile; + *l = line - lastdelta; + if(ctxt->debughist) + print("\tgot %d %d [%d %d %d]\n", *f, *l, laststart, lastend, lastdelta); + return; + } + if(h->file == nil) { + // pop included file + if(nstk == 0) + sysfatal("history stack phase error: stack underflow"); + nstk--; + if(nstk > 0) + stk[nstk-1].delta += h->line - stk[nstk].h->line; + start = h->line; + } else if(h->off == 0) { + // push included file + if(nstk >= nelem(stk)) + sysfatal("history stack phase error: stack overflow"); + start = h->line; + stk[nstk].h = h; + stk[nstk].delta = h->line - 1; + nstk++; + } else { + // #line directive + if(nstk == 0) + sysfatal("history stack phase error: stack underflow"); + stk[nstk-1].h = h; + stk[nstk-1].delta = h->line - h->off; + start = h->line; + } + if(ctxt->debughist) + print("\t\tnstk=%d delta=%d\n", nstk, stk[nstk].delta); + } + + sysfatal("history stack phase error: cannot find line for %d", line); + nstk = 0; + for(h = h0; h->line != -1; h++) { + print("\t%d %d %s\n", h->line, h->off, h->file ? h->file->name : ""); + if(h->file == nil) + nstk--; + else if(h->off == 0) + nstk++; + } +} + +void +addlib(Link *ctxt, char *src, char *obj) +{ + char name[1024], pname[1024], comp[256], *p; + int i, search; + + if(ctxt->histfrogp <= 0) + return; + + search = 0; + if(ctxt->histfrog[0]->name[1] == '/') { + sprint(name, ""); + i = 1; + } else + if(isalpha((uchar)ctxt->histfrog[0]->name[1]) && ctxt->histfrog[0]->name[2] == ':') { + strcpy(name, ctxt->histfrog[0]->name+1); + i = 1; + } else + if(ctxt->histfrog[0]->name[1] == '.') { + sprint(name, "."); + i = 0; + } else { + sprint(name, ""); + i = 0; + search = 1; + } + + for(; i<ctxt->histfrogp; i++) { + snprint(comp, sizeof comp, "%s", ctxt->histfrog[i]->name+1); + for(;;) { + p = strstr(comp, "$O"); + if(p == 0) + break; + memmove(p+1, p+2, strlen(p+2)+1); + p[0] = ctxt->thechar; + } + for(;;) { + p = strstr(comp, "$M"); + if(p == 0) + break; + if(strlen(comp)+strlen(ctxt->thestring)-2+1 >= sizeof comp) + sysfatal("library component too long"); + memmove(p+strlen(ctxt->thestring), p+2, strlen(p+2)+1); + memmove(p, ctxt->thestring, strlen(ctxt->thestring)); + } + if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) + sysfatal("library component too long"); + if(i > 0 || !search) + strcat(name, "/"); + strcat(name, comp); + } + cleanname(name); + + // runtime.a -> runtime + p = nil; + if(strlen(name) > 2 && name[strlen(name)-2] == '.') { + p = name+strlen(name)-2; + *p = '\0'; + } + + // already loaded? + for(i=0; i<ctxt->libraryp; i++) + if(strcmp(ctxt->library[i].pkg, name) == 0) + return; + + // runtime -> runtime.a for search + if(p != nil) + *p = '.'; + + if(search) { + // try dot, -L "libdir", and then goroot. + for(i=0; i<ctxt->nlibdir; i++) { + snprint(pname, sizeof pname, "%s/%s", ctxt->libdir[i], name); + if(access(pname, AEXIST) >= 0) + break; + } + }else + strcpy(pname, name); + cleanname(pname); + + /* runtime.a -> runtime */ + if(p != nil) + *p = '\0'; + + if(ctxt->debugvlog > 1 && ctxt->bso) + Bprint(ctxt->bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname); + + addlibpath(ctxt, src, obj, pname, name); +} + +/* + * add library to library list. + * srcref: src file referring to package + * objref: object file referring to package + * file: object file, e.g., /home/rsc/go/pkg/container/vector.a + * pkg: package import path, e.g. container/vector + */ +void +addlibpath(Link *ctxt, char *srcref, char *objref, char *file, char *pkg) +{ + int i; + Library *l; + + for(i=0; i<ctxt->libraryp; i++) + if(strcmp(file, ctxt->library[i].file) == 0) + return; + + if(ctxt->debugvlog > 1 && ctxt->bso) + Bprint(ctxt->bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n", + cputime(), srcref, objref, file, pkg); + + if(ctxt->libraryp == ctxt->nlibrary){ + ctxt->nlibrary = 50 + 2*ctxt->libraryp; + ctxt->library = erealloc(ctxt->library, sizeof ctxt->library[0] * ctxt->nlibrary); + } + + l = &ctxt->library[ctxt->libraryp++]; + l->objref = estrdup(objref); + l->srcref = estrdup(srcref); + l->file = estrdup(file); + l->pkg = estrdup(pkg); +} + +int +find1(int32 l, int c) +{ + char *p; + int i; + + p = (char*)&l; + for(i=0; i<4; i++) + if(*p++ == c) + return i; + return 0; +} + +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; + if(c == i) { + inuxi8[i] = c; + inuxi8[i+4] = c+4; + } else { + inuxi8[i] = c+4; + inuxi8[i+4] = c; + } + fnuxi4[i] = c; + fnuxi8[i] = c; + fnuxi8[i+4] = c+4; + } +} + +uchar fnuxi8[8]; +uchar fnuxi4[4]; +uchar inuxi1[1]; +uchar inuxi2[2]; +uchar inuxi4[4]; +uchar inuxi8[8]; + +#define LOG 5 +void +mkfwd(LSym *sym) +{ + Prog *p; + int i; + int32 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] = nil; + } + i = 0; + for(p = sym->text; p != nil && p->link != nil; p = p->link) { + i--; + if(i < 0) + i = LOG-1; + p->forwd = nil; + dwn[i]--; + if(dwn[i] <= 0) { + dwn[i] = cnt[i]; + if(lst[i] != nil) + lst[i]->forwd = p; + lst[i] = p; + } + } +} + +Prog* +copyp(Link *ctxt, Prog *q) +{ + Prog *p; + + p = ctxt->arch->prg(); + *p = *q; + return p; +} + +Prog* +appendp(Link *ctxt, Prog *q) +{ + Prog *p; + + p = ctxt->arch->prg(); + p->link = q->link; + q->link = p; + p->lineno = q->lineno; + p->mode = q->mode; + return p; +} + +vlong +atolwhex(char *s) +{ + vlong 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; +} diff --git a/src/liblink/obj.c b/src/liblink/obj.c new file mode 100644 index 000000000..eacbc4011 --- /dev/null +++ b/src/liblink/obj.c @@ -0,0 +1,403 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> + +enum +{ + HISTSZ = 10, + NSYM = 50, +}; + +int +linklinefmt(Link *ctxt, Fmt *fp) +{ + struct + { + Hist* incl; /* start of this include file */ + int32 idel; /* delta line number to apply to include */ + Hist* line; /* start of this #line directive */ + int32 ldel; /* delta line number to apply to #line */ + } a[HISTSZ]; + int32 lno, d; + int i, n; + Hist *h; + + lno = va_arg(fp->args, int32); + + n = 0; + for(h=ctxt->hist; h!=nil; h=h->link) { + if(h->offset < 0) + continue; + if(lno < h->line) + break; + if(h->name) { + if(h->offset > 0) { + // #line directive + if(n > 0 && n < HISTSZ) { + a[n-1].line = h; + a[n-1].ldel = h->line - h->offset + 1; + } + } else { + // beginning of file + if(n < HISTSZ) { + a[n].incl = h; + a[n].idel = h->line; + a[n].line = 0; + } + n++; + } + continue; + } + n--; + if(n > 0 && n < HISTSZ) { + d = h->line - a[n].incl->line; + a[n-1].ldel += d; + a[n-1].idel += d; + } + } + + if(n > HISTSZ) + n = HISTSZ; + + for(i=n-1; i>=0; i--) { + if(i != n-1) { + if(fp->flags & ~(FmtWidth|FmtPrec)) + break; + fmtprint(fp, " "); + } + if(ctxt->debugline || (fp->flags&FmtLong)) + fmtprint(fp, "%s/", ctxt->pathname); + if(a[i].line) + fmtprint(fp, "%s:%d[%s:%d]", + a[i].line->name, lno-a[i].ldel+1, + a[i].incl->name, lno-a[i].idel+1); + else + fmtprint(fp, "%s:%d", + a[i].incl->name, lno-a[i].idel+1); + lno = a[i].incl->line - 1; // now print out start of this file + } + if(n == 0) + fmtprint(fp, "<unknown line number>"); + + return 0; +} + +static void +outzfile(Link *ctxt, Biobuf *b, char *p) +{ + char *q, *q2; + + while(p) { + q = utfrune(p, '/'); + if(ctxt->windows) { + q2 = utfrune(p, '\\'); + if(q2 && (!q || q2 < q)) + q = q2; + } + if(!q) { + ctxt->arch->zfile(b, p, strlen(p)); + return; + } + if(q > p) + ctxt->arch->zfile(b, p, q-p); + p = q + 1; + } +} + +#define isdelim(c) (c == '/' || c == '\\') + +static void +outwinname(Link *ctxt, Biobuf *b, Hist *h, char *ds, char *p) +{ + if(isdelim(p[0])) { + // full rooted name + ctxt->arch->zfile(b, ds, 3); // leading "c:/" + outzfile(ctxt, b, p+1); + } else { + // relative name + if(h->offset >= 0 && ctxt->pathname && ctxt->pathname[1] == ':') { + if(tolowerrune(ds[0]) == tolowerrune(ctxt->pathname[0])) { + // using current drive + ctxt->arch->zfile(b, ctxt->pathname, 3); // leading "c:/" + outzfile(ctxt, b, ctxt->pathname+3); + } else { + // using drive other then current, + // we don't have any simple way to + // determine current working directory + // there, therefore will output name as is + ctxt->arch->zfile(b, ds, 2); // leading "c:" + } + } + outzfile(ctxt, b, p); + } +} + +void +linkouthist(Link *ctxt, Biobuf *b) +{ + Hist *h; + char *p, ds[] = {'c', ':', '/', 0}; + char *tofree; + int n; + static int first = 1; + static char *goroot, *goroot_final; + + if(first) { + // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL. + first = 0; + goroot = getenv("GOROOT"); + goroot_final = getenv("GOROOT_FINAL"); + if(goroot == nil) + goroot = ""; + if(goroot_final == nil) + goroot_final = goroot; + if(strcmp(goroot, goroot_final) == 0) { + goroot = nil; + goroot_final = nil; + } + } + + tofree = nil; + for(h = ctxt->hist; h != nil; h = h->link) { + p = h->name; + if(p) { + if(goroot != nil) { + n = strlen(goroot); + if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') { + tofree = smprint("%s%s", goroot_final, p+n); + p = tofree; + } + } + if(ctxt->windows) { + // if windows variable is set, then, we know already, + // pathname is started with windows drive specifier + // and all '\' were replaced with '/' (see lex.c) + if(isdelim(p[0]) && isdelim(p[1])) { + // file name has network name in it, + // like \\server\share\dir\file.go + ctxt->arch->zfile(b, "//", 2); // leading "//" + outzfile(ctxt, b, p+2); + } else if(p[1] == ':') { + // file name has drive letter in it + ds[0] = p[0]; + outwinname(ctxt, b, h, ds, p+2); + } else { + // no drive letter in file name + outwinname(ctxt, b, h, ctxt->pathname, p); + } + } else { + if(p[0] == '/') { + // full rooted name, like /home/rsc/dir/file.go + ctxt->arch->zfile(b, "/", 1); // leading "/" + outzfile(ctxt, b, p+1); + } else { + // relative name, like dir/file.go + if(h->offset >= 0 && ctxt->pathname && ctxt->pathname[0] == '/') { + ctxt->arch->zfile(b, "/", 1); // leading "/" + outzfile(ctxt, b, ctxt->pathname+1); + } + outzfile(ctxt, b, p); + } + } + } + ctxt->arch->zhist(b, h->line, h->offset); + if(tofree) { + free(tofree); + tofree = nil; + } + } +} + +void +linklinehist(Link *ctxt, int lineno, char *f, int offset) +{ + Hist *h; + + if(0) // debug['f'] + if(f) { + if(offset) + print("%4d: %s (#line %d)\n", lineno, f, offset); + else + print("%4d: %s\n", lineno, f); + } else + print("%4d: <pop>\n", lineno); + + h = malloc(sizeof(Hist)); + memset(h, 0, sizeof *h); + h->name = f; + h->line = lineno; + h->offset = offset; + h->link = nil; + if(ctxt->ehist == nil) { + ctxt->hist = h; + ctxt->ehist = h; + return; + } + ctxt->ehist->link = h; + ctxt->ehist = h; +} + +void +linkprfile(Link *ctxt, int32 l) +{ + int i, n; + Hist a[HISTSZ], *h; + int32 d; + + n = 0; + for(h = ctxt->hist; h != nil; h = h->link) { + if(l < h->line) + break; + if(h->name) { + if(h->offset == 0) { + if(n >= 0 && n < HISTSZ) + a[n] = *h; + n++; + continue; + } + if(n > 0 && n < HISTSZ) + if(a[n-1].offset == 0) { + a[n] = *h; + n++; + } else + a[n-1] = *h; + continue; + } + n--; + if(n >= 0 && n < HISTSZ) { + d = h->line - a[n].line; + for(i=0; i<n; i++) + a[i].line += d; + } + } + if(n > HISTSZ) + n = HISTSZ; + for(i=0; i<n; i++) + print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1)); +} + +/* + * start a new Prog list. + */ +Plist* +linknewplist(Link *ctxt) +{ + Plist *pl; + + pl = malloc(sizeof(*pl)); + memset(pl, 0, sizeof *pl); + if(ctxt->plist == nil) + ctxt->plist = pl; + else + ctxt->plast->link = pl; + ctxt->plast = pl; + + return pl; +} + +static struct { + struct { LSym *sym; short type; } h[NSYM]; + int sym; +} z; + +static void +zsymreset(void) +{ + for(z.sym=0; z.sym<NSYM; z.sym++) { + z.h[z.sym].sym = nil; + z.h[z.sym].type = 0; + } + z.sym = 1; +} + + +static int +zsym(Link *ctxt, Biobuf *b, LSym *s, int t, int *new) +{ + int i; + + *new = 0; + if(s == nil) + return 0; + + i = s->symid; + if(i < 0 || i >= NSYM) + i = 0; + if(z.h[i].type == t && z.h[i].sym == s) + return i; + i = z.sym; + s->symid = i; + ctxt->arch->zname(b, s, t); + z.h[i].sym = s; + z.h[i].type = t; + if(++z.sym >= NSYM) + z.sym = 1; + *new = 1; + return i; +} + +static int +zsymaddr(Link *ctxt, Biobuf *b, Addr *a, int *new) +{ + return zsym(ctxt, b, a->sym, ctxt->arch->symtype(a), new); +} + +void +linkwritefuncs(Link *ctxt, Biobuf *b) +{ + int32 pcloc; + Plist *pl; + LSym *s; + Prog *p; + int sf, st, gf, gt, new; + + zsymreset(); + + // fix up pc + pcloc = 0; + for(pl=ctxt->plist; pl!=nil; pl=pl->link) { + if(pl->name != nil && strcmp(pl->name->name, "_") == 0) + continue; + for(p=pl->firstpc; p!=nil; p=p->link) { + p->loc = pcloc; + if(!ctxt->arch->isdata(p)) + pcloc++; + } + } + + // put out functions + for(pl=ctxt->plist; pl!=nil; pl=pl->link) { + if(pl->name != nil && strcmp(pl->name->name, "_") == 0) + continue; + + // -S prints code; -S -S prints code and data + if(ctxt->debugasm && (pl->name || ctxt->debugasm>1)) { + s = pl->name; + print("\n--- prog list \"%lS\" ---\n", s); + for(p=pl->firstpc; p!=nil; p=p->link) + print("%P\n", p); + } + + for(p=pl->firstpc; p!=nil; p=p->link) { + for(;;) { + sf = zsymaddr(ctxt, b, &p->from, &new); + gf = zsym(ctxt, b, p->from.gotype, ctxt->arch->D_EXTERN, &new); + if(new && sf == gf) + continue; + st = zsymaddr(ctxt, b, &p->to, &new); + if(new && (st == sf || st == gf)) + continue; + gt = zsym(ctxt, b, p->to.gotype, ctxt->arch->D_EXTERN, &new); + if(new && (gt == sf || gt == gf || gt == st)) + continue; + break; + } + ctxt->arch->zprog(ctxt, b, p, sf, gf, st, gt); + } + } +} diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c new file mode 100644 index 000000000..e9c0b5731 --- /dev/null +++ b/src/liblink/obj5.c @@ -0,0 +1,1187 @@ +// Derived from Inferno utils/5c/swt.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.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 <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> +#include "../cmd/5l/5.out.h" +#include "../pkg/runtime/stack.h" + +static Addr noaddr = { + .type = D_NONE, + .name = D_NONE, + .reg = NREG, +}; + +static Prog zprg = { + .as = AGOK, + .scond = 14, + .reg = NREG, + .from = { + .name = D_NONE, + .type = D_NONE, + .reg = NREG, + }, + .to = { + .name = D_NONE, + .type = D_NONE, + .reg = NREG, + }, +}; + +static void +zname(Biobuf *b, LSym *s, int t) +{ + BPUTC(b, ANAME); /* as */ + BPUTC(b, t); /* type */ + BPUTC(b, s->symid); /* sym */ + Bwrite(b, s->name, strlen(s->name)+1); +} + +static void +zfile(Biobuf *b, char *p, int n) +{ + BPUTC(b, ANAME); + BPUTC(b, D_FILE); + BPUTC(b, 1); + BPUTC(b, '<'); + Bwrite(b, p, n); + BPUTC(b, 0); +} + +static void +zaddr(Biobuf *b, Addr *a, int s, int gotype) +{ + int32 l; + uint64 e; + int i; + char *n; + + switch(a->type) { + case D_STATIC: + case D_AUTO: + case D_EXTERN: + case D_PARAM: + // TODO(kaib): remove once everything seems to work + sysfatal("We should no longer generate these as types"); + + default: + BPUTC(b, a->type); + BPUTC(b, a->reg); + BPUTC(b, s); + BPUTC(b, a->name); + BPUTC(b, gotype); + } + + switch(a->type) { + default: + print("unknown type %d in zaddr\n", a->type); + + case D_NONE: + case D_REG: + case D_FREG: + case D_PSR: + break; + + case D_CONST2: + l = a->offset2; + BPUTLE4(b, l); // fall through + case D_OREG: + case D_CONST: + case D_SHIFT: + case D_STATIC: + case D_AUTO: + case D_EXTERN: + case D_PARAM: + l = a->offset; + BPUTLE4(b, l); + break; + + case D_BRANCH: + if(a->offset == 0 || a->u.branch != nil) { + if(a->u.branch == nil) + sysfatal("unpatched branch %D", a); + a->offset = a->u.branch->loc; + } + l = a->offset; + BPUTLE4(b, l); + break; + + case D_SCONST: + n = a->u.sval; + for(i=0; i<NSNAME; i++) { + BPUTC(b, *n); + n++; + } + break; + + case D_REGREG: + case D_REGREG2: + BPUTC(b, a->offset); + break; + + case D_FCONST: + double2ieee(&e, a->u.dval); + BPUTLE4(b, e); + BPUTLE4(b, e >> 32); + break; + } +} + +static void +zhist(Biobuf *b, int line, vlong offset) +{ + Addr a; + + BPUTC(b, AHISTORY); + BPUTC(b, C_SCOND_NONE); + BPUTC(b, NREG); + BPUTLE4(b, line); + zaddr(b, &noaddr, 0, 0); + a = noaddr; + if(offset != 0) { + a.offset = offset; + a.type = D_CONST; + } + zaddr(b, &a, 0, 0); +} + +static int +symtype(Addr *a) +{ + return a->name; +} + +static void +zprog(Link *ctxt, Biobuf *b, Prog *p, int sf, int gf, int st, int gt) +{ + USED(ctxt); + + BPUTC(b, p->as); + BPUTC(b, p->scond); + BPUTC(b, p->reg); + BPUTLE4(b, p->lineno); + zaddr(b, &p->from, sf, gf); + zaddr(b, &p->to, st, gt); +} + +static int +isdata(Prog *p) +{ + return p->as == ADATA || p->as == AGLOBL; +} + +static int +iscall(Prog *p) +{ + return p->as == ABL; +} + +static int +datasize(Prog *p) +{ + return p->reg; +} + +static int +textflag(Prog *p) +{ + return p->reg; +} + +static void +settextflag(Prog *p, int f) +{ + p->reg = f; +} + +static Prog* +prg(void) +{ + Prog *p; + + p = emallocz(sizeof(*p)); + *p = zprg; + return p; +} + +static Prog* stacksplit(Link*, Prog*, int32); +static void initdiv(Link*); +static void softfloat(Link*, LSym*); + +// Prog.mark +enum +{ + FOLL = 1<<0, + LABEL = 1<<1, + LEAF = 1<<2, +}; + +static void +linkcase(Prog *casep) +{ + Prog *p; + + for(p = casep; p != nil; p = p->link){ + if(p->as == ABCASE) { + for(; p != nil && p->as == ABCASE; p = p->link) + p->pcrel = casep; + break; + } + } +} + +static void +nocache(Prog *p) +{ + p->optab = 0; + p->from.class = 0; + p->to.class = 0; +} + +static void +addstacksplit(Link *ctxt, LSym *cursym) +{ + Prog *p, *pl, *q, *q1, *q2; + int o; + LSym *tlsfallback; + int32 autosize, autoffset; + + autosize = 0; + + if(ctxt->symmorestack[0] == nil) + ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0); + + tlsfallback = linklookup(ctxt, "runtime.read_tls_fallback", 0); + ctxt->gmsym = nil; + if(ctxt->linkmode == LinkExternal) + ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0); + q = nil; + + ctxt->cursym = cursym; + + if(cursym->text == nil || cursym->text->link == nil) + return; + + softfloat(ctxt, cursym); + + if(ctxt->debugzerostack) { + p = cursym->text; + autoffset = p->to.offset; + if(autoffset < 0) + autoffset = 0; + if(autoffset && !(p->reg&NOSPLIT)) { + // MOVW $4(R13), R1 + p = appendp(ctxt, p); + p->as = AMOVW; + p->from.type = D_CONST; + p->from.reg = 13; + p->from.offset = 4; + p->to.type = D_REG; + p->to.reg = 1; + + // MOVW $n(R13), R2 + p = appendp(ctxt, p); + p->as = AMOVW; + p->from.type = D_CONST; + p->from.reg = 13; + p->from.offset = 4 + autoffset; + p->to.type = D_REG; + p->to.reg = 2; + + // MOVW $0, R3 + p = appendp(ctxt, p); + p->as = AMOVW; + p->from.type = D_CONST; + p->from.offset = 0; + p->to.type = D_REG; + p->to.reg = 3; + + // L: + // MOVW.nil R3, 0(R1) +4 + // CMP R1, R2 + // BNE L + p = pl = appendp(ctxt, p); + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = 3; + p->to.type = D_OREG; + p->to.reg = 1; + p->to.offset = 4; + p->scond |= C_PBIT; + + p = appendp(ctxt, p); + p->as = ACMP; + p->from.type = D_REG; + p->from.reg = 1; + p->reg = 2; + + p = appendp(ctxt, p); + p->as = ABNE; + p->to.type = D_BRANCH; + p->pcond = pl; + } + } + + /* + * find leaf subroutines + * strip NOPs + * expand RET + * expand BECOME pseudo + * fixup TLS + */ + + for(p = cursym->text; p != nil; p = p->link) { + switch(p->as) { + case ACASE: + if(ctxt->flag_shared) + linkcase(p); + break; + + case ATEXT: + p->mark |= LEAF; + break; + + case ARET: + break; + + case ADIV: + case ADIVU: + case AMOD: + case AMODU: + q = p; + if(ctxt->sym_div == nil) + initdiv(ctxt); + cursym->text->mark &= ~LEAF; + continue; + + case ANOP: + q1 = p->link; + q->link = q1; /* q is non-nop */ + if(q1 != nil) + q1->mark |= p->mark; + continue; + + case ABL: + case ABX: + cursym->text->mark &= ~LEAF; + + case ABCASE: + case AB: + + case ABEQ: + case ABNE: + case ABCS: + case ABHS: + case ABCC: + case ABLO: + case ABMI: + case ABPL: + case ABVS: + case ABVC: + case ABHI: + case ABLS: + case ABGE: + case ABLT: + case ABGT: + case ABLE: + q1 = p->pcond; + if(q1 != nil) { + while(q1->as == ANOP) { + q1 = q1->link; + p->pcond = q1; + } + } + break; + case AWORD: + // Rewrite TLS register fetch: MRC 15, 0, <reg>, C13, C0, 3 + if((p->to.offset & 0xffff0fff) == 0xee1d0f70) { + if(ctxt->headtype == Hopenbsd) { + p->as = ARET; + } else if(ctxt->goarm < 7) { + if(tlsfallback->type != STEXT) { + ctxt->diag("runtime·read_tls_fallback not defined"); + sysfatal("tlsfallback"); + } + // BL runtime.read_tls_fallback(SB) + p->as = ABL; + p->to.type = D_BRANCH; + p->to.sym = tlsfallback; + p->pcond = tlsfallback->text; + p->to.offset = 0; + cursym->text->mark &= ~LEAF; + } + if(ctxt->linkmode == LinkExternal) { + // runtime.tlsgm is relocated with R_ARM_TLS_LE32 + // and $runtime.tlsgm will contain the TLS offset. + // + // MOV $runtime.tlsgm+ctxt->tlsoffset(SB), REGTMP + // ADD REGTMP, <reg> + // + // In shared mode, runtime.tlsgm is relocated with + // R_ARM_TLS_IE32 and runtime.tlsgm(SB) will point + // to the GOT entry containing the TLS offset. + // + // MOV runtime.tlsgm(SB), REGTMP + // ADD REGTMP, <reg> + // SUB -ctxt->tlsoffset, <reg> + // + // The SUB compensates for ctxt->tlsoffset + // used in runtime.save_gm and runtime.load_gm. + q = p; + p = appendp(ctxt, p); + p->as = AMOVW; + p->scond = 14; + p->reg = NREG; + if(ctxt->flag_shared) { + p->from.type = D_OREG; + p->from.offset = 0; + } else { + p->from.type = D_CONST; + p->from.offset = ctxt->tlsoffset; + } + p->from.sym = ctxt->gmsym; + p->from.name = D_EXTERN; + p->to.type = D_REG; + p->to.reg = REGTMP; + p->to.offset = 0; + + p = appendp(ctxt, p); + p->as = AADD; + p->scond = 14; + p->reg = NREG; + p->from.type = D_REG; + p->from.reg = REGTMP; + p->to.type = D_REG; + p->to.reg = (q->to.offset & 0xf000) >> 12; + p->to.offset = 0; + + if(ctxt->flag_shared) { + p = appendp(ctxt, p); + p->as = ASUB; + p->scond = 14; + p->reg = NREG; + p->from.type = D_CONST; + p->from.offset = -ctxt->tlsoffset; + p->to.type = D_REG; + p->to.reg = (q->to.offset & 0xf000) >> 12; + p->to.offset = 0; + } + } + } + } + q = p; + } + + for(p = cursym->text; p != nil; p = p->link) { + o = p->as; + switch(o) { + case ATEXT: + autosize = p->to.offset + 4; + if(autosize <= 4) + if(cursym->text->mark & LEAF) { + p->to.offset = -4; + autosize = 0; + } + + if(!autosize && !(cursym->text->mark & LEAF)) { + if(ctxt->debugvlog) { + Bprint(ctxt->bso, "save suppressed in: %s\n", + cursym->name); + Bflush(ctxt->bso); + } + cursym->text->mark |= LEAF; + } + if(cursym->text->mark & LEAF) { + cursym->leaf = 1; + if(!autosize) + break; + } + + if(!(p->reg & NOSPLIT)) + p = stacksplit(ctxt, p, autosize); // emit split check + + // MOVW.W R14,$-autosize(SP) + p = appendp(ctxt, p); + p->as = AMOVW; + p->scond |= C_WBIT; + p->from.type = D_REG; + p->from.reg = REGLINK; + p->to.type = D_OREG; + p->to.offset = -autosize; + p->to.reg = REGSP; + p->spadj = autosize; + + if(cursym->text->reg & WRAPPER) { + // g->panicwrap += autosize; + // MOVW panicwrap_offset(g), R3 + // ADD $autosize, R3 + // MOVW R3 panicwrap_offset(g) + p = appendp(ctxt, p); + p->as = AMOVW; + p->from.type = D_OREG; + p->from.reg = REGG; + p->from.offset = 2*ctxt->arch->ptrsize; + p->to.type = D_REG; + p->to.reg = 3; + + p = appendp(ctxt, p); + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to.type = D_REG; + p->to.reg = 3; + + p = appendp(ctxt, p); + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = 3; + p->to.type = D_OREG; + p->to.reg = REGG; + p->to.offset = 2*ctxt->arch->ptrsize; + } + break; + + case ARET: + nocache(p); + if(cursym->text->mark & LEAF) { + if(!autosize) { + p->as = AB; + p->from = zprg.from; + if(p->to.sym) { // retjmp + p->to.type = D_BRANCH; + p->pcond = p->to.sym->text; + } else { + p->to.type = D_OREG; + p->to.offset = 0; + p->to.reg = REGLINK; + } + break; + } + } + + if(cursym->text->reg & WRAPPER) { + int scond; + + // Preserve original RET's cond, to allow RET.EQ + // in the implementation of reflect.call. + scond = p->scond; + p->scond = C_SCOND_NONE; + + // g->panicwrap -= autosize; + // MOVW panicwrap_offset(g), R3 + // SUB $autosize, R3 + // MOVW R3 panicwrap_offset(g) + p->as = AMOVW; + p->from.type = D_OREG; + p->from.reg = REGG; + p->from.offset = 2*ctxt->arch->ptrsize; + p->to.type = D_REG; + p->to.reg = 3; + p = appendp(ctxt, p); + + p->as = ASUB; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to.type = D_REG; + p->to.reg = 3; + p = appendp(ctxt, p); + + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = 3; + p->to.type = D_OREG; + p->to.reg = REGG; + p->to.offset = 2*ctxt->arch->ptrsize; + p = appendp(ctxt, p); + + p->scond = scond; + } + + p->as = AMOVW; + p->scond |= C_PBIT; + p->from.type = D_OREG; + p->from.offset = autosize; + p->from.reg = REGSP; + p->to.type = D_REG; + p->to.reg = REGPC; + // If there are instructions following + // this ARET, they come from a branch + // with the same stackframe, so no spadj. + + if(p->to.sym) { // retjmp + p->to.reg = REGLINK; + q2 = appendp(ctxt, p); + q2->as = AB; + q2->to.type = D_BRANCH; + q2->to.sym = p->to.sym; + q2->pcond = p->to.sym->text; + p->to.sym = nil; + p = q2; + } + break; + + case AADD: + if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) + p->spadj = -p->from.offset; + break; + + case ASUB: + if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) + p->spadj = p->from.offset; + break; + + case ADIV: + case ADIVU: + case AMOD: + case AMODU: + if(ctxt->debugdivmod) + break; + if(p->from.type != D_REG) + break; + if(p->to.type != D_REG) + break; + q1 = p; + + /* MOV a,4(SP) */ + p = appendp(ctxt, p); + p->as = AMOVW; + p->lineno = q1->lineno; + p->from.type = D_REG; + p->from.reg = q1->from.reg; + p->to.type = D_OREG; + p->to.reg = REGSP; + p->to.offset = 4; + + /* MOV b,REGTMP */ + p = appendp(ctxt, p); + p->as = AMOVW; + p->lineno = q1->lineno; + p->from.type = D_REG; + p->from.reg = q1->reg; + if(q1->reg == NREG) + p->from.reg = q1->to.reg; + p->to.type = D_REG; + p->to.reg = REGTMP; + p->to.offset = 0; + + /* CALL appropriate */ + p = appendp(ctxt, p); + p->as = ABL; + p->lineno = q1->lineno; + p->to.type = D_BRANCH; + p->pcond = p; + switch(o) { + case ADIV: + p->to.sym = ctxt->sym_div; + break; + case ADIVU: + p->to.sym = ctxt->sym_divu; + break; + case AMOD: + p->to.sym = ctxt->sym_mod; + break; + case AMODU: + p->to.sym = ctxt->sym_modu; + break; + } + + /* MOV REGTMP, b */ + p = appendp(ctxt, p); + p->as = AMOVW; + p->lineno = q1->lineno; + p->from.type = D_REG; + p->from.reg = REGTMP; + p->from.offset = 0; + p->to.type = D_REG; + p->to.reg = q1->to.reg; + + /* ADD $8,SP */ + p = appendp(ctxt, p); + p->as = AADD; + p->lineno = q1->lineno; + p->from.type = D_CONST; + p->from.reg = NREG; + p->from.offset = 8; + p->reg = NREG; + p->to.type = D_REG; + p->to.reg = REGSP; + p->spadj = -8; + + /* Keep saved LR at 0(SP) after SP change. */ + /* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */ + /* TODO: Remove SP adjustments; see issue 6699. */ + q1->as = AMOVW; + q1->from.type = D_OREG; + q1->from.reg = REGSP; + q1->from.offset = 0; + q1->reg = NREG; + q1->to.type = D_REG; + q1->to.reg = REGTMP; + + /* SUB $8,SP */ + q1 = appendp(ctxt, q1); + q1->as = AMOVW; + q1->from.type = D_REG; + q1->from.reg = REGTMP; + q1->reg = NREG; + q1->to.type = D_OREG; + q1->to.reg = REGSP; + q1->to.offset = -8; + q1->scond |= C_WBIT; + q1->spadj = 8; + + break; + case AMOVW: + if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP) + p->spadj = -p->to.offset; + if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC) + p->spadj = -p->from.offset; + if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP) + p->spadj = -p->from.offset; + break; + } + } +} + +static void +softfloat(Link *ctxt, LSym *cursym) +{ + Prog *p, *next, *psfloat; + LSym *symsfloat; + int wasfloat; + + if(!ctxt->debugfloat) + return; + + symsfloat = linklookup(ctxt, "_sfloat", 0); + psfloat = nil; + if(symsfloat->type == STEXT) + psfloat = symsfloat->text; + + wasfloat = 0; + for(p = cursym->text; p != nil; p = p->link) + if(p->pcond != nil) + p->pcond->mark |= LABEL; + for(p = cursym->text; p != nil; p = p->link) { + switch(p->as) { + case AMOVW: + if(p->to.type == D_FREG || p->from.type == D_FREG) + goto soft; + goto notsoft; + + case AMOVWD: + case AMOVWF: + case AMOVDW: + case AMOVFW: + case AMOVFD: + case AMOVDF: + case AMOVF: + case AMOVD: + + case ACMPF: + case ACMPD: + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + case ASQRTF: + case ASQRTD: + case AABSF: + case AABSD: + goto soft; + + default: + goto notsoft; + + soft: + if (psfloat == nil) + ctxt->diag("floats used with _sfloat not defined"); + if (!wasfloat || (p->mark&LABEL)) { + next = ctxt->arch->prg(); + *next = *p; + + // BL _sfloat(SB) + *p = zprg; + p->link = next; + p->as = ABL; + p->to.type = D_BRANCH; + p->to.sym = symsfloat; + p->pcond = psfloat; + p->lineno = next->lineno; + + p = next; + wasfloat = 1; + } + break; + + notsoft: + wasfloat = 0; + } + } +} + +static Prog* +stacksplit(Link *ctxt, Prog *p, int32 framesize) +{ + int32 arg; + + // MOVW g_stackguard(g), R1 + p = appendp(ctxt, p); + p->as = AMOVW; + p->from.type = D_OREG; + p->from.reg = REGG; + p->to.type = D_REG; + p->to.reg = 1; + + if(framesize <= StackSmall) { + // small stack: SP < stackguard + // CMP stackguard, SP + p = appendp(ctxt, p); + p->as = ACMP; + p->from.type = D_REG; + p->from.reg = 1; + p->reg = REGSP; + } else if(framesize <= StackBig) { + // large stack: SP-framesize < stackguard-StackSmall + // MOVW $-framesize(SP), R2 + // CMP stackguard, R2 + p = appendp(ctxt, p); + p->as = AMOVW; + p->from.type = D_CONST; + p->from.reg = REGSP; + p->from.offset = -framesize; + p->to.type = D_REG; + p->to.reg = 2; + + p = appendp(ctxt, p); + p->as = ACMP; + p->from.type = D_REG; + p->from.reg = 1; + p->reg = 2; + } else { + // Such a large stack we need to protect against wraparound + // if SP is close to zero. + // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall) + // The +StackGuard on both sides is required to keep the left side positive: + // SP is allowed to be slightly below stackguard. See stack.h. + // CMP $StackPreempt, R1 + // MOVW.NE $StackGuard(SP), R2 + // SUB.NE R1, R2 + // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3 + // CMP.NE R3, R2 + p = appendp(ctxt, p); + p->as = ACMP; + p->from.type = D_CONST; + p->from.offset = (uint32)StackPreempt; + p->reg = 1; + + p = appendp(ctxt, p); + p->as = AMOVW; + p->from.type = D_CONST; + p->from.reg = REGSP; + p->from.offset = StackGuard; + p->to.type = D_REG; + p->to.reg = 2; + p->scond = C_SCOND_NE; + + p = appendp(ctxt, p); + p->as = ASUB; + p->from.type = D_REG; + p->from.reg = 1; + p->to.type = D_REG; + p->to.reg = 2; + p->scond = C_SCOND_NE; + + p = appendp(ctxt, p); + p->as = AMOVW; + p->from.type = D_CONST; + p->from.offset = framesize + (StackGuard - StackSmall); + p->to.type = D_REG; + p->to.reg = 3; + p->scond = C_SCOND_NE; + + p = appendp(ctxt, p); + p->as = ACMP; + p->from.type = D_REG; + p->from.reg = 3; + p->reg = 2; + p->scond = C_SCOND_NE; + } + + // MOVW.LS $framesize, R1 + p = appendp(ctxt, p); + p->as = AMOVW; + p->scond = C_SCOND_LS; + p->from.type = D_CONST; + p->from.offset = framesize; + p->to.type = D_REG; + p->to.reg = 1; + + // MOVW.LS $args, R2 + p = appendp(ctxt, p); + p->as = AMOVW; + p->scond = C_SCOND_LS; + p->from.type = D_CONST; + arg = ctxt->cursym->text->to.offset2; + if(arg == 1) // special marker for known 0 + arg = 0; + if(arg&3) + ctxt->diag("misaligned argument size in stack split"); + p->from.offset = arg; + p->to.type = D_REG; + p->to.reg = 2; + + // MOVW.LS R14, R3 + p = appendp(ctxt, p); + p->as = AMOVW; + p->scond = C_SCOND_LS; + p->from.type = D_REG; + p->from.reg = REGLINK; + p->to.type = D_REG; + p->to.reg = 3; + + // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted + p = appendp(ctxt, p); + p->as = ABL; + p->scond = C_SCOND_LS; + p->to.type = D_BRANCH; + p->to.sym = ctxt->symmorestack[0]; + + // BLS start + p = appendp(ctxt, p); + p->as = ABLS; + p->to.type = D_BRANCH; + p->pcond = ctxt->cursym->text->link; + + return p; +} + +static void +initdiv(Link *ctxt) +{ + if(ctxt->sym_div != nil) + return; + ctxt->sym_div = linklookup(ctxt, "_div", 0); + ctxt->sym_divu = linklookup(ctxt, "_divu", 0); + ctxt->sym_mod = linklookup(ctxt, "_mod", 0); + ctxt->sym_modu = linklookup(ctxt, "_modu", 0); +} + +static void xfol(Link*, Prog*, Prog**); + +static void +follow(Link *ctxt, LSym *s) +{ + Prog *firstp, *lastp; + + ctxt->cursym = s; + + firstp = ctxt->arch->prg(); + lastp = firstp; + xfol(ctxt, s->text, &lastp); + lastp->link = nil; + s->text = firstp->link; +} + +static int +relinv(int a) +{ + switch(a) { + case ABEQ: return ABNE; + case ABNE: return ABEQ; + case ABCS: return ABCC; + case ABHS: return ABLO; + case ABCC: return ABCS; + case ABLO: return ABHS; + case ABMI: return ABPL; + case ABPL: return ABMI; + case ABVS: return ABVC; + case ABVC: return ABVS; + case ABHI: return ABLS; + case ABLS: return ABHI; + case ABGE: return ABLT; + case ABLT: return ABGE; + case ABGT: return ABLE; + case ABLE: return ABGT; + } + sysfatal("unknown relation: %s", anames5[a]); + return 0; +} + +static void +xfol(Link *ctxt, Prog *p, Prog **last) +{ + Prog *q, *r; + int a, i; + +loop: + if(p == nil) + return; + a = p->as; + if(a == AB) { + q = p->pcond; + if(q != nil && q->as != ATEXT) { + p->mark |= FOLL; + p = q; + if(!(p->mark & FOLL)) + goto loop; + } + } + if(p->mark & FOLL) { + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == *last || q == nil) + break; + a = q->as; + if(a == ANOP) { + i--; + continue; + } + if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF) + goto copy; + if(q->pcond == nil || (q->pcond->mark&FOLL)) + continue; + if(a != ABEQ && a != ABNE) + continue; + copy: + for(;;) { + r = ctxt->arch->prg(); + *r = *p; + if(!(r->mark&FOLL)) + print("can't happen 1\n"); + r->mark |= FOLL; + if(p != q) { + p = p->link; + (*last)->link = r; + *last = r; + continue; + } + (*last)->link = r; + *last = r; + if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF) + return; + r->as = ABNE; + if(a == ABNE) + r->as = ABEQ; + r->pcond = p->link; + r->link = p->pcond; + if(!(r->link->mark&FOLL)) + xfol(ctxt, r->link, last); + if(!(r->pcond->mark&FOLL)) + print("can't happen 2\n"); + return; + } + } + a = AB; + q = ctxt->arch->prg(); + q->as = a; + q->lineno = p->lineno; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->pcond = p; + p = q; + } + p->mark |= FOLL; + (*last)->link = p; + *last = p; + if(a == AB || (a == ARET && p->scond == 14) || a == ARFE || a == AUNDEF){ + return; + } + if(p->pcond != nil) + if(a != ABL && a != ABX && p->link != nil) { + q = brchain(ctxt, p->link); + if(a != ATEXT && a != ABCASE) + if(q != nil && (q->mark&FOLL)) { + p->as = relinv(a); + p->link = p->pcond; + p->pcond = q; + } + xfol(ctxt, p->link, last); + q = brchain(ctxt, p->pcond); + if(q == nil) + q = p->pcond; + if(q->mark&FOLL) { + p->pcond = q; + return; + } + p = q; + goto loop; + } + p = p->link; + goto loop; +} + +LinkArch linkarm = { + .name = "arm", + + .addstacksplit = addstacksplit, + .assemble = span5, + .datasize = datasize, + .follow = follow, + .iscall = iscall, + .isdata = isdata, + .ldobj = ldobj5, + .nopout = nopout5, + .prg = prg, + .settextflag = settextflag, + .symtype = symtype, + .textflag = textflag, + .zfile = zfile, + .zhist = zhist, + .zname = zname, + .zprog = zprog, + + .minlc = 4, + .ptrsize = 4, + + .D_ADDR = D_ADDR, + .D_BRANCH = D_BRANCH, + .D_CONST = D_CONST, + .D_EXTERN = D_EXTERN, + .D_FCONST = D_FCONST, + .D_NONE = D_NONE, + .D_PCREL = D_PCREL, + .D_SCONST = D_SCONST, + .D_SIZE = D_SIZE, + + .ACALL = ABL, + .AFUNCDATA = AFUNCDATA, + .AJMP = AB, + .ANOP = ANOP, + .APCDATA = APCDATA, + .ARET = ARET, + .ATEXT = ATEXT, + .AUSEFIELD = AUSEFIELD, +}; diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c new file mode 100644 index 000000000..bd24d1d9e --- /dev/null +++ b/src/liblink/obj6.c @@ -0,0 +1,1078 @@ +// Inferno utils/6l/pass.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/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 <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> +#include "../cmd/6l/6.out.h" +#include "../pkg/runtime/stack.h" + +static Addr noaddr = { + .type = D_NONE, + .index = D_NONE, + .scale = 0, +}; + +static Prog zprg = { + .back = 2, + .as = AGOK, + .from = { + .type = D_NONE, + .index = D_NONE, + }, + .to = { + .type = D_NONE, + .index = D_NONE, + }, +}; + +static void +zname(Biobuf *b, LSym *s, int t) +{ + BPUTLE2(b, ANAME); /* as */ + BPUTC(b, t); /* type */ + BPUTC(b, s->symid); /* sym */ + Bwrite(b, s->name, strlen(s->name)+1); +} + +static void +zfile(Biobuf *b, char *p, int n) +{ + BPUTLE2(b, ANAME); + BPUTC(b, D_FILE); + BPUTC(b, 1); + BPUTC(b, '<'); + Bwrite(b, p, n); + BPUTC(b, 0); +} + +static void +zaddr(Biobuf *b, Addr *a, int s, int gotype) +{ + int32 l; + uint64 e; + int i, t; + char *n; + + t = 0; + if(a->index != D_NONE || a->scale != 0) + t |= T_INDEX; + if(s != 0) + t |= T_SYM; + if(gotype != 0) + t |= T_GOTYPE; + + switch(a->type) { + + case D_BRANCH: + if(a->offset == 0 || a->u.branch != nil) { + if(a->u.branch == nil) + sysfatal("unpatched branch %D", a); + a->offset = a->u.branch->loc; + } + + default: + t |= T_TYPE; + + case D_NONE: + if(a->offset != 0) { + t |= T_OFFSET; + l = a->offset; + if((vlong)l != a->offset) + t |= T_64; + } + break; + case D_FCONST: + t |= T_FCONST; + break; + case D_SCONST: + t |= T_SCONST; + break; + } + BPUTC(b, t); + + if(t & T_INDEX) { /* implies index, scale */ + BPUTC(b, a->index); + BPUTC(b, a->scale); + } + if(t & T_OFFSET) { /* implies offset */ + l = a->offset; + BPUTLE4(b, l); + if(t & T_64) { + l = a->offset>>32; + BPUTLE4(b, l); + } + } + if(t & T_SYM) /* implies sym */ + BPUTC(b, s); + if(t & T_FCONST) { + double2ieee(&e, a->u.dval); + BPUTLE4(b, e); + BPUTLE4(b, e >> 32); + return; + } + if(t & T_SCONST) { + n = a->u.sval; + for(i=0; i<NSNAME; i++) { + BPUTC(b, *n); + n++; + } + return; + } + if(t & T_TYPE) + BPUTC(b, a->type); + if(t & T_GOTYPE) + BPUTC(b, gotype); +} + +static void +zhist(Biobuf *b, int line, vlong offset) +{ + Addr a; + + BPUTLE2(b, AHISTORY); + BPUTLE4(b, line); + zaddr(b, &noaddr, 0, 0); + a = noaddr; + if(offset != 0) { + a.offset = offset; + a.type = D_CONST; + } + zaddr(b, &a, 0, 0); +} + +static int +symtype(Addr *a) +{ + int t; + + t = a->type; + if(t == D_ADDR) + t = a->index; + return t; +} + +static void +zprog(Link *ctxt, Biobuf *b, Prog *p, int sf, int gf, int st, int gt) +{ + USED(ctxt); + + BPUTLE2(b, p->as); + BPUTLE4(b, p->lineno); + zaddr(b, &p->from, sf, gf); + zaddr(b, &p->to, st, gt); +} + +static int +isdata(Prog *p) +{ + return p->as == ADATA || p->as == AGLOBL; +} + +static int +iscall(Prog *p) +{ + return p->as == ACALL; +} + +static int +datasize(Prog *p) +{ + return p->from.scale; +} + +static int +textflag(Prog *p) +{ + return p->from.scale; +} + +static void +settextflag(Prog *p, int f) +{ + p->from.scale = f; +} + +static void +progedit(Link *ctxt, Prog *p) +{ + Prog *q; + LSym *gmsym; + + gmsym = nil; // TODO + + if(ctxt->headtype == Hwindows) { + // Windows + // Convert + // op n(GS), reg + // to + // MOVL 0x28(GS), reg + // op n(reg), reg + // The purpose of this patch is to fix some accesses + // to extern register variables (TLS) on Windows, as + // a different method is used to access them. + if(p->from.type == D_INDIR+D_GS + && p->to.type >= D_AX && p->to.type <= D_DI + && p->from.offset <= 8) { + q = appendp(ctxt, p); + q->from = p->from; + q->from.type = D_INDIR + p->to.type; + q->to = p->to; + q->as = p->as; + p->as = AMOVQ; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0x28; + } + } + if(ctxt->headtype == Hlinux || ctxt->headtype == Hfreebsd + || ctxt->headtype == Hopenbsd || ctxt->headtype == Hnetbsd + || ctxt->headtype == Hplan9 || ctxt->headtype == Hdragonfly) { + // ELF uses FS instead of GS. + if(p->from.type == D_INDIR+D_GS) + p->from.type = D_INDIR+D_FS; + if(p->to.type == D_INDIR+D_GS) + p->to.type = D_INDIR+D_FS; + if(p->from.index == D_GS) + p->from.index = D_FS; + if(p->to.index == D_GS) + p->to.index = D_FS; + } + if(!ctxt->flag_shared) { + // Convert g() or m() accesses of the form + // op n(reg)(GS*1), reg + // to + // op n(GS*1), reg + if(p->from.index == D_FS || p->from.index == D_GS) { + p->from.type = D_INDIR + p->from.index; + p->from.index = D_NONE; + } + // Convert g() or m() accesses of the form + // op reg, n(reg)(GS*1) + // to + // op reg, n(GS*1) + if(p->to.index == D_FS || p->to.index == D_GS) { + p->to.type = D_INDIR + p->to.index; + p->to.index = D_NONE; + } + // Convert get_tls access of the form + // op runtime.tlsgm(SB), reg + // to + // NOP + if(gmsym != nil && p->from.sym == gmsym) { + p->as = ANOP; + p->from.type = D_NONE; + p->to.type = D_NONE; + p->from.sym = nil; + p->to.sym = nil; + return; + } + } else { + /* + // Convert TLS reads of the form + // op n(GS), reg + // to + // MOVQ $runtime.tlsgm(SB), reg + // op n(reg)(GS*1), reg + if((p->from.type == D_INDIR+D_FS || p->from.type == D_INDIR + D_GS) && p->to.type >= D_AX && p->to.type <= D_DI) { + q = appendp(ctxt, p); + q->to = p->to; + q->as = p->as; + q->from.type = D_INDIR+p->to.type; + q->from.index = p->from.type - D_INDIR; + q->from.scale = 1; + q->from.offset = p->from.offset; + p->as = AMOVQ; + p->from.type = D_EXTERN; + p->from.sym = gmsym; + p->from.offset = 0; + } + */ + } +} + +static char* +morename[] = +{ + "runtime.morestack00", + "runtime.morestack10", + "runtime.morestack01", + "runtime.morestack11", + + "runtime.morestack8", + "runtime.morestack16", + "runtime.morestack24", + "runtime.morestack32", + "runtime.morestack40", + "runtime.morestack48", +}; + +static Prog* load_g_cx(Link*, Prog*); +static Prog* stacksplit(Link*, Prog*, int32, int32, Prog**); + +static void +parsetextconst(vlong arg, vlong *textstksiz, vlong *textarg) +{ + *textstksiz = arg & 0xffffffffLL; + if(*textstksiz & 0x80000000LL) + *textstksiz = -(-*textstksiz & 0xffffffffLL); + + *textarg = (arg >> 32) & 0xffffffffLL; + if(*textarg & 0x80000000LL) + *textarg = 0; + *textarg = (*textarg+7) & ~7LL; +} + +static void +addstacksplit(Link *ctxt, LSym *cursym) +{ + Prog *p, *q, *q1; + int32 autoffset, deltasp; + int a, pcsize; + uint32 i; + vlong textstksiz, textarg; + + if(ctxt->gmsym == nil) { + ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0); + if(nelem(morename) > nelem(ctxt->symmorestack)) + sysfatal("Link.symmorestack needs at least %d elements", nelem(morename)); + for(i=0; i<nelem(morename); i++) + ctxt->symmorestack[i] = linklookup(ctxt, morename[i], 0); + } + ctxt->cursym = cursym; + + if(cursym->text == nil || cursym->text->link == nil) + return; + + p = cursym->text; + parsetextconst(p->to.offset, &textstksiz, &textarg); + autoffset = textstksiz; + if(autoffset < 0) + autoffset = 0; + + if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) { + for(q = p; q != nil; q = q->link) + if(q->as == ACALL) + goto noleaf; + p->from.scale |= NOSPLIT; + noleaf:; + } + + if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) + ctxt->diag("nosplit func likely to overflow stack"); + + q = nil; + if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) { + p = appendp(ctxt, p); + p = load_g_cx(ctxt, p); // load g into CX + } + if(!(cursym->text->from.scale & NOSPLIT)) + p = stacksplit(ctxt, p, autoffset, textarg, &q); // emit split check + + if(autoffset) { + p = appendp(ctxt, p); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = autoffset; + p->spadj = autoffset; + } else { + // zero-byte stack adjustment. + // Insert a fake non-zero adjustment so that stkcheck can + // recognize the end of the stack-splitting prolog. + p = appendp(ctxt, p); + p->as = ANOP; + p->spadj = -ctxt->arch->ptrsize; + p = appendp(ctxt, p); + p->as = ANOP; + p->spadj = ctxt->arch->ptrsize; + } + if(q != nil) + q->pcond = p; + deltasp = autoffset; + + if(cursym->text->from.scale & WRAPPER) { + // g->panicwrap += autoffset + ctxt->arch->ptrsize; + p = appendp(ctxt, p); + p->as = AADDL; + p->from.type = D_CONST; + p->from.offset = autoffset + ctxt->arch->ptrsize; + p->to.type = D_INDIR+D_CX; + p->to.offset = 2*ctxt->arch->ptrsize; + } + + if(ctxt->debugstack > 1 && autoffset) { + // 6l -K -K means double-check for stack overflow + // even after calling morestack and even if the + // function is marked as nosplit. + p = appendp(ctxt, p); + p->as = AMOVQ; + p->from.type = D_INDIR+D_CX; + p->from.offset = 0; + p->to.type = D_BX; + + p = appendp(ctxt, p); + p->as = ASUBQ; + p->from.type = D_CONST; + p->from.offset = StackSmall+32; + p->to.type = D_BX; + + p = appendp(ctxt, p); + p->as = ACMPQ; + p->from.type = D_SP; + p->to.type = D_BX; + + p = appendp(ctxt, p); + p->as = AJHI; + p->to.type = D_BRANCH; + q1 = p; + + p = appendp(ctxt, p); + p->as = AINT; + p->from.type = D_CONST; + p->from.offset = 3; + + p = appendp(ctxt, p); + p->as = ANOP; + q1->pcond = p; + } + + if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) { + // 6l -Z means zero the stack frame on entry. + // This slows down function calls but can help avoid + // false positives in garbage collection. + p = appendp(ctxt, p); + p->as = AMOVQ; + p->from.type = D_SP; + p->to.type = D_DI; + + p = appendp(ctxt, p); + p->as = AMOVQ; + p->from.type = D_CONST; + p->from.offset = autoffset/8; + p->to.type = D_CX; + + p = appendp(ctxt, p); + p->as = AMOVQ; + p->from.type = D_CONST; + p->from.offset = 0; + p->to.type = D_AX; + + p = appendp(ctxt, p); + p->as = AREP; + + p = appendp(ctxt, p); + p->as = ASTOSQ; + } + + for(; p != nil; p = p->link) { + pcsize = p->mode/8; + a = p->from.type; + if(a == D_AUTO) + p->from.offset += deltasp; + if(a == D_PARAM) + p->from.offset += deltasp + pcsize; + a = p->to.type; + if(a == D_AUTO) + p->to.offset += deltasp; + if(a == D_PARAM) + p->to.offset += deltasp + pcsize; + + switch(p->as) { + default: + continue; + case APUSHL: + case APUSHFL: + deltasp += 4; + p->spadj = 4; + continue; + case APUSHQ: + case APUSHFQ: + deltasp += 8; + p->spadj = 8; + continue; + case APUSHW: + case APUSHFW: + deltasp += 2; + p->spadj = 2; + continue; + case APOPL: + case APOPFL: + deltasp -= 4; + p->spadj = -4; + continue; + case APOPQ: + case APOPFQ: + deltasp -= 8; + p->spadj = -8; + continue; + case APOPW: + case APOPFW: + deltasp -= 2; + p->spadj = -2; + continue; + case ARET: + break; + } + + if(autoffset != deltasp) + ctxt->diag("unbalanced PUSH/POP"); + + if(cursym->text->from.scale & WRAPPER) { + p = load_g_cx(ctxt, p); + p = appendp(ctxt, p); + // g->panicwrap -= autoffset + ctxt->arch->ptrsize; + p->as = ASUBL; + p->from.type = D_CONST; + p->from.offset = autoffset + ctxt->arch->ptrsize; + p->to.type = D_INDIR+D_CX; + p->to.offset = 2*ctxt->arch->ptrsize; + p = appendp(ctxt, p); + p->as = ARET; + } + + if(autoffset) { + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = -autoffset; + p->spadj = -autoffset; + p = appendp(ctxt, p); + p->as = ARET; + // If there are instructions following + // this ARET, they come from a branch + // with the same stackframe, so undo + // the cleanup. + p->spadj = +autoffset; + } + if(p->to.sym) // retjmp + p->as = AJMP; + } +} + +// Append code to p to load g into cx. +// Overwrites p with the first instruction (no first appendp). +// Overwriting p is unusual but it lets use this in both the +// prologue (caller must call appendp first) and in the epilogue. +// Returns last new instruction. +static Prog* +load_g_cx(Link *ctxt, Prog *p) +{ + if(ctxt->flag_shared) { + // Load TLS offset with MOVQ $runtime.tlsgm(SB), CX + p->as = AMOVQ; + p->from.type = D_EXTERN; + p->from.sym = ctxt->gmsym; + p->to.type = D_CX; + p = appendp(ctxt, p); + } + p->as = AMOVQ; + if(ctxt->headtype == Hlinux || ctxt->headtype == Hfreebsd + || ctxt->headtype == Hopenbsd || ctxt->headtype == Hnetbsd + || ctxt->headtype == Hplan9 || ctxt->headtype == Hdragonfly) + // ELF uses FS + p->from.type = D_INDIR+D_FS; + else + p->from.type = D_INDIR+D_GS; + if(ctxt->flag_shared) { + // Add TLS offset stored in CX + p->from.index = p->from.type - D_INDIR; + p->from.type = D_INDIR + D_CX; + } + p->from.offset = ctxt->tlsoffset+0; + p->to.type = D_CX; + if(ctxt->headtype == Hwindows) { + // movq %gs:0x28, %rcx + // movq (%rcx), %rcx + p->as = AMOVQ; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0x28; + p->to.type = D_CX; + + p = appendp(ctxt, p); + p->as = AMOVQ; + p->from.type = D_INDIR+D_CX; + p->from.offset = 0; + p->to.type = D_CX; + } + return p; +} + +// Append code to p to check for stack split. +// Appends to (does not overwrite) p. +// Assumes g is in CX. +// Returns last new instruction. +// On return, *jmpok is the instruction that should jump +// to the stack frame allocation if no split is needed. +static Prog* +stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, Prog **jmpok) +{ + Prog *q, *q1; + uint32 moreconst1, moreconst2, i; + + if(ctxt->debugstack) { + // 6l -K means check not only for stack + // overflow but stack underflow. + // On underflow, INT 3 (breakpoint). + // Underflow itself is rare but this also + // catches out-of-sync stack guard info + + p = appendp(ctxt, p); + p->as = ACMPQ; + p->from.type = D_INDIR+D_CX; + p->from.offset = 8; + p->to.type = D_SP; + + p = appendp(ctxt, p); + p->as = AJHI; + p->to.type = D_BRANCH; + p->to.offset = 4; + q1 = p; + + p = appendp(ctxt, p); + p->as = AINT; + p->from.type = D_CONST; + p->from.offset = 3; + + p = appendp(ctxt, p); + p->as = ANOP; + q1->pcond = p; + } + + q = nil; + q1 = nil; + if(framesize <= StackSmall) { + // small stack: SP <= stackguard + // CMPQ SP, stackguard + p = appendp(ctxt, p); + p->as = ACMPQ; + p->from.type = D_SP; + p->to.type = D_INDIR+D_CX; + } else if(framesize <= StackBig) { + // large stack: SP-framesize <= stackguard-StackSmall + // LEAQ -xxx(SP), AX + // CMPQ AX, stackguard + p = appendp(ctxt, p); + p->as = ALEAQ; + p->from.type = D_INDIR+D_SP; + p->from.offset = -(framesize-StackSmall); + p->to.type = D_AX; + + p = appendp(ctxt, p); + p->as = ACMPQ; + p->from.type = D_AX; + p->to.type = D_INDIR+D_CX; + } else { + // Such a large stack we need to protect against wraparound. + // If SP is close to zero: + // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) + // The +StackGuard on both sides is required to keep the left side positive: + // SP is allowed to be slightly below stackguard. See stack.h. + // + // Preemption sets stackguard to StackPreempt, a very large value. + // That breaks the math above, so we have to check for that explicitly. + // MOVQ stackguard, CX + // CMPQ CX, $StackPreempt + // JEQ label-of-call-to-morestack + // LEAQ StackGuard(SP), AX + // SUBQ CX, AX + // CMPQ AX, $(framesize+(StackGuard-StackSmall)) + + p = appendp(ctxt, p); + p->as = AMOVQ; + p->from.type = D_INDIR+D_CX; + p->from.offset = 0; + p->to.type = D_SI; + + p = appendp(ctxt, p); + p->as = ACMPQ; + p->from.type = D_SI; + p->to.type = D_CONST; + p->to.offset = StackPreempt; + + p = appendp(ctxt, p); + p->as = AJEQ; + p->to.type = D_BRANCH; + q1 = p; + + p = appendp(ctxt, p); + p->as = ALEAQ; + p->from.type = D_INDIR+D_SP; + p->from.offset = StackGuard; + p->to.type = D_AX; + + p = appendp(ctxt, p); + p->as = ASUBQ; + p->from.type = D_SI; + p->to.type = D_AX; + + p = appendp(ctxt, p); + p->as = ACMPQ; + p->from.type = D_AX; + p->to.type = D_CONST; + p->to.offset = framesize+(StackGuard-StackSmall); + } + + // common + p = appendp(ctxt, p); + p->as = AJHI; + p->to.type = D_BRANCH; + q = p; + + // If we ask for more stack, we'll get a minimum of StackMin bytes. + // We need a stack frame large enough to hold the top-of-stack data, + // the function arguments+results, our caller's PC, our frame, + // a word for the return PC of the next call, and then the StackLimit bytes + // that must be available on entry to any function called from a function + // that did a stack check. If StackMin is enough, don't ask for a specific + // amount: then we can use the custom functions and save a few + // instructions. + moreconst1 = 0; + if(StackTop + textarg + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin) + moreconst1 = framesize; + moreconst2 = textarg; + if(moreconst2 == 1) // special marker + moreconst2 = 0; + if((moreconst2&7) != 0) + ctxt->diag("misaligned argument size in stack split"); + // 4 varieties varieties (const1==0 cross const2==0) + // and 6 subvarieties of (const1==0 and const2!=0) + p = appendp(ctxt, p); + if(moreconst1 == 0 && moreconst2 == 0) { + p->as = ACALL; + p->to.type = D_BRANCH; + p->to.sym = ctxt->symmorestack[0]; + } else + if(moreconst1 != 0 && moreconst2 == 0) { + p->as = AMOVL; + p->from.type = D_CONST; + p->from.offset = moreconst1; + p->to.type = D_AX; + + p = appendp(ctxt, p); + p->as = ACALL; + p->to.type = D_BRANCH; + p->to.sym = ctxt->symmorestack[1]; + } else + if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { + i = moreconst2/8 + 3; + p->as = ACALL; + p->to.type = D_BRANCH; + p->to.sym = ctxt->symmorestack[i]; + } else + if(moreconst1 == 0 && moreconst2 != 0) { + p->as = AMOVL; + p->from.type = D_CONST; + p->from.offset = moreconst2; + p->to.type = D_AX; + + p = appendp(ctxt, p); + p->as = ACALL; + p->to.type = D_BRANCH; + p->to.sym = ctxt->symmorestack[2]; + } else { + p->as = AMOVQ; + p->from.type = D_CONST; + p->from.offset = (uint64)moreconst2 << 32; + p->from.offset |= moreconst1; + p->to.type = D_AX; + + p = appendp(ctxt, p); + p->as = ACALL; + p->to.type = D_BRANCH; + p->to.sym = ctxt->symmorestack[3]; + } + + p = appendp(ctxt, p); + p->as = AJMP; + p->to.type = D_BRANCH; + p->pcond = ctxt->cursym->text->link; + + if(q != nil) + q->pcond = p->link; + if(q1 != nil) + q1->pcond = q->link; + + *jmpok = q; + return p; +} + +static void xfol(Link*, Prog*, Prog**); + +static void +follow(Link *ctxt, LSym *s) +{ + Prog *firstp, *lastp; + + ctxt->cursym = s; + + firstp = ctxt->arch->prg(); + lastp = firstp; + xfol(ctxt, s->text, &lastp); + lastp->link = nil; + s->text = firstp->link; +} + +static int +nofollow(int a) +{ + switch(a) { + case AJMP: + case ARET: + case AIRETL: + case AIRETQ: + case AIRETW: + case ARETFL: + case ARETFQ: + case ARETFW: + case AUNDEF: + return 1; + } + return 0; +} + +static int +pushpop(int a) +{ + switch(a) { + case APUSHL: + case APUSHFL: + case APUSHQ: + case APUSHFQ: + case APUSHW: + case APUSHFW: + case APOPL: + case APOPFL: + case APOPQ: + case APOPFQ: + case APOPW: + case APOPFW: + return 1; + } + return 0; +} + +static 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; + } + sysfatal("unknown relation: %s", anames6[a]); + return 0; +} + +static void +xfol(Link *ctxt, Prog *p, Prog **last) +{ + Prog *q; + int i; + enum as a; + +loop: + if(p == nil) + return; + if(p->as == AJMP) + if((q = p->pcond) != nil && q->as != ATEXT) { + /* mark instruction as done and continue layout at target of jump */ + p->mark = 1; + p = q; + if(p->mark == 0) + goto loop; + } + if(p->mark) { + /* + * p goes here, but already used it elsewhere. + * copy up to 4 instructions or else branch to other copy. + */ + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == nil) + break; + if(q == *last) + break; + a = q->as; + if(a == ANOP) { + i--; + continue; + } + if(nofollow(a) || pushpop(a)) + break; // NOTE(rsc): arm does goto copy + if(q->pcond == nil || q->pcond->mark) + continue; + if(a == ACALL || a == ALOOP) + continue; + for(;;) { + if(p->as == ANOP) { + p = p->link; + continue; + } + q = copyp(ctxt, p); + p = p->link; + q->mark = 1; + (*last)->link = q; + *last = q; + if(q->as != a || q->pcond == nil || q->pcond->mark) + continue; + + q->as = relinv(q->as); + p = q->pcond; + q->pcond = q->link; + q->link = p; + xfol(ctxt, q->link, last); + p = q->link; + if(p->mark) + return; + goto loop; + } + } /* */ + q = ctxt->arch->prg(); + q->as = AJMP; + q->lineno = p->lineno; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->pcond = p; + p = q; + } + + /* emit p */ + p->mark = 1; + (*last)->link = p; + *last = p; + a = p->as; + + /* continue loop with what comes after p */ + if(nofollow(a)) + return; + if(p->pcond != nil && a != ACALL) { + /* + * some kind of conditional branch. + * recurse to follow one path. + * continue loop on the other. + */ + if((q = brchain(ctxt, p->pcond)) != nil) + p->pcond = q; + if((q = brchain(ctxt, p->link)) != nil) + p->link = q; + if(p->from.type == D_CONST) { + if(p->from.offset == 1) { + /* + * expect conditional jump to be taken. + * rewrite so that's the fall-through case. + */ + p->as = relinv(a); + q = p->link; + p->link = p->pcond; + p->pcond = q; + } + } else { + q = p->link; + if(q->mark) + if(a != ALOOP) { + p->as = relinv(a); + p->link = p->pcond; + p->pcond = q; + } + } + xfol(ctxt, p->link, last); + if(p->pcond->mark) + return; + p = p->pcond; + goto loop; + } + p = p->link; + goto loop; +} + +static Prog* +prg(void) +{ + Prog *p; + + p = emallocz(sizeof(*p)); + *p = zprg; + return p; +} + +LinkArch linkamd64 = { + .name = "amd64", + + .zprog = zprog, + .zhist = zhist, + .zfile = zfile, + .zname = zname, + .isdata = isdata, + .ldobj = ldobj6, + .nopout = nopout6, + .symtype = symtype, + .iscall = iscall, + .datasize = datasize, + .textflag = textflag, + .settextflag = settextflag, + .progedit = progedit, + .prg = prg, + .addstacksplit = addstacksplit, + .assemble = span6, + .follow = follow, + + .minlc = 1, + .ptrsize = 8, + + .D_ADDR = D_ADDR, + .D_BRANCH = D_BRANCH, + .D_CONST = D_CONST, + .D_EXTERN = D_EXTERN, + .D_FCONST = D_FCONST, + .D_NONE = D_NONE, + .D_PCREL = D_PCREL, + .D_SCONST = D_SCONST, + .D_SIZE = D_SIZE, + + .ACALL = ACALL, + .AFUNCDATA = AFUNCDATA, + .AJMP = AJMP, + .ANOP = ANOP, + .APCDATA = APCDATA, + .ARET = ARET, + .ATEXT = ATEXT, + .AUSEFIELD = AUSEFIELD, +}; diff --git a/src/liblink/obj8.c b/src/liblink/obj8.c new file mode 100644 index 000000000..e744abe55 --- /dev/null +++ b/src/liblink/obj8.c @@ -0,0 +1,937 @@ +// 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 <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> +#include "../cmd/8l/8.out.h" +#include "../pkg/runtime/stack.h" + +static Addr noaddr = { + .type = D_NONE, + .index = D_NONE, + .scale = 1, +}; + +static Prog zprg = { + .back = 2, + .as = AGOK, + .from = { + .type = D_NONE, + .index = D_NONE, + .scale = 1, + }, + .to = { + .type = D_NONE, + .index = D_NONE, + .scale = 1, + }, +}; + +static void +zname(Biobuf *b, LSym *s, int t) +{ + BPUTLE2(b, ANAME); /* as */ + BPUTC(b, t); /* type */ + BPUTC(b, s->symid); /* sym */ + Bwrite(b, s->name, strlen(s->name)+1); +} + +static void +zfile(Biobuf *b, char *p, int n) +{ + BPUTLE2(b, ANAME); + BPUTC(b, D_FILE); + BPUTC(b, 1); + BPUTC(b, '<'); + Bwrite(b, p, n); + BPUTC(b, 0); +} + +static void +zaddr(Biobuf *b, Addr *a, int s, int gotype) +{ + int32 l; + uint64 e; + int i, t; + char *n; + + t = 0; + if(a->index != D_NONE || a->scale != 0) + t |= T_INDEX; + if(s != 0) + t |= T_SYM; + if(gotype != 0) + t |= T_GOTYPE; + + switch(a->type) { + + case D_BRANCH: + if(a->offset == 0 || a->u.branch != nil) { + if(a->u.branch == nil) + sysfatal("unpatched branch %D", a); + a->offset = a->u.branch->loc; + } + + default: + t |= T_TYPE; + + case D_NONE: + if(a->offset != 0) + t |= T_OFFSET; + if(a->offset2 != 0) + t |= T_OFFSET2; + break; + case D_FCONST: + t |= T_FCONST; + break; + case D_SCONST: + t |= T_SCONST; + break; + } + BPUTC(b, t); + + if(t & T_INDEX) { /* implies index, scale */ + BPUTC(b, a->index); + BPUTC(b, a->scale); + } + if(t & T_OFFSET) { /* implies offset */ + l = a->offset; + BPUTLE4(b, l); + } + if(t & T_OFFSET2) { /* implies offset */ + l = a->offset2; + BPUTLE4(b, l); + } + if(t & T_SYM) /* implies sym */ + BPUTC(b, s); + if(t & T_FCONST) { + double2ieee(&e, a->u.dval); + BPUTLE4(b, e); + BPUTLE4(b, e >> 32); + return; + } + if(t & T_SCONST) { + n = a->u.sval; + for(i=0; i<NSNAME; i++) { + BPUTC(b, *n); + n++; + } + return; + } + if(t & T_TYPE) + BPUTC(b, a->type); + if(t & T_GOTYPE) + BPUTC(b, gotype); +} + +static void +zhist(Biobuf *b, int line, vlong offset) +{ + Addr a; + + BPUTLE2(b, AHISTORY); + BPUTLE4(b, line); + zaddr(b, &noaddr, 0, 0); + a = noaddr; + if(offset != 0) { + a.offset = offset; + a.type = D_CONST; + } + zaddr(b, &a, 0, 0); +} + +static int +symtype(Addr *a) +{ + int t; + + t = a->type; + if(t == D_ADDR) + t = a->index; + return t; +} + +static void +zprog(Link *ctxt, Biobuf *b, Prog *p, int sf, int gf, int st, int gt) +{ + USED(ctxt); + + BPUTLE2(b, p->as); + BPUTLE4(b, p->lineno); + zaddr(b, &p->from, sf, gf); + zaddr(b, &p->to, st, gt); +} + +static int +isdata(Prog *p) +{ + return p->as == ADATA || p->as == AGLOBL; +} + +static int +iscall(Prog *p) +{ + return p->as == ACALL; +} + +static int +datasize(Prog *p) +{ + return p->from.scale; +} + +static int +textflag(Prog *p) +{ + return p->from.scale; +} + +static void +settextflag(Prog *p, int f) +{ + p->from.scale = f; +} + +static void +progedit(Link *ctxt, Prog *p) +{ + Prog *q; + + if(ctxt->headtype == Hwindows) { + // Convert + // op n(GS), reg + // to + // MOVL 0x14(FS), reg + // op n(reg), reg + // The purpose of this patch is to fix some accesses + // to extern register variables (TLS) on Windows, as + // a different method is used to access them. + if(p->from.type == D_INDIR+D_GS + && p->to.type >= D_AX && p->to.type <= D_DI) { + q = appendp(ctxt, p); + q->from = p->from; + q->from.type = D_INDIR + p->to.type; + q->to = p->to; + q->as = p->as; + p->as = AMOVL; + p->from.type = D_INDIR+D_FS; + p->from.offset = 0x14; + } + } + if(ctxt->headtype == Hlinux) { + // Running binaries under Xen requires using + // MOVL 0(GS), reg + // and then off(reg) instead of saying off(GS) directly + // when the offset is negative. + // In external mode we just produce a reloc. + if(p->from.type == D_INDIR+D_GS && p->from.offset < 0 + && p->to.type >= D_AX && p->to.type <= D_DI) { + if(ctxt->linkmode != LinkExternal) { + q = appendp(ctxt, p); + q->from = p->from; + q->from.type = D_INDIR + p->to.type; + q->to = p->to; + q->as = p->as; + p->as = AMOVL; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0; + } else { + // Add signals to relocate. + p->from.index = D_GS; + p->from.scale = 1; + } + } + } + /* TODO + if(ctxt->headtype == Hplan9) { + if(p->from.type == D_INDIR+D_GS + && p->to.type >= D_AX && p->to.type <= D_DI) { + q = appendp(ctxt, p); + q->from = p->from; + q->from.type = D_INDIR + p->to.type; + q->to = p->to; + q->as = p->as; + p->as = AMOVL; + p->from.type = D_EXTERN; + p->from.sym = plan9_tos; + p->from.offset = 0; + } + } + */ +} + +static Prog* +prg(void) +{ + Prog *p; + + p = emallocz(sizeof(*p)); + *p = zprg; + return p; +} + +static Prog* load_g_cx(Link*, Prog*); +static Prog* stacksplit(Link*, Prog*, int32, Prog**); + +static void +addstacksplit(Link *ctxt, LSym *cursym) +{ + Prog *p, *q; + int32 autoffset, deltasp; + int a; + + if(ctxt->symmorestack[0] == nil) + ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0); + + if(ctxt->headtype == Hplan9 && ctxt->plan9tos == nil) + ctxt->plan9tos = linklookup(ctxt, "_tos", 0); + + ctxt->cursym = cursym; + + if(cursym->text == nil || cursym->text->link == nil) + return; + + p = cursym->text; + autoffset = p->to.offset; + if(autoffset < 0) + autoffset = 0; + + q = nil; + + if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) { + p = appendp(ctxt, p); + p = load_g_cx(ctxt, p); // load g into CX + } + if(!(cursym->text->from.scale & NOSPLIT)) + p = stacksplit(ctxt, p, autoffset, &q); // emit split check + + if(autoffset) { + p = appendp(ctxt, p); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = autoffset; + p->spadj = autoffset; + } else { + // zero-byte stack adjustment. + // Insert a fake non-zero adjustment so that stkcheck can + // recognize the end of the stack-splitting prolog. + p = appendp(ctxt, p); + p->as = ANOP; + p->spadj = -ctxt->arch->ptrsize; + p = appendp(ctxt, p); + p->as = ANOP; + p->spadj = ctxt->arch->ptrsize; + } + if(q != nil) + q->pcond = p; + deltasp = autoffset; + + if(cursym->text->from.scale & WRAPPER) { + // g->panicwrap += autoffset + ctxt->arch->ptrsize; + p = appendp(ctxt, p); + p->as = AADDL; + p->from.type = D_CONST; + p->from.offset = autoffset + ctxt->arch->ptrsize; + p->to.type = D_INDIR+D_CX; + p->to.offset = 2*ctxt->arch->ptrsize; + } + + if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) { + // 8l -Z means zero the stack frame on entry. + // This slows down function calls but can help avoid + // false positives in garbage collection. + p = appendp(ctxt, p); + p->as = AMOVL; + p->from.type = D_SP; + p->to.type = D_DI; + + p = appendp(ctxt, p); + p->as = AMOVL; + p->from.type = D_CONST; + p->from.offset = autoffset/4; + p->to.type = D_CX; + + p = appendp(ctxt, p); + p->as = AMOVL; + p->from.type = D_CONST; + p->from.offset = 0; + p->to.type = D_AX; + + p = appendp(ctxt, p); + p->as = AREP; + + p = appendp(ctxt, p); + p->as = ASTOSL; + } + + for(; p != nil; p = p->link) { + 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; + p->spadj = 4; + continue; + case APUSHW: + case APUSHFW: + deltasp += 2; + p->spadj = 2; + continue; + case APOPL: + case APOPFL: + deltasp -= 4; + p->spadj = -4; + continue; + case APOPW: + case APOPFW: + deltasp -= 2; + p->spadj = -2; + continue; + case ARET: + break; + } + + if(autoffset != deltasp) + ctxt->diag("unbalanced PUSH/POP"); + + if(cursym->text->from.scale & WRAPPER) { + p = load_g_cx(ctxt, p); + p = appendp(ctxt, p); + // g->panicwrap -= autoffset + ctxt->arch->ptrsize; + p->as = ASUBL; + p->from.type = D_CONST; + p->from.offset = autoffset + ctxt->arch->ptrsize; + p->to.type = D_INDIR+D_CX; + p->to.offset = 2*ctxt->arch->ptrsize; + p = appendp(ctxt, p); + p->as = ARET; + } + + if(autoffset) { + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = -autoffset; + p->spadj = -autoffset; + p = appendp(ctxt, p); + p->as = ARET; + // If there are instructions following + // this ARET, they come from a branch + // with the same stackframe, so undo + // the cleanup. + p->spadj = +autoffset; + } + if(p->to.sym) // retjmp + p->as = AJMP; + } +} + +// Append code to p to load g into cx. +// Overwrites p with the first instruction (no first appendp). +// Overwriting p is unusual but it lets use this in both the +// prologue (caller must call appendp first) and in the epilogue. +// Returns last new instruction. +static Prog* +load_g_cx(Link *ctxt, Prog *p) +{ + switch(ctxt->headtype) { + case Hwindows: + p->as = AMOVL; + p->from.type = D_INDIR+D_FS; + p->from.offset = 0x14; + p->to.type = D_CX; + + p = appendp(ctxt, p); + p->as = AMOVL; + p->from.type = D_INDIR+D_CX; + p->from.offset = 0; + p->to.type = D_CX; + break; + + case Hlinux: + if(ctxt->linkmode != LinkExternal) { + p->as = AMOVL; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0; + p->to.type = D_CX; + + p = appendp(ctxt, p); + p->as = AMOVL; + p->from.type = D_INDIR+D_CX; + p->from.offset = ctxt->tlsoffset + 0; + p->to.type = D_CX; + } else { + p->as = AMOVL; + p->from.type = D_INDIR+D_GS; + p->from.offset = ctxt->tlsoffset + 0; + p->to.type = D_CX; + p->from.index = D_GS; + p->from.scale = 1; + } + break; + + case Hplan9: + p->as = AMOVL; + p->from.type = D_EXTERN; + p->from.sym = ctxt->plan9tos; + p->to.type = D_CX; + + p = appendp(ctxt, p); + p->as = AMOVL; + p->from.type = D_INDIR+D_CX; + p->from.offset = ctxt->tlsoffset + 0; + p->to.type = D_CX; + break; + + default: + p->as = AMOVL; + p->from.type = D_INDIR+D_GS; + p->from.offset = ctxt->tlsoffset + 0; + p->to.type = D_CX; + } + return p; +} + +// Append code to p to check for stack split. +// Appends to (does not overwrite) p. +// Assumes g is in CX. +// Returns last new instruction. +// On return, *jmpok is the instruction that should jump +// to the stack frame allocation if no split is needed. +static Prog* +stacksplit(Link *ctxt, Prog *p, int32 framesize, Prog **jmpok) +{ + Prog *q, *q1; + int arg; + + if(ctxt->debugstack) { + // 8l -K means check not only for stack + // overflow but stack underflow. + // On underflow, INT 3 (breakpoint). + // Underflow itself is rare but this also + // catches out-of-sync stack guard info. + p = appendp(ctxt, p); + p->as = ACMPL; + p->from.type = D_INDIR+D_CX; + p->from.offset = 4; + p->to.type = D_SP; + + p = appendp(ctxt, p); + p->as = AJCC; + p->to.type = D_BRANCH; + p->to.offset = 4; + q1 = p; + + p = appendp(ctxt, p); + p->as = AINT; + p->from.type = D_CONST; + p->from.offset = 3; + + p = appendp(ctxt, p); + p->as = ANOP; + q1->pcond = p; + } + q1 = nil; + + if(framesize <= StackSmall) { + // small stack: SP <= stackguard + // CMPL SP, stackguard + p = appendp(ctxt, p); + p->as = ACMPL; + p->from.type = D_SP; + p->to.type = D_INDIR+D_CX; + } else if(framesize <= StackBig) { + // large stack: SP-framesize <= stackguard-StackSmall + // LEAL -(framesize-StackSmall)(SP), AX + // CMPL AX, stackguard + p = appendp(ctxt, p); + p->as = ALEAL; + p->from.type = D_INDIR+D_SP; + p->from.offset = -(framesize-StackSmall); + p->to.type = D_AX; + + p = appendp(ctxt, p); + p->as = ACMPL; + p->from.type = D_AX; + p->to.type = D_INDIR+D_CX; + } else { + // Such a large stack we need to protect against wraparound + // if SP is close to zero. + // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) + // The +StackGuard on both sides is required to keep the left side positive: + // SP is allowed to be slightly below stackguard. See stack.h. + // + // Preemption sets stackguard to StackPreempt, a very large value. + // That breaks the math above, so we have to check for that explicitly. + // MOVL stackguard, CX + // CMPL CX, $StackPreempt + // JEQ label-of-call-to-morestack + // LEAL StackGuard(SP), AX + // SUBL stackguard, AX + // CMPL AX, $(framesize+(StackGuard-StackSmall)) + p = appendp(ctxt, p); + p->as = AMOVL; + p->from.type = D_INDIR+D_CX; + p->from.offset = 0; + p->to.type = D_SI; + + p = appendp(ctxt, p); + p->as = ACMPL; + p->from.type = D_SI; + p->to.type = D_CONST; + p->to.offset = (uint32)StackPreempt; + + p = appendp(ctxt, p); + p->as = AJEQ; + p->to.type = D_BRANCH; + q1 = p; + + p = appendp(ctxt, p); + p->as = ALEAL; + p->from.type = D_INDIR+D_SP; + p->from.offset = StackGuard; + p->to.type = D_AX; + + p = appendp(ctxt, p); + p->as = ASUBL; + p->from.type = D_SI; + p->from.offset = 0; + p->to.type = D_AX; + + p = appendp(ctxt, p); + p->as = ACMPL; + p->from.type = D_AX; + p->to.type = D_CONST; + p->to.offset = framesize+(StackGuard-StackSmall); + } + + // common + p = appendp(ctxt, p); + p->as = AJHI; + p->to.type = D_BRANCH; + p->to.offset = 4; + q = p; + + p = appendp(ctxt, p); // save frame size in DI + p->as = AMOVL; + p->to.type = D_DI; + p->from.type = D_CONST; + + // If we ask for more stack, we'll get a minimum of StackMin bytes. + // We need a stack frame large enough to hold the top-of-stack data, + // the function arguments+results, our caller's PC, our frame, + // a word for the return PC of the next call, and then the StackLimit bytes + // that must be available on entry to any function called from a function + // that did a stack check. If StackMin is enough, don't ask for a specific + // amount: then we can use the custom functions and save a few + // instructions. + if(StackTop + ctxt->cursym->text->to.offset2 + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin) + p->from.offset = (framesize+7) & ~7LL; + + arg = ctxt->cursym->text->to.offset2; + if(arg == 1) // special marker for known 0 + arg = 0; + if(arg&3) + ctxt->diag("misaligned argument size in stack split"); + p = appendp(ctxt, p); // save arg size in AX + p->as = AMOVL; + p->to.type = D_AX; + p->from.type = D_CONST; + p->from.offset = arg; + + p = appendp(ctxt, p); + p->as = ACALL; + p->to.type = D_BRANCH; + p->to.sym = ctxt->symmorestack[0]; + + p = appendp(ctxt, p); + p->as = AJMP; + p->to.type = D_BRANCH; + p->pcond = ctxt->cursym->text->link; + + if(q != nil) + q->pcond = p->link; + if(q1 != nil) + q1->pcond = q->link; + + *jmpok = q; + return p; +} + +static void xfol(Link*, Prog*, Prog**); + +static void +follow(Link *ctxt, LSym *s) +{ + Prog *firstp, *lastp; + + ctxt->cursym = s; + + firstp = ctxt->arch->prg(); + lastp = firstp; + xfol(ctxt, s->text, &lastp); + lastp->link = nil; + s->text = firstp->link; +} + +static int +nofollow(int a) +{ + switch(a) { + case AJMP: + case ARET: + case AIRETL: + case AIRETW: + case AUNDEF: + return 1; + } + return 0; +} + +static int +pushpop(int a) +{ + switch(a) { + case APUSHL: + case APUSHFL: + case APUSHW: + case APUSHFW: + case APOPL: + case APOPFL: + case APOPW: + case APOPFW: + return 1; + } + return 0; +} + +static 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; + } + sysfatal("unknown relation: %s", anames8[a]); + return 0; +} + +static void +xfol(Link *ctxt, Prog *p, Prog **last) +{ + Prog *q; + int i; + enum as a; + +loop: + if(p == nil) + return; + if(p->as == AJMP) + if((q = p->pcond) != nil && q->as != ATEXT) { + /* mark instruction as done and continue layout at target of jump */ + p->mark = 1; + p = q; + if(p->mark == 0) + goto loop; + } + if(p->mark) { + /* + * p goes here, but already used it elsewhere. + * copy up to 4 instructions or else branch to other copy. + */ + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == nil) + break; + if(q == *last) + break; + a = q->as; + if(a == ANOP) { + i--; + continue; + } + if(nofollow(a) || pushpop(a)) + break; // NOTE(rsc): arm does goto copy + if(q->pcond == nil || q->pcond->mark) + continue; + if(a == ACALL || a == ALOOP) + continue; + for(;;) { + if(p->as == ANOP) { + p = p->link; + continue; + } + q = copyp(ctxt, p); + p = p->link; + q->mark = 1; + (*last)->link = q; + *last = q; + if(q->as != a || q->pcond == nil || q->pcond->mark) + continue; + + q->as = relinv(q->as); + p = q->pcond; + q->pcond = q->link; + q->link = p; + xfol(ctxt, q->link, last); + p = q->link; + if(p->mark) + return; + goto loop; + } + } /* */ + q = ctxt->arch->prg(); + q->as = AJMP; + q->lineno = p->lineno; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->pcond = p; + p = q; + } + + /* emit p */ + p->mark = 1; + (*last)->link = p; + *last = p; + a = p->as; + + /* continue loop with what comes after p */ + if(nofollow(a)) + return; + if(p->pcond != nil && a != ACALL) { + /* + * some kind of conditional branch. + * recurse to follow one path. + * continue loop on the other. + */ + if((q = brchain(ctxt, p->pcond)) != nil) + p->pcond = q; + if((q = brchain(ctxt, p->link)) != nil) + p->link = q; + if(p->from.type == D_CONST) { + if(p->from.offset == 1) { + /* + * expect conditional jump to be taken. + * rewrite so that's the fall-through case. + */ + p->as = relinv(a); + q = p->link; + p->link = p->pcond; + p->pcond = q; + } + } else { + q = p->link; + if(q->mark) + if(a != ALOOP) { + p->as = relinv(a); + p->link = p->pcond; + p->pcond = q; + } + } + xfol(ctxt, p->link, last); + if(p->pcond->mark) + return; + p = p->pcond; + goto loop; + } + p = p->link; + goto loop; +} + +LinkArch link386 = { + .name = "386", + + .addstacksplit = addstacksplit, + .assemble = span8, + .datasize = datasize, + .follow = follow, + .iscall = iscall, + .isdata = isdata, + .ldobj = ldobj8, + .nopout = nopout8, + .prg = prg, + .progedit = progedit, + .settextflag = settextflag, + .symtype = symtype, + .textflag = textflag, + .zfile = zfile, + .zhist = zhist, + .zname = zname, + .zprog = zprog, + + .minlc = 1, + .ptrsize = 4, + + .D_ADDR = D_ADDR, + .D_BRANCH = D_BRANCH, + .D_CONST = D_CONST, + .D_EXTERN = D_EXTERN, + .D_FCONST = D_FCONST, + .D_NONE = D_NONE, + .D_PCREL = D_PCREL, + .D_SCONST = D_SCONST, + .D_SIZE = D_SIZE, + + .ACALL = ACALL, + .AFUNCDATA = AFUNCDATA, + .AJMP = AJMP, + .ANOP = ANOP, + .APCDATA = APCDATA, + .ARET = ARET, + .ATEXT = ATEXT, + .AUSEFIELD = AUSEFIELD, +}; diff --git a/src/liblink/pass.c b/src/liblink/pass.c new file mode 100644 index 000000000..3fe77d61b --- /dev/null +++ b/src/liblink/pass.c @@ -0,0 +1,115 @@ +// Inferno utils/6l/pass.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/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. + +// Code and data passes. + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> + +Prog* +brchain(Link *ctxt, Prog *p) +{ + int i; + + for(i=0; i<20; i++) { + if(p == nil || p->as != ctxt->arch->AJMP) + return p; + p = p->pcond; + } + return nil; +} + +Prog* +brloop(Link *ctxt, Prog *p) +{ + int c; + Prog *q; + + c = 0; + for(q = p; q != nil; q = q->pcond) { + if(q->as != ctxt->arch->AJMP) + break; + c++; + if(c >= 5000) + return nil; + } + return q; +} + +void +linkpatch(Link *ctxt, LSym *sym) +{ + int32 c; + Prog *p, *q; + LSym *s; + + ctxt->cursym = sym; + + for(p = sym->text; p != nil; p = p->link) { + if(ctxt->arch->progedit) + ctxt->arch->progedit(ctxt, p); + if(p->as == ctxt->arch->ACALL || (p->as == ctxt->arch->AJMP && p->to.type != ctxt->arch->D_BRANCH) || (p->as == ctxt->arch->ARET && p->to.sym != nil)) { + s = p->to.sym; + if(s) { + p->to.type = ctxt->arch->D_BRANCH; + continue; + } + } + if(p->to.type != ctxt->arch->D_BRANCH) + continue; + c = p->to.offset; + for(q = sym->text; q != nil;) { + if(c == q->pc) + break; + if(q->forwd != nil && c >= q->forwd->pc) + q = q->forwd; + else + q = q->link; + } + if(q == nil) { + ctxt->diag("branch out of range (%#ux)\n%P [%s]", + c, p, p->to.sym ? p->to.sym->name : "<nil>"); + p->to.type = ctxt->arch->D_NONE; + } + p->pcond = q; + } + + for(p = sym->text; p != nil; p = p->link) { + p->mark = 0; /* initialization for follow */ + if(p->pcond != nil) { + p->pcond = brloop(ctxt, p->pcond); + if(p->pcond != nil) + if(p->to.type == ctxt->arch->D_BRANCH) + p->to.offset = p->pcond->pc; + } + } +} diff --git a/src/liblink/pcln.c b/src/liblink/pcln.c new file mode 100644 index 000000000..21eb94414 --- /dev/null +++ b/src/liblink/pcln.c @@ -0,0 +1,298 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> + +static void +addvarint(Link *ctxt, Pcdata *d, uint32 val) +{ + int32 n; + uint32 v; + uchar *p; + + USED(ctxt); + + n = 0; + for(v = val; v >= 0x80; v >>= 7) + n++; + n++; + + if(d->n + n > d->m) { + d->m = (d->n + n)*2; + d->p = erealloc(d->p, d->m); + } + + p = d->p + d->n; + for(v = val; v >= 0x80; v >>= 7) + *p++ = v | 0x80; + *p++ = v; + d->n += n; +} + +// funcpctab writes to dst a pc-value table mapping the code in func to the values +// returned by valfunc parameterized by arg. The invocation of valfunc to update the +// current value is, for each p, +// +// val = valfunc(func, val, p, 0, arg); +// record val as value at p->pc; +// val = valfunc(func, val, p, 1, arg); +// +// where func is the function, val is the current value, p is the instruction being +// considered, and arg can be used to further parameterize valfunc. +static void +funcpctab(Link *ctxt, Pcdata *dst, LSym *func, char *desc, int32 (*valfunc)(Link*, LSym*, int32, Prog*, int32, void*), void* arg) +{ + int dbg, i; + int32 oldval, val, started; + uint32 delta; + vlong pc; + Prog *p; + + // To debug a specific function, uncomment second line and change name. + dbg = 0; + //dbg = strcmp(func->name, "main.main") == 0; + //dbg = strcmp(desc, "pctofile") == 0; + + ctxt->debugpcln += dbg; + + dst->n = 0; + + if(ctxt->debugpcln) + Bprint(ctxt->bso, "funcpctab %s [valfunc=%s]\n", func->name, desc); + + val = -1; + oldval = val; + if(func->text == nil) + return; + + pc = func->text->pc; + + if(ctxt->debugpcln) + Bprint(ctxt->bso, "%6llux %6d %P\n", pc, val, func->text); + + started = 0; + for(p=func->text; p != nil; p = p->link) { + // Update val. If it's not changing, keep going. + val = valfunc(ctxt, func, val, p, 0, arg); + if(val == oldval && started) { + val = valfunc(ctxt, func, val, p, 1, arg); + if(ctxt->debugpcln) + Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p); + continue; + } + + // If the pc of the next instruction is the same as the + // pc of this instruction, this instruction is not a real + // instruction. Keep going, so that we only emit a delta + // for a true instruction boundary in the program. + if(p->link && p->link->pc == p->pc) { + val = valfunc(ctxt, func, val, p, 1, arg); + if(ctxt->debugpcln) + Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p); + continue; + } + + // The table is a sequence of (value, pc) pairs, where each + // pair states that the given value is in effect from the current position + // up to the given pc, which becomes the new current position. + // To generate the table as we scan over the program instructions, + // we emit a "(value" when pc == func->value, and then + // each time we observe a change in value we emit ", pc) (value". + // When the scan is over, we emit the closing ", pc)". + // + // The table is delta-encoded. The value deltas are signed and + // transmitted in zig-zag form, where a complement bit is placed in bit 0, + // and the pc deltas are unsigned. Both kinds of deltas are sent + // as variable-length little-endian base-128 integers, + // where the 0x80 bit indicates that the integer continues. + + if(ctxt->debugpcln) + Bprint(ctxt->bso, "%6llux %6d %P\n", (vlong)p->pc, val, p); + + if(started) { + addvarint(ctxt, dst, (p->pc - pc) / ctxt->arch->minlc); + pc = p->pc; + } + delta = val - oldval; + if(delta>>31) + delta = 1 | ~(delta<<1); + else + delta <<= 1; + addvarint(ctxt, dst, delta); + oldval = val; + started = 1; + val = valfunc(ctxt, func, val, p, 1, arg); + } + + if(started) { + if(ctxt->debugpcln) + Bprint(ctxt->bso, "%6llux done\n", (vlong)func->text->pc+func->size); + addvarint(ctxt, dst, (func->value+func->size - pc) / ctxt->arch->minlc); + addvarint(ctxt, dst, 0); // terminator + } + + if(ctxt->debugpcln) { + Bprint(ctxt->bso, "wrote %d bytes to %p\n", dst->n, dst); + for(i=0; i<dst->n; i++) + Bprint(ctxt->bso, " %02ux", dst->p[i]); + Bprint(ctxt->bso, "\n"); + } + + ctxt->debugpcln -= dbg; +} + +// pctofileline computes either the file number (arg == 0) +// or the line number (arg == 1) to use at p. +// Because p->lineno applies to p, phase == 0 (before p) +// takes care of the update. +static int32 +pctofileline(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg) +{ + int32 i, l; + LSym *f; + Pcln *pcln; + + if(p->as == ctxt->arch->ATEXT || p->as == ctxt->arch->ANOP || p->as == ctxt->arch->AUSEFIELD || p->lineno == 0 || phase == 1) + return oldval; + linkgetline(ctxt, sym->hist, p->lineno, &f, &l); + if(f == nil) { + // print("getline failed for %s %P\n", ctxt->cursym->name, p); + return oldval; + } + if(arg == nil) + return l; + pcln = arg; + + if(f == pcln->lastfile) + return pcln->lastindex; + + for(i=0; i<pcln->nfile; i++) { + if(pcln->file[i] == f) { + pcln->lastfile = f; + pcln->lastindex = i; + return i; + } + } + + if(pcln->nfile >= pcln->mfile) { + pcln->mfile = (pcln->nfile+1)*2; + pcln->file = erealloc(pcln->file, pcln->mfile*sizeof pcln->file[0]); + } + pcln->file[pcln->nfile++] = f; + pcln->lastfile = f; + pcln->lastindex = i; + return i; +} + +// pctospadj computes the sp adjustment in effect. +// It is oldval plus any adjustment made by p itself. +// The adjustment by p takes effect only after p, so we +// apply the change during phase == 1. +static int32 +pctospadj(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg) +{ + USED(arg); + USED(sym); + + if(oldval == -1) // starting + oldval = 0; + if(phase == 0) + return oldval; + if(oldval + p->spadj < -10000 || oldval + p->spadj > 1100000000) { + ctxt->diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj); + sysfatal("bad code"); + } + return oldval + p->spadj; +} + +// pctopcdata computes the pcdata value in effect at p. +// A PCDATA instruction sets the value in effect at future +// non-PCDATA instructions. +// Since PCDATA instructions have no width in the final code, +// it does not matter which phase we use for the update. +static int32 +pctopcdata(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg) +{ + USED(sym); + + if(phase == 0 || p->as != ctxt->arch->APCDATA || p->from.offset != (uintptr)arg) + return oldval; + if((int32)p->to.offset != p->to.offset) { + ctxt->diag("overflow in PCDATA instruction: %P", p); + sysfatal("bad code"); + } + return p->to.offset; +} + +void +linkpcln(Link *ctxt, LSym *cursym) +{ + Prog *p; + Pcln *pcln; + int i, npcdata, nfuncdata, n; + uint32 *havepc, *havefunc; + + ctxt->cursym = cursym; + + pcln = emallocz(sizeof *pcln); + cursym->pcln = pcln; + + npcdata = 0; + nfuncdata = 0; + for(p = cursym->text; p != nil; p = p->link) { + if(p->as == ctxt->arch->APCDATA && p->from.offset >= npcdata) + npcdata = p->from.offset+1; + if(p->as == ctxt->arch->AFUNCDATA && p->from.offset >= nfuncdata) + nfuncdata = p->from.offset+1; + } + + pcln->pcdata = emallocz(npcdata*sizeof pcln->pcdata[0]); + pcln->npcdata = npcdata; + pcln->funcdata = emallocz(nfuncdata*sizeof pcln->funcdata[0]); + pcln->funcdataoff = emallocz(nfuncdata*sizeof pcln->funcdataoff[0]); + pcln->nfuncdata = nfuncdata; + + funcpctab(ctxt, &pcln->pcsp, cursym, "pctospadj", pctospadj, nil); + funcpctab(ctxt, &pcln->pcfile, cursym, "pctofile", pctofileline, pcln); + funcpctab(ctxt, &pcln->pcline, cursym, "pctoline", pctofileline, nil); + + // tabulate which pc and func data we have. + n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4; + havepc = emallocz(n); + havefunc = havepc + (npcdata+31)/32; + for(p = cursym->text; p != nil; p = p->link) { + if(p->as == ctxt->arch->AFUNCDATA) { + if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1) + ctxt->diag("multiple definitions for FUNCDATA $%d", p->from.offset); + havefunc[p->from.offset/32] |= 1<<(p->from.offset%32); + } + if(p->as == ctxt->arch->APCDATA) + havepc[p->from.offset/32] |= 1<<(p->from.offset%32); + } + // pcdata. + for(i=0; i<npcdata; i++) { + if(!(havepc[i/32]>>(i%32))&1) + continue; + funcpctab(ctxt, &pcln->pcdata[i], cursym, "pctopcdata", pctopcdata, (void*)(uintptr)i); + } + free(havepc); + + // funcdata + if(nfuncdata > 0) { + for(p = cursym->text; p != nil; p = p->link) { + if(p->as == ctxt->arch->AFUNCDATA) { + i = p->from.offset; + pcln->funcdataoff[i] = p->to.offset; + if(p->to.type != ctxt->arch->D_CONST) { + // TODO: Dedup. + //funcdata_bytes += p->to.sym->size; + pcln->funcdata[i] = p->to.sym; + } + } + } + } +} diff --git a/src/liblink/rdobj5.c b/src/liblink/rdobj5.c new file mode 100644 index 000000000..f2a8b8223 --- /dev/null +++ b/src/liblink/rdobj5.c @@ -0,0 +1,585 @@ +// Inferno utils/5l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/5l/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. + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> +#include "../cmd/5l/5.out.h" + +// TODO: remove duplicate chipzero, chipfloat + +static void finish(Link*); + +static int +chipzero(Link *ctxt, float64 e) +{ + // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. + if(ctxt->goarm < 7 || e != 0) + return -1; + return 0; +} + +static int +chipfloat(Link *ctxt, float64 e) +{ + int n; + ulong h1; + int32 l, h; + uint64 ei; + + // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. + if(ctxt->goarm < 7) + goto no; + + memmove(&ei, &e, 8); + l = (int32)ei; + h = (int32)(ei>>32); + + if(l != 0 || (h&0xffff) != 0) + goto no; + h1 = h & 0x7fc00000; + if(h1 != 0x40000000 && h1 != 0x3fc00000) + goto no; + n = 0; + + // sign bit (a) + if(h & 0x80000000) + n |= 1<<7; + + // exp sign bit (b) + if(h1 == 0x3fc00000) + n |= 1<<6; + + // rest of exp and mantissa (cd-efgh) + n |= (h >> 16) & 0x3f; + +//print("match %.8lux %.8lux %d\n", l, h, n); + return n; + +no: + return -1; +} + +static LSym* +zsym(char *pn, Biobuf *f, LSym *h[]) +{ + int o; + + o = BGETC(f); + if(o == 0) + return nil; + if(o < 0 || o >= NSYM || h[o] == nil) + mangle(pn); + return h[o]; +} + +static void +zaddr(Link *ctxt, char *pn, Biobuf *f, Addr *a, LSym *h[], LSym **pgotype) +{ + int i, c; + int32 l; + LSym *s, *gotype; + Auto *u; + uint64 v; + + a->type = BGETC(f); + a->reg = BGETC(f); + c = BGETC(f); + if(c < 0 || c > NSYM){ + print("sym out of range: %d\n", c); + BPUTC(f, ALAST+1); + return; + } + a->sym = h[c]; + a->name = BGETC(f); + gotype = zsym(pn, f, h); + if(pgotype) + *pgotype = gotype; + + if((schar)a->reg < 0 || a->reg > NREG) { + print("register out of range %d\n", a->reg); + BPUTC(f, ALAST+1); + return; /* force real diagnostic */ + } + + if(a->type == D_CONST || a->type == D_OCONST) { + if(a->name == D_EXTERN || a->name == D_STATIC) { + s = a->sym; + if(s != nil && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) { + if(0 && !s->fnptr && s->name[0] != '.') + print("%s used as function pointer\n", s->name); + s->fnptr = 1; // over the top cos of SXREF + } + } + } + + switch(a->type) { + default: + print("unknown type %d\n", a->type); + BPUTC(f, ALAST+1); + return; /* force real diagnostic */ + + case D_NONE: + case D_REG: + case D_FREG: + case D_PSR: + case D_FPCR: + break; + + case D_REGREG: + case D_REGREG2: + a->offset = BGETC(f); + break; + + case D_CONST2: + a->offset2 = BGETLE4(f); // fall through + case D_BRANCH: + case D_OREG: + case D_CONST: + case D_OCONST: + case D_SHIFT: + a->offset = BGETLE4(f); + break; + + case D_SCONST: + Bread(f, a->u.sval, NSNAME); + break; + + case D_FCONST: + v = (uint32)BGETLE4(f); + v |= (uint64)BGETLE4(f)<<32; + memmove(&a->u.dval, &v, 8); + break; + } + s = a->sym; + if(s == nil) + return; + i = a->name; + if(i != D_AUTO && i != D_PARAM) { + if(s && gotype) + s->gotype = gotype; + return; + } + + l = a->offset; + for(u=ctxt->curauto; u; u=u->link) + if(u->asym == s) + if(u->type == i) { + if(u->aoffset > l) + u->aoffset = l; + if(gotype) + u->gotype = gotype; + return; + } + + u = emallocz(sizeof(Auto)); + u->link = ctxt->curauto; + ctxt->curauto = u; + u->asym = s; + u->aoffset = l; + u->type = i; + u->gotype = gotype; +} + +void +nopout5(Prog *p) +{ + p->as = ANOP; + p->from.type = D_NONE; + p->to.type = D_NONE; +} + +void +ldobj5(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn) +{ + int32 ipc; + Prog *p; + LSym *h[NSYM], *s; + int v, o, r, skip; + uint32 sig; + char *name; + int ntext; + int32 eof, autosize; + char src[1024], *x, literal[64]; + Prog *lastp; + LSym *fromgotype; + + lastp = nil; + ntext = 0; + eof = Boffset(f) + len; + src[0] = 0; + pn = estrdup(pn); // we keep it in LSym* references + +newloop: + memset(h, 0, sizeof(h)); + ctxt->version++; + ctxt->histfrogp = 0; + ipc = ctxt->pc; + skip = 0; + +loop: + if(f->state == Bracteof || Boffset(f) >= eof) + goto eof; + o = BGETC(f); + if(o == Beof) + goto eof; + + if(o <= AXXX || o >= ALAST) { + ctxt->diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); + sysfatal("probably not a .5 file"); + } + if(o == ANAME || o == ASIGNAME) { + sig = 0; + if(o == ASIGNAME) + sig = BGETLE4(f); + v = BGETC(f); /* type */ + o = BGETC(f); /* sym */ + r = 0; + if(v == D_STATIC) + r = ctxt->version; + name = Brdline(f, '\0'); + if(name == nil) { + if(Blinelen(f) > 0) { + fprint(2, "%s: name too long\n", pn); + sysfatal("invalid object file"); + } + goto eof; + } + x = expandpkg(name, pkg); + s = linklookup(ctxt, x, r); + if(x != name) + free(x); + + if(sig != 0){ + if(s->sig != 0 && s->sig != sig) + ctxt->diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name); + s->sig = sig; + s->file = pn; + } + + if(ctxt->debugread) + print(" ANAME %s\n", s->name); + if(o < 0 || o >= nelem(h)) { + fprint(2, "%s: mangled input file\n", pn); + sysfatal("invalid object"); + } + h[o] = s; + if((v == D_EXTERN || v == D_STATIC) && s->type == 0) + s->type = SXREF; + if(v == D_FILE) { + if(s->type != SFILE) { + ctxt->histgen++; + s->type = SFILE; + s->value = ctxt->histgen; + } + if(ctxt->histfrogp < LinkMaxHist) { + ctxt->histfrog[ctxt->histfrogp] = s; + ctxt->histfrogp++; + } else + collapsefrog(ctxt, s); + ctxt->dwarfaddfrag(s->value, s->name); + } + goto loop; + } + + p = emallocz(sizeof(Prog)); + p->as = o; + p->scond = BGETC(f); + p->reg = BGETC(f); + p->lineno = BGETLE4(f); + + zaddr(ctxt, pn, f, &p->from, h, &fromgotype); + zaddr(ctxt, pn, f, &p->to, h, nil); + + if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG) + ctxt->diag("register out of range %A %d", p->as, p->reg); + + p->link = nil; + p->pcond = nil; + + if(ctxt->debugread) + print("%P\n", p); + + switch(o) { + case AHISTORY: + if(p->to.offset == -1) { + addlib(ctxt, src, pn); + ctxt->histfrogp = 0; + goto loop; + } + if(src[0] == '\0') + copyhistfrog(ctxt, src, sizeof src); + addhist(ctxt, p->lineno, D_FILE); /* 'z' */ + if(p->to.offset) + addhist(ctxt, p->to.offset, D_FILE1); /* 'Z' */ + savehist(ctxt, p->lineno, p->to.offset); + ctxt->histfrogp = 0; + goto loop; + + case AEND: + finish(ctxt); + if(Boffset(f) == eof) + return; + goto newloop; + + case AGLOBL: + s = p->from.sym; + if(s == nil) { + ctxt->diag("GLOBL must have a name\n%P", p); + sysfatal("mangled input"); + } + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->value = 0; + } + if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) { + ctxt->diag("redefinition: %s\n%P", s->name, p); + s->type = SBSS; + s->value = 0; + } + if(p->to.offset > s->size) + s->size = p->to.offset; + if(p->reg & DUPOK) + s->dupok = 1; + if(p->reg & RODATA) + s->type = SRODATA; + else if(p->reg & NOPTR) + s->type = SNOPTRBSS; + break; + + case ADATA: + // Assume that AGLOBL comes after ADATA. + // If we've seen an AGLOBL that said this sym was DUPOK, + // ignore any more ADATA we see, which must be + // redefinitions. + s = p->from.sym; + if(s->dupok) { +// if(debug['v']) +// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); + goto loop; + } + if(s->file == nil) + s->file = pn; + else if(s->file != pn) { + ctxt->diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); + sysfatal("mangled input"); + } + savedata(ctxt, s, p, pn); + free(p); + break; + + case AGOK: + ctxt->diag("unknown opcode\n%P", p); + p->pc = ctxt->pc; + ctxt->pc++; + break; + + case ATYPE: + if(skip) + goto casedef; + ctxt->pc++; + goto loop; + + case ATEXT: + if(ctxt->cursym != nil && ctxt->cursym->text) + finish(ctxt); + s = p->from.sym; + if(s == nil) { + ctxt->diag("TEXT must have a name\n%P", p); + sysfatal("mangled input"); + } + ctxt->cursym = s; + if(s->type != 0 && s->type != SXREF && (p->reg & DUPOK)) { + skip = 1; + goto casedef; + } + if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { + /* redefinition, so file has probably been seen before */ + if(ctxt->debugvlog) + Bprint(ctxt->bso, "skipping: %s: redefinition: %s", pn, s->name); + return; + } + skip = 0; + if(s->type != 0 && s->type != SXREF) + ctxt->diag("redefinition: %s\n%P", s->name, p); + if(ctxt->etextp) + ctxt->etextp->next = s; + else + ctxt->textp = s; + if(fromgotype) { + if(s->gotype && s->gotype != fromgotype) + ctxt->diag("%s: type mismatch for %s", pn, s->name); + s->gotype = fromgotype; + } + ctxt->etextp = s; + autosize = (p->to.offset+3L) & ~3L; + p->to.offset = autosize; + autosize += 4; + s->type = STEXT; + s->hist = gethist(ctxt); + s->text = p; + s->value = ctxt->pc; + s->args = p->to.offset2; + lastp = p; + p->pc = ctxt->pc; + ctxt->pc++; + break; + + case ASUB: + if(p->from.type == D_CONST) + if(p->from.name == D_NONE) + if(p->from.offset < 0) { + p->from.offset = -p->from.offset; + p->as = AADD; + } + goto casedef; + + case AADD: + if(p->from.type == D_CONST) + if(p->from.name == D_NONE) + if(p->from.offset < 0) { + p->from.offset = -p->from.offset; + p->as = ASUB; + } + goto casedef; + + case AMOVWD: + case AMOVWF: + case AMOVDW: + case AMOVFW: + case AMOVFD: + case AMOVDF: + // case AMOVF: + // case AMOVD: + case ACMPF: + case ACMPD: + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + goto casedef; + + case AMOVF: + if(skip) + goto casedef; + + if(p->from.type == D_FCONST && chipfloat(ctxt, p->from.u.dval) < 0 && + (chipzero(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) { + /* size sb 9 max */ + sprint(literal, "$%.17gf", (float32)p->from.u.dval); + s = linklookup(ctxt, literal, 0); + if(s->type == 0) { + float32 f32; + int32 i32; + s->type = SRODATA; + f32 = p->from.u.dval; + memmove(&i32, &f32, 4); + adduint32(ctxt, s, i32); + s->reachable = 0; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + case AMOVD: + if(skip) + goto casedef; + + if(p->from.type == D_FCONST && chipfloat(ctxt, p->from.u.dval) < 0 && + (chipzero(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) { + /* size sb 18 max */ + sprint(literal, "$%.17g", p->from.u.dval); + s = linklookup(ctxt, literal, 0); + if(s->type == 0) { + int64 i64; + s->type = SRODATA; + memmove(&i64, &p->from.u.dval, 8); + adduint64(ctxt, s, i64); + s->reachable = 0; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + default: + casedef: + if(skip) + nopout5(p); + p->pc = ctxt->pc; + ctxt->pc++; + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + if(lastp == nil) { + if(p->as != ANOP) + ctxt->diag("unexpected instruction: %P", p); + break; + } + lastp->link = p; + lastp = p; + break; + } + goto loop; + +eof: + ctxt->diag("truncated object file: %s", pn); +} + +static void +finish(Link *ctxt) +{ + LSym *s; + + histtoauto(ctxt); + if(ctxt->cursym != nil && ctxt->cursym->text) { + s = ctxt->cursym; + s->autom = ctxt->curauto; + // mkfwd(s); + // linkpatch(ctxt, s); + // ctxt->arch->follow(ctxt, s); + // ctxt->arch->addstacksplit(ctxt, s); + // ctxt->arch->assemble(ctxt, s); + // linkpcln(ctxt, s); + } + + ctxt->curauto = 0; + ctxt->cursym = nil; +} + diff --git a/src/liblink/rdobj6.c b/src/liblink/rdobj6.c new file mode 100644 index 000000000..52ed18b93 --- /dev/null +++ b/src/liblink/rdobj6.c @@ -0,0 +1,495 @@ +// Inferno utils/6l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/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. + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> +#include "../cmd/6l/6.out.h" + +static LSym* +zsym(char *pn, Biobuf *f, LSym *h[]) +{ + int o; + + o = BGETC(f); + if(o < 0 || o >= NSYM || h[o] == nil) + mangle(pn); + return h[o]; +} + +static void finish(Link*); + +static void +zaddr(Link *ctxt, char *pn, Biobuf *f, Addr *a, LSym *h[], LSym **pgotype) +{ + int t; + int32 l; + LSym *s, *gotype; + Auto *u; + uint64 v; + + t = BGETC(f); + a->index = D_NONE; + a->scale = 0; + if(t & T_INDEX) { + a->index = BGETC(f); + a->scale = BGETC(f); + } + a->offset = 0; + if(t & T_OFFSET) { + a->offset = BGETLE4(f); + if(t & T_64) { + a->offset &= 0xFFFFFFFFULL; + a->offset |= (uvlong)BGETLE4(f) << 32; + } + } + a->sym = nil; + if(t & T_SYM) + a->sym = zsym(pn, f, h); + a->type = D_NONE; + if(t & T_FCONST) { + v = (uint32)BGETLE4(f); + v |= (uint64)BGETLE4(f)<<32; + memmove(&a->u.dval, &v, 8); + a->type = D_FCONST; + } else + if(t & T_SCONST) { + Bread(f, a->u.sval, NSNAME); + a->type = D_SCONST; + } + if(t & T_TYPE) + a->type = BGETC(f); + if(a->type < 0 || a->type >= D_SIZE) + mangle(pn); + gotype = nil; + if(t & T_GOTYPE) + gotype = zsym(pn, f, h); + if(pgotype) + *pgotype = gotype; + s = a->sym; + t = a->type; + if(t == D_INDIR+D_GS || a->index == D_GS) + a->offset += ctxt->tlsoffset; + if(t != D_AUTO && t != D_PARAM) { + if(s && gotype) + s->gotype = gotype; + return; + } + l = a->offset; + for(u=ctxt->curauto; u; u=u->link) { + if(u->asym == s) + if(u->type == t) { + if(u->aoffset > l) + u->aoffset = l; + if(gotype) + u->gotype = gotype; + return; + } + } + + switch(t) { + case D_FILE: + case D_FILE1: + case D_AUTO: + case D_PARAM: + if(s == nil) + mangle(pn); + } + + u = emallocz(sizeof(*u)); + u->link = ctxt->curauto; + ctxt->curauto = u; + u->asym = s; + u->aoffset = l; + u->type = t; + u->gotype = gotype; +} + +void +nopout6(Prog *p) +{ + p->as = ANOP; + p->from.type = D_NONE; + p->to.type = D_NONE; +} + +void +ldobj6(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn) +{ + vlong ipc; + Prog *p; + int v, o, r, skip, mode; + LSym *h[NSYM], *s; + uint32 sig; + char *name, *x; + int ntext; + vlong eof; + char src[1024], literal[64]; + Prog *lastp; + LSym *fromgotype; + + lastp = nil; + ntext = 0; + eof = Boffset(f) + len; + src[0] = 0; + pn = estrdup(pn); // we keep it in LSym* references + +newloop: + memset(h, 0, sizeof(h)); + ctxt->version++; + ctxt->histfrogp = 0; + ipc = ctxt->pc; + skip = 0; + mode = 64; + +loop: + if(f->state == Bracteof || Boffset(f) >= eof) + goto eof; + o = BGETC(f); + if(o == Beof) + goto eof; + o |= BGETC(f) << 8; + if(o <= AXXX || o >= ALAST) { + if(o < 0) + goto eof; + sysfatal("%s:#%lld: opcode out of range: %#ux\n\tprobably not a .6 file", pn, Boffset(f), o); + } + + if(o == ANAME || o == ASIGNAME) { + sig = 0; + if(o == ASIGNAME) + sig = BGETLE4(f); + USED(sig); + v = BGETC(f); /* type */ + o = BGETC(f); /* sym */ + r = 0; + if(v == D_STATIC) + r = ctxt->version; + name = Brdline(f, '\0'); + if(name == nil) { + if(Blinelen(f) > 0) + sysfatal("%s: name too long", pn); + goto eof; + } + x = expandpkg(name, pkg); + s = linklookup(ctxt, x, r); + if(x != name) + free(x); + + if(ctxt->debugread) + print(" ANAME %s\n", s->name); + if(o < 0 || o >= nelem(h)) + mangle(pn); + h[o] = s; + if((v == D_EXTERN || v == D_STATIC) && s->type == 0) + s->type = SXREF; + if(v == D_FILE) { + if(s->type != SFILE) { + ctxt->histgen++; + s->type = SFILE; + s->value = ctxt->histgen; + } + if(ctxt->histfrogp < LinkMaxHist) { + ctxt->histfrog[ctxt->histfrogp] = s; + ctxt->histfrogp++; + } else + collapsefrog(ctxt, s); + if(ctxt->dwarfaddfrag) + ctxt->dwarfaddfrag(s->value, s->name); + } + goto loop; + } + + p = emallocz(sizeof(*p)); + p->as = o; + p->lineno = BGETLE4(f); + p->back = 2; + p->mode = mode; + zaddr(ctxt, pn, f, &p->from, h, &fromgotype); + zaddr(ctxt, pn, f, &p->to, h, nil); + + switch(p->as) { + case ATEXT: + case ADATA: + case AGLOBL: + if(p->from.sym == nil) + mangle(pn); + break; + } + + if(ctxt->debugread) + print("%P\n", p); + + switch(p->as) { + case AHISTORY: + if(p->to.offset == -1) { + addlib(ctxt, src, pn); + ctxt->histfrogp = 0; + goto loop; + } + if(src[0] == '\0') + copyhistfrog(ctxt, src, sizeof src); + addhist(ctxt, p->lineno, D_FILE); /* 'z' */ + if(p->to.offset) + addhist(ctxt, p->to.offset, D_FILE1); /* 'Z' */ + savehist(ctxt, p->lineno, p->to.offset); + ctxt->histfrogp = 0; + goto loop; + + case AEND: + finish(ctxt); + if(Boffset(f) == eof) + return; + goto newloop; + + case AGLOBL: + s = p->from.sym; + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->size = 0; + } + if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) { + ctxt->diag("%s: redefinition: %s in %s", + pn, s->name, ctxt->cursym ? ctxt->cursym->name : "<none>"); + s->type = SBSS; + s->size = 0; + } + if(p->to.offset > s->size) + s->size = p->to.offset; + if(p->from.scale & DUPOK) + s->dupok = 1; + if(p->from.scale & RODATA) + s->type = SRODATA; + else if(p->from.scale & NOPTR) + s->type = SNOPTRBSS; + goto loop; + + case ADATA: + // Assume that AGLOBL comes after ADATA. + // If we've seen an AGLOBL that said this sym was DUPOK, + // ignore any more ADATA we see, which must be + // redefinitions. + s = p->from.sym; + if(s->dupok) { +// if(ctxt->debugvlog) +// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); + goto loop; + } + if(s->file == nil) + s->file = pn; + else if(s->file != pn) + sysfatal("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); + savedata(ctxt, s, p, pn); + free(p); + goto loop; + + case AGOK: + ctxt->diag("%s: GOK opcode in %s", pn, ctxt->cursym ? ctxt->cursym->name : "<none>"); + ctxt->pc++; + goto loop; + + case ATYPE: + if(skip) + goto casdef; + ctxt->pc++; + goto loop; + + case ATEXT: + s = p->from.sym; + if(s->text != nil) { + if(p->from.scale & DUPOK) { + skip = 1; + goto casdef; + } + ctxt->diag("%s: %s: redefinition", pn, s->name); + return; + } + if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { + /* redefinition, so file has probably been seen before */ + if(ctxt->debugvlog && ctxt->bso) + Bprint(ctxt->bso, "skipping: %s: redefinition: %s", pn, s->name); + return; + } + if(ctxt->cursym != nil && ctxt->cursym->text) + finish(ctxt); + skip = 0; + if(ctxt->etextp) + ctxt->etextp->next = s; + else + ctxt->textp = s; + ctxt->etextp = s; + s->text = p; + ctxt->cursym = s; + if(s->type != 0 && s->type != SXREF) { + if(p->from.scale & DUPOK) { + skip = 1; + goto casdef; + } + ctxt->diag("%s: redefinition: %s\n%P", pn, s->name, p); + } + if(fromgotype) { + if(s->gotype && s->gotype != fromgotype) + ctxt->diag("%s: type mismatch for %s", pn, s->name); + s->gotype = fromgotype; + } + s->type = STEXT; + s->hist = gethist(ctxt); + s->value = ctxt->pc; + s->args = p->to.offset >> 32; + lastp = p; + p->pc = ctxt->pc++; + goto loop; + + case AMODE: + if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){ + switch((int)p->from.offset){ + case 16: case 32: case 64: + mode = p->from.offset; + break; + } + } + goto loop; + + case AFMOVF: + case AFADDF: + case AFSUBF: + case AFSUBRF: + case AFMULF: + case AFDIVF: + case AFDIVRF: + case AFCOMF: + case AFCOMFP: + case AMOVSS: + case AADDSS: + case ASUBSS: + case AMULSS: + case ADIVSS: + case ACOMISS: + case AUCOMISS: + if(skip) + goto casdef; + if(p->from.type == D_FCONST) { + /* size sb 9 max */ + sprint(literal, "$%.17gf", (float32)p->from.u.dval); + s = linklookup(ctxt, literal, 0); + if(s->type == 0) { + int32 i32; + float32 f32; + s->type = SRODATA; + f32 = p->from.u.dval; + memmove(&i32, &f32, 4); + adduint32(ctxt, s, i32); + s->reachable = 0; + } + 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: + case AMOVSD: + case AADDSD: + case ASUBSD: + case AMULSD: + case ADIVSD: + case ACOMISD: + case AUCOMISD: + if(skip) + goto casdef; + if(p->from.type == D_FCONST) { + /* size sb 18 max */ + sprint(literal, "$%.17g", p->from.u.dval); + s = linklookup(ctxt, literal, 0); + if(s->type == 0) { + int64 i64; + s->type = SRODATA; + memmove(&i64, &p->from.u.dval, 8); + adduint64(ctxt, s, i64); + s->reachable = 0; + } + p->from.type = D_EXTERN; + p->from.sym = s; + p->from.offset = 0; + } + goto casdef; + + casdef: + default: + if(skip) + nopout6(p); + p->pc = ctxt->pc; + ctxt->pc++; + + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + if(lastp == nil) { + if(p->as != ANOP) + ctxt->diag("unexpected instruction: %P", p); + goto loop; + } + lastp->link = p; + lastp = p; + goto loop; + } + +eof: + ctxt->diag("truncated object file: %s", pn); +} + +static void +finish(Link *ctxt) +{ + LSym *s; + + histtoauto(ctxt); + if(ctxt->cursym != nil && ctxt->cursym->text) { + s = ctxt->cursym; + s->autom = ctxt->curauto; + // mkfwd(s); + // linkpatch(ctxt, s); + // ctxt->arch->follow(ctxt, s); + // ctxt->arch->addstacksplit(ctxt, s); + // ctxt->arch->assemble(ctxt, s); + // linkpcln(ctxt, s); + } + + ctxt->curauto = 0; + ctxt->cursym = nil; +} diff --git a/src/liblink/rdobj8.c b/src/liblink/rdobj8.c new file mode 100644 index 000000000..d84e42889 --- /dev/null +++ b/src/liblink/rdobj8.c @@ -0,0 +1,466 @@ +// 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. + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> +#include "../cmd/8l/8.out.h" + +static LSym* +zsym(char *pn, Biobuf *f, LSym *h[]) +{ + int o; + + o = BGETC(f); + if(o < 0 || o >= NSYM || h[o] == nil) + mangle(pn); + return h[o]; +} + +static void finish(Link*); + +static void +zaddr(Link *ctxt, char *pn, Biobuf *f, Addr *a, LSym *h[], LSym **pgotype) +{ + int t; + int32 l; + LSym *s, *gotype; + Auto *u; + uint64 v; + + t = BGETC(f); + a->index = D_NONE; + a->scale = 0; + if(t & T_INDEX) { + a->index = BGETC(f); + a->scale = BGETC(f); + } + a->type = D_NONE; + a->offset = 0; + if(t & T_OFFSET) + a->offset = BGETLE4(f); + a->offset2 = 0; + if(t & T_OFFSET2) { + a->offset2 = BGETLE4(f); + a->type = D_CONST2; + } + a->sym = nil; + if(t & T_SYM) + a->sym = zsym(pn, f, h); + if(t & T_FCONST) { + v = (uint32)BGETLE4(f); + v |= (uint64)BGETLE4(f)<<32; + memmove(&a->u.dval, &v, 8); + a->type = D_FCONST; + } else + if(t & T_SCONST) { + Bread(f, a->u.sval, NSNAME); + a->type = D_SCONST; + } + if(t & T_TYPE) + a->type = BGETC(f); + gotype = nil; + if(t & T_GOTYPE) + gotype = zsym(pn, f, h); + if(pgotype) + *pgotype = gotype; + t = a->type; + if(t == D_INDIR+D_GS) + a->offset += ctxt->tlsoffset; + + s = a->sym; + if(s == nil) + return; + if(t != D_AUTO && t != D_PARAM) { + if(gotype) + s->gotype = gotype; + return; + } + l = a->offset; + for(u=ctxt->curauto; u; u=u->link) { + if(u->asym == s) + if(u->type == t) { + if(u->aoffset > l) + u->aoffset = l; + if(gotype) + u->gotype = gotype; + return; + } + } + + u = emallocz(sizeof(*u)); + u->link = ctxt->curauto; + ctxt->curauto = u; + u->asym = s; + u->aoffset = l; + u->type = t; + u->gotype = gotype; +} + +void +nopout8(Prog *p) +{ + p->as = ANOP; + p->from.type = D_NONE; + p->to.type = D_NONE; +} + +void +ldobj8(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn) +{ + int32 ipc; + Prog *p; + int v, o, r, skip; + LSym *h[NSYM], *s; + uint32 sig; + int ntext; + int32 eof; + char *name, *x; + char src[1024], literal[64]; + Prog *lastp; + LSym *fromgotype; + + lastp = nil; + ntext = 0; + eof = Boffset(f) + len; + src[0] = 0; + pn = estrdup(pn); // we keep it in LSym* references + +newloop: + memset(h, 0, sizeof(h)); + ctxt->version++; + ctxt->histfrogp = 0; + ipc = ctxt->pc; + skip = 0; + +loop: + if(f->state == Bracteof || Boffset(f) >= eof) + goto eof; + o = BGETC(f); + if(o == Beof) + goto eof; + o |= BGETC(f) << 8; + if(o <= AXXX || o >= ALAST) { + if(o < 0) + goto eof; + ctxt->diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); + print(" probably not a .%c file\n", ctxt->thechar); + sysfatal("invalid file"); + } + + if(o == ANAME || o == ASIGNAME) { + sig = 0; + if(o == ASIGNAME) + sig = BGETLE4(f); + USED(sig); + + v = BGETC(f); /* type */ + o = BGETC(f); /* sym */ + r = 0; + if(v == D_STATIC) + r = ctxt->version; + name = Brdline(f, '\0'); + if(name == nil) { + if(Blinelen(f) > 0) + sysfatal("%s: name too long", pn); + goto eof; + } + x = expandpkg(name, pkg); + s = linklookup(ctxt, x, r); + if(x != name) + free(x); + + if(ctxt->debugread) + print(" ANAME %s\n", s->name); + if(o < 0 || o >= nelem(h)) + mangle(pn); + h[o] = s; + if((v == D_EXTERN || v == D_STATIC) && s->type == 0) + s->type = SXREF; + if(v == D_FILE) { + if(s->type != SFILE) { + ctxt->histgen++; + s->type = SFILE; + s->value = ctxt->histgen; + } + if(ctxt->histfrogp < LinkMaxHist) { + ctxt->histfrog[ctxt->histfrogp] = s; + ctxt->histfrogp++; + } else + collapsefrog(ctxt, s); + ctxt->dwarfaddfrag(s->value, s->name); + } + goto loop; + } + + p = emallocz(sizeof(*p)); + p->as = o; + p->lineno = BGETLE4(f); + p->back = 2; + zaddr(ctxt, pn, f, &p->from, h, &fromgotype); + zaddr(ctxt, pn, f, &p->to, h, nil); + + if(ctxt->debugread) + print("%P\n", p); + + switch(p->as) { + case AHISTORY: + if(p->to.offset == -1) { + addlib(ctxt, src, pn); + ctxt->histfrogp = 0; + goto loop; + } + if(src[0] == '\0') + copyhistfrog(ctxt, src, sizeof src); + addhist(ctxt, p->lineno, D_FILE); /* 'z' */ + if(p->to.offset) + addhist(ctxt, p->to.offset, D_FILE1); /* 'Z' */ + savehist(ctxt, p->lineno, p->to.offset); + ctxt->histfrogp = 0; + goto loop; + + case AEND: + finish(ctxt); + if(Boffset(f) == eof) + return; + goto newloop; + + case AGLOBL: + s = p->from.sym; + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->size = 0; + } + if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) { + ctxt->diag("%s: redefinition: %s in %s", + pn, s->name, ctxt->cursym ? ctxt->cursym->name : "<none>"); + s->type = SBSS; + s->size = 0; + } + if(p->to.offset > s->size) + s->size = p->to.offset; + if(p->from.scale & DUPOK) + s->dupok = 1; + if(p->from.scale & RODATA) + s->type = SRODATA; + else if(p->from.scale & NOPTR) + s->type = SNOPTRBSS; + goto loop; + + case ADATA: + // Assume that AGLOBL comes after ADATA. + // If we've seen an AGLOBL that said this sym was DUPOK, + // ignore any more ADATA we see, which must be + // redefinitions. + s = p->from.sym; + if(s->dupok) { +// if(ctxt->debugvlog) +// Bprint(ctxt->bso, "skipping %s in %s: dupok\n", s->name, pn); + goto loop; + } + if(s->file == nil) + s->file = pn; + else if(s->file != pn) { + ctxt->diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); + sysfatal("multiple init"); + } + savedata(ctxt, s, p, pn); + free(p); + goto loop; + + case AGOK: + ctxt->diag("%s: GOK opcode in %s", pn, ctxt->cursym ? ctxt->cursym->name : "<none>"); + ctxt->pc++; + goto loop; + + case ATYPE: + if(skip) + goto casdef; + ctxt->pc++; + goto loop; + + case ATEXT: + s = p->from.sym; + if(s->text != nil) { + if(p->from.scale & DUPOK) { + skip = 1; + goto casdef; + } + ctxt->diag("%s: %s: redefinition", pn, s->name); + return; + } + if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { + /* redefinition, so file has probably been seen before */ + if(ctxt->debugvlog) + ctxt->diag("skipping: %s: redefinition: %s", pn, s->name); + return; + } + if(ctxt->cursym != nil && ctxt->cursym->text) + finish(ctxt); + skip = 0; + if(ctxt->etextp) + ctxt->etextp->next = s; + else + ctxt->textp = s; + ctxt->etextp = s; + s->text = p; + ctxt->cursym = s; + if(s->type != 0 && s->type != SXREF) { + if(p->from.scale & DUPOK) { + skip = 1; + goto casdef; + } + ctxt->diag("%s: redefinition: %s\n%P", pn, s->name, p); + } + s->type = STEXT; + s->hist = gethist(ctxt); + s->value = ctxt->pc; + s->args = p->to.offset2; + lastp = p; + p->pc = ctxt->pc++; + goto loop; + + case AFMOVF: + case AFADDF: + case AFSUBF: + case AFSUBRF: + case AFMULF: + case AFDIVF: + case AFDIVRF: + case AFCOMF: + case AFCOMFP: + case AMOVSS: + case AADDSS: + case ASUBSS: + case AMULSS: + case ADIVSS: + case ACOMISS: + case AUCOMISS: + if(skip) + goto casdef; + if(p->from.type == D_FCONST) { + /* size sb 9 max */ + sprint(literal, "$(%.17gf)", (float32)p->from.u.dval); + s = linklookup(ctxt, literal, 0); + if(s->type == 0) { + float32 f32; + int32 i32; + s->type = SRODATA; + f32 = p->from.u.dval; + memmove(&i32, &f32, 4); + adduint32(ctxt, s, i32); + s->reachable = 0; + } + 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: + case AMOVSD: + case AADDSD: + case ASUBSD: + case AMULSD: + case ADIVSD: + case ACOMISD: + case AUCOMISD: + if(skip) + goto casdef; + if(p->from.type == D_FCONST) { + /* size sb 18 max */ + sprint(literal, "$%.17g", + p->from.u.dval); + s = linklookup(ctxt, literal, 0); + if(s->type == 0) { + int64 i64; + s->type = SRODATA; + memmove(&i64, &p->from.u.dval, 8); + adduint64(ctxt, s, i64); + s->reachable = 0; + } + p->from.type = D_EXTERN; + p->from.sym = s; + p->from.offset = 0; + } + goto casdef; + + casdef: + default: + if(skip) + nopout8(p); + p->pc = ctxt->pc; + ctxt->pc++; + + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + if(lastp == nil) { + if(p->as != ANOP) + ctxt->diag("unexpected instruction: %P", p); + goto loop; + } + lastp->link = p; + lastp = p; + goto loop; + } + +eof: + ctxt->diag("truncated object file: %s", pn); +} + +static void +finish(Link *ctxt) +{ + LSym *s; + + histtoauto(ctxt); + if(ctxt->cursym != nil && ctxt->cursym->text) { + s = ctxt->cursym; + s->autom = ctxt->curauto; + // mkfwd(s); + // linkpatch(ctxt, s); + // ctxt->arch->follow(ctxt, s); + // ctxt->arch->addstacksplit(ctxt, s); + // ctxt->arch->assemble(ctxt, s); + // linkpcln(ctxt, s); + } + + ctxt->curauto = 0; + ctxt->cursym = nil; +} diff --git a/src/liblink/sym.c b/src/liblink/sym.c new file mode 100644 index 000000000..e876a5ca0 --- /dev/null +++ b/src/liblink/sym.c @@ -0,0 +1,158 @@ +// Derived from Inferno utils/6l/obj.c and utils/6l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/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 <u.h> +#include <libc.h> +#include <bio.h> +#include <link.h> + +static int +yy_isalpha(int c) +{ + return c >= 0 && c <= 0xFF && isalpha(c); +} + +Link* +linknew(LinkArch *arch) +{ + Link *ctxt; + char *p; + char buf[1024]; + + nuxiinit(); + + ctxt = emallocz(sizeof *ctxt); + ctxt->arch = arch; + ctxt->version = HistVersion; + + // TODO: Make caller pass in ctxt->arch, + // so that for example 6g only has the linkamd64 code. + p = getgoarch(); + if(strncmp(p, arch->name, strlen(arch->name)) != 0) + sysfatal("invalid goarch %s (want %s or derivative)", p, arch->name); + + if(getwd(buf, sizeof buf) == 0) + strcpy(buf, "/???"); + if(yy_isalpha(buf[0]) && buf[1] == ':') { + // On Windows. + ctxt->windows = 1; + + // Canonicalize path by converting \ to / (Windows accepts both). + for(p=buf; *p; p++) + if(*p == '\\') + *p = '/'; + } + ctxt->pathname = strdup(buf); + + return ctxt; +} + +LSym* +linknewsym(Link *ctxt, char *symb, int v) +{ + LSym *s; + int l; + + l = strlen(symb) + 1; + s = malloc(sizeof(*s)); + memset(s, 0, sizeof(*s)); + + s->dynid = -1; + s->plt = -1; + s->got = -1; + s->name = malloc(l + 1); + memmove(s->name, symb, l); + s->name[l] = '\0'; + + s->type = 0; + s->version = v; + s->value = 0; + s->sig = 0; + s->size = 0; + ctxt->nsymbol++; + + s->allsym = ctxt->allsym; + ctxt->allsym = s; + + return s; +} + +static LSym* +_lookup(Link *ctxt, char *symb, int v, int creat) +{ + LSym *s; + char *p; + uint32 h; + int c; + + h = v; + for(p=symb; c = *p; p++) + h = h+h+h + c; + h &= 0xffffff; + h %= LINKHASH; + for(s = ctxt->hash[h]; s != nil; s = s->hash) + if(strcmp(s->name, symb) == 0) + return s; + if(!creat) + return nil; + + s = linknewsym(ctxt, symb, v); + s->extname = s->name; + s->hash = ctxt->hash[h]; + ctxt->hash[h] = s; + + return s; +} + +LSym* +linklookup(Link *ctxt, char *name, int v) +{ + return _lookup(ctxt, name, v, 1); +} + +// read-only lookup +LSym* +linkrlookup(Link *ctxt, char *name, int v) +{ + return _lookup(ctxt, name, v, 0); +} + +int +linksymfmt(Fmt *f) +{ + LSym *s; + + s = va_arg(f->args, LSym*); + if(s == nil) + return fmtstrcpy(f, "<nil>"); + + return fmtstrcpy(f, s->name); +} |