]> Cypherpunks repositories - gostls13.git/commitdiff
liblink: create new library based on linker code
authorRuss Cox <rsc@golang.org>
Mon, 9 Dec 2013 03:49:37 +0000 (22:49 -0500)
committerRuss Cox <rsc@golang.org>
Mon, 9 Dec 2013 03:49:37 +0000 (22:49 -0500)
There is an enormous amount of code moving around in this CL,
but the code is the same, and it is invoked in the same ways.
This CL is preparation for the new linker structure, not the new
structure itself.

The new library's definition is in include/link.h.

The main change is the use of a Link structure to hold all the
linker-relevant state, replacing the smattering of global variables.
The Link structure should both make it clearer which state must
be carried around and make it possible to parallelize more easily
later.

The main body of the linker has moved into the architecture-independent
cmd/ld directory. That includes the list of known header types, so the
distinction between Hplan9x32 and Hplan9x64 is removed (no other
header type distinguished 32- and 64-bit formats), and code for unused
formats such as ipaq kernels has been deleted.

The code being deleted from 5l, 6l, and 8l reappears in liblink or in ld.
Because multiple files are being merged in the liblink directory,
it is not possible to show the diffs nicely in hg.

The Prog and Addr structures have been unified into an
architecture-independent form and moved to link.h, where they will
be shared by all tools: the assemblers, the compilers, and the linkers.
The unification makes it possible to write architecture-independent
traversal of Prog lists, among other benefits.

The Sym structures cannot be unified: they are too fundamentally
different between the linker and the compilers. Instead, liblink defines
an LSym - a linker Sym - to be used in the Prog and Addr structures,
and the linker now refers exclusively to LSyms. The compilers will
keep using their own syms but will fill out the corresponding LSyms in
the Prog and Addr structures.

Although code from 5l, 6l, and 8l is now in a single library, the
code has been arranged so that only one architecture needs to
be linked into a particular program: 5l will not contain the code
needed for x86 instruction layout, for example.

The object file writing code in liblink/obj.c is from cmd/gc/obj.c.

Preparation for golang.org/s/go13linker work.

This CL does not build by itself. It depends on 35740044
and will be submitted at the same time.

R=iant
CC=golang-dev
https://golang.org/cl/35790044

67 files changed:
include/link.h [new file with mode: 0644]
include/u.h
src/cmd/5l/5.out.h
src/cmd/5l/asm.c
src/cmd/5l/l.h
src/cmd/5l/list.c
src/cmd/5l/noop.c
src/cmd/5l/obj.c
src/cmd/5l/optab.c [deleted file]
src/cmd/5l/pass.c [deleted file]
src/cmd/5l/prof.c [deleted file]
src/cmd/5l/softfloat.c [deleted file]
src/cmd/5l/span.c [deleted file]
src/cmd/6l/6.out.h
src/cmd/6l/asm.c
src/cmd/6l/l.h
src/cmd/6l/list.c
src/cmd/6l/obj.c
src/cmd/6l/optab.c [deleted file]
src/cmd/6l/pass.c [deleted file]
src/cmd/6l/prof.c [deleted file]
src/cmd/6l/span.c [deleted file]
src/cmd/8l/8.out.h
src/cmd/8l/asm.c
src/cmd/8l/l.h
src/cmd/8l/list.c
src/cmd/8l/obj.c
src/cmd/8l/optab.c [deleted file]
src/cmd/8l/pass.c [deleted file]
src/cmd/8l/prof.c [deleted file]
src/cmd/8l/span.c [deleted file]
src/cmd/ld/data.c
src/cmd/ld/decodesym.c
src/cmd/ld/dwarf.c
src/cmd/ld/dwarf.h
src/cmd/ld/elf.c
src/cmd/ld/elf.h
src/cmd/ld/go.c
src/cmd/ld/ldelf.c
src/cmd/ld/ldmacho.c
src/cmd/ld/ldpe.c
src/cmd/ld/lib.c
src/cmd/ld/lib.h
src/cmd/ld/macho.c
src/cmd/ld/pass.c [new file with mode: 0644]
src/cmd/ld/pcln.c [new file with mode: 0644]
src/cmd/ld/pe.c
src/cmd/ld/pe.h
src/cmd/ld/pobj.c [new file with mode: 0644]
src/cmd/ld/symtab.c
src/liblink/Makefile [new file with mode: 0644]
src/liblink/asm5.c [new file with mode: 0644]
src/liblink/asm6.c [new file with mode: 0644]
src/liblink/asm8.c [new file with mode: 0644]
src/liblink/data.c [new file with mode: 0644]
src/liblink/go.c [new file with mode: 0644]
src/liblink/ld.c [new file with mode: 0644]
src/liblink/obj.c [new file with mode: 0644]
src/liblink/obj5.c [new file with mode: 0644]
src/liblink/obj6.c [new file with mode: 0644]
src/liblink/obj8.c [new file with mode: 0644]
src/liblink/pass.c [new file with mode: 0644]
src/liblink/pcln.c [new file with mode: 0644]
src/liblink/rdobj5.c [new file with mode: 0644]
src/liblink/rdobj6.c [new file with mode: 0644]
src/liblink/rdobj8.c [new file with mode: 0644]
src/liblink/sym.c [new file with mode: 0644]

diff --git a/include/link.h b/include/link.h
new file mode 100644 (file)
index 0000000..1d6aec4
--- /dev/null
@@ -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;
index 44bfcd63b23120d7844fcfed49d6fdb2d2042b09..6b2d50cc1f97143f22edeeebcaa138f1768aba7b 100644 (file)
@@ -188,6 +188,8 @@ typedef u32int uint32;
 typedef s64int int64;
 typedef u64int uint64;
 
+typedef float float32;
+typedef double float64;
 
 #undef _NEEDUCHAR
 #undef _NEEDUSHORT
index ebbadde2c978b734333268bd33be6571b14fa16a..f832f2af8510b5c3a0f4a46157bc08861c6eeec3 100644 (file)
@@ -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 */
-};
index 33cdf80968d36e0c0b183f27884c66a3465dad26..85600cabf6f72bca04c31579cc091f390d9c2749 100644 (file)
@@ -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;
 }
index ae4b05ba1dfc957ea5fe6aa78443b114a80c8343..25f5810478f40046b028ccc3e9edc2457ea1e7ea 100644 (file)
@@ -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)
index 7502a3b818671e7c4bdcfee54eb11bb83497c239..02a9575793e4dd6acd1fc782838822dd6650295a 100644 (file)
@@ -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);
index 305ed684ee4d2c0a09aaad78060293abaad5a5ec..d42c862892e2273318b8e0c0cce795581c56c015 100644 (file)
 
 #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);
 }
index 80f5787dc44ef7601642c0be599c43a400ce3593..96198f99c08d3023926525dec14b2e9fbc52f2bb 100644 (file)
 
 // 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 (file)
index 3d05d6d..0000000
+++ /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 (file)
index cd88979..0000000
+++ /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 (file)
index 225a524..0000000
+++ /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 (file)
index de6481c..0000000
+++ /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 (file)
index e7cc0b4..0000000
+++ /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;
-}
-*/
index 64c8ac2fe55b45574cf553cbe0cb15e762aa5e5d..f5ade5a34aa37329e7a7d827dcba5041d702c98b 100644 (file)
@@ -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 */
-};
index a09cc9727ca07f5429c8cfd9cc86ded113f5fe83..084e2cc6a7c3233053079017a864e4ca8b961824 100644 (file)
@@ -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;
index ecab867e4302293b9ba949d00137f3571b70a9e4..d2a8d94b1e9b607707b7f9de24c5850f19aba637 100644 (file)
@@ -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*
index 5040e432716408e0be63f985b46c3091a760edf8..4a7b0d04ac2d33386fb99d1293ceaca6e80c7ea1 100644 (file)
@@ -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);
index ae649a74b63b5954513e26567b99f3b30e367ce5..ac3273f9398c98ff00c8e38ea2b6d1b851a90a19 100644 (file)
@@ -30,7 +30,6 @@
 
 // Reading object files.
 
-#define        EXTERN
 #include       "l.h"
 #include       "../ld/lib.h"
 #include       "../ld/elf.h"
 #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 (file)
index f48c6c3..0000000
+++ /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 (file)
index 1be3c18..0000000
+++ /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 (file)
index 862ce08..0000000
+++ /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 (file)
index 74f11d6..0000000
+++ /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);
-       }
-}
index a28115eb4870ca6f37bdd32e6560f01ba0ce16fb..8319482ca3f85833ad863f97b4ad760046289c19 100644 (file)
@@ -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 */
-};
index 3be37ea22c1b14bb096fa5ba1fde30c37b9fb026..46e8e47ecdc0fcd977c91d115e7ffea7f589ec2d 100644 (file)
@@ -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;
index 814aa14582ca5c7bd0774885e6f0c5a79c903409..928e2e49ab5b905b2851f05d27ee82f706df2a50 100644 (file)
@@ -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)
index e2a2ec5edc7d03d1d391c7cbfb25b9a5d0f3ae2a..8e57b4af1c951934dd3d18cefb72b23aafdbb40d 100644 (file)
@@ -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);
index 3fdc413810e25c67e5a7f900b309421a049470bc..e588060bee277f924a177638434219b951520901 100644 (file)
@@ -30,7 +30,6 @@
 
 // Reading object files.
 
-#define        EXTERN
 #include       "l.h"
 #include       "../ld/lib.h"
 #include       "../ld/elf.h"
 #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 (file)
index 19952e5..0000000
+++ /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 (file)
index 1eaf78f..0000000
+++ /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 (file)
index d99c5e4..0000000
+++ /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 (file)
index acf973c..0000000
+++ /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();
-       }
-}
index 30d7c81856c5088ae4ed155513212fdfe425b770..ac28041fbba7941dfe082879fdd5128179f44376 100644 (file)
 #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);
index ab3f4fbd55a0565ff9dd662c0c85d4b6a82fb005..3859d1c6d8202fa3cf734dea119307b86175a576 100644 (file)
@@ -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);
 }
index c832bcc9441ded3fe358550e6784c30a0f9f6756..8170abe3357e08eba9e941620db11bdae7a18e26 100644 (file)
 
 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;
        }
 }
index f0df2f9b1ee8d4628a5a5b54e53f7166b2c4615f..7952a7436907b5024ed73e4f305eb3a0c5c9abbd 100644 (file)
@@ -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
index 6b3638ec56f6c63032b2da7e608d3927df62abf9..8c7ca86097847d8b0eedfc4d105741fc0aad6a7a 100644 (file)
@@ -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;
        }
 
index 5b2ff041a30d8c6183c035bd6a8445966bb5c96d..76085c7c6ec7baabdac213c486abc99fc17151d8 100644 (file)
@@ -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);
index 39ffa3d87343cff58b561357a4775dd3a3773bc2..9950a3886e9f795557634279ecc5fa402abc9941 100644 (file)
@@ -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 */
index 27041bc472c654fcb0fc0cc5eafd61d63b5a9440..4bc830ef32120a4327b2bee6e18d4d01eac27a14 100644 (file)
@@ -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;
                        }
index e0f5405f69cae0d795e67fdb92317657e5e230ce..7318381e35e93966dd48c91520bc5c0cca82be26 100644 (file)
@@ -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;
                        }
                }
        }
index 6bcda2cb66429c9987e39e82a284aa77aa6e7f12..f7e4bfcdb25e4f4d0afa51cd56cb53e8de10c9bc 100644 (file)
@@ -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:
index da522dc0c78bacf58b9feb8ac5c3874fac8b09d1..56e50acb9598c105cb00931c8e095b70b9a9bcc1 100644 (file)
@@ -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
@@ -146,146 +138,6 @@ errorexit(void)
        exits(0);
 }
 
-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)
 {
@@ -293,12 +145,12 @@ loadinternal(char *name)
        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();
+}
index be95bb46e81b14cf1495b85a147fbc5a9ea1438b..63e2825119eae3383442d453b97334e598d56604 100644 (file)
 // 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);
index d135a92dafe1f7ec75d715efcbdc0d19d13f49b7..49db83eea252d86a82e1c61e32b9cde4f5a31bd3 100644 (file)
@@ -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 (file)
index 0000000..788b7c7
--- /dev/null
@@ -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 (file)
index 0000000..5934dbc
--- /dev/null
@@ -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);
+}      
index 7b9a596fce280a9223f5e7834445393ddb1d966c..e4848643ee73e2eb7ff50b35fc486cfce31942a0 100644 (file)
@@ -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);
index 7aa938829367a9c577a2dbcfb74dfa0272263ad6..03ed8d830ae58fa75768d59fa6a58f4a982144b9 100644 (file)
@@ -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 (file)
index 0000000..8883d37
--- /dev/null
@@ -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();
+}
index c9b4657f70e431bc9e208690f42150d4db007694..54e6041483b06c449c57eb3301c50d0b4da0e479 100644 (file)
@@ -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 (file)
index 0000000..2a31746
--- /dev/null
@@ -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 (file)
index 0000000..8ed8bea
--- /dev/null
@@ -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 (file)
index 0000000..019ec06
--- /dev/null
@@ -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 (file)
index 0000000..6246276
--- /dev/null
@@ -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 (file)
index 0000000..97d2260
--- /dev/null
@@ -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 (file)
index 0000000..9f5a423
--- /dev/null
@@ -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 (file)
index 0000000..f663287
--- /dev/null
@@ -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 (file)
index 0000000..eacbc40
--- /dev/null
@@ -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 (file)
index 0000000..e9c0b57
--- /dev/null
@@ -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 (file)
index 0000000..bd24d1d
--- /dev/null
@@ -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 (file)
index 0000000..e744abe
--- /dev/null
@@ -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 (file)
index 0000000..3fe77d6
--- /dev/null
@@ -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 (file)
index 0000000..21eb944
--- /dev/null
@@ -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 (file)
index 0000000..f2a8b82
--- /dev/null
@@ -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 (file)
index 0000000..52ed18b
--- /dev/null
@@ -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 (file)
index 0000000..d84e428
--- /dev/null
@@ -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 (file)
index 0000000..e876a5c
--- /dev/null
@@ -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);
+}