Liblink is still needed for the linker (for a bit longer) but mostly not.
Delete the unused parts.
Change-Id: Ie63a7c1520dee52b17425b384943cd16262d36e3
Reviewed-on: https://go-review.googlesource.com/6110
Reviewed-by: Rob Pike <r@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
// 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 Link Link;
-typedef struct Plist Plist;
typedef struct LinkArch LinkArch;
typedef struct Library Library;
typedef struct Pcdata Pcdata;
typedef struct Pciter Pciter;
-// An Addr is an argument to an instruction.
-// The general forms and their encodings are:
-//
-// sym±offset(symkind)(reg)(index*scale)
-// Memory reference at address &sym(symkind) + offset + reg + index*scale.
-// Any of sym(symkind), ±offset, (reg), (index*scale), and *scale can be omitted.
-// If (reg) and *scale are both omitted, the resulting expression (index) is parsed as (reg).
-// To force a parsing as index*scale, write (index*1).
-// Encoding:
-// type = TYPE_MEM
-// name = symkind (NAME_AUTO, ...) or 0 (NAME_NONE)
-// sym = sym
-// offset = ±offset
-// reg = reg (REG_*)
-// index = index (REG_*)
-// scale = scale (1, 2, 4, 8)
-//
-// $<mem>
-// Effective address of memory reference <mem>, defined above.
-// Encoding: same as memory reference, but type = TYPE_ADDR.
-//
-// $<±integer value>
-// This is a special case of $<mem>, in which only ±offset is present.
-// It has a separate type for easy recognition.
-// Encoding:
-// type = TYPE_CONST
-// offset = ±integer value
-//
-// *<mem>
-// Indirect reference through memory reference <mem>, defined above.
-// Only used on x86 for CALL/JMP *sym(SB), which calls/jumps to a function
-// pointer stored in the data word sym(SB), not a function named sym(SB).
-// Encoding: same as above, but type = TYPE_INDIR.
-//
-// $*$<mem>
-// No longer used.
-// On machines with actual SB registers, $*$<mem> forced the
-// instruction encoding to use a full 32-bit constant, never a
-// reference relative to SB.
-//
-// $<floating point literal>
-// Floating point constant value.
-// Encoding:
-// type = TYPE_FCONST
-// u.dval = floating point value
-//
-// $<string literal, up to 8 chars>
-// String literal value (raw bytes used for DATA instruction).
-// Encoding:
-// type = TYPE_SCONST
-// u.sval = string
-//
-// <register name>
-// Any register: integer, floating point, control, segment, and so on.
-// If looking for specific register kind, must check type and reg value range.
-// Encoding:
-// type = TYPE_REG
-// reg = reg (REG_*)
-//
-// x(PC)
-// Encoding:
-// type = TYPE_BRANCH
-// u.branch = Prog* reference OR ELSE offset = target pc (branch takes priority)
-//
-// $±x-±y
-// Final argument to TEXT, specifying local frame size x and argument size y.
-// In this form, x and y are integer literals only, not arbitrary expressions.
-// This avoids parsing ambiguities due to the use of - as a separator.
-// The ± are optional.
-// If the final argument to TEXT omits the -±y, the encoding should still
-// use TYPE_TEXTSIZE (not TYPE_CONST), with u.argsize = ArgsSizeUnknown.
-// Encoding:
-// type = TYPE_TEXTSIZE
-// offset = x
-// u.argsize = y
-//
-// reg<<shift, reg>>shift, reg->shift, reg@>shift
-// Shifted register value, for ARM.
-// In this form, reg must be a register and shift can be a register or an integer constant.
-// Encoding:
-// type = TYPE_SHIFT
-// offset = (reg&15) | shifttype<<5 | count
-// shifttype = 0, 1, 2, 3 for <<, >>, ->, @>
-// count = (reg&15)<<8 | 1<<4 for a register shift count, (n&31)<<7 for an integer constant.
-//
-// (reg, reg)
-// A destination register pair. When used as the last argument of an instruction,
-// this form makes clear that both registers are destinations.
-// Encoding:
-// type = TYPE_REGREG
-// reg = first register
-// offset = second register
-//
-// reg, reg
-// TYPE_REGREG2, to be removed.
-//
-struct Addr
-{
- int16 type; // could be int8
- int16 reg;
- int16 index;
- int8 scale;
- int8 name;
- int64 offset;
- LSym* sym;
-
- union
- {
- char sval[8];
- float64 dval;
- Prog* branch;
- int32 argsize; // for 5l, 8l
- uint64 bits; // raw union bits, for testing if anything has been written to any field
- } u;
-
- // gotype is the name of the Go type descriptor for sym.
- // It cannot be set using assembly syntax.
- // It is generated by the Go compiler for global declarations,
- // to convey information about pointer locations to the back end
- // and for use in generating debug information.
- LSym* gotype;
-
- int8 class; // for internal use by liblink
- uint8 etype; // for internal use by 5g, 6g, 8g
- void* node; // for internal use by 5g, 6g, 8g
- int64 width; // for internal use by 5g, 6g, 8g
-};
-
-enum {
- NAME_NONE = 0,
- NAME_EXTERN,
- NAME_STATIC,
- NAME_AUTO,
- NAME_PARAM,
-};
-
-enum {
- TYPE_NONE = 0,
- TYPE_BRANCH = 5, // avoid accidental conflicts with NAME_*
- TYPE_TEXTSIZE,
- TYPE_MEM,
- TYPE_CONST,
- TYPE_FCONST,
- TYPE_SCONST,
- TYPE_REG,
- TYPE_ADDR,
- TYPE_SHIFT,
- TYPE_REGREG,
- TYPE_REGREG2,
- TYPE_INDIR,
-};
-
struct Reloc
{
int32 off;
LSym* xsym;
};
-// TODO(rsc): Describe prog.
-// TODO(rsc): Describe TEXT/GLOBL flag in from3, DATA width in from3.
-struct Prog
-{
- vlong pc;
- int32 lineno;
- Prog* link;
- short as;
- uchar scond; // arm only; condition codes
-
- // operands
- Addr from;
- int16 reg; // arm, ppc64 only (e.g., ADD from, reg, to);
- // starts at 0 for both GPRs and FPRs;
- // also used for ADATA width on arm, ppc64
- Addr from3; // addl source argument (e.g., RLWM/FMADD from, reg, from3, to)
- Addr to;
-
- // for 5g, 6g, 8g internal use
- void* opt;
-
- // for liblink internal use
- Prog* forwd;
- Prog* pcond;
- Prog* comefrom; // amd64, 386
- Prog* pcrel; // arm
- int32 spadj;
- uint16 mark;
- uint16 optab; // arm, ppc64
- uchar back; // amd64, 386
- uchar ft; // oclass cache
- uchar tt; // oclass cache
- uchar isize; // amd64, 386
- uchar printed;
-
- char width; /* fake for DATA */
- char mode; /* 16, 32, or 64 in 6l, 8l; internal use in 5g, 6g, 8g */
-};
-
-extern Prog zprog; // zeroed Prog
-
-// Prog.as opcodes.
-// These are the portable opcodes, common to all architectures.
-// Each architecture defines many more arch-specific opcodes,
-// with values starting at A_ARCHSPECIFIC.
-enum {
- AXXX = 0,
-
- ACALL,
- ACHECKNIL,
- ADATA,
- ADUFFCOPY,
- ADUFFZERO,
- AEND,
- AFUNCDATA,
- AGLOBL,
- AJMP,
- ANOP,
- APCDATA,
- ARET,
- ATEXT,
- ATYPE,
- AUNDEF,
- AUSEFIELD,
- AVARDEF,
- AVARKILL,
-
- A_ARCHSPECIFIC, // first architecture-specific opcode value
-};
-
-void nopout(Prog*);
-void nocache(Prog*);
-
// prevent incompatible type signatures between liblink and 8l on Plan 9
#pragma incomplete struct Section
uchar stkcheck;
uchar hide;
uchar leaf; // arm only
- uchar fnptr; // arm only
uchar localentry; // ppc64: instrs between global & local entry
- uchar seenglobl;
uchar onlist; // on the textp or datap lists
- uchar printed;
- int16 symid; // for writing .5/.6/.8 files
int32 dynid;
int32 sig;
int32 plt;
// STEXT
Auto* autom;
- Prog* text;
- Prog* etext;
Pcln* pcln;
// SDATA, SBSS
LINKHASH = 100003,
};
-struct Hist
-{
- Hist* link;
- char* name;
- int32 line;
- int32 offset;
- uchar printed;
-};
-
-struct Plist
-{
- LSym* name;
- Prog* firstpc;
- int recur;
- Plist* link;
-};
-
struct Library
{
char *objref; // object where we found the reference
int headtype;
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;
- char* trimpath;
char* goroot;
- char* goroot_final;
- int32 enforce_data_order; // for use by assembler
// 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[2];
LSym* tlsg;
- LSym* plan9privates;
- Prog* curp;
- Prog* printp;
- Prog* blitrl;
- Prog* elitrl;
- int rexflag;
- int rep; // for nacl
- int repn; // for nacl
- int lock; // for nacl
- int asmode;
- uchar* andptr;
- uchar and[100];
- int64 instoffset;
- int32 autosize;
- int32 armsize;
// for reading input files (during linker)
- vlong pc;
char** libdir;
int32 nlibdir;
int32 maxlibdir;
int nlibrary;
int tlsoffset;
void (*diag)(char*, ...);
- int mode;
- Auto* curauto;
- Auto* curhist;
LSym* cursym;
int version;
LSym* textp;
LSym* etextp;
- int32 histdepth;
int32 nhistfile;
LSym* filesyms;
};
int thechar; // '5', '6', and so on
int32 endian; // LittleEndian or BigEndian
- void (*preprocess)(Link*, LSym*);
- void (*assemble)(Link*, LSym*);
- void (*follow)(Link*, LSym*);
- void (*progedit)(Link*, Prog*);
-
int minlc;
int ptrsize;
int regsize;
extern uchar inuxi4[4];
extern uchar inuxi8[8];
-// asm5.c
-void span5(Link *ctxt, LSym *s);
-int chipfloat5(Link *ctxt, float64 e);
-int chipzero5(Link *ctxt, float64 e);
-
-// asm6.c
-void span6(Link *ctxt, LSym *s);
-
-// asm8.c
-void span8(Link *ctxt, LSym *s);
-
-// asm9.c
-void span9(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);
+void addlib(Link *ctxt, char *src, char *obj, char *pathname);
+void addlibpath(Link *ctxt, char *srcref, char *objref, char *file, char *pkg);
vlong addpcrelplus(Link *ctxt, LSym *s, LSym *t, vlong add);
Reloc* addrel(LSym *s);
vlong addsize(Link *ctxt, LSym *s, LSym *t);
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);
-void savedata1(Link *ctxt, LSym *s, Prog *p, char *pn, int enforce_order);
-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, vlong siz);
-
-// go.c
-void double2ieee(uint64 *ieee, double native);
+vlong atolwhex(char *s);
void* emallocz(long n);
void* erealloc(void *p, long n);
char* estrdup(char *p);
char* expandpkg(char *t0, char *pkg);
-void linksetexp(void);
-char* expstring(void);
-
-extern int fieldtrack_enabled;
-extern int framepointer_enabled;
-
-// ld.c
-void addhist(Link *ctxt, int32 line, int type);
-void addlib(Link *ctxt, char *src, char *obj, char *path);
-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);
-void linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l);
-void histtoauto(Link *ctxt);
-void mkfwd(LSym*);
-void nuxiinit(LinkArch*);
-void savehist(Link *ctxt, int32 line, int32 off);
-Prog* copyp(Link*, Prog*);
-Prog* appendp(Link*, Prog*);
-vlong atolwhex(char*);
-
-// list[5689].c
-void listinit5(void);
-void listinit6(void);
-void listinit8(void);
-void listinit9(void);
-
-// obj.c
-int linklinefmt(Link *ctxt, Fmt *fp);
-void linklinehist(Link *ctxt, int lineno, char *f, int offset);
-Plist* linknewplist(Link *ctxt);
-void linkprfile(Link *ctxt, int32 l);
-
-// objfile.c
-void ldobjfile(Link *ctxt, Biobuf *b, char *pkg, int64 len, char *path);
-void writeobj(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*);
-
-// sym.c
+char* headstr(int v);
+int headtype(char *name);
+void ldobjfile(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn);
LSym* linklookup(Link *ctxt, char *name, int v);
-Link* linknew(LinkArch*);
+Link* linknew(LinkArch *arch);
LSym* linknewsym(Link *ctxt, char *symb, int v);
LSym* linkrlookup(Link *ctxt, char *name, int v);
-int linksymfmt(Fmt *f);
-int headtype(char*);
-char* headstr(int);
-
-extern char* anames5[];
-extern char* anames6[];
-extern char* anames8[];
-extern char* anames9[];
-
-extern char* cnames5[];
-extern char* cnames9[];
-
-extern char* dnames5[];
-extern char* dnames6[];
-extern char* dnames8[];
-extern char* dnames9[];
+void nuxiinit(LinkArch *arch);
+void pciterinit(Link *ctxt, Pciter *it, Pcdata *d);
+void pciternext(Pciter *it);
+vlong setaddr(Link *ctxt, LSym *s, vlong off, LSym *t);
+vlong setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add);
+vlong setuint32(Link *ctxt, LSym *s, vlong r, uint32 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, vlong lsiz);
extern LinkArch link386;
extern LinkArch linkamd64;
extern LinkArch linkarm;
extern LinkArch linkppc64;
extern LinkArch linkppc64le;
-
-extern int linkbasepointer;
-extern void linksetexp(void);
-
-#pragma varargck type "A" int
-#pragma varargck type "E" uint
-#pragma varargck type "D" Addr*
-#pragma varargck type "lD" Addr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "^" int // for 5l/9l, C_* classes (liblink internal)
-
-// TODO(ality): remove this workaround.
-// It's here because Pconv in liblink/list?.c references %L.
-#pragma varargck type "L" int32
+++ /dev/null
-// Inferno utils/5c/5.out.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/5.out.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.
-
-enum
-{
- NSNAME = 8,
- NSYM = 50,
- NREG = 16,
-};
-#include "../ld/textflag.h"
-
-/* -1 disables use of REGARG */
-#define REGARG -1
-/*c2go enum { REGARG = -1 }; */
-
-enum
-{
- REG_R0 = 32, // must be 16-aligned
- REG_R1,
- REG_R2,
- REG_R3,
- REG_R4,
- REG_R5,
- REG_R6,
- REG_R7,
- REG_R8,
- REG_R9,
- REG_R10,
- REG_R11,
- REG_R12,
- REG_R13,
- REG_R14,
- REG_R15,
-
- REG_F0, // must be 16-aligned
- REG_F1,
- REG_F2,
- REG_F3,
- REG_F4,
- REG_F5,
- REG_F6,
- REG_F7,
- REG_F8,
- REG_F9,
- REG_F10,
- REG_F11,
- REG_F12,
- REG_F13,
- REG_F14,
- REG_F15,
-
- REG_FPSR, // must be 2-aligned
- REG_FPCR,
-
- REG_CPSR, // must be 2-aligned
- REG_SPSR,
-
- REGRET = REG_R0,
- /* compiler allocates R1 up as temps */
- /* compiler allocates register variables R3 up */
- /* compiler allocates external registers R10 down */
- REGEXT = REG_R10,
- /* these two registers are declared in runtime.h */
- REGG = REGEXT-0,
- REGM = REGEXT-1,
-
- REGCTXT = REG_R7,
- REGTMP = REG_R11,
- REGSP = REG_R13,
- REGLINK = REG_R14,
- REGPC = REG_R15,
-
- NFREG = 16,
- FREGRET = REG_F0,
- FREGEXT = REG_F7,
- FREGTMP = REG_F15,
-};
-/* compiler allocates register variables F0 up */
-/* compiler allocates external registers F7 down */
-
-enum
-{
- C_NONE,
- 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_TEXTSIZE,
-
- C_GOK,
-
- C_NCLASS, /* must be the last */
-};
-
-enum
-{
- AAND = A_ARCHSPECIFIC,
- AEOR,
- ASUB,
- ARSB,
- AADD,
- AADC,
- ASBC,
- ARSC,
- ATST,
- ATEQ,
- ACMP,
- ACMN,
- AORR,
- ABIC,
-
- AMVN,
-
-/*
- * Do not reorder or fragment the conditional branch
- * opcodes, or the predication code will break
- */
- ABEQ,
- ABNE,
- ABCS,
- ABHS,
- ABCC,
- ABLO,
- ABMI,
- ABPL,
- ABVS,
- ABVC,
- ABHI,
- ABLS,
- ABGE,
- ABLT,
- ABGT,
- ABLE,
-
- AMOVWD,
- AMOVWF,
- AMOVDW,
- AMOVFW,
- AMOVFD,
- AMOVDF,
- AMOVF,
- AMOVD,
-
- ACMPF,
- ACMPD,
- AADDF,
- AADDD,
- ASUBF,
- ASUBD,
- AMULF,
- AMULD,
- ADIVF,
- ADIVD,
- ASQRTF,
- ASQRTD,
- AABSF,
- AABSD,
-
- ASRL,
- ASRA,
- ASLL,
- AMULU,
- ADIVU,
- AMUL,
- ADIV,
- AMOD,
- AMODU,
-
- AMOVB,
- AMOVBS,
- AMOVBU,
- AMOVH,
- AMOVHS,
- AMOVHU,
- AMOVW,
- AMOVM,
- ASWPBU,
- ASWPW,
-
- ARFE,
- ASWI,
- AMULA,
-
- AWORD,
- ABCASE,
- ACASE,
-
-
- AMULL,
- AMULAL,
- AMULLU,
- AMULALU,
-
- ABX,
- ABXRET,
- ADWORD,
-
-
- ALDREX,
- ASTREX,
-
- ALDREXD,
- ASTREXD,
-
- APLD,
-
-
- ACLZ,
-
- AMULWT,
- AMULWB,
- AMULAWT,
- AMULAWB,
-
- ADATABUNDLE,
- ADATABUNDLEEND,
-
- AMRC, // MRC/MCR
-
- ALAST,
-
- // aliases
- AB = AJMP,
- ABL = ACALL,
-};
-
-/* scond byte */
-enum
-{
- C_SCOND = (1<<4)-1,
- C_SBIT = 1<<4,
- C_PBIT = 1<<5,
- C_WBIT = 1<<6,
- C_FBIT = 1<<7, /* psr flags-only */
- C_UBIT = 1<<7, /* up bit, unsigned bit */
-
- // These constants are the ARM condition codes encodings,
- // XORed with 14 so that C_SCOND_NONE has value 0,
- // so that a zeroed Prog.scond means "always execute".
- C_SCOND_XOR = 14,
-
- C_SCOND_EQ = 0 ^ C_SCOND_XOR,
- C_SCOND_NE = 1 ^ C_SCOND_XOR,
- C_SCOND_HS = 2 ^ C_SCOND_XOR,
- C_SCOND_LO = 3 ^ C_SCOND_XOR,
- C_SCOND_MI = 4 ^ C_SCOND_XOR,
- C_SCOND_PL = 5 ^ C_SCOND_XOR,
- C_SCOND_VS = 6 ^ C_SCOND_XOR,
- C_SCOND_VC = 7 ^ C_SCOND_XOR,
- C_SCOND_HI = 8 ^ C_SCOND_XOR,
- C_SCOND_LS = 9 ^ C_SCOND_XOR,
- C_SCOND_GE = 10 ^ C_SCOND_XOR,
- C_SCOND_LT = 11 ^ C_SCOND_XOR,
- C_SCOND_GT = 12 ^ C_SCOND_XOR,
- C_SCOND_LE = 13 ^ C_SCOND_XOR,
- C_SCOND_NONE = 14 ^ C_SCOND_XOR,
- C_SCOND_NV = 15 ^ C_SCOND_XOR,
-
- /* D_SHIFT type */
- SHIFT_LL = 0<<5,
- SHIFT_LR = 1<<5,
- SHIFT_AR = 2<<5,
- SHIFT_RR = 3<<5,
-};
-
-
-/*
- * this is the ranlib header
- */
-#define SYMDEF "__.GOSYMDEF"
-/*c2go extern char SYMDEF[]; */
void asmb(void);
int elfreloc1(Reloc *r, vlong sectoff);
void elfsetupplt(void);
-void listinit(void);
int machoreloc1(Reloc *r, vlong sectoff);
/* Used by ../ld/dwarf.c */
+++ /dev/null
-// Inferno utils/5l/list.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/list.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Printing.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-listinit(void)
-{
- listinit5();
-}
thearch.elfreloc1 = elfreloc1;
thearch.elfsetupplt = elfsetupplt;
thearch.gentext = gentext;
- thearch.listinit = listinit;
thearch.machoreloc1 = machoreloc1;
thearch.lput = lputl;
thearch.wput = wputl;
+++ /dev/null
-// Inferno utils/6c/6.out.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/6.out.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.
-
-#define NSYM 50
-#define NSNAME 8
-#include "../ld/textflag.h"
-
-/*
- * amd64
- */
-
-enum
-{
- AAAA = A_ARCHSPECIFIC,
- AAAD,
- AAAM,
- AAAS,
- AADCB,
- AADCL,
- AADCW,
- AADDB,
- AADDL,
- AADDW,
- AADJSP,
- AANDB,
- AANDL,
- AANDW,
- AARPL,
- ABOUNDL,
- ABOUNDW,
- ABSFL,
- ABSFW,
- ABSRL,
- ABSRW,
- ABTL,
- ABTW,
- ABTCL,
- ABTCW,
- ABTRL,
- ABTRW,
- ABTSL,
- ABTSW,
- ABYTE,
- ACLC,
- ACLD,
- ACLI,
- ACLTS,
- ACMC,
- ACMPB,
- ACMPL,
- ACMPW,
- ACMPSB,
- ACMPSL,
- ACMPSW,
- ADAA,
- ADAS,
- ADECB,
- ADECL,
- ADECQ,
- ADECW,
- ADIVB,
- ADIVL,
- ADIVW,
- AENTER,
- AHLT,
- AIDIVB,
- AIDIVL,
- AIDIVW,
- AIMULB,
- AIMULL,
- AIMULW,
- AINB,
- AINL,
- AINW,
- AINCB,
- AINCL,
- AINCQ,
- AINCW,
- AINSB,
- AINSL,
- AINSW,
- AINT,
- AINTO,
- AIRETL,
- AIRETW,
- AJCC,
- AJCS,
- AJCXZL,
- AJEQ,
- AJGE,
- AJGT,
- AJHI,
- AJLE,
- AJLS,
- AJLT,
- AJMI,
- AJNE,
- AJOC,
- AJOS,
- AJPC,
- AJPL,
- AJPS,
- ALAHF,
- ALARL,
- ALARW,
- ALEAL,
- ALEAW,
- ALEAVEL,
- ALEAVEW,
- ALOCK,
- ALODSB,
- ALODSL,
- ALODSW,
- ALONG,
- ALOOP,
- ALOOPEQ,
- ALOOPNE,
- ALSLL,
- ALSLW,
- AMOVB,
- AMOVL,
- AMOVW,
- AMOVBLSX,
- AMOVBLZX,
- AMOVBQSX,
- AMOVBQZX,
- AMOVBWSX,
- AMOVBWZX,
- AMOVWLSX,
- AMOVWLZX,
- AMOVWQSX,
- AMOVWQZX,
- AMOVSB,
- AMOVSL,
- AMOVSW,
- AMULB,
- AMULL,
- AMULW,
- ANEGB,
- ANEGL,
- ANEGW,
- ANOTB,
- ANOTL,
- ANOTW,
- AORB,
- AORL,
- AORW,
- AOUTB,
- AOUTL,
- AOUTW,
- AOUTSB,
- AOUTSL,
- AOUTSW,
- APAUSE,
- APOPAL,
- APOPAW,
- APOPFL,
- APOPFW,
- APOPL,
- APOPW,
- APUSHAL,
- APUSHAW,
- APUSHFL,
- APUSHFW,
- APUSHL,
- APUSHW,
- ARCLB,
- ARCLL,
- ARCLW,
- ARCRB,
- ARCRL,
- ARCRW,
- AREP,
- AREPN,
- AROLB,
- AROLL,
- AROLW,
- ARORB,
- ARORL,
- ARORW,
- ASAHF,
- ASALB,
- ASALL,
- ASALW,
- ASARB,
- ASARL,
- ASARW,
- ASBBB,
- ASBBL,
- ASBBW,
- ASCASB,
- ASCASL,
- ASCASW,
- ASETCC,
- ASETCS,
- ASETEQ,
- ASETGE,
- ASETGT,
- ASETHI,
- ASETLE,
- ASETLS,
- ASETLT,
- ASETMI,
- ASETNE,
- ASETOC,
- ASETOS,
- ASETPC,
- ASETPL,
- ASETPS,
- ACDQ,
- ACWD,
- ASHLB,
- ASHLL,
- ASHLW,
- ASHRB,
- ASHRL,
- ASHRW,
- ASTC,
- ASTD,
- ASTI,
- ASTOSB,
- ASTOSL,
- ASTOSW,
- ASUBB,
- ASUBL,
- ASUBW,
- ASYSCALL,
- ATESTB,
- ATESTL,
- ATESTW,
- AVERR,
- AVERW,
- AWAIT,
- AWORD,
- AXCHGB,
- AXCHGL,
- AXCHGW,
- AXLAT,
- AXORB,
- AXORL,
- AXORW,
-
- AFMOVB,
- AFMOVBP,
- AFMOVD,
- AFMOVDP,
- AFMOVF,
- AFMOVFP,
- AFMOVL,
- AFMOVLP,
- AFMOVV,
- AFMOVVP,
- AFMOVW,
- AFMOVWP,
- AFMOVX,
- AFMOVXP,
-
- AFCOMB,
- AFCOMBP,
- AFCOMD,
- AFCOMDP,
- AFCOMDPP,
- AFCOMF,
- AFCOMFP,
- AFCOML,
- AFCOMLP,
- AFCOMW,
- AFCOMWP,
- AFUCOM,
- AFUCOMP,
- AFUCOMPP,
-
- AFADDDP,
- AFADDW,
- AFADDL,
- AFADDF,
- AFADDD,
-
- AFMULDP,
- AFMULW,
- AFMULL,
- AFMULF,
- AFMULD,
-
- AFSUBDP,
- AFSUBW,
- AFSUBL,
- AFSUBF,
- AFSUBD,
-
- AFSUBRDP,
- AFSUBRW,
- AFSUBRL,
- AFSUBRF,
- AFSUBRD,
-
- AFDIVDP,
- AFDIVW,
- AFDIVL,
- AFDIVF,
- AFDIVD,
-
- AFDIVRDP,
- AFDIVRW,
- AFDIVRL,
- AFDIVRF,
- AFDIVRD,
-
- AFXCHD,
- AFFREE,
-
- AFLDCW,
- AFLDENV,
- AFRSTOR,
- AFSAVE,
- AFSTCW,
- AFSTENV,
- AFSTSW,
-
- AF2XM1,
- AFABS,
- AFCHS,
- AFCLEX,
- AFCOS,
- AFDECSTP,
- AFINCSTP,
- AFINIT,
- AFLD1,
- AFLDL2E,
- AFLDL2T,
- AFLDLG2,
- AFLDLN2,
- AFLDPI,
- AFLDZ,
- AFNOP,
- AFPATAN,
- AFPREM,
- AFPREM1,
- AFPTAN,
- AFRNDINT,
- AFSCALE,
- AFSIN,
- AFSINCOS,
- AFSQRT,
- AFTST,
- AFXAM,
- AFXTRACT,
- AFYL2X,
- AFYL2XP1,
-
-
-
-
- /* extra 32-bit operations */
- ACMPXCHGB,
- ACMPXCHGL,
- ACMPXCHGW,
- ACMPXCHG8B,
- ACPUID,
- AINVD,
- AINVLPG,
- ALFENCE,
- AMFENCE,
- AMOVNTIL,
- ARDMSR,
- ARDPMC,
- ARDTSC,
- ARSM,
- ASFENCE,
- ASYSRET,
- AWBINVD,
- AWRMSR,
- AXADDB,
- AXADDL,
- AXADDW,
-
- /* conditional move */
- ACMOVLCC,
- ACMOVLCS,
- ACMOVLEQ,
- ACMOVLGE,
- ACMOVLGT,
- ACMOVLHI,
- ACMOVLLE,
- ACMOVLLS,
- ACMOVLLT,
- ACMOVLMI,
- ACMOVLNE,
- ACMOVLOC,
- ACMOVLOS,
- ACMOVLPC,
- ACMOVLPL,
- ACMOVLPS,
- ACMOVQCC,
- ACMOVQCS,
- ACMOVQEQ,
- ACMOVQGE,
- ACMOVQGT,
- ACMOVQHI,
- ACMOVQLE,
- ACMOVQLS,
- ACMOVQLT,
- ACMOVQMI,
- ACMOVQNE,
- ACMOVQOC,
- ACMOVQOS,
- ACMOVQPC,
- ACMOVQPL,
- ACMOVQPS,
- ACMOVWCC,
- ACMOVWCS,
- ACMOVWEQ,
- ACMOVWGE,
- ACMOVWGT,
- ACMOVWHI,
- ACMOVWLE,
- ACMOVWLS,
- ACMOVWLT,
- ACMOVWMI,
- ACMOVWNE,
- ACMOVWOC,
- ACMOVWOS,
- ACMOVWPC,
- ACMOVWPL,
- ACMOVWPS,
-
- /* 64-bit */
- AADCQ,
- AADDQ,
- AANDQ,
- ABSFQ,
- ABSRQ,
- ABTCQ,
- ABTQ,
- ABTRQ,
- ABTSQ,
- ACMPQ,
- ACMPSQ,
- ACMPXCHGQ,
- ACQO,
- ADIVQ,
- AIDIVQ,
- AIMULQ,
- AIRETQ,
- AJCXZQ,
- ALEAQ,
- ALEAVEQ,
- ALODSQ,
- AMOVQ,
- AMOVLQSX,
- AMOVLQZX,
- AMOVNTIQ,
- AMOVSQ,
- AMULQ,
- ANEGQ,
- ANOTQ,
- AORQ,
- APOPFQ,
- APOPQ,
- APUSHFQ,
- APUSHQ,
- ARCLQ,
- ARCRQ,
- AROLQ,
- ARORQ,
- AQUAD,
- ASALQ,
- ASARQ,
- ASBBQ,
- ASCASQ,
- ASHLQ,
- ASHRQ,
- ASTOSQ,
- ASUBQ,
- ATESTQ,
- AXADDQ,
- AXCHGQ,
- AXORQ,
-
- /* media */
- AADDPD,
- AADDPS,
- AADDSD,
- AADDSS,
- AANDNPD,
- AANDNPS,
- AANDPD,
- AANDPS,
- ACMPPD,
- ACMPPS,
- ACMPSD,
- ACMPSS,
- ACOMISD,
- ACOMISS,
- ACVTPD2PL,
- ACVTPD2PS,
- ACVTPL2PD,
- ACVTPL2PS,
- ACVTPS2PD,
- ACVTPS2PL,
- ACVTSD2SL,
- ACVTSD2SQ,
- ACVTSD2SS,
- ACVTSL2SD,
- ACVTSL2SS,
- ACVTSQ2SD,
- ACVTSQ2SS,
- ACVTSS2SD,
- ACVTSS2SL,
- ACVTSS2SQ,
- ACVTTPD2PL,
- ACVTTPS2PL,
- ACVTTSD2SL,
- ACVTTSD2SQ,
- ACVTTSS2SL,
- ACVTTSS2SQ,
- ADIVPD,
- ADIVPS,
- ADIVSD,
- ADIVSS,
- AEMMS,
- AFXRSTOR,
- AFXRSTOR64,
- AFXSAVE,
- AFXSAVE64,
- ALDMXCSR,
- AMASKMOVOU,
- AMASKMOVQ,
- AMAXPD,
- AMAXPS,
- AMAXSD,
- AMAXSS,
- AMINPD,
- AMINPS,
- AMINSD,
- AMINSS,
- AMOVAPD,
- AMOVAPS,
- AMOVOU,
- AMOVHLPS,
- AMOVHPD,
- AMOVHPS,
- AMOVLHPS,
- AMOVLPD,
- AMOVLPS,
- AMOVMSKPD,
- AMOVMSKPS,
- AMOVNTO,
- AMOVNTPD,
- AMOVNTPS,
- AMOVNTQ,
- AMOVO,
- AMOVQOZX,
- AMOVSD,
- AMOVSS,
- AMOVUPD,
- AMOVUPS,
- AMULPD,
- AMULPS,
- AMULSD,
- AMULSS,
- AORPD,
- AORPS,
- APACKSSLW,
- APACKSSWB,
- APACKUSWB,
- APADDB,
- APADDL,
- APADDQ,
- APADDSB,
- APADDSW,
- APADDUSB,
- APADDUSW,
- APADDW,
- APANDB,
- APANDL,
- APANDSB,
- APANDSW,
- APANDUSB,
- APANDUSW,
- APANDW,
- APAND,
- APANDN,
- APAVGB,
- APAVGW,
- APCMPEQB,
- APCMPEQL,
- APCMPEQW,
- APCMPGTB,
- APCMPGTL,
- APCMPGTW,
- APEXTRW,
- APFACC,
- APFADD,
- APFCMPEQ,
- APFCMPGE,
- APFCMPGT,
- APFMAX,
- APFMIN,
- APFMUL,
- APFNACC,
- APFPNACC,
- APFRCP,
- APFRCPIT1,
- APFRCPI2T,
- APFRSQIT1,
- APFRSQRT,
- APFSUB,
- APFSUBR,
- APINSRW,
- APINSRD,
- APINSRQ,
- APMADDWL,
- APMAXSW,
- APMAXUB,
- APMINSW,
- APMINUB,
- APMOVMSKB,
- APMULHRW,
- APMULHUW,
- APMULHW,
- APMULLW,
- APMULULQ,
- APOR,
- APSADBW,
- APSHUFHW,
- APSHUFL,
- APSHUFLW,
- APSHUFW,
- APSHUFB,
- APSLLO,
- APSLLL,
- APSLLQ,
- APSLLW,
- APSRAL,
- APSRAW,
- APSRLO,
- APSRLL,
- APSRLQ,
- APSRLW,
- APSUBB,
- APSUBL,
- APSUBQ,
- APSUBSB,
- APSUBSW,
- APSUBUSB,
- APSUBUSW,
- APSUBW,
- APSWAPL,
- APUNPCKHBW,
- APUNPCKHLQ,
- APUNPCKHQDQ,
- APUNPCKHWL,
- APUNPCKLBW,
- APUNPCKLLQ,
- APUNPCKLQDQ,
- APUNPCKLWL,
- APXOR,
- ARCPPS,
- ARCPSS,
- ARSQRTPS,
- ARSQRTSS,
- ASHUFPD,
- ASHUFPS,
- ASQRTPD,
- ASQRTPS,
- ASQRTSD,
- ASQRTSS,
- ASTMXCSR,
- ASUBPD,
- ASUBPS,
- ASUBSD,
- ASUBSS,
- AUCOMISD,
- AUCOMISS,
- AUNPCKHPD,
- AUNPCKHPS,
- AUNPCKLPD,
- AUNPCKLPS,
- AXORPD,
- AXORPS,
-
- APF2IW,
- APF2IL,
- API2FW,
- API2FL,
- ARETFW,
- ARETFL,
- ARETFQ,
- ASWAPGS,
-
- AMODE,
- ACRC32B,
- ACRC32Q,
- AIMUL3Q,
-
- APREFETCHT0,
- APREFETCHT1,
- APREFETCHT2,
- APREFETCHNTA,
-
- AMOVQL,
- ABSWAPL,
- ABSWAPQ,
-
-
- AAESENC,
- AAESENCLAST,
- AAESDEC,
- AAESDECLAST,
- AAESIMC,
- AAESKEYGENASSIST,
-
- APSHUFD,
- APCLMULQDQ,
-
-
- ALAST
-};
-
-enum
-{
- REG_NONE = 0,
-
- REG_AL = 0+16,
- REG_CL,
- REG_DL,
- REG_BL,
- REG_SPB,
- REG_BPB,
- REG_SIB,
- REG_DIB,
- REG_R8B,
- REG_R9B,
- REG_R10B,
- REG_R11B,
- REG_R12B,
- REG_R13B,
- REG_R14B,
- REG_R15B,
-
- REG_AX = 16+16,
- REG_CX,
- REG_DX,
- REG_BX,
- REG_SP,
- REG_BP,
- REG_SI,
- REG_DI,
- REG_R8,
- REG_R9,
- REG_R10,
- REG_R11,
- REG_R12,
- REG_R13,
- REG_R14,
- REG_R15,
-
- REG_AH = 32+16,
- REG_CH,
- REG_DH,
- REG_BH,
-
- REG_F0 = 36+16,
-
- REG_M0 = 44+16,
-
- REG_X0 = 52+16,
- REG_X1,
- REG_X2,
- REG_X3,
- REG_X4,
- REG_X5,
- REG_X6,
- REG_X7,
- REG_X8,
- REG_X9,
- REG_X10,
- REG_X11,
- REG_X12,
- REG_X13,
- REG_X14,
- REG_X15,
-
- REG_CS = 68+16,
- REG_SS,
- REG_DS,
- REG_ES,
- REG_FS,
- REG_GS,
-
- REG_GDTR, /* global descriptor table register */
- REG_IDTR, /* interrupt descriptor table register */
- REG_LDTR, /* local descriptor table register */
- REG_MSW, /* machine status word */
- REG_TASK, /* task register */
-
- REG_CR = 79+16,
- REG_DR = 95+16,
- REG_TR = 103+16,
-
- REG_TLS = 111+16,
- MAXREG,
-
- REGARG = -1,
- REGRET = REG_AX,
- FREGRET = REG_X0,
- REGSP = REG_SP,
- REGTMP = REG_DI,
- REGCTXT = REG_DX,
- REGEXT = REG_R15, /* compiler allocates external registers R15 down */
- FREGMIN = REG_X0+5, /* first register variable */
- FREGEXT = REG_X0+15, /* first external register */
-
- T_TYPE = 1<<0,
- T_INDEX = 1<<1,
- T_OFFSET = 1<<2,
- T_FCONST = 1<<3,
- T_SYM = 1<<4,
- T_SCONST = 1<<5,
- T_64 = 1<<6,
- T_GOTYPE = 1<<7,
-};
-
-/*
- * this is the ranlib header
- */
-#define SYMDEF "__.GOSYMDEF"
void asmb(void);
int elfreloc1(Reloc *r, vlong sectoff);
void elfsetupplt(void);
-void listinit(void);
int machoreloc1(Reloc *r, vlong sectoff);
/* Used by ../ld/dwarf.c */
+++ /dev/null
-// Inferno utils/6l/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/list.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Printing.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-listinit(void)
-{
- listinit6();
-}
thearch.elfreloc1 = elfreloc1;
thearch.elfsetupplt = elfsetupplt;
thearch.gentext = gentext;
- thearch.listinit = listinit;
thearch.machoreloc1 = machoreloc1;
thearch.lput = lputl;
thearch.wput = wputl;
+++ /dev/null
-// Inferno utils/8c/8.out.h
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/8.out.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.
-
-#define NSYM 50
-#define NSNAME 8
-#include "../ld/textflag.h"
-
-enum
-{
- AAAA = A_ARCHSPECIFIC,
- AAAD,
- AAAM,
- AAAS,
- AADCB,
- AADCL,
- AADCW,
- AADDB,
- AADDL,
- AADDW,
- AADJSP,
- AANDB,
- AANDL,
- AANDW,
- AARPL,
- ABOUNDL,
- ABOUNDW,
- ABSFL,
- ABSFW,
- ABSRL,
- ABSRW,
- ABTL,
- ABTW,
- ABTCL,
- ABTCW,
- ABTRL,
- ABTRW,
- ABTSL,
- ABTSW,
- ABYTE,
- ACLC,
- ACLD,
- ACLI,
- ACLTS,
- ACMC,
- ACMPB,
- ACMPL,
- ACMPW,
- ACMPSB,
- ACMPSL,
- ACMPSW,
- ADAA,
- ADAS,
- ADECB,
- ADECL,
- ADECW,
- ADIVB,
- ADIVL,
- ADIVW,
- AENTER,
- AHLT,
- AIDIVB,
- AIDIVL,
- AIDIVW,
- AIMULB,
- AIMULL,
- AIMULW,
- AINB,
- AINL,
- AINW,
- AINCB,
- AINCL,
- AINCW,
- AINSB,
- AINSL,
- AINSW,
- AINT,
- AINTO,
- AIRETL,
- AIRETW,
- AJCC,
- AJCS,
- AJCXZL,
- AJCXZW,
- AJEQ,
- AJGE,
- AJGT,
- AJHI,
- AJLE,
- AJLS,
- AJLT,
- AJMI,
- AJNE,
- AJOC,
- AJOS,
- AJPC,
- AJPL,
- AJPS,
- ALAHF,
- ALARL,
- ALARW,
- ALEAL,
- ALEAW,
- ALEAVEL,
- ALEAVEW,
- ALOCK,
- ALODSB,
- ALODSL,
- ALODSW,
- ALONG,
- ALOOP,
- ALOOPEQ,
- ALOOPNE,
- ALSLL,
- ALSLW,
- AMOVB,
- AMOVL,
- AMOVW,
- AMOVQ,
- AMOVBLSX,
- AMOVBLZX,
- AMOVBWSX,
- AMOVBWZX,
- AMOVWLSX,
- AMOVWLZX,
- AMOVSB,
- AMOVSL,
- AMOVSW,
- AMULB,
- AMULL,
- AMULW,
- ANEGB,
- ANEGL,
- ANEGW,
- ANOTB,
- ANOTL,
- ANOTW,
- AORB,
- AORL,
- AORW,
- AOUTB,
- AOUTL,
- AOUTW,
- AOUTSB,
- AOUTSL,
- AOUTSW,
- APAUSE,
- APOPAL,
- APOPAW,
- APOPFL,
- APOPFW,
- APOPL,
- APOPW,
- APUSHAL,
- APUSHAW,
- APUSHFL,
- APUSHFW,
- APUSHL,
- APUSHW,
- ARCLB,
- ARCLL,
- ARCLW,
- ARCRB,
- ARCRL,
- ARCRW,
- AREP,
- AREPN,
- AROLB,
- AROLL,
- AROLW,
- ARORB,
- ARORL,
- ARORW,
- ASAHF,
- ASALB,
- ASALL,
- ASALW,
- ASARB,
- ASARL,
- ASARW,
- ASBBB,
- ASBBL,
- ASBBW,
- ASCASB,
- ASCASL,
- ASCASW,
- ASETCC,
- ASETCS,
- ASETEQ,
- ASETGE,
- ASETGT,
- ASETHI,
- ASETLE,
- ASETLS,
- ASETLT,
- ASETMI,
- ASETNE,
- ASETOC,
- ASETOS,
- ASETPC,
- ASETPL,
- ASETPS,
- ACDQ,
- ACWD,
- ASHLB,
- ASHLL,
- ASHLW,
- ASHRB,
- ASHRL,
- ASHRW,
- ASTC,
- ASTD,
- ASTI,
- ASTOSB,
- ASTOSL,
- ASTOSW,
- ASUBB,
- ASUBL,
- ASUBW,
- ASYSCALL,
- ATESTB,
- ATESTL,
- ATESTW,
- AVERR,
- AVERW,
- AWAIT,
- AWORD,
- AXCHGB,
- AXCHGL,
- AXCHGW,
- AXLAT,
- AXORB,
- AXORL,
- AXORW,
-
- AFMOVB,
- AFMOVBP,
- AFMOVD,
- AFMOVDP,
- AFMOVF,
- AFMOVFP,
- AFMOVL,
- AFMOVLP,
- AFMOVV,
- AFMOVVP,
- AFMOVW,
- AFMOVWP,
- AFMOVX,
- AFMOVXP,
-
- AFCOMB,
- AFCOMBP,
- AFCOMD,
- AFCOMDP,
- AFCOMDPP,
- AFCOMF,
- AFCOMFP,
- AFCOMI,
- AFCOMIP,
- AFCOML,
- AFCOMLP,
- AFCOMW,
- AFCOMWP,
- AFUCOM,
- AFUCOMI,
- AFUCOMIP,
- AFUCOMP,
- AFUCOMPP,
-
- AFADDDP,
- AFADDW,
- AFADDL,
- AFADDF,
- AFADDD,
-
- AFMULDP,
- AFMULW,
- AFMULL,
- AFMULF,
- AFMULD,
-
- AFSUBDP,
- AFSUBW,
- AFSUBL,
- AFSUBF,
- AFSUBD,
-
- AFSUBRDP,
- AFSUBRW,
- AFSUBRL,
- AFSUBRF,
- AFSUBRD,
-
- AFDIVDP,
- AFDIVW,
- AFDIVL,
- AFDIVF,
- AFDIVD,
-
- AFDIVRDP,
- AFDIVRW,
- AFDIVRL,
- AFDIVRF,
- AFDIVRD,
-
- AFXCHD,
- AFFREE,
-
- AFLDCW,
- AFLDENV,
- AFRSTOR,
- AFSAVE,
- AFSTCW,
- AFSTENV,
- AFSTSW,
-
- AF2XM1,
- AFABS,
- AFCHS,
- AFCLEX,
- AFCOS,
- AFDECSTP,
- AFINCSTP,
- AFINIT,
- AFLD1,
- AFLDL2E,
- AFLDL2T,
- AFLDLG2,
- AFLDLN2,
- AFLDPI,
- AFLDZ,
- AFNOP,
- AFPATAN,
- AFPREM,
- AFPREM1,
- AFPTAN,
- AFRNDINT,
- AFSCALE,
- AFSIN,
- AFSINCOS,
- AFSQRT,
- AFTST,
- AFXAM,
- AFXTRACT,
- AFYL2X,
- AFYL2XP1,
-
-
-
-
- ACMPXCHGB,
- ACMPXCHGL,
- ACMPXCHGW,
- ACMPXCHG8B,
-
- ACPUID,
- ARDTSC,
-
- AXADDB,
- AXADDL,
- AXADDW,
-
- /* conditional move */
- ACMOVLCC,
- ACMOVLCS,
- ACMOVLEQ,
- ACMOVLGE,
- ACMOVLGT,
- ACMOVLHI,
- ACMOVLLE,
- ACMOVLLS,
- ACMOVLLT,
- ACMOVLMI,
- ACMOVLNE,
- ACMOVLOC,
- ACMOVLOS,
- ACMOVLPC,
- ACMOVLPL,
- ACMOVLPS,
- ACMOVWCC,
- ACMOVWCS,
- ACMOVWEQ,
- ACMOVWGE,
- ACMOVWGT,
- ACMOVWHI,
- ACMOVWLE,
- ACMOVWLS,
- ACMOVWLT,
- ACMOVWMI,
- ACMOVWNE,
- ACMOVWOC,
- ACMOVWOS,
- ACMOVWPC,
- ACMOVWPL,
- ACMOVWPS,
-
- AFCMOVCC,
- AFCMOVCS,
- AFCMOVEQ,
- AFCMOVHI,
- AFCMOVLS,
- AFCMOVNE,
- AFCMOVNU,
- AFCMOVUN,
-
- ALFENCE,
- AMFENCE,
- ASFENCE,
-
- AEMMS,
-
- APREFETCHT0,
- APREFETCHT1,
- APREFETCHT2,
- APREFETCHNTA,
-
- ABSWAPL,
-
-
- // SSE2
- AADDPD,
- AADDPS,
- AADDSD,
- AADDSS,
- AANDNPD,
- AANDNPS,
- AANDPD,
- AANDPS,
- ACMPPD,
- ACMPPS,
- ACMPSD,
- ACMPSS,
- ACOMISD,
- ACOMISS,
- ACVTPL2PD,
- ACVTPL2PS,
- ACVTPD2PL,
- ACVTPD2PS,
- ACVTPS2PL,
- ACVTPS2PD,
- ACVTSD2SL,
- ACVTSD2SS,
- ACVTSL2SD,
- ACVTSL2SS,
- ACVTSS2SD,
- ACVTSS2SL,
- ACVTTPD2PL,
- ACVTTPS2PL,
- ACVTTSD2SL,
- ACVTTSS2SL,
- ADIVPD,
- ADIVPS,
- ADIVSD,
- ADIVSS,
- AMASKMOVOU,
- AMAXPD,
- AMAXPS,
- AMAXSD,
- AMAXSS,
- AMINPD,
- AMINPS,
- AMINSD,
- AMINSS,
- AMOVAPD,
- AMOVAPS,
- AMOVO,
- AMOVOU,
- AMOVHLPS,
- AMOVHPD,
- AMOVHPS,
- AMOVLHPS,
- AMOVLPD,
- AMOVLPS,
- AMOVMSKPD,
- AMOVMSKPS,
- AMOVNTO,
- AMOVNTPD,
- AMOVNTPS,
- AMOVSD,
- AMOVSS,
- AMOVUPD,
- AMOVUPS,
- AMULPD,
- AMULPS,
- AMULSD,
- AMULSS,
- AORPD,
- AORPS,
- APADDQ,
- APAND,
- APCMPEQB,
- APMAXSW,
- APMAXUB,
- APMINSW,
- APMINUB,
- APMOVMSKB,
- APSADBW,
- APSUBB,
- APSUBL,
- APSUBQ,
- APSUBSB,
- APSUBSW,
- APSUBUSB,
- APSUBUSW,
- APSUBW,
- APUNPCKHQDQ,
- APUNPCKLQDQ,
- APXOR,
- ARCPPS,
- ARCPSS,
- ARSQRTPS,
- ARSQRTSS,
- ASQRTPD,
- ASQRTPS,
- ASQRTSD,
- ASQRTSS,
- ASUBPD,
- ASUBPS,
- ASUBSD,
- ASUBSS,
- AUCOMISD,
- AUCOMISS,
- AUNPCKHPD,
- AUNPCKHPS,
- AUNPCKLPD,
- AUNPCKLPS,
- AXORPD,
- AXORPS,
- APSHUFHW,
- APSHUFL,
- APSHUFLW,
-
- /* SSE 3+ */
- AAESENC,
- APINSRD,
- APSHUFB,
-
-
- ALAST
-};
-
-enum
-{
- REG_NONE = 0,
-
- REG_AL = 0+16,
- REG_CL,
- REG_DL,
- REG_BL,
-
- REG_AH = 4+16,
- REG_CH,
- REG_DH,
- REG_BH,
-
- REG_AX = 8+16,
- REG_CX,
- REG_DX,
- REG_BX,
- REG_SP,
- REG_BP,
- REG_SI,
- REG_DI,
-
- REG_F0 = 16+16,
- REG_F7 = REG_F0 + 7+16,
-
- REG_CS = 24+16,
- REG_SS,
- REG_DS,
- REG_ES,
- REG_FS,
- REG_GS,
-
- REG_GDTR, /* global descriptor table register */
- REG_IDTR, /* interrupt descriptor table register */
- REG_LDTR, /* local descriptor table register */
- REG_MSW, /* machine status word */
- REG_TASK, /* task register */
-
- REG_CR = 35+16,
- REG_DR = 43+16,
- REG_TR = 51+16,
-
- REG_X0 = 59+16,
- REG_X1,
- REG_X2,
- REG_X3,
- REG_X4,
- REG_X5,
- REG_X6,
- REG_X7,
-
- REG_TLS = 67+16,
- MAXREG = 68+16,
-
- T_TYPE = 1<<0,
- T_INDEX = 1<<1,
- T_OFFSET = 1<<2,
- T_FCONST = 1<<3,
- T_SYM = 1<<4,
- T_SCONST = 1<<5,
- T_OFFSET2 = 1<<6,
- T_GOTYPE = 1<<7,
-
- REGARG = -1,
- REGRET = REG_AX,
- FREGRET = REG_F0,
- REGSP = REG_SP,
- REGTMP = REG_DI,
- REGCTXT = REG_DX,
-};
-
-/*
- * this is the ranlib header
- */
-#define SYMDEF "__.GOSYMDEF"
void asmb(void);
int elfreloc1(Reloc *r, vlong sectoff);
void elfsetupplt(void);
-void listinit(void);
int machoreloc1(Reloc *r, vlong sectoff);
/* Used by ../ld/dwarf.c */
+++ /dev/null
-// Inferno utils/8l/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/list.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Printing.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-listinit(void)
-{
- listinit8();
-}
thearch.elfreloc1 = elfreloc1;
thearch.elfsetupplt = elfsetupplt;
thearch.gentext = gentext;
- thearch.listinit = listinit;
thearch.machoreloc1 = machoreloc1;
thearch.lput = lputl;
thearch.wput = wputl;
+++ /dev/null
-// cmd/9c/9.out.h from Vita Nuova.
-//
-// 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-2008 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-2008 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.
-
-/*
- * powerpc 64
- */
-enum
-{
- NSNAME = 8,
- NSYM = 50,
- NREG = 32, /* number of general registers */
- NFREG = 32, /* number of floating point registers */
-};
-
-#include "../ld/textflag.h"
-
-// avoid conflict with ucontext.h. sigh.
-#undef REG_R0
-#undef REG_R1
-#undef REG_R2
-#undef REG_R3
-#undef REG_R4
-#undef REG_R5
-#undef REG_R6
-#undef REG_R7
-#undef REG_R8
-#undef REG_R9
-#undef REG_R10
-#undef REG_R11
-#undef REG_R12
-#undef REG_R13
-#undef REG_R14
-#undef REG_R15
-#undef REG_R16
-#undef REG_R17
-#undef REG_R18
-#undef REG_R19
-#undef REG_R20
-#undef REG_R21
-#undef REG_R22
-#undef REG_R23
-#undef REG_R24
-#undef REG_R25
-#undef REG_R26
-#undef REG_R27
-#undef REG_R28
-#undef REG_R29
-#undef REG_R30
-#undef REG_R31
-#define REG_R0 GO_REG_R0
-#define REG_R1 GO_REG_R1
-#define REG_R2 GO_REG_R2
-#define REG_R3 GO_REG_R3
-#define REG_R4 GO_REG_R4
-#define REG_R5 GO_REG_R5
-#define REG_R6 GO_REG_R6
-#define REG_R7 GO_REG_R7
-#define REG_R8 GO_REG_R8
-#define REG_R9 GO_REG_R9
-#define REG_R10 GO_REG_R10
-#define REG_R11 GO_REG_R11
-#define REG_R12 GO_REG_R12
-#define REG_R13 GO_REG_R13
-#define REG_R14 GO_REG_R14
-#define REG_R15 GO_REG_R15
-#define REG_R16 GO_REG_R16
-#define REG_R17 GO_REG_R17
-#define REG_R18 GO_REG_R18
-#define REG_R19 GO_REG_R19
-#define REG_R20 GO_REG_R20
-#define REG_R21 GO_REG_R21
-#define REG_R22 GO_REG_R22
-#define REG_R23 GO_REG_R23
-#define REG_R24 GO_REG_R24
-#define REG_R25 GO_REG_R25
-#define REG_R26 GO_REG_R26
-#define REG_R27 GO_REG_R27
-#define REG_R28 GO_REG_R28
-#define REG_R29 GO_REG_R29
-#define REG_R30 GO_REG_R30
-#define REG_R31 GO_REG_R31
-
-enum
-{
- REG_R0 = 32,
- REG_R1,
- REG_R2,
- REG_R3,
- REG_R4,
- REG_R5,
- REG_R6,
- REG_R7,
- REG_R8,
- REG_R9,
- REG_R10,
- REG_R11,
- REG_R12,
- REG_R13,
- REG_R14,
- REG_R15,
- REG_R16,
- REG_R17,
- REG_R18,
- REG_R19,
- REG_R20,
- REG_R21,
- REG_R22,
- REG_R23,
- REG_R24,
- REG_R25,
- REG_R26,
- REG_R27,
- REG_R28,
- REG_R29,
- REG_R30,
- REG_R31,
-
- REG_F0 = 64,
- REG_F1,
- REG_F2,
- REG_F3,
- REG_F4,
- REG_F5,
- REG_F6,
- REG_F7,
- REG_F8,
- REG_F9,
- REG_F10,
- REG_F11,
- REG_F12,
- REG_F13,
- REG_F14,
- REG_F15,
- REG_F16,
- REG_F17,
- REG_F18,
- REG_F19,
- REG_F20,
- REG_F21,
- REG_F22,
- REG_F23,
- REG_F24,
- REG_F25,
- REG_F26,
- REG_F27,
- REG_F28,
- REG_F29,
- REG_F30,
- REG_F31,
-
- REG_SPECIAL = 96,
-
- REG_C0 = 96,
- REG_C1,
- REG_C2,
- REG_C3,
- REG_C4,
- REG_C5,
- REG_C6,
- REG_C7,
-
- REG_MSR = 104,
- REG_FPSCR,
- REG_CR,
-
- REG_SPR0 = 1024, // first of 1024 registers
- REG_DCR0 = 2048, // first of 1024 registers
-
- REG_XER = REG_SPR0 + 1,
- REG_LR = REG_SPR0 + 8,
- REG_CTR = REG_SPR0 + 9,
-
- REGZERO = REG_R0, /* set to zero */
- REGSP = REG_R1,
- REGSB = REG_R2,
- REGRET = REG_R3,
- REGARG = -1, /* -1 disables passing the first argument in register */
- REGRT1 = REG_R3, /* reserved for runtime, duffzero and duffcopy */
- REGRT2 = REG_R4, /* reserved for runtime, duffcopy */
- REGMIN = REG_R7, /* register variables allocated from here to REGMAX */
- REGCTXT = REG_R11, /* context for closures */
- REGTLS = REG_R13, /* C ABI TLS base pointer */
- REGMAX = REG_R27,
- REGEXT = REG_R30, /* external registers allocated from here down */
- REGG = REG_R30, /* G */
- REGTMP = REG_R31, /* used by the linker */
-
- FREGRET = REG_F0,
- FREGMIN = REG_F17, /* first register variable */
- FREGMAX = REG_F26, /* last register variable for 9g only */
- FREGEXT = REG_F26, /* first external register */
- FREGCVI = REG_F27, /* floating conversion constant */
- FREGZERO = REG_F28, /* both float and double */
- FREGHALF = REG_F29, /* double */
- FREGONE = REG_F30, /* double */
- FREGTWO = REG_F31 /* double */
-/*
- * GENERAL:
- *
- * compiler allocates R3 up as temps
- * compiler allocates register variables R7-R27
- * compiler allocates external registers R30 down
- *
- * compiler allocates register variables F17-F26
- * compiler allocates external registers F26 down
- */
-};
-
-enum {
- BIG = 32768-8,
-};
-
-enum {
-/* mark flags */
- LABEL = 1<<0,
- LEAF = 1<<1,
- FLOAT = 1<<2,
- BRANCH = 1<<3,
- LOAD = 1<<4,
- FCMP = 1<<5,
- SYNC = 1<<6,
- LIST = 1<<7,
- FOLL = 1<<8,
- NOSCHED = 1<<9,
-};
-
-enum
-{
- C_NONE,
- C_REG,
- C_FREG,
- C_CREG,
- C_SPR, /* special processor register */
- C_ZCON,
- C_SCON, /* 16 bit signed */
- C_UCON, /* 32 bit signed, low 16 bits 0 */
- C_ADDCON, /* -0x8000 <= v < 0 */
- C_ANDCON, /* 0 < v <= 0xFFFF */
- C_LCON, /* other 32 */
- C_DCON, /* other 64 (could subdivide further) */
- C_SACON, /* $n(REG) where n <= int16 */
- C_SECON,
- C_LACON, /* $n(REG) where int16 < n <= int32 */
- C_LECON,
- C_DACON, /* $n(REG) where int32 < n */
- C_SBRA,
- C_LBRA,
- C_SAUTO,
- C_LAUTO,
- C_SEXT,
- C_LEXT,
- C_ZOREG,
- C_SOREG,
- C_LOREG,
- C_FPSCR,
- C_MSR,
- C_XER,
- C_LR,
- C_CTR,
- C_ANY,
- C_GOK,
- C_ADDR,
- C_TEXTSIZE,
-
- C_NCLASS, /* must be the last */
-};
-
-enum
-{
- AADD = A_ARCHSPECIFIC,
- AADDCC,
- AADDV,
- AADDVCC,
- AADDC,
- AADDCCC,
- AADDCV,
- AADDCVCC,
- AADDME,
- AADDMECC,
- AADDMEVCC,
- AADDMEV,
- AADDE,
- AADDECC,
- AADDEVCC,
- AADDEV,
- AADDZE,
- AADDZECC,
- AADDZEVCC,
- AADDZEV,
- AAND,
- AANDCC,
- AANDN,
- AANDNCC,
- ABC,
- ABCL,
- ABEQ,
- ABGE,
- ABGT,
- ABLE,
- ABLT,
- ABNE,
- ABVC,
- ABVS,
- ACMP,
- ACMPU,
- ACNTLZW,
- ACNTLZWCC,
- ACRAND,
- ACRANDN,
- ACREQV,
- ACRNAND,
- ACRNOR,
- ACROR,
- ACRORN,
- ACRXOR,
- ADIVW,
- ADIVWCC,
- ADIVWVCC,
- ADIVWV,
- ADIVWU,
- ADIVWUCC,
- ADIVWUVCC,
- ADIVWUV,
- AEQV,
- AEQVCC,
- AEXTSB,
- AEXTSBCC,
- AEXTSH,
- AEXTSHCC,
- AFABS,
- AFABSCC,
- AFADD,
- AFADDCC,
- AFADDS,
- AFADDSCC,
- AFCMPO,
- AFCMPU,
- AFCTIW,
- AFCTIWCC,
- AFCTIWZ,
- AFCTIWZCC,
- AFDIV,
- AFDIVCC,
- AFDIVS,
- AFDIVSCC,
- AFMADD,
- AFMADDCC,
- AFMADDS,
- AFMADDSCC,
- AFMOVD,
- AFMOVDCC,
- AFMOVDU,
- AFMOVS,
- AFMOVSU,
- AFMSUB,
- AFMSUBCC,
- AFMSUBS,
- AFMSUBSCC,
- AFMUL,
- AFMULCC,
- AFMULS,
- AFMULSCC,
- AFNABS,
- AFNABSCC,
- AFNEG,
- AFNEGCC,
- AFNMADD,
- AFNMADDCC,
- AFNMADDS,
- AFNMADDSCC,
- AFNMSUB,
- AFNMSUBCC,
- AFNMSUBS,
- AFNMSUBSCC,
- AFRSP,
- AFRSPCC,
- AFSUB,
- AFSUBCC,
- AFSUBS,
- AFSUBSCC,
- AMOVMW,
- ALSW,
- ALWAR,
- AMOVWBR,
- AMOVB,
- AMOVBU,
- AMOVBZ,
- AMOVBZU,
- AMOVH,
- AMOVHBR,
- AMOVHU,
- AMOVHZ,
- AMOVHZU,
- AMOVW,
- AMOVWU,
- AMOVFL,
- AMOVCRFS,
- AMTFSB0,
- AMTFSB0CC,
- AMTFSB1,
- AMTFSB1CC,
- AMULHW,
- AMULHWCC,
- AMULHWU,
- AMULHWUCC,
- AMULLW,
- AMULLWCC,
- AMULLWVCC,
- AMULLWV,
- ANAND,
- ANANDCC,
- ANEG,
- ANEGCC,
- ANEGVCC,
- ANEGV,
- ANOR,
- ANORCC,
- AOR,
- AORCC,
- AORN,
- AORNCC,
- AREM,
- AREMCC,
- AREMV,
- AREMVCC,
- AREMU,
- AREMUCC,
- AREMUV,
- AREMUVCC,
- ARFI,
- ARLWMI,
- ARLWMICC,
- ARLWNM,
- ARLWNMCC,
- ASLW,
- ASLWCC,
- ASRW,
- ASRAW,
- ASRAWCC,
- ASRWCC,
- ASTSW,
- ASTWCCC,
- ASUB,
- ASUBCC,
- ASUBVCC,
- ASUBC,
- ASUBCCC,
- ASUBCV,
- ASUBCVCC,
- ASUBME,
- ASUBMECC,
- ASUBMEVCC,
- ASUBMEV,
- ASUBV,
- ASUBE,
- ASUBECC,
- ASUBEV,
- ASUBEVCC,
- ASUBZE,
- ASUBZECC,
- ASUBZEVCC,
- ASUBZEV,
- ASYNC,
- AXOR,
- AXORCC,
-
- ADCBF,
- ADCBI,
- ADCBST,
- ADCBT,
- ADCBTST,
- ADCBZ,
- AECIWX,
- AECOWX,
- AEIEIO,
- AICBI,
- AISYNC,
- APTESYNC,
- ATLBIE,
- ATLBIEL,
- ATLBSYNC,
- ATW,
-
- ASYSCALL,
- AWORD,
-
- ARFCI,
-
- /* optional on 32-bit */
- AFRES,
- AFRESCC,
- AFRSQRTE,
- AFRSQRTECC,
- AFSEL,
- AFSELCC,
- AFSQRT,
- AFSQRTCC,
- AFSQRTS,
- AFSQRTSCC,
-
- /* 64-bit */
-
- ACNTLZD,
- ACNTLZDCC,
- ACMPW, /* CMP with L=0 */
- ACMPWU,
- ADIVD,
- ADIVDCC,
- ADIVDVCC,
- ADIVDV,
- ADIVDU,
- ADIVDUCC,
- ADIVDUVCC,
- ADIVDUV,
- AEXTSW,
- AEXTSWCC,
- /* AFCFIW; AFCFIWCC */
- AFCFID,
- AFCFIDCC,
- AFCTID,
- AFCTIDCC,
- AFCTIDZ,
- AFCTIDZCC,
- ALDAR,
- AMOVD,
- AMOVDU,
- AMOVWZ,
- AMOVWZU,
- AMULHD,
- AMULHDCC,
- AMULHDU,
- AMULHDUCC,
- AMULLD,
- AMULLDCC,
- AMULLDVCC,
- AMULLDV,
- ARFID,
- ARLDMI,
- ARLDMICC,
- ARLDC,
- ARLDCCC,
- ARLDCR,
- ARLDCRCC,
- ARLDCL,
- ARLDCLCC,
- ASLBIA,
- ASLBIE,
- ASLBMFEE,
- ASLBMFEV,
- ASLBMTE,
- ASLD,
- ASLDCC,
- ASRD,
- ASRAD,
- ASRADCC,
- ASRDCC,
- ASTDCCC,
- ATD,
-
- /* 64-bit pseudo operation */
- ADWORD,
- AREMD,
- AREMDCC,
- AREMDV,
- AREMDVCC,
- AREMDU,
- AREMDUCC,
- AREMDUV,
- AREMDUVCC,
-
- /* more 64-bit operations */
- AHRFID,
-
- ALAST,
-
- // aliases
- ABR = AJMP,
- ABL = ACALL,
- ARETURN = ARET,
-};
-
-/*
- * this is the ranlib header
- */
-#define SYMDEF "__.GOSYMDEF"
#include <libc.h>
#include <bio.h>
#include <link.h>
-#include "9.out.h"
#ifndef EXTERN
#define EXTERN extern
void asmb(void);
int elfreloc1(Reloc *r, vlong sectoff);
void elfsetupplt(void);
-void listinit(void);
int machoreloc1(Reloc *r, vlong sectoff);
/* Used by ../ld/dwarf.c */
+++ /dev/null
-// Inferno utils/5l/list.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/list.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Printing.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-listinit(void)
-{
- listinit9();
-}
thearch.elfreloc1 = elfreloc1;
thearch.elfsetupplt = elfsetupplt;
thearch.gentext = gentext;
- thearch.listinit = listinit;
thearch.machoreloc1 = machoreloc1;
if(thelinkarch == &linkppc64le) {
thearch.lput = lputl;
"-Wno-switch",
"-Wno-comment",
"-Wno-missing-field-initializers",
- "-Werror",
"-fno-common",
"-ggdb",
"-pipe",
"$GOROOT/include/bio.h",
"$GOROOT/include/ar.h",
"$GOROOT/include/link.h",
- "anames5.c",
- "anames6.c",
- "anames8.c",
- "anames9.c",
}},
{"cmd/5l", []string{
"$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a",
nameprefix string
gen func(string, string)
}{
- {"anames5.c", mkanames},
- {"anames6.c", mkanames},
- {"anames8.c", mkanames},
- {"anames9.c", mkanames},
{"zdefaultcc.go", mkzdefaultcc},
{"zversion.go", mkzversion},
// not generated anymore, but delete the file if we see it
{"enam.c", nil},
+ {"anames5.c", nil},
+ {"anames6.c", nil},
+ {"anames8.c", nil},
+ {"anames9.c", nil},
}
// install installs the library, package, or binary associated with dir,
+++ /dev/null
-// Copyright 2012 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.
-
-package main
-
-import (
- "bytes"
- "fmt"
- "strings"
-)
-
-/*
- * Helpers for building cmd/gc.
- */
-
-// gcopnames creates opnames.h from go.h.
-// It finds the OXXX enum, pulls out all the constants
-// from OXXX to OEND, and writes a table mapping
-// op to string.
-func gcopnames(dir, file string) {
- var out bytes.Buffer
- fmt.Fprintf(&out, "// auto generated by go tool dist\n")
- fmt.Fprintf(&out, "static char *opnames[] = {\n")
-
- in := readfile(pathf("%s/go.h", dir))
- lines := splitlines(in)
- i := 0
- for i < len(lines) && !strings.Contains(lines[i], "OXXX") {
- i++
- }
- for _, line := range lines[i:] {
- if i := strings.Index(line, "//"); i >= 0 {
- line = line[:i]
- }
- for _, field := range splitfields(line) {
- field = strings.TrimPrefix(field, "O")
- field = strings.TrimSuffix(field, ",")
- fmt.Fprintf(&out, "\t[O%s] = \"%s\",\n", field, field)
- }
- if strings.Contains(line, "OEND") {
- break
- }
- }
- fmt.Fprintf(&out, "};\n")
-
- writefile(out.String(), file, 0)
-}
-
-// mkanames reads [5689].out.h and writes anames[5689].c
-// The format is much the same as the Go opcodes above.
-// It also writes out cnames array for C_* constants.
-func mkanames(dir, file string) {
- ch := file[len(file)-3]
- targ := pathf("%s/../cmd/%cl/%c.out.h", dir, ch, ch)
- in := readfile(pathf("%s/../../include/link.h", dir)) + readfile(targ)
- lines := splitlines(in)
-
- // Include link.h so that the extern declaration there is
- // checked against the non-extern declaration we are generating.
- var out bytes.Buffer
- fmt.Fprintf(&out, "// auto generated by go tool dist\n")
- fmt.Fprintf(&out, "#include <u.h>\n")
- fmt.Fprintf(&out, "#include <libc.h>\n")
- fmt.Fprintf(&out, "#include <bio.h>\n")
- fmt.Fprintf(&out, "#include <link.h>\n")
- fmt.Fprintf(&out, "#include \"../cmd/%cl/%c.out.h\"\n", ch, ch)
- fmt.Fprintf(&out, "\n")
-
- fmt.Fprintf(&out, "char* anames%c[] = {\n", ch)
- for _, line := range lines {
- // Use all A names found in the headers,
- // except don't use A_ARCHSPECIFIC (left to arch to define),
- // and don't use any aliases (= A...),
- // except do use the arch-defined alias for A_ARCHSPECIFIC.
- if strings.Contains(line, ";") {
- continue
- }
- if strings.HasPrefix(line, "\tA") && !strings.Contains(line, "\tA_") && (!strings.Contains(line, "= A") || strings.Contains(line, "= A_ARCHSPECIFIC")) {
- if i := strings.Index(line, ","); i >= 0 {
- line = line[:i]
- }
- if i := strings.Index(line, "="); i >= 0 {
- line = line[:i]
- }
- if i := strings.Index(line, "\n"); i >= 0 {
- line = line[:i]
- }
- line = line[2:]
- fmt.Fprintf(&out, "\t\"%s\",\n", strings.TrimSpace(line))
- }
- }
- fmt.Fprintf(&out, "};\n")
-
- j := 0
- var out2 bytes.Buffer
- fmt.Fprintf(&out2, "char* cnames%c[] = {\n", ch)
- for _, line := range lines {
- if strings.HasPrefix(line, "\tC_") {
- if i := strings.Index(line, ","); i >= 0 {
- line = line[:i]
- }
- if i := strings.Index(line, "\n"); i >= 0 {
- line = line[:i]
- }
- line = line[3:]
- fmt.Fprintf(&out2, "\t\"%s\",\n", line)
- j++
- }
- }
- fmt.Fprintf(&out2, "};\n")
- if j > 0 {
- out.Write(out2.Bytes())
- }
-
- writefile(out.String(), file, 0)
-}
int (*elfreloc1)(Reloc*, vlong);
void (*elfsetupplt)(void);
void (*gentext)(void);
- void (*listinit)(void);
int (*machoreloc1)(Reloc*, vlong);
void (*lput)(uint32);
ctxt->bso = &bso;
Binit(&bso, 1, OWRITE);
- thearch.listinit();
memset(debug, 0, sizeof(debug));
nerrors = 0;
outfile = nil;
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)
headstring = headstr(HEADTYPE);
thearch.archinit();
- ctxt->debugfloat = debug['F'];
if(debug['v'])
Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
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));
Bprint(&bso, "%lld liveness data\n", liveness);
}
Bflush(&bso);
--- /dev/null
+// Copyright 2015 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>
+
+LinkArch linkarm = {
+ .name = "arm",
+ .thechar = '5',
+ .endian = LittleEndian,
+
+ .minlc = 4,
+ .ptrsize = 4,
+ .regsize = 4,
+};
+
+LinkArch linkamd64 = {
+ .name = "amd64",
+ .thechar = '6',
+ .endian = LittleEndian,
+
+ .minlc = 1,
+ .ptrsize = 8,
+ .regsize = 8,
+};
+
+LinkArch linkamd64p32 = {
+ .name = "amd64p32",
+ .thechar = '6',
+ .endian = LittleEndian,
+
+ .minlc = 1,
+ .ptrsize = 4,
+ .regsize = 8,
+};
+
+LinkArch link386 = {
+ .name = "386",
+ .thechar = '8',
+ .endian = LittleEndian,
+
+ .minlc = 1,
+ .ptrsize = 4,
+ .regsize = 4,
+};
+
+LinkArch linkppc64 = {
+ .name = "ppc64",
+ .thechar = '9',
+ .endian = BigEndian,
+
+ .minlc = 4,
+ .ptrsize = 8,
+ .regsize = 8,
+};
+
+LinkArch linkppc64le = {
+ .name = "ppc64le",
+ .thechar = '9',
+ .endian = LittleEndian,
+
+ .minlc = 4,
+ .ptrsize = 8,
+ .regsize = 8,
+};
+++ /dev/null
-// 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 "../runtime/stack.h"
-
-typedef struct Optab Optab;
-typedef struct Oprang Oprang;
-typedef uchar Opcross[32][2][32];
-
-struct Optab
-{
- uchar 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,
-};
-
-static Optab optab[] =
-{
- /* struct Optab:
- OPCODE, from, prog->reg, to, type,size,param,flag */
- { ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 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 },
- { ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0 }, // prediction hinted form, hint ignored
-
- { 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 },
- { ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0 },
-
- { ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, // same as ABL
- { ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, // same as ABL
-
- { ADATABUNDLE, C_NONE, C_NONE, C_NONE, 100, 4, 0 },
- { ADATABUNDLEEND, C_NONE, C_NONE, C_NONE, 100, 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*, uint32*);
-static int asmoutnacl(Link*, int32, Prog*, Optab*, uint32*);
-static Optab* oplook(Link*, Prog*);
-static uint32 oprrr(Link*, int, int);
-static uint32 olr(Link*, int32, int, int, int);
-static uint32 olhr(Link*, int32, int, int, int);
-static uint32 olrr(Link*, int, int, int, int);
-static uint32 olhrr(Link*, int, int, int, int);
-static uint32 osr(Link*, int, int, int32, int, int);
-static uint32 oshr(Link*, int, int32, int, int);
-static uint32 ofsr(Link*, int, int, int32, int, int, Prog*);
-static uint32 osrr(Link*, int, int, int, int);
-static uint32 oshrr(Link*, int, int, int, int);
-static uint32 omvl(Link*, Prog*, Addr*, int);
-static int32 immaddr(int32);
-static int aclass(Link*, Addr*);
-static int32 immrot(uint32);
-static int32 immaddr(int32);
-static uint32 opbra(Link*, int, int);
-
-static Oprang oprange[ALAST];
-static uchar xcmp[C_GOK+1][C_GOK+1];
-
-static LSym *deferreturn;
-
-/* 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*);
-
-// Note about encoding: Prog.scond holds the condition encoding,
-// but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0.
-// The code that shifts the value << 28 has the responsibility
-// for XORing with C_SCOND_XOR too.
-
-// asmoutnacl assembles the instruction p. It replaces asmout for NaCl.
-// It returns the total number of bytes put in out, and it can change
-// p->pc if extra padding is necessary.
-// In rare cases, asmoutnacl might split p into two instructions.
-// origPC is the PC for this Prog (no padding is taken into account).
-static int
-asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, uint32 *out)
-{
- int size, reg;
- Prog *q;
- Addr *a, *a2;
-
- size = o->size;
-
- // instruction specific
- switch(p->as) {
- default:
- if(out != nil)
- asmout(ctxt, p, o, out);
- break;
- case ADATABUNDLE: // align to 16-byte boundary
- case ADATABUNDLEEND: // zero width instruction, just to align next instruction to 16-byte boundary
- p->pc = (p->pc+15) & ~15;
- if(out != nil)
- asmout(ctxt, p, o, out);
- break;
- case AUNDEF:
- case APLD:
- size = 4;
- if(out != nil) {
- switch(p->as) {
- case AUNDEF:
- out[0] = 0xe7fedef0; // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0)
- break;
- case APLD:
- out[0] = 0xe1a01001; // (MOVW R1, R1)
- break;
- }
- }
- break;
- case AB:
- case ABL:
- if(p->to.type != TYPE_MEM) {
- if(out != nil)
- asmout(ctxt, p, o, out);
- } else {
- if(p->to.offset != 0 || size != 4 || p->to.reg > REG_R15 || p->to.reg < REG_R0)
- ctxt->diag("unsupported instruction: %P", p);
- if((p->pc&15) == 12)
- p->pc += 4;
- if(out != nil) {
- out[0] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x03c0013f | ((p->to.reg&15) << 12) | ((p->to.reg&15) << 16); // BIC $0xc000000f, Rx
- if(p->as == AB)
- out[1] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x012fff10 | (p->to.reg&15)<<0; // BX Rx
- else // ABL
- out[1] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x012fff30 | (p->to.reg&15)<<0; // BLX Rx
- }
- size = 8;
- }
- // align the last instruction (the actual BL) to the last instruction in a bundle
- if(p->as == ABL) {
- if(deferreturn == nil)
- deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
- if(p->to.sym == deferreturn)
- p->pc = ((origPC+15) & ~15) + 16 - size;
- else
- p->pc += (16 - ((p->pc+size)&15)) & 15;
- }
- break;
- case ALDREX:
- case ALDREXD:
- case AMOVB:
- case AMOVBS:
- case AMOVBU:
- case AMOVD:
- case AMOVF:
- case AMOVH:
- case AMOVHS:
- case AMOVHU:
- case AMOVM:
- case AMOVW:
- case ASTREX:
- case ASTREXD:
- if(p->to.type == TYPE_REG && p->to.reg == REG_R15 && p->from.reg == REG_R13) { // MOVW.W x(R13), PC
- if(out != nil)
- asmout(ctxt, p, o, out);
- if(size == 4) {
- if(out != nil) {
- // Note: 5c and 5g reg.c know that DIV/MOD smashes R12
- // so that this return instruction expansion is valid.
- out[0] = out[0] & ~0x3000; // change PC to R12
- out[1] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12
- out[2] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x012fff1c; // BX R12
- }
- size += 8;
- if(((p->pc+size) & 15) == 4)
- p->pc += 4;
- break;
- } else {
- // if the instruction used more than 4 bytes, then it must have used a very large
- // offset to update R13, so we need to additionally mask R13.
- if(out != nil) {
- out[size/4-1] &= ~0x3000; // change PC to R12
- out[size/4] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x03cdd103; // BIC $0xc0000000, R13
- out[size/4+1] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12
- out[size/4+2] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x012fff1c; // BX R12
- }
- // p->pc+size is only ok at 4 or 12 mod 16.
- if((p->pc+size)%8 == 0)
- p->pc += 4;
- size += 12;
- break;
- }
- }
-
- if(p->to.type == TYPE_REG && p->to.reg == REG_R15)
- ctxt->diag("unsupported instruction (move to another register and use indirect jump instead): %P", p);
-
- if(p->to.type == TYPE_MEM && p->to.reg == REG_R13 && (p->scond & C_WBIT) && size > 4) {
- // function prolog with very large frame size: MOVW.W R14,-100004(R13)
- // split it into two instructions:
- // ADD $-100004, R13
- // MOVW R14, 0(R13)
- q = emallocz(sizeof(Prog));
- p->scond &= ~C_WBIT;
- *q = *p;
- a = &p->to;
- if(p->to.type == TYPE_MEM)
- a2 = &q->to;
- else
- a2 = &q->from;
- nocache(q);
- nocache(p);
- // insert q after p
- q->link = p->link;
- p->link = q;
- q->pcond = nil;
- // make p into ADD $X, R13
- p->as = AADD;
- p->from = *a;
- p->from.reg = 0;
- p->from.type = TYPE_CONST;
- p->to = zprog.to;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R13;
- // make q into p but load/store from 0(R13)
- q->spadj = 0;
- *a2 = zprog.from;
- a2->type = TYPE_MEM;
- a2->reg = REG_R13;
- a2->sym = nil;
- a2->offset = 0;
- size = oplook(ctxt, p)->size;
- break;
- }
-
- if((p->to.type == TYPE_MEM && p->to.reg != REG_R13 && p->to.reg != REG_R9) || // MOVW Rx, X(Ry), y != 13 && y != 9
- (p->from.type == TYPE_MEM && p->from.reg != REG_R13 && p->from.reg != REG_R9)) { // MOVW X(Rx), Ry, x != 13 && x != 9
- if(p->to.type == TYPE_MEM)
- a = &p->to;
- else
- a = &p->from;
- reg = a->reg;
- if(size == 4) {
- // if addr.reg == 0, then it is probably load from x(FP) with small x, no need to modify.
- if(reg == 0) {
- if(out != nil)
- asmout(ctxt, p, o, out);
- } else {
- if(out != nil)
- out[0] = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | 0x03c00103 | ((reg&15) << 16) | ((reg&15) << 12); // BIC $0xc0000000, Rx
- if((p->pc&15) == 12)
- p->pc += 4;
- size += 4;
- if(out != nil)
- asmout(ctxt, p, o, &out[1]);
- }
- break;
- } else {
- // if a load/store instruction takes more than 1 word to implement, then
- // we need to seperate the instruction into two:
- // 1. explicitly load the address into R11.
- // 2. load/store from R11.
- // This won't handle .W/.P, so we should reject such code.
- if(p->scond & (C_PBIT|C_WBIT))
- ctxt->diag("unsupported instruction (.P/.W): %P", p);
- q = emallocz(sizeof(Prog));
- *q = *p;
- if(p->to.type == TYPE_MEM)
- a2 = &q->to;
- else
- a2 = &q->from;
- nocache(q);
- nocache(p);
- // insert q after p
- q->link = p->link;
- p->link = q;
- q->pcond = nil;
- // make p into MOVW $X(R), R11
- p->as = AMOVW;
- p->from = *a;
- p->from.type = TYPE_ADDR;
- p->to = zprog.to;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R11;
- // make q into p but load/store from 0(R11)
- *a2 = zprog.from;
- a2->type = TYPE_MEM;
- a2->reg = REG_R11;
- a2->sym = nil;
- a2->offset = 0;
- size = oplook(ctxt, p)->size;
- break;
- }
- } else if(out != nil)
- asmout(ctxt, p, o, out);
- break;
- }
-
- // destination register specific
- if(p->to.type == TYPE_REG) {
- switch(p->to.reg) {
- case REG_R9:
- ctxt->diag("invalid instruction, cannot write to R9: %P", p);
- break;
- case REG_R13:
- if(out != nil)
- out[size/4] = 0xe3cdd103; // BIC $0xc0000000, R13
- if(((p->pc+size) & 15) == 0)
- p->pc += 4;
- size += 4;
- break;
- }
- }
- return size;
-}
-
-void
-span5(Link *ctxt, LSym *cursym)
-{
- Prog *p, *op;
- Optab *o;
- int m, bflag, i, v, times;
- int32 c, opc;
- uint32 out[6+3];
- uchar *bp;
-
- 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 || ctxt->blitrl != nil; op = p, p = p->link) {
- if(p == nil) {
- if(checkpool(ctxt, op, 0)) {
- p = op;
- continue;
- }
- // can't happen: blitrl is not nil, but checkpool didn't flushpool
- ctxt->diag("internal inconsistency");
- break;
- }
- ctxt->curp = p;
- p->pc = c;
- o = oplook(ctxt, p);
- if(ctxt->headtype != Hnacl) {
- m = o->size;
- } else {
- m = asmoutnacl(ctxt, c, p, o, nil);
- c = p->pc; // asmoutnacl might change pc for alignment
- o = oplook(ctxt, p); // asmoutnacl might change p in rare cases
- }
- if(m % 4 != 0 || p->pc % 4 != 0) {
- ctxt->diag("!pc invalid: %P size=%d", p, m);
- }
- // must check literal pool here in case p generates many instructions
- if(ctxt->blitrl){
- i = m;
- if(p->as == ACASE)
- i = casesz(ctxt, p);
- if(checkpool(ctxt, op, i)) {
- p = op;
- continue;
- }
- }
- if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA && p->as != ADATABUNDLEEND && p->as != ANOP)) {
- 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) == C_SCOND_NONE)
- flushpool(ctxt, p, 0, 0);
- break;
- }
- if(p->as==AMOVW && p->to.type==TYPE_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == C_SCOND_NONE)
- flushpool(ctxt, p, 0, 0);
- c += m;
- }
- 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.
- */
- times = 0;
- do {
- if(ctxt->debugvlog)
- Bprint(ctxt->bso, "%5.2f span1\n", cputime());
- bflag = 0;
- c = 0;
- times++;
- cursym->text->pc = 0; // force re-layout the code.
- for(p = cursym->text; p != nil; p = p->link) {
- ctxt->curp = p;
- o = oplook(ctxt,p);
- if(c > p->pc)
- p->pc = c;
-/* 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 = emallocz(sizeof(Prog));
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = TYPE_BRANCH;
- q->pcond = p->pcond;
- p->pcond = q;
- q = emallocz(sizeof(Prog));
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = TYPE_BRANCH;
- q->pcond = q->link->link;
- bflag = 1;
- }
- }
- */
- opc = p->pc;
- if(ctxt->headtype != Hnacl)
- m = o->size;
- else
- m = asmoutnacl(ctxt, c, p, o, nil);
- if(p->pc != opc) {
- bflag = 1;
- //print("%P pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times);
- }
- c = p->pc + m;
- if(m % 4 != 0 || p->pc % 4 != 0) {
- ctxt->diag("pc invalid: %P size=%d", p, m);
- }
- if(m/4 > nelem(out))
- ctxt->diag("instruction size too large: %d > %d", m/4, nelem(out));
- if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA && p->as != ADATABUNDLEEND && p->as != ANOP)) {
- if(p->as == ATEXT) {
- ctxt->autosize = p->to.offset + 4;
- continue;
- }
- ctxt->diag("zero-width instruction\n%P", p);
- continue;
- }
- }
- cursym->size = c;
- } while(bflag);
- if(c % 4 != 0) {
- ctxt->diag("sym->size=%d, invalid", c);
- }
-
- /*
- * 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.
- */
- if(ctxt->tlsg == nil)
- ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
-
- p = cursym->text;
- ctxt->autosize = p->to.offset + 4;
- symgrow(ctxt, cursym, cursym->size);
-
- bp = cursym->p;
- c = p->pc; // even p->link might need extra padding
- for(p = p->link; p != nil; p = p->link) {
- ctxt->pc = p->pc;
- ctxt->curp = p;
- o = oplook(ctxt, p);
- opc = p->pc;
- if(ctxt->headtype != Hnacl) {
- asmout(ctxt, p, o, out);
- m = o->size;
- } else {
- m = asmoutnacl(ctxt, c, p, o, out);
- if(opc != p->pc)
- ctxt->diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %P", opc, (int32)p->pc, p);
- }
- if(m % 4 != 0 || p->pc % 4 != 0) {
- ctxt->diag("final stage: pc invalid: %P size=%d", p, m);
- }
- if(c > p->pc)
- ctxt->diag("PC padding invalid: want %#lld, has %#d: %P", p->pc, c, p);
- while(c != p->pc) {
- // emit 0xe1a00000 (MOVW R0, R0)
- *bp++ = 0x00;
- *bp++ = 0x00;
- *bp++ = 0xa0;
- *bp++ = 0xe1;
- c += 4;
- }
- for(i=0; i<m/4; i++) {
- v = out[i];
- *bp++ = v;
- *bp++ = v>>8;
- *bp++ = v>>16;
- *bp++ = v>>24;
- }
- c += m;
- }
-}
-
-/*
- * 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 >= 0xff0 || immaddr((p->pc+sz+4)+4+(12+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 %llux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
- q = emallocz(sizeof(Prog));
- q->as = AB;
- q->to.type = TYPE_BRANCH;
- q->pcond = p->link;
- q->link = ctxt->blitrl;
- q->lineno = p->lineno;
- ctxt->blitrl = q;
- }
- else if(!force && (p->pc+(12+pool.size)-pool.start < 2048)) // 12 take into account the maximum nacl literal pool alignment padding size
- return 0;
- if(ctxt->headtype == Hnacl && pool.size % 16 != 0) {
- // if pool is not multiple of 16 bytes, add an alignment marker
- q = emallocz(sizeof(Prog));
- q->as = ADATABUNDLEEND;
- ctxt->elitrl->link = q;
- ctxt->elitrl = q;
- }
- 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 = zprog;
- t.as = AWORD;
-
- switch(c) {
- default:
- t.to.offset = a->offset;
- t.to.sym = a->sym;
- t.to.type = a->type;
- t.to.name = a->name;
-
- 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 = TYPE_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;
- }
- }
-
- if(ctxt->headtype == Hnacl && pool.size%16 == 0) {
- // start a new data bundle
- q = emallocz(sizeof(Prog));
- *q = zprog;
- q->as = ADATABUNDLE;
- q->pc = pool.size;
- pool.size += 4;
- if(ctxt->blitrl == nil) {
- ctxt->blitrl = q;
- pool.start = p->pc;
- } else {
- ctxt->elitrl->link = q;
- }
- ctxt->elitrl = q;
- }
-
- q = emallocz(sizeof(Prog));
- *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 aconsize(Link *ctxt);
-
-static int
-aclass(Link *ctxt, Addr *a)
-{
- LSym *s;
- int t;
-
- switch(a->type) {
- case TYPE_NONE:
- return C_NONE;
-
- case TYPE_REG:
- if(REG_R0 <= a->reg && a->reg <= REG_R15)
- return C_REG;
- if(REG_F0 <= a->reg && a->reg <= REG_F15)
- return C_FREG;
- if(a->reg == REG_FPSR || a->reg == REG_FPCR)
- return C_FCR;
- if(a->reg == REG_CPSR || a->reg == REG_SPSR)
- return C_PSR;
- return C_GOK;
-
- case TYPE_REGREG:
- return C_REGREG;
-
- case TYPE_REGREG2:
- return C_REGREG2;
-
- case TYPE_SHIFT:
- return C_SHIFT;
-
- case TYPE_MEM:
- switch(a->name) {
- case NAME_EXTERN:
- case NAME_STATIC:
- if(a->sym == 0 || a->sym->name == 0) {
- print("null sym external\n");
- return C_GOK;
- }
- ctxt->instoffset = 0; // s.b. unused but just in case
- return C_ADDR;
-
- case NAME_AUTO:
- ctxt->instoffset = ctxt->autosize + a->offset;
- t = immaddr(ctxt->instoffset);
- if(t){
- if(immhalf(ctxt->instoffset)) {
- if(immfloat(t))
- return C_HFAUTO;
- return C_HAUTO;
- }
- if(immfloat(t))
- return C_FAUTO;
- return C_SAUTO;
- }
- return C_LAUTO;
-
- case NAME_PARAM:
- ctxt->instoffset = ctxt->autosize + a->offset + 4L;
- t = immaddr(ctxt->instoffset);
- if(t){
- if(immhalf(ctxt->instoffset)) {
- if(immfloat(t))
- return C_HFAUTO;
- return C_HAUTO;
- }
- if(immfloat(t))
- return C_FAUTO;
- return C_SAUTO;
- }
- return C_LAUTO;
- case TYPE_NONE:
- ctxt->instoffset = a->offset;
- t = immaddr(ctxt->instoffset);
- if(t) {
- if(immhalf(ctxt->instoffset)) { /* n.b. that it will also satisfy immrot */
- if(immfloat(t))
- return C_HFOREG;
- return 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 TYPE_FCONST:
- if(chipzero5(ctxt, a->u.dval) >= 0)
- return C_ZFCON;
- if(chipfloat5(ctxt, a->u.dval) >= 0)
- return C_SFCON;
- return C_LFCON;
-
- case TYPE_TEXTSIZE:
- return C_TEXTSIZE;
-
- case TYPE_CONST:
- case TYPE_ADDR:
- switch(a->name) {
-
- case TYPE_NONE:
- ctxt->instoffset = a->offset;
- if(a->reg != 0)
- return aconsize(ctxt);
-
- t = immrot(ctxt->instoffset);
- if(t)
- return C_RCON;
- t = immrot(~ctxt->instoffset);
- if(t)
- return C_NCON;
- return C_LCON;
-
- case NAME_EXTERN:
- case NAME_STATIC:
- s = a->sym;
- if(s == nil)
- break;
- ctxt->instoffset = 0; // s.b. unused but just in case
- return C_LCONADDR;
-
- case NAME_AUTO:
- ctxt->instoffset = ctxt->autosize + a->offset;
- return aconsize(ctxt);
-
- case NAME_PARAM:
- ctxt->instoffset = ctxt->autosize + a->offset + 4L;
- return aconsize(ctxt);
- }
- return C_GOK;
-
- case TYPE_BRANCH:
- return C_SBRA;
- }
- return C_GOK;
-}
-
-static int
-aconsize(Link *ctxt)
-{
- int t;
-
- t = immrot(ctxt->instoffset);
- if(t)
- return C_RACON;
- return C_LACON;
-}
-
-static void
-prasm(Prog *p)
-{
- print("%P\n", p);
-}
-
-static Optab*
-oplook(Link *ctxt, Prog *p)
-{
- int a1, a2, a3, r;
- uchar *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 != 0)
- a2 = C_REG;
- r = p->as;
- o = oprange[r].start;
- if(o == 0) {
- o = oprange[r].stop; /* just generate an error */
- }
- if(0 /*debug['O']*/) {
- print("oplook %A %^ %^ %^\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 %P; %^ %^ %^, %d %d",
- p, a1, a2, a3, p->from.type, p->to.type);
- ctxt->diag("from %d %d to %d %d\n", p->from.type, p->from.name, p->to.type, p->to.name);
- 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 ADUFFZERO:
- case ADUFFCOPY:
- 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:
- case ANOP:
- case ADATABUNDLE:
- case ADATABUNDLEEND:
- break;
- }
- }
-}
-
-static uint32 mov(Link*, Prog*);
-
-static void
-asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
-{
- uint32 o1, o2, o3, o4, o5, o6;
- int32 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 == TYPE_NONE)
- rt = 0;
- if(p->as == AMOVB || p->as == AMOVH || p->as == AMOVW || p->as == AMVN)
- r = 0;
- else
- if(r == 0)
- r = rt;
- o1 |= ((rf&15)<<0) | ((r&15)<<16) | ((rt&15)<<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 == TYPE_NONE)
- rt = 0;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == 0)
- r = rt;
- o1 |= ((r&15)<<16) | ((rt&15)<<12);
- break;
-
- case 3: /* add R<<[IR],[R],R */
- o1 = mov(ctxt, p);
- 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 == 0)
- r = o->param;
- o1 |= (r&15) << 16;
- o1 |= (p->to.reg&15) << 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;
- v += p->to.offset;
- rel->add = o1 | ((v >> 2) & 0xffffff);
- rel->type = R_CALLARM;
- 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&15) << 16;
- o1 |= (REGPC&15) << 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&15) << 0;
- rel = addrel(ctxt->cursym);
- rel->off = ctxt->pc;
- rel->siz = 0;
- rel->type = R_CALLIND;
- 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 == 0)
- r = p->to.reg;
- o1 |= (r&15) << 0;
- o1 |= (ctxt->instoffset&31) << 7;
- o1 |= (p->to.reg&15) << 12;
- break;
-
- case 9: /* sll R,[R],R -> mov (R<<R),R */
- o1 = oprrr(ctxt, p->as, p->scond);
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- o1 |= (r&15) << 0;
- o1 |= ((p->from.reg&15) << 8) | (1<<4);
- o1 |= (p->to.reg&15) << 12;
- break;
-
- case 10: /* swi [$con] */
- o1 = oprrr(ctxt, p->as, p->scond);
- if(p->to.type != TYPE_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) {
- // This case happens with words generated
- // in the PC stream as part of the literal pool.
- rel = addrel(ctxt->cursym);
- rel->off = ctxt->pc;
- rel->siz = 4;
- rel->sym = p->to.sym;
- rel->add = p->to.offset;
-
- // runtime.tlsg is special.
- // Its "address" is the offset from the TLS thread pointer
- // to the thread-local g and m pointers.
- // Emit a TLS relocation instead of a standard one if its
- // type is not explicitly set by runtime. This assumes that
- // all references to runtime.tlsg should be accompanied with
- // its type declaration if necessary.
- if(rel->sym == ctxt->tlsg && ctxt->tlsg->type == 0) {
- rel->type = R_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 = R_PCREL;
- rel->add += ctxt->pc - p->pcrel->pc - 8;
- } else
- rel->type = R_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&15) << 0 | (REGPC&15) << 16 | (p->to.reg&15) << 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&15);
- r = p->reg;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == 0)
- r = p->to.reg;
- o2 |= (r&15) << 16;
- if(p->to.type != TYPE_NONE)
- o2 |= (p->to.reg&15) << 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&15)<<0)|((r&15)<<12);
- o2 |= (r&15)|((r&15)<<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 == 0)
- r = rt;
- if(rt == r) {
- r = rf;
- rf = rt;
- }
- if(0)
- if(rt == r || rf == (REGPC&15) || r == (REGPC&15) || rt == (REGPC&15)) {
- ctxt->diag("bad registers in MUL");
- prasm(p);
- }
- o1 |= ((rf&15)<<8) | ((r&15)<<0) | ((rt&15)<<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&15)<<8) | ((r&15)<<0) | ((rt&15)<<16) | ((rt2&15)<<12);
- break;
-
- case 20: /* mov/movb/movbu R,O(R) */
- aclass(ctxt, &p->to);
- r = p->to.reg;
- if(r == 0)
- 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 == 0)
- 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 == 0)
- r = o->param;
- o2 = osrr(ctxt, p->from.reg, REGTMP&15, 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 == 0)
- r = o->param;
- o2 = olrr(ctxt, REGTMP&15, 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&15);
- r = p->from.reg;
- if(r == 0)
- r = o->param;
- o2 |= (r&15) << 16;
- if(p->to.type != TYPE_NONE)
- o2 |= (p->to.reg&15) << 12;
- break;
-
- case 35: /* mov PSR,R */
- o1 = (2<<23) | (0xf<<16) | (0<<0);
- o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
- o1 |= (p->from.reg & 1) << 22;
- o1 |= (p->to.reg&15) << 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) ^ C_SCOND_XOR) << 28;
- o1 |= (p->to.reg & 1) << 22;
- o1 |= (p->from.reg&15) << 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) ^ C_SCOND_XOR) << 28;
- o1 |= immrot(ctxt->instoffset);
- o1 |= (p->to.reg & 1) << 22;
- o1 |= (p->from.reg&15) << 0;
- break;
-
- case 38:
- case 39:
- switch(o->type) {
- case 38: /* movm $con,oreg -> stm */
- o1 = (0x4 << 25);
- o1 |= p->from.offset & 0xffff;
- o1 |= (p->to.reg&15) << 16;
- aclass(ctxt, &p->to);
- break;
-
- case 39: /* movm oreg,$con -> ldm */
- o1 = (0x4 << 25) | (1 << 20);
- o1 |= p->to.offset & 0xffff;
- o1 |= (p->from.reg&15) << 16;
- aclass(ctxt, &p->from);
- break;
- }
- if(ctxt->instoffset != 0)
- ctxt->diag("offset must be zero in MOVM; %P", p);
- o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 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&15) << 16;
- o1 |= (p->reg&15) << 0;
- o1 |= (p->to.reg&15) << 12;
- o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 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 == 0)
- 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 == 0)
- 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 == 0)
- r = o->param;
- o2 = oprrr(ctxt, AADD, p->scond) | ((REGTMP&15) << 12) | ((REGTMP&15) << 16) | ((r&15) << 0);
- 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 == 0)
- r = o->param;
- o2 = oprrr(ctxt, AADD, p->scond) | ((REGTMP&15) << 12) | ((REGTMP&15) << 16) | ((r&15) << 0);
- o3 = ofsr(ctxt, p->as, p->to.reg, 0, (REGTMP&15), 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 == 0) {
- r = rt;
- if(p->as == AMOVF || p->as == AMOVD || p->as == AMOVFD || p->as == AMOVDF ||
- p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD)
- r = 0;
- }
- o1 |= ((rf&15)<<0) | ((r&15)<<16) | ((rt&15)<<12);
- break;
-
- case 56: /* move to FP[CS]R */
- o1 = (((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28) | (0xe << 24) | (1<<8) | (1<<4);
- o1 |= (((p->to.reg&1)+1)<<21) | ((p->from.reg&15) << 12);
- break;
-
- case 57: /* move from FP[CS]R */
- o1 = (((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28) | (0xe << 24) | (1<<8) | (1<<4);
- o1 |= (((p->from.reg&1)+1)<<21) | ((p->to.reg&15)<<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 == TYPE_NONE)
- rt = 0;
- if(r == 0)
- r = rt;
- o1 |= ((r&15)<<16) | ((rt&15)<<12);
- break;
-
- case 59: /* movw/bu R<<I(R),R -> ldr indexed */
- if(p->from.reg == 0) {
- if(p->as != AMOVW)
- ctxt->diag("byte MOV from shifter operand");
- o1 = mov(ctxt, p);
- break;
- }
- 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 == 0) {
- ctxt->diag("byte MOV from shifter operand");
- o1 = mov(ctxt, p);
- break;
- }
- 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 == 0)
- 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&15) << 16 | (REGTMP&15) << 12;
- o2 = olrr(ctxt, REGTMP&15, REGPC, REGTMP, p->scond);
- o2 |= 2<<7;
- o3 = oprrr(ctxt, AADD, p->scond) | (REGTMP&15) | (REGPC&15) << 16 | (REGPC&15) << 12;
- } else {
- o1 = olrr(ctxt, p->from.reg&15, 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 = R_PCREL;
- rel->add += ctxt->pc - p->pcrel->pc - 16 + rel->siz;
- } else
- rel->type = R_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&15) | (REGPC&15) << 16 | (REGTMP&15) << 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&15) | (REGPC&15) << 16 | (REGTMP&15) << 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&15) | (REGPC&15) << 16 | (REGTMP&15) << 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&15), p->scond, p) | (1<<20);
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP&15) | (REGPC&15) << 16 | (REGTMP&15) << 12;
- }
- break;
-
- /* ArmV4 ops: */
- case 70: /* movh/movhu R,O(R) -> strh */
- aclass(ctxt, &p->to);
- r = p->to.reg;
- if(r == 0)
- 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 == 0)
- 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 == 0)
- r = o->param;
- o2 = oshrr(ctxt, p->from.reg, REGTMP&15, 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 == 0)
- r = o->param;
- o2 = olhrr(ctxt, REGTMP&15, 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&15)<<16) | ((REGLINK&15)<<12); // mov PC, LR
- o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0); // BX R
-*/
- // p->to.reg may be REGLINK
- o1 = oprrr(ctxt, AADD, p->scond);
- o1 |= immrot(ctxt->instoffset);
- o1 |= (p->to.reg&15) << 16;
- o1 |= (REGTMP&15) << 12;
- o2 = oprrr(ctxt, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12); // mov PC, LR
- o3 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | (REGTMP&15); // 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&15) << 16;
- o1 |= (p->to.reg&15) << 12;
- o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 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&15) << 16;
- o1 |= (p->reg&15) << 0;
- o1 |= (p->to.reg&15) << 12;
- o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 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&15) << 0;
-
- // movf $1.0, r
- o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
- o1 |= (r&15) << 12;
- o1 |= (v&0xf) << 0;
- o1 |= (v&0xf0) << 12;
-
- // subf r,r,r
- o2 |= ((r&15)<<0) | ((r&15)<<16) | ((r&15)<<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) ^ C_SCOND_XOR) << 28;
- o1 |= (p->to.reg&15) << 12;
- v = chipfloat5(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&15)<<12) | ((p->from.reg&15)<<0);
- o2 = 0x0ef1fa10; // VMRS R15
- o2 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
- break;
- case 83: /* fcmp freg,, */
- o1 = oprrr(ctxt, p->as, p->scond);
- o1 |= ((p->from.reg&15)<<12) | (1<<16);
- o2 = 0x0ef1fa10; // VMRS R15
- o2 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 28;
- break;
- case 84: /* movfw freg,freg - truncate float-to-fix */
- o1 = oprrr(ctxt, p->as, p->scond);
- o1 |= ((p->from.reg&15)<<0);
- o1 |= ((p->to.reg&15)<<12);
- break;
- case 85: /* movwf freg,freg - fix-to-float */
- o1 = oprrr(ctxt, p->as, p->scond);
- o1 |= ((p->from.reg&15)<<0);
- o1 |= ((p->to.reg&15)<<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&15)<<0);
- o1 |= ((FREGTMP&15)<<12);
- o2 = oprrr(ctxt, AMOVFW+ALAST, p->scond);
- o2 |= ((FREGTMP&15)<<16);
- o2 |= ((p->to.reg&15)<<12);
- break;
- case 87: /* movwf reg,freg - fix-to-float */
- // macro for movw reg,FTMP; movwf FTMP,freg
- o1 = oprrr(ctxt, AMOVWF+ALAST, p->scond);
- o1 |= ((p->from.reg&15)<<12);
- o1 |= ((FREGTMP&15)<<16);
- o2 = oprrr(ctxt, p->as, p->scond);
- o2 |= ((FREGTMP&15)<<0);
- o2 |= ((p->to.reg&15)<<12);
- break;
- case 88: /* movw reg,freg */
- o1 = oprrr(ctxt, AMOVWF+ALAST, p->scond);
- o1 |= ((p->from.reg&15)<<12);
- o1 |= ((p->to.reg&15)<<16);
- break;
- case 89: /* movw freg,reg */
- o1 = oprrr(ctxt, AMOVFW+ALAST, p->scond);
- o1 |= ((p->from.reg&15)<<16);
- o1 |= ((p->to.reg&15)<<12);
- break;
- case 90: /* tst reg */
- o1 = oprrr(ctxt, ACMP+ALAST, p->scond);
- o1 |= (p->from.reg&15)<<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&15) << 16;
- o1 |= (p->to.reg&15) << 12;
- o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 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&15) << 16;
- o1 |= (p->reg&15) << 0;
- o1 |= (p->to.reg&15) << 12;
- o1 |= ((p->scond & C_SCOND) ^ C_SCOND_XOR) << 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&15) | (REGPC&15) << 16 | (REGTMP&15) << 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&15) | (REGPC&15) << 16 | (REGTMP&15) << 12;
- }
- break;
- case 95: /* PLD off(reg) */
- o1 = 0xf5d0f000;
- o1 |= (p->from.reg&15) << 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 guaranteed to raise undefined instruction
- // exception.
- o1 = 0xf7fabcfd;
- break;
- case 97: /* CLZ Rm, Rd */
- o1 = oprrr(ctxt, p->as, p->scond);
- o1 |= (p->to.reg&15) << 12;
- o1 |= (p->from.reg&15) << 0;
- break;
- case 98: /* MULW{T,B} Rs, Rm, Rd */
- o1 = oprrr(ctxt, p->as, p->scond);
- o1 |= (p->to.reg&15) << 16;
- o1 |= (p->from.reg&15) << 8;
- o1 |= (p->reg&15) << 0;
- break;
- case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
- o1 = oprrr(ctxt, p->as, p->scond);
- o1 |= (p->to.reg&15) << 12;
- o1 |= (p->from.reg&15) << 8;
- o1 |= (p->reg&15) << 0;
- o1 |= (p->to.offset&15) << 16;
- break;
- case 100:
- // DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
- // DATABUNDLEEND: zero width alignment marker
- if(p->as == ADATABUNDLE)
- o1 = 0xe125be70;
- break;
- }
-
- out[0] = o1;
- out[1] = o2;
- out[2] = o3;
- out[3] = o4;
- out[4] = o5;
- out[5] = o6;
- return;
-}
-
-static uint32
-mov(Link *ctxt, Prog *p)
-{
- uint32 o1;
- int rt, r;
-
- aclass(ctxt, &p->from);
- o1 = oprrr(ctxt, p->as, p->scond);
- o1 |= p->from.offset;
- rt = p->to.reg;
- if(p->to.type == TYPE_NONE)
- rt = 0;
- r = p->reg;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == 0)
- r = rt;
- o1 |= ((r&15)<<16) | ((rt&15)<<12);
- return o1;
-}
-
-static uint32
-oprrr(Link *ctxt, int a, int sc)
-{
- uint32 o;
-
- o = ((sc & C_SCOND) ^ C_SCOND_XOR) << 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+ALAST: // copy WtoF
- return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4);
- case AMOVFW+ALAST: // copy FtoW
- return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
- case ACMP+ALAST: // 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;
-}
-
-static uint32
-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;
- sc ^= C_SCOND_XOR;
- if(a == ABL || a == ADUFFZERO || a == ADUFFCOPY)
- 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;
-}
-
-static uint32
-olr(Link *ctxt, int32 v, int b, int r, int sc)
-{
- uint32 o;
-
- if(sc & C_SBIT)
- ctxt->diag(".nil on LDR/STR instruction");
- o = ((sc & C_SCOND) ^ C_SCOND_XOR) << 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&15) << 16;
- o |= (r&15) << 12;
- return o;
-}
-
-static uint32
-olhr(Link *ctxt, int32 v, int b, int r, int sc)
-{
- uint32 o;
-
- if(sc & C_SBIT)
- ctxt->diag(".nil on LDRH/STRH instruction");
- o = ((sc & C_SCOND) ^ C_SCOND_XOR) << 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&15) << 16;
- o |= (r&15) << 12;
- return o;
-}
-
-static uint32
-osr(Link *ctxt, int a, int r, int32 v, int b, int sc)
-{
- uint32 o;
-
- o = olr(ctxt, v, b, r, sc) ^ (1<<20);
- if(a != AMOVW)
- o |= 1<<22;
- return o;
-}
-
-static uint32
-oshr(Link *ctxt, int r, int32 v, int b, int sc)
-{
- uint32 o;
-
- o = olhr(ctxt, v, b, r, sc) ^ (1<<20);
- return o;
-}
-
-
-static uint32
-osrr(Link *ctxt, int r, int i, int b, int sc)
-{
-
- return olr(ctxt, i, b, r, sc) ^ ((1<<25) | (1<<20));
-}
-
-static uint32
-oshrr(Link *ctxt, int r, int i, int b, int sc)
-{
- return olhr(ctxt, i, b, r, sc) ^ ((1<<22) | (1<<20));
-}
-
-static uint32
-olrr(Link *ctxt, int i, int b, int r, int sc)
-{
-
- return olr(ctxt, i, b, r, sc) ^ (1<<25);
-}
-
-static uint32
-olhrr(Link *ctxt, int i, int b, int r, int sc)
-{
- return olhr(ctxt, i, b, r, sc) ^ (1<<22);
-}
-
-static uint32
-ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p)
-{
- uint32 o;
-
- if(sc & C_SBIT)
- ctxt->diag(".nil on FLDR/FSTR instruction");
- o = ((sc & C_SCOND) ^ C_SCOND_XOR) << 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&15) << 16;
- o |= (r&15) << 12;
-
- switch(a) {
- default:
- ctxt->diag("bad fst %A", a);
- case AMOVD:
- o |= 1 << 8;
- case AMOVF:
- break;
- }
- return o;
-}
-
-static uint32
-omvl(Link *ctxt, Prog *p, Addr *a, int dr)
-{
- int32 v;
- uint32 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&15) << 12;
- } else {
- v = p->pcond->pc - p->pc - 8;
- o1 = olr(ctxt, v, REGPC, dr, p->scond&C_SCOND);
- }
- return o1;
-}
-
-int
-chipzero5(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;
-}
-
-int
-chipfloat5(Link *ctxt, float64 e)
-{
- int n;
- ulong h1;
- uint32 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 = (uint32)ei;
- h = (uint32)(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;
-}
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/6l/6.out.h"
-#include "../runtime/stack.h"
-
-enum
-{
- MaxAlign = 32, // max data alignment
-
- // Loop alignment constants:
- // want to align loop entry to LoopAlign-byte boundary,
- // 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,
- // 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 and
- // for future experiments.
- //
- LoopAlign = 16,
- MaxLoopPad = 0,
-
- FuncAlign = 16
-};
-
-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,
- Ytls,
- Ytextsize,
- Ymax,
-
- Zxxx = 0,
-
- Zlit,
- Zlitm_r,
- Z_rp,
- Zbr,
- Zcall,
- Zcallindreg,
- 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 uchar ycover[Ymax*Ymax];
-static int reg[MAXREG];
-static int regrex[MAXREG+1];
-static void asmins(Link *ctxt, Prog *p);
-
-static uchar ynone[] =
-{
- Ynone, Ynone, Zlit, 1,
- 0
-};
-static uchar ytext[] =
-{
- Ymb, Ytextsize, 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, Zcallindreg, 0,
- Yrx, Yrx, Zcallindreg, 2,
- Ynone, Ybr, Zcall, 1,
- 0
-};
-static uchar yduff[] =
-{
- Ynone, Yi32, 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,
- * and p->from and p->to as operands (Addr*). 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.
- */
-static 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 },
- { 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, Pm, {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)} },
- { 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, Pb, {0x0f,0x93,(00)} },
- { ASETCS, yscond, Pb, {0x0f,0x92,(00)} },
- { ASETEQ, yscond, Pb, {0x0f,0x94,(00)} },
- { ASETGE, yscond, Pb, {0x0f,0x9d,(00)} },
- { ASETGT, yscond, Pb, {0x0f,0x9f,(00)} },
- { ASETHI, yscond, Pb, {0x0f,0x97,(00)} },
- { ASETLE, yscond, Pb, {0x0f,0x9e,(00)} },
- { ASETLS, yscond, Pb, {0x0f,0x96,(00)} },
- { ASETLT, yscond, Pb, {0x0f,0x9c,(00)} },
- { ASETMI, yscond, Pb, {0x0f,0x98,(00)} },
- { ASETNE, yscond, Pb, {0x0f,0x95,(00)} },
- { ASETOC, yscond, Pb, {0x0f,0x91,(00)} },
- { ASETOS, yscond, Pb, {0x0f,0x90,(00)} },
- { ASETPC, yscond, Pb, {0x0f,0x9b,(00)} },
- { ASETPL, yscond, Pb, {0x0f,0x99,(00)} },
- { ASETPS, yscond, Pb, {0x0f,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 },
- { AVARDEF },
- { AVARKILL },
- { ADUFFCOPY, yduff, Px, {0xe8} },
- { ADUFFZERO, yduff, Px, {0xe8} },
-
- { AEND },
- {0}
-};
-
-static Optab* opindex[ALAST+1];
-static vlong vaddr(Link*, Prog*, Addr*, Reloc*);
-
-// isextern reports whether s describes an external symbol that must avoid pc-relative addressing.
-// This happens on systems like Solaris that call .so functions instead of system calls.
-// It does not seem to be necessary for any other systems. This is probably working
-// around a Solaris-specific bug that should be fixed differently, but we don't know
-// what that bug is. And this does fix it.
-static int
-isextern(LSym *s)
-{
- // All the Solaris dynamic imports from libc.so begin with "libc_".
- return strncmp(s->name, "libc_", 5) == 0;
-}
-
-// 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},
- // Native Client rejects the repeated 0x66 prefix.
- // {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);
-
-static int32
-naclpad(Link *ctxt, LSym *s, int32 c, int32 pad)
-{
- symgrow(ctxt, s, c+pad);
- fillnop(s->p+c, pad);
- return c+pad;
-}
-
-static int
-spadjop(Link *ctxt, Prog *p, int l, int q)
-{
- if(p->mode != 64 || ctxt->arch->ptrsize == 4)
- return l;
- return q;
-}
-
-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) {
- if(p->to.type == TYPE_BRANCH)
- if(p->pcond == nil)
- p->pcond = p;
- if(p->as == AADJSP) {
- p->to.type = TYPE_REG;
- p->to.reg = REG_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = spadjop(ctxt, p, AADDL, AADDQ);
- if(v < 0) {
- p->as = spadjop(ctxt, p, 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 = TYPE_REG;
- p->to.reg = REG_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = spadjop(ctxt, p, AADDL, AADDQ);
- if(v < 0) {
- p->as = spadjop(ctxt, p, 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(ctxt->headtype == Hnacl && p->isize > 0) {
- static LSym *deferreturn;
-
- if(deferreturn == nil)
- deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
-
- // pad everything to avoid crossing 32-byte boundary
- if((c>>5) != ((c+p->isize-1)>>5))
- c = naclpad(ctxt, s, c, -c&31);
- // pad call deferreturn to start at 32-byte boundary
- // so that subtracting 5 in jmpdefer will jump back
- // to that boundary and rerun the call.
- if(p->as == ACALL && p->to.sym == deferreturn)
- c = naclpad(ctxt, s, c, -c&31);
- // pad call to end at 32-byte boundary
- if(p->as == ACALL)
- c = naclpad(ctxt, s, c, -(c+p->isize)&31);
-
- // the linker treats REP and STOSQ as different instructions
- // but in fact the REP is a prefix on the STOSQ.
- // make sure REP has room for 2 more bytes, so that
- // padding will not be inserted before the next instruction.
- if((p->as == AREP || p->as == AREPN) && (c>>5) != ((c+3-1)>>5))
- c = naclpad(ctxt, s, c, -c&31);
-
- // same for LOCK.
- // various instructions follow; the longest is 4 bytes.
- // give ourselves 8 bytes so as to avoid surprises.
- if(p->as == ALOCK && (c>>5) != ((c+8-1)>>5))
- c = naclpad(ctxt, s, c, -c&31);
- }
-
- 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;
-
- p->pc = c;
- asmins(ctxt, p);
- m = ctxt->andptr-ctxt->and;
- if(p->isize != m) {
- p->isize = m;
- loop++;
- }
- 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);
-
- if(ctxt->headtype == Hnacl)
- c = naclpad(ctxt, s, c, -c&31);
-
- c += -c&(FuncAlign-1);
- 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<MAXREG; i++) {
- reg[i] = -1;
- if(i >= REG_AL && i <= REG_R15B) {
- reg[i] = (i-REG_AL) & 7;
- if(i >= REG_SPB && i <= REG_DIB)
- regrex[i] = 0x40;
- if(i >= REG_R8B && i <= REG_R15B)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= REG_AH && i<= REG_BH)
- reg[i] = 4 + ((i-REG_AH) & 7);
- if(i >= REG_AX && i <= REG_R15) {
- reg[i] = (i-REG_AX) & 7;
- if(i >= REG_R8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= REG_F0 && i <= REG_F0+7)
- reg[i] = (i-REG_F0) & 7;
- if(i >= REG_M0 && i <= REG_M0+7)
- reg[i] = (i-REG_M0) & 7;
- if(i >= REG_X0 && i <= REG_X0+15) {
- reg[i] = (i-REG_X0) & 7;
- if(i >= REG_X0+8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= REG_CR+8 && i <= REG_CR+15)
- regrex[i] = Rxr;
- }
-}
-
-static int
-prefixof(Link *ctxt, Addr *a)
-{
- if(a->type == TYPE_MEM && a->name == NAME_NONE) {
- switch(a->reg) {
- case REG_CS:
- return 0x2e;
- case REG_DS:
- return 0x3e;
- case REG_ES:
- return 0x26;
- case REG_FS:
- return 0x64;
- case REG_GS:
- return 0x65;
- case REG_TLS:
- // NOTE: Systems listed here should be only systems that
- // support direct TLS references like 8(TLS) implemented as
- // direct references from FS or GS. Systems that require
- // the initial-exec model, where you load the TLS base into
- // a register and then index from that register, do not reach
- // this code and should not be listed.
- switch(ctxt->headtype) {
- default:
- sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
- case Hdragonfly:
- case Hfreebsd:
- case Hlinux:
- case Hnetbsd:
- case Hopenbsd:
- case Hsolaris:
- return 0x64; // FS
- case Hdarwin:
- return 0x65; // GS
- }
- }
- }
- switch(a->index) {
- case REG_CS:
- return 0x2e;
- case REG_DS:
- return 0x3e;
- case REG_ES:
- return 0x26;
- case REG_FS:
- return 0x64;
- case REG_GS:
- return 0x65;
- }
- return 0;
-}
-
-static int
-oclass(Link *ctxt, Prog *p, Addr *a)
-{
- vlong v;
- int32 l;
-
- USED(p);
-
- // TODO(rsc): This special case is for SHRQ $3, AX:DX,
- // which encodes as SHRQ $32(DX*0), AX.
- // Similarly SHRQ CX, AX:DX is really SHRQ CX(DX*0), AX.
- // Change encoding and remove.
- if((a->type == TYPE_CONST || a->type == TYPE_REG) && a->index != REG_NONE && a->scale == 0)
- return Ycol;
-
- switch(a->type) {
- case TYPE_NONE:
- return Ynone;
-
- case TYPE_BRANCH:
- return Ybr;
-
- case TYPE_MEM:
- return Ym;
-
- case TYPE_ADDR:
- switch(a->name) {
- case NAME_EXTERN:
- case NAME_STATIC:
- if(a->sym != nil && isextern(a->sym))
- return Yi32;
- return Yiauto; // use pc-relative addressing
- case NAME_AUTO:
- case NAME_PARAM:
- return Yiauto;
- }
-
- // TODO(rsc): DUFFZERO/DUFFCOPY encoding forgot to set a->index
- // and got Yi32 in an earlier version of this code.
- // Keep doing that until we fix yduff etc.
- if(a->sym != nil && strncmp(a->sym->name, "runtime.duff", 12) == 0)
- return Yi32;
-
- if(a->sym != nil || a->name != NAME_NONE)
- ctxt->diag("unexpected addr: %D", a);
- // fall through
-
- case TYPE_CONST:
- if(a->sym != nil)
- ctxt->diag("TYPE_CONST with symbol: %D", a);
-
- 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;
-
- case TYPE_TEXTSIZE:
- return Ytextsize;
- }
-
- if(a->type != TYPE_REG) {
- ctxt->diag("unexpected addr1: type=%d %D", a->type, a);
- return Yxxx;
- }
-
- switch(a->reg) {
- case REG_AL:
- return Yal;
-
- case REG_AX:
- return Yax;
-
-/*
- case REG_SPB:
-*/
- case REG_BPB:
- case REG_SIB:
- case REG_DIB:
- case REG_R8B:
- case REG_R9B:
- case REG_R10B:
- case REG_R11B:
- case REG_R12B:
- case REG_R13B:
- case REG_R14B:
- case REG_R15B:
- if(ctxt->asmode != 64)
- return Yxxx;
- case REG_DL:
- case REG_BL:
- case REG_AH:
- case REG_CH:
- case REG_DH:
- case REG_BH:
- return Yrb;
-
- case REG_CL:
- return Ycl;
-
- case REG_CX:
- return Ycx;
-
- case REG_DX:
- case REG_BX:
- return Yrx;
-
- case REG_R8: /* not really Yrl */
- case REG_R9:
- case REG_R10:
- case REG_R11:
- case REG_R12:
- case REG_R13:
- case REG_R14:
- case REG_R15:
- if(ctxt->asmode != 64)
- return Yxxx;
- case REG_SP:
- case REG_BP:
- case REG_SI:
- case REG_DI:
- return Yrl;
-
- case REG_F0+0:
- return Yf0;
-
- case REG_F0+1:
- case REG_F0+2:
- case REG_F0+3:
- case REG_F0+4:
- case REG_F0+5:
- case REG_F0+6:
- case REG_F0+7:
- return Yrf;
-
- case REG_M0+0:
- case REG_M0+1:
- case REG_M0+2:
- case REG_M0+3:
- case REG_M0+4:
- case REG_M0+5:
- case REG_M0+6:
- case REG_M0+7:
- return Ymr;
-
- case REG_X0+0:
- case REG_X0+1:
- case REG_X0+2:
- case REG_X0+3:
- case REG_X0+4:
- case REG_X0+5:
- case REG_X0+6:
- case REG_X0+7:
- case REG_X0+8:
- case REG_X0+9:
- case REG_X0+10:
- case REG_X0+11:
- case REG_X0+12:
- case REG_X0+13:
- case REG_X0+14:
- case REG_X0+15:
- return Yxr;
-
- case REG_CS: return Ycs;
- case REG_SS: return Yss;
- case REG_DS: return Yds;
- case REG_ES: return Yes;
- case REG_FS: return Yfs;
- case REG_GS: return Ygs;
- case REG_TLS: return Ytls;
-
- case REG_GDTR: return Ygdtr;
- case REG_IDTR: return Yidtr;
- case REG_LDTR: return Yldtr;
- case REG_MSW: return Ymsw;
- case REG_TASK: return Ytask;
-
- case REG_CR+0: return Ycr0;
- case REG_CR+1: return Ycr1;
- case REG_CR+2: return Ycr2;
- case REG_CR+3: return Ycr3;
- case REG_CR+4: return Ycr4;
- case REG_CR+5: return Ycr5;
- case REG_CR+6: return Ycr6;
- case REG_CR+7: return Ycr7;
- case REG_CR+8: return Ycr8;
-
- case REG_DR+0: return Ydr0;
- case REG_DR+1: return Ydr1;
- case REG_DR+2: return Ydr2;
- case REG_DR+3: return Ydr3;
- case REG_DR+4: return Ydr4;
- case REG_DR+5: return Ydr5;
- case REG_DR+6: return Ydr6;
- case REG_DR+7: return Ydr7;
-
- case REG_TR+0: return Ytr0;
- case REG_TR+1: return Ytr1;
- case REG_TR+2: return Ytr2;
- case REG_TR+3: return Ytr3;
- case REG_TR+4: return Ytr4;
- case REG_TR+5: return Ytr5;
- case REG_TR+6: return Ytr6;
- case REG_TR+7: return Ytr7;
-
- }
- return Yxxx;
-}
-
-static void
-asmidx(Link *ctxt, int scale, int index, int base)
-{
- int i;
-
- switch(index) {
- default:
- goto bad;
-
- case REG_NONE:
- i = 4 << 3;
- goto bas;
-
- case REG_R8:
- case REG_R9:
- case REG_R10:
- case REG_R11:
- case REG_R12:
- case REG_R13:
- case REG_R14:
- case REG_R15:
- if(ctxt->asmode != 64)
- goto bad;
- case REG_AX:
- case REG_CX:
- case REG_DX:
- case REG_BX:
- case REG_BP:
- case REG_SI:
- case REG_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 REG_NONE: /* must be mod=00 */
- i |= 5;
- break;
- case REG_R8:
- case REG_R9:
- case REG_R10:
- case REG_R11:
- case REG_R12:
- case REG_R13:
- case REG_R14:
- case REG_R15:
- if(ctxt->asmode != 64)
- goto bad;
- case REG_AX:
- case REG_CX:
- case REG_DX:
- case REG_BX:
- case REG_SP:
- case REG_BP:
- case REG_SI:
- case REG_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, p, 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, p, 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, Prog *p, Addr *a, Reloc *r)
-{
- LSym *s;
-
- USED(p);
-
- if(r != nil)
- memset(r, 0, sizeof *r);
-
- switch(a->name) {
- case NAME_STATIC:
- case NAME_EXTERN:
- s = a->sym;
- if(r == nil) {
- ctxt->diag("need reloc for %D", a);
- sysfatal("reloc");
- }
- if(isextern(s)) {
- r->siz = 4;
- r->type = R_ADDR;
- } else {
- r->siz = 4;
- r->type = R_PCREL;
- }
- r->off = -1; // caller must fill in
- r->sym = s;
- r->add = a->offset;
- if(s->type == STLSBSS) {
- r->xadd = r->add - r->siz;
- r->type = R_TLS;
- r->xsym = s;
- }
- return 0;
- }
-
- if((a->type == TYPE_MEM || a->type == TYPE_ADDR) && a->reg == REG_TLS) {
- if(r == nil) {
- ctxt->diag("need reloc for %D", a);
- sysfatal("reloc");
- }
- r->type = R_TLS_LE;
- r->siz = 4;
- r->off = -1; // caller must fill in
- r->add = a->offset;
- return 0;
- }
-
- return a->offset;
-}
-
-static void
-asmandsz(Link *ctxt, Prog *p, Addr *a, int r, int rex, int m64)
-{
- int32 v;
- int base;
- Reloc rel;
-
- USED(m64);
- USED(p);
-
- rex &= (0x40 | Rxr);
- v = a->offset;
- rel.siz = 0;
-
- switch(a->type) {
- case TYPE_ADDR:
- if(a->name == NAME_NONE)
- ctxt->diag("unexpected TYPE_ADDR with NAME_NONE");
- if(a->index == REG_TLS)
- ctxt->diag("unexpected TYPE_ADDR with index==REG_TLS");
- goto bad;
-
- case TYPE_REG:
- if(a->reg < REG_AL || REG_X0+15 < a->reg)
- goto bad;
- if(v)
- goto bad;
- *ctxt->andptr++ = (3 << 6) | (reg[a->reg] << 0) | (r << 3);
- ctxt->rexflag |= (regrex[a->reg] & (0x40 | Rxb)) | rex;
- return;
- }
-
- if(a->type != TYPE_MEM)
- goto bad;
-
- if(a->index != REG_NONE && a->index != REG_TLS) {
- base = a->reg;
- switch(a->name) {
- case NAME_EXTERN:
- case NAME_STATIC:
- if(!isextern(a->sym))
- goto bad;
- base = REG_NONE;
- v = vaddr(ctxt, p, a, &rel);
- break;
- case NAME_AUTO:
- case NAME_PARAM:
- base = REG_SP;
- break;
- }
-
- ctxt->rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[base] & Rxb) | rex;
- if(base == REG_NONE) {
- *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(ctxt, a->scale, a->index, base);
- goto putrelv;
- }
- if(v == 0 && rel.siz == 0 && base != REG_BP && base != REG_R13) {
- *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(ctxt, a->scale, a->index, base);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(ctxt, a->scale, a->index, base);
- *ctxt->andptr++ = v;
- return;
- }
- *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(ctxt, a->scale, a->index, base);
- goto putrelv;
- }
-
- base = a->reg;
- switch(a->name) {
- case NAME_STATIC:
- case NAME_EXTERN:
- if(a->sym == nil)
- ctxt->diag("bad addr: %P", p);
- base = REG_NONE;
- v = vaddr(ctxt, p, a, &rel);
- break;
- case NAME_AUTO:
- case NAME_PARAM:
- base = REG_SP;
- break;
- }
-
- if(base == REG_TLS)
- v = vaddr(ctxt, p, a, &rel);
-
- ctxt->rexflag |= (regrex[base] & Rxb) | rex;
- if(base == REG_NONE || (REG_CS <= base && base <= REG_GS) || base == REG_TLS) {
- if((a->sym == nil || !isextern(a->sym)) && base == REG_NONE && (a->name == NAME_STATIC || a->name == NAME_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(base == REG_SP || base == REG_R12) {
- if(v == 0) {
- *ctxt->andptr++ = (0 << 6) | (reg[base] << 0) | (r << 3);
- asmidx(ctxt, a->scale, REG_NONE, base);
- return;
- }
- if(v >= -128 && v < 128) {
- *ctxt->andptr++ = (1 << 6) | (reg[base] << 0) | (r << 3);
- asmidx(ctxt, a->scale, REG_NONE, base);
- *ctxt->andptr++ = v;
- return;
- }
- *ctxt->andptr++ = (2 << 6) | (reg[base] << 0) | (r << 3);
- asmidx(ctxt, a->scale, REG_NONE, base);
- goto putrelv;
- }
-
- if(REG_AX <= base && base <= REG_R15) {
- if(a->index == REG_TLS) {
- memset(&rel, 0, sizeof rel);
- rel.type = R_TLS_IE;
- rel.siz = 4;
- rel.sym = nil;
- rel.add = v;
- v = 0;
- }
- if(v == 0 && rel.siz == 0 && base != REG_BP && base != REG_R13) {
- *ctxt->andptr++ = (0 << 6) | (reg[base] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- ctxt->andptr[0] = (1 << 6) | (reg[base] << 0) | (r << 3);
- ctxt->andptr[1] = v;
- ctxt->andptr += 2;
- return;
- }
- *ctxt->andptr++ = (2 << 6) | (reg[base] << 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;
- }
-
- put4(ctxt, v);
- return;
-
-bad:
- ctxt->diag("asmand: bad address %D", a);
- return;
-}
-
-static void
-asmand(Link *ctxt, Prog *p, Addr *a, Addr *ra)
-{
- asmandsz(ctxt, p, a, reg[ra->reg], regrex[ra->reg], 0);
-}
-
-static void
-asmando(Link *ctxt, Prog *p, Addr *a, int o)
-{
- asmandsz(ctxt, p, a, o, 0, 0);
-}
-
-static void
-bytereg(Addr *a, uint8 *t)
-{
- if(a->type == TYPE_REG && a->index == REG_NONE && (REG_AX <= a->reg && a->reg <= REG_R15)) {
- a->reg += REG_AL - REG_AX;
- *t = 0;
- }
-}
-
-enum {
- 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}},
-
-/* load TLS base */
- {AMOVQ, Ytls, Yrl, 7, {0,0,0,0}},
-
- {0}
-};
-
-static int
-isax(Addr *a)
-{
- switch(a->reg) {
- case REG_AX:
- case REG_AL:
- case REG_AH:
- return 1;
- }
- if(a->index == REG_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.reg == from) {
- p->from.reg = to;
- p->ft = 0;
- }
- if(p->to.reg == from) {
- p->to.reg = 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;
- }
-
- 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->and[ctxt->andptr - ctxt->and - 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(ctxt, &p->from);
- if(pre)
- *ctxt->andptr++ = pre;
- pre = prefixof(ctxt, &p->to);
- if(pre)
- *ctxt->andptr++ = pre;
-
- if(p->ft == 0)
- p->ft = oclass(ctxt, p, &p->from);
- if(p->tt == 0)
- p->tt = oclass(ctxt, p, &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 and opcode escape */
- *ctxt->andptr++ = Pe;
- *ctxt->andptr++ = Pm;
- break;
- case Pq3: /* 16 bit escape, Rex.w, 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, &p->from, &p->to);
- break;
-
- case Zmb_r:
- bytereg(&p->from, &p->ft);
- /* fall through */
- case Zm_r:
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->from, &p->to);
- break;
- case Zm2_r:
- *ctxt->andptr++ = op;
- *ctxt->andptr++ = o->op[z+1];
- asmand(ctxt, p, &p->from, &p->to);
- break;
-
- case Zm_r_xm:
- mediaop(ctxt, o, op, t[3], z);
- asmand(ctxt, p, &p->from, &p->to);
- break;
-
- case Zm_r_xm_nr:
- ctxt->rexflag = 0;
- mediaop(ctxt, o, op, t[3], z);
- asmand(ctxt, p, &p->from, &p->to);
- break;
-
- case Zm_r_i_xm:
- mediaop(ctxt, o, op, t[3], z);
- asmand(ctxt, p, &p->from, &p->to);
- *ctxt->andptr++ = p->to.offset;
- break;
-
- case Zm_r_3d:
- *ctxt->andptr++ = 0x0f;
- *ctxt->andptr++ = 0x0f;
- asmand(ctxt, p, &p->from, &p->to);
- *ctxt->andptr++ = op;
- break;
-
- case Zibm_r:
- while ((op = o->op[z++]) != 0)
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->from, &p->to);
- *ctxt->andptr++ = p->to.offset;
- break;
-
- case Zaut_r:
- *ctxt->andptr++ = 0x8d; /* leal */
- if(p->from.type != TYPE_ADDR)
- ctxt->diag("asmins: Zaut sb type ADDR");
- p->from.type = TYPE_MEM;
- asmand(ctxt, p, &p->from, &p->to);
- p->from.type = TYPE_ADDR;
- break;
-
- case Zm_o:
- *ctxt->andptr++ = op;
- asmando(ctxt, p, &p->from, o->op[z+1]);
- break;
-
- case Zr_m:
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->to, &p->from);
- break;
-
- case Zr_m_xm:
- mediaop(ctxt, o, op, t[3], z);
- asmand(ctxt, p, &p->to, &p->from);
- break;
-
- case Zr_m_xm_nr:
- ctxt->rexflag = 0;
- mediaop(ctxt, o, op, t[3], z);
- asmand(ctxt, p, &p->to, &p->from);
- break;
-
- case Zr_m_i_xm:
- mediaop(ctxt, o, op, t[3], z);
- asmand(ctxt, p, &p->to, &p->from);
- *ctxt->andptr++ = p->from.offset;
- break;
-
- case Zo_m:
- *ctxt->andptr++ = op;
- asmando(ctxt, p, &p->to, o->op[z+1]);
- break;
-
- case Zcallindreg:
- r = addrel(ctxt->cursym);
- r->off = p->pc;
- r->type = R_CALLIND;
- r->siz = 0;
- // fallthrough
- case Zo_m64:
- *ctxt->andptr++ = op;
- asmandsz(ctxt, p, &p->to, o->op[z+1], 0, 1);
- break;
-
- case Zm_ibo:
- *ctxt->andptr++ = op;
- asmando(ctxt, p, &p->from, o->op[z+1]);
- *ctxt->andptr++ = vaddr(ctxt, p, &p->to, nil);
- break;
-
- case Zibo_m:
- *ctxt->andptr++ = op;
- asmando(ctxt, p, &p->to, o->op[z+1]);
- *ctxt->andptr++ = vaddr(ctxt, p, &p->from, nil);
- break;
-
- case Zibo_m_xm:
- z = mediaop(ctxt, o, op, t[3], z);
- asmando(ctxt, p, &p->to, o->op[z+1]);
- *ctxt->andptr++ = vaddr(ctxt, p, &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, p, a, nil);
- break;
-
- case Zib_rp:
- ctxt->rexflag |= regrex[p->to.reg] & (Rxb|0x40);
- *ctxt->andptr++ = op + reg[p->to.reg];
- *ctxt->andptr++ = vaddr(ctxt, p, &p->from, nil);
- break;
-
- case Zil_rp:
- ctxt->rexflag |= regrex[p->to.reg] & Rxb;
- *ctxt->andptr++ = op + reg[p->to.reg];
- if(o->prefix == Pe) {
- v = vaddr(ctxt, p, &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 != TYPE_NONE){
- v = vaddr(ctxt, p, &p->from, nil);
- *ctxt->andptr++ = v;
- *ctxt->andptr++ = v>>8;
- }
- break;
-
- case Ziq_rp:
- v = vaddr(ctxt, p, &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.reg] & Rxb;
- *ctxt->andptr++ = 0xb8 + reg[p->to.reg];
- 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, &p->to, 0);
- put4(ctxt, v);
- }else{ /* need all 8 */
- //print("all: %llux %P\n", v, p);
- ctxt->rexflag |= regrex[p->to.reg] & Rxb;
- *ctxt->andptr++ = op + reg[p->to.reg];
- 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, &p->to, &p->to);
- *ctxt->andptr++ = vaddr(ctxt, p, &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, p, 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, &p->to, o->op[z+1]);
- } else {
- a = &p->to;
- asmando(ctxt, p, &p->from, o->op[z+1]);
- }
- if(o->prefix == Pe) {
- v = vaddr(ctxt, p, a, nil);
- *ctxt->andptr++ = v;
- *ctxt->andptr++ = v>>8;
- }
- else
- relput4(ctxt, p, a);
- break;
-
- case Zil_rr:
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->to, &p->to);
- if(o->prefix == Pe) {
- v = vaddr(ctxt, p, &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.reg] & (Rxb|0x40);
- *ctxt->andptr++ = op + reg[p->to.reg];
- break;
-
- case Zrp_:
- ctxt->rexflag |= regrex[p->from.reg] & (Rxb|0x40);
- *ctxt->andptr++ = op + reg[p->from.reg];
- break;
-
- case Zclr:
- ctxt->rexflag &= ~Pw;
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &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->add = p->to.offset;
- r->type = R_CALL;
- 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 = R_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, &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 and reissue the
- * instruction with the operands renamed.
- */
- pp = *p;
- z = p->from.reg;
- if(p->from.type == TYPE_REG && z >= REG_BP && z <= REG_DI) {
- if(isax(&p->to) || p->to.type == TYPE_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, &p->from, reg[REG_BX]);
- subreg(&pp, z, REG_BX);
- doasm(ctxt, &pp);
- *ctxt->andptr++ = 0x87; /* xchg lhs,bx */
- asmando(ctxt, p, &p->from, reg[REG_BX]);
- } else {
- *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- subreg(&pp, z, REG_AX);
- doasm(ctxt, &pp);
- *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- }
- return;
- }
- z = p->to.reg;
- if(p->to.type == TYPE_REG && z >= REG_BP && z <= REG_DI) {
- if(isax(&p->from)) {
- *ctxt->andptr++ = 0x87; /* xchg rhs,bx */
- asmando(ctxt, p, &p->to, reg[REG_BX]);
- subreg(&pp, z, REG_BX);
- doasm(ctxt, &pp);
- *ctxt->andptr++ = 0x87; /* xchg rhs,bx */
- asmando(ctxt, p, &p->to, reg[REG_BX]);
- } else {
- *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- subreg(&pp, z, REG_AX);
- doasm(ctxt, &pp);
- *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- }
- return;
- }
- }
- ctxt->diag("doasm: notfound ft=%d tt=%d %P %d %d", p->ft, p->tt, p, oclass(ctxt, p, &p->from), oclass(ctxt, p, &p->to));
- 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, &p->to, t[1]);
- break;
-
- case 2: /* m,r */
- *ctxt->andptr++ = t[0];
- asmando(ctxt, p, &p->from, t[1]);
- break;
-
- case 3: /* r,m - 2op */
- *ctxt->andptr++ = t[0];
- *ctxt->andptr++ = t[1];
- asmando(ctxt, p, &p->to, t[2]);
- ctxt->rexflag |= regrex[p->from.reg] & (Rxr|0x40);
- break;
-
- case 4: /* m,r - 2op */
- *ctxt->andptr++ = t[0];
- *ctxt->andptr++ = t[1];
- asmando(ctxt, p, &p->from, t[2]);
- ctxt->rexflag |= regrex[p->to.reg] & (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 REG_DS:
- *ctxt->andptr++ = 0xc5;
- break;
- case REG_SS:
- *ctxt->andptr++ = 0x0f;
- *ctxt->andptr++ = 0xb2;
- break;
- case REG_ES:
- *ctxt->andptr++ = 0xc4;
- break;
- case REG_FS:
- *ctxt->andptr++ = 0x0f;
- *ctxt->andptr++ = 0xb4;
- break;
- case REG_GS:
- *ctxt->andptr++ = 0x0f;
- *ctxt->andptr++ = 0xb5;
- break;
- }
- asmand(ctxt, p, &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++;
- }
- switch(p->from.type) {
- default:
- goto bad;
- case TYPE_CONST:
- *ctxt->andptr++ = 0x0f;
- *ctxt->andptr++ = t[0];
- asmandsz(ctxt, p, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
- *ctxt->andptr++ = p->from.offset;
- break;
- case TYPE_REG:
- switch(p->from.reg) {
- default:
- goto bad;
- case REG_CL:
- case REG_CX:
- *ctxt->andptr++ = 0x0f;
- *ctxt->andptr++ = t[1];
- asmandsz(ctxt, p, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
- break;
- }
- }
- break;
-
- case 7: /* mov tls, r */
- // NOTE: The systems listed here are the ones that use the "TLS initial exec" model,
- // where you load the TLS base register into a register and then index off that
- // register to access the actual TLS variables. Systems that allow direct TLS access
- // are handled in prefixof above and should not be listed here.
- switch(ctxt->headtype) {
- default:
- sysfatal("unknown TLS base location for %s", headstr(ctxt->headtype));
-
- case Hplan9:
- if(ctxt->plan9privates == nil)
- ctxt->plan9privates = linklookup(ctxt, "_privates", 0);
- memset(&pp.from, 0, sizeof pp.from);
- pp.from.type = TYPE_MEM;
- pp.from.name = NAME_EXTERN;
- pp.from.sym = ctxt->plan9privates;
- pp.from.offset = 0;
- pp.from.index = REG_NONE;
- ctxt->rexflag |= Pw;
- *ctxt->andptr++ = 0x8B;
- asmand(ctxt, p, &pp.from, &p->to);
- break;
-
- case Hsolaris: // TODO(rsc): Delete Hsolaris from list. Should not use this code. See progedit in obj6.c.
- // TLS base is 0(FS).
- pp.from = p->from;
- pp.from.type = TYPE_MEM;
- pp.from.name = NAME_NONE;
- pp.from.reg = REG_NONE;
- pp.from.offset = 0;
- pp.from.index = REG_NONE;
- pp.from.scale = 0;
- ctxt->rexflag |= Pw;
- *ctxt->andptr++ = 0x64; // FS
- *ctxt->andptr++ = 0x8B;
- asmand(ctxt, p, &pp.from, &p->to);
- break;
-
- case Hwindows:
- // Windows TLS base is always 0x28(GS).
- pp.from = p->from;
- pp.from.type = TYPE_MEM;
- pp.from.name = NAME_NONE;
- pp.from.reg = REG_GS;
- pp.from.offset = 0x28;
- pp.from.index = REG_NONE;
- pp.from.scale = 0;
- ctxt->rexflag |= Pw;
- *ctxt->andptr++ = 0x65; // GS
- *ctxt->andptr++ = 0x8B;
- asmand(ctxt, p, &pp.from, &p->to);
- break;
- }
- break;
- }
-}
-
-static uchar naclret[] = {
- 0x5e, // POPL SI
- // 0x8b, 0x7d, 0x00, // MOVL (BP), DI - catch return to invalid address, for debugging
- 0x83, 0xe6, 0xe0, // ANDL $~31, SI
- 0x4c, 0x01, 0xfe, // ADDQ R15, SI
- 0xff, 0xe6, // JMP SI
-};
-
-static uchar naclspfix[] = {
- 0x4c, 0x01, 0xfc, // ADDQ R15, SP
-};
-
-static uchar naclbpfix[] = {
- 0x4c, 0x01, 0xfd, // ADDQ R15, BP
-};
-
-static uchar naclmovs[] = {
- 0x89, 0xf6, // MOVL SI, SI
- 0x49, 0x8d, 0x34, 0x37, // LEAQ (R15)(SI*1), SI
- 0x89, 0xff, // MOVL DI, DI
- 0x49, 0x8d, 0x3c, 0x3f, // LEAQ (R15)(DI*1), DI
-};
-
-static uchar naclstos[] = {
- 0x89, 0xff, // MOVL DI, DI
- 0x49, 0x8d, 0x3c, 0x3f, // LEAQ (R15)(DI*1), DI
-};
-
-static void
-nacltrunc(Link *ctxt, int reg)
-{
- if(reg >= REG_R8)
- *ctxt->andptr++ = 0x45;
- reg = (reg - REG_AX) & 7;
- *ctxt->andptr++ = 0x89;
- *ctxt->andptr++ = (3<<6) | (reg<<3) | reg;
-}
-
-static void
-asmins(Link *ctxt, Prog *p)
-{
- int i, n, np, c;
- uchar *and0;
- Reloc *r;
-
- ctxt->andptr = ctxt->and;
- ctxt->asmode = p->mode;
-
- if(p->as == AUSEFIELD) {
- r = addrel(ctxt->cursym);
- r->off = 0;
- r->siz = 0;
- r->sym = p->from.sym;
- r->type = R_USEFIELD;
- return;
- }
-
- if(ctxt->headtype == Hnacl) {
- if(p->as == AREP) {
- ctxt->rep++;
- return;
- }
- if(p->as == AREPN) {
- ctxt->repn++;
- return;
- }
- if(p->as == ALOCK) {
- ctxt->lock++;
- return;
- }
- if(p->as != ALEAQ && p->as != ALEAL) {
- if(p->from.index != TYPE_NONE && p->from.scale > 0)
- nacltrunc(ctxt, p->from.index);
- if(p->to.index != TYPE_NONE && p->to.scale > 0)
- nacltrunc(ctxt, p->to.index);
- }
- switch(p->as) {
- case ARET:
- memmove(ctxt->andptr, naclret, sizeof naclret);
- ctxt->andptr += sizeof naclret;
- return;
- case ACALL:
- case AJMP:
- if(p->to.type == TYPE_REG && REG_AX <= p->to.reg && p->to.reg <= REG_DI) {
- // ANDL $~31, reg
- *ctxt->andptr++ = 0x83;
- *ctxt->andptr++ = 0xe0 | (p->to.reg - REG_AX);
- *ctxt->andptr++ = 0xe0;
- // ADDQ R15, reg
- *ctxt->andptr++ = 0x4c;
- *ctxt->andptr++ = 0x01;
- *ctxt->andptr++ = 0xf8 | (p->to.reg - REG_AX);
- }
- if(p->to.type == TYPE_REG && REG_R8 <= p->to.reg && p->to.reg <= REG_R15) {
- // ANDL $~31, reg
- *ctxt->andptr++ = 0x41;
- *ctxt->andptr++ = 0x83;
- *ctxt->andptr++ = 0xe0 | (p->to.reg - REG_R8);
- *ctxt->andptr++ = 0xe0;
- // ADDQ R15, reg
- *ctxt->andptr++ = 0x4d;
- *ctxt->andptr++ = 0x01;
- *ctxt->andptr++ = 0xf8 | (p->to.reg - REG_R8);
- }
- break;
- case AINT:
- *ctxt->andptr++ = 0xf4;
- return;
- case ASCASB:
- case ASCASW:
- case ASCASL:
- case ASCASQ:
- case ASTOSB:
- case ASTOSW:
- case ASTOSL:
- case ASTOSQ:
- memmove(ctxt->andptr, naclstos, sizeof naclstos);
- ctxt->andptr += sizeof naclstos;
- break;
- case AMOVSB:
- case AMOVSW:
- case AMOVSL:
- case AMOVSQ:
- memmove(ctxt->andptr, naclmovs, sizeof naclmovs);
- ctxt->andptr += sizeof naclmovs;
- break;
- }
- if(ctxt->rep) {
- *ctxt->andptr++ = 0xf3;
- ctxt->rep = 0;
- }
- if(ctxt->repn) {
- *ctxt->andptr++ = 0xf2;
- ctxt->repn = 0;
- }
- if(ctxt->lock) {
- *ctxt->andptr++ = 0xf0;
- ctxt->lock = 0;
- }
- }
-
- ctxt->rexflag = 0;
- and0 = ctxt->andptr;
- 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
- * (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 - and0;
- for(np = 0; np < n; np++) {
- c = and0[np];
- if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
- break;
- }
- memmove(and0+np+1, and0+np, n-np);
- and0[np] = 0x40 | ctxt->rexflag;
- ctxt->andptr++;
- }
- n = ctxt->andptr - ctxt->and;
- for(i=ctxt->cursym->nr-1; i>=0; i--) {
- r = ctxt->cursym->r+i;
- if(r->off < p->pc)
- break;
- if(ctxt->rexflag)
- r->off++;
- if(r->type == R_PCREL || r->type == R_CALL)
- r->add -= p->pc + n - (r->off + r->siz);
- }
-
- if(ctxt->headtype == Hnacl && p->as != ACMPL && p->as != ACMPQ && p->to.type == TYPE_REG) {
- switch(p->to.reg) {
- case REG_SP:
- memmove(ctxt->andptr, naclspfix, sizeof naclspfix);
- ctxt->andptr += sizeof naclspfix;
- break;
- case REG_BP:
- memmove(ctxt->andptr, naclbpfix, sizeof naclbpfix);
- ctxt->andptr += sizeof naclbpfix;
- break;
- }
- }
-}
+++ /dev/null
-// 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 "../runtime/stack.h"
-
-enum
-{
- MaxAlign = 32, // max data alignment
- FuncAlign = 16
-};
-
-typedef struct Optab Optab;
-
-struct Optab
-{
- short as;
- uchar* ytab;
- uchar prefix;
- uchar op[13];
-};
-
-static Optab* opindex[ALAST+1];
-
-enum
-{
- Yxxx = 0,
- Ynone,
- Yi0,
- Yi1,
- Yi8,
- Yi32,
- Yiauto,
- Yal,
- Ycl,
- Yax,
- Ycx,
- Yrb,
- Yrl,
- Yrf,
- Yf0,
- Yrx,
- Ymb,
- Yml,
- Ym,
- Ybr,
- Ycol,
- Ytextsize,
- Ytls,
-
- 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,
- Zcallindreg,
- 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 int reg[MAXREG];
-static void asmins(Link *ctxt, Prog *p);
-
-static uchar ynone[] =
-{
- Ynone, Ynone, Zlit, 1,
- 0
-};
-static uchar ytext[] =
-{
- Ymb, Ytextsize, Zpseudo,1,
- 0
-};
-static uchar ynop[] =
-{
- Ynone, Ynone, Zpseudo,0,
- Ynone, Yiauto, Zpseudo,0,
- Ynone, Yml, Zpseudo,0,
- Ynone, Yrf, Zpseudo,0,
- Yiauto, Ynone, Zpseudo,0,
- Ynone, Yxr, 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 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, Zcallindreg, 0,
- Yrx, Yrx, Zcallindreg, 2,
- Ynone, Ycol, Zcallind, 2,
- Ynone, Ybr, Zcall, 0,
- Ynone, Yi32, Zcallcon, 1,
- 0
-};
-static uchar yduff[] =
-{
- Ynone, Yi32, Zcall, 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 uchar yxshuf[] =
-{
- Yxm, Yxr, Zibm_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 },
- { 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)} },
- { ANEGB, yscond, Px, {0xf6,(03)} },
- { ANEGL, yscond, Px, {0xf7,(03)} }, // TODO(rsc): yscond is wrong here.
- { ANEGW, yscond, Pe, {0xf7,(03)} }, // TODO(rsc): yscond is wrong here.
- { ANOP, ynop, Px, {0,0} },
- { ANOTB, yscond, Px, {0xf6,(02)} },
- { ANOTL, yscond, Px, {0xf7,(02)} }, // TODO(rsc): yscond is wrong here.
- { ANOTW, yscond, Pe, {0xf7,(02)} }, // TODO(rsc): yscond is wrong here.
- { 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, {0x9b,(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 },
- { ACMPXCHGB, yrb_mb, Pm, {0xb0} },
- { ACMPXCHGL, yrl_ml, Pm, {0xb1} },
- { ACMPXCHGW, yrl_ml, Pm, {0xb1} },
- { ACMPXCHG8B, yscond, Pm, {0xc7,(01)} }, // TODO(rsc): yscond is wrong here.
-
- { 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} },
- { APXOR, yxm, Pe, {0xef} },
- { 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} },
- { APSHUFHW, yxshuf, Pf3, {0x70,(00)} },
- { APSHUFL, yxshuf, Pq, {0x70,(00)} },
- { APSHUFLW, yxshuf, Pf2, {0x70,(00)} },
-
-
- { 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 },
- { AVARDEF },
- { AVARKILL },
- { ADUFFCOPY, yduff, Px, {0xe8} },
- { ADUFFZERO, yduff, Px, {0xe8} },
-
- {0}
-};
-
-static int32 vaddr(Link*, Prog*, Addr*, 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},
- // Native Client rejects the repeated 0x66 prefix.
- // {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 int32
-naclpad(Link *ctxt, LSym *s, int32 c, int32 pad)
-{
- symgrow(ctxt, s, c+pad);
- fillnop(s->p+c, pad);
- return c+pad;
-}
-
-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) {
- if(p->to.type == TYPE_BRANCH)
- if(p->pcond == nil)
- p->pcond = p;
- if(p->as == AADJSP) {
- p->to.type = TYPE_REG;
- p->to.reg = REG_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 = TYPE_REG;
- p->to.reg = REG_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) {
- if(ctxt->headtype == Hnacl && p->isize > 0) {
- static LSym *deferreturn;
-
- if(deferreturn == nil)
- deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
-
- // pad everything to avoid crossing 32-byte boundary
- if((c>>5) != ((c+p->isize-1)>>5))
- c = naclpad(ctxt, s, c, -c&31);
- // pad call deferreturn to start at 32-byte boundary
- // so that subtracting 5 in jmpdefer will jump back
- // to that boundary and rerun the call.
- if(p->as == ACALL && p->to.sym == deferreturn)
- c = naclpad(ctxt, s, c, -c&31);
- // pad call to end at 32-byte boundary
- if(p->as == ACALL)
- c = naclpad(ctxt, s, c, -(c+p->isize)&31);
-
- // the linker treats REP and STOSQ as different instructions
- // but in fact the REP is a prefix on the STOSQ.
- // make sure REP has room for 2 more bytes, so that
- // padding will not be inserted before the next instruction.
- if(p->as == AREP && (c>>5) != ((c+3-1)>>5))
- c = naclpad(ctxt, s, c, -c&31);
-
- // same for LOCK.
- // various instructions follow; the longest is 4 bytes.
- // give ourselves 8 bytes so as to avoid surprises.
- if(p->as == ALOCK && (c>>5) != ((c+8-1)>>5))
- c = naclpad(ctxt, s, c, -c&31);
- }
-
- 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;
-
- p->pc = c;
- asmins(ctxt, p);
- m = ctxt->andptr-ctxt->and;
- if(p->isize != m) {
- p->isize = m;
- loop++;
- }
- 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);
-
- if(ctxt->headtype == Hnacl)
- c = naclpad(ctxt, s, c, -c&31);
- c += -c&(FuncAlign-1);
- 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 i, c;
-
- 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 + 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<MAXREG; i++) {
- reg[i] = -1;
- if(i >= REG_AL && i <= REG_BH)
- reg[i] = (i-REG_AL) & 7;
- if(i >= REG_AX && i <= REG_DI)
- reg[i] = (i-REG_AX) & 7;
- if(i >= REG_F0 && i <= REG_F0+7)
- reg[i] = (i-REG_F0) & 7;
- if(i >= REG_X0 && i <= REG_X0+7)
- reg[i] = (i-REG_X0) & 7;
- }
-}
-
-static int
-prefixof(Link *ctxt, Addr *a)
-{
- if(a->type == TYPE_MEM && a->name == NAME_NONE) {
- switch(a->reg) {
- case REG_CS:
- return 0x2e;
- case REG_DS:
- return 0x3e;
- case REG_ES:
- return 0x26;
- case REG_FS:
- return 0x64;
- case REG_GS:
- return 0x65;
- case REG_TLS:
- // NOTE: Systems listed here should be only systems that
- // support direct TLS references like 8(TLS) implemented as
- // direct references from FS or GS. Systems that require
- // the initial-exec model, where you load the TLS base into
- // a register and then index from that register, do not reach
- // this code and should not be listed.
- switch(ctxt->headtype) {
- default:
- sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
- case Hdarwin:
- case Hdragonfly:
- case Hfreebsd:
- case Hnetbsd:
- case Hopenbsd:
- return 0x65; // GS
- }
- }
- }
- return 0;
-}
-
-static int
-oclass(Link *ctxt, Prog *p, Addr *a)
-{
- int32 v;
-
- USED(p);
-
- // TODO(rsc): This special case is for SHRQ $3, AX:DX,
- // which encodes as SHRQ $32(DX*0), AX.
- // Similarly SHRQ CX, AX:DX is really SHRQ CX(DX*0), AX.
- // Change encoding and remove.
- if((a->type == TYPE_CONST || a->type == TYPE_REG) && a->index != REG_NONE && a->scale == 0)
- return Ycol;
-
- switch(a->type) {
- case TYPE_NONE:
- return Ynone;
-
- case TYPE_BRANCH:
- return Ybr;
-
- case TYPE_INDIR:
- // TODO(rsc): Why this is also Ycol is a mystery. Should split the two meanings.
- if(a->name != NAME_NONE && a->reg == REG_NONE && a->index == REG_NONE && a->scale == 0)
- return Ycol;
- return Yxxx;
-
- case TYPE_MEM:
- return Ym;
-
- case TYPE_ADDR:
- switch(a->name) {
- case NAME_EXTERN:
- case NAME_STATIC:
- return Yi32;
- case NAME_AUTO:
- case NAME_PARAM:
- return Yiauto;
- }
-
- // DUFFZERO/DUFFCOPY encoding forgot to set a->index
- // and got Yi32 in an earlier version of this code.
- // Keep doing that until we fix yduff etc.
- if(a->sym != nil && strncmp(a->sym->name, "runtime.duff", 12) == 0)
- return Yi32;
-
- if(a->sym != nil || a->name != NAME_NONE)
- ctxt->diag("unexpected addr: %D", a);
- // fall through
-
- case TYPE_CONST:
- if(a->sym != nil)
- ctxt->diag("TYPE_CONST with symbol: %D", a);
-
- v = a->offset;
- if(v == 0)
- return Yi0;
- if(v == 1)
- return Yi1;
- if(v >= -128 && v <= 127)
- return Yi8;
- return Yi32;
-
- case TYPE_TEXTSIZE:
- return Ytextsize;
- }
-
- if(a->type != TYPE_REG) {
- ctxt->diag("unexpected addr1: type=%d %D", a->type, a);
- return Yxxx;
- }
-
- switch(a->reg) {
- case REG_AL:
- return Yal;
-
- case REG_AX:
- return Yax;
-
- case REG_CL:
- case REG_DL:
- case REG_BL:
- case REG_AH:
- case REG_CH:
- case REG_DH:
- case REG_BH:
- return Yrb;
-
- case REG_CX:
- return Ycx;
-
- case REG_DX:
- case REG_BX:
- return Yrx;
-
- case REG_SP:
- case REG_BP:
- case REG_SI:
- case REG_DI:
- return Yrl;
-
- case REG_F0+0:
- return Yf0;
-
- case REG_F0+1:
- case REG_F0+2:
- case REG_F0+3:
- case REG_F0+4:
- case REG_F0+5:
- case REG_F0+6:
- case REG_F0+7:
- return Yrf;
-
- case REG_X0+0:
- case REG_X0+1:
- case REG_X0+2:
- case REG_X0+3:
- case REG_X0+4:
- case REG_X0+5:
- case REG_X0+6:
- case REG_X0+7:
- return Yxr;
-
- case REG_CS: return Ycs;
- case REG_SS: return Yss;
- case REG_DS: return Yds;
- case REG_ES: return Yes;
- case REG_FS: return Yfs;
- case REG_GS: return Ygs;
- case REG_TLS: return Ytls;
-
- case REG_GDTR: return Ygdtr;
- case REG_IDTR: return Yidtr;
- case REG_LDTR: return Yldtr;
- case REG_MSW: return Ymsw;
- case REG_TASK: return Ytask;
-
- case REG_CR+0: return Ycr0;
- case REG_CR+1: return Ycr1;
- case REG_CR+2: return Ycr2;
- case REG_CR+3: return Ycr3;
- case REG_CR+4: return Ycr4;
- case REG_CR+5: return Ycr5;
- case REG_CR+6: return Ycr6;
- case REG_CR+7: return Ycr7;
-
- case REG_DR+0: return Ydr0;
- case REG_DR+1: return Ydr1;
- case REG_DR+2: return Ydr2;
- case REG_DR+3: return Ydr3;
- case REG_DR+4: return Ydr4;
- case REG_DR+5: return Ydr5;
- case REG_DR+6: return Ydr6;
- case REG_DR+7: return Ydr7;
-
- case REG_TR+0: return Ytr0;
- case REG_TR+1: return Ytr1;
- case REG_TR+2: return Ytr2;
- case REG_TR+3: return Ytr3;
- case REG_TR+4: return Ytr4;
- case REG_TR+5: return Ytr5;
- case REG_TR+6: return Ytr6;
- case REG_TR+7: return Ytr7;
-
- }
- return Yxxx;
-}
-
-static void
-asmidx(Link *ctxt, int scale, int index, int base)
-{
- int i;
-
- switch(index) {
- default:
- goto bad;
-
- case TYPE_NONE:
- i = 4 << 3;
- goto bas;
-
- case REG_AX:
- case REG_CX:
- case REG_DX:
- case REG_BX:
- case REG_BP:
- case REG_SI:
- case REG_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 REG_NONE: /* must be mod=00 */
- i |= 5;
- break;
- case REG_AX:
- case REG_CX:
- case REG_DX:
- case REG_BX:
- case REG_SP:
- case REG_BP:
- case REG_SI:
- case REG_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, p, 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, Prog *p, Addr *a, Reloc *r)
-{
- LSym *s;
-
- USED(p);
-
- if(r != nil)
- memset(r, 0, sizeof *r);
-
- switch(a->name) {
- case NAME_STATIC:
- case NAME_EXTERN:
- s = a->sym;
- if(s != nil) {
- if(r == nil) {
- ctxt->diag("need reloc for %D", a);
- sysfatal("bad code");
- }
- r->type = R_ADDR;
- r->siz = 4;
- r->off = -1;
- r->sym = s;
- r->add = a->offset;
- return 0;
- }
- return a->offset;
- }
-
- if((a->type == TYPE_MEM || a->type == TYPE_ADDR) && a->reg == REG_TLS) {
- if(r == nil) {
- ctxt->diag("need reloc for %D", a);
- sysfatal("bad code");
- }
- r->type = R_TLS_LE;
- r->siz = 4;
- r->off = -1; // caller must fill in
- r->add = a->offset;
- return 0;
- }
-
- return a->offset;
-}
-
-static void
-asmand(Link *ctxt, Prog *p, Addr *a, int r)
-{
- int32 v;
- int base;
- Reloc rel;
-
- USED(p);
-
- v = a->offset;
- rel.siz = 0;
-
- switch(a->type) {
- case TYPE_ADDR:
- if(a->name == NAME_NONE)
- ctxt->diag("unexpected TYPE_ADDR with NAME_NONE");
- if(a->index == REG_TLS)
- ctxt->diag("unexpected TYPE_ADDR with index==REG_TLS");
- goto bad;
-
- case TYPE_REG:
- if((a->reg < REG_AL || REG_F7 < a->reg) && (a->reg < REG_X0 || REG_X0+7 < a->reg))
- goto bad;
- if(v)
- goto bad;
- *ctxt->andptr++ = (3 << 6) | (reg[a->reg] << 0) | (r << 3);
- return;
- }
-
- if(a->type != TYPE_MEM)
- goto bad;
-
- if(a->index != REG_NONE && a->index != REG_TLS) {
- base = a->reg;
- switch(a->name) {
- case NAME_EXTERN:
- case NAME_STATIC:
- base = REG_NONE;
- v = vaddr(ctxt, p, a, &rel);
- break;
- case NAME_AUTO:
- case NAME_PARAM:
- base = REG_SP;
- break;
- }
-
- if(base == REG_NONE) {
- *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(ctxt, a->scale, a->index, base);
- goto putrelv;
- }
- if(v == 0 && rel.siz == 0 && base != REG_BP) {
- *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(ctxt, a->scale, a->index, base);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(ctxt, a->scale, a->index, base);
- *ctxt->andptr++ = v;
- return;
- }
- *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(ctxt, a->scale, a->index, base);
- goto putrelv;
- }
-
- base = a->reg;
- switch(a->name) {
- case NAME_STATIC:
- case NAME_EXTERN:
- base = REG_NONE;
- v = vaddr(ctxt, p, a, &rel);
- break;
- case NAME_AUTO:
- case NAME_PARAM:
- base = REG_SP;
- break;
- }
-
- if(base == REG_TLS)
- v = vaddr(ctxt, p, a, &rel);
-
- if(base == REG_NONE || (REG_CS <= base && base <= REG_GS) || base == REG_TLS) {
- *ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- goto putrelv;
- }
-
- if(base == REG_SP) {
- if(v == 0 && rel.siz == 0) {
- *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(ctxt, a->scale, REG_NONE, base);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(ctxt, a->scale, REG_NONE, base);
- *ctxt->andptr++ = v;
- return;
- }
- *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(ctxt, a->scale, REG_NONE, base);
- goto putrelv;
- }
-
- if(REG_AX <= base && base <= REG_DI) {
- if(a->index == REG_TLS) {
- memset(&rel, 0, sizeof rel);
- rel.type = R_TLS_IE;
- rel.siz = 4;
- rel.sym = nil;
- rel.add = v;
- v = 0;
- }
- if(v == 0 && rel.siz == 0 && base != REG_BP) {
- *ctxt->andptr++ = (0 << 6) | (reg[base] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- ctxt->andptr[0] = (1 << 6) | (reg[base] << 0) | (r << 3);
- ctxt->andptr[1] = v;
- ctxt->andptr += 2;
- return;
- }
- *ctxt->andptr++ = (2 << 6) | (reg[base] << 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;
- }
-
- put4(ctxt, v);
- return;
-
-bad:
- ctxt->diag("asmand: bad address %D", a);
- return;
-}
-
-enum
-{
- 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,
-
-/* load TLS base pointer */
- AMOVL, Ytls, Yrl, 8, 0,0,0,0,
-
- 0
-};
-
-// byteswapreg returns a byte-addressable register (AX, BX, CX, DX)
-// which is not referenced in a.
-// 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;
-
- if(a->type == TYPE_NONE)
- cana = cand = 0;
-
- if(a->type == TYPE_REG || ((a->type == TYPE_MEM || a->type == TYPE_ADDR) && a->name == NAME_NONE)) {
- switch(a->reg) {
- case REG_NONE:
- cana = cand = 0;
- break;
- case REG_AX:
- case REG_AL:
- case REG_AH:
- cana = 0;
- break;
- case REG_BX:
- case REG_BL:
- case REG_BH:
- canb = 0;
- break;
- case REG_CX:
- case REG_CL:
- case REG_CH:
- canc = 0;
- break;
- case REG_DX:
- case REG_DL:
- case REG_DH:
- cand = 0;
- break;
- }
- }
- if(a->type == TYPE_MEM || a->type == TYPE_ADDR) {
- switch(a->index) {
- case REG_AX:
- cana = 0;
- break;
- case REG_BX:
- canb = 0;
- break;
- case REG_CX:
- canc = 0;
- break;
- case REG_DX:
- cand = 0;
- break;
- }
- }
- if(cana)
- return REG_AX;
- if(canb)
- return REG_BX;
- if(canc)
- return REG_CX;
- if(cand)
- return REG_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.reg == from) {
- p->from.reg = to;
- p->ft = 0;
- }
- if(p->to.reg == from) {
- p->to.reg = 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;
- }
-
- 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->and[ctxt->andptr - ctxt->and - 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(ctxt, &p->from);
- if(pre)
- *ctxt->andptr++ = pre;
- pre = prefixof(ctxt, &p->to);
- if(pre)
- *ctxt->andptr++ = pre;
-
- if(p->ft == 0)
- p->ft = oclass(ctxt, p, &p->from);
- if(p->tt == 0)
- p->tt = oclass(ctxt, p, &p->to);
-
- ft = p->ft * Ymax;
- tt = p->tt * Ymax;
- o = opindex[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, &p->from, reg[p->to.reg]);
- break;
-
- case Zm_r:
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->from, reg[p->to.reg]);
- break;
-
- case Zm2_r:
- *ctxt->andptr++ = op;
- *ctxt->andptr++ = o->op[z+1];
- asmand(ctxt, p, &p->from, reg[p->to.reg]);
- break;
-
- case Zm_r_xm:
- mediaop(ctxt, o, op, t[3], z);
- asmand(ctxt, p, &p->from, reg[p->to.reg]);
- break;
-
- case Zm_r_i_xm:
- mediaop(ctxt, o, op, t[3], z);
- asmand(ctxt, p, &p->from, reg[p->to.reg]);
- *ctxt->andptr++ = p->to.offset;
- break;
-
- case Zibm_r:
- while ((op = o->op[z++]) != 0)
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->from, reg[p->to.reg]);
- *ctxt->andptr++ = p->to.offset;
- break;
-
- case Zaut_r:
- *ctxt->andptr++ = 0x8d; /* leal */
- if(p->from.type != TYPE_ADDR)
- ctxt->diag("asmins: Zaut sb type ADDR");
- p->from.type = TYPE_MEM;
- p->ft = 0;
- asmand(ctxt, p, &p->from, reg[p->to.reg]);
- p->from.type = TYPE_ADDR;
- p->ft = 0;
- break;
-
- case Zm_o:
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->from, o->op[z+1]);
- break;
-
- case Zr_m:
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->to, reg[p->from.reg]);
- break;
-
- case Zr_m_xm:
- mediaop(ctxt, o, op, t[3], z);
- asmand(ctxt, p, &p->to, reg[p->from.reg]);
- break;
-
- case Zr_m_i_xm:
- mediaop(ctxt, o, op, t[3], z);
- asmand(ctxt, p, &p->to, reg[p->from.reg]);
- *ctxt->andptr++ = p->from.offset;
- break;
-
- case Zcallindreg:
- r = addrel(ctxt->cursym);
- r->off = p->pc;
- r->type = R_CALLIND;
- r->siz = 0;
- // fallthrough
- case Zo_m:
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->to, o->op[z+1]);
- break;
-
- case Zm_ibo:
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->from, o->op[z+1]);
- *ctxt->andptr++ = vaddr(ctxt, p, &p->to, nil);
- break;
-
- case Zibo_m:
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->to, o->op[z+1]);
- *ctxt->andptr++ = vaddr(ctxt, p, &p->from, nil);
- break;
-
- case Z_ib:
- case Zib_:
- if(t[2] == Zib_)
- a = &p->from;
- else
- a = &p->to;
- v = vaddr(ctxt, p, a, nil);
- *ctxt->andptr++ = op;
- *ctxt->andptr++ = v;
- break;
-
- case Zib_rp:
- *ctxt->andptr++ = op + reg[p->to.reg];
- *ctxt->andptr++ = vaddr(ctxt, p, &p->from, nil);
- break;
-
- case Zil_rp:
- *ctxt->andptr++ = op + reg[p->to.reg];
- if(o->prefix == Pe) {
- v = vaddr(ctxt, p, &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, &p->to, reg[p->to.reg]);
- *ctxt->andptr++ = vaddr(ctxt, p, &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, p, 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, &p->to, o->op[z+1]);
- } else {
- a = &p->to;
- asmand(ctxt, p, &p->from, o->op[z+1]);
- }
- if(o->prefix == Pe) {
- v = vaddr(ctxt, p, a, nil);
- *ctxt->andptr++ = v;
- *ctxt->andptr++ = v>>8;
- }
- else
- relput4(ctxt, p, a);
- break;
-
- case Zil_rr:
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->to, reg[p->to.reg]);
- if(o->prefix == Pe) {
- v = vaddr(ctxt, p, &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.reg];
- break;
-
- case Zrp_:
- *ctxt->andptr++ = op + reg[p->from.reg];
- break;
-
- case Zclr:
- *ctxt->andptr++ = op;
- asmand(ctxt, p, &p->to, reg[p->to.reg]);
- 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 = R_CALL;
- r->siz = 4;
- r->sym = p->to.sym;
- r->add = p->to.offset;
- 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 = R_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 = R_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 = R_ADDR;
- r->siz = 4;
- r->add = p->to.offset;
- r->sym = p->to.sym;
- put4(ctxt, 0);
- break;
-
- case Zbyte:
- v = vaddr(ctxt, p, &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.reg;
- if(p->from.type == TYPE_REG && z >= REG_BP && z <= REG_DI) {
- if((breg = byteswapreg(ctxt, &p->to)) != REG_AX) {
- *ctxt->andptr++ = 0x87; /* xchg lhs,bx */
- asmand(ctxt, p, &p->from, reg[breg]);
- subreg(&pp, z, breg);
- doasm(ctxt, &pp);
- *ctxt->andptr++ = 0x87; /* xchg lhs,bx */
- asmand(ctxt, p, &p->from, reg[breg]);
- } else {
- *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- subreg(&pp, z, REG_AX);
- doasm(ctxt, &pp);
- *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- }
- return;
- }
- z = p->to.reg;
- if(p->to.type == TYPE_REG && z >= REG_BP && z <= REG_DI) {
- if((breg = byteswapreg(ctxt, &p->from)) != REG_AX) {
- *ctxt->andptr++ = 0x87; /* xchg rhs,bx */
- asmand(ctxt, p, &p->to, reg[breg]);
- subreg(&pp, z, breg);
- doasm(ctxt, &pp);
- *ctxt->andptr++ = 0x87; /* xchg rhs,bx */
- asmand(ctxt, p, &p->to, reg[breg]);
- } else {
- *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- subreg(&pp, z, REG_AX);
- doasm(ctxt, &pp);
- *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- }
- return;
- }
- ctxt->diag("doasm: notfound t2=%d from=%d to=%d %P", t[2], p->ft, p->tt, 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, &p->to, t[5]);
- break;
-
- case 2: /* m,r */
- *ctxt->andptr++ = t[4];
- asmand(ctxt, p, &p->from, t[5]);
- break;
-
- case 3: /* r,m - 2op */
- *ctxt->andptr++ = t[4];
- *ctxt->andptr++ = t[5];
- asmand(ctxt, p, &p->to, t[6]);
- break;
-
- case 4: /* m,r - 2op */
- *ctxt->andptr++ = t[4];
- *ctxt->andptr++ = t[5];
- asmand(ctxt, p, &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 REG_DS:
- *ctxt->andptr++ = 0xc5;
- break;
- case REG_SS:
- *ctxt->andptr++ = 0x0f;
- *ctxt->andptr++ = 0xb2;
- break;
- case REG_ES:
- *ctxt->andptr++ = 0xc4;
- break;
- case REG_FS:
- *ctxt->andptr++ = 0x0f;
- *ctxt->andptr++ = 0xb4;
- break;
- case REG_GS:
- *ctxt->andptr++ = 0x0f;
- *ctxt->andptr++ = 0xb5;
- break;
- }
- asmand(ctxt, p, &p->from, reg[p->to.reg]);
- break;
-
- case 6: /* double shift */
- switch(p->from.type) {
- default:
- goto bad;
-
- case TYPE_CONST:
- *ctxt->andptr++ = 0x0f;
- *ctxt->andptr++ = t[4];
- asmand(ctxt, p, &p->to, reg[p->from.index]);
- *ctxt->andptr++ = p->from.offset;
- break;
-
- case TYPE_REG:
- switch(p->from.reg) {
- default:
- goto bad;
- case REG_CL:
- case REG_CX:
- *ctxt->andptr++ = 0x0f;
- *ctxt->andptr++ = t[5];
- asmand(ctxt, p, &p->to, reg[p->from.index]);
- break;
- }
- 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, &p->from, reg[p->to.reg]);
- break;
-
- case 8: /* mov tls, r */
- // NOTE: The systems listed here are the ones that use the "TLS initial exec" model,
- // where you load the TLS base register into a register and then index off that
- // register to access the actual TLS variables. Systems that allow direct TLS access
- // are handled in prefixof above and should not be listed here.
- switch(ctxt->headtype) {
- default:
- sysfatal("unknown TLS base location for %s", headstr(ctxt->headtype));
-
- case Hlinux:
- case Hnacl:
- // ELF TLS base is 0(GS).
- pp.from = p->from;
- pp.from.type = TYPE_MEM;
- pp.from.reg = REG_GS;
- pp.from.offset = 0;
- pp.from.index = REG_NONE;
- pp.from.scale = 0;
- *ctxt->andptr++ = 0x65; // GS
- *ctxt->andptr++ = 0x8B;
- asmand(ctxt, p, &pp.from, reg[p->to.reg]);
- break;
-
- case Hplan9:
- if(ctxt->plan9privates == nil)
- ctxt->plan9privates = linklookup(ctxt, "_privates", 0);
- memset(&pp.from, 0, sizeof pp.from);
- pp.from.type = TYPE_MEM;
- pp.from.name = NAME_EXTERN;
- pp.from.sym = ctxt->plan9privates;
- pp.from.offset = 0;
- pp.from.index = REG_NONE;
- *ctxt->andptr++ = 0x8B;
- asmand(ctxt, p, &pp.from, reg[p->to.reg]);
- break;
-
- case Hwindows:
- // Windows TLS base is always 0x14(FS).
- pp.from = p->from;
- pp.from.type = TYPE_MEM;
- pp.from.reg = REG_FS;
- pp.from.offset = 0x14;
- pp.from.index = REG_NONE;
- pp.from.scale = 0;
- *ctxt->andptr++ = 0x64; // FS
- *ctxt->andptr++ = 0x8B;
- asmand(ctxt, p, &pp.from, reg[p->to.reg]);
- break;
- }
- break;
- }
-}
-
-static uchar naclret[] = {
- 0x5d, // POPL BP
- // 0x8b, 0x7d, 0x00, // MOVL (BP), DI - catch return to invalid address, for debugging
- 0x83, 0xe5, 0xe0, // ANDL $~31, BP
- 0xff, 0xe5, // JMP BP
-};
-
-static void
-asmins(Link *ctxt, Prog *p)
-{
- Reloc *r;
-
- ctxt->andptr = ctxt->and;
-
- if(p->as == AUSEFIELD) {
- r = addrel(ctxt->cursym);
- r->off = 0;
- r->sym = p->from.sym;
- r->type = R_USEFIELD;
- r->siz = 0;
- return;
- }
-
- if(ctxt->headtype == Hnacl) {
- switch(p->as) {
- case ARET:
- memmove(ctxt->andptr, naclret, sizeof naclret);
- ctxt->andptr += sizeof naclret;
- return;
- case ACALL:
- case AJMP:
- if(p->to.type == TYPE_REG && REG_AX <= p->to.reg && p->to.reg <= REG_DI) {
- *ctxt->andptr++ = 0x83;
- *ctxt->andptr++ = 0xe0 | (p->to.reg - REG_AX);
- *ctxt->andptr++ = 0xe0;
- }
- break;
- case AINT:
- *ctxt->andptr++ = 0xf4;
- return;
- }
- }
-
- 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");
- }
-}
+++ /dev/null
-// cmd/9l/optab.c, cmd/9l/asmout.c from Vita Nuova.
-//
-// 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-2008 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-2008 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/9l/9.out.h"
-#include "../runtime/stack.h"
-
-enum {
- FuncAlign = 8,
-};
-
-enum {
- r0iszero = 1,
-};
-
-typedef struct Optab Optab;
-
-struct Optab
-{
- short as;
- uchar a1;
- uchar a2;
- uchar a3;
- uchar a4;
- char type;
- char size;
- char param;
-};
-
-static Optab optab[] = {
- { ATEXT, C_LEXT, C_NONE, C_NONE, C_TEXTSIZE, 0, 0, 0 },
- { ATEXT, C_LEXT, C_NONE, C_LCON, C_TEXTSIZE, 0, 0, 0 },
- { ATEXT, C_ADDR, C_NONE, C_NONE, C_TEXTSIZE, 0, 0, 0 },
- { ATEXT, C_ADDR, C_NONE, C_LCON, C_TEXTSIZE, 0, 0, 0 },
-
- /* move register */
- { AMOVD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0 },
- { AMOVB, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0 },
- { AMOVBZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0 },
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0 },
-
- { AADD, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 },
- { AADD, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
- { AADD, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
- { AADD, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 },
- { AADD, C_UCON, C_REG, C_NONE, C_REG, 20, 4, 0 },
- { AADD, C_UCON, C_NONE, C_NONE, C_REG, 20, 4, 0 },
- { AADD, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0 },
- { AADD, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0 },
-
- { AADDC, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 },
- { AADDC, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
- { AADDC, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
- { AADDC, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 },
- { AADDC, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0 },
- { AADDC, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0 },
-
- { AAND, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, /* logical, no literal */
- { AAND, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
- { AANDCC, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
- { AANDCC, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
-
- { AANDCC, C_ANDCON,C_NONE, C_NONE, C_REG, 58, 4, 0 },
- { AANDCC, C_ANDCON,C_REG, C_NONE, C_REG, 58, 4, 0 },
- { AANDCC, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0 },
- { AANDCC, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0 },
- { AANDCC, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0 },
- { AANDCC, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0 },
-
- { AMULLW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 },
- { AMULLW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
- { AMULLW, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
- { AMULLW, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 },
- { AMULLW, C_ANDCON,C_REG, C_NONE, C_REG, 4, 4, 0 },
- { AMULLW, C_ANDCON, C_NONE, C_NONE, C_REG, 4, 4, 0 },
- { AMULLW, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0},
- { AMULLW, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0},
-
- { ASUBC, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0 },
- { ASUBC, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0 },
- { ASUBC, C_REG, C_NONE, C_ADDCON, C_REG, 27, 4, 0 },
- { ASUBC, C_REG, C_NONE, C_LCON, C_REG, 28, 12, 0},
-
- { AOR, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, /* logical, literal not cc (or/xor) */
- { AOR, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
- { AOR, C_ANDCON, C_NONE, C_NONE, C_REG, 58, 4, 0 },
- { AOR, C_ANDCON, C_REG, C_NONE, C_REG, 58, 4, 0 },
- { AOR, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0 },
- { AOR, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0 },
- { AOR, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0 },
- { AOR, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0 },
-
- { ADIVW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 }, /* op r1[,r2],r3 */
- { ADIVW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 },
- { ASUB, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0 }, /* op r2[,r1],r3 */
- { ASUB, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0 },
-
- { ASLW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
- { ASLW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
- { ASLD, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
- { ASLD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
- { ASLD, C_SCON, C_REG, C_NONE, C_REG, 25, 4, 0 },
- { ASLD, C_SCON, C_NONE, C_NONE, C_REG, 25, 4, 0 },
- { ASLW, C_SCON, C_REG, C_NONE, C_REG, 57, 4, 0 },
- { ASLW, C_SCON, C_NONE, C_NONE, C_REG, 57, 4, 0 },
-
- { ASRAW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
- { ASRAW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
- { ASRAW, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0 },
- { ASRAW, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0 },
- { ASRAD, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 },
- { ASRAD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 },
- { ASRAD, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0 },
- { ASRAD, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0 },
-
- { ARLWMI, C_SCON, C_REG, C_LCON, C_REG, 62, 4, 0 },
- { ARLWMI, C_REG, C_REG, C_LCON, C_REG, 63, 4, 0 },
- { ARLDMI, C_SCON, C_REG, C_LCON, C_REG, 30, 4, 0 },
-
- { ARLDC, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0 },
- { ARLDCL, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0 },
- { ARLDCL, C_REG, C_REG, C_LCON, C_REG, 14, 4, 0 },
- { ARLDCL, C_REG, C_NONE, C_LCON, C_REG, 14, 4, 0 },
-
- { AFADD, C_FREG, C_NONE, C_NONE, C_FREG, 2, 4, 0 },
- { AFADD, C_FREG, C_REG, C_NONE, C_FREG, 2, 4, 0 },
- { AFABS, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0 },
- { AFABS, C_NONE, C_NONE, C_NONE, C_FREG, 33, 4, 0 },
- { AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0 },
-
- { AFMADD, C_FREG, C_REG, C_FREG, C_FREG, 34, 4, 0 },
- { AFMUL, C_FREG, C_NONE, C_NONE, C_FREG, 32, 4, 0 },
- { AFMUL, C_FREG, C_REG, C_NONE, C_FREG, 32, 4, 0 },
-
- /* store, short offset */
- { AMOVD, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
- { AMOVW, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
- { AMOVWZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
- { AMOVBZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
- { AMOVBZU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
- { AMOVB, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
- { AMOVBU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO },
- { AMOVD, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
- { AMOVW, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
- { AMOVBZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
- { AMOVB, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
- { AMOVD, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
- { AMOVW, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
- { AMOVBZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
- { AMOVB, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
- { AMOVD, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
- { AMOVW, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
- { AMOVBZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
- { AMOVBZU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
- { AMOVB, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
- { AMOVBU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
-
- /* load, short offset */
- { AMOVD, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
- { AMOVW, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
- { AMOVWZ, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
- { AMOVBZ, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
- { AMOVBZU, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO },
- { AMOVB, C_ZOREG,C_REG, C_NONE, C_REG, 9, 8, REGZERO },
- { AMOVBU, C_ZOREG,C_REG, C_NONE, C_REG, 9, 8, REGZERO },
- { AMOVD, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
- { AMOVW, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
- { AMOVWZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
- { AMOVBZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB },
- { AMOVB, C_SEXT, C_NONE, C_NONE, C_REG, 9, 8, REGSB },
- { AMOVD, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
- { AMOVW, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
- { AMOVWZ, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
- { AMOVBZ, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP },
- { AMOVB, C_SAUTO,C_NONE, C_NONE, C_REG, 9, 8, REGSP },
- { AMOVD, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
- { AMOVW, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
- { AMOVWZ, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
- { AMOVBZ, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
- { AMOVBZU, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO },
- { AMOVB, C_SOREG,C_NONE, C_NONE, C_REG, 9, 8, REGZERO },
- { AMOVBU, C_SOREG,C_NONE, C_NONE, C_REG, 9, 8, REGZERO },
-
- /* store, long offset */
- { AMOVD, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
- { AMOVW, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
- { AMOVBZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
- { AMOVB, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
- { AMOVD, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
- { AMOVW, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
- { AMOVBZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
- { AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
- { AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
- { AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
- { AMOVBZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
- { AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
- { AMOVD, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
- { AMOVW, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
- { AMOVBZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
- { AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
-
- /* load, long offset */
- { AMOVD, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
- { AMOVW, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
- { AMOVWZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
- { AMOVBZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB },
- { AMOVB, C_LEXT, C_NONE, C_NONE, C_REG, 37, 12, REGSB },
- { AMOVD, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
- { AMOVW, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
- { AMOVWZ, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
- { AMOVBZ, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP },
- { AMOVB, C_LAUTO,C_NONE, C_NONE, C_REG, 37, 12, REGSP },
- { AMOVD, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
- { AMOVW, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
- { AMOVWZ, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
- { AMOVBZ, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO },
- { AMOVB, C_LOREG,C_NONE, C_NONE, C_REG, 37, 12, REGZERO },
- { AMOVD, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
- { AMOVW, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
- { AMOVWZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
- { AMOVBZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 },
- { AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 76, 12, 0 },
-
- /* load constant */
- { AMOVD, C_SECON,C_NONE, C_NONE, C_REG, 3, 4, REGSB },
- { AMOVD, C_SACON,C_NONE, C_NONE, C_REG, 3, 4, REGSP },
- { AMOVD, C_LECON,C_NONE, C_NONE, C_REG, 26, 8, REGSB },
- { AMOVD, C_LACON,C_NONE, C_NONE, C_REG, 26, 8, REGSP },
- { AMOVD, C_ADDCON,C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
- { AMOVW, C_SECON,C_NONE, C_NONE, C_REG, 3, 4, REGSB }, /* TO DO: check */
- { AMOVW, C_SACON,C_NONE, C_NONE, C_REG, 3, 4, REGSP },
- { AMOVW, C_LECON,C_NONE, C_NONE, C_REG, 26, 8, REGSB },
- { AMOVW, C_LACON,C_NONE, C_NONE, C_REG, 26, 8, REGSP },
- { AMOVW, C_ADDCON,C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
- { AMOVWZ, C_SECON,C_NONE, C_NONE, C_REG, 3, 4, REGSB }, /* TO DO: check */
- { AMOVWZ, C_SACON,C_NONE, C_NONE, C_REG, 3, 4, REGSP },
- { AMOVWZ, C_LECON,C_NONE, C_NONE, C_REG, 26, 8, REGSB },
- { AMOVWZ, C_LACON,C_NONE, C_NONE, C_REG, 26, 8, REGSP },
- { AMOVWZ, C_ADDCON,C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
-
- /* load unsigned/long constants (TO DO: check) */
- { AMOVD, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
- { AMOVD, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0 },
- { AMOVW, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
- { AMOVW, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0 },
- { AMOVWZ, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO },
- { AMOVWZ, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0 },
-
- { AMOVHBR, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0 },
- { AMOVHBR, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 },
- { AMOVHBR, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0 },
- { AMOVHBR, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 },
-
- { ASYSCALL, C_NONE, C_NONE, C_NONE, C_NONE, 5, 4, 0 },
- { ASYSCALL, C_REG, C_NONE, C_NONE, C_NONE, 77, 12, 0 },
- { ASYSCALL, C_SCON, C_NONE, C_NONE, C_NONE, 77, 12, 0 },
-
- { ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 16, 4, 0 },
- { ABEQ, C_CREG, C_NONE, C_NONE, C_SBRA, 16, 4, 0 },
-
- { ABR, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0 },
-
- { ABC, C_SCON, C_REG, C_NONE, C_SBRA, 16, 4, 0 },
- { ABC, C_SCON, C_REG, C_NONE, C_LBRA, 17, 4, 0 },
-
- { ABR, C_NONE, C_NONE, C_NONE, C_LR, 18, 4, 0 },
- { ABR, C_NONE, C_NONE, C_NONE, C_CTR, 18, 4, 0 },
- { ABR, C_REG, C_NONE, C_NONE, C_CTR, 18, 4, 0 },
- { ABR, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0 },
-
- { ABC, C_NONE, C_REG, C_NONE, C_LR, 18, 4, 0 },
- { ABC, C_NONE, C_REG, C_NONE, C_CTR, 18, 4, 0 },
- { ABC, C_SCON, C_REG, C_NONE, C_LR, 18, 4, 0 },
- { ABC, C_SCON, C_REG, C_NONE, C_CTR, 18, 4, 0 },
- { ABC, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0 },
-
- { AFMOVD, C_SEXT, C_NONE, C_NONE, C_FREG, 8, 4, REGSB },
- { AFMOVD, C_SAUTO,C_NONE, C_NONE, C_FREG, 8, 4, REGSP },
- { AFMOVD, C_SOREG,C_NONE, C_NONE, C_FREG, 8, 4, REGZERO },
-
- { AFMOVD, C_LEXT, C_NONE, C_NONE, C_FREG, 36, 8, REGSB },
- { AFMOVD, C_LAUTO,C_NONE, C_NONE, C_FREG, 36, 8, REGSP },
- { AFMOVD, C_LOREG,C_NONE, C_NONE, C_FREG, 36, 8, REGZERO },
- { AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 75, 8, 0 },
-
- { AFMOVD, C_FREG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB },
- { AFMOVD, C_FREG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP },
- { AFMOVD, C_FREG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO },
-
- { AFMOVD, C_FREG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB },
- { AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP },
- { AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO },
- { AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 },
-
- { ASYNC, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0 },
- { AWORD, C_LCON, C_NONE, C_NONE, C_NONE, 40, 4, 0 },
- { ADWORD, C_LCON, C_NONE, C_NONE, C_NONE, 31, 8, 0 },
- { ADWORD, C_DCON, C_NONE, C_NONE, C_NONE, 31, 8, 0 },
-
- { AADDME, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0 },
-
- { AEXTSB, C_REG, C_NONE, C_NONE, C_REG, 48, 4, 0 },
- { AEXTSB, C_NONE, C_NONE, C_NONE, C_REG, 48, 4, 0 },
-
- { ANEG, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0 },
- { ANEG, C_NONE, C_NONE, C_NONE, C_REG, 47, 4, 0 },
-
- { AREM, C_REG, C_NONE, C_NONE, C_REG, 50, 12, 0 },
- { AREM, C_REG, C_REG, C_NONE, C_REG, 50, 12, 0 },
- { AREMU, C_REG, C_NONE, C_NONE, C_REG, 50, 16, 0 },
- { AREMU, C_REG, C_REG, C_NONE, C_REG, 50, 16, 0 },
- { AREMD, C_REG, C_NONE, C_NONE, C_REG, 51, 12, 0 },
- { AREMD, C_REG, C_REG, C_NONE, C_REG, 51, 12, 0 },
- { AREMDU, C_REG, C_NONE, C_NONE, C_REG, 51, 12, 0 },
- { AREMDU, C_REG, C_REG, C_NONE, C_REG, 51, 12, 0 },
-
- { AMTFSB0, C_SCON, C_NONE, C_NONE, C_NONE, 52, 4, 0 },
- { AMOVFL, C_FPSCR, C_NONE, C_NONE, C_FREG, 53, 4, 0 },
- { AMOVFL, C_FREG, C_NONE, C_NONE, C_FPSCR, 64, 4, 0 },
- { AMOVFL, C_FREG, C_NONE, C_LCON, C_FPSCR, 64, 4, 0 },
- { AMOVFL, C_LCON, C_NONE, C_NONE, C_FPSCR, 65, 4, 0 },
-
- { AMOVD, C_MSR, C_NONE, C_NONE, C_REG, 54, 4, 0 }, /* mfmsr */
- { AMOVD, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0 }, /* mtmsrd */
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0 }, /* mtmsr */
-
- /* 64-bit special registers */
- { AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0 },
- { AMOVD, C_REG, C_NONE, C_NONE, C_LR, 66, 4, 0 },
- { AMOVD, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0 },
- { AMOVD, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0 },
- { AMOVD, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
- { AMOVD, C_LR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
- { AMOVD, C_CTR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
- { AMOVD, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0 },
-
- /* 32-bit special registers (gloss over sign-extension or not?) */
- { AMOVW, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0 },
- { AMOVW, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
- { AMOVW, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0 },
-
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0 },
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0 },
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0 },
- { AMOVWZ, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0 },
- { AMOVWZ, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0 },
-
- { AMOVFL, C_FPSCR, C_NONE, C_NONE, C_CREG, 73, 4, 0 },
- { AMOVFL, C_CREG, C_NONE, C_NONE, C_CREG, 67, 4, 0 },
- { AMOVW, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0 },
- { AMOVWZ, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0 },
- { AMOVFL, C_REG, C_NONE, C_LCON, C_CREG, 69, 4, 0 },
- { AMOVFL, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 },
- { AMOVWZ, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 },
-
- { ACMP, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0 },
- { ACMP, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0 },
- { ACMP, C_REG, C_NONE, C_NONE, C_ADDCON, 71, 4, 0 },
- { ACMP, C_REG, C_REG, C_NONE, C_ADDCON, 71, 4, 0 },
-
- { ACMPU, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0 },
- { ACMPU, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0 },
- { ACMPU, C_REG, C_NONE, C_NONE, C_ANDCON, 71, 4, 0 },
- { ACMPU, C_REG, C_REG, C_NONE, C_ANDCON, 71, 4, 0 },
-
- { AFCMPO, C_FREG, C_NONE, C_NONE, C_FREG, 70, 4, 0 },
- { AFCMPO, C_FREG, C_REG, C_NONE, C_FREG, 70, 4, 0 },
-
- { ATW, C_LCON, C_REG, C_NONE, C_REG, 60, 4, 0 },
- { ATW, C_LCON, C_REG, C_NONE, C_ADDCON, 61, 4, 0 },
-
- { ADCBF, C_ZOREG, C_NONE, C_NONE, C_NONE, 43, 4, 0 },
- { ADCBF, C_ZOREG, C_REG, C_NONE, C_NONE, 43, 4, 0 },
-
- { AECOWX, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0 },
- { AECIWX, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0 },
- { AECOWX, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 },
- { AECIWX, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 },
-
- { AEIEIO, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0 },
- { ATLBIE, C_REG, C_NONE, C_NONE, C_NONE, 49, 4, 0 },
- { ATLBIE, C_SCON, C_NONE, C_NONE, C_REG, 49, 4, 0 },
- { ASLBMFEE, C_REG, C_NONE, C_NONE, C_REG, 55, 4, 0 },
- { ASLBMTE, C_REG, C_NONE, C_NONE, C_REG, 55, 4, 0 },
-
- { ASTSW, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 },
- { ASTSW, C_REG, C_NONE, C_LCON, C_ZOREG, 41, 4, 0 },
- { ALSW, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 },
- { ALSW, C_ZOREG, C_NONE, C_LCON, C_REG, 42, 4, 0 },
-
- { AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 78, 4, 0 },
- { AUSEFIELD, C_ADDR, C_NONE, C_NONE, C_NONE, 0, 0, 0 },
- { APCDATA, C_LCON, C_NONE, C_NONE, C_LCON, 0, 0, 0 },
- { AFUNCDATA, C_SCON, C_NONE, C_NONE, C_ADDR, 0, 0, 0 },
- { ANOP, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0 },
-
- { ADUFFZERO, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0 }, // same as ABR/ABL
- { ADUFFCOPY, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0 }, // same as ABR/ABL
-
- { AXXX, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
-};
-
-static int ocmp(const void *, const void *);
-static int cmp(int, int);
-static void buildop(Link*);
-static void prasm(Prog *);
-static int isint32(vlong);
-static int isuint32(uvlong);
-static int aclass(Link*, Addr*);
-static Optab* oplook(Link*, Prog*);
-static void asmout(Link*, Prog*, Optab*, uint32*);
-static vlong vregoff(Link*, Addr*);
-static int32 regoff(Link*, Addr*);
-static int32 oprrr(Link*, int);
-static int32 opirr(Link*, int);
-static int32 opload(Link*, int);
-static int32 opstore(Link*, int);
-static int32 oploadx(Link*, int);
-static int32 opstorex(Link*, int);
-static int getmask(uchar*, uint32);
-static void maskgen(Link*, Prog*, uchar*, uint32);
-static int getmask64(uchar*, uvlong);
-static void maskgen64(Link*, Prog*, uchar*, uvlong);
-static uint32 loadu32(int, vlong);
-static void addaddrreloc(Link*, LSym*, uint32*, uint32*);
-
-typedef struct Oprang Oprang;
-struct Oprang
-{
- Optab* start;
- Optab* stop;
-};
-
-static Oprang oprange[ALAST];
-
-static uchar xcmp[C_NCLASS][C_NCLASS];
-
-
-void
-span9(Link *ctxt, LSym *cursym)
-{
- Prog *p, *q;
- Optab *o;
- int m, bflag;
- vlong c, otxt;
- uint32 out[6];
- int32 i, j;
- uchar *bp, *cast;
-
- p = cursym->text;
- if(p == nil || p->link == nil) // handle external functions and ELF section symbols
- return;
- ctxt->cursym = cursym;
- ctxt->autosize = p->to.offset + 8;
-
- if(oprange[AANDN].start == nil)
- buildop(ctxt);
-
- c = 0;
- p->pc = c;
-
- for(p = p->link; p != nil; p = p->link) {
- ctxt->curp = p;
- p->pc = c;
- o = oplook(ctxt, p);
- m = o->size;
- if(m == 0) {
- if(p->as != ANOP && p->as != AFUNCDATA && p->as != APCDATA)
- ctxt->diag("zero-width instruction\n%P", p);
- continue;
- }
- c += m;
- }
- 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.
- */
- bflag = 1;
- while(bflag) {
- if(ctxt->debugvlog)
- Bprint(ctxt->bso, "%5.2f span1\n", cputime());
- bflag = 0;
- c = 0;
- for(p = cursym->text->link; p != nil; p = p->link) {
- p->pc = c;
- o = oplook(ctxt, p);
-
- // very large conditional branches
- if((o->type == 16 || o->type == 17) && p->pcond) {
- otxt = p->pcond->pc - c;
- if(otxt < -(1L<<15)+10 || otxt >= (1L<<15)-10) {
- q = emallocz(sizeof(Prog));
- q->link = p->link;
- p->link = q;
- q->as = ABR;
- q->to.type = TYPE_BRANCH;
- q->pcond = p->pcond;
- p->pcond = q;
- q = emallocz(sizeof(Prog));
- q->link = p->link;
- p->link = q;
- q->as = ABR;
- q->to.type = TYPE_BRANCH;
- q->pcond = q->link->link;
- //addnop(p->link);
- //addnop(p);
- bflag = 1;
- }
- }
-
- m = o->size;
- if(m == 0) {
- if(p->as != ANOP && p->as != AFUNCDATA && p->as != APCDATA)
- ctxt->diag("zero-width instruction\n%P", p);
- continue;
- }
- c += m;
- }
- cursym->size = c;
- }
-
- c += -c&(FuncAlign-1);
- cursym->size = c;
-
- /*
- * lay out the code, emitting code and data relocations.
- */
- if(ctxt->tlsg == nil)
- ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
-
- symgrow(ctxt, cursym, cursym->size);
-
- bp = cursym->p;
- for(p = cursym->text->link; p != nil; p = p->link) {
- ctxt->pc = p->pc;
- ctxt->curp = p;
- o = oplook(ctxt, p);
- if(o->size > 4*nelem(out))
- sysfatal("out array in span9 is too small, need at least %d for %P", o->size/4, p);
- asmout(ctxt, p, o, out);
- for(i=0; i<o->size/4; i++) {
- cast = (uchar*)&out[i];
- for(j=0; j<4; j++)
- *bp++ = cast[inuxi4[j]];
- }
- }
-}
-
-static int
-isint32(vlong v)
-{
- return (int32)v == v;
-}
-
-static int
-isuint32(uvlong v)
-{
- return (uint32)v == v;
-}
-
-static int
-aclass(Link *ctxt, Addr *a)
-{
- LSym *s;
-
- switch(a->type) {
- case TYPE_NONE:
- return C_NONE;
-
- case TYPE_REG:
- if(REG_R0 <= a->reg && a->reg <= REG_R31)
- return C_REG;
- if(REG_F0 <= a->reg && a->reg <= REG_F31)
- return C_FREG;
- if(REG_C0 <= a->reg && a->reg <= REG_C7 || a->reg == REG_CR)
- return C_CREG;
- if(REG_SPR0 <= a->reg && a->reg <= REG_SPR0+1023) {
- switch(a->reg) {
- case REG_LR:
- return C_LR;
- case REG_XER:
- return C_XER;
- case REG_CTR:
- return C_CTR;
- }
- return C_SPR;
- }
- if(REG_DCR0 <= a->reg && a->reg <= REG_DCR0+1023)
- return C_SPR;
- if(a->reg == REG_FPSCR)
- return C_FPSCR;
- if(a->reg == REG_MSR)
- return C_MSR;
- return C_GOK;
-
- case TYPE_MEM:
- switch(a->name) {
- case NAME_EXTERN:
- case NAME_STATIC:
- if(a->sym == nil)
- break;
- ctxt->instoffset = a->offset;
- if(a->sym != nil) // use relocation
- return C_ADDR;
- return C_LEXT;
- case NAME_AUTO:
- ctxt->instoffset = ctxt->autosize + a->offset;
- if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
- return C_SAUTO;
- return C_LAUTO;
- case NAME_PARAM:
- ctxt->instoffset = ctxt->autosize + a->offset + 8L;
- if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
- return C_SAUTO;
- return C_LAUTO;
- case TYPE_NONE:
- ctxt->instoffset = a->offset;
- if(ctxt->instoffset == 0)
- return C_ZOREG;
- if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
- return C_SOREG;
- return C_LOREG;
- }
- return C_GOK;
-
- case TYPE_TEXTSIZE:
- return C_TEXTSIZE;
-
- case TYPE_CONST:
- case TYPE_ADDR:
- switch(a->name) {
- case TYPE_NONE:
- ctxt->instoffset = a->offset;
- if(a->reg != 0) {
- if(-BIG <= ctxt->instoffset && ctxt->instoffset <= BIG)
- return C_SACON;
- if(isint32(ctxt->instoffset))
- return C_LACON;
- return C_DACON;
- }
- goto consize;
-
- case NAME_EXTERN:
- case NAME_STATIC:
- s = a->sym;
- if(s == nil)
- break;
- if(s->type == SCONST) {
- ctxt->instoffset = s->value + a->offset;
- goto consize;
- }
- ctxt->instoffset = s->value + a->offset;
- /* not sure why this barfs */
- return C_LCON;
-
- case NAME_AUTO:
- ctxt->instoffset = ctxt->autosize + a->offset;
- if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
- return C_SACON;
- return C_LACON;
-
- case NAME_PARAM:
- ctxt->instoffset = ctxt->autosize + a->offset + 8L;
- if(ctxt->instoffset >= -BIG && ctxt->instoffset < BIG)
- return C_SACON;
- return C_LACON;
- }
- return C_GOK;
-
- consize:
- if(ctxt->instoffset >= 0) {
- if(ctxt->instoffset == 0)
- return C_ZCON;
- if(ctxt->instoffset <= 0x7fff)
- return C_SCON;
- if(ctxt->instoffset <= 0xffff)
- return C_ANDCON;
- if((ctxt->instoffset & 0xffff) == 0 && isuint32(ctxt->instoffset)) /* && (instoffset & (1<<31)) == 0) */
- return C_UCON;
- if(isint32(ctxt->instoffset) || isuint32(ctxt->instoffset))
- return C_LCON;
- return C_DCON;
- }
- if(ctxt->instoffset >= -0x8000)
- return C_ADDCON;
- if((ctxt->instoffset & 0xffff) == 0 && isint32(ctxt->instoffset))
- return C_UCON;
- if(isint32(ctxt->instoffset))
- return C_LCON;
- return C_DCON;
-
- case TYPE_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, a4, r;
- uchar *c1, *c3, *c4;
- 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->from3.class;
- if(a3 == 0) {
- a3 = aclass(ctxt, &p->from3) + 1;
- p->from3.class = a3;
- }
- a3--;
- a4 = p->to.class;
- if(a4 == 0) {
- a4 = aclass(ctxt, &p->to) + 1;
- p->to.class = a4;
- }
- a4--;
- a2 = C_NONE;
- if(p->reg != 0)
- a2 = C_REG;
-//print("oplook %P %d %d %d %d\n", p, a1, a2, a3, a4);
- r = p->as;
- o = oprange[r].start;
- if(o == 0)
- o = oprange[r].stop; /* just generate an error */
- e = oprange[r].stop;
- c1 = xcmp[a1];
- c3 = xcmp[a3];
- c4 = xcmp[a4];
- for(; o<e; o++)
- if(o->a2 == a2)
- if(c1[o->a1])
- if(c3[o->a3])
- if(c4[o->a4]) {
- p->optab = (o-optab)+1;
- return o;
- }
- ctxt->diag("illegal combination %A %^ %^ %^ %^",
- p->as, a1, a2, a3, a4);
- 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_ZCON || b == C_SCON || b == C_UCON || b == C_ADDCON || b == C_ANDCON)
- return 1;
- break;
- case C_ADDCON:
- if(b == C_ZCON || b == C_SCON)
- return 1;
- break;
- case C_ANDCON:
- if(b == C_ZCON || b == C_SCON)
- return 1;
- break;
- case C_SPR:
- if(b == C_LR || b == C_XER || b == C_CTR)
- return 1;
- break;
- case C_UCON:
- if(b == C_ZCON)
- return 1;
- break;
- case C_SCON:
- if(b == C_ZCON)
- return 1;
- break;
- case C_LACON:
- if(b == C_SACON)
- return 1;
- break;
- case C_LBRA:
- if(b == C_SBRA)
- return 1;
- break;
- case C_LEXT:
- if(b == C_SEXT)
- return 1;
- break;
- case C_LAUTO:
- if(b == C_SAUTO)
- return 1;
- break;
- case C_REG:
- if(b == C_ZCON)
- return r0iszero;
- break;
- case C_LOREG:
- if(b == C_ZOREG || b == C_SOREG)
- return 1;
- break;
- case C_SOREG:
- if(b == C_ZOREG)
- return 1;
- break;
-
- case C_ANY:
- return 1;
- }
- return 0;
-}
-
-static int
-ocmp(const void *a1, const void *a2)
-{
- const Optab *p1, *p2;
- int n;
-
- p1 = a1;
- p2 = 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;
- n = p1->a4 - p2->a4;
- if(n)
- return n;
- return 0;
-}
-
-static void
-buildop(Link *ctxt)
-{
- int i, n, r;
-
- for(i=0; i<C_NCLASS; i++)
- for(n=0; n<C_NCLASS; n++)
- xcmp[i][n] = cmp(n, i);
- for(n=0; optab[n].as != AXXX; n++)
- ;
- 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 ADCBF: /* unary indexed: op (b+a); op (b) */
- oprange[ADCBI] = oprange[r];
- oprange[ADCBST] = oprange[r];
- oprange[ADCBT] = oprange[r];
- oprange[ADCBTST] = oprange[r];
- oprange[ADCBZ] = oprange[r];
- oprange[AICBI] = oprange[r];
- break;
- case AECOWX: /* indexed store: op s,(b+a); op s,(b) */
- oprange[ASTWCCC] = oprange[r];
- oprange[ASTDCCC] = oprange[r];
- break;
- case AREM: /* macro */
- oprange[AREMCC] = oprange[r];
- oprange[AREMV] = oprange[r];
- oprange[AREMVCC] = oprange[r];
- break;
- case AREMU:
- oprange[AREMU] = oprange[r];
- oprange[AREMUCC] = oprange[r];
- oprange[AREMUV] = oprange[r];
- oprange[AREMUVCC] = oprange[r];
- break;
- case AREMD:
- oprange[AREMDCC] = oprange[r];
- oprange[AREMDV] = oprange[r];
- oprange[AREMDVCC] = oprange[r];
- break;
- case AREMDU:
- oprange[AREMDU] = oprange[r];
- oprange[AREMDUCC] = oprange[r];
- oprange[AREMDUV] = oprange[r];
- oprange[AREMDUVCC] = oprange[r];
- break;
- case ADIVW: /* op Rb[,Ra],Rd */
- oprange[AMULHW] = oprange[r];
- oprange[AMULHWCC] = oprange[r];
- oprange[AMULHWU] = oprange[r];
- oprange[AMULHWUCC] = oprange[r];
- oprange[AMULLWCC] = oprange[r];
- oprange[AMULLWVCC] = oprange[r];
- oprange[AMULLWV] = oprange[r];
- oprange[ADIVWCC] = oprange[r];
- oprange[ADIVWV] = oprange[r];
- oprange[ADIVWVCC] = oprange[r];
- oprange[ADIVWU] = oprange[r];
- oprange[ADIVWUCC] = oprange[r];
- oprange[ADIVWUV] = oprange[r];
- oprange[ADIVWUVCC] = oprange[r];
- oprange[AADDCC] = oprange[r];
- oprange[AADDCV] = oprange[r];
- oprange[AADDCVCC] = oprange[r];
- oprange[AADDV] = oprange[r];
- oprange[AADDVCC] = oprange[r];
- oprange[AADDE] = oprange[r];
- oprange[AADDECC] = oprange[r];
- oprange[AADDEV] = oprange[r];
- oprange[AADDEVCC] = oprange[r];
- oprange[ACRAND] = oprange[r];
- oprange[ACRANDN] = oprange[r];
- oprange[ACREQV] = oprange[r];
- oprange[ACRNAND] = oprange[r];
- oprange[ACRNOR] = oprange[r];
- oprange[ACROR] = oprange[r];
- oprange[ACRORN] = oprange[r];
- oprange[ACRXOR] = oprange[r];
- oprange[AMULHD] = oprange[r];
- oprange[AMULHDCC] = oprange[r];
- oprange[AMULHDU] = oprange[r];
- oprange[AMULHDUCC] = oprange[r];
- oprange[AMULLD] = oprange[r];
- oprange[AMULLDCC] = oprange[r];
- oprange[AMULLDVCC] = oprange[r];
- oprange[AMULLDV] = oprange[r];
- oprange[ADIVD] = oprange[r];
- oprange[ADIVDCC] = oprange[r];
- oprange[ADIVDVCC] = oprange[r];
- oprange[ADIVDV] = oprange[r];
- oprange[ADIVDU] = oprange[r];
- oprange[ADIVDUCC] = oprange[r];
- oprange[ADIVDUVCC] = oprange[r];
- oprange[ADIVDUCC] = oprange[r];
- break;
- case AMOVBZ: /* lbz, stz, rlwm(r/r), lhz, lha, stz, and x variants */
- oprange[AMOVH] = oprange[r];
- oprange[AMOVHZ] = oprange[r];
- break;
- case AMOVBZU: /* lbz[x]u, stb[x]u, lhz[x]u, lha[x]u, sth[u]x, ld[x]u, std[u]x */
- oprange[AMOVHU] = oprange[r];
- oprange[AMOVHZU] = oprange[r];
- oprange[AMOVWU] = oprange[r];
- oprange[AMOVWZU] = oprange[r];
- oprange[AMOVDU] = oprange[r];
- oprange[AMOVMW] = oprange[r];
- break;
- case AAND: /* logical op Rb,Rs,Ra; no literal */
- oprange[AANDN] = oprange[r];
- oprange[AANDNCC] = oprange[r];
- oprange[AEQV] = oprange[r];
- oprange[AEQVCC] = oprange[r];
- oprange[ANAND] = oprange[r];
- oprange[ANANDCC] = oprange[r];
- oprange[ANOR] = oprange[r];
- oprange[ANORCC] = oprange[r];
- oprange[AORCC] = oprange[r];
- oprange[AORN] = oprange[r];
- oprange[AORNCC] = oprange[r];
- oprange[AXORCC] = oprange[r];
- break;
- case AADDME: /* op Ra, Rd */
- oprange[AADDMECC] = oprange[r];
- oprange[AADDMEV] = oprange[r];
- oprange[AADDMEVCC] = oprange[r];
- oprange[AADDZE] = oprange[r];
- oprange[AADDZECC] = oprange[r];
- oprange[AADDZEV] = oprange[r];
- oprange[AADDZEVCC] = oprange[r];
- oprange[ASUBME] = oprange[r];
- oprange[ASUBMECC] = oprange[r];
- oprange[ASUBMEV] = oprange[r];
- oprange[ASUBMEVCC] = oprange[r];
- oprange[ASUBZE] = oprange[r];
- oprange[ASUBZECC] = oprange[r];
- oprange[ASUBZEV] = oprange[r];
- oprange[ASUBZEVCC] = oprange[r];
- break;
- case AADDC:
- oprange[AADDCCC] = oprange[r];
- break;
- case ABEQ:
- oprange[ABGE] = oprange[r];
- oprange[ABGT] = oprange[r];
- oprange[ABLE] = oprange[r];
- oprange[ABLT] = oprange[r];
- oprange[ABNE] = oprange[r];
- oprange[ABVC] = oprange[r];
- oprange[ABVS] = oprange[r];
- break;
- case ABR:
- oprange[ABL] = oprange[r];
- break;
- case ABC:
- oprange[ABCL] = oprange[r];
- break;
- case AEXTSB: /* op Rs, Ra */
- oprange[AEXTSBCC] = oprange[r];
- oprange[AEXTSH] = oprange[r];
- oprange[AEXTSHCC] = oprange[r];
- oprange[ACNTLZW] = oprange[r];
- oprange[ACNTLZWCC] = oprange[r];
- oprange[ACNTLZD] = oprange[r];
- oprange[AEXTSW] = oprange[r];
- oprange[AEXTSWCC] = oprange[r];
- oprange[ACNTLZDCC] = oprange[r];
- break;
- case AFABS: /* fop [s,]d */
- oprange[AFABSCC] = oprange[r];
- oprange[AFNABS] = oprange[r];
- oprange[AFNABSCC] = oprange[r];
- oprange[AFNEG] = oprange[r];
- oprange[AFNEGCC] = oprange[r];
- oprange[AFRSP] = oprange[r];
- oprange[AFRSPCC] = oprange[r];
- oprange[AFCTIW] = oprange[r];
- oprange[AFCTIWCC] = oprange[r];
- oprange[AFCTIWZ] = oprange[r];
- oprange[AFCTIWZCC] = oprange[r];
- oprange[AFCTID] = oprange[r];
- oprange[AFCTIDCC] = oprange[r];
- oprange[AFCTIDZ] = oprange[r];
- oprange[AFCTIDZCC] = oprange[r];
- oprange[AFCFID] = oprange[r];
- oprange[AFCFIDCC] = oprange[r];
- oprange[AFRES] = oprange[r];
- oprange[AFRESCC] = oprange[r];
- oprange[AFRSQRTE] = oprange[r];
- oprange[AFRSQRTECC] = oprange[r];
- oprange[AFSQRT] = oprange[r];
- oprange[AFSQRTCC] = oprange[r];
- oprange[AFSQRTS] = oprange[r];
- oprange[AFSQRTSCC] = oprange[r];
- break;
- case AFADD:
- oprange[AFADDS] = oprange[r];
- oprange[AFADDCC] = oprange[r];
- oprange[AFADDSCC] = oprange[r];
- oprange[AFDIV] = oprange[r];
- oprange[AFDIVS] = oprange[r];
- oprange[AFDIVCC] = oprange[r];
- oprange[AFDIVSCC] = oprange[r];
- oprange[AFSUB] = oprange[r];
- oprange[AFSUBS] = oprange[r];
- oprange[AFSUBCC] = oprange[r];
- oprange[AFSUBSCC] = oprange[r];
- break;
- case AFMADD:
- oprange[AFMADDCC] = oprange[r];
- oprange[AFMADDS] = oprange[r];
- oprange[AFMADDSCC] = oprange[r];
- oprange[AFMSUB] = oprange[r];
- oprange[AFMSUBCC] = oprange[r];
- oprange[AFMSUBS] = oprange[r];
- oprange[AFMSUBSCC] = oprange[r];
- oprange[AFNMADD] = oprange[r];
- oprange[AFNMADDCC] = oprange[r];
- oprange[AFNMADDS] = oprange[r];
- oprange[AFNMADDSCC] = oprange[r];
- oprange[AFNMSUB] = oprange[r];
- oprange[AFNMSUBCC] = oprange[r];
- oprange[AFNMSUBS] = oprange[r];
- oprange[AFNMSUBSCC] = oprange[r];
- oprange[AFSEL] = oprange[r];
- oprange[AFSELCC] = oprange[r];
- break;
- case AFMUL:
- oprange[AFMULS] = oprange[r];
- oprange[AFMULCC] = oprange[r];
- oprange[AFMULSCC] = oprange[r];
- break;
- case AFCMPO:
- oprange[AFCMPU] = oprange[r];
- break;
- case AMTFSB0:
- oprange[AMTFSB0CC] = oprange[r];
- oprange[AMTFSB1] = oprange[r];
- oprange[AMTFSB1CC] = oprange[r];
- break;
- case ANEG: /* op [Ra,] Rd */
- oprange[ANEGCC] = oprange[r];
- oprange[ANEGV] = oprange[r];
- oprange[ANEGVCC] = oprange[r];
- break;
- case AOR: /* or/xor Rb,Rs,Ra; ori/xori $uimm,Rs,Ra; oris/xoris $uimm,Rs,Ra */
- oprange[AXOR] = oprange[r];
- break;
- case ASLW:
- oprange[ASLWCC] = oprange[r];
- oprange[ASRW] = oprange[r];
- oprange[ASRWCC] = oprange[r];
- break;
- case ASLD:
- oprange[ASLDCC] = oprange[r];
- oprange[ASRD] = oprange[r];
- oprange[ASRDCC] = oprange[r];
- break;
- case ASRAW: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
- oprange[ASRAWCC] = oprange[r];
- break;
- case ASRAD: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
- oprange[ASRADCC] = oprange[r];
- break;
- case ASUB: /* SUB Ra,Rb,Rd => subf Rd,ra,rb */
- oprange[ASUB] = oprange[r];
- oprange[ASUBCC] = oprange[r];
- oprange[ASUBV] = oprange[r];
- oprange[ASUBVCC] = oprange[r];
- oprange[ASUBCCC] = oprange[r];
- oprange[ASUBCV] = oprange[r];
- oprange[ASUBCVCC] = oprange[r];
- oprange[ASUBE] = oprange[r];
- oprange[ASUBECC] = oprange[r];
- oprange[ASUBEV] = oprange[r];
- oprange[ASUBEVCC] = oprange[r];
- break;
- case ASYNC:
- oprange[AISYNC] = oprange[r];
- oprange[APTESYNC] = oprange[r];
- oprange[ATLBSYNC] = oprange[r];
- break;
- case ARLWMI:
- oprange[ARLWMICC] = oprange[r];
- oprange[ARLWNM] = oprange[r];
- oprange[ARLWNMCC] = oprange[r];
- break;
- case ARLDMI:
- oprange[ARLDMICC] = oprange[r];
- break;
- case ARLDC:
- oprange[ARLDCCC] = oprange[r];
- break;
- case ARLDCL:
- oprange[ARLDCR] = oprange[r];
- oprange[ARLDCLCC] = oprange[r];
- oprange[ARLDCRCC] = oprange[r];
- break;
- case AFMOVD:
- oprange[AFMOVDCC] = oprange[r];
- oprange[AFMOVDU] = oprange[r];
- oprange[AFMOVS] = oprange[r];
- oprange[AFMOVSU] = oprange[r];
- break;
- case AECIWX:
- oprange[ALWAR] = oprange[r];
- oprange[ALDAR] = oprange[r];
- break;
- case ASYSCALL: /* just the op; flow of control */
- oprange[ARFI] = oprange[r];
- oprange[ARFCI] = oprange[r];
- oprange[ARFID] = oprange[r];
- oprange[AHRFID] = oprange[r];
- break;
- case AMOVHBR:
- oprange[AMOVWBR] = oprange[r];
- break;
- case ASLBMFEE:
- oprange[ASLBMFEV] = oprange[r];
- break;
- case ATW:
- oprange[ATD] = oprange[r];
- break;
- case ATLBIE:
- oprange[ASLBIE] = oprange[r];
- oprange[ATLBIEL] = oprange[r];
- break;
- case AEIEIO:
- oprange[ASLBIA] = oprange[r];
- break;
- case ACMP:
- oprange[ACMPW] = oprange[r];
- break;
- case ACMPU:
- oprange[ACMPWU] = oprange[r];
- break;
- case AADD:
- case AANDCC: /* and. Rb,Rs,Ra; andi. $uimm,Rs,Ra; andis. $uimm,Rs,Ra */
- case ALSW:
- case AMOVW: /* load/store/move word with sign extension; special 32-bit move; move 32-bit literals */
- case AMOVWZ: /* load/store/move word with zero extension; move 32-bit literals */
- case AMOVD: /* load/store/move 64-bit values, including 32-bit literals with/without sign-extension */
- case AMOVB: /* macro: move byte with sign extension */
- case AMOVBU: /* macro: move byte with sign extension & update */
- case AMOVFL:
- case AMULLW: /* op $s[,r2],r3; op r1[,r2],r3; no cc/v */
- case ASUBC: /* op r1,$s,r3; op r1[,r2],r3 */
- case ASTSW:
- case ASLBMTE:
- case AWORD:
- case ADWORD:
- case ANOP:
- case ATEXT:
- case AUNDEF:
- case AUSEFIELD:
- case AFUNCDATA:
- case APCDATA:
- case ADUFFZERO:
- case ADUFFCOPY:
- break;
- }
- }
-}
-
-uint32
-OPVCC(uint32 o, uint32 xo, uint32 oe, uint32 rc)
-{
- return o<<26 | xo<<1 | oe<<10 | rc&1;
-}
-
-uint32
-OPCC(uint32 o, uint32 xo, uint32 rc)
-{
- return OPVCC(o, xo, 0, rc);
-}
-
-uint32
-OP(uint32 o, uint32 xo)
-{
- return OPVCC(o, xo, 0, 0);
-}
-
-/* the order is dest, a/s, b/imm for both arithmetic and logical operations */
-uint32
-AOP_RRR(uint32 op, uint32 d, uint32 a, uint32 b)
-{
- return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11;
-}
-
-uint32
-AOP_IRR(uint32 op, uint32 d, uint32 a, uint32 simm)
-{
- return op | (d&31)<<21 | (a&31)<<16 | (simm&0xFFFF);
-}
-
-uint32
-LOP_RRR(uint32 op, uint32 a, uint32 s, uint32 b)
-{
- return op | (s&31)<<21 | (a&31)<<16 | (b&31)<<11;
-}
-
-uint32
-LOP_IRR(uint32 op, uint32 a, uint32 s, uint32 uimm)
-{
- return op | (s&31)<<21 | (a&31)<<16 | (uimm&0xFFFF);
-}
-
-uint32
-OP_BR(uint32 op, uint32 li, uint32 aa)
-{
- return op | li&0x03FFFFFC | aa<<1;
-}
-
-uint32
-OP_BC(uint32 op, uint32 bo, uint32 bi, uint32 bd, uint32 aa)
-{
- return op | (bo&0x1F)<<21 | (bi&0x1F)<<16 | bd&0xFFFC | aa<<1;
-}
-
-uint32
-OP_BCR(uint32 op, uint32 bo, uint32 bi)
-{
- return op | (bo&0x1F)<<21 | (bi&0x1F)<<16;
-}
-
-uint32
-OP_RLW(uint32 op, uint32 a, uint32 s, uint32 sh, uint32 mb, uint32 me)
-{
- return op | (s&31)<<21 | (a&31)<<16 | (sh&31)<<11 | (mb&31)<<6 | (me&31)<<1;
-}
-
-enum {
- /* each rhs is OPVCC(_, _, _, _) */
- OP_ADD = 31<<26 | 266<<1 | 0<<10 | 0,
- OP_ADDI = 14<<26 | 0<<1 | 0<<10 | 0,
- OP_ADDIS = 15<<26 | 0<<1 | 0<<10 | 0,
- OP_ANDI = 28<<26 | 0<<1 | 0<<10 | 0,
- OP_EXTSB = 31<<26 | 954<<1 | 0<<10 | 0,
- OP_EXTSH = 31<<26 | 922<<1 | 0<<10 | 0,
- OP_EXTSW = 31<<26 | 986<<1 | 0<<10 | 0,
- OP_MCRF = 19<<26 | 0<<1 | 0<<10 | 0,
- OP_MCRFS = 63<<26 | 64<<1 | 0<<10 | 0,
- OP_MCRXR = 31<<26 | 512<<1 | 0<<10 | 0,
- OP_MFCR = 31<<26 | 19<<1 | 0<<10 | 0,
- OP_MFFS = 63<<26 | 583<<1 | 0<<10 | 0,
- OP_MFMSR = 31<<26 | 83<<1 | 0<<10 | 0,
- OP_MFSPR = 31<<26 | 339<<1 | 0<<10 | 0,
- OP_MFSR = 31<<26 | 595<<1 | 0<<10 | 0,
- OP_MFSRIN = 31<<26 | 659<<1 | 0<<10 | 0,
- OP_MTCRF = 31<<26 | 144<<1 | 0<<10 | 0,
- OP_MTFSF = 63<<26 | 711<<1 | 0<<10 | 0,
- OP_MTFSFI = 63<<26 | 134<<1 | 0<<10 | 0,
- OP_MTMSR = 31<<26 | 146<<1 | 0<<10 | 0,
- OP_MTMSRD = 31<<26 | 178<<1 | 0<<10 | 0,
- OP_MTSPR = 31<<26 | 467<<1 | 0<<10 | 0,
- OP_MTSR = 31<<26 | 210<<1 | 0<<10 | 0,
- OP_MTSRIN = 31<<26 | 242<<1 | 0<<10 | 0,
- OP_MULLW = 31<<26 | 235<<1 | 0<<10 | 0,
- OP_MULLD = 31<<26 | 233<<1 | 0<<10 | 0,
- OP_OR = 31<<26 | 444<<1 | 0<<10 | 0,
- OP_ORI = 24<<26 | 0<<1 | 0<<10 | 0,
- OP_ORIS = 25<<26 | 0<<1 | 0<<10 | 0,
- OP_RLWINM = 21<<26 | 0<<1 | 0<<10 | 0,
- OP_SUBF = 31<<26 | 40<<1 | 0<<10 | 0,
- OP_RLDIC = 30<<26 | 4<<1 | 0<<10 | 0,
- OP_RLDICR = 30<<26 | 2<<1 | 0<<10 | 0,
- OP_RLDICL = 30<<26 | 0<<1 | 0<<10 | 0,
-};
-
-int
-oclass(Addr *a)
-{
- return a->class - 1;
-}
-
-// add R_ADDRPOWER relocation to symbol s for the two instructions o1 and o2.
-static void
-addaddrreloc(Link *ctxt, LSym *s, uint32 *o1, uint32 *o2)
-{
- Reloc *rel;
-
- rel = addrel(ctxt->cursym);
- rel->off = ctxt->pc;
- rel->siz = 8;
- rel->sym = s;
- rel->add = ((uvlong)*o1<<32) | (uint32)*o2;
- rel->type = R_ADDRPOWER;
-}
-
-/*
- * 32-bit masks
- */
-static int
-getmask(uchar *m, uint32 v)
-{
- int i;
-
- m[0] = m[1] = 0;
- if(v != ~(uint32)0 && v & (1<<31) && v & 1){ /* MB > ME */
- if(getmask(m, ~v)){
- i = m[0]; m[0] = m[1]+1; m[1] = i-1;
- return 1;
- }
- return 0;
- }
- for(i=0; i<32; i++)
- if(v & (1<<(31-i))){
- m[0] = i;
- do {
- m[1] = i;
- } while(++i<32 && (v & (1<<(31-i))) != 0);
- for(; i<32; i++)
- if(v & (1<<(31-i)))
- return 0;
- return 1;
- }
- return 0;
-}
-
-static void
-maskgen(Link *ctxt, Prog *p, uchar *m, uint32 v)
-{
- if(!getmask(m, v))
- ctxt->diag("cannot generate mask #%lux\n%P", v, p);
-}
-
-/*
- * 64-bit masks (rldic etc)
- */
-static int
-getmask64(uchar *m, uvlong v)
-{
- int i;
-
- m[0] = m[1] = 0;
- for(i=0; i<64; i++)
- if(v & ((uvlong)1<<(63-i))){
- m[0] = i;
- do {
- m[1] = i;
- } while(++i<64 && (v & ((uvlong)1<<(63-i))) != 0);
- for(; i<64; i++)
- if(v & ((uvlong)1<<(63-i)))
- return 0;
- return 1;
- }
- return 0;
-}
-
-static void
-maskgen64(Link *ctxt, Prog *p, uchar *m, uvlong v)
-{
- if(!getmask64(m, v))
- ctxt->diag("cannot generate mask #%llux\n%P", v, p);
-}
-
-static uint32
-loadu32(int r, vlong d)
-{
- int32 v;
-
- v = d>>16;
- if(isuint32(d))
- return LOP_IRR(OP_ORIS, r, REGZERO, v);
- return AOP_IRR(OP_ADDIS, r, REGZERO, v);
-}
-
-static uint16
-high16adjusted(int32 d)
-{
- if(d & 0x8000)
- return (d>>16) + 1;
- return d>>16;
-}
-
-static void
-asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
-{
- uint32 o1, o2, o3, o4, o5;
- int32 v, t;
- vlong d;
- int r, a;
- uchar mask[2];
- Reloc *rel;
-
- o1 = 0;
- o2 = 0;
- o3 = 0;
- o4 = 0;
- o5 = 0;
-
-//print("%P => case %d\n", p, o->type);
- switch(o->type) {
- default:
- ctxt->diag("unknown type %d", o->type);
- prasm(p);
- break;
-
- case 0: /* pseudo ops */
- break;
-
- case 1: /* mov r1,r2 ==> OR Rs,Rs,Ra */
- if(p->to.reg == REGZERO && p->from.type == TYPE_CONST) {
- v = regoff(ctxt, &p->from);
- if(r0iszero && v != 0) {
- //nerrors--;
- ctxt->diag("literal operation on R0\n%P", p);
- }
- o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, v);
- break;
- }
- o1 = LOP_RRR(OP_OR, p->to.reg, p->from.reg, p->from.reg);
- break;
-
- case 2: /* int/cr/fp op Rb,[Ra],Rd */
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, p->from.reg);
- break;
-
- case 3: /* mov $soreg/addcon/ucon, r ==> addis/addi $i,reg',r */
- d = vregoff(ctxt, &p->from);
- v = d;
- r = p->from.reg;
- if(r == 0)
- r = o->param;
- if(r0iszero && p->to.reg == 0 && (r != 0 || v != 0))
- ctxt->diag("literal operation on R0\n%P", p);
- a = OP_ADDI;
- if(o->a1 == C_UCON) {
- if((d&0xffff) != 0)
- sysfatal("invalid handling of %P", p);
- v >>= 16;
- if(r == REGZERO && isuint32(d)){
- o1 = LOP_IRR(OP_ORIS, p->to.reg, REGZERO, v);
- break;
- }
- a = OP_ADDIS;
- } else {
- if((int16)d != d)
- sysfatal("invalid handling of %P", p);
- }
- o1 = AOP_IRR(a, p->to.reg, r, v);
- break;
-
- case 4: /* add/mul $scon,[r1],r2 */
- v = regoff(ctxt, &p->from);
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- if(r0iszero && p->to.reg == 0)
- ctxt->diag("literal operation on R0\n%P", p);
- if((int16)v != v)
- sysfatal("mishandled instruction %P", p);
- o1 = AOP_IRR(opirr(ctxt, p->as), p->to.reg, r, v);
- break;
-
- case 5: /* syscall */
- o1 = oprrr(ctxt, p->as);
- break;
-
- case 6: /* logical op Rb,[Rs,]Ra; no literal */
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- o1 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, p->from.reg);
- break;
-
- case 7: /* mov r, soreg ==> stw o(r) */
- r = p->to.reg;
- if(r == 0)
- r = o->param;
- v = regoff(ctxt, &p->to);
- if(p->to.type == TYPE_MEM && p->reg != 0) {
- if(v)
- ctxt->diag("illegal indexed instruction\n%P", p);
- o1 = AOP_RRR(opstorex(ctxt, p->as), p->from.reg, p->reg, r);
- } else {
- if((int16)v != v)
- sysfatal("mishandled instruction %P", p);
- o1 = AOP_IRR(opstore(ctxt, p->as), p->from.reg, r, v);
- }
- break;
-
- case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */
- r = p->from.reg;
- if(r == 0)
- r = o->param;
- v = regoff(ctxt, &p->from);
- if(p->from.type == TYPE_MEM && p->reg != 0) {
- if(v)
- ctxt->diag("illegal indexed instruction\n%P", p);
- o1 = AOP_RRR(oploadx(ctxt, p->as), p->to.reg, p->reg, r);
- } else {
- if((int16)v != v)
- sysfatal("mishandled instruction %P", p);
- o1 = AOP_IRR(opload(ctxt, p->as), p->to.reg, r, v);
- }
- break;
-
- case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */
- r = p->from.reg;
- if(r == 0)
- r = o->param;
- v = regoff(ctxt, &p->from);
- if(p->from.type == TYPE_MEM && p->reg != 0) {
- if(v)
- ctxt->diag("illegal indexed instruction\n%P", p);
- o1 = AOP_RRR(oploadx(ctxt, p->as), p->to.reg, p->reg, r);
- } else
- o1 = AOP_IRR(opload(ctxt, p->as), p->to.reg, r, v);
- o2 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0);
- break;
-
- case 10: /* sub Ra,[Rb],Rd => subf Rd,Ra,Rb */
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, p->from.reg, r);
- break;
-
- case 11: /* br/bl lbra */
- v = 0;
- if(p->pcond) {
- v = p->pcond->pc - p->pc;
- if(v & 03) {
- ctxt->diag("odd branch target address\n%P", p);
- v &= ~03;
- }
- if(v < -(1L<<25) || v >= (1L<<24))
- ctxt->diag("branch too far\n%P", p);
- }
- o1 = OP_BR(opirr(ctxt, p->as), v, 0);
- if(p->to.sym != nil) {
- rel = addrel(ctxt->cursym);
- rel->off = ctxt->pc;
- rel->siz = 4;
- rel->sym = p->to.sym;
- v += p->to.offset;
- if(v & 03) {
- ctxt->diag("odd branch target address\n%P", p);
- v &= ~03;
- }
- rel->add = v;
- rel->type = R_CALLPOWER;
- }
- break;
-
- case 12: /* movb r,r (extsb); movw r,r (extsw) */
- if(p->to.reg == REGZERO && p->from.type == TYPE_CONST) {
- v = regoff(ctxt, &p->from);
- if(r0iszero && v != 0) {
- ctxt->diag("literal operation on R0\n%P", p);
- }
- o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, v);
- break;
- }
- if(p->as == AMOVW)
- o1 = LOP_RRR(OP_EXTSW, p->to.reg, p->from.reg, 0);
- else
- o1 = LOP_RRR(OP_EXTSB, p->to.reg, p->from.reg, 0);
- break;
-
- case 13: /* mov[bhw]z r,r; uses rlwinm not andi. to avoid changing CC */
- if(p->as == AMOVBZ)
- o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 24, 31);
- else if(p->as == AMOVH)
- o1 = LOP_RRR(OP_EXTSH, p->to.reg, p->from.reg, 0);
- else if(p->as == AMOVHZ)
- o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 16, 31);
- else if(p->as == AMOVWZ)
- o1 = OP_RLW(OP_RLDIC, p->to.reg, p->from.reg, 0, 0, 0) | (1<<5); /* MB=32 */
- else
- ctxt->diag("internal: bad mov[bhw]z\n%P", p);
- break;
-
- case 14: /* rldc[lr] Rb,Rs,$mask,Ra -- left, right give different masks */
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- d = vregoff(ctxt, &p->from3);
- maskgen64(ctxt, p, mask, d);
- switch(p->as){
- case ARLDCL: case ARLDCLCC:
- a = mask[0]; /* MB */
- if(mask[1] != 63)
- ctxt->diag("invalid mask for rotate: %llux (end != bit 63)\n%P", d, p);
- break;
- case ARLDCR: case ARLDCRCC:
- a = mask[1]; /* ME */
- if(mask[0] != 0)
- ctxt->diag("invalid mask for rotate: %llux (start != 0)\n%P", d, p);
- break;
- default:
- ctxt->diag("unexpected op in rldc case\n%P", p);
- a = 0;
- }
- o1 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, p->from.reg);
- o1 |= (a&31L)<<6;
- if(a & 0x20)
- o1 |= 1<<5; /* mb[5] is top bit */
- break;
-
- case 17: /* bc bo,bi,lbra (same for now) */
- case 16: /* bc bo,bi,sbra */
- a = 0;
- if(p->from.type == TYPE_CONST)
- a = regoff(ctxt, &p->from);
- r = p->reg;
- if(r == 0)
- r = 0;
- v = 0;
- if(p->pcond)
- v = p->pcond->pc - p->pc;
- if(v & 03) {
- ctxt->diag("odd branch target address\n%P", p);
- v &= ~03;
- }
- if(v < -(1L<<16) || v >= (1L<<15))
- ctxt->diag("branch too far\n%P", p);
- o1 = OP_BC(opirr(ctxt, p->as), a, r, v, 0);
- break;
-
- case 15: /* br/bl (r) => mov r,lr; br/bl (lr) */
- if(p->as == ABC || p->as == ABCL)
- v = regoff(ctxt, &p->to)&31L;
- else
- v = 20; /* unconditional */
- r = p->reg;
- if(r == 0)
- r = 0;
- o1 = AOP_RRR(OP_MTSPR, p->to.reg, 0, 0) | ((REG_LR&0x1f)<<16) | (((REG_LR>>5)&0x1f)<<11);
- o2 = OPVCC(19, 16, 0, 0);
- if(p->as == ABL || p->as == ABCL)
- o2 |= 1;
- o2 = OP_BCR(o2, v, r);
- break;
-
- case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */
- if(p->as == ABC || p->as == ABCL)
- v = regoff(ctxt, &p->from)&31L;
- else
- v = 20; /* unconditional */
- r = p->reg;
- if(r == 0)
- r = 0;
- switch(oclass(&p->to)) {
- case C_CTR:
- o1 = OPVCC(19, 528, 0, 0);
- break;
- case C_LR:
- o1 = OPVCC(19, 16, 0, 0);
- break;
- default:
- ctxt->diag("bad optab entry (18): %d\n%P", p->to.class, p);
- v = 0;
- }
- if(p->as == ABL || p->as == ABCL)
- o1 |= 1;
- o1 = OP_BCR(o1, v, r);
- break;
-
- case 19: /* mov $lcon,r ==> cau+or */
- d = vregoff(ctxt, &p->from);
- if(p->from.sym == nil) {
- o1 = loadu32(p->to.reg, d);
- o2 = LOP_IRR(OP_ORI, p->to.reg, p->to.reg, (int32)d);
- } else {
- o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, high16adjusted(d));
- o2 = AOP_IRR(OP_ADDI, p->to.reg, REGTMP, d);
- addaddrreloc(ctxt, p->from.sym, &o1, &o2);
- }
- //if(dlm) reloc(&p->from, p->pc, 0);
- break;
-
- case 20: /* add $ucon,,r */
- v = regoff(ctxt, &p->from);
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- if(p->as == AADD && (!r0iszero && p->reg == 0 || r0iszero && p->to.reg == 0))
- ctxt->diag("literal operation on R0\n%P", p);
- o1 = AOP_IRR(opirr(ctxt, p->as+ALAST), p->to.reg, r, v>>16);
- break;
-
- case 22: /* add $lcon,r1,r2 ==> cau+or+add */ /* could do add/sub more efficiently */
- if(p->to.reg == REGTMP || p->reg == REGTMP)
- ctxt->diag("cant synthesize large constant\n%P", p);
- d = vregoff(ctxt, &p->from);
- o1 = loadu32(REGTMP, d);
- o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, (int32)d);
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- o3 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, REGTMP, r);
- if(p->from.sym != nil)
- ctxt->diag("%P is not supported", p);
- //if(dlm) reloc(&p->from, p->pc, 0);
- break;
-
- case 23: /* and $lcon,r1,r2 ==> cau+or+and */ /* masks could be done using rlnm etc. */
- if(p->to.reg == REGTMP || p->reg == REGTMP)
- ctxt->diag("cant synthesize large constant\n%P", p);
- d = vregoff(ctxt, &p->from);
- o1 = loadu32(REGTMP, d);
- o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, (int32)d);
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- o3 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, REGTMP, r);
- if(p->from.sym != nil)
- ctxt->diag("%P is not supported", p);
- //if(dlm) reloc(&p->from, p->pc, 0);
- break;
-/*24*/
-
- case 25: /* sld[.] $sh,rS,rA -> rldicr[.] $sh,rS,mask(0,63-sh),rA; srd[.] -> rldicl */
- v = regoff(ctxt, &p->from);
- if(v < 0)
- v = 0;
- else if(v > 63)
- v = 63;
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- switch(p->as){
- case ASLD: case ASLDCC:
- a = 63-v;
- o1 = OP_RLDICR;
- break;
- case ASRD: case ASRDCC:
- a = v;
- v = 64-v;
- o1 = OP_RLDICL;
- break;
- default:
- ctxt->diag("unexpected op in sldi case\n%P", p);
- a = 0;
- o1 = 0;
- }
- o1 = AOP_RRR(o1, r, p->to.reg, (v&0x1F));
- o1 |= (a&31L)<<6;
- if(v & 0x20)
- o1 |= 1<<1;
- if(a & 0x20)
- o1 |= 1<<5; /* mb[5] is top bit */
- if(p->as == ASLDCC || p->as == ASRDCC)
- o1 |= 1; /* Rc */
- break;
-
- case 26: /* mov $lsext/auto/oreg,,r2 ==> addis+addi */
- if(p->to.reg == REGTMP)
- ctxt->diag("can't synthesize large constant\n%P", p);
- v = regoff(ctxt, &p->from);
- r = p->from.reg;
- if(r == 0)
- r = o->param;
- o1 = AOP_IRR(OP_ADDIS, REGTMP, r, high16adjusted(v));
- o2 = AOP_IRR(OP_ADDI, p->to.reg, REGTMP, v);
- break;
-
- case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */
- v = regoff(ctxt, &p->from3);
- r = p->from.reg;
- o1 = AOP_IRR(opirr(ctxt, p->as), p->to.reg, r, v);
- break;
-
- case 28: /* subc r1,$lcon,r2 ==> cau+or+subfc */
- if(p->to.reg == REGTMP || p->from.reg == REGTMP)
- ctxt->diag("can't synthesize large constant\n%P", p);
- v = regoff(ctxt, &p->from3);
- o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16);
- o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, v);
- o3 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, p->from.reg, REGTMP);
- if(p->from.sym != nil)
- ctxt->diag("%P is not supported", p);
- //if(dlm) reloc(&p->from3, p->pc, 0);
- break;
-
- case 29: /* rldic[lr]? $sh,s,$mask,a -- left, right, plain give different masks */
- v = regoff(ctxt, &p->from);
- d = vregoff(ctxt, &p->from3);
- maskgen64(ctxt, p, mask, d);
- switch(p->as){
- case ARLDC: case ARLDCCC:
- a = mask[0]; /* MB */
- if(mask[1] != (63-v))
- ctxt->diag("invalid mask for shift: %llux (shift %ld)\n%P", d, v, p);
- break;
- case ARLDCL: case ARLDCLCC:
- a = mask[0]; /* MB */
- if(mask[1] != 63)
- ctxt->diag("invalid mask for shift: %llux (shift %ld)\n%P", d, v, p);
- break;
- case ARLDCR: case ARLDCRCC:
- a = mask[1]; /* ME */
- if(mask[0] != 0)
- ctxt->diag("invalid mask for shift: %llux (shift %ld)\n%P", d, v, p);
- break;
- default:
- ctxt->diag("unexpected op in rldic case\n%P", p);
- a = 0;
- }
- o1 = AOP_RRR(opirr(ctxt, p->as), p->reg, p->to.reg, (v&0x1F));
- o1 |= (a&31L)<<6;
- if(v & 0x20)
- o1 |= 1<<1;
- if(a & 0x20)
- o1 |= 1<<5; /* mb[5] is top bit */
- break;
-
- case 30: /* rldimi $sh,s,$mask,a */
- v = regoff(ctxt, &p->from);
- d = vregoff(ctxt, &p->from3);
- maskgen64(ctxt, p, mask, d);
- if(mask[1] != (63-v))
- ctxt->diag("invalid mask for shift: %llux (shift %ld)\n%P", d, v, p);
- o1 = AOP_RRR(opirr(ctxt, p->as), p->reg, p->to.reg, (v&0x1F));
- o1 |= (mask[0]&31L)<<6;
- if(v & 0x20)
- o1 |= 1<<1;
- if(mask[0] & 0x20)
- o1 |= 1<<5; /* mb[5] is top bit */
- break;
-
- case 31: /* dword */
- d = vregoff(ctxt, &p->from);
- if(ctxt->arch->endian == BigEndian) {
- o1 = d>>32;
- o2 = d;
- } else {
- o1 = d;
- o2 = d>>32;
- }
- if(p->from.sym != nil) {
- rel = addrel(ctxt->cursym);
- rel->off = ctxt->pc;
- rel->siz = 8;
- rel->sym = p->from.sym;
- rel->add = p->from.offset;
- rel->type = R_ADDR;
- o1 = o2 = 0;
- }
- break;
-
- case 32: /* fmul frc,fra,frd */
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, 0)|((p->from.reg&31L)<<6);
- break;
-
- case 33: /* fabs [frb,]frd; fmr. frb,frd */
- r = p->from.reg;
- if(oclass(&p->from) == C_NONE)
- r = p->to.reg;
- o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, 0, r);
- break;
-
- case 34: /* FMADDx fra,frb,frc,frd (d=a*b+c); FSELx a<0? (d=b): (d=c) */
- o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, p->from.reg, p->reg)|((p->from3.reg&31L)<<6);
- break;
-
- case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */
- v = regoff(ctxt, &p->to);
- r = p->to.reg;
- if(r == 0)
- r = o->param;
- o1 = AOP_IRR(OP_ADDIS, REGTMP, r, high16adjusted(v));
- o2 = AOP_IRR(opstore(ctxt, p->as), p->from.reg, REGTMP, v);
- break;
-
- case 36: /* mov bz/h/hz lext/lauto/lreg,r ==> lbz/lha/lhz etc */
- v = regoff(ctxt, &p->from);
- r = p->from.reg;
- if(r == 0)
- r = o->param;
- o1 = AOP_IRR(OP_ADDIS, REGTMP, r, high16adjusted(v));
- o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
- break;
-
- case 37: /* movb lext/lauto/lreg,r ==> lbz o(reg),r; extsb r */
- v = regoff(ctxt, &p->from);
- r = p->from.reg;
- if(r == 0)
- r = o->param;
- o1 = AOP_IRR(OP_ADDIS, REGTMP, r, high16adjusted(v));
- o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
- o3 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0);
- break;
-
- case 40: /* word */
- o1 = regoff(ctxt, &p->from);
- break;
-
- case 41: /* stswi */
- o1 = AOP_RRR(opirr(ctxt, p->as), p->from.reg, p->to.reg, 0) | ((regoff(ctxt, &p->from3)&0x7F)<<11);
- break;
-
- case 42: /* lswi */
- o1 = AOP_RRR(opirr(ctxt, p->as), p->to.reg, p->from.reg, 0) | ((regoff(ctxt, &p->from3)&0x7F)<<11);
- break;
-
- case 43: /* unary indexed source: dcbf (b); dcbf (a+b) */
- r = p->reg;
- if(r == 0)
- r = 0;
- o1 = AOP_RRR(oprrr(ctxt, p->as), 0, r, p->from.reg);
- break;
-
- case 44: /* indexed store */
- r = p->reg;
- if(r == 0)
- r = 0;
- o1 = AOP_RRR(opstorex(ctxt, p->as), p->from.reg, r, p->to.reg);
- break;
- case 45: /* indexed load */
- r = p->reg;
- if(r == 0)
- r = 0;
- o1 = AOP_RRR(oploadx(ctxt, p->as), p->to.reg, r, p->from.reg);
- break;
-
- case 46: /* plain op */
- o1 = oprrr(ctxt, p->as);
- break;
-
- case 47: /* op Ra, Rd; also op [Ra,] Rd */
- r = p->from.reg;
- if(r == 0)
- r = p->to.reg;
- o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, 0);
- break;
-
- case 48: /* op Rs, Ra */
- r = p->from.reg;
- if(r == 0)
- r = p->to.reg;
- o1 = LOP_RRR(oprrr(ctxt, p->as), p->to.reg, r, 0);
- break;
-
- case 49: /* op Rb; op $n, Rb */
- if(p->from.type != TYPE_REG){ /* tlbie $L, rB */
- v = regoff(ctxt, &p->from) & 1;
- o1 = AOP_RRR(oprrr(ctxt, p->as), 0, 0, p->to.reg) | (v<<21);
- }else
- o1 = AOP_RRR(oprrr(ctxt, p->as), 0, 0, p->from.reg);
- break;
-
- case 50: /* rem[u] r1[,r2],r3 */
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- v = oprrr(ctxt, p->as);
- t = v & ((1<<10)|1); /* OE|Rc */
- o1 = AOP_RRR(v&~t, REGTMP, r, p->from.reg);
- o2 = AOP_RRR(OP_MULLW, REGTMP, REGTMP, p->from.reg);
- o3 = AOP_RRR(OP_SUBF|t, p->to.reg, REGTMP, r);
- if(p->as == AREMU) {
- o4 = o3;
- /* Clear top 32 bits */
- o3 = OP_RLW(OP_RLDIC, REGTMP, REGTMP, 0, 0, 0) | (1<<5);
- }
- break;
-
- case 51: /* remd[u] r1[,r2],r3 */
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- v = oprrr(ctxt, p->as);
- t = v & ((1<<10)|1); /* OE|Rc */
- o1 = AOP_RRR(v&~t, REGTMP, r, p->from.reg);
- o2 = AOP_RRR(OP_MULLD, REGTMP, REGTMP, p->from.reg);
- o3 = AOP_RRR(OP_SUBF|t, p->to.reg, REGTMP, r);
- break;
-
- case 52: /* mtfsbNx cr(n) */
- v = regoff(ctxt, &p->from)&31L;
- o1 = AOP_RRR(oprrr(ctxt, p->as), v, 0, 0);
- break;
-
- case 53: /* mffsX ,fr1 */
- o1 = AOP_RRR(OP_MFFS, p->to.reg, 0, 0);
- break;
-
- case 54: /* mov msr,r1; mov r1, msr*/
- if(oclass(&p->from) == C_REG){
- if(p->as == AMOVD)
- o1 = AOP_RRR(OP_MTMSRD, p->from.reg, 0, 0);
- else
- o1 = AOP_RRR(OP_MTMSR, p->from.reg, 0, 0);
- }else
- o1 = AOP_RRR(OP_MFMSR, p->to.reg, 0, 0);
- break;
-
- case 55: /* op Rb, Rd */
- o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, 0, p->from.reg);
- break;
-
- case 56: /* sra $sh,[s,]a; srd $sh,[s,]a */
- v = regoff(ctxt, &p->from);
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- o1 = AOP_RRR(opirr(ctxt, p->as), r, p->to.reg, v&31L);
- if(p->as == ASRAD && (v&0x20))
- o1 |= 1<<1; /* mb[5] */
- break;
-
- case 57: /* slw $sh,[s,]a -> rlwinm ... */
- v = regoff(ctxt, &p->from);
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- /*
- * Let user (gs) shoot himself in the foot.
- * qc has already complained.
- *
- if(v < 0 || v > 31)
- ctxt->diag("illegal shift %ld\n%P", v, p);
- */
- if(v < 0)
- v = 0;
- else if(v > 32)
- v = 32;
- if(p->as == ASRW || p->as == ASRWCC) { /* shift right */
- mask[0] = v;
- mask[1] = 31;
- v = 32-v;
- } else {
- mask[0] = 0;
- mask[1] = 31-v;
- }
- o1 = OP_RLW(OP_RLWINM, p->to.reg, r, v, mask[0], mask[1]);
- if(p->as == ASLWCC || p->as == ASRWCC)
- o1 |= 1; /* Rc */
- break;
-
- case 58: /* logical $andcon,[s],a */
- v = regoff(ctxt, &p->from);
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- o1 = LOP_IRR(opirr(ctxt, p->as), p->to.reg, r, v);
- break;
-
- case 59: /* or/and $ucon,,r */
- v = regoff(ctxt, &p->from);
- r = p->reg;
- if(r == 0)
- r = p->to.reg;
- o1 = LOP_IRR(opirr(ctxt, p->as+ALAST), p->to.reg, r, v>>16); /* oris, xoris, andis */
- break;
-
- case 60: /* tw to,a,b */
- r = regoff(ctxt, &p->from)&31L;
- o1 = AOP_RRR(oprrr(ctxt, p->as), r, p->reg, p->to.reg);
- break;
-
- case 61: /* tw to,a,$simm */
- r = regoff(ctxt, &p->from)&31L;
- v = regoff(ctxt, &p->to);
- o1 = AOP_IRR(opirr(ctxt, p->as), r, p->reg, v);
- break;
-
- case 62: /* rlwmi $sh,s,$mask,a */
- v = regoff(ctxt, &p->from);
- maskgen(ctxt, p, mask, regoff(ctxt, &p->from3));
- o1 = AOP_RRR(opirr(ctxt, p->as), p->reg, p->to.reg, v);
- o1 |= ((mask[0]&31L)<<6)|((mask[1]&31L)<<1);
- break;
-
- case 63: /* rlwmi b,s,$mask,a */
- maskgen(ctxt, p, mask, regoff(ctxt, &p->from3));
- o1 = AOP_RRR(opirr(ctxt, p->as), p->reg, p->to.reg, p->from.reg);
- o1 |= ((mask[0]&31L)<<6)|((mask[1]&31L)<<1);
- break;
-
- case 64: /* mtfsf fr[, $m] {,fpcsr} */
- if(p->from3.type != TYPE_NONE)
- v = regoff(ctxt, &p->from3)&255L;
- else
- v = 255;
- o1 = OP_MTFSF | (v<<17) | (p->from.reg<<11);
- break;
-
- case 65: /* MOVFL $imm,FPSCR(n) => mtfsfi crfd,imm */
- if(p->to.reg == 0)
- ctxt->diag("must specify FPSCR(n)\n%P", p);
- o1 = OP_MTFSFI | ((p->to.reg&15L)<<23) | ((regoff(ctxt, &p->from)&31L)<<12);
- break;
-
- case 66: /* mov spr,r1; mov r1,spr, also dcr */
- if(REG_R0 <= p->from.reg && p->from.reg <= REG_R31) {
- r = p->from.reg;
- v = p->to.reg;
- if(REG_DCR0 <= v && v <= REG_DCR0+1023)
- o1 = OPVCC(31,451,0,0); /* mtdcr */
- else
- o1 = OPVCC(31,467,0,0); /* mtspr */
- } else {
- r = p->to.reg;
- v = p->from.reg;
- if(REG_DCR0 <= v && v <= REG_DCR0+1023)
- o1 = OPVCC(31,323,0,0); /* mfdcr */
- else
- o1 = OPVCC(31,339,0,0); /* mfspr */
- }
- o1 = AOP_RRR(o1, r, 0, 0) | ((v&0x1f)<<16) | (((v>>5)&0x1f)<<11);
- break;
-
- case 67: /* mcrf crfD,crfS */
- if(p->from.type != TYPE_REG || p->from.reg < REG_C0 || REG_C7 < p->from.reg ||
- p->to.type != TYPE_REG || p->to.reg < REG_C0 || REG_C7 < p->to.reg)
- ctxt->diag("illegal CR field number\n%P", p);
- o1 = AOP_RRR(OP_MCRF, ((p->to.reg&7L)<<2), ((p->from.reg&7)<<2), 0);
- break;
-
- case 68: /* mfcr rD; mfocrf CRM,rD */
- if(p->from.type == TYPE_REG && REG_C0 <= p->from.reg && p->from.reg <= REG_C7) {
- v = 1<<(7-(p->to.reg&7)); /* CR(n) */
- o1 = AOP_RRR(OP_MFCR, p->to.reg, 0, 0) | (1<<20) | (v<<12); /* new form, mfocrf */
- }else
- o1 = AOP_RRR(OP_MFCR, p->to.reg, 0, 0); /* old form, whole register */
- break;
-
- case 69: /* mtcrf CRM,rS */
- if(p->from3.type != TYPE_NONE) {
- if(p->to.reg != 0)
- ctxt->diag("can't use both mask and CR(n)\n%P", p);
- v = regoff(ctxt, &p->from3) & 0xff;
- } else {
- if(p->to.reg == 0)
- v = 0xff; /* CR */
- else
- v = 1<<(7-(p->to.reg&7)); /* CR(n) */
- }
- o1 = AOP_RRR(OP_MTCRF, p->from.reg, 0, 0) | (v<<12);
- break;
-
- case 70: /* [f]cmp r,r,cr*/
- if(p->reg == 0)
- r = 0;
- else
- r = (p->reg&7)<<2;
- o1 = AOP_RRR(oprrr(ctxt, p->as), r, p->from.reg, p->to.reg);
- break;
-
- case 71: /* cmp[l] r,i,cr*/
- if(p->reg == 0)
- r = 0;
- else
- r = (p->reg&7)<<2;
- o1 = AOP_RRR(opirr(ctxt, p->as), r, p->from.reg, 0) | (regoff(ctxt, &p->to)&0xffff);
- break;
-
- case 72: /* slbmte (Rb+Rs -> slb[Rb]) -> Rs, Rb */
- o1 = AOP_RRR(oprrr(ctxt, p->as), p->from.reg, 0, p->to.reg);
- break;
-
- case 73: /* mcrfs crfD,crfS */
- if(p->from.type != TYPE_REG || p->from.reg != REG_FPSCR ||
- p->to.type != TYPE_REG || p->to.reg < REG_C0 || REG_C7 < p->to.reg)
- ctxt->diag("illegal FPSCR/CR field number\n%P", p);
- o1 = AOP_RRR(OP_MCRFS, ((p->to.reg&7L)<<2), ((0&7)<<2), 0);
- break;
-
- case 77: /* syscall $scon, syscall Rx */
- if(p->from.type == TYPE_CONST) {
- if(p->from.offset > BIG || p->from.offset < -BIG)
- ctxt->diag("illegal syscall, sysnum too large: %P", p);
- o1 = AOP_IRR(OP_ADDI, REGZERO, REGZERO, p->from.offset);
- } else if(p->from.type == TYPE_REG) {
- o1 = LOP_RRR(OP_OR, REGZERO, p->from.reg, p->from.reg);
- } else {
- ctxt->diag("illegal syscall: %P", p);
- o1 = 0x7fe00008; // trap always
- }
- o2 = oprrr(ctxt, p->as);
- o3 = AOP_RRR(oprrr(ctxt, AXOR), REGZERO, REGZERO, REGZERO); // XOR R0, R0
- break;
-
- case 78: /* undef */
- o1 = 0; /* "An instruction consisting entirely of binary 0s is guaranteed
- always to be an illegal instruction." */
- break;
-
- /* relocation operations */
-
- case 74:
- v = regoff(ctxt, &p->to);
- o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, high16adjusted(v));
- o2 = AOP_IRR(opstore(ctxt, p->as), p->from.reg, REGTMP, v);
- addaddrreloc(ctxt, p->to.sym, &o1, &o2);
- //if(dlm) reloc(&p->to, p->pc, 1);
- break;
-
- case 75:
- v = regoff(ctxt, &p->from);
- o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, high16adjusted(v));
- o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
- addaddrreloc(ctxt, p->from.sym, &o1, &o2);
- //if(dlm) reloc(&p->from, p->pc, 1);
- break;
-
- case 76:
- v = regoff(ctxt, &p->from);
- o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, high16adjusted(v));
- o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v);
- addaddrreloc(ctxt, p->from.sym, &o1, &o2);
- o3 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0);
- //if(dlm) reloc(&p->from, p->pc, 1);
- break;
-
- }
-
- out[0] = o1;
- out[1] = o2;
- out[2] = o3;
- out[3] = o4;
- out[4] = o5;
- return;
-}
-
-static vlong
-vregoff(Link *ctxt, Addr *a)
-{
-
- ctxt->instoffset = 0;
- aclass(ctxt, a);
- return ctxt->instoffset;
-}
-
-static int32
-regoff(Link *ctxt, Addr *a)
-{
- return vregoff(ctxt, a);
-}
-
-static int32
-oprrr(Link *ctxt, int a)
-{
- switch(a) {
- case AADD: return OPVCC(31,266,0,0);
- case AADDCC: return OPVCC(31,266,0,1);
- case AADDV: return OPVCC(31,266,1,0);
- case AADDVCC: return OPVCC(31,266,1,1);
- case AADDC: return OPVCC(31,10,0,0);
- case AADDCCC: return OPVCC(31,10,0,1);
- case AADDCV: return OPVCC(31,10,1,0);
- case AADDCVCC: return OPVCC(31,10,1,1);
- case AADDE: return OPVCC(31,138,0,0);
- case AADDECC: return OPVCC(31,138,0,1);
- case AADDEV: return OPVCC(31,138,1,0);
- case AADDEVCC: return OPVCC(31,138,1,1);
- case AADDME: return OPVCC(31,234,0,0);
- case AADDMECC: return OPVCC(31,234,0,1);
- case AADDMEV: return OPVCC(31,234,1,0);
- case AADDMEVCC: return OPVCC(31,234,1,1);
- case AADDZE: return OPVCC(31,202,0,0);
- case AADDZECC: return OPVCC(31,202,0,1);
- case AADDZEV: return OPVCC(31,202,1,0);
- case AADDZEVCC: return OPVCC(31,202,1,1);
-
- case AAND: return OPVCC(31,28,0,0);
- case AANDCC: return OPVCC(31,28,0,1);
- case AANDN: return OPVCC(31,60,0,0);
- case AANDNCC: return OPVCC(31,60,0,1);
-
- case ACMP: return OPVCC(31,0,0,0)|(1<<21); /* L=1 */
- case ACMPU: return OPVCC(31,32,0,0)|(1<<21);
- case ACMPW: return OPVCC(31,0,0,0); /* L=0 */
- case ACMPWU: return OPVCC(31,32,0,0);
-
- case ACNTLZW: return OPVCC(31,26,0,0);
- case ACNTLZWCC: return OPVCC(31,26,0,1);
- case ACNTLZD: return OPVCC(31,58,0,0);
- case ACNTLZDCC: return OPVCC(31,58,0,1);
-
- case ACRAND: return OPVCC(19,257,0,0);
- case ACRANDN: return OPVCC(19,129,0,0);
- case ACREQV: return OPVCC(19,289,0,0);
- case ACRNAND: return OPVCC(19,225,0,0);
- case ACRNOR: return OPVCC(19,33,0,0);
- case ACROR: return OPVCC(19,449,0,0);
- case ACRORN: return OPVCC(19,417,0,0);
- case ACRXOR: return OPVCC(19,193,0,0);
-
- case ADCBF: return OPVCC(31,86,0,0);
- case ADCBI: return OPVCC(31,470,0,0);
- case ADCBST: return OPVCC(31,54,0,0);
- case ADCBT: return OPVCC(31,278,0,0);
- case ADCBTST: return OPVCC(31,246,0,0);
- case ADCBZ: return OPVCC(31,1014,0,0);
-
- case AREM:
- case ADIVW: return OPVCC(31,491,0,0);
- case AREMCC:
- case ADIVWCC: return OPVCC(31,491,0,1);
- case AREMV:
- case ADIVWV: return OPVCC(31,491,1,0);
- case AREMVCC:
- case ADIVWVCC: return OPVCC(31,491,1,1);
- case AREMU:
- case ADIVWU: return OPVCC(31,459,0,0);
- case AREMUCC:
- case ADIVWUCC: return OPVCC(31,459,0,1);
- case AREMUV:
- case ADIVWUV: return OPVCC(31,459,1,0);
- case AREMUVCC:
- case ADIVWUVCC: return OPVCC(31,459,1,1);
-
- case AREMD:
- case ADIVD: return OPVCC(31,489,0,0);
- case AREMDCC:
- case ADIVDCC: return OPVCC(31,489,0,1);
- case AREMDV:
- case ADIVDV: return OPVCC(31,489,1,0);
- case AREMDVCC:
- case ADIVDVCC: return OPVCC(31,489,1,1);
- case AREMDU:
- case ADIVDU: return OPVCC(31,457,0,0);
- case AREMDUCC:
- case ADIVDUCC: return OPVCC(31,457,0,1);
- case AREMDUV:
- case ADIVDUV: return OPVCC(31,457,1,0);
- case AREMDUVCC:
- case ADIVDUVCC: return OPVCC(31,457,1,1);
-
- case AEIEIO: return OPVCC(31,854,0,0);
-
- case AEQV: return OPVCC(31,284,0,0);
- case AEQVCC: return OPVCC(31,284,0,1);
-
- case AEXTSB: return OPVCC(31,954,0,0);
- case AEXTSBCC: return OPVCC(31,954,0,1);
- case AEXTSH: return OPVCC(31,922,0,0);
- case AEXTSHCC: return OPVCC(31,922,0,1);
- case AEXTSW: return OPVCC(31,986,0,0);
- case AEXTSWCC: return OPVCC(31,986,0,1);
-
- case AFABS: return OPVCC(63,264,0,0);
- case AFABSCC: return OPVCC(63,264,0,1);
- case AFADD: return OPVCC(63,21,0,0);
- case AFADDCC: return OPVCC(63,21,0,1);
- case AFADDS: return OPVCC(59,21,0,0);
- case AFADDSCC: return OPVCC(59,21,0,1);
- case AFCMPO: return OPVCC(63,32,0,0);
- case AFCMPU: return OPVCC(63,0,0,0);
- case AFCFID: return OPVCC(63,846,0,0);
- case AFCFIDCC: return OPVCC(63,846,0,1);
- case AFCTIW: return OPVCC(63,14,0,0);
- case AFCTIWCC: return OPVCC(63,14,0,1);
- case AFCTIWZ: return OPVCC(63,15,0,0);
- case AFCTIWZCC: return OPVCC(63,15,0,1);
- case AFCTID: return OPVCC(63,814,0,0);
- case AFCTIDCC: return OPVCC(63,814,0,1);
- case AFCTIDZ: return OPVCC(63,815,0,0);
- case AFCTIDZCC: return OPVCC(63,815,0,1);
- case AFDIV: return OPVCC(63,18,0,0);
- case AFDIVCC: return OPVCC(63,18,0,1);
- case AFDIVS: return OPVCC(59,18,0,0);
- case AFDIVSCC: return OPVCC(59,18,0,1);
- case AFMADD: return OPVCC(63,29,0,0);
- case AFMADDCC: return OPVCC(63,29,0,1);
- case AFMADDS: return OPVCC(59,29,0,0);
- case AFMADDSCC: return OPVCC(59,29,0,1);
- case AFMOVS:
- case AFMOVD: return OPVCC(63,72,0,0); /* load */
- case AFMOVDCC: return OPVCC(63,72,0,1);
- case AFMSUB: return OPVCC(63,28,0,0);
- case AFMSUBCC: return OPVCC(63,28,0,1);
- case AFMSUBS: return OPVCC(59,28,0,0);
- case AFMSUBSCC: return OPVCC(59,28,0,1);
- case AFMUL: return OPVCC(63,25,0,0);
- case AFMULCC: return OPVCC(63,25,0,1);
- case AFMULS: return OPVCC(59,25,0,0);
- case AFMULSCC: return OPVCC(59,25,0,1);
- case AFNABS: return OPVCC(63,136,0,0);
- case AFNABSCC: return OPVCC(63,136,0,1);
- case AFNEG: return OPVCC(63,40,0,0);
- case AFNEGCC: return OPVCC(63,40,0,1);
- case AFNMADD: return OPVCC(63,31,0,0);
- case AFNMADDCC: return OPVCC(63,31,0,1);
- case AFNMADDS: return OPVCC(59,31,0,0);
- case AFNMADDSCC: return OPVCC(59,31,0,1);
- case AFNMSUB: return OPVCC(63,30,0,0);
- case AFNMSUBCC: return OPVCC(63,30,0,1);
- case AFNMSUBS: return OPVCC(59,30,0,0);
- case AFNMSUBSCC: return OPVCC(59,30,0,1);
- case AFRES: return OPVCC(59,24,0,0);
- case AFRESCC: return OPVCC(59,24,0,1);
- case AFRSP: return OPVCC(63,12,0,0);
- case AFRSPCC: return OPVCC(63,12,0,1);
- case AFRSQRTE: return OPVCC(63,26,0,0);
- case AFRSQRTECC: return OPVCC(63,26,0,1);
- case AFSEL: return OPVCC(63,23,0,0);
- case AFSELCC: return OPVCC(63,23,0,1);
- case AFSQRT: return OPVCC(63,22,0,0);
- case AFSQRTCC: return OPVCC(63,22,0,1);
- case AFSQRTS: return OPVCC(59,22,0,0);
- case AFSQRTSCC: return OPVCC(59,22,0,1);
- case AFSUB: return OPVCC(63,20,0,0);
- case AFSUBCC: return OPVCC(63,20,0,1);
- case AFSUBS: return OPVCC(59,20,0,0);
- case AFSUBSCC: return OPVCC(59,20,0,1);
-
- case AICBI: return OPVCC(31,982,0,0);
- case AISYNC: return OPVCC(19,150,0,0);
-
- case AMTFSB0: return OPVCC(63,70,0,0);
- case AMTFSB0CC: return OPVCC(63,70,0,1);
- case AMTFSB1: return OPVCC(63,38,0,0);
- case AMTFSB1CC: return OPVCC(63,38,0,1);
-
- case AMULHW: return OPVCC(31,75,0,0);
- case AMULHWCC: return OPVCC(31,75,0,1);
- case AMULHWU: return OPVCC(31,11,0,0);
- case AMULHWUCC: return OPVCC(31,11,0,1);
- case AMULLW: return OPVCC(31,235,0,0);
- case AMULLWCC: return OPVCC(31,235,0,1);
- case AMULLWV: return OPVCC(31,235,1,0);
- case AMULLWVCC: return OPVCC(31,235,1,1);
-
- case AMULHD: return OPVCC(31,73,0,0);
- case AMULHDCC: return OPVCC(31,73,0,1);
- case AMULHDU: return OPVCC(31,9,0,0);
- case AMULHDUCC: return OPVCC(31,9,0,1);
- case AMULLD: return OPVCC(31,233,0,0);
- case AMULLDCC: return OPVCC(31,233,0,1);
- case AMULLDV: return OPVCC(31,233,1,0);
- case AMULLDVCC: return OPVCC(31,233,1,1);
-
- case ANAND: return OPVCC(31,476,0,0);
- case ANANDCC: return OPVCC(31,476,0,1);
- case ANEG: return OPVCC(31,104,0,0);
- case ANEGCC: return OPVCC(31,104,0,1);
- case ANEGV: return OPVCC(31,104,1,0);
- case ANEGVCC: return OPVCC(31,104,1,1);
- case ANOR: return OPVCC(31,124,0,0);
- case ANORCC: return OPVCC(31,124,0,1);
- case AOR: return OPVCC(31,444,0,0);
- case AORCC: return OPVCC(31,444,0,1);
- case AORN: return OPVCC(31,412,0,0);
- case AORNCC: return OPVCC(31,412,0,1);
-
- case ARFI: return OPVCC(19,50,0,0);
- case ARFCI: return OPVCC(19,51,0,0);
- case ARFID: return OPVCC(19,18,0,0);
- case AHRFID: return OPVCC(19,274,0,0);
-
- case ARLWMI: return OPVCC(20,0,0,0);
- case ARLWMICC: return OPVCC(20,0,0,1);
- case ARLWNM: return OPVCC(23,0,0,0);
- case ARLWNMCC: return OPVCC(23,0,0,1);
-
- case ARLDCL: return OPVCC(30,8,0,0);
- case ARLDCR: return OPVCC(30,9,0,0);
-
- case ASYSCALL: return OPVCC(17,1,0,0);
-
- case ASLW: return OPVCC(31,24,0,0);
- case ASLWCC: return OPVCC(31,24,0,1);
- case ASLD: return OPVCC(31,27,0,0);
- case ASLDCC: return OPVCC(31,27,0,1);
-
- case ASRAW: return OPVCC(31,792,0,0);
- case ASRAWCC: return OPVCC(31,792,0,1);
- case ASRAD: return OPVCC(31,794,0,0);
- case ASRADCC: return OPVCC(31,794,0,1);
-
- case ASRW: return OPVCC(31,536,0,0);
- case ASRWCC: return OPVCC(31,536,0,1);
- case ASRD: return OPVCC(31,539,0,0);
- case ASRDCC: return OPVCC(31,539,0,1);
-
- case ASUB: return OPVCC(31,40,0,0);
- case ASUBCC: return OPVCC(31,40,0,1);
- case ASUBV: return OPVCC(31,40,1,0);
- case ASUBVCC: return OPVCC(31,40,1,1);
- case ASUBC: return OPVCC(31,8,0,0);
- case ASUBCCC: return OPVCC(31,8,0,1);
- case ASUBCV: return OPVCC(31,8,1,0);
- case ASUBCVCC: return OPVCC(31,8,1,1);
- case ASUBE: return OPVCC(31,136,0,0);
- case ASUBECC: return OPVCC(31,136,0,1);
- case ASUBEV: return OPVCC(31,136,1,0);
- case ASUBEVCC: return OPVCC(31,136,1,1);
- case ASUBME: return OPVCC(31,232,0,0);
- case ASUBMECC: return OPVCC(31,232,0,1);
- case ASUBMEV: return OPVCC(31,232,1,0);
- case ASUBMEVCC: return OPVCC(31,232,1,1);
- case ASUBZE: return OPVCC(31,200,0,0);
- case ASUBZECC: return OPVCC(31,200,0,1);
- case ASUBZEV: return OPVCC(31,200,1,0);
- case ASUBZEVCC: return OPVCC(31,200,1,1);
-
- case ASYNC: return OPVCC(31,598,0,0);
- case APTESYNC: return OPVCC(31,598,0,0) | (2<<21);
-
- case ATLBIE: return OPVCC(31,306,0,0);
- case ATLBIEL: return OPVCC(31,274,0,0);
- case ATLBSYNC: return OPVCC(31,566,0,0);
- case ASLBIA: return OPVCC(31,498,0,0);
- case ASLBIE: return OPVCC(31,434,0,0);
- case ASLBMFEE: return OPVCC(31,915,0,0);
- case ASLBMFEV: return OPVCC(31,851,0,0);
- case ASLBMTE: return OPVCC(31,402,0,0);
-
- case ATW: return OPVCC(31,4,0,0);
- case ATD: return OPVCC(31,68,0,0);
-
- case AXOR: return OPVCC(31,316,0,0);
- case AXORCC: return OPVCC(31,316,0,1);
- }
- ctxt->diag("bad r/r opcode %A", a);
- return 0;
-}
-
-static int32
-opirr(Link *ctxt, int a)
-{
- switch(a) {
- case AADD: return OPVCC(14,0,0,0);
- case AADDC: return OPVCC(12,0,0,0);
- case AADDCCC: return OPVCC(13,0,0,0);
- case AADD+ALAST: return OPVCC(15,0,0,0); /* ADDIS/CAU */
-
- case AANDCC: return OPVCC(28,0,0,0);
- case AANDCC+ALAST: return OPVCC(29,0,0,0); /* ANDIS./ANDIU. */
-
- case ABR: return OPVCC(18,0,0,0);
- case ABL: return OPVCC(18,0,0,0) | 1;
- case ADUFFZERO: return OPVCC(18,0,0,0) | 1;
- case ADUFFCOPY: return OPVCC(18,0,0,0) | 1;
- case ABC: return OPVCC(16,0,0,0);
- case ABCL: return OPVCC(16,0,0,0) | 1;
-
- case ABEQ: return AOP_RRR(16<<26,12,2,0);
- case ABGE: return AOP_RRR(16<<26,4,0,0);
- case ABGT: return AOP_RRR(16<<26,12,1,0);
- case ABLE: return AOP_RRR(16<<26,4,1,0);
- case ABLT: return AOP_RRR(16<<26,12,0,0);
- case ABNE: return AOP_RRR(16<<26,4,2,0);
- case ABVC: return AOP_RRR(16<<26,4,3,0);
- case ABVS: return AOP_RRR(16<<26,12,3,0);
-
- case ACMP: return OPVCC(11,0,0,0)|(1<<21); /* L=1 */
- case ACMPU: return OPVCC(10,0,0,0)|(1<<21);
- case ACMPW: return OPVCC(11,0,0,0); /* L=0 */
- case ACMPWU: return OPVCC(10,0,0,0);
- case ALSW: return OPVCC(31,597,0,0);
-
- case AMULLW: return OPVCC(7,0,0,0);
-
- case AOR: return OPVCC(24,0,0,0);
- case AOR+ALAST: return OPVCC(25,0,0,0); /* ORIS/ORIU */
-
- case ARLWMI: return OPVCC(20,0,0,0); /* rlwimi */
- case ARLWMICC: return OPVCC(20,0,0,1);
- case ARLDMI: return OPVCC(30,0,0,0) | (3<<2); /* rldimi */
- case ARLDMICC: return OPVCC(30,0,0,1) | (3<<2);
-
- case ARLWNM: return OPVCC(21,0,0,0); /* rlwinm */
- case ARLWNMCC: return OPVCC(21,0,0,1);
-
- case ARLDCL: return OPVCC(30,0,0,0); /* rldicl */
- case ARLDCLCC: return OPVCC(30,0,0,1);
- case ARLDCR: return OPVCC(30,1,0,0); /* rldicr */
- case ARLDCRCC: return OPVCC(30,1,0,1);
- case ARLDC: return OPVCC(30,0,0,0) | (2<<2);
- case ARLDCCC: return OPVCC(30,0,0,1) | (2<<2);
-
- case ASRAW: return OPVCC(31,824,0,0);
- case ASRAWCC: return OPVCC(31,824,0,1);
- case ASRAD: return OPVCC(31,(413<<1),0,0);
- case ASRADCC: return OPVCC(31,(413<<1),0,1);
-
- case ASTSW: return OPVCC(31,725,0,0);
-
- case ASUBC: return OPVCC(8,0,0,0);
-
- case ATW: return OPVCC(3,0,0,0);
- case ATD: return OPVCC(2,0,0,0);
-
- case AXOR: return OPVCC(26,0,0,0); /* XORIL */
- case AXOR+ALAST: return OPVCC(27,0,0,0); /* XORIU */
- }
- ctxt->diag("bad opcode i/r %A", a);
- return 0;
-}
-
-/*
- * load o(a),d
- */
-static int32
-opload(Link *ctxt, int a)
-{
- switch(a) {
- case AMOVD: return OPVCC(58,0,0,0); /* ld */
- case AMOVDU: return OPVCC(58,0,0,1); /* ldu */
- case AMOVWZ: return OPVCC(32,0,0,0); /* lwz */
- case AMOVWZU: return OPVCC(33,0,0,0); /* lwzu */
- case AMOVW: return OPVCC(58,0,0,0)|(1<<1); /* lwa */
- /* no AMOVWU */
- case AMOVB:
- case AMOVBZ: return OPVCC(34,0,0,0); /* load */
- case AMOVBU:
- case AMOVBZU: return OPVCC(35,0,0,0);
- case AFMOVD: return OPVCC(50,0,0,0);
- case AFMOVDU: return OPVCC(51,0,0,0);
- case AFMOVS: return OPVCC(48,0,0,0);
- case AFMOVSU: return OPVCC(49,0,0,0);
- case AMOVH: return OPVCC(42,0,0,0);
- case AMOVHU: return OPVCC(43,0,0,0);
- case AMOVHZ: return OPVCC(40,0,0,0);
- case AMOVHZU: return OPVCC(41,0,0,0);
- case AMOVMW: return OPVCC(46,0,0,0); /* lmw */
- }
- ctxt->diag("bad load opcode %A", a);
- return 0;
-}
-
-/*
- * indexed load a(b),d
- */
-static int32
-oploadx(Link *ctxt, int a)
-{
- switch(a) {
- case AMOVWZ: return OPVCC(31,23,0,0); /* lwzx */
- case AMOVWZU: return OPVCC(31,55,0,0); /* lwzux */
- case AMOVW: return OPVCC(31,341,0,0); /* lwax */
- case AMOVWU: return OPVCC(31,373,0,0); /* lwaux */
- case AMOVB:
- case AMOVBZ: return OPVCC(31,87,0,0); /* lbzx */
- case AMOVBU:
- case AMOVBZU: return OPVCC(31,119,0,0); /* lbzux */
- case AFMOVD: return OPVCC(31,599,0,0); /* lfdx */
- case AFMOVDU: return OPVCC(31,631,0,0); /* lfdux */
- case AFMOVS: return OPVCC(31,535,0,0); /* lfsx */
- case AFMOVSU: return OPVCC(31,567,0,0); /* lfsux */
- case AMOVH: return OPVCC(31,343,0,0); /* lhax */
- case AMOVHU: return OPVCC(31,375,0,0); /* lhaux */
- case AMOVHBR: return OPVCC(31,790,0,0); /* lhbrx */
- case AMOVWBR: return OPVCC(31,534,0,0); /* lwbrx */
- case AMOVHZ: return OPVCC(31,279,0,0); /* lhzx */
- case AMOVHZU: return OPVCC(31,311,0,0); /* lhzux */
- case AECIWX: return OPVCC(31,310,0,0); /* eciwx */
- case ALWAR: return OPVCC(31,20,0,0); /* lwarx */
- case ALDAR: return OPVCC(31,84,0,0);
- case ALSW: return OPVCC(31,533,0,0); /* lswx */
- case AMOVD: return OPVCC(31,21,0,0); /* ldx */
- case AMOVDU: return OPVCC(31,53,0,0); /* ldux */
- }
- ctxt->diag("bad loadx opcode %A", a);
- return 0;
-}
-
-/*
- * store s,o(d)
- */
-static int32
-opstore(Link *ctxt, int a)
-{
- switch(a) {
- case AMOVB:
- case AMOVBZ: return OPVCC(38,0,0,0); /* stb */
- case AMOVBU:
- case AMOVBZU: return OPVCC(39,0,0,0); /* stbu */
- case AFMOVD: return OPVCC(54,0,0,0); /* stfd */
- case AFMOVDU: return OPVCC(55,0,0,0); /* stfdu */
- case AFMOVS: return OPVCC(52,0,0,0); /* stfs */
- case AFMOVSU: return OPVCC(53,0,0,0); /* stfsu */
- case AMOVHZ:
- case AMOVH: return OPVCC(44,0,0,0); /* sth */
- case AMOVHZU:
- case AMOVHU: return OPVCC(45,0,0,0); /* sthu */
- case AMOVMW: return OPVCC(47,0,0,0); /* stmw */
- case ASTSW: return OPVCC(31,725,0,0); /* stswi */
- case AMOVWZ:
- case AMOVW: return OPVCC(36,0,0,0); /* stw */
- case AMOVWZU:
- case AMOVWU: return OPVCC(37,0,0,0); /* stwu */
- case AMOVD: return OPVCC(62,0,0,0); /* std */
- case AMOVDU: return OPVCC(62,0,0,1); /* stdu */
- }
- ctxt->diag("unknown store opcode %A", a);
- return 0;
-}
-
-/*
- * indexed store s,a(b)
- */
-static int32
-opstorex(Link *ctxt, int a)
-{
- switch(a) {
- case AMOVB:
- case AMOVBZ: return OPVCC(31,215,0,0); /* stbx */
- case AMOVBU:
- case AMOVBZU: return OPVCC(31,247,0,0); /* stbux */
- case AFMOVD: return OPVCC(31,727,0,0); /* stfdx */
- case AFMOVDU: return OPVCC(31,759,0,0); /* stfdux */
- case AFMOVS: return OPVCC(31,663,0,0); /* stfsx */
- case AFMOVSU: return OPVCC(31,695,0,0); /* stfsux */
- case AMOVHZ:
- case AMOVH: return OPVCC(31,407,0,0); /* sthx */
- case AMOVHBR: return OPVCC(31,918,0,0); /* sthbrx */
- case AMOVHZU:
- case AMOVHU: return OPVCC(31,439,0,0); /* sthux */
- case AMOVWZ:
- case AMOVW: return OPVCC(31,151,0,0); /* stwx */
- case AMOVWZU:
- case AMOVWU: return OPVCC(31,183,0,0); /* stwux */
- case ASTSW: return OPVCC(31,661,0,0); /* stswx */
- case AMOVWBR: return OPVCC(31,662,0,0); /* stwbrx */
- case ASTWCCC: return OPVCC(31,150,0,1); /* stwcx. */
- case ASTDCCC: return OPVCC(31,214,0,1); /* stwdx. */
- case AECOWX: return OPVCC(31,438,0,0); /* ecowx */
- case AMOVD: return OPVCC(31,149,0,0); /* stdx */
- case AMOVDU: return OPVCC(31,181,0,0); /* stdux */
- }
- ctxt->diag("unknown storex opcode %A", a);
- return 0;
-}
-
#include <bio.h>
#include <link.h>
-void
-mangle(char *file)
-{
- sysfatal("%s: mangled input file", file);
-}
void
symgrow(Link *ctxt, LSym *s, vlong lsiz)
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 = p->from3.offset;
- if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
- mangle(pn);
- if(ctxt->enforce_data_order && off < s->np)
- ctxt->diag("data out of order (already have %d)\n%P", p);
- symgrow(ctxt, s, off+siz);
-
- if(p->to.type == TYPE_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 == TYPE_SCONST) {
- for(i=0; i<siz; i++)
- s->p[off+i] = p->to.u.sval[i];
- } else if(p->to.type == TYPE_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 == TYPE_ADDR) {
- addr:
- r = addrel(s);
- r->off = off;
- r->siz = siz;
- r->sym = p->to.sym;
- r->type = R_ADDR;
- r->add = p->to.offset;
- } else {
- ctxt->diag("bad data: %P", p);
- }
-}
Reloc*
addrel(LSym *s)
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)
#include <bio.h>
#include <link.h>
-int framepointer_enabled;
-int fieldtrack_enabled;
-Prog zprog;
-
-// Toolchain experiments.
-// These are controlled by the GOEXPERIMENT environment
-// variable recorded when the toolchain is built.
-// This list is also known to cmd/gc.
-static struct {
- char *name;
- int *val;
-} exper[] = {
- {"fieldtrack", &fieldtrack_enabled},
- {"framepointer", &framepointer_enabled},
-};
-
-static void
-addexp(char *s)
-{
- int i;
-
- for(i=0; i < nelem(exper); i++ ) {
- if(strcmp(exper[i].name, s) == 0) {
- if(exper[i].val != nil)
- *exper[i].val = 1;
- return;
- }
- }
-
- print("unknown experiment %s\n", s);
- exits("unknown experiment");
-}
-
-void
-linksetexp(void)
-{
- char *f[20];
- int i, nf;
-
- // cmd/dist #defines GOEXPERIMENT for us.
- nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ",");
- for(i=0; i<nf; i++)
- addexp(f[i]);
-}
-
-char*
-expstring(void)
-{
- int i;
- static char buf[512];
-
- strcpy(buf, "X");
- for(i=0; i<nelem(exper); i++)
- if(*exper[i].val)
- seprint(buf+strlen(buf), buf+sizeof buf, ",%s", exper[i].name);
- if(strlen(buf) == 1)
- strcpy(buf, "X,none");
- buf[1] = ':';
- return buf;
-}
-
// replace all "". with pkg.
char*
expandpkg(char *t0, char *pkg)
return p;
}
-void
-double2ieee(uint64 *ieee, float64 f)
-{
- memmove(ieee, &f, 8);
-}
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->scond = zprog.scond;
- p->from = zprog.from;
- p->from3 = zprog.from3;
- p->reg = zprog.reg;
- p->to = zprog.to;
-}
-void
-nocache(Prog *p)
-{
- p->optab = 0;
- p->from.class = 0;
- p->from3.class = 0;
- p->to.class = 0;
-}
uchar inuxi4[4];
uchar inuxi8[8];
-enum
-{
- 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;
-
- USED(ctxt);
- p = emallocz(sizeof(Prog));
- *p = *q;
- return p;
-}
-
-Prog*
-appendp(Link *ctxt, Prog *q)
-{
- Prog *p;
-
- USED(ctxt);
- p = emallocz(sizeof(Prog));
- p->link = q->link;
- q->link = p;
- p->lineno = q->lineno;
- p->mode = q->mode;
- return p;
-}
vlong
atolwhex(char *s)
+++ /dev/null
-// Inferno utils/5c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/5l/5.out.h"
-#include "../runtime/funcdata.h"
-
-enum
-{
- STRINGSZ = 1000
-};
-
-static int Aconv(Fmt *fp);
-static int Dconv(Fmt *fp);
-static int Mconv(Fmt *fp);
-static int Pconv(Fmt *fp);
-static int Rconv(Fmt *fp);
-static int RAconv(Fmt *fp);
-static int DSconv(Fmt *fp);
-static int DRconv(Fmt*);
-
-#pragma varargck type "$" char*
-#pragma varargck type "M" Addr*
-#pragma varargck type "@" Addr*
-
-void
-listinit5(void)
-{
- fmtinstall('A', Aconv);
- fmtinstall('D', Dconv);
- fmtinstall('P', Pconv);
- fmtinstall('R', Rconv);
-
- // for liblink internal use
- fmtinstall('^', DRconv);
-
- // for internal use
- fmtinstall('$', DSconv);
- fmtinstall('M', Mconv);
- fmtinstall('@', RAconv);
-}
-
-static char *extra [] = {
- ".EQ", ".NE", ".CS", ".CC",
- ".MI", ".PL", ".VS", ".VC",
- ".HI", ".LS", ".GE", ".LT",
- ".GT", ".LE", "", ".NV",
-};
-
-static Prog* bigP;
-
-static int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ], sc[20];
- Prog *p;
- int a, s;
-
- p = va_arg(fp->args, Prog*);
- bigP = p;
- a = p->as;
- s = p->scond;
- strcpy(sc, extra[(s & C_SCOND) ^ C_SCOND_XOR]);
- if(s & C_SBIT)
- strcat(sc, ".S");
- if(s & C_PBIT)
- strcat(sc, ".P");
- if(s & C_WBIT)
- strcat(sc, ".W");
- if(s & C_UBIT) /* ambiguous with FBIT */
- strcat(sc, ".U");
- if(a == AMOVM) {
- if(p->from.type == TYPE_CONST)
- sprint(str, "%.5lld (%L) %A%s %@,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
- else
- if(p->to.type == TYPE_CONST)
- sprint(str, "%.5lld (%L) %A%s %D,%@", p->pc, p->lineno, a, sc, &p->from, &p->to);
- else
- sprint(str, "%.5lld (%L) %A%s %D,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
- } else
- if(a == ADATA)
- sprint(str, "%.5lld (%L) %A %D/%lld,%D", p->pc, p->lineno, a, &p->from, p->from3.offset, &p->to);
- else
- if(p->as == ATEXT)
- sprint(str, "%.5lld (%L) %A %D,%lld,%D", p->pc, p->lineno, a, &p->from, p->from3.offset, &p->to);
- else
- if(p->reg == 0)
- sprint(str, "%.5lld (%L) %A%s %D,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
- else
- sprint(str, "%.5lld (%L) %A%s %D,%R,%D", p->pc, p->lineno, a, sc, &p->from, p->reg, &p->to);
- bigP = nil;
- return fmtstrcpy(fp, str);
-}
-
-static int
-Aconv(Fmt *fp)
-{
- char *s;
- int a;
-
- a = va_arg(fp->args, int);
- s = "???";
- if(a >= AXXX && a < ALAST)
- s = anames5[a];
- return fmtstrcpy(fp, s);
-}
-
-static int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Addr *a;
- const char *op;
- int v;
-
- a = va_arg(fp->args, Addr*);
- switch(a->type) {
-
- default:
- sprint(str, "GOK-type(%d)", a->type);
- break;
-
- case TYPE_NONE:
- str[0] = 0;
- if(a->name != TYPE_NONE || a->reg != 0 || a->sym != nil)
- sprint(str, "%M(%R)(NONE)", a, a->reg);
- break;
-
- case TYPE_CONST:
- case TYPE_ADDR:
- if(a->reg != 0)
- sprint(str, "$%M(%R)", a, a->reg);
- else
- sprint(str, "$%M", a);
- break;
-
- case TYPE_TEXTSIZE:
- if(a->u.argsize == ArgsSizeUnknown)
- sprint(str, "$%lld", a->offset);
- else
- sprint(str, "$%lld-%d", a->offset, a->u.argsize);
- break;
-
- case TYPE_SHIFT:
- v = a->offset;
- op = &"<<>>->@>"[(((v>>5) & 3) << 1)];
- if(v & (1<<4))
- sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
- else
- sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
- if(a->reg != 0)
- sprint(str+strlen(str), "(%R)", a->reg);
- break;
-
- case TYPE_MEM:
- if(a->reg != 0)
- sprint(str, "%M(%R)", a, a->reg);
- else
- sprint(str, "%M", a);
- break;
-
- case TYPE_REG:
- sprint(str, "%R", a->reg);
- if(a->name != TYPE_NONE || a->sym != nil)
- sprint(str, "%M(%R)(REG)", a, a->reg);
- break;
-
- case TYPE_BRANCH:
- if(a->sym != nil)
- sprint(str, "%s(SB)", a->sym->name);
- else if(bigP != nil && bigP->pcond != nil)
- sprint(str, "%lld", bigP->pcond->pc);
- else if(a->u.branch != nil)
- sprint(str, "%lld", a->u.branch->pc);
- else
- sprint(str, "%lld(PC)", a->offset/*-pc*/);
- break;
-
- case TYPE_FCONST:
- sprint(str, "$%.17g", a->u.dval);
- break;
-
- case TYPE_SCONST:
- sprint(str, "$\"%$\"", a->u.sval);
- break;
-
- case TYPE_REGREG:
- sprint(str, "(%R, %R)", a->reg, (int)a->offset);
- break;
-
- case TYPE_REGREG2:
- sprint(str, "%R, %R", a->reg, (int)a->offset);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-static int
-RAconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Addr *a;
- int i, v;
-
- a = va_arg(fp->args, Addr*);
- sprint(str, "GOK-reglist");
- switch(a->type) {
- case TYPE_CONST:
- if(a->reg != 0)
- break;
- if(a->sym != nil)
- break;
- v = a->offset;
- strcpy(str, "");
- for(i=0; i<NREG; i++) {
- if(v & (1<<i)) {
- if(str[0] == 0)
- strcat(str, "[R");
- else
- strcat(str, ",R");
- sprint(strchr(str, 0), "%d", i);
- }
- }
- strcat(str, "]");
- }
- return fmtstrcpy(fp, str);
-}
-
-static int
-DSconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<NSNAME; i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9' ||
- c == ' ' || c == '%') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- case 0:
- *p++ = 'z';
- continue;
- case '\\':
- case '"':
- *p++ = c;
- continue;
- case '\n':
- *p++ = 'n';
- continue;
- case '\t':
- *p++ = 't';
- continue;
- case '\r':
- *p++ = 'r';
- continue;
- case '\f':
- *p++ = 'f';
- continue;
- }
- *p++ = (c>>6) + '0';
- *p++ = ((c>>3) & 7) + '0';
- *p++ = (c & 7) + '0';
- }
- *p = 0;
- return fmtstrcpy(fp, str);
-}
-
-static int
-Rconv(Fmt *fp)
-{
- int r;
-
- r = va_arg(fp->args, int);
- if(r == 0)
- return fmtstrcpy(fp, "NONE");
- if(REG_R0 <= r && r <= REG_R15)
- return fmtprint(fp, "R%d", r-REG_R0);
- if(REG_F0 <= r && r <= REG_F15)
- return fmtprint(fp, "F%d", r-REG_F0);
-
- switch(r) {
- case REG_FPSR:
- return fmtstrcpy(fp, "FPSR");
- case REG_FPCR:
- return fmtstrcpy(fp, "FPCR");
- case REG_CPSR:
- return fmtstrcpy(fp, "CPSR");
- case REG_SPSR:
- return fmtstrcpy(fp, "SPSR");
- }
-
- return fmtprint(fp, "badreg(%d)", r);
-}
-
-static int
-DRconv(Fmt *fp)
-{
- char *s;
- int a;
-
- a = va_arg(fp->args, int);
- s = "C_??";
- if(a >= C_NONE && a <= C_NCLASS)
- s = cnames5[a];
- return fmtstrcpy(fp, s);
-}
-
-static int
-Mconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Addr *a;
- LSym *s;
-
- a = va_arg(fp->args, Addr*);
- s = a->sym;
- if(s == nil) {
- sprint(str, "%d", (int)a->offset);
- goto out;
- }
- switch(a->name) {
- default:
- sprint(str, "GOK-name(%d)", a->name);
- break;
-
- case NAME_NONE:
- sprint(str, "%lld", a->offset);
- break;
-
- case NAME_EXTERN:
- sprint(str, "%s+%d(SB)", s->name, (int)a->offset);
- break;
-
- case NAME_STATIC:
- sprint(str, "%s<>+%d(SB)", s->name, (int)a->offset);
- break;
-
- case NAME_AUTO:
- sprint(str, "%s-%d(SP)", s->name, (int)-a->offset);
- break;
-
- case NAME_PARAM:
- sprint(str, "%s+%d(FP)", s->name, (int)a->offset);
- break;
- }
-out:
- return fmtstrcpy(fp, str);
-}
+++ /dev/null
-// Inferno utils/6c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/6l/6.out.h"
-#include "../runtime/funcdata.h"
-
-//
-// Format conversions
-// %A int Opcodes (instruction mnemonics)
-//
-// %D Addr* Addresses (instruction operands)
-//
-// %P Prog* Instructions
-//
-// %R int Registers
-//
-// %$ char* String constant addresses (for internal use only)
-
-static int Aconv(Fmt *fp);
-static int Dconv(Fmt *fp);
-static int Pconv(Fmt *fp);
-static int Rconv(Fmt *fp);
-static int DSconv(Fmt *fp);
-
-enum
-{
- STRINGSZ = 1000
-};
-
-#pragma varargck type "$" char*
-
-void
-listinit6(void)
-{
- fmtinstall('A', Aconv);
- fmtinstall('D', Dconv);
- fmtinstall('P', Pconv);
- fmtinstall('R', Rconv);
-
- // for internal use
- fmtinstall('$', DSconv);
-}
-
-static Prog* bigP;
-
-static int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Prog *p;
-
- p = va_arg(fp->args, Prog*);
- bigP = p;
-
- switch(p->as) {
- case ADATA:
- sprint(str, "%.5lld (%L) %A %D/%lld,%D",
- p->pc, p->lineno, p->as, &p->from, p->from3.offset, &p->to);
- break;
-
- case ATEXT:
- if(p->from3.offset) {
- sprint(str, "%.5lld (%L) %A %D,%lld,%D",
- p->pc, p->lineno, p->as, &p->from, p->from3.offset, &p->to);
- break;
- }
- sprint(str, "%.5lld (%L) %A %D,%D",
- p->pc, p->lineno, p->as, &p->from, &p->to);
- break;
-
- default:
- sprint(str, "%.5lld (%L) %A %D,%D",
- p->pc, p->lineno, p->as, &p->from, &p->to);
- // TODO(rsc): This special case is for SHRQ $32, AX:DX, which encodes as
- // SHRQ $32(DX*0), AX
- // Remove.
- if((p->from.type == TYPE_REG || p->from.type == TYPE_CONST) && p->from.index != REG_NONE)
- sprint(strchr(str, 0), ":%R", p->from.index);
- break;
- }
- bigP = nil;
- return fmtstrcpy(fp, str);
-}
-
-static int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames6[i]);
-}
-
-static int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Addr *a;
-
- a = va_arg(fp->args, Addr*);
-
- switch(a->type) {
- default:
- sprint(str, "type=%d", a->type);
- break;
-
- case TYPE_NONE:
- str[0] = 0;
- break;
-
- case TYPE_REG:
- // TODO(rsc): This special case is for instructions like
- // PINSRQ CX,$1,X6
- // where the $1 is included in the p->to Addr.
- // Move into a new field.
- if(a->offset != 0) {
- sprint(str, "$%lld,%R", a->offset, a->reg);
- break;
- }
- sprint(str, "%R", a->reg);
- break;
-
- case TYPE_BRANCH:
- if(a->sym != nil)
- sprint(str, "%s(SB)", a->sym->name);
- else if(bigP != nil && bigP->pcond != nil)
- sprint(str, "%lld", bigP->pcond->pc);
- else if(a->u.branch != nil)
- sprint(str, "%lld", a->u.branch->pc);
- else
- sprint(str, "%lld(PC)", a->offset);
- break;
-
- case TYPE_MEM:
- switch(a->name) {
- default:
- sprint(str, "name=%d", a->name);
- break;
- case NAME_NONE:
- if(a->offset)
- sprint(str, "%lld(%R)", a->offset, a->reg);
- else
- sprint(str, "(%R)", a->reg);
- break;
- case NAME_EXTERN:
- sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
- break;
- case NAME_STATIC:
- sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
- break;
- case NAME_AUTO:
- if(a->sym)
- sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
- else
- sprint(str, "%lld(SP)", a->offset);
- break;
- case NAME_PARAM:
- if(a->sym)
- sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
- else
- sprint(str, "%lld(FP)", a->offset);
- break;
- }
- if(a->index != REG_NONE) {
- sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
- strcat(str, s);
- }
- break;
-
- case TYPE_CONST:
- sprint(str, "$%lld", a->offset);
- break;
-
- case TYPE_TEXTSIZE:
- if(a->u.argsize == ArgsSizeUnknown)
- sprint(str, "$%lld", a->offset);
- else
- sprint(str, "$%lld-%d", a->offset, a->u.argsize);
- break;
-
- case TYPE_FCONST:
- sprint(str, "$(%.17g)", a->u.dval);
- break;
-
- case TYPE_SCONST:
- sprint(str, "$\"%$\"", a->u.sval);
- break;
-
- case TYPE_ADDR:
- a->type = TYPE_MEM;
- sprint(str, "$%D", a);
- a->type = TYPE_ADDR;
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-static char* regstr[] =
-{
- "AL", /* [D_AL] */
- "CL",
- "DL",
- "BL",
- "SPB",
- "BPB",
- "SIB",
- "DIB",
- "R8B",
- "R9B",
- "R10B",
- "R11B",
- "R12B",
- "R13B",
- "R14B",
- "R15B",
-
- "AX", /* [D_AX] */
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
- "R8",
- "R9",
- "R10",
- "R11",
- "R12",
- "R13",
- "R14",
- "R15",
-
- "AH",
- "CH",
- "DH",
- "BH",
-
- "F0", /* [D_F0] */
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
-
- "M0",
- "M1",
- "M2",
- "M3",
- "M4",
- "M5",
- "M6",
- "M7",
-
- "X0",
- "X1",
- "X2",
- "X3",
- "X4",
- "X5",
- "X6",
- "X7",
- "X8",
- "X9",
- "X10",
- "X11",
- "X12",
- "X13",
- "X14",
- "X15",
-
- "CS", /* [D_CS] */
- "SS",
- "DS",
- "ES",
- "FS",
- "GS",
-
- "GDTR", /* [D_GDTR] */
- "IDTR", /* [D_IDTR] */
- "LDTR", /* [D_LDTR] */
- "MSW", /* [D_MSW] */
- "TASK", /* [D_TASK] */
-
- "CR0", /* [D_CR] */
- "CR1",
- "CR2",
- "CR3",
- "CR4",
- "CR5",
- "CR6",
- "CR7",
- "CR8",
- "CR9",
- "CR10",
- "CR11",
- "CR12",
- "CR13",
- "CR14",
- "CR15",
-
- "DR0", /* [D_DR] */
- "DR1",
- "DR2",
- "DR3",
- "DR4",
- "DR5",
- "DR6",
- "DR7",
-
- "TR0", /* [D_TR] */
- "TR1",
- "TR2",
- "TR3",
- "TR4",
- "TR5",
- "TR6",
- "TR7",
-
- "TLS", /* [D_TLS] */
- "MAXREG", /* [MAXREG] */
-};
-
-static int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int r;
-
- r = va_arg(fp->args, int);
- if(r == REG_NONE)
- return fmtstrcpy(fp, "NONE");
-
- if(REG_AL <= r && r-REG_AL < nelem(regstr))
- sprint(str, "%s", regstr[r-REG_AL]);
- else
- sprint(str, "gok(%d)", r);
-
- return fmtstrcpy(fp, str);
-}
-
-static int
-DSconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(double); i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- case 0:
- *p++ = 'z';
- continue;
- case '\\':
- case '"':
- *p++ = c;
- continue;
- case '\n':
- *p++ = 'n';
- continue;
- case '\t':
- *p++ = 't';
- continue;
- }
- *p++ = (c>>6) + '0';
- *p++ = ((c>>3) & 7) + '0';
- *p++ = (c & 7) + '0';
- }
- *p = 0;
- return fmtstrcpy(fp, str);
-}
+++ /dev/null
-// Inferno utils/8c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/list.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/8l/8.out.h"
-#include "../runtime/funcdata.h"
-
-static int Aconv(Fmt *fp);
-static int Dconv(Fmt *fp);
-static int Pconv(Fmt *fp);
-static int Rconv(Fmt *fp);
-static int DSconv(Fmt *fp);
-
-enum
-{
- STRINGSZ = 1000
-};
-
-#pragma varargck type "$" char*
-
-void
-listinit8(void)
-{
- fmtinstall('A', Aconv);
- fmtinstall('D', Dconv);
- fmtinstall('P', Pconv);
- fmtinstall('R', Rconv);
-
- // for internal use
- fmtinstall('$', DSconv);
-}
-
-static Prog* bigP;
-
-static int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Prog *p;
-
- p = va_arg(fp->args, Prog*);
- bigP = p;
- switch(p->as) {
- case ADATA:
- sprint(str, "%.5lld (%L) %A %D/%lld,%D",
- p->pc, p->lineno, p->as, &p->from, p->from3.offset, &p->to);
- break;
-
- case ATEXT:
- if(p->from3.offset) {
- sprint(str, "%.5lld (%L) %A %D,%lld,%D",
- p->pc, p->lineno, p->as, &p->from, p->from3.offset, &p->to);
- break;
- }
- sprint(str, "%.5lld (%L) %A %D,%D",
- p->pc, p->lineno, p->as, &p->from, &p->to);
- break;
-
- default:
- sprint(str, "%.5lld (%L) %A %D,%D",
- p->pc, p->lineno, p->as, &p->from, &p->to);
- // TODO(rsc): This special case is for SHRQ $32, AX:DX, which encodes as
- // SHRQ $32(DX*0), AX
- // Remove.
- if((p->from.type == TYPE_REG || p->from.type == TYPE_CONST) && p->from.index != 0)
- sprint(strchr(str, 0), ":%R", p->from.index);
- break;
- }
- bigP = nil;
- return fmtstrcpy(fp, str);
-}
-
-static int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames8[i]);
-}
-
-static int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Addr *a;
-
- a = va_arg(fp->args, Addr*);
-
- switch(a->type) {
- default:
- sprint(str, "type=%d", a->type);
- break;
-
- case TYPE_NONE:
- str[0] = 0;
- break;
-
- case TYPE_REG:
- // TODO(rsc): This special case is for instructions like
- // PINSRQ CX,$1,X6
- // where the $1 is included in the p->to Addr.
- // Move into a new field.
- if(a->offset != 0) {
- sprint(str, "$%lld,%R", a->offset, a->reg);
- break;
- }
- sprint(str, "%R", a->reg);
- break;
-
- case TYPE_BRANCH:
- if(a->sym != nil)
- sprint(str, "%s(SB)", a->sym->name);
- else if(bigP != nil && bigP->pcond != nil)
- sprint(str, "%lld", bigP->pcond->pc);
- else if(a->u.branch != nil)
- sprint(str, "%lld", a->u.branch->pc);
- else
- sprint(str, "%lld(PC)", a->offset);
- break;
-
- case TYPE_MEM:
- switch(a->name) {
- default:
- sprint(str, "name=%d", a->name);
- break;
- case NAME_NONE:
- if(a->offset)
- sprint(str, "%lld(%R)", a->offset, a->reg);
- else
- sprint(str, "(%R)", a->reg);
- break;
- case NAME_EXTERN:
- sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
- break;
- case NAME_STATIC:
- sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
- break;
- case NAME_AUTO:
- if(a->sym)
- sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
- else
- sprint(str, "%lld(SP)", a->offset);
- break;
- case NAME_PARAM:
- if(a->sym)
- sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
- else
- sprint(str, "%lld(FP)", a->offset);
- break;
- }
- if(a->index != REG_NONE) {
- sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
- strcat(str, s);
- }
- break;
-
- case TYPE_CONST:
- sprint(str, "$%lld", a->offset);
- break;
-
- case TYPE_TEXTSIZE:
- if(a->u.argsize == ArgsSizeUnknown)
- sprint(str, "$%lld", a->offset);
- else
- sprint(str, "$%lld-%d", a->offset, a->u.argsize);
- break;
-
- case TYPE_FCONST:
- sprint(str, "$(%.17g)", a->u.dval);
- break;
-
- case TYPE_SCONST:
- sprint(str, "$\"%$\"", a->u.sval);
- break;
-
- case TYPE_ADDR:
- a->type = TYPE_MEM;
- sprint(str, "$%D", a);
- a->type = TYPE_ADDR;
- break;
- }
-
- return fmtstrcpy(fp, str);
-}
-
-static char* regstr[] =
-{
- "AL", /* [REG_AL] */
- "CL",
- "DL",
- "BL",
- "AH",
- "CH",
- "DH",
- "BH",
-
- "AX", /* [REG_AX] */
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
-
- "F0", /* [REG_F0] */
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
-
- "CS", /* [REG_CS] */
- "SS",
- "DS",
- "ES",
- "FS",
- "GS",
-
- "GDTR", /* [REG_GDTR] */
- "IDTR", /* [REG_IDTR] */
- "LDTR", /* [REG_LDTR] */
- "MSW", /* [REG_MSW] */
- "TASK", /* [REG_TASK] */
-
- "CR0", /* [REG_CR] */
- "CR1",
- "CR2",
- "CR3",
- "CR4",
- "CR5",
- "CR6",
- "CR7",
-
- "DR0", /* [REG_DR] */
- "DR1",
- "DR2",
- "DR3",
- "DR4",
- "DR5",
- "DR6",
- "DR7",
-
- "TR0", /* [REG_TR] */
- "TR1",
- "TR2",
- "TR3",
- "TR4",
- "TR5",
- "TR6",
- "TR7",
-
- "X0", /* [REG_X0] */
- "X1",
- "X2",
- "X3",
- "X4",
- "X5",
- "X6",
- "X7",
-
- "TLS", /* [REG_TLS] */
- "MAXREG", /* [MAXREG] */
-};
-
-static int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int r;
-
- r = va_arg(fp->args, int);
- if(r == REG_NONE)
- return fmtstrcpy(fp, "NONE");
- if(r >= REG_AL && r-REG_AL < nelem(regstr))
- sprint(str, "%s", regstr[r-REG_AL]);
- else
- sprint(str, "gok(%d)", r);
-
- return fmtstrcpy(fp, str);
-}
-
-static int
-DSconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(double); i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- case 0:
- *p++ = 'z';
- continue;
- case '\\':
- case '"':
- *p++ = c;
- continue;
- case '\n':
- *p++ = 'n';
- continue;
- case '\t':
- *p++ = 't';
- continue;
- }
- *p++ = (c>>6) + '0';
- *p++ = ((c>>3) & 7) + '0';
- *p++ = (c & 7) + '0';
- }
- *p = 0;
- return fmtstrcpy(fp, str);
-}
+++ /dev/null
-// cmd/9l/list.c from Vita Nuova.
-//
-// 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-2008 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-2008 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/9l/9.out.h"
-#include "../runtime/funcdata.h"
-
-enum
-{
- STRINGSZ = 1000,
-};
-
-static int Aconv(Fmt*);
-static int Dconv(Fmt*);
-static int Pconv(Fmt*);
-static int Rconv(Fmt*);
-static int DSconv(Fmt*);
-static int Mconv(Fmt*);
-static int DRconv(Fmt*);
-
-//
-// Format conversions
-// %A int Opcodes (instruction mnemonics)
-//
-// %D Addr* Addresses (instruction operands)
-//
-// %P Prog* Instructions
-//
-// %R int Registers
-//
-// %$ char* String constant addresses (for internal use only)
-// %^ int C_* classes (for liblink internal use)
-
-#pragma varargck type "$" char*
-#pragma varargck type "M" Addr*
-
-void
-listinit9(void)
-{
- fmtinstall('A', Aconv);
- fmtinstall('D', Dconv);
- fmtinstall('P', Pconv);
- fmtinstall('R', Rconv);
-
- // for liblink internal use
- fmtinstall('^', DRconv);
-
- // for internal use
- fmtinstall('$', DSconv);
- fmtinstall('M', Mconv);
-}
-
-static Prog* bigP;
-
-static int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Prog *p;
- int a;
-
- p = va_arg(fp->args, Prog*);
- bigP = p;
- a = p->as;
-
- str[0] = 0;
- if(a == ADATA)
- sprint(str, "%.5lld (%L) %A %D/%lld,%D", p->pc, p->lineno, a, &p->from, p->from3.offset, &p->to);
- else if(a == ATEXT || a == AGLOBL) {
- if(p->from3.offset != 0)
- sprint(str, "%.5lld (%L) %A %D,%lld,%D", p->pc, p->lineno, a, &p->from, p->from3.offset, &p->to);
- else
- sprint(str, "%.5lld (%L) %A %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
- } else {
- if(p->mark & NOSCHED)
- sprint(strchr(str, 0), "*");
- if(p->reg == 0 && p->from3.type == TYPE_NONE)
- sprint(strchr(str, 0), "%.5lld (%L) %A %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
- else
- if(a != ATEXT && p->from.type == TYPE_MEM) {
- sprint(strchr(str, 0), "%.5lld (%L) %A %lld(%R+%R),%D", p->pc, p->lineno, a,
- p->from.offset, p->from.reg, p->reg, &p->to);
- } else
- if(p->to.type == TYPE_MEM) {
- sprint(strchr(str, 0), "%.5lld (%L) %A %D,%lld(%R+%R)", p->pc, p->lineno, a,
- &p->from, p->to.offset, p->to.reg, p->reg);
- } else {
- sprint(strchr(str, 0), "%.5lld (%L) %A %D", p->pc, p->lineno, a, &p->from);
- if(p->reg != 0)
- sprint(strchr(str, 0), ",%R", p->reg);
- if(p->from3.type != TYPE_NONE)
- sprint(strchr(str, 0), ",%D", &p->from3);
- sprint(strchr(str, 0), ",%D", &p->to);
- }
- if(p->spadj != 0)
- return fmtprint(fp, "%s # spadj=%d", str, p->spadj);
- }
- return fmtstrcpy(fp, str);
-}
-
-static int
-Aconv(Fmt *fp)
-{
- char *s;
- int a;
-
- a = va_arg(fp->args, int);
- s = "???";
- if(a >= AXXX && a < ALAST)
- s = anames9[a];
- return fmtstrcpy(fp, s);
-}
-
-static int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Addr *a;
- int32 v;
-
- a = va_arg(fp->args, Addr*);
-
- switch(a->type) {
- default:
- sprint(str, "GOK-type(%d)", a->type);
- break;
-
- case TYPE_NONE:
- str[0] = 0;
- if(a->name != TYPE_NONE || a->reg != 0 || a->sym != nil)
- sprint(str, "%M(%R)(NONE)", a, a->reg);
- break;
-
- case TYPE_CONST:
- case TYPE_ADDR:
- if(a->reg != 0)
- sprint(str, "$%M(%R)", a, a->reg);
- else
- sprint(str, "$%M", a);
- break;
-
- case TYPE_TEXTSIZE:
- if(a->u.argsize == ArgsSizeUnknown)
- sprint(str, "$%lld", a->offset);
- else
- sprint(str, "$%lld-%d", a->offset, a->u.argsize);
- break;
-
- case TYPE_MEM:
- if(a->reg != 0)
- sprint(str, "%M(%R)", a, a->reg);
- else
- sprint(str, "%M", a);
- break;
-
- case TYPE_REG:
- sprint(str, "%R", a->reg);
- if(a->name != TYPE_NONE || a->sym != nil)
- sprint(str, "%M(%R)(REG)", a, a->reg);
- break;
-
- case TYPE_BRANCH:
- if(bigP->pcond != nil) {
- v = bigP->pcond->pc;
- //if(v >= INITTEXT)
- // v -= INITTEXT-HEADR;
- if(a->sym != nil)
- sprint(str, "%s+%.5ux(BRANCH)", a->sym->name, v);
- else
- sprint(str, "%.5ux(BRANCH)", v);
- } else if(a->u.branch != nil)
- sprint(str, "%lld", a->u.branch->pc);
- else if(a->sym != nil)
- sprint(str, "%s+%lld(APC)", a->sym->name, a->offset);
- else
- sprint(str, "%lld(APC)", a->offset);
- break;
-
- case TYPE_FCONST:
- //sprint(str, "$%lux-%lux", a->ieee.h, a->ieee.l);
- sprint(str, "$%.17g", a->u.dval);
- break;
-
- case TYPE_SCONST:
- sprint(str, "$\"%$\"", a->u.sval);
- break;
- }
-
- return fmtstrcpy(fp, str);
-}
-
-static int
-Mconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Addr *a;
- LSym *s;
- int32 l;
-
- a = va_arg(fp->args, Addr*);
- s = a->sym;
- //if(s == nil) {
- // l = a->offset;
- // if((vlong)l != a->offset)
- // sprint(str, "0x%llux", a->offset);
- // else
- // sprint(str, "%lld", a->offset);
- // goto out;
- //}
- switch(a->name) {
- default:
- sprint(str, "GOK-name(%d)", a->name);
- break;
-
- case TYPE_NONE:
- l = a->offset;
- if((vlong)l != a->offset)
- sprint(str, "0x%llux", a->offset);
- else
- sprint(str, "%lld", a->offset);
- break;
-
- case NAME_EXTERN:
- if(a->offset != 0)
- sprint(str, "%s+%lld(SB)", s->name, a->offset);
- else
- sprint(str, "%s(SB)", s->name);
- break;
-
- case NAME_STATIC:
- sprint(str, "%s<>+%lld(SB)", s->name, a->offset);
- break;
-
- case NAME_AUTO:
- if(s == nil)
- sprint(str, "%lld(SP)", -a->offset);
- else
- sprint(str, "%s-%lld(SP)", s->name, -a->offset);
- break;
-
- case NAME_PARAM:
- if(s == nil)
- sprint(str, "%lld(FP)", a->offset);
- else
- sprint(str, "%s+%lld(FP)", s->name, a->offset);
- break;
- }
-//out:
- return fmtstrcpy(fp, str);
-}
-
-static int
-Rconv(Fmt *fp)
-{
- int r;
-
- r = va_arg(fp->args, int);
- if(r == 0)
- return fmtstrcpy(fp, "NONE");
- if(REG_R0 <= r && r <= REG_R31)
- return fmtprint(fp, "R%d", r-REG_R0);
- if(REG_F0 <= r && r <= REG_F31)
- return fmtprint(fp, "F%d", r-REG_F0);
- if(REG_C0 <= r && r <= REG_C7)
- return fmtprint(fp, "C%d", r-REG_C0);
- if(r == REG_CR)
- return fmtstrcpy(fp, "CR");
- if(REG_SPR0 <= r && r <= REG_SPR0+1023) {
- switch(r) {
- case REG_XER:
- return fmtstrcpy(fp, "XER");
- case REG_LR:
- return fmtstrcpy(fp, "LR");
- case REG_CTR:
- return fmtstrcpy(fp, "CTR");
- }
- return fmtprint(fp, "SPR(%d)", r-REG_SPR0);
- }
- if(REG_DCR0 <= r && r <= REG_DCR0+1023)
- return fmtprint(fp, "DCR(%d)", r-REG_DCR0);
- if(r == REG_FPSCR)
- return fmtstrcpy(fp, "FPSCR");
- if(r == REG_MSR)
- return fmtstrcpy(fp, "MSR");
-
- return fmtprint(fp, "badreg(%d)", r);
-}
-
-static int
-DRconv(Fmt *fp)
-{
- char *s;
- int a;
-
- a = va_arg(fp->args, int);
- s = "C_??";
- if(a >= C_NONE && a <= C_NCLASS)
- s = cnames9[a];
- return fmtstrcpy(fp, s);
-}
-
-static int
-DSconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(int32); i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9' ||
- c == ' ' || c == '%') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- case 0:
- *p++ = 'z';
- continue;
- case '\\':
- case '"':
- *p++ = c;
- continue;
- case '\n':
- *p++ = 'n';
- continue;
- case '\t':
- *p++ = 't';
- continue;
- }
- *p++ = (c>>6) + '0';
- *p++ = ((c>>3) & 7) + '0';
- *p++ = (c & 7) + '0';
- }
- *p = 0;
- return fmtstrcpy(fp, str);
-}
+++ /dev/null
-// 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;
-}
-
-// Does s have t as a path prefix?
-// That is, does s == t or does s begin with t followed by a slash?
-// For portability, we allow ASCII case folding, so that haspathprefix("a/b/c", "A/B") is true.
-// Similarly, we allow slash folding, so that haspathprefix("a/b/c", "a\\b") is true.
-static int
-haspathprefix(char *s, char *t)
-{
- int i, cs, ct;
-
- if(t == nil)
- return 0;
- for(i=0; t[i]; i++) {
- cs = s[i];
- ct = t[i];
- if('A' <= cs && cs <= 'Z')
- cs += 'a' - 'A';
- if('A' <= ct && ct <= 'Z')
- ct += 'a' - 'A';
- if(cs == '\\')
- cs = '/';
- if(ct == '\\')
- ct = '/';
- if(cs != ct)
- return 0;
- }
- return s[i] == '\0' || s[i] == '/' || s[i] == '\\';
-}
-
-// This is a simplified copy of linklinefmt above.
-// It doesn't allow printing the full stack, and it returns the file name and line number separately.
-// TODO: Unify with linklinefmt somehow.
-void
-linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
-{
- 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, dlno;
- int n;
- Hist *h;
- char buf[1024], buf1[1024], *file;
-
- lno = line;
- 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;
-
- if(n <= 0) {
- *f = linklookup(ctxt, "??", HistVersion);
- *l = 0;
- return;
- }
-
- n--;
- if(a[n].line) {
- file = a[n].line->name;
- dlno = a[n].ldel-1;
- } else {
- file = a[n].incl->name;
- dlno = a[n].idel-1;
- }
- if((!ctxt->windows && file[0] == '/') || (ctxt->windows && file[1] == ':') || file[0] == '<')
- snprint(buf, sizeof buf, "%s", file);
- else
- snprint(buf, sizeof buf, "%s/%s", ctxt->pathname, file);
-
- // Remove leading ctxt->trimpath, or else rewrite $GOROOT to $GOROOT_FINAL.
- if(haspathprefix(buf, ctxt->trimpath)) {
- if(strlen(buf) == strlen(ctxt->trimpath))
- strcpy(buf, "??");
- else {
- snprint(buf1, sizeof buf1, "%s", buf+strlen(ctxt->trimpath)+1);
- if(buf1[0] == '\0')
- strcpy(buf1, "??");
- strcpy(buf, buf1);
- }
- } else if(ctxt->goroot_final != nil && haspathprefix(buf, ctxt->goroot)) {
- snprint(buf1, sizeof buf1, "%s%s", ctxt->goroot_final, buf+strlen(ctxt->goroot));
- strcpy(buf, buf1);
- }
-
- lno -= dlno;
- *f = linklookup(ctxt, buf, HistVersion);
- *l = lno;
-}
-
-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;
-}
+++ /dev/null
-// 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 "../runtime/stack.h"
-
-static void
-progedit(Link *ctxt, Prog *p)
-{
- char literal[64];
- LSym *s;
- static LSym *tlsfallback;
-
- p->from.class = 0;
- p->to.class = 0;
-
- // Rewrite B/BL to symbol as TYPE_BRANCH.
- switch(p->as) {
- case AB:
- case ABL:
- case ADUFFZERO:
- case ADUFFCOPY:
- if(p->to.type == TYPE_MEM && (p->to.name == NAME_EXTERN || p->to.name == NAME_STATIC) && p->to.sym != nil)
- p->to.type = TYPE_BRANCH;
- break;
- }
-
- // Replace TLS register fetches on older ARM procesors.
- switch(p->as) {
- case AMRC:
- // Treat MRC 15, 0, <reg>, C13, C0, 3 specially.
- if((p->to.offset & 0xffff0fff) == 0xee1d0f70) {
- // Because the instruction might be rewriten to a BL which returns in R0
- // the register must be zero.
- if ((p->to.offset & 0xf000) != 0)
- ctxt->diag("%L: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p->lineno);
-
- if(ctxt->goarm < 7) {
- // Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension.
- if(tlsfallback == nil)
- tlsfallback = linklookup(ctxt, "runtime.read_tls_fallback", 0);
- // MOVW LR, R11
- p->as = AMOVW;
- p->from.type = TYPE_REG;
- p->from.reg = REGLINK;
- p->to.type = TYPE_REG;
- p->to.reg = REGTMP;
-
- // BL runtime.read_tls_fallback(SB)
- p = appendp(ctxt, p);
- p->as = ABL;
- p->to.type = TYPE_BRANCH;
- p->to.sym = tlsfallback;
- p->to.offset = 0;
-
- // MOVW R11, LR
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->from.type = TYPE_REG;
- p->from.reg = REGTMP;
- p->to.type = TYPE_REG;
- p->to.reg = REGLINK;
- break;
- }
- }
- // Otherwise, MRC/MCR instructions need no further treatment.
- p->as = AWORD;
- break;
- }
-
- // Rewrite float constants to values stored in memory.
- switch(p->as) {
- case AMOVF:
- if(p->from.type == TYPE_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
- (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
- uint32 i32;
- float32 f32;
- f32 = p->from.u.dval;
- memmove(&i32, &f32, 4);
- sprint(literal, "$f32.%08ux", i32);
- s = linklookup(ctxt, literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(ctxt, s, i32);
- s->reachable = 0;
- }
- p->from.type = TYPE_MEM;
- p->from.sym = s;
- p->from.name = NAME_EXTERN;
- p->from.offset = 0;
- }
- break;
-
- case AMOVD:
- if(p->from.type == TYPE_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
- (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
- uint64 i64;
- memmove(&i64, &p->from.u.dval, 8);
- sprint(literal, "$f64.%016llux", i64);
- s = linklookup(ctxt, literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint64(ctxt, s, i64);
- s->reachable = 0;
- }
- p->from.type = TYPE_MEM;
- p->from.sym = s;
- p->from.name = NAME_EXTERN;
- p->from.offset = 0;
- }
- break;
- }
-
- if(ctxt->flag_shared) {
- // Shared libraries use R_ARM_TLS_IE32 instead of
- // R_ARM_TLS_LE32, replacing the link time constant TLS offset in
- // runtime.tlsg with an address to a GOT entry containing the
- // offset. Rewrite $runtime.tlsg(SB) to runtime.tlsg(SB) to
- // compensate.
- if(ctxt->tlsg == nil)
- ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
-
- if(p->from.type == TYPE_ADDR && p->from.name == NAME_EXTERN && p->from.sym == ctxt->tlsg)
- p->from.type = TYPE_MEM;
- if(p->to.type == TYPE_ADDR && p->to.name == NAME_EXTERN && p->to.sym == ctxt->tlsg)
- p->to.type = TYPE_MEM;
- }
-}
-
-static Prog* stacksplit(Link*, Prog*, int32, int);
-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
-preprocess(Link *ctxt, LSym *cursym)
-{
- Prog *p, *pl, *p1, *p2, *q, *q1, *q2;
- int o;
- int32 autosize, autoffset;
-
- autosize = 0;
-
- if(ctxt->symmorestack[0] == nil) {
- ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
- ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
- }
-
- q = nil;
-
- ctxt->cursym = cursym;
-
- if(cursym->text == nil || cursym->text->link == nil)
- return;
-
- softfloat(ctxt, cursym);
-
- p = cursym->text;
- autoffset = p->to.offset;
- if(autoffset < 0)
- autoffset = 0;
- cursym->locals = autoffset;
- cursym->args = p->to.u.argsize;
-
- if(ctxt->debugzerostack) {
- if(autoffset && !(p->from3.offset&NOSPLIT)) {
- // MOVW $4(R13), R1
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->from.type = TYPE_ADDR;
- p->from.reg = REG_R13;
- p->from.offset = 4;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R1;
-
- // MOVW $n(R13), R2
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->from.type = TYPE_ADDR;
- p->from.reg = REG_R13;
- p->from.offset = 4 + autoffset;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R2;
-
- // MOVW $0, R3
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->from.type = TYPE_CONST;
- p->from.offset = 0;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R3;
-
- // L:
- // MOVW.nil R3, 0(R1) +4
- // CMP R1, R2
- // BNE L
- p = pl = appendp(ctxt, p);
- p->as = AMOVW;
- p->from.type = TYPE_REG;
- p->from.reg = REG_R3;
- p->to.type = TYPE_MEM;
- p->to.reg = REG_R1;
- p->to.offset = 4;
- p->scond |= C_PBIT;
-
- p = appendp(ctxt, p);
- p->as = ACMP;
- p->from.type = TYPE_REG;
- p->from.reg = REG_R1;
- p->reg = REG_R2;
-
- p = appendp(ctxt, p);
- p->as = ABNE;
- p->to.type = TYPE_BRANCH;
- p->pcond = pl;
- }
- }
-
- /*
- * find leaf subroutines
- * strip NOPs
- * expand RET
- * expand BECOME pseudo
- */
-
- 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:
- case ADUFFZERO:
- case ADUFFCOPY:
- 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;
- }
- 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->from3.offset & NOSPLIT))
- p = stacksplit(ctxt, p, autosize, !(cursym->text->from3.offset&NEEDCTXT)); // emit split check
-
- // MOVW.W R14,$-autosize(SP)
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->scond |= C_WBIT;
- p->from.type = TYPE_REG;
- p->from.reg = REGLINK;
- p->to.type = TYPE_MEM;
- p->to.offset = -autosize;
- p->to.reg = REGSP;
- p->spadj = autosize;
-
- if(cursym->text->from3.offset & WRAPPER) {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOVW g_panic(g), R1
- // CMP $0, R1
- // B.EQ end
- // MOVW panic_argp(R1), R2
- // ADD $(autosize+4), R13, R3
- // CMP R2, R3
- // B.NE end
- // ADD $4, R13, R4
- // MOVW R4, panic_argp(R1)
- // end:
- // NOP
- //
- // The NOP is needed to give the jumps somewhere to land.
- // It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes.
-
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->from.type = TYPE_MEM;
- p->from.reg = REGG;
- p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
- p->to.type = TYPE_REG;
- p->to.reg = REG_R1;
-
- p = appendp(ctxt, p);
- p->as = ACMP;
- p->from.type = TYPE_CONST;
- p->from.offset = 0;
- p->reg = REG_R1;
-
- p = appendp(ctxt, p);
- p->as = ABEQ;
- p->to.type = TYPE_BRANCH;
- p1 = p;
-
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_R1;
- p->from.offset = 0; // Panic.argp
- p->to.type = TYPE_REG;
- p->to.reg = REG_R2;
-
- p = appendp(ctxt, p);
- p->as = AADD;
- p->from.type = TYPE_CONST;
- p->from.offset = autosize+4;
- p->reg = REG_R13;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R3;
-
- p = appendp(ctxt, p);
- p->as = ACMP;
- p->from.type = TYPE_REG;
- p->from.reg = REG_R2;
- p->reg = REG_R3;
-
- p = appendp(ctxt, p);
- p->as = ABNE;
- p->to.type = TYPE_BRANCH;
- p2 = p;
-
- p = appendp(ctxt, p);
- p->as = AADD;
- p->from.type = TYPE_CONST;
- p->from.offset = 4;
- p->reg = REG_R13;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R4;
-
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->from.type = TYPE_REG;
- p->from.reg = REG_R4;
- p->to.type = TYPE_MEM;
- p->to.reg = REG_R1;
- p->to.offset = 0; // Panic.argp
-
- p = appendp(ctxt, p);
- p->as = ANOP;
- p1->pcond = p;
- p2->pcond = p;
- }
- break;
-
- case ARET:
- nocache(p);
- if(cursym->text->mark & LEAF) {
- if(!autosize) {
- p->as = AB;
- p->from = zprog.from;
- if(p->to.sym) { // retjmp
- p->to.type = TYPE_BRANCH;
- } else {
- p->to.type = TYPE_MEM;
- p->to.offset = 0;
- p->to.reg = REGLINK;
- }
- break;
- }
- }
-
- p->as = AMOVW;
- p->scond |= C_PBIT;
- p->from.type = TYPE_MEM;
- p->from.offset = autosize;
- p->from.reg = REGSP;
- p->to.type = TYPE_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 = TYPE_BRANCH;
- q2->to.sym = p->to.sym;
- p->to.sym = nil;
- p = q2;
- }
- break;
-
- case AADD:
- if(p->from.type == TYPE_CONST && p->from.reg == 0 && p->to.type == TYPE_REG && p->to.reg == REGSP)
- p->spadj = -p->from.offset;
- break;
-
- case ASUB:
- if(p->from.type == TYPE_CONST && p->from.reg == 0 && p->to.type == TYPE_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 != TYPE_REG)
- break;
- if(p->to.type != TYPE_REG)
- break;
- q1 = p;
-
- /* MOV a,4(SP) */
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->lineno = q1->lineno;
- p->from.type = TYPE_REG;
- p->from.reg = q1->from.reg;
- p->to.type = TYPE_MEM;
- 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 = TYPE_REG;
- p->from.reg = q1->reg;
- if(q1->reg == 0)
- p->from.reg = q1->to.reg;
- p->to.type = TYPE_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 = TYPE_BRANCH;
- 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 = TYPE_REG;
- p->from.reg = REGTMP;
- p->from.offset = 0;
- p->to.type = TYPE_REG;
- p->to.reg = q1->to.reg;
-
- /* ADD $8,SP */
- p = appendp(ctxt, p);
- p->as = AADD;
- p->lineno = q1->lineno;
- p->from.type = TYPE_CONST;
- p->from.reg = 0;
- p->from.offset = 8;
- p->reg = 0;
- p->to.type = TYPE_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 = TYPE_MEM;
- q1->from.reg = REGSP;
- q1->from.offset = 0;
- q1->reg = 0;
- q1->to.type = TYPE_REG;
- q1->to.reg = REGTMP;
-
- /* SUB $8,SP */
- q1 = appendp(ctxt, q1);
- q1->as = AMOVW;
- q1->from.type = TYPE_REG;
- q1->from.reg = REGTMP;
- q1->reg = 0;
- q1->to.type = TYPE_MEM;
- 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 == TYPE_MEM && p->to.reg == REGSP)
- p->spadj = -p->to.offset;
- if((p->scond & C_PBIT) && p->from.type == TYPE_MEM && p->from.reg == REGSP && p->to.reg != REGPC)
- p->spadj = -p->from.offset;
- if(p->from.type == TYPE_ADDR && p->from.reg == REGSP && p->to.type == TYPE_REG && p->to.reg == REGSP)
- p->spadj = -p->from.offset;
- break;
- }
- }
-}
-
-static int
-isfloatreg(Addr *a)
-{
- return a->type == TYPE_REG && REG_F0 <= a->reg && a->reg <= REG_F15;
-}
-
-static void
-softfloat(Link *ctxt, LSym *cursym)
-{
- Prog *p, *next;
- LSym *symsfloat;
- int wasfloat;
-
- if(ctxt->goarm > 5)
- return;
-
- symsfloat = linklookup(ctxt, "_sfloat", 0);
-
- 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(isfloatreg(&p->to) || isfloatreg(&p->from))
- 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 (!wasfloat || (p->mark&LABEL)) {
- next = emallocz(sizeof(Prog));
- *next = *p;
-
- // BL _sfloat(SB)
- *p = zprog;
- p->link = next;
- p->as = ABL;
- p->to.type = TYPE_BRANCH;
- p->to.sym = symsfloat;
- p->lineno = next->lineno;
-
- p = next;
- wasfloat = 1;
- }
- continue;
-
- notsoft:
- wasfloat = 0;
- }
-}
-
-static Prog*
-stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
-{
- // MOVW g_stackguard(g), R1
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->from.type = TYPE_MEM;
- p->from.reg = REGG;
- p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0
- if(ctxt->cursym->cfunc)
- p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1
- p->to.type = TYPE_REG;
- p->to.reg = REG_R1;
-
- if(framesize <= StackSmall) {
- // small stack: SP < stackguard
- // CMP stackguard, SP
- p = appendp(ctxt, p);
- p->as = ACMP;
- p->from.type = TYPE_REG;
- p->from.reg = REG_R1;
- 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 = TYPE_ADDR;
- p->from.reg = REGSP;
- p->from.offset = -framesize;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R2;
-
- p = appendp(ctxt, p);
- p->as = ACMP;
- p->from.type = TYPE_REG;
- p->from.reg = REG_R1;
- p->reg = REG_R2;
- } 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 = TYPE_CONST;
- p->from.offset = (uint32)StackPreempt;
- p->reg = REG_R1;
-
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->from.type = TYPE_ADDR;
- p->from.reg = REGSP;
- p->from.offset = StackGuard;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R2;
- p->scond = C_SCOND_NE;
-
- p = appendp(ctxt, p);
- p->as = ASUB;
- p->from.type = TYPE_REG;
- p->from.reg = REG_R1;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R2;
- p->scond = C_SCOND_NE;
-
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->from.type = TYPE_ADDR;
- p->from.offset = framesize + (StackGuard - StackSmall);
- p->to.type = TYPE_REG;
- p->to.reg = REG_R3;
- p->scond = C_SCOND_NE;
-
- p = appendp(ctxt, p);
- p->as = ACMP;
- p->from.type = TYPE_REG;
- p->from.reg = REG_R3;
- p->reg = REG_R2;
- p->scond = C_SCOND_NE;
- }
-
- // MOVW.LS R14, R3
- p = appendp(ctxt, p);
- p->as = AMOVW;
- p->scond = C_SCOND_LS;
- p->from.type = TYPE_REG;
- p->from.reg = REGLINK;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R3;
-
- // 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 = TYPE_BRANCH;
- if(ctxt->cursym->cfunc)
- p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
- else
- p->to.sym = ctxt->symmorestack[noctxt];
-
- // BLS start
- p = appendp(ctxt, p);
- p->as = ABLS;
- p->to.type = TYPE_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 = emallocz(sizeof(Prog));
- 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 == C_SCOND_NONE) || a == ARFE || a == AUNDEF)
- goto copy;
- if(q->pcond == nil || (q->pcond->mark&FOLL))
- continue;
- if(a != ABEQ && a != ABNE)
- continue;
- copy:
- for(;;) {
- r = emallocz(sizeof(Prog));
- *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 == C_SCOND_NONE) || 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 = emallocz(sizeof(Prog));
- q->as = a;
- q->lineno = p->lineno;
- q->to.type = TYPE_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 == C_SCOND_NONE) || 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",
- .thechar = '5',
- .endian = LittleEndian,
-
- .preprocess = preprocess,
- .assemble = span5,
- .follow = follow,
- .progedit = progedit,
-
- .minlc = 4,
- .ptrsize = 4,
- .regsize = 4,
-};
+++ /dev/null
-// 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 "../runtime/stack.h"
-
-static void nacladdr(Link*, Prog*, Addr*);
-
-static int
-canuselocaltls(Link *ctxt)
-{
- switch(ctxt->headtype) {
- case Hplan9:
- case Hwindows:
- return 0;
- }
- return 1;
-}
-
-static void
-progedit(Link *ctxt, Prog *p)
-{
- char literal[64];
- LSym *s;
- Prog *q;
-
- // Thread-local storage references use the TLS pseudo-register.
- // As a register, TLS refers to the thread-local storage base, and it
- // can only be loaded into another register:
- //
- // MOVQ TLS, AX
- //
- // An offset from the thread-local storage base is written off(reg)(TLS*1).
- // Semantically it is off(reg), but the (TLS*1) annotation marks this as
- // indexing from the loaded TLS base. This emits a relocation so that
- // if the linker needs to adjust the offset, it can. For example:
- //
- // MOVQ TLS, AX
- // MOVQ 8(AX)(TLS*1), CX // load m into CX
- //
- // On systems that support direct access to the TLS memory, this
- // pair of instructions can be reduced to a direct TLS memory reference:
- //
- // MOVQ 8(TLS), CX // load m into CX
- //
- // The 2-instruction and 1-instruction forms correspond roughly to
- // ELF TLS initial exec mode and ELF TLS local exec mode, respectively.
- //
- // We applies this rewrite on systems that support the 1-instruction form.
- // The decision is made using only the operating system (and probably
- // the -shared flag, eventually), not the link mode. If some link modes
- // on a particular operating system require the 2-instruction form,
- // then all builds for that operating system will use the 2-instruction
- // form, so that the link mode decision can be delayed to link time.
- //
- // In this way, all supported systems use identical instructions to
- // access TLS, and they are rewritten appropriately first here in
- // liblink and then finally using relocations in the linker.
-
- if(canuselocaltls(ctxt)) {
- // Reduce TLS initial exec model to TLS local exec model.
- // Sequences like
- // MOVQ TLS, BX
- // ... off(BX)(TLS*1) ...
- // become
- // NOP
- // ... off(TLS) ...
- //
- // TODO(rsc): Remove the Hsolaris special case. It exists only to
- // guarantee we are producing byte-identical binaries as before this code.
- // But it should be unnecessary.
- if((p->as == AMOVQ || p->as == AMOVL) && p->from.type == TYPE_REG && p->from.reg == REG_TLS && p->to.type == TYPE_REG && REG_AX <= p->to.reg && p->to.reg <= REG_R15 && ctxt->headtype != Hsolaris)
- nopout(p);
- if(p->from.type == TYPE_MEM && p->from.index == REG_TLS && REG_AX <= p->from.reg && p->from.reg <= REG_R15) {
- p->from.reg = REG_TLS;
- p->from.scale = 0;
- p->from.index = REG_NONE;
- }
- if(p->to.type == TYPE_MEM && p->to.index == REG_TLS && REG_AX <= p->to.reg && p->to.reg <= REG_R15) {
- p->to.reg = REG_TLS;
- p->to.scale = 0;
- p->to.index = REG_NONE;
- }
- } else {
- // As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
- // The instruction
- // MOVQ off(TLS), BX
- // becomes the sequence
- // MOVQ TLS, BX
- // MOVQ off(BX)(TLS*1), BX
- // This allows the C compilers to emit references to m and g using the direct off(TLS) form.
- if((p->as == AMOVQ || p->as == AMOVL) && p->from.type == TYPE_MEM && p->from.reg == REG_TLS && p->to.type == TYPE_REG && REG_AX <= p->to.reg && p->to.reg <= REG_R15) {
- q = appendp(ctxt, p);
- q->as = p->as;
- q->from = p->from;
- q->from.type = TYPE_MEM;
- q->from.reg = p->to.reg;
- q->from.index = REG_TLS;
- q->from.scale = 2; // TODO: use 1
- q->to = p->to;
- p->from.type = TYPE_REG;
- p->from.reg = REG_TLS;
- p->from.index = REG_NONE;
- p->from.offset = 0;
- }
- }
-
- // TODO: Remove.
- if(ctxt->headtype == Hwindows || ctxt->headtype == Hplan9) {
- if(p->from.scale == 1 && p->from.index == REG_TLS)
- p->from.scale = 2;
- if(p->to.scale == 1 && p->to.index == REG_TLS)
- p->to.scale = 2;
- }
-
- if(ctxt->headtype == Hnacl) {
- nacladdr(ctxt, p, &p->from);
- nacladdr(ctxt, p, &p->to);
- }
-
- // Maintain information about code generation mode.
- if(ctxt->mode == 0)
- ctxt->mode = 64;
- p->mode = ctxt->mode;
-
- switch(p->as) {
- case AMODE:
- if(p->from.type == TYPE_CONST || (p->from.type == TYPE_MEM && p->from.reg == REG_NONE)) {
- switch((int)p->from.offset) {
- case 16:
- case 32:
- case 64:
- ctxt->mode = p->from.offset;
- break;
- }
- }
- nopout(p);
- break;
- }
-
- // Rewrite CALL/JMP/RET to symbol as TYPE_BRANCH.
- switch(p->as) {
- case ACALL:
- case AJMP:
- case ARET:
- if(p->to.type == TYPE_MEM && (p->to.name == NAME_EXTERN || p->to.name == NAME_STATIC) && p->to.sym != nil)
- p->to.type = TYPE_BRANCH;
- break;
- }
-
- // Rewrite float constants to values stored in memory.
- switch(p->as) {
- case AMOVSS:
- // Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
- if(p->from.type == TYPE_FCONST)
- if(p->from.u.dval == 0)
- if(p->to.type == TYPE_REG && REG_X0 <= p->to.reg && p->to.reg <= REG_X15) {
- p->as = AXORPS;
- p->from = p->to;
- break;
- }
- // fallthrough
-
- case AFMOVF:
- case AFADDF:
- case AFSUBF:
- case AFSUBRF:
- case AFMULF:
- case AFDIVF:
- case AFDIVRF:
- case AFCOMF:
- case AFCOMFP:
- case AADDSS:
- case ASUBSS:
- case AMULSS:
- case ADIVSS:
- case ACOMISS:
- case AUCOMISS:
- if(p->from.type == TYPE_FCONST) {
- uint32 i32;
- float32 f32;
- f32 = p->from.u.dval;
- memmove(&i32, &f32, 4);
- sprint(literal, "$f32.%08ux", i32);
- s = linklookup(ctxt, literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(ctxt, s, i32);
- s->reachable = 0;
- }
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- break;
-
- case AMOVSD:
- // Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
- if(p->from.type == TYPE_FCONST)
- if(p->from.u.dval == 0)
- if(p->to.type == TYPE_REG && REG_X0 <= p->to.reg && p->to.reg <= REG_X15) {
- p->as = AXORPS;
- p->from = p->to;
- break;
- }
- // fallthrough
-
- case AFMOVD:
- case AFADDD:
- case AFSUBD:
- case AFSUBRD:
- case AFMULD:
- case AFDIVD:
- case AFDIVRD:
- case AFCOMD:
- case AFCOMDP:
- case AADDSD:
- case ASUBSD:
- case AMULSD:
- case ADIVSD:
- case ACOMISD:
- case AUCOMISD:
- if(p->from.type == TYPE_FCONST) {
- uint64 i64;
- memmove(&i64, &p->from.u.dval, 8);
- sprint(literal, "$f64.%016llux", i64);
- s = linklookup(ctxt, literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint64(ctxt, s, i64);
- s->reachable = 0;
- }
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- break;
- }
-}
-
-static void
-nacladdr(Link *ctxt, Prog *p, Addr *a)
-{
- if(p->as == ALEAL || p->as == ALEAQ)
- return;
-
- if(a->reg == REG_BP) {
- ctxt->diag("invalid address: %P", p);
- return;
- }
- if(a->reg == REG_TLS)
- a->reg = REG_BP;
- if(a->type == TYPE_MEM && a->name == NAME_NONE) {
- switch(a->reg) {
- case REG_BP:
- case REG_SP:
- case REG_R15:
- // all ok
- break;
- default:
- if(a->index != REG_NONE)
- ctxt->diag("invalid address %P", p);
- a->index = a->reg;
- if(a->index != REG_NONE)
- a->scale = 1;
- a->reg = REG_R15;
- break;
- }
- }
-}
-
-static Prog* load_g_cx(Link*, Prog*);
-static Prog* stacksplit(Link*, Prog*, int32, int32, int, Prog**);
-static void indir_cx(Link*, Addr*);
-
-static void
-preprocess(Link *ctxt, LSym *cursym)
-{
- Prog *p, *q, *p1, *p2;
- int32 autoffset, deltasp;
- int a, pcsize, bpsize;
- vlong textarg;
-
- if(ctxt->tlsg == nil)
- ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
- if(ctxt->symmorestack[0] == nil) {
- ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
- ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
- }
-
- if(ctxt->headtype == Hplan9 && ctxt->plan9privates == nil)
- ctxt->plan9privates = linklookup(ctxt, "_privates", 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;
-
- if(framepointer_enabled && autoffset > 0) {
- // Make room for to save a base pointer. If autoffset == 0,
- // this might do something special like a tail jump to
- // another function, so in that case we omit this.
- bpsize = ctxt->arch->ptrsize;
- autoffset += bpsize;
- p->to.offset += bpsize;
- } else {
- bpsize = 0;
- }
-
- textarg = p->to.u.argsize;
- cursym->args = textarg;
- cursym->locals = p->to.offset;
-
- if(autoffset < StackSmall && !(p->from3.offset & NOSPLIT)) {
- for(q = p; q != nil; q = q->link) {
- if(q->as == ACALL)
- goto noleaf;
- if((q->as == ADUFFCOPY || q->as == ADUFFZERO) && autoffset >= StackSmall - 8)
- goto noleaf;
- }
- p->from3.offset |= NOSPLIT;
- noleaf:;
- }
-
- q = nil;
- if(!(p->from3.offset & NOSPLIT) || (p->from3.offset & WRAPPER)) {
- p = appendp(ctxt, p);
- p = load_g_cx(ctxt, p); // load g into CX
- }
- if(!(cursym->text->from3.offset & NOSPLIT))
- p = stacksplit(ctxt, p, autoffset, textarg, !(cursym->text->from3.offset&NEEDCTXT), &q); // emit split check
-
- if(autoffset) {
- if(autoffset%ctxt->arch->regsize != 0)
- ctxt->diag("unaligned stack size %d", autoffset);
- p = appendp(ctxt, p);
- p->as = AADJSP;
- p->from.type = TYPE_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(bpsize > 0) {
- // Save caller's BP
- p = appendp(ctxt, p);
- p->as = AMOVQ;
- p->from.type = TYPE_REG;
- p->from.reg = REG_BP;
- p->to.type = TYPE_MEM;
- p->to.reg = REG_SP;
- p->to.scale = 1;
- p->to.offset = autoffset - bpsize;
-
- // Move current frame to BP
- p = appendp(ctxt, p);
- p->as = ALEAQ;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_SP;
- p->from.scale = 1;
- p->from.offset = autoffset - bpsize;
- p->to.type = TYPE_REG;
- p->to.reg = REG_BP;
- }
-
- if(cursym->text->from3.offset & WRAPPER) {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOVQ g_panic(CX), BX
- // TESTQ BX, BX
- // JEQ end
- // LEAQ (autoffset+8)(SP), DI
- // CMPQ panic_argp(BX), DI
- // JNE end
- // MOVQ SP, panic_argp(BX)
- // end:
- // NOP
- //
- // The NOP is needed to give the jumps somewhere to land.
- // It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes.
-
- p = appendp(ctxt, p);
- p->as = AMOVQ;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_CX;
- p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
- p->to.type = TYPE_REG;
- p->to.reg = REG_BX;
- if(ctxt->headtype == Hnacl) {
- p->as = AMOVL;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_R15;
- p->from.scale = 1;
- p->from.index = REG_CX;
- }
-
- p = appendp(ctxt, p);
- p->as = ATESTQ;
- p->from.type = TYPE_REG;
- p->from.reg = REG_BX;
- p->to.type = TYPE_REG;
- p->to.reg = REG_BX;
- if(ctxt->headtype == Hnacl)
- p->as = ATESTL;
-
- p = appendp(ctxt, p);
- p->as = AJEQ;
- p->to.type = TYPE_BRANCH;
- p1 = p;
-
- p = appendp(ctxt, p);
- p->as = ALEAQ;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_SP;
- p->from.offset = autoffset+8;
- p->to.type = TYPE_REG;
- p->to.reg = REG_DI;
- if(ctxt->headtype == Hnacl)
- p->as = ALEAL;
-
- p = appendp(ctxt, p);
- p->as = ACMPQ;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_BX;
- p->from.offset = 0; // Panic.argp
- p->to.type = TYPE_REG;
- p->to.reg = REG_DI;
- if(ctxt->headtype == Hnacl) {
- p->as = ACMPL;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_R15;
- p->from.scale = 1;
- p->from.index = REG_BX;
- }
-
- p = appendp(ctxt, p);
- p->as = AJNE;
- p->to.type = TYPE_BRANCH;
- p2 = p;
-
- p = appendp(ctxt, p);
- p->as = AMOVQ;
- p->from.type = TYPE_REG;
- p->from.reg = REG_SP;
- p->to.type = TYPE_MEM;
- p->to.reg = REG_BX;
- p->to.offset = 0; // Panic.argp
- if(ctxt->headtype == Hnacl) {
- p->as = AMOVL;
- p->to.type = TYPE_MEM;
- p->to.reg = REG_R15;
- p->to.scale = 1;
- p->to.index = REG_BX;
- }
-
- p = appendp(ctxt, p);
- p->as = ANOP;
- p1->pcond = p;
- p2->pcond = p;
- }
-
- if(ctxt->debugzerostack && autoffset && !(cursym->text->from3.offset&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 = TYPE_REG;
- p->from.reg = REG_SP;
- p->to.type = TYPE_REG;
- p->to.reg = REG_DI;
-
- p = appendp(ctxt, p);
- p->as = AMOVQ;
- p->from.type = TYPE_CONST;
- p->from.offset = autoffset/8;
- p->to.type = TYPE_REG;
- p->to.reg = REG_CX;
-
- p = appendp(ctxt, p);
- p->as = AMOVQ;
- p->from.type = TYPE_CONST;
- p->from.offset = 0;
- p->to.type = TYPE_REG;
- p->to.reg = REG_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.name;
- if(a == NAME_AUTO)
- p->from.offset += deltasp - bpsize;
- if(a == NAME_PARAM)
- p->from.offset += deltasp + pcsize;
- a = p->to.name;
- if(a == NAME_AUTO)
- p->to.offset += deltasp - bpsize;
- if(a == NAME_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(autoffset) {
- if(bpsize > 0) {
- // Restore caller's BP
- p->as = AMOVQ;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_SP;
- p->from.scale = 1;
- p->from.offset = autoffset - bpsize;
- p->to.type = TYPE_REG;
- p->to.reg = REG_BP;
- p = appendp(ctxt, p);
- }
-
- p->as = AADJSP;
- p->from.type = TYPE_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;
- }
-}
-
-static void
-indir_cx(Link *ctxt, Addr *a)
-{
- if(ctxt->headtype == Hnacl) {
- a->type = TYPE_MEM;
- a->reg = REG_R15;
- a->index = REG_CX;
- a->scale = 1;
- return;
- }
-
- a->type = TYPE_MEM;
- a->reg = REG_CX;
-}
-
-// 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)
-{
- Prog *next;
-
- p->as = AMOVQ;
- if(ctxt->arch->ptrsize == 4)
- p->as = AMOVL;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_TLS;
- p->from.offset = 0;
- p->to.type = TYPE_REG;
- p->to.reg = REG_CX;
-
- next = p->link;
- progedit(ctxt, p);
- while(p->link != next)
- p = p->link;
-
- if(p->from.index == REG_TLS)
- p->from.scale = 2;
-
- 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, int noctxt, Prog **jmpok)
-{
- Prog *q, *q1;
- int cmp, lea, mov, sub;
-
- USED(textarg);
- cmp = ACMPQ;
- lea = ALEAQ;
- mov = AMOVQ;
- sub = ASUBQ;
-
- if(ctxt->headtype == Hnacl) {
- cmp = ACMPL;
- lea = ALEAL;
- mov = AMOVL;
- sub = ASUBL;
- }
-
- q1 = nil;
- if(framesize <= StackSmall) {
- // small stack: SP <= stackguard
- // CMPQ SP, stackguard
- p = appendp(ctxt, p);
- p->as = cmp;
- p->from.type = TYPE_REG;
- p->from.reg = REG_SP;
- indir_cx(ctxt, &p->to);
- p->to.offset = 2*ctxt->arch->ptrsize; // G.stackguard0
- if(ctxt->cursym->cfunc)
- p->to.offset = 3*ctxt->arch->ptrsize; // G.stackguard1
- } else if(framesize <= StackBig) {
- // large stack: SP-framesize <= stackguard-StackSmall
- // LEAQ -xxx(SP), AX
- // CMPQ AX, stackguard
- p = appendp(ctxt, p);
- p->as = lea;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_SP;
- p->from.offset = -(framesize-StackSmall);
- p->to.type = TYPE_REG;
- p->to.reg = REG_AX;
-
- p = appendp(ctxt, p);
- p->as = cmp;
- p->from.type = TYPE_REG;
- p->from.reg = REG_AX;
- indir_cx(ctxt, &p->to);
- p->to.offset = 2*ctxt->arch->ptrsize; // G.stackguard0
- if(ctxt->cursym->cfunc)
- p->to.offset = 3*ctxt->arch->ptrsize; // G.stackguard1
- } 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 = mov;
- indir_cx(ctxt, &p->from);
- p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0
- if(ctxt->cursym->cfunc)
- p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1
- p->to.type = TYPE_REG;
- p->to.reg = REG_SI;
-
- p = appendp(ctxt, p);
- p->as = cmp;
- p->from.type = TYPE_REG;
- p->from.reg = REG_SI;
- p->to.type = TYPE_CONST;
- p->to.offset = StackPreempt;
-
- p = appendp(ctxt, p);
- p->as = AJEQ;
- p->to.type = TYPE_BRANCH;
- q1 = p;
-
- p = appendp(ctxt, p);
- p->as = lea;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_SP;
- p->from.offset = StackGuard;
- p->to.type = TYPE_REG;
- p->to.reg = REG_AX;
-
- p = appendp(ctxt, p);
- p->as = sub;
- p->from.type = TYPE_REG;
- p->from.reg = REG_SI;
- p->to.type = TYPE_REG;
- p->to.reg = REG_AX;
-
- p = appendp(ctxt, p);
- p->as = cmp;
- p->from.type = TYPE_REG;
- p->from.reg = REG_AX;
- p->to.type = TYPE_CONST;
- p->to.offset = framesize+(StackGuard-StackSmall);
- }
-
- // common
- p = appendp(ctxt, p);
- p->as = AJHI;
- p->to.type = TYPE_BRANCH;
- q = p;
-
- p = appendp(ctxt, p);
- p->as = ACALL;
- p->to.type = TYPE_BRANCH;
- if(ctxt->cursym->cfunc)
- p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
- else
- p->to.sym = ctxt->symmorestack[noctxt];
-
- p = appendp(ctxt, p);
- p->as = AJMP;
- p->to.type = TYPE_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 = emallocz(sizeof(Prog));
- 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;
- int 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 = emallocz(sizeof(Prog));
- q->as = AJMP;
- q->lineno = p->lineno;
- q->to.type = TYPE_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 == TYPE_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 linkamd64 = {
- .name = "amd64",
- .thechar = '6',
- .endian = LittleEndian,
-
- .preprocess = preprocess,
- .assemble = span6,
- .follow = follow,
- .progedit = progedit,
-
- .minlc = 1,
- .ptrsize = 8,
- .regsize = 8,
-};
-
-LinkArch linkamd64p32 = {
- .name = "amd64p32",
- .thechar = '6',
- .endian = LittleEndian,
-
- .preprocess = preprocess,
- .assemble = span6,
- .follow = follow,
- .progedit = progedit,
-
- .minlc = 1,
- .ptrsize = 4,
- .regsize = 8,
-};
+++ /dev/null
-// 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 "../runtime/stack.h"
-
-static int
-canuselocaltls(Link *ctxt)
-{
- switch(ctxt->headtype) {
- case Hlinux:
- case Hnacl:
- case Hplan9:
- case Hwindows:
- return 0;
- }
- return 1;
-}
-
-static void
-progedit(Link *ctxt, Prog *p)
-{
- char literal[64];
- LSym *s;
- Prog *q;
-
- // See obj6.c for discussion of TLS.
- if(canuselocaltls(ctxt)) {
- // Reduce TLS initial exec model to TLS local exec model.
- // Sequences like
- // MOVL TLS, BX
- // ... off(BX)(TLS*1) ...
- // become
- // NOP
- // ... off(TLS) ...
- if(p->as == AMOVL && p->from.type == TYPE_REG && p->from.reg == REG_TLS && p->to.type == TYPE_REG && REG_AX <= p->to.reg && p->to.reg <= REG_DI) {
- p->as = ANOP;
- p->from.type = TYPE_NONE;
- p->to.type = TYPE_NONE;
- }
- if(p->from.type == TYPE_MEM && p->from.index == REG_TLS && REG_AX <= p->from.reg && p->from.reg <= REG_DI) {
- p->from.type = TYPE_MEM;
- p->from.reg = REG_TLS;
- p->from.scale = 0;
- p->from.index = REG_NONE;
- }
- if(p->to.type == TYPE_MEM && p->to.index == REG_TLS && REG_AX <= p->to.reg && p->to.reg <= REG_DI) {
- p->to.type = TYPE_MEM;
- p->to.reg = REG_TLS;
- p->to.scale = 0;
- p->to.index = REG_NONE;
- }
- } else {
- // As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
- // The instruction
- // MOVL off(TLS), BX
- // becomes the sequence
- // MOVL TLS, BX
- // MOVL off(BX)(TLS*1), BX
- // This allows the C compilers to emit references to m and g using the direct off(TLS) form.
- if(p->as == AMOVL && p->from.type == TYPE_MEM && p->from.reg == REG_TLS && p->to.type == TYPE_REG && REG_AX <= p->to.reg && p->to.reg <= REG_DI) {
- q = appendp(ctxt, p);
- q->as = p->as;
- q->from.type = TYPE_MEM;
- q->from.reg = p->to.reg;
- q->from.index = REG_TLS;
- q->from.scale = 2; // TODO: use 1
- q->to = p->to;
- p->from.type = TYPE_REG;
- p->from.reg = REG_TLS;
- p->from.index = REG_NONE;
- p->from.offset = 0;
- }
- }
-
- // TODO: Remove.
- if(ctxt->headtype == Hplan9) {
- if(p->from.scale == 1 && p->from.index == REG_TLS)
- p->from.scale = 2;
- if(p->to.scale == 1 && p->to.index == REG_TLS)
- p->to.scale = 2;
- }
-
- // Rewrite CALL/JMP/RET to symbol as TYPE_BRANCH.
- switch(p->as) {
- case ACALL:
- case AJMP:
- case ARET:
- if(p->to.type == TYPE_MEM && (p->to.name == NAME_EXTERN || p->to.name == NAME_STATIC) && p->to.sym != nil)
- p->to.type = TYPE_BRANCH;
- break;
- }
-
- // Rewrite float constants to values stored in memory.
- switch(p->as) {
- case AMOVSS:
- // Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
- if(p->from.type == TYPE_FCONST)
- if(p->from.u.dval == 0)
- if(p->to.type == TYPE_REG && REG_X0 <= p->to.reg && p->to.reg <= REG_X7) {
- p->as = AXORPS;
- p->from = p->to;
- break;
- }
- // fallthrough
-
- case AFMOVF:
- case AFADDF:
- case AFSUBF:
- case AFSUBRF:
- case AFMULF:
- case AFDIVF:
- case AFDIVRF:
- case AFCOMF:
- case AFCOMFP:
- case AADDSS:
- case ASUBSS:
- case AMULSS:
- case ADIVSS:
- case ACOMISS:
- case AUCOMISS:
- if(p->from.type == TYPE_FCONST) {
- uint32 i32;
- float32 f32;
- f32 = p->from.u.dval;
- memmove(&i32, &f32, 4);
- sprint(literal, "$f32.%08ux", i32);
- s = linklookup(ctxt, literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(ctxt, s, i32);
- s->reachable = 0;
- }
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- break;
-
- case AMOVSD:
- // Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
- if(p->from.type == TYPE_FCONST)
- if(p->from.u.dval == 0)
- if(p->to.type == TYPE_REG && REG_X0 <= p->to.reg && p->to.reg <= REG_X7) {
- p->as = AXORPS;
- p->from = p->to;
- break;
- }
- // fallthrough
-
- case AFMOVD:
- case AFADDD:
- case AFSUBD:
- case AFSUBRD:
- case AFMULD:
- case AFDIVD:
- case AFDIVRD:
- case AFCOMD:
- case AFCOMDP:
- case AADDSD:
- case ASUBSD:
- case AMULSD:
- case ADIVSD:
- case ACOMISD:
- case AUCOMISD:
- if(p->from.type == TYPE_FCONST) {
- uint64 i64;
- memmove(&i64, &p->from.u.dval, 8);
- sprint(literal, "$f64.%016llux", i64);
- s = linklookup(ctxt, literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint64(ctxt, s, i64);
- s->reachable = 0;
- }
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- break;
- }
-}
-
-static Prog* load_g_cx(Link*, Prog*);
-static Prog* stacksplit(Link*, Prog*, int32, int, Prog**);
-
-static void
-preprocess(Link *ctxt, LSym *cursym)
-{
- Prog *p, *q, *p1, *p2;
- int32 autoffset, deltasp;
- int a;
-
- if(ctxt->symmorestack[0] == nil) {
- ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
- ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
- }
-
- if(ctxt->headtype == Hplan9 && ctxt->plan9privates == nil)
- ctxt->plan9privates = linklookup(ctxt, "_privates", 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;
-
- cursym->locals = autoffset;
- cursym->args = p->to.u.argsize;
-
- q = nil;
-
- if(!(p->from3.offset & NOSPLIT) || (p->from3.offset & WRAPPER)) {
- p = appendp(ctxt, p);
- p = load_g_cx(ctxt, p); // load g into CX
- }
- if(!(cursym->text->from3.offset & NOSPLIT))
- p = stacksplit(ctxt, p, autoffset, !(cursym->text->from3.offset&NEEDCTXT), &q); // emit split check
-
- if(autoffset) {
- p = appendp(ctxt, p);
- p->as = AADJSP;
- p->from.type = TYPE_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->from3.offset & WRAPPER) {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOVL g_panic(CX), BX
- // TESTL BX, BX
- // JEQ end
- // LEAL (autoffset+4)(SP), DI
- // CMPL panic_argp(BX), DI
- // JNE end
- // MOVL SP, panic_argp(BX)
- // end:
- // NOP
- //
- // The NOP is needed to give the jumps somewhere to land.
- // It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes.
-
- p = appendp(ctxt, p);
- p->as = AMOVL;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_CX;
- p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
- p->to.type = TYPE_REG;
- p->to.reg = REG_BX;
-
- p = appendp(ctxt, p);
- p->as = ATESTL;
- p->from.type = TYPE_REG;
- p->from.reg = REG_BX;
- p->to.type = TYPE_REG;
- p->to.reg = REG_BX;
-
- p = appendp(ctxt, p);
- p->as = AJEQ;
- p->to.type = TYPE_BRANCH;
- p1 = p;
-
- p = appendp(ctxt, p);
- p->as = ALEAL;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_SP;
- p->from.offset = autoffset+4;
- p->to.type = TYPE_REG;
- p->to.reg = REG_DI;
-
- p = appendp(ctxt, p);
- p->as = ACMPL;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_BX;
- p->from.offset = 0; // Panic.argp
- p->to.type = TYPE_REG;
- p->to.reg = REG_DI;
-
- p = appendp(ctxt, p);
- p->as = AJNE;
- p->to.type = TYPE_BRANCH;
- p2 = p;
-
- p = appendp(ctxt, p);
- p->as = AMOVL;
- p->from.type = TYPE_REG;
- p->from.reg = REG_SP;
- p->to.type = TYPE_MEM;
- p->to.reg = REG_BX;
- p->to.offset = 0; // Panic.argp
-
- p = appendp(ctxt, p);
- p->as = ANOP;
- p1->pcond = p;
- p2->pcond = p;
- }
-
- if(ctxt->debugzerostack && autoffset && !(cursym->text->from3.offset&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 = TYPE_REG;
- p->from.reg = REG_SP;
- p->to.type = TYPE_REG;
- p->to.reg = REG_DI;
-
- p = appendp(ctxt, p);
- p->as = AMOVL;
- p->from.type = TYPE_CONST;
- p->from.offset = autoffset/4;
- p->to.type = TYPE_REG;
- p->to.reg = REG_CX;
-
- p = appendp(ctxt, p);
- p->as = AMOVL;
- p->from.type = TYPE_CONST;
- p->from.offset = 0;
- p->to.type = TYPE_REG;
- p->to.reg = REG_AX;
-
- p = appendp(ctxt, p);
- p->as = AREP;
-
- p = appendp(ctxt, p);
- p->as = ASTOSL;
- }
-
- for(; p != nil; p = p->link) {
- a = p->from.name;
- if(a == NAME_AUTO)
- p->from.offset += deltasp;
- if(a == NAME_PARAM)
- p->from.offset += deltasp + 4;
- a = p->to.name;
- if(a == NAME_AUTO)
- p->to.offset += deltasp;
- if(a == NAME_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(autoffset) {
- p->as = AADJSP;
- p->from.type = TYPE_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)
-{
- Prog *next;
-
- p->as = AMOVL;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_TLS;
- p->from.offset = 0;
- p->to.type = TYPE_REG;
- p->to.reg = REG_CX;
-
- next = p->link;
- progedit(ctxt, p);
- while(p->link != next)
- p = p->link;
-
- if(p->from.index == REG_TLS)
- p->from.scale = 2;
-
- 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, int noctxt, Prog **jmpok)
-{
- Prog *q, *q1;
-
- 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 = TYPE_MEM;
- p->from.reg = REG_CX;
- p->from.offset = 4;
- p->to.type = TYPE_REG;
- p->to.reg = REG_SP;
-
- p = appendp(ctxt, p);
- p->as = AJCC;
- p->to.type = TYPE_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
- p = appendp(ctxt, p);
- p->as = AINT;
- p->from.type = TYPE_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 = TYPE_REG;
- p->from.reg = REG_SP;
- p->to.type = TYPE_MEM;
- p->to.reg = REG_CX;
- p->to.offset = 2*ctxt->arch->ptrsize; // G.stackguard0
- if(ctxt->cursym->cfunc)
- p->to.offset = 3*ctxt->arch->ptrsize; // G.stackguard1
- } 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 = TYPE_MEM;
- p->from.reg = REG_SP;
- p->from.offset = -(framesize-StackSmall);
- p->to.type = TYPE_REG;
- p->to.reg = REG_AX;
-
- p = appendp(ctxt, p);
- p->as = ACMPL;
- p->from.type = TYPE_REG;
- p->from.reg = REG_AX;
- p->to.type = TYPE_MEM;
- p->to.reg = REG_CX;
- p->to.offset = 2*ctxt->arch->ptrsize; // G.stackguard0
- if(ctxt->cursym->cfunc)
- p->to.offset = 3*ctxt->arch->ptrsize; // G.stackguard1
- } 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 = TYPE_MEM;
- p->from.reg = REG_CX;
- p->from.offset = 0;
- p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0
- if(ctxt->cursym->cfunc)
- p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1
- p->to.type = TYPE_REG;
- p->to.reg = REG_SI;
-
- p = appendp(ctxt, p);
- p->as = ACMPL;
- p->from.type = TYPE_REG;
- p->from.reg = REG_SI;
- p->to.type = TYPE_CONST;
- p->to.offset = (uint32)StackPreempt;
-
- p = appendp(ctxt, p);
- p->as = AJEQ;
- p->to.type = TYPE_BRANCH;
- q1 = p;
-
- p = appendp(ctxt, p);
- p->as = ALEAL;
- p->from.type = TYPE_MEM;
- p->from.reg = REG_SP;
- p->from.offset = StackGuard;
- p->to.type = TYPE_REG;
- p->to.reg = REG_AX;
-
- p = appendp(ctxt, p);
- p->as = ASUBL;
- p->from.type = TYPE_REG;
- p->from.reg = REG_SI;
- p->from.offset = 0;
- p->to.type = TYPE_REG;
- p->to.reg = REG_AX;
-
- p = appendp(ctxt, p);
- p->as = ACMPL;
- p->from.type = TYPE_REG;
- p->from.reg = REG_AX;
- p->to.type = TYPE_CONST;
- p->to.offset = framesize+(StackGuard-StackSmall);
- }
-
- // common
- p = appendp(ctxt, p);
- p->as = AJHI;
- p->to.type = TYPE_BRANCH;
- p->to.offset = 4;
- q = p;
-
- p = appendp(ctxt, p);
- p->as = ACALL;
- p->to.type = TYPE_BRANCH;
- if(ctxt->cursym->cfunc)
- p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
- else
- p->to.sym = ctxt->symmorestack[noctxt];
-
- p = appendp(ctxt, p);
- p->as = AJMP;
- p->to.type = TYPE_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 = emallocz(sizeof(Prog));
- 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;
- int 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 = emallocz(sizeof(Prog));
- q->as = AJMP;
- q->lineno = p->lineno;
- q->to.type = TYPE_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 == TYPE_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",
- .thechar = '8',
- .endian = LittleEndian,
-
- .preprocess = preprocess,
- .assemble = span8,
- .follow = follow,
- .progedit = progedit,
-
- .minlc = 1,
- .ptrsize = 4,
- .regsize = 4,
-};
+++ /dev/null
-// cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
-//
-// 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-2008 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-2008 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/9l/9.out.h"
-#include "../runtime/stack.h"
-#include "../runtime/funcdata.h"
-
-static void
-progedit(Link *ctxt, Prog *p)
-{
- char literal[64];
- LSym *s;
-
- USED(ctxt);
-
- p->from.class = 0;
- p->to.class = 0;
-
- // Rewrite BR/BL to symbol as TYPE_BRANCH.
- switch(p->as) {
- case ABR:
- case ABL:
- case ARETURN:
- case ADUFFZERO:
- case ADUFFCOPY:
- if(p->to.sym != nil)
- p->to.type = TYPE_BRANCH;
- break;
- }
-
- // Rewrite float constants to values stored in memory.
- switch(p->as) {
- case AFMOVS:
- if(p->from.type == TYPE_FCONST) {
- uint32 i32;
- float32 f32;
- f32 = p->from.u.dval;
- memmove(&i32, &f32, 4);
- sprint(literal, "$f32.%08ux", i32);
- s = linklookup(ctxt, literal, 0);
- s->size = 4;
- p->from.type = TYPE_MEM;
- p->from.sym = s;
- p->from.name = NAME_EXTERN;
- p->from.offset = 0;
- }
- break;
- case AFMOVD:
- if(p->from.type == TYPE_FCONST) {
- uint64 i64;
- memmove(&i64, &p->from.u.dval, 8);
- sprint(literal, "$f64.%016llux", i64);
- s = linklookup(ctxt, literal, 0);
- s->size = 8;
- p->from.type = TYPE_MEM;
- p->from.sym = s;
- p->from.name = NAME_EXTERN;
- p->from.offset = 0;
- }
- break;
- case AMOVD:
- // Put >32-bit constants in memory and load them
- if(p->from.type == TYPE_CONST && p->from.name == NAME_NONE && p->from.reg == 0 && (int32)p->from.offset != p->from.offset) {
- sprint(literal, "$i64.%016llux", (uvlong)p->from.offset);
- s = linklookup(ctxt, literal, 0);
- s->size = 8;
- p->from.type = TYPE_MEM;
- p->from.sym = s;
- p->from.name = NAME_EXTERN;
- p->from.offset = 0;
- }
- }
-
- // Rewrite SUB constants into ADD.
- switch(p->as) {
- case ASUBC:
- if(p->from.type == TYPE_CONST) {
- p->from.offset = -p->from.offset;
- p->as = AADDC;
- }
- break;
-
- case ASUBCCC:
- if(p->from.type == TYPE_CONST) {
- p->from.offset = -p->from.offset;
- p->as = AADDCCC;
- }
- break;
-
- case ASUB:
- if(p->from.type == TYPE_CONST) {
- p->from.offset = -p->from.offset;
- p->as = AADD;
- }
- break;
- }
-}
-
-static Prog* stacksplit(Link*, Prog*, int32, int);
-
-static void
-preprocess(Link *ctxt, LSym *cursym)
-{
- Prog *p, *q, *p1, *p2, *q1;
- int o, mov, aoffset;
- vlong textstksiz;
- int32 autosize;
-
- if(ctxt->symmorestack[0] == nil) {
- ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
- ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
- // TODO(minux): add morestack short-cuts with small fixed frame-size.
- }
-
- ctxt->cursym = cursym;
-
- if(cursym->text == nil || cursym->text->link == nil)
- return;
-
- p = cursym->text;
- textstksiz = p->to.offset;
-
- cursym->args = p->to.u.argsize;
- cursym->locals = textstksiz;
-
- /*
- * find leaf subroutines
- * strip NOPs
- * expand RET
- * expand BECOME pseudo
- */
-
- if(ctxt->debugvlog)
- Bprint(ctxt->bso, "%5.2f noops\n", cputime());
- Bflush(ctxt->bso);
-
- q = nil;
- for(p = cursym->text; p != nil; p = p->link) {
- switch(p->as) {
- /* too hard, just leave alone */
- case ATEXT:
- q = p;
- p->mark |= LABEL|LEAF|SYNC;
- if(p->link)
- p->link->mark |= LABEL;
- break;
-
- case ANOR:
- q = p;
- if(p->to.type == TYPE_REG)
- if(p->to.reg == REGZERO)
- p->mark |= LABEL|SYNC;
- break;
-
- case ALWAR:
- case ASTWCCC:
- case AECIWX:
- case AECOWX:
- case AEIEIO:
- case AICBI:
- case AISYNC:
- case ATLBIE:
- case ATLBIEL:
- case ASLBIA:
- case ASLBIE:
- case ASLBMFEE:
- case ASLBMFEV:
- case ASLBMTE:
- case ADCBF:
- case ADCBI:
- case ADCBST:
- case ADCBT:
- case ADCBTST:
- case ADCBZ:
- case ASYNC:
- case ATLBSYNC:
- case APTESYNC:
- case ATW:
- case AWORD:
- case ARFI:
- case ARFCI:
- case ARFID:
- case AHRFID:
- q = p;
- p->mark |= LABEL|SYNC;
- continue;
-
- case AMOVW:
- case AMOVWZ:
- case AMOVD:
- q = p;
- if(p->from.reg >= REG_SPECIAL || p->to.reg >= REG_SPECIAL)
- p->mark |= LABEL|SYNC;
- continue;
-
- case AFABS:
- case AFABSCC:
- case AFADD:
- case AFADDCC:
- case AFCTIW:
- case AFCTIWCC:
- case AFCTIWZ:
- case AFCTIWZCC:
- case AFDIV:
- case AFDIVCC:
- case AFMADD:
- case AFMADDCC:
- case AFMOVD:
- case AFMOVDU:
- /* case AFMOVDS: */
- case AFMOVS:
- case AFMOVSU:
- /* case AFMOVSD: */
- case AFMSUB:
- case AFMSUBCC:
- case AFMUL:
- case AFMULCC:
- case AFNABS:
- case AFNABSCC:
- case AFNEG:
- case AFNEGCC:
- case AFNMADD:
- case AFNMADDCC:
- case AFNMSUB:
- case AFNMSUBCC:
- case AFRSP:
- case AFRSPCC:
- case AFSUB:
- case AFSUBCC:
- q = p;
- p->mark |= FLOAT;
- continue;
-
- case ABL:
- case ABCL:
- case ADUFFZERO:
- case ADUFFCOPY:
- cursym->text->mark &= ~LEAF;
-
- case ABC:
- case ABEQ:
- case ABGE:
- case ABGT:
- case ABLE:
- case ABLT:
- case ABNE:
- case ABR:
- case ABVC:
- case ABVS:
- p->mark |= BRANCH;
- q = p;
- q1 = p->pcond;
- if(q1 != nil) {
- while(q1->as == ANOP) {
- q1 = q1->link;
- p->pcond = q1;
- }
- if(!(q1->mark & LEAF))
- q1->mark |= LABEL;
- } else
- p->mark |= LABEL;
- q1 = p->link;
- if(q1 != nil)
- q1->mark |= LABEL;
- continue;
-
- case AFCMPO:
- case AFCMPU:
- q = p;
- p->mark |= FCMP|FLOAT;
- continue;
-
- case ARETURN:
- q = p;
- if(p->link != nil)
- p->link->mark |= LABEL;
- continue;
-
- case ANOP:
- q1 = p->link;
- q->link = q1; /* q is non-nop */
- q1->mark |= p->mark;
- continue;
-
- default:
- q = p;
- continue;
- }
- }
-
- autosize = 0;
- for(p = cursym->text; p != nil; p = p->link) {
- o = p->as;
- switch(o) {
- case ATEXT:
- mov = AMOVD;
- aoffset = 0;
- autosize = textstksiz + 8;
- if((p->mark & LEAF) && autosize <= 8)
- autosize = 0;
- else
- if(autosize & 4)
- autosize += 4;
- p->to.offset = autosize-8;
-
- if(!(p->from3.offset & NOSPLIT))
- p = stacksplit(ctxt, p, autosize, !(cursym->text->from3.offset&NEEDCTXT)); // emit split check
-
- q = p;
- if(autosize) {
- /* use MOVDU to adjust R1 when saving R31, if autosize is small */
- if(!(cursym->text->mark & LEAF) && autosize >= -BIG && autosize <= BIG) {
- mov = AMOVDU;
- aoffset = -autosize;
- } else {
- q = appendp(ctxt, p);
- q->as = AADD;
- q->lineno = p->lineno;
- q->from.type = TYPE_CONST;
- q->from.offset = -autosize;
- q->to.type = TYPE_REG;
- q->to.reg = REGSP;
- q->spadj = +autosize;
- }
- } else
- if(!(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;
- break;
- }
-
- q = appendp(ctxt, q);
- q->as = AMOVD;
- q->lineno = p->lineno;
- q->from.type = TYPE_REG;
- q->from.reg = REG_LR;
- q->to.type = TYPE_REG;
- q->to.reg = REGTMP;
-
- q = appendp(ctxt, q);
- q->as = mov;
- q->lineno = p->lineno;
- q->from.type = TYPE_REG;
- q->from.reg = REGTMP;
- q->to.type = TYPE_MEM;
- q->to.offset = aoffset;
- q->to.reg = REGSP;
- if(q->as == AMOVDU)
- q->spadj = -aoffset;
-
- if(cursym->text->from3.offset & WRAPPER) {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOVD g_panic(g), R3
- // CMP R0, R3
- // BEQ end
- // MOVD panic_argp(R3), R4
- // ADD $(autosize+8), R1, R5
- // CMP R4, R5
- // BNE end
- // ADD $8, R1, R6
- // MOVD R6, panic_argp(R3)
- // end:
- // NOP
- //
- // The NOP is needed to give the jumps somewhere to land.
- // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes.
-
-
- q = appendp(ctxt, q);
- q->as = AMOVD;
- q->from.type = TYPE_MEM;
- q->from.reg = REGG;
- q->from.offset = 4*ctxt->arch->ptrsize; // G.panic
- q->to.type = TYPE_REG;
- q->to.reg = REG_R3;
-
- q = appendp(ctxt, q);
- q->as = ACMP;
- q->from.type = TYPE_REG;
- q->from.reg = REG_R0;
- q->to.type = TYPE_REG;
- q->to.reg = REG_R3;
-
- q = appendp(ctxt, q);
- q->as = ABEQ;
- q->to.type = TYPE_BRANCH;
- p1 = q;
-
- q = appendp(ctxt, q);
- q->as = AMOVD;
- q->from.type = TYPE_MEM;
- q->from.reg = REG_R3;
- q->from.offset = 0; // Panic.argp
- q->to.type = TYPE_REG;
- q->to.reg = REG_R4;
-
- q = appendp(ctxt, q);
- q->as = AADD;
- q->from.type = TYPE_CONST;
- q->from.offset = autosize+8;
- q->reg = REGSP;
- q->to.type = TYPE_REG;
- q->to.reg = REG_R5;
-
- q = appendp(ctxt, q);
- q->as = ACMP;
- q->from.type = TYPE_REG;
- q->from.reg = REG_R4;
- q->to.type = TYPE_REG;
- q->to.reg = REG_R5;
-
- q = appendp(ctxt, q);
- q->as = ABNE;
- q->to.type = TYPE_BRANCH;
- p2 = q;
-
- q = appendp(ctxt, q);
- q->as = AADD;
- q->from.type = TYPE_CONST;
- q->from.offset = 8;
- q->reg = REGSP;
- q->to.type = TYPE_REG;
- q->to.reg = REG_R6;
-
- q = appendp(ctxt, q);
- q->as = AMOVD;
- q->from.type = TYPE_REG;
- q->from.reg = REG_R6;
- q->to.type = TYPE_MEM;
- q->to.reg = REG_R3;
- q->to.offset = 0; // Panic.argp
-
- q = appendp(ctxt, q);
- q->as = ANOP;
- p1->pcond = q;
- p2->pcond = q;
- }
-
- break;
-
- case ARETURN:
- if(p->from.type == TYPE_CONST) {
- ctxt->diag("using BECOME (%P) is not supported!", p);
- break;
- }
- if(p->to.sym) { // retjmp
- p->as = ABR;
- p->to.type = TYPE_BRANCH;
- break;
- }
- if(cursym->text->mark & LEAF) {
- if(!autosize) {
- p->as = ABR;
- p->from = zprog.from;
- p->to.type = TYPE_REG;
- p->to.reg = REG_LR;
- p->mark |= BRANCH;
- break;
- }
-
- p->as = AADD;
- p->from.type = TYPE_CONST;
- p->from.offset = autosize;
- p->to.type = TYPE_REG;
- p->to.reg = REGSP;
- p->spadj = -autosize;
-
- q = emallocz(sizeof(Prog));
- q->as = ABR;
- q->lineno = p->lineno;
- q->to.type = TYPE_REG;
- q->to.reg = REG_LR;
- q->mark |= BRANCH;
- q->spadj = +autosize;
-
- q->link = p->link;
- p->link = q;
- break;
- }
-
- p->as = AMOVD;
- p->from.type = TYPE_MEM;
- p->from.offset = 0;
- p->from.reg = REGSP;
- p->to.type = TYPE_REG;
- p->to.reg = REGTMP;
-
- q = emallocz(sizeof(Prog));
- q->as = AMOVD;
- q->lineno = p->lineno;
- q->from.type = TYPE_REG;
- q->from.reg = REGTMP;
- q->to.type = TYPE_REG;
- q->to.reg = REG_LR;
-
- q->link = p->link;
- p->link = q;
- p = q;
-
- if(0) {
- // Debug bad returns
- q = emallocz(sizeof(Prog));
- q->as = AMOVD;
- q->lineno = p->lineno;
- q->from.type = TYPE_MEM;
- q->from.offset = 0;
- q->from.reg = REGTMP;
- q->to.type = TYPE_REG;
- q->to.reg = REGTMP;
-
- q->link = p->link;
- p->link = q;
- p = q;
- }
-
- if(autosize) {
- q = emallocz(sizeof(Prog));
- q->as = AADD;
- q->lineno = p->lineno;
- q->from.type = TYPE_CONST;
- q->from.offset = autosize;
- q->to.type = TYPE_REG;
- q->to.reg = REGSP;
- q->spadj = -autosize;
-
- q->link = p->link;
- p->link = q;
- }
-
- q1 = emallocz(sizeof(Prog));
- q1->as = ABR;
- q1->lineno = p->lineno;
- q1->to.type = TYPE_REG;
- q1->to.reg = REG_LR;
- q1->mark |= BRANCH;
- q1->spadj = +autosize;
-
- q1->link = q->link;
- q->link = q1;
- break;
-
- case AADD:
- if(p->to.type == TYPE_REG && p->to.reg == REGSP && p->from.type == TYPE_CONST)
- p->spadj = -p->from.offset;
- break;
- }
- }
-
-/*
-// instruction scheduling
- if(debug['Q'] == 0)
- return;
-
- curtext = nil;
- q = nil; // p - 1
- q1 = firstp; // top of block
- o = 0; // count of instructions
- for(p = firstp; p != nil; p = p1) {
- p1 = p->link;
- o++;
- if(p->mark & NOSCHED){
- if(q1 != p){
- sched(q1, q);
- }
- for(; p != nil; p = p->link){
- if(!(p->mark & NOSCHED))
- break;
- q = p;
- }
- p1 = p;
- q1 = p;
- o = 0;
- continue;
- }
- if(p->mark & (LABEL|SYNC)) {
- if(q1 != p)
- sched(q1, q);
- q1 = p;
- o = 1;
- }
- if(p->mark & (BRANCH|SYNC)) {
- sched(q1, p);
- q1 = p1;
- o = 0;
- }
- if(o >= NSCHED) {
- sched(q1, p);
- q1 = p1;
- o = 0;
- }
- q = p;
- }
-*/
-}
-
-static Prog*
-stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
-{
- Prog *q, *q1;
-
- // MOVD g_stackguard(g), R3
- p = appendp(ctxt, p);
- p->as = AMOVD;
- p->from.type = TYPE_MEM;
- p->from.reg = REGG;
- p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0
- if(ctxt->cursym->cfunc)
- p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1
- p->to.type = TYPE_REG;
- p->to.reg = REG_R3;
-
- q = nil;
- if(framesize <= StackSmall) {
- // small stack: SP < stackguard
- // CMP stackguard, SP
- p = appendp(ctxt, p);
- p->as = ACMPU;
- p->from.type = TYPE_REG;
- p->from.reg = REG_R3;
- p->to.type = TYPE_REG;
- p->to.reg = REGSP;
- } else if(framesize <= StackBig) {
- // large stack: SP-framesize < stackguard-StackSmall
- // ADD $-framesize, SP, R4
- // CMP stackguard, R4
- p = appendp(ctxt, p);
- p->as = AADD;
- p->from.type = TYPE_CONST;
- p->from.offset = -framesize;
- p->reg = REGSP;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R4;
-
- p = appendp(ctxt, p);
- p->as = ACMPU;
- p->from.type = TYPE_REG;
- p->from.reg = REG_R3;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R4;
- } 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.
- // // stackguard is R3
- // CMP R3, $StackPreempt
- // BEQ label-of-call-to-morestack
- // ADD $StackGuard, SP, R4
- // SUB R3, R4
- // MOVD $(framesize+(StackGuard-StackSmall)), R31
- // CMPU R31, R4
- p = appendp(ctxt, p);
- p->as = ACMP;
- p->from.type = TYPE_REG;
- p->from.reg = REG_R3;
- p->to.type = TYPE_CONST;
- p->to.offset = StackPreempt;
-
- q = p = appendp(ctxt, p);
- p->as = ABEQ;
- p->to.type = TYPE_BRANCH;
-
- p = appendp(ctxt, p);
- p->as = AADD;
- p->from.type = TYPE_CONST;
- p->from.offset = StackGuard;
- p->reg = REGSP;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R4;
-
- p = appendp(ctxt, p);
- p->as = ASUB;
- p->from.type = TYPE_REG;
- p->from.reg = REG_R3;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R4;
-
- p = appendp(ctxt, p);
- p->as = AMOVD;
- p->from.type = TYPE_CONST;
- p->from.offset = framesize + StackGuard - StackSmall;
- p->to.type = TYPE_REG;
- p->to.reg = REGTMP;
-
- p = appendp(ctxt, p);
- p->as = ACMPU;
- p->from.type = TYPE_REG;
- p->from.reg = REGTMP;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R4;
- }
-
- // q1: BLT done
- q1 = p = appendp(ctxt, p);
- p->as = ABLT;
- p->to.type = TYPE_BRANCH;
-
- // MOVD LR, R5
- p = appendp(ctxt, p);
- p->as = AMOVD;
- p->from.type = TYPE_REG;
- p->from.reg = REG_LR;
- p->to.type = TYPE_REG;
- p->to.reg = REG_R5;
- if(q)
- q->pcond = p;
-
- // BL runtime.morestack(SB)
- p = appendp(ctxt, p);
- p->as = ABL;
- p->to.type = TYPE_BRANCH;
- if(ctxt->cursym->cfunc)
- p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
- else
- p->to.sym = ctxt->symmorestack[noctxt];
-
- // BR start
- p = appendp(ctxt, p);
- p->as = ABR;
- p->to.type = TYPE_BRANCH;
- p->pcond = ctxt->cursym->text->link;
-
- // placeholder for q1's jump target
- p = appendp(ctxt, p);
- p->as = ANOP; // zero-width place holder
- q1->pcond = p;
-
- return p;
-}
-
-static void xfol(Link*, Prog*, Prog**);
-
-static void
-follow(Link *ctxt, LSym *s)
-{
- Prog *firstp, *lastp;
-
- ctxt->cursym = s;
-
- firstp = emallocz(sizeof(Prog));
- 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 ABGE: return ABLT;
- case ABLT: return ABGE;
-
- case ABGT: return ABLE;
- case ABLE: return ABGT;
-
- case ABVC: return ABVS;
- case ABVS: return ABVC;
- }
- return 0;
-}
-
-static void
-xfol(Link *ctxt, Prog *p, Prog **last)
-{
- Prog *q, *r;
- int a, b, i;
-
-loop:
- if(p == nil)
- return;
- a = p->as;
- if(a == ABR) {
- q = p->pcond;
- if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){
- p->mark |= FOLL;
- (*last)->link = p;
- *last = p;
- p = p->link;
- xfol(ctxt, p, last);
- p = q;
- if(p && !(p->mark & FOLL))
- goto loop;
- return;
- }
- if(q != nil) {
- 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->mark&NOSCHED))
- break;
- b = 0; /* set */
- a = q->as;
- if(a == ANOP) {
- i--;
- continue;
- }
- if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID)
- goto copy;
- if(!q->pcond || (q->pcond->mark&FOLL))
- continue;
- b = relinv(a);
- if(!b)
- continue;
- copy:
- for(;;) {
- r = emallocz(sizeof(Prog));
- *r = *p;
- if(!(r->mark&FOLL))
- print("cant 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 == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID)
- return;
- r->as = b;
- r->pcond = p->link;
- r->link = p->pcond;
- if(!(r->link->mark&FOLL))
- xfol(ctxt, r->link, last);
- if(!(r->pcond->mark&FOLL))
- print("cant happen 2\n");
- return;
- }
- }
-
- a = ABR;
- q = emallocz(sizeof(Prog));
- q->as = a;
- q->lineno = p->lineno;
- q->to.type = TYPE_BRANCH;
- q->to.offset = p->pc;
- q->pcond = p;
- p = q;
- }
- p->mark |= FOLL;
- (*last)->link = p;
- *last = p;
- if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID){
- if(p->mark & NOSCHED){
- p = p->link;
- goto loop;
- }
- return;
- }
- if(p->pcond != nil)
- if(a != ABL && p->link != nil) {
- xfol(ctxt, p->link, last);
- p = p->pcond;
- if(p == nil || (p->mark&FOLL))
- return;
- goto loop;
- }
- p = p->link;
- goto loop;
-}
-
-LinkArch linkppc64 = {
- .name = "ppc64",
- .thechar = '9',
- .endian = BigEndian,
-
- .preprocess = preprocess,
- .assemble = span9,
- .follow = follow,
- .progedit = progedit,
-
- .minlc = 4,
- .ptrsize = 8,
- .regsize = 8,
-};
-
-LinkArch linkppc64le = {
- .name = "ppc64le",
- .thechar = '9',
- .endian = LittleEndian,
-
- .preprocess = preprocess,
- .assemble = span9,
- .follow = follow,
- .progedit = progedit,
-
- .minlc = 4,
- .ptrsize = 8,
- .regsize = 8,
-};
#include "../cmd/ld/textflag.h"
#include "../runtime/funcdata.h"
-static void writesym(Link*, Biobuf*, LSym*);
-static void wrint(Biobuf*, int64);
-static void wrstring(Biobuf*, char*);
-static void wrpath(Link *, Biobuf*, char*);
-static void wrdata(Biobuf*, void*, int);
-static void wrsym(Biobuf*, LSym*);
-static void wrpathsym(Link *ctxt, Biobuf *b, LSym *s);
-
static void readsym(Link*, Biobuf*, char*, char*);
static int64 rdint(Biobuf*);
static char *rdstring(Biobuf*);
static void rddata(Biobuf*, uchar**, int*);
static LSym *rdsym(Link*, Biobuf*, char*);
-void writeobjdirect(Link *ctxt, Biobuf *b);
-
-void writeobjgo1(Link*, char*);
-void writeobjgo2(Link*, char*, int64);
-
extern char *outfile;
-void
-writeobj(Link *ctxt, Biobuf *b)
-{
- vlong start;
- char *env;
-
- // If $GOOBJ > 0, invoke the Go version of the liblink
- // output routines via a subprocess.
- // If $GOOBJ == 1, copy that subprocess's output to
- // the actual output file.
- // If $GOOBJ >= 2, generate output using the usual C version
- // but then check that the subprocess wrote the same bytes.
- // $GOOBJ is a temporary setting for the transition to a
- // Go liblink back end. Once the C liblink back ends are deleted,
- // we will hard code the GOOBJ=1 behavior.
- env = getenv("GOOBJ");
- if(env == nil)
- env = "0";
- if(atoi(env) == 0) {
- writeobjdirect(ctxt, b);
- return;
- }
-
- Bflush(b);
- start = Boffset(b);
- writeobjgo1(ctxt, outfile);
- if(atoi(env) > 1) {
- writeobjdirect(ctxt, b);
- Bflush(b);
- }
- writeobjgo2(ctxt, outfile, start);
- Bseek(b, 0, 2);
-}
-
-// The Go and C compilers, and the assembler, call writeobj to write
-// out a Go object file. The linker does not call this; the linker
-// does not write out object files.
-void
-writeobjdirect(Link *ctxt, Biobuf *b)
-{
- int flag, found;
- Hist *h;
- LSym *s, *text, *etext, *curtext, *data, *edata;
- Plist *pl;
- Prog *p, *plink;
- Auto *a;
-
- // Build list of symbols, and assign instructions to lists.
- // Ignore ctxt->plist boundaries. There are no guarantees there,
- // and the C compilers and assemblers just use one big list.
- text = nil;
- curtext = nil;
- data = nil;
- etext = nil;
- edata = nil;
- for(pl = ctxt->plist; pl != nil; pl = pl->link) {
- for(p = pl->firstpc; p != nil; p = plink) {
- if(ctxt->debugasm && ctxt->debugvlog)
- print("obj: %P\n", p);
- plink = p->link;
- p->link = nil;
-
- if(p->as == AEND)
- continue;
-
- if(p->as == ATYPE) {
- // Assume each TYPE instruction describes
- // a different local variable or parameter,
- // so no dedup.
- // Using only the TYPE instructions means
- // that we discard location information about local variables
- // in C and assembly functions; that information is inferred
- // from ordinary references, because there are no TYPE
- // instructions there. Without the type information, gdb can't
- // use the locations, so we don't bother to save them.
- // If something else could use them, we could arrange to
- // preserve them.
- if(curtext == nil)
- continue;
- a = emallocz(sizeof *a);
- a->asym = p->from.sym;
- a->aoffset = p->from.offset;
- a->name = p->from.name;
- a->gotype = p->from.gotype;
- a->link = curtext->autom;
- curtext->autom = a;
- continue;
- }
-
- if(p->as == AGLOBL) {
- s = p->from.sym;
- if(s->seenglobl++)
- print("duplicate %P\n", p);
- if(s->onlist)
- sysfatal("symbol %s listed multiple times", s->name);
- s->onlist = 1;
- if(data == nil)
- data = s;
- else
- edata->next = s;
- s->next = nil;
- s->size = p->to.offset;
- if(s->type == 0 || s->type == SXREF)
- s->type = SBSS;
- flag = p->from3.offset;
- if(flag & DUPOK)
- s->dupok = 1;
- if(flag & RODATA)
- s->type = SRODATA;
- else if(flag & NOPTR)
- s->type = SNOPTRBSS;
- edata = s;
- continue;
- }
-
- if(p->as == ADATA) {
- savedata(ctxt, p->from.sym, p, "<input>");
- continue;
- }
-
- if(p->as == ATEXT) {
- s = p->from.sym;
- if(s == nil) {
- // func _() { }
- curtext = nil;
- continue;
- }
- if(s->text != nil)
- sysfatal("duplicate TEXT for %s", s->name);
- if(s->onlist)
- sysfatal("symbol %s listed multiple times", s->name);
- s->onlist = 1;
- if(text == nil)
- text = s;
- else
- etext->next = s;
- etext = s;
- flag = p->from3.offset;
- if(flag & DUPOK)
- s->dupok = 1;
- if(flag & NOSPLIT)
- s->nosplit = 1;
- s->next = nil;
- s->type = STEXT;
- s->text = p;
- s->etext = p;
- curtext = s;
- continue;
- }
-
- if(p->as == AFUNCDATA) {
- // Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
- if(curtext == nil) // func _() {}
- continue;
- if(strcmp(p->to.sym->name, "go_args_stackmap") == 0) {
- if(p->from.type != TYPE_CONST || p->from.offset != FUNCDATA_ArgsPointerMaps)
- ctxt->diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps");
- p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", curtext->name), curtext->version);
- }
- }
-
- if(curtext == nil)
- continue;
- s = curtext;
- s->etext->link = p;
- s->etext = p;
- }
- }
-
- // Add reference to Go arguments for C or assembly functions without them.
- for(s = text; s != nil; s = s->next) {
- if(strncmp(s->name, "\"\".", 3) != 0)
- continue;
- found = 0;
- for(p = s->text; p != nil; p = p->link) {
- if(p->as == AFUNCDATA && p->from.type == TYPE_CONST && p->from.offset == FUNCDATA_ArgsPointerMaps) {
- found = 1;
- break;
- }
- }
- if(!found) {
- p = appendp(ctxt, s->text);
- p->as = AFUNCDATA;
- p->from.type = TYPE_CONST;
- p->from.offset = FUNCDATA_ArgsPointerMaps;
- p->to.type = TYPE_MEM;
- p->to.name = NAME_EXTERN;
- p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", s->name), s->version);
- }
- }
-
- // Turn functions into machine code images.
- for(s = text; s != nil; s = s->next) {
- mkfwd(s);
- linkpatch(ctxt, s);
- ctxt->arch->follow(ctxt, s);
- ctxt->arch->preprocess(ctxt, s);
- ctxt->arch->assemble(ctxt, s);
- linkpcln(ctxt, s);
- }
-
- // Emit header.
- Bputc(b, 0);
- Bputc(b, 0);
- Bprint(b, "go13ld");
- Bputc(b, 1); // version
-
- // Emit autolib.
- for(h = ctxt->hist; h != nil; h = h->link)
- if(h->offset < 0)
- wrstring(b, h->name);
- wrstring(b, "");
-
- // Emit symbols.
- for(s = text; s != nil; s = s->next)
- writesym(ctxt, b, s);
- for(s = data; s != nil; s = s->next)
- writesym(ctxt, b, s);
-
- // Emit footer.
- Bputc(b, 0xff);
- Bputc(b, 0xff);
- Bprint(b, "go13ld");
-}
-
-static void
-writesym(Link *ctxt, Biobuf *b, LSym *s)
-{
- Reloc *r;
- int i, j, c, n;
- Pcln *pc;
- Prog *p;
- Auto *a;
- char *name;
-
- if(ctxt->debugasm) {
- Bprint(ctxt->bso, "%s ", s->name);
- if(s->version)
- Bprint(ctxt->bso, "v=%d ", s->version);
- if(s->type)
- Bprint(ctxt->bso, "t=%d ", s->type);
- if(s->dupok)
- Bprint(ctxt->bso, "dupok ");
- if(s->cfunc)
- Bprint(ctxt->bso, "cfunc ");
- if(s->nosplit)
- Bprint(ctxt->bso, "nosplit ");
- Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
- if(s->type == STEXT) {
- Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
- if(s->leaf)
- Bprint(ctxt->bso, " leaf");
- }
- Bprint(ctxt->bso, "\n");
- for(p=s->text; p != nil; p = p->link)
- Bprint(ctxt->bso, "\t%#06ux %P\n", (int)p->pc, p);
- for(i=0; i<s->np; ) {
- Bprint(ctxt->bso, "\t%#06ux", i);
- for(j=i; j<i+16 && j<s->np; j++)
- Bprint(ctxt->bso, " %02ux", s->p[j]);
- for(; j<i+16; j++)
- Bprint(ctxt->bso, " ");
- Bprint(ctxt->bso, " ");
- for(j=i; j<i+16 && j<s->np; j++) {
- c = s->p[j];
- if(' ' <= c && c <= 0x7e)
- Bprint(ctxt->bso, "%c", c);
- else
- Bprint(ctxt->bso, ".");
- }
- Bprint(ctxt->bso, "\n");
- i += 16;
- }
- for(i=0; i<s->nr; i++) {
- r = &s->r[i];
- name = "";
- if(r->sym != nil)
- name = r->sym->name;
- if(ctxt->arch->thechar == '5' || ctxt->arch->thechar == '9')
- Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%llux\n", (int)r->off, r->siz, r->type, name, (vlong)r->add);
- else
- Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, name, (vlong)r->add);
- }
- }
-
- Bputc(b, 0xfe);
- wrint(b, s->type);
- wrstring(b, s->name);
- wrint(b, s->version);
- wrint(b, s->dupok);
- wrint(b, s->size);
- wrsym(b, s->gotype);
- wrdata(b, s->p, s->np);
-
- wrint(b, s->nr);
- for(i=0; i<s->nr; i++) {
- r = &s->r[i];
- wrint(b, r->off);
- wrint(b, r->siz);
- wrint(b, r->type);
- wrint(b, r->add);
- wrint(b, r->xadd);
- wrsym(b, r->sym);
- wrsym(b, r->xsym);
- }
-
- if(s->type == STEXT) {
- wrint(b, s->args);
- wrint(b, s->locals);
- wrint(b, s->nosplit);
- wrint(b, s->leaf | s->cfunc<<1);
- n = 0;
- for(a = s->autom; a != nil; a = a->link)
- n++;
- wrint(b, n);
- for(a = s->autom; a != nil; a = a->link) {
- wrsym(b, a->asym);
- wrint(b, a->aoffset);
- if(a->name == NAME_AUTO)
- wrint(b, A_AUTO);
- else if(a->name == NAME_PARAM)
- wrint(b, A_PARAM);
- else
- sysfatal("%s: invalid local variable type %d", s->name, a->name);
- wrsym(b, a->gotype);
- }
-
- pc = s->pcln;
- wrdata(b, pc->pcsp.p, pc->pcsp.n);
- wrdata(b, pc->pcfile.p, pc->pcfile.n);
- wrdata(b, pc->pcline.p, pc->pcline.n);
- wrint(b, pc->npcdata);
- for(i=0; i<pc->npcdata; i++)
- wrdata(b, pc->pcdata[i].p, pc->pcdata[i].n);
- wrint(b, pc->nfuncdata);
- for(i=0; i<pc->nfuncdata; i++)
- wrsym(b, pc->funcdata[i]);
- for(i=0; i<pc->nfuncdata; i++)
- wrint(b, pc->funcdataoff[i]);
- wrint(b, pc->nfile);
- for(i=0; i<pc->nfile; i++)
- wrpathsym(ctxt, b, pc->file[i]);
- }
-}
-
-static void
-wrint(Biobuf *b, int64 sval)
-{
- uint64 uv, v;
- uchar buf[10], *p;
-
- uv = ((uint64)sval<<1) ^ (uint64)(int64)(sval>>63);
-
- p = buf;
- for(v = uv; v >= 0x80; v >>= 7)
- *p++ = v | 0x80;
- *p++ = v;
-
- Bwrite(b, buf, p - buf);
-}
-
-static void
-wrstring(Biobuf *b, char *s)
-{
- wrdata(b, s, strlen(s));
-}
-
-// wrpath writes a path just like a string, but on windows, it
-// translates '\\' to '/' in the process.
-static void
-wrpath(Link *ctxt, Biobuf *b, char *p)
-{
- int i, n;
- if (!ctxt->windows || strchr(p, '\\') == nil) {
- wrstring(b, p);
- return;
- } else {
- n = strlen(p);
- wrint(b, n);
- for (i = 0; i < n; i++)
- Bputc(b, p[i] == '\\' ? '/' : p[i]);
- }
-}
-
-static void
-wrdata(Biobuf *b, void *v, int n)
-{
- wrint(b, n);
- Bwrite(b, v, n);
-}
-
-static void
-wrpathsym(Link *ctxt, Biobuf *b, LSym *s)
-{
- if(s == nil) {
- wrint(b, 0);
- wrint(b, 0);
- return;
- }
- wrpath(ctxt, b, s->name);
- wrint(b, s->version);
-}
-
-static void
-wrsym(Biobuf *b, LSym *s)
-{
- if(s == nil) {
- wrint(b, 0);
- wrint(b, 0);
- return;
- }
- wrstring(b, s->name);
- wrint(b, s->version);
-}
-
static char startmagic[] = "\x00\x00go13ld";
static char endmagic[] = "\xff\xffgo13ld";
+++ /dev/null
-// Copyright 2015 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.
-
-// Writing of internal program representation to a serialized form
-// so that the Go translation of these routines can do the actual
-// program layout.
-// The serialized form and this code support the piecewise transition
-// from C to Go and will be removed along with the rest of the C code
-// when it is no longer needed.
-// There has been no attempt to make it particularly efficient, nor will there be.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-/*c2go
-
-char *mktempdir(void);
-int runcmd(char**);
-void removeall(char*);
-*/
-
-static void printtype(Link*, Biobuf*, int);
-static void printsym(Link*, Biobuf*, LSym*);
-static void printprog(Link*, Biobuf*, Prog*);
-static void printaddr(Link*, Biobuf*, Addr*);
-static void printhist(Link*, Biobuf*, Hist*);
-static void printint(Link*, Biobuf*, int64);
-static void printstr(Link*, Biobuf*, char*);
-static void printptr(Link*, Biobuf*, void*);
-
-#undef waitpid
-
-enum
-{
- TypeEnd = 0,
- TypeCtxt,
- TypePlist,
- TypeSym,
- TypeProg,
- TypeAddr,
- TypeHist,
-};
-
-void
-writeobjgo1(Link *ctxt, char *outfile)
-{
- int i;
- char *p;
- Biobuf *bw;
- Plist *pl;
-
- p = smprint("%s.goliblink.in", outfile);
- bw = Bopen(p, OWRITE);
- if(bw == nil)
- sysfatal("writing liblinktest input: %r");
-
- printtype(ctxt, bw, TypeCtxt);
- printstr(ctxt, bw, ctxt->arch->name);
- printint(ctxt, bw, ctxt->goarm);
- printint(ctxt, bw, ctxt->debugasm);
- printstr(ctxt, bw, ctxt->trimpath);
- printptr(ctxt, bw, ctxt->plist);
- printptr(ctxt, bw, ctxt->plast);
- printptr(ctxt, bw, ctxt->hist);
- printptr(ctxt, bw, ctxt->ehist);
- for(i = 0; i < LINKHASH; i++) {
- if(ctxt->hash[i] != nil) {
- printint(ctxt, bw, i);
- printptr(ctxt, bw, ctxt->hash[i]);
- }
- }
- printint(ctxt, bw, -1);
-
- printhist(ctxt, bw, ctxt->hist);
- printhist(ctxt, bw, ctxt->ehist);
-
- for(pl=ctxt->plist; pl != nil; pl = pl->link) {
- printtype(ctxt, bw, TypePlist);
- printptr(ctxt, bw, pl);
- printint(ctxt, bw, pl->recur);
- printptr(ctxt, bw, pl->name);
- printptr(ctxt, bw, pl->firstpc);
- printptr(ctxt, bw, pl->link);
- printsym(ctxt, bw, pl->name);
- printprog(ctxt, bw, pl->firstpc);
- }
-
- for(i = 0; i < LINKHASH; i++)
- printsym(ctxt, bw, ctxt->hash[i]);
-
- printtype(ctxt, bw, TypeEnd);
- Bterm(bw);
-}
-
-void
-writeobjgo2(Link *ctxt, char *outfile, int64 offset)
-{
- char *p, *env, *prog, *cmd[10];
- char offsetbuf[20];
-
- USED(ctxt);
-
- env = getenv("GOOBJWRITER");
- if(env != nil && env[0] != '\0')
- prog = env;
- else
- prog = smprint("%s/pkg/tool/%s_%s/objwriter", getgoroot(), getgohostos(), getgohostarch());
-
- p = smprint("%s.goliblink.in", outfile);
-
- snprint(offsetbuf, sizeof offsetbuf, "%lld", offset);
-
- cmd[0] = prog;
- cmd[1] = p;
- cmd[2] = outfile;
- cmd[3] = offsetbuf;
- cmd[4] = ctxt->arch->name;
- cmd[5] = nil;
- if(runcmd(cmd) < 0)
- sysfatal("running %s: %r", prog);
-
- env = getenv("GOOBJ");
- if(env == nil || atoi(env) <= 2)
- remove(p);
-}
-
-static void
-printtype(Link *ctxt, Biobuf *bw, int t)
-{
- printint(ctxt, bw, t);
-}
-
-static void
-printint(Link *ctxt, Biobuf *bw, int64 v)
-{
- uint64 u;
-
- USED(ctxt);
-
- u = (uint64)(v<<1) ^ (uint64)(v>>63);
- while(u >= 0x80) {
- Bputc(bw, u&0x7F | 0x80);
- u >>= 7;
- }
- Bputc(bw, u);
-}
-
-static void
-printstr(Link *ctxt, Biobuf *bw, char *s)
-{
- if(s == nil)
- s = "";
- printint(ctxt, bw, strlen(s));
- Bwrite(bw, s, strlen(s));
-}
-
-static void
-printptr(Link *ctxt, Biobuf *bw, void *v)
-{
- printint(ctxt, bw, (int64)(uintptr)v);
-}
-
-static void
-printsym(Link *ctxt, Biobuf *bw, LSym *s)
-{
- int i;
- Reloc *r;
-
- if(s == nil || s->printed)
- return;
- s->printed = 1;
- printtype(ctxt, bw, TypeSym);
- printptr(ctxt, bw, s);
- printstr(ctxt, bw, s->name);
- printstr(ctxt, bw, s->extname);
- printint(ctxt, bw, s->type);
- printint(ctxt, bw, s->version);
- printint(ctxt, bw, s->dupok);
- printint(ctxt, bw, s->external);
- printint(ctxt, bw, s->nosplit);
- printint(ctxt, bw, s->reachable);
- printint(ctxt, bw, s->cgoexport);
- printint(ctxt, bw, s->special);
- printint(ctxt, bw, s->stkcheck);
- printint(ctxt, bw, s->hide);
- printint(ctxt, bw, s->leaf);
- printint(ctxt, bw, s->fnptr);
- printint(ctxt, bw, s->seenglobl);
- printint(ctxt, bw, s->onlist);
- printint(ctxt, bw, s->symid);
- printint(ctxt, bw, s->dynid);
- printint(ctxt, bw, s->sig);
- printint(ctxt, bw, s->plt);
- printint(ctxt, bw, s->got);
- printint(ctxt, bw, s->align);
- printint(ctxt, bw, s->elfsym);
- printint(ctxt, bw, s->args);
- printint(ctxt, bw, s->locals);
- printint(ctxt, bw, s->value);
- printint(ctxt, bw, s->size);
- printptr(ctxt, bw, s->hash);
- printptr(ctxt, bw, s->allsym);
- printptr(ctxt, bw, s->next);
- printptr(ctxt, bw, s->sub);
- printptr(ctxt, bw, s->outer);
- printptr(ctxt, bw, s->gotype);
- printptr(ctxt, bw, s->reachparent);
- printptr(ctxt, bw, s->queue);
- printstr(ctxt, bw, s->file);
- printstr(ctxt, bw, s->dynimplib);
- printstr(ctxt, bw, s->dynimpvers);
- printptr(ctxt, bw, s->text);
- printptr(ctxt, bw, s->etext);
- printint(ctxt, bw, s->np);
- Bwrite(bw, s->p, s->np);
- printint(ctxt, bw, s->nr);
- for(i=0; i<s->nr; i++) {
- r = s->r+i;
- printint(ctxt, bw, r->off);
- printint(ctxt, bw, r->siz);
- printint(ctxt, bw, r->done);
- printint(ctxt, bw, r->type);
- printint(ctxt, bw, r->add);
- printint(ctxt, bw, r->xadd);
- printptr(ctxt, bw, r->sym);
- printptr(ctxt, bw, r->xsym);
- }
-
- printsym(ctxt, bw, s->hash);
- printsym(ctxt, bw, s->allsym);
- printsym(ctxt, bw, s->next);
- printsym(ctxt, bw, s->sub);
- printsym(ctxt, bw, s->outer);
- printsym(ctxt, bw, s->gotype);
- printsym(ctxt, bw, s->reachparent);
- printsym(ctxt, bw, s->queue);
- printprog(ctxt, bw, s->text);
- printprog(ctxt, bw, s->etext);
- for(i=0; i<s->nr; i++) {
- r = s->r+i;
- printsym(ctxt, bw, r->sym);
- printsym(ctxt, bw, r->xsym);
- }
-}
-
-static void
-printprog(Link *ctxt, Biobuf *bw, Prog *p0)
-{
- Prog *p, *q;
-
- for(p = p0; p != nil && !p->printed; p=p->link) {
- p->printed = 1;
-
- printtype(ctxt, bw, TypeProg);
- printptr(ctxt, bw, p);
- printint(ctxt, bw, p->pc);
- printint(ctxt, bw, p->lineno);
- printptr(ctxt, bw, p->link);
- printint(ctxt, bw, p->as);
- printint(ctxt, bw, p->reg);
- printint(ctxt, bw, p->scond);
- printint(ctxt, bw, p->width);
- printaddr(ctxt, bw, &p->from);
- printaddr(ctxt, bw, &p->from3);
- printaddr(ctxt, bw, &p->to);
- printsym(ctxt, bw, p->from.sym);
- printsym(ctxt, bw, p->from.gotype);
- printsym(ctxt, bw, p->to.sym);
- printsym(ctxt, bw, p->to.gotype);
- }
-
- q = p;
- for(p=p0; p!=q; p=p->link) {
- if(p->from.type == TYPE_BRANCH)
- printprog(ctxt, bw, p->from.u.branch);
- if(p->to.type == TYPE_BRANCH)
- printprog(ctxt, bw, p->to.u.branch);
- }
-}
-
-static void
-printaddr(Link *ctxt, Biobuf *bw, Addr *a)
-{
- static char zero[8];
-
- printtype(ctxt, bw, TypeAddr);
- printint(ctxt, bw, a->offset);
- if(a->type == TYPE_FCONST) {
- uint64 u;
- float64 f;
- f = a->u.dval;
- memmove(&u, &f, 8);
- printint(ctxt, bw, u);
- } else
- printint(ctxt, bw, 0);
- if(a->type == TYPE_SCONST)
- Bwrite(bw, a->u.sval, 8);
- else
- Bwrite(bw, zero, 8);
- if(a->type == TYPE_BRANCH)
- printptr(ctxt, bw, a->u.branch);
- else
- printptr(ctxt, bw, nil);
- printptr(ctxt, bw, a->sym);
- printptr(ctxt, bw, a->gotype);
- printint(ctxt, bw, a->type);
- printint(ctxt, bw, a->index);
- printint(ctxt, bw, a->scale);
- printint(ctxt, bw, a->reg);
- printint(ctxt, bw, a->name);
- printint(ctxt, bw, a->class);
- printint(ctxt, bw, a->etype);
- if(a->type == TYPE_TEXTSIZE)
- printint(ctxt, bw, a->u.argsize);
- else
- printint(ctxt, bw, 0);
- printint(ctxt, bw, a->width);
-}
-
-static void
-printhist(Link *ctxt, Biobuf *bw, Hist *h)
-{
- if(h == nil || h->printed)
- return;
- h->printed = 1;
-
- printtype(ctxt, bw, TypeHist);
- printptr(ctxt, bw, h);
- printptr(ctxt, bw, h->link);
- if(h->name == nil)
- printstr(ctxt, bw, "<pop>");
- else
- printstr(ctxt, bw, h->name);
- printint(ctxt, bw, h->line);
- printint(ctxt, bw, h->offset);
- printhist(ctxt, bw, h->link);
-}
+++ /dev/null
-// 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;
-
- USED(ctxt);
- for(i=0; i<20; i++) {
- if(p == nil || p->as != AJMP || p->pcond == nil)
- return p;
- p = p->pcond;
- }
- return nil;
-}
-
-Prog*
-brloop(Link *ctxt, Prog *p)
-{
- int c;
- Prog *q;
-
- USED(ctxt);
- c = 0;
- for(q = p; q != nil; q = q->pcond) {
- if(q->as != AJMP || q->pcond == nil)
- break;
- c++;
- if(c >= 5000)
- return nil;
- }
- return q;
-}
-
-static void
-checkaddr(Link *ctxt, Prog *p, Addr *a)
-{
- // Check expected encoding, especially TYPE_CONST vs TYPE_ADDR.
- switch(a->type) {
- case TYPE_NONE:
- return;
-
- case TYPE_BRANCH:
- if(a->reg != 0 || a->index != 0 || a->scale != 0 || a->name != 0)
- break;
- return;
-
- case TYPE_TEXTSIZE:
- if(a->reg != 0 || a->index != 0 || a->scale != 0 || a->name != 0)
- break;
- return;
-
- case TYPE_MEM:
- //if(a->u.bits != 0)
- // break;
- return;
-
- case TYPE_CONST:
- // TODO(rsc): After fixing SHRQ, check a->index != 0 too.
- if(a->name != 0 || a->sym != 0 || a->reg != 0) {
- ctxt->diag("argument %D is TYPE_CONST, should be TYPE_ADDR, in %P", a, p);
- return;
- }
- if(a->reg != 0 || a->scale != 0 || a->name != 0 || a->sym != nil || a->u.bits != 0)
- break;
- return;
-
- case TYPE_FCONST:
- case TYPE_SCONST:
- if(a->reg != 0 || a->index != 0 || a->scale != 0 || a->name != 0 || a->offset != 0 || a->sym != nil)
- break;
- return;
-
- case TYPE_REG:
- // TODO(rsc): After fixing PINSRQ, check a->offset != 0 too.
- // TODO(rsc): After fixing SHRQ, check a->index != 0 too.
- if(a->scale != 0 || a->name != 0 || a->sym != nil)
- break;
- return;
-
- case TYPE_ADDR:
- if(a->u.bits != 0)
- break;
- if(a->reg == 0 && a->index == 0 && a->scale == 0 && a->name == 0 && a->sym == nil)
- ctxt->diag("argument %D is TYPE_ADDR, should be TYPE_CONST, in %P", a, p);
- return;
-
- case TYPE_SHIFT:
- if(a->index != 0 || a->scale != 0 || a->name != 0 || a->sym != nil || a->u.bits != 0)
- break;
- return;
-
- case TYPE_REGREG:
- if(a->index != 0 || a->scale != 0 || a->name != 0 || a->sym != nil || a->u.bits != 0)
- break;
- return;
-
- case TYPE_REGREG2:
- return;
-
- case TYPE_INDIR:
- // Expect sym and name to be set, nothing else.
- // Technically more is allowed, but this is only used for *name(SB).
- if(a->reg != 0 || a->index != 0 || a->scale != 0 || a->name == 0 || a->offset != 0 || a->sym == nil || a->u.bits != 0)
- break;
- return;
- }
-
- ctxt->diag("invalid encoding for argument %D in %P", a, p);
-}
-
-void
-linkpatch(Link *ctxt, LSym *sym)
-{
- int32 c;
- char *name;
- Prog *p, *q;
-
- ctxt->cursym = sym;
-
- for(p = sym->text; p != nil; p = p->link) {
- checkaddr(ctxt, p, &p->from);
- checkaddr(ctxt, p, &p->from3);
- checkaddr(ctxt, p, &p->to);
-
- if(ctxt->arch->progedit)
- ctxt->arch->progedit(ctxt, p);
- if(p->to.type != TYPE_BRANCH)
- continue;
- if(p->to.u.branch != nil) {
- // TODO: Remove to.u.branch in favor of p->pcond.
- p->pcond = p->to.u.branch;
- continue;
- }
- if(p->to.sym != nil)
- 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) {
- name = "<nil>";
- if(p->to.sym)
- name = p->to.sym->name;
- ctxt->diag("branch out of range (%#ux)\n%P [%s]", c, p, name);
- p->to.type = TYPE_NONE;
- }
- p->to.u.branch = q;
- 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 == TYPE_BRANCH)
- p->to.offset = p->pcond->pc;
- }
- }
-}
#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
//
// 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) {
- ctxt->debugpcln -= dbg;
- 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;
-
- USED(sym);
-
- if(p->as == ATEXT || p->as == ANOP || p->as == AUSEFIELD || p->lineno == 0 || phase == 1)
- return oldval;
- linkgetline(ctxt, 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 != 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 == APCDATA && p->from.offset >= npcdata)
- npcdata = p->from.offset+1;
- if(p->as == 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 == 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 == 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) == 0)
- 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 == AFUNCDATA) {
- i = p->from.offset;
- pcln->funcdataoff[i] = p->to.offset;
- if(p->to.type != TYPE_CONST) {
- // TODO: Dedup.
- //funcdata_bytes += p->to.sym->size;
- pcln->funcdata[i] = p->to.sym;
- }
- }
- }
- }
-}
// iteration over encoded pcdata tables.
char *p;
char buf[1024];
- linksetexp();
nuxiinit(arch);
ctxt = emallocz(sizeof *ctxt);
ctxt->arch = arch;
ctxt->version = HistVersion;
ctxt->goroot = getgoroot();
- ctxt->goroot_final = getenv("GOROOT_FINAL");
- if(ctxt->goroot_final != nil && ctxt->goroot_final[0] == '\0')
- ctxt->goroot_final = nil;
p = getgoarch();
if(strcmp(p, arch->name) != 0)
if(*p == '\\')
*p = '/';
}
- ctxt->pathname = strdup(buf);
ctxt->headtype = headtype(getgoos());
if(ctxt->headtype < 0)
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);
-}