From: Russ Cox Date: Wed, 25 Feb 2015 02:40:57 +0000 (-0500) Subject: liblink: delete unused code X-Git-Tag: go1.5beta1~1844 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=26438d4d80c8c517f1d287d065ad7a967160281e;p=gostls13.git liblink: delete unused code 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 Reviewed-by: Brad Fitzpatrick --- diff --git a/include/link.h b/include/link.h index 7fa136b035..c511a95cf1 100644 --- a/include/link.h +++ b/include/link.h @@ -28,14 +28,10 @@ // 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; @@ -43,158 +39,6 @@ typedef struct Pcln Pcln; 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) -// -// $ -// Effective address of memory reference , defined above. -// Encoding: same as memory reference, but type = TYPE_ADDR. -// -// $<±integer value> -// This is a special case of $, in which only ±offset is present. -// It has a separate type for easy recognition. -// Encoding: -// type = TYPE_CONST -// offset = ±integer value -// -// * -// Indirect reference through memory reference , 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. -// -// $*$ -// No longer used. -// On machines with actual SB registers, $*$ forced the -// instruction encoding to use a full 32-bit constant, never a -// reference relative to SB. -// -// $ -// Floating point constant value. -// Encoding: -// type = TYPE_FCONST -// u.dval = floating point value -// -// $ -// String literal value (raw bytes used for DATA instruction). -// Encoding: -// type = TYPE_SCONST -// u.sval = string -// -// -// 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 -// 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; @@ -208,79 +52,6 @@ struct Reloc 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 @@ -300,12 +71,8 @@ struct LSym 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; @@ -331,8 +98,6 @@ struct LSym // STEXT Auto* autom; - Prog* text; - Prog* etext; Pcln* pcln; // SDATA, SBSS @@ -454,23 +219,6 @@ enum 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 @@ -539,65 +287,21 @@ struct Link 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; @@ -606,14 +310,10 @@ struct Link 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; }; @@ -630,11 +330,6 @@ struct LinkArch 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; @@ -670,24 +365,11 @@ extern uchar inuxi2[2]; 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); @@ -696,91 +378,28 @@ vlong adduint32(Link *ctxt, LSym *s, uint32 v); vlong adduint64(Link *ctxt, LSym *s, uint64 v); vlong adduint8(Link *ctxt, LSym *s, uint8 v); vlong adduintxx(Link *ctxt, LSym *s, uint64 v, int wid); -void mangle(char *file); -void savedata(Link *ctxt, LSym *s, Prog *p, char *pn); -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; @@ -788,18 +407,3 @@ extern LinkArch linkamd64p32; 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 diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h deleted file mode 100644 index a266a6b87c..0000000000 --- a/src/cmd/5l/5.out.h +++ /dev/null @@ -1,336 +0,0 @@ -// 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[]; */ diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h index b32b89bb06..0258d5a776 100644 --- a/src/cmd/5l/l.h +++ b/src/cmd/5l/l.h @@ -57,7 +57,6 @@ vlong archrelocvariant(Reloc *r, LSym *s, vlong t); 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 */ diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c deleted file mode 100644 index d4cc8acd7c..0000000000 --- a/src/cmd/5l/list.c +++ /dev/null @@ -1,40 +0,0 @@ -// 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(); -} diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c index a7bd0f45ea..887cc5aef4 100644 --- a/src/cmd/5l/obj.c +++ b/src/cmd/5l/obj.c @@ -70,7 +70,6 @@ linkarchinit(void) thearch.elfreloc1 = elfreloc1; thearch.elfsetupplt = elfsetupplt; thearch.gentext = gentext; - thearch.listinit = listinit; thearch.machoreloc1 = machoreloc1; thearch.lput = lputl; thearch.wput = wputl; diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h deleted file mode 100644 index e25c6efec8..0000000000 --- a/src/cmd/6l/6.out.h +++ /dev/null @@ -1,855 +0,0 @@ -// 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" diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index acc97d93d4..b314e25836 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -58,7 +58,6 @@ vlong archrelocvariant(Reloc *r, LSym *s, vlong t); 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 */ diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c deleted file mode 100644 index 6c4ea79f91..0000000000 --- a/src/cmd/6l/list.c +++ /dev/null @@ -1,40 +0,0 @@ -// 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(); -} diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index 0a2b2cb59e..ebd4bae894 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -72,7 +72,6 @@ linkarchinit(void) thearch.elfreloc1 = elfreloc1; thearch.elfsetupplt = elfsetupplt; thearch.gentext = gentext; - thearch.listinit = listinit; thearch.machoreloc1 = machoreloc1; thearch.lput = lputl; thearch.wput = wputl; diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h deleted file mode 100644 index 273a8ad523..0000000000 --- a/src/cmd/8l/8.out.h +++ /dev/null @@ -1,643 +0,0 @@ -// 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" diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h index e844bc4180..77c06b3656 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -57,7 +57,6 @@ vlong archrelocvariant(Reloc *r, LSym *s, vlong t); 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 */ diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c deleted file mode 100644 index 4cd8f08d34..0000000000 --- a/src/cmd/8l/list.c +++ /dev/null @@ -1,40 +0,0 @@ -// 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(); -} diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c index 41900d6543..767db331da 100644 --- a/src/cmd/8l/obj.c +++ b/src/cmd/8l/obj.c @@ -70,7 +70,6 @@ linkarchinit(void) thearch.elfreloc1 = elfreloc1; thearch.elfsetupplt = elfsetupplt; thearch.gentext = gentext; - thearch.listinit = listinit; thearch.machoreloc1 = machoreloc1; thearch.lput = lputl; thearch.wput = wputl; diff --git a/src/cmd/9l/9.out.h b/src/cmd/9l/9.out.h deleted file mode 100644 index 6e95698db9..0000000000 --- a/src/cmd/9l/9.out.h +++ /dev/null @@ -1,611 +0,0 @@ -// 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" diff --git a/src/cmd/9l/l.h b/src/cmd/9l/l.h index a634cf80b4..5c048d2570 100644 --- a/src/cmd/9l/l.h +++ b/src/cmd/9l/l.h @@ -31,7 +31,6 @@ #include #include #include -#include "9.out.h" #ifndef EXTERN #define EXTERN extern @@ -57,7 +56,6 @@ vlong archrelocvariant(Reloc *r, LSym *s, vlong t); 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 */ diff --git a/src/cmd/9l/list.c b/src/cmd/9l/list.c deleted file mode 100644 index af8dc15885..0000000000 --- a/src/cmd/9l/list.c +++ /dev/null @@ -1,40 +0,0 @@ -// 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(); -} diff --git a/src/cmd/9l/obj.c b/src/cmd/9l/obj.c index 17dd5caacd..5449319f38 100644 --- a/src/cmd/9l/obj.c +++ b/src/cmd/9l/obj.c @@ -71,7 +71,6 @@ linkarchinit(void) thearch.elfreloc1 = elfreloc1; thearch.elfsetupplt = elfsetupplt; thearch.gentext = gentext; - thearch.listinit = listinit; thearch.machoreloc1 = machoreloc1; if(thelinkarch == &linkppc64le) { thearch.lput = lputl; diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index a9b4988a38..00d289cf29 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -475,7 +475,6 @@ var proto_gccargs = []string{ "-Wno-switch", "-Wno-comment", "-Wno-missing-field-initializers", - "-Werror", "-fno-common", "-ggdb", "-pipe", @@ -531,10 +530,6 @@ var deptab = []struct { "$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", @@ -574,15 +569,15 @@ var gentab = []struct { 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, diff --git a/src/cmd/dist/buildgc.go b/src/cmd/dist/buildgc.go deleted file mode 100644 index b59aa5b5a4..0000000000 --- a/src/cmd/dist/buildgc.go +++ /dev/null @@ -1,117 +0,0 @@ -// 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 \n") - fmt.Fprintf(&out, "#include \n") - fmt.Fprintf(&out, "#include \n") - fmt.Fprintf(&out, "#include \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) -} diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index 4990a80535..6a36c9ac95 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -60,7 +60,6 @@ struct Arch { int (*elfreloc1)(Reloc*, vlong); void (*elfsetupplt)(void); void (*gentext)(void); - void (*listinit)(void); int (*machoreloc1)(Reloc*, vlong); void (*lput)(uint32); diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c index 0a48eb3a76..1e9a12747a 100644 --- a/src/cmd/ld/pobj.c +++ b/src/cmd/ld/pobj.c @@ -57,7 +57,6 @@ ldmain(int argc, char **argv) ctxt->bso = &bso; Binit(&bso, 1, OWRITE); - thearch.listinit(); memset(debug, 0, sizeof(debug)); nerrors = 0; outfile = nil; @@ -128,12 +127,6 @@ ldmain(int argc, char **argv) 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) @@ -154,7 +147,6 @@ ldmain(int argc, char **argv) headstring = headstr(HEADTYPE); thearch.archinit(); - ctxt->debugfloat = debug['F']; if(debug['v']) Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n", @@ -201,8 +193,6 @@ ldmain(int argc, char **argv) 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); diff --git a/src/liblink/arch.c b/src/liblink/arch.c new file mode 100644 index 0000000000..2e425a6117 --- /dev/null +++ b/src/liblink/arch.c @@ -0,0 +1,68 @@ +// 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 +#include +#include +#include + +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, +}; diff --git a/src/liblink/asm5.c b/src/liblink/asm5.c deleted file mode 100644 index 398b7841c2..0000000000 --- a/src/liblink/asm5.c +++ /dev/null @@ -1,2689 +0,0 @@ -// Inferno utils/5l/span.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Instruction layout. - -#include -#include -#include -#include -#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>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(; oa2 == 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; iflag_shared) - optab[n].size += optab[n].pcrelsiz; - else - optab[n].flag &= ~LPCREL; - } - } - qsort(optab, n, sizeof(optab[0]), ocmp); - for(i=0; idiag("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<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< 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; -} diff --git a/src/liblink/asm6.c b/src/liblink/asm6.c deleted file mode 100644 index 8119f74a14..0000000000 --- a/src/liblink/asm6.c +++ /dev/null @@ -1,3640 +0,0 @@ -// Inferno utils/6l/span.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Instruction layout. - -#include -#include -#include -#include -#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; inp; i++) { - print(" %.2ux", s->p[i]); - if(i%16 == 15) - print("\n %.6ux", i+1); - } - if(i%16) - print("\n"); - - for(i=0; inr; 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= 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; - } - } -} diff --git a/src/liblink/asm8.c b/src/liblink/asm8.c deleted file mode 100644 index ed1e7bc078..0000000000 --- a/src/liblink/asm8.c +++ /dev/null @@ -1,2822 +0,0 @@ -// Inferno utils/8l/span.c -// http://code.google.com/p/inferno-os/source/browse/utils/8l/span.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Instruction layout. - -#include -#include -#include -#include -#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; inp; i++) { - print(" %.2ux", s->p[i]); - if(i%16 == 15) - print("\n %.6ux", i+1); - } - if(i%16) - print("\n"); - - for(i=0; inr; 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= 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"); - } -} diff --git a/src/liblink/asm9.c b/src/liblink/asm9.c deleted file mode 100644 index 742d204b5b..0000000000 --- a/src/liblink/asm9.c +++ /dev/null @@ -1,2836 +0,0 @@ -// 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 -#include -#include -#include -#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; isize/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(; oa2 == 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; idiag("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; -} - diff --git a/src/liblink/data.c b/src/liblink/data.c index e9dbc966b9..06fe7e0471 100644 --- a/src/liblink/data.c +++ b/src/liblink/data.c @@ -34,11 +34,6 @@ #include #include -void -mangle(char *file) -{ - sysfatal("%s: mangled input file", file); -} void symgrow(Link *ctxt, LSym *s, vlong lsiz) @@ -70,80 +65,6 @@ 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; ip[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) @@ -237,11 +158,6 @@ setuint8(Link *ctxt, LSym *s, vlong r, uint8 v) return setuintxx(ctxt, s, r, v, 1); } -vlong -setuint16(Link *ctxt, LSym *s, vlong r, uint16 v) -{ - return setuintxx(ctxt, s, r, v, 2); -} vlong setuint32(Link *ctxt, LSym *s, vlong r, uint32 v) @@ -249,11 +165,6 @@ 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) diff --git a/src/liblink/go.c b/src/liblink/go.c index 08ce82b30c..6dae3f438c 100644 --- a/src/liblink/go.c +++ b/src/liblink/go.c @@ -9,67 +9,6 @@ #include #include -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; ias = 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; -} diff --git a/src/liblink/ld.c b/src/liblink/ld.c index e055829142..5dfb4efc21 100644 --- a/src/liblink/ld.c +++ b/src/liblink/ld.c @@ -176,66 +176,8 @@ uchar inuxi2[2]; 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; itext; 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) diff --git a/src/liblink/list5.c b/src/liblink/list5.c deleted file mode 100644 index 3ea411d2b8..0000000000 --- a/src/liblink/list5.c +++ /dev/null @@ -1,386 +0,0 @@ -// 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 -#include -#include -#include -#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; iargs, char*); - p = str; - for(i=0; i= '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); -} diff --git a/src/liblink/list6.c b/src/liblink/list6.c deleted file mode 100644 index b324ec89d6..0000000000 --- a/src/liblink/list6.c +++ /dev/null @@ -1,418 +0,0 @@ -// 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 -#include -#include -#include -#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= '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); -} diff --git a/src/liblink/list8.c b/src/liblink/list8.c deleted file mode 100644 index 07c1d7cd67..0000000000 --- a/src/liblink/list8.c +++ /dev/null @@ -1,359 +0,0 @@ -// 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 -#include -#include -#include -#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= '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); -} diff --git a/src/liblink/list9.c b/src/liblink/list9.c deleted file mode 100644 index ac37bb566e..0000000000 --- a/src/liblink/list9.c +++ /dev/null @@ -1,370 +0,0 @@ -// 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 -#include -#include -#include -#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= '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); -} diff --git a/src/liblink/obj.c b/src/liblink/obj.c deleted file mode 100644 index b8083b0ec4..0000000000 --- a/src/liblink/obj.c +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include -#include - -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, ""); - - 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: \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 HISTSZ) - n = HISTSZ; - for(i=0; iplist == nil) - ctxt->plist = pl; - else - ctxt->plast->link = pl; - ctxt->plast = pl; - - return pl; -} diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c deleted file mode 100644 index abddbc3c4f..0000000000 --- a/src/liblink/obj5.c +++ /dev/null @@ -1,998 +0,0 @@ -// 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 -#include -#include -#include -#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, , 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, -}; diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c deleted file mode 100644 index 546c89d53c..0000000000 --- a/src/liblink/obj6.c +++ /dev/null @@ -1,1046 +0,0 @@ -// Inferno utils/6l/pass.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include -#include -#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, -}; diff --git a/src/liblink/obj8.c b/src/liblink/obj8.c deleted file mode 100644 index eb8e318762..0000000000 --- a/src/liblink/obj8.c +++ /dev/null @@ -1,842 +0,0 @@ -// Inferno utils/8l/pass.c -// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include -#include -#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, -}; diff --git a/src/liblink/obj9.c b/src/liblink/obj9.c deleted file mode 100644 index 450ed00306..0000000000 --- a/src/liblink/obj9.c +++ /dev/null @@ -1,944 +0,0 @@ -// 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 -#include -#include -#include -#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, -}; diff --git a/src/liblink/objfile.c b/src/liblink/objfile.c index 99f5e97607..ab88c45550 100644 --- a/src/liblink/objfile.c +++ b/src/liblink/objfile.c @@ -105,442 +105,14 @@ #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, ""); - 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; inp; ) { - Bprint(ctxt->bso, "\t%#06ux", i); - for(j=i; jnp; j++) - Bprint(ctxt->bso, " %02ux", s->p[j]); - for(; jbso, " "); - Bprint(ctxt->bso, " "); - for(j=i; jnp; 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; inr; 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; inr; 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; inpcdata; i++) - wrdata(b, pc->pcdata[i].p, pc->pcdata[i].n); - wrint(b, pc->nfuncdata); - for(i=0; infuncdata; i++) - wrsym(b, pc->funcdata[i]); - for(i=0; infuncdata; i++) - wrint(b, pc->funcdataoff[i]); - wrint(b, pc->nfile); - for(i=0; infile; 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"; diff --git a/src/liblink/objfilego.c b/src/liblink/objfilego.c deleted file mode 100644 index 406019312d..0000000000 --- a/src/liblink/objfilego.c +++ /dev/null @@ -1,340 +0,0 @@ -// 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 -#include -#include -#include - -/*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; inr; 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; inr; 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, ""); - else - printstr(ctxt, bw, h->name); - printint(ctxt, bw, h->line); - printint(ctxt, bw, h->offset); - printhist(ctxt, bw, h->link); -} diff --git a/src/liblink/pass.c b/src/liblink/pass.c deleted file mode 100644 index db5c4ebd13..0000000000 --- a/src/liblink/pass.c +++ /dev/null @@ -1,201 +0,0 @@ -// Inferno utils/6l/pass.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Code and data passes. - -#include -#include -#include -#include - -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 = ""; - 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; - } - } -} diff --git a/src/liblink/pcln.c b/src/liblink/pcln.c index 93e4127a1e..cdc11b85db 100644 --- a/src/liblink/pcln.c +++ b/src/liblink/pcln.c @@ -7,31 +7,6 @@ #include #include -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 @@ -43,263 +18,23 @@ addvarint(Link *ctxt, Pcdata *d, uint32 val) // // 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; in; 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; infile; 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>(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. diff --git a/src/liblink/sym.c b/src/liblink/sym.c index cae7e4aafe..9ee179717a 100644 --- a/src/liblink/sym.c +++ b/src/liblink/sym.c @@ -90,16 +90,12 @@ linknew(LinkArch *arch) 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) @@ -116,7 +112,6 @@ linknew(LinkArch *arch) if(*p == '\\') *p = '/'; } - ctxt->pathname = strdup(buf); ctxt->headtype = headtype(getgoos()); if(ctxt->headtype < 0) @@ -258,14 +253,3 @@ linkrlookup(Link *ctxt, char *name, int v) return _lookup(ctxt, name, v, 0); } -int -linksymfmt(Fmt *f) -{ - LSym *s; - - s = va_arg(f->args, LSym*); - if(s == nil) - return fmtstrcpy(f, ""); - - return fmtstrcpy(f, s->name); -}