diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-09-13 13:13:40 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-09-13 13:13:40 +0200 |
commit | 5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch) | |
tree | c0650497e988f47be9c6f2324fa692a52dea82e1 /src/cmd/6l | |
parent | 80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff) | |
download | golang-upstream/60.tar.gz |
Imported Upstream version 60upstream/60
Diffstat (limited to 'src/cmd/6l')
-rw-r--r-- | src/cmd/6l/6.out.h | 866 | ||||
-rw-r--r-- | src/cmd/6l/Makefile | 48 | ||||
-rw-r--r-- | src/cmd/6l/asm.c | 1179 | ||||
-rw-r--r-- | src/cmd/6l/doc.go | 53 | ||||
-rw-r--r-- | src/cmd/6l/l.h | 421 | ||||
-rw-r--r-- | src/cmd/6l/list.c | 458 | ||||
-rw-r--r-- | src/cmd/6l/mkenam | 45 | ||||
-rw-r--r-- | src/cmd/6l/obj.c | 765 | ||||
-rw-r--r-- | src/cmd/6l/optab.c | 1279 | ||||
-rw-r--r-- | src/cmd/6l/pass.c | 722 | ||||
-rw-r--r-- | src/cmd/6l/prof.c | 171 | ||||
-rw-r--r-- | src/cmd/6l/span.c | 1747 |
12 files changed, 7754 insertions, 0 deletions
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h new file mode 100644 index 000000000..262da02ab --- /dev/null +++ b/src/cmd/6l/6.out.h @@ -0,0 +1,866 @@ +// 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 +#define NOPROF (1<<0) +#define DUPOK (1<<1) +#define NOSPLIT (1<<2) +#define RODATA (1<<3) + +/* + * amd64 + */ + +enum as +{ + AXXX, + AAAA, + 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, + ACALL, + ACLC, + ACLD, + ACLI, + ACLTS, + ACMC, + ACMPB, + ACMPL, + ACMPW, + ACMPSB, + ACMPSL, + ACMPSW, + ADAA, + ADAS, + ADATA, + ADECB, + ADECL, + ADECQ, + ADECW, + ADIVB, + ADIVL, + ADIVW, + AENTER, + AGLOBL, + AGOK, + AHISTORY, + AHLT, + AIDIVB, + AIDIVL, + AIDIVW, + AIMULB, + AIMULL, + AIMULW, + AINB, + AINL, + AINW, + AINCB, + AINCL, + AINCQ, + AINCW, + AINSB, + AINSL, + AINSW, + AINT, + AINTO, + AIRETL, + AIRETW, + AJCC, + AJCS, + AJCXZ, + AJEQ, + AJGE, + AJGT, + AJHI, + AJLE, + AJLS, + AJLT, + AJMI, + AJMP, + 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, + ANAME, + ANEGB, + ANEGL, + ANEGW, + ANOP, + 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, + ARET, + 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, + ATEXT, + 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, + + AEND, + + ADYNT_, + AINIT_, + + ASIGNAME, + + /* 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, + 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, + APMADDWL, + APMAXSW, + APMAXUB, + APMINSW, + APMINUB, + APMOVMSKB, + APMULHRW, + APMULHUW, + APMULHW, + APMULLW, + APMULULQ, + APOR, + APSADBW, + APSHUFHW, + APSHUFL, + APSHUFLW, + APSHUFW, + 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, + + ALAST +}; + +enum +{ + + D_AL = 0, + D_CL, + D_DL, + D_BL, + D_SPB, + D_BPB, + D_SIB, + D_DIB, + D_R8B, + D_R9B, + D_R10B, + D_R11B, + D_R12B, + D_R13B, + D_R14B, + D_R15B, + + D_AX = 16, + D_CX, + D_DX, + D_BX, + D_SP, + D_BP, + D_SI, + D_DI, + D_R8, + D_R9, + D_R10, + D_R11, + D_R12, + D_R13, + D_R14, + D_R15, + + D_AH = 32, + D_CH, + D_DH, + D_BH, + + D_F0 = 36, + + D_M0 = 44, + + D_X0 = 52, + D_X1, + D_X2, + D_X3, + D_X4, + D_X5, + D_X6, + D_X7, + + D_CS = 68, + D_SS, + D_DS, + D_ES, + D_FS, + D_GS, + + D_GDTR, /* global descriptor table register */ + D_IDTR, /* interrupt descriptor table register */ + D_LDTR, /* local descriptor table register */ + D_MSW, /* machine status word */ + D_TASK, /* task register */ + + D_CR = 79, + D_DR = 95, + D_TR = 103, + + D_NONE = 111, + + D_BRANCH = 112, + D_EXTERN = 113, + D_STATIC = 114, + D_AUTO = 115, + D_PARAM = 116, + D_CONST = 117, + D_FCONST = 118, + D_SCONST = 119, + D_ADDR = 120, + + D_FILE, + D_FILE1, + + D_INDIR, /* additive */ + + D_SIZE = D_INDIR + D_INDIR, /* 6l internal */ + D_PCREL, + + 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, + + REGARG = -1, + REGRET = D_AX, + FREGRET = D_X0, + REGSP = D_SP, + REGTMP = D_DI, + REGEXT = D_R15, /* compiler allocates external registers R15 down */ + FREGMIN = D_X0+5, /* first register variable */ + FREGEXT = D_X0+15 /* first external register */ +}; + +/* + * this is the ranlib header + */ +#define SYMDEF "__.SYMDEF" + +/* + * this is the simulated IEEE floating point + */ +typedef struct ieee Ieee; +struct ieee +{ + int32 l; /* contains ls-man 0xffffffff */ + int32 h; /* contains sign 0x80000000 + exp 0x7ff00000 + ms-man 0x000fffff */ +}; diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile new file mode 100644 index 000000000..8ed3e1411 --- /dev/null +++ b/src/cmd/6l/Makefile @@ -0,0 +1,48 @@ +# 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 ../../Make.inc +O:=$(HOST_O) + +TARG=6l + +OFILES=\ + asm.$O\ + data.$O\ + dwarf.$O\ + elf.$O\ + enam.$O\ + go.$O\ + ldelf.$O\ + ldmacho.$O\ + ldpe.$O\ + lib.$O\ + list.$O\ + macho.$O\ + obj.$O\ + optab.$O\ + pass.$O\ + pe.$O\ + prof.$O\ + span.$O\ + symtab.$O\ + +HFILES=\ + l.h\ + 6.out.h\ + ../ld/lib.h\ + ../ld/elf.h\ + ../ld/macho.h\ + ../ld/dwarf.h\ + ../ld/pe.h\ + +include ../../Make.ccmd + +enam.c: 6.out.h + sh mkenam + +CLEANFILES+=enam.c + +%.$O: ../ld/%.c + $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c new file mode 100644 index 000000000..3a8223e65 --- /dev/null +++ b/src/cmd/6l/asm.c @@ -0,0 +1,1179 @@ +// Inferno utils/6l/asm.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Writing object files. + +#include "l.h" +#include "../ld/lib.h" +#include "../ld/elf.h" +#include "../ld/dwarf.h" +#include "../ld/macho.h" +#include "../ld/pe.h" + +#define Dbufslop 100 + +#define PADDR(a) ((uint32)(a) & ~0x80000000) + +char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2"; +char freebsddynld[] = "/libexec/ld-elf.so.1"; +char openbsddynld[] = "/usr/libexec/ld.so"; + +char zeroes[32]; + +vlong +entryvalue(void) +{ + char *a; + Sym *s; + + a = INITENTRY; + if(*a >= '0' && *a <= '9') + return atolwhex(a); + s = lookup(a, 0); + if(s->type == 0) + return INITTEXT; + if(s->type != STEXT) + diag("entry not text: %s", s->name); + return s->value; +} + +vlong +datoff(vlong addr) +{ + if(addr >= segdata.vaddr) + return addr - segdata.vaddr + segdata.fileoff; + if(addr >= segtext.vaddr) + return addr - segtext.vaddr + segtext.fileoff; + diag("datoff %#llx", addr); + return 0; +} + +enum { + ElfStrEmpty, + ElfStrInterp, + ElfStrHash, + ElfStrGot, + ElfStrGotPlt, + ElfStrDynamic, + ElfStrDynsym, + ElfStrDynstr, + ElfStrRela, + ElfStrText, + ElfStrData, + ElfStrBss, + ElfStrShstrtab, + ElfStrSymtab, + ElfStrStrtab, + ElfStrRelaPlt, + ElfStrPlt, + ElfStrGnuVersion, + ElfStrGnuVersionR, + NElfStr +}; + +vlong elfstr[NElfStr]; + +static int +needlib(char *name) +{ + char *p; + Sym *s; + + if(*name == '\0') + return 0; + + /* reuse hash code in symbol table */ + p = smprint(".elfload.%s", name); + s = lookup(p, 0); + if(s->type == 0) { + s->type = 100; // avoid SDATA, etc. + return 1; + } + return 0; +} + +int nelfsym = 1; + +static void addpltsym(Sym*); +static void addgotsym(Sym*); + +void +adddynrel(Sym *s, Reloc *r) +{ + Sym *targ, *rela, *got; + + targ = r->sym; + cursym = s; + + switch(r->type) { + default: + if(r->type >= 256) { + diag("unexpected relocation type %d", r->type); + return; + } + break; + + // Handle relocations found in ELF object files. + case 256 + R_X86_64_PC32: + if(targ->dynimpname != nil && !targ->dynexport) + diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name); + if(targ->type == 0 || targ->type == SXREF) + diag("unknown symbol %s in pcrel", targ->name); + r->type = D_PCREL; + r->add += 4; + return; + + case 256 + R_X86_64_PLT32: + r->type = D_PCREL; + r->add += 4; + if(targ->dynimpname != nil && !targ->dynexport) { + addpltsym(targ); + r->sym = lookup(".plt", 0); + r->add += targ->plt; + } + return; + + case 256 + R_X86_64_GOTPCREL: + if(targ->dynimpname == nil || targ->dynexport) { + // have symbol + if(r->off >= 2 && s->p[r->off-2] == 0x8b) { + // turn MOVQ of GOT entry into LEAQ of symbol itself + s->p[r->off-2] = 0x8d; + r->type = D_PCREL; + r->add += 4; + return; + } + // fall back to using GOT and hope for the best (CMOV*) + // TODO: just needs relocation, no need to put in .dynsym + targ->dynimpname = targ->name; + } + addgotsym(targ); + r->type = D_PCREL; + r->sym = lookup(".got", 0); + r->add += 4; + r->add += targ->got; + return; + + case 256 + R_X86_64_64: + if(targ->dynimpname != nil && !targ->dynexport) + diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name); + r->type = D_ADDR; + return; + + // Handle relocations found in Mach-O object files. + case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0: + case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0: + case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0: + // TODO: What is the difference between all these? + r->type = D_ADDR; + if(targ->dynimpname != nil && !targ->dynexport) + diag("unexpected reloc for dynamic symbol %s", targ->name); + return; + + case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1: + if(targ->dynimpname != nil && !targ->dynexport) { + addpltsym(targ); + r->sym = lookup(".plt", 0); + r->add = targ->plt; + r->type = D_PCREL; + return; + } + // fall through + case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1: + case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1: + case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1: + case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1: + case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1: + r->type = D_PCREL; + if(targ->dynimpname != nil && !targ->dynexport) + diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name); + return; + + case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1: + if(targ->dynimpname == nil || targ->dynexport) { + // have symbol + // turn MOVQ of GOT entry into LEAQ of symbol itself + if(r->off < 2 || s->p[r->off-2] != 0x8b) { + diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name); + return; + } + s->p[r->off-2] = 0x8d; + r->type = D_PCREL; + return; + } + // fall through + case 512 + MACHO_X86_64_RELOC_GOT*2 + 1: + if(targ->dynimpname == nil || targ->dynexport) + diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); + addgotsym(targ); + r->type = D_PCREL; + r->sym = lookup(".got", 0); + r->add += targ->got; + return; + } + + // Handle references to ELF symbols from our own object files. + if(targ->dynimpname == nil || targ->dynexport) + return; + + switch(r->type) { + case D_PCREL: + addpltsym(targ); + r->sym = lookup(".plt", 0); + r->add = targ->plt; + return; + + case D_ADDR: + if(s->type != SDATA) + break; + if(iself) { + adddynsym(targ); + rela = lookup(".rela", 0); + addaddrplus(rela, s, r->off); + if(r->siz == 8) + adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64)); + else + adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32)); + adduint64(rela, r->add); + r->type = 256; // ignore during relocsym + return; + } + if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) { + // Mach-O relocations are a royal pain to lay out. + // They use a compact stateful bytecode representation + // that is too much bother to deal with. + // Instead, interpret the C declaration + // void *_Cvar_stderr = &stderr; + // as making _Cvar_stderr the name of a GOT entry + // for stderr. This is separate from the usual GOT entry, + // just in case the C code assigns to the variable, + // and of course it only works for single pointers, + // but we only need to support cgo and that's all it needs. + adddynsym(targ); + got = lookup(".got", 0); + s->type = got->type | SSUB; + s->outer = got; + s->sub = got->sub; + got->sub = s; + s->value = got->size; + adduint64(got, 0); + adduint32(lookup(".linkedit.got", 0), targ->dynid); + r->type = 256; // ignore during relocsym + return; + } + break; + } + + cursym = s; + diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); +} + +int +archreloc(Reloc *r, Sym *s, vlong *val) +{ + USED(r); + USED(s); + USED(val); + return -1; +} + +static void +elfsetupplt(void) +{ + Sym *plt, *got; + + plt = lookup(".plt", 0); + got = lookup(".got.plt", 0); + if(plt->size == 0) { + // pushq got+8(IP) + adduint8(plt, 0xff); + adduint8(plt, 0x35); + addpcrelplus(plt, got, 8); + + // jmpq got+16(IP) + adduint8(plt, 0xff); + adduint8(plt, 0x25); + addpcrelplus(plt, got, 16); + + // nopl 0(AX) + adduint32(plt, 0x00401f0f); + + // assume got->size == 0 too + addaddrplus(got, lookup(".dynamic", 0), 0); + adduint64(got, 0); + adduint64(got, 0); + } +} + +static void +addpltsym(Sym *s) +{ + if(s->plt >= 0) + return; + + adddynsym(s); + + if(iself) { + Sym *plt, *got, *rela; + + plt = lookup(".plt", 0); + got = lookup(".got.plt", 0); + rela = lookup(".rela.plt", 0); + if(plt->size == 0) + elfsetupplt(); + + // jmpq *got+size(IP) + adduint8(plt, 0xff); + adduint8(plt, 0x25); + addpcrelplus(plt, got, got->size); + + // add to got: pointer to current pos in plt + addaddrplus(got, plt, plt->size); + + // pushq $x + adduint8(plt, 0x68); + adduint32(plt, (got->size-24-8)/8); + + // jmpq .plt + adduint8(plt, 0xe9); + adduint32(plt, -(plt->size+4)); + + // rela + addaddrplus(rela, got, got->size-8); + adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT)); + adduint64(rela, 0); + + s->plt = plt->size - 16; + } else if(HEADTYPE == Hdarwin) { + // To do lazy symbol lookup right, we're supposed + // to tell the dynamic loader which library each + // symbol comes from and format the link info + // section just so. I'm too lazy (ha!) to do that + // so for now we'll just use non-lazy pointers, + // which don't need to be told which library to use. + // + // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html + // has details about what we're avoiding. + + Sym *plt; + + addgotsym(s); + plt = lookup(".plt", 0); + + adduint32(lookup(".linkedit.plt", 0), s->dynid); + + // jmpq *got+size(IP) + s->plt = plt->size; + + adduint8(plt, 0xff); + adduint8(plt, 0x25); + addpcrelplus(plt, lookup(".got", 0), s->got); + } else { + diag("addpltsym: unsupported binary format"); + } +} + +static void +addgotsym(Sym *s) +{ + Sym *got, *rela; + + if(s->got >= 0) + return; + + adddynsym(s); + got = lookup(".got", 0); + s->got = got->size; + adduint64(got, 0); + + if(iself) { + rela = lookup(".rela", 0); + addaddrplus(rela, got, s->got); + adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT)); + adduint64(rela, 0); + } else if(HEADTYPE == Hdarwin) { + adduint32(lookup(".linkedit.got", 0), s->dynid); + } else { + diag("addgotsym: unsupported binary format"); + } +} + +void +adddynsym(Sym *s) +{ + Sym *d, *str; + int t; + char *name; + + if(s->dynid >= 0) + return; + + if(s->dynimpname == nil) + diag("adddynsym: no dynamic name for %s", s->name); + + if(iself) { + s->dynid = nelfsym++; + + d = lookup(".dynsym", 0); + + name = s->dynimpname; + if(name == nil) + name = s->name; + adduint32(d, addstring(lookup(".dynstr", 0), name)); + /* type */ + t = STB_GLOBAL << 4; + if(s->dynexport && s->type == STEXT) + t |= STT_FUNC; + else + t |= STT_OBJECT; + adduint8(d, t); + + /* reserved */ + adduint8(d, 0); + + /* section where symbol is defined */ + if(!s->dynexport && s->dynimpname != nil) + adduint16(d, SHN_UNDEF); + else { + switch(s->type) { + default: + case STEXT: + t = 11; + break; + case SRODATA: + t = 12; + break; + case SDATA: + t = 13; + break; + case SBSS: + t = 14; + break; + } + adduint16(d, t); + } + + /* value */ + if(s->type == SDYNIMPORT) + adduint64(d, 0); + else + addaddr(d, s); + + /* size of object */ + adduint64(d, 0); + + if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) { + elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, + addstring(lookup(".dynstr", 0), s->dynimplib)); + } + } else if(HEADTYPE == Hdarwin) { + // Mach-o symbol nlist64 + d = lookup(".dynsym", 0); + name = s->dynimpname; + if(name == nil) + name = s->name; + s->dynid = d->size/16; + // darwin still puts _ prefixes on all C symbols + str = lookup(".dynstr", 0); + adduint32(d, str->size); + adduint8(str, '_'); + addstring(str, name); + if(s->type == SDYNIMPORT) { + adduint8(d, 0x01); // type - N_EXT - external symbol + adduint8(d, 0); // section + } else { + adduint8(d, 0x0f); + switch(s->type) { + default: + case STEXT: + adduint8(d, 1); + break; + case SDATA: + adduint8(d, 2); + break; + case SBSS: + adduint8(d, 4); + break; + } + } + adduint16(d, 0); // desc + if(s->type == SDYNIMPORT) + adduint64(d, 0); // value + else + addaddr(d, s); + } else if(HEADTYPE != Hwindows) { + diag("adddynsym: unsupported binary format"); + } +} + +void +adddynlib(char *lib) +{ + Sym *s; + + if(!needlib(lib)) + return; + + if(iself) { + s = lookup(".dynstr", 0); + if(s->size == 0) + addstring(s, ""); + elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); + } else if(HEADTYPE == Hdarwin) { + machoadddynlib(lib); + } else { + diag("adddynlib: unsupported binary format"); + } +} + +void +doelf(void) +{ + Sym *s, *shstrtab, *dynstr; + + if(HEADTYPE != Hlinux && HEADTYPE != Hfreebsd && HEADTYPE != Hopenbsd) + return; + + /* predefine strings we need for section headers */ + shstrtab = lookup(".shstrtab", 0); + shstrtab->type = SELFROSECT; + shstrtab->reachable = 1; + + elfstr[ElfStrEmpty] = addstring(shstrtab, ""); + elfstr[ElfStrText] = addstring(shstrtab, ".text"); + elfstr[ElfStrData] = addstring(shstrtab, ".data"); + elfstr[ElfStrBss] = addstring(shstrtab, ".bss"); + addstring(shstrtab, ".elfdata"); + addstring(shstrtab, ".rodata"); + addstring(shstrtab, ".gosymtab"); + addstring(shstrtab, ".gopclntab"); + if(!debug['s']) { + elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab"); + elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab"); + dwarfaddshstrings(shstrtab); + } + elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab"); + + if(!debug['d']) { /* -d suppresses dynamic loader format */ + elfstr[ElfStrInterp] = addstring(shstrtab, ".interp"); + elfstr[ElfStrHash] = addstring(shstrtab, ".hash"); + elfstr[ElfStrGot] = addstring(shstrtab, ".got"); + elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt"); + elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic"); + elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym"); + elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr"); + elfstr[ElfStrRela] = addstring(shstrtab, ".rela"); + elfstr[ElfStrRelaPlt] = addstring(shstrtab, ".rela.plt"); + elfstr[ElfStrPlt] = addstring(shstrtab, ".plt"); + elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version"); + elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r"); + + /* dynamic symbol table - first entry all zeros */ + s = lookup(".dynsym", 0); + s->type = SELFROSECT; + s->reachable = 1; + s->size += ELF64SYMSIZE; + + /* dynamic string table */ + s = lookup(".dynstr", 0); + s->type = SELFROSECT; + s->reachable = 1; + if(s->size == 0) + addstring(s, ""); + dynstr = s; + + /* relocation table */ + s = lookup(".rela", 0); + s->reachable = 1; + s->type = SELFROSECT; + + /* global offset table */ + s = lookup(".got", 0); + s->reachable = 1; + s->type = SELFSECT; // writable + + /* hash */ + s = lookup(".hash", 0); + s->reachable = 1; + s->type = SELFROSECT; + + s = lookup(".got.plt", 0); + s->reachable = 1; + s->type = SELFSECT; // writable + + s = lookup(".plt", 0); + s->reachable = 1; + s->type = SELFROSECT; + + elfsetupplt(); + + s = lookup(".rela.plt", 0); + s->reachable = 1; + s->type = SELFROSECT; + + s = lookup(".gnu.version", 0); + s->reachable = 1; + s->type = SELFROSECT; + + s = lookup(".gnu.version_r", 0); + s->reachable = 1; + s->type = SELFROSECT; + + /* define dynamic elf table */ + s = lookup(".dynamic", 0); + s->reachable = 1; + s->type = SELFROSECT; + + /* + * .dynamic table + */ + elfwritedynentsym(s, DT_HASH, lookup(".hash", 0)); + elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0)); + elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE); + elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0)); + elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0)); + elfwritedynentsym(s, DT_RELA, lookup(".rela", 0)); + elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0)); + elfwritedynent(s, DT_RELAENT, ELF64RELASIZE); + if(rpath) + elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath)); + + elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0)); + elfwritedynent(s, DT_PLTREL, DT_RELA); + elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0)); + elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0)); + + // Do not write DT_NULL. elfdynhash will finish it. + } +} + +void +shsym(ElfShdr *sh, Sym *s) +{ + vlong addr; + addr = symaddr(s); + if(sh->flags&SHF_ALLOC) + sh->addr = addr; + sh->off = datoff(addr); + sh->size = s->size; +} + +void +phsh(ElfPhdr *ph, ElfShdr *sh) +{ + ph->vaddr = sh->addr; + ph->paddr = ph->vaddr; + ph->off = sh->off; + ph->filesz = sh->size; + ph->memsz = sh->size; + ph->align = sh->addralign; +} + +void +asmb(void) +{ + int32 magic; + int a, dynsym; + vlong vl, startva, symo, machlink; + ElfEhdr *eh; + ElfPhdr *ph, *pph; + ElfShdr *sh; + Section *sect; + int o; + + if(debug['v']) + Bprint(&bso, "%5.2f asmb\n", cputime()); + Bflush(&bso); + + elftextsh = 0; + + if(debug['v']) + Bprint(&bso, "%5.2f codeblk\n", cputime()); + Bflush(&bso); + + sect = segtext.sect; + cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); + codeblk(sect->vaddr, sect->len); + + /* output read-only data in text segment (rodata, gosymtab and pclntab) */ + for(sect = sect->next; sect != nil; sect = sect->next) { + cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); + datblk(sect->vaddr, sect->len); + } + + if(debug['v']) + Bprint(&bso, "%5.2f datblk\n", cputime()); + Bflush(&bso); + + cseek(segdata.fileoff); + datblk(segdata.vaddr, segdata.filelen); + + machlink = 0; + if(HEADTYPE == Hdarwin) + machlink = domacholink(); + + switch(HEADTYPE) { + default: + diag("unknown header type %d", HEADTYPE); + case Hplan9x32: + case Helf: + break; + case Hdarwin: + debug['8'] = 1; /* 64-bit addresses */ + break; + case Hlinux: + case Hfreebsd: + case Hopenbsd: + debug['8'] = 1; /* 64-bit addresses */ + /* index of elf text section; needed by asmelfsym, double-checked below */ + /* !debug['d'] causes extra sections before the .text section */ + elftextsh = 2; + if(!debug['d']) { + elftextsh += 10; + if(elfverneed) + elftextsh += 2; + } + break; + case Hwindows: + break; + } + + symsize = 0; + spsize = 0; + lcsize = 0; + symo = 0; + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sym\n", cputime()); + Bflush(&bso); + switch(HEADTYPE) { + default: + case Hplan9x32: + case Helf: + debug['s'] = 1; + symo = HEADR+segtext.len+segdata.filelen; + break; + case Hdarwin: + symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink; + break; + case Hlinux: + case Hfreebsd: + case Hopenbsd: + symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen; + symo = rnd(symo, INITRND); + break; + case Hwindows: + symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen; + symo = rnd(symo, PEFILEALIGN); + break; + } + cseek(symo); + switch(HEADTYPE) { + default: + if(iself) { + cseek(symo); + asmelfsym(); + cflush(); + cwrite(elfstrdat, elfstrsize); + + if(debug['v']) + Bprint(&bso, "%5.2f dwarf\n", cputime()); + + dwarfemitdebugsections(); + } + break; + case Hdarwin: + case Hwindows: + if(debug['v']) + Bprint(&bso, "%5.2f dwarf\n", cputime()); + + dwarfemitdebugsections(); + break; + } + } + + if(debug['v']) + Bprint(&bso, "%5.2f headr\n", cputime()); + Bflush(&bso); + cseek(0L); + switch(HEADTYPE) { + default: + case Hplan9x32: /* plan9 */ + magic = 4*26*26+7; + magic |= 0x00008000; /* fat header */ + lputb(magic); /* magic */ + lputb(segtext.filelen); /* sizes */ + lputb(segdata.filelen); + lputb(segdata.len - segdata.filelen); + lputb(symsize); /* nsyms */ + vl = entryvalue(); + lputb(PADDR(vl)); /* va of entry */ + lputb(spsize); /* sp offsets */ + lputb(lcsize); /* line offsets */ + vputb(vl); /* va of entry */ + break; + case Hplan9x64: /* plan9 */ + magic = 4*26*26+7; + lputb(magic); /* magic */ + lputb(segtext.filelen); /* sizes */ + lputb(segdata.filelen); + lputb(segdata.len - segdata.filelen); + lputb(symsize); /* nsyms */ + lputb(entryvalue()); /* va of entry */ + lputb(spsize); /* sp offsets */ + lputb(lcsize); /* line offsets */ + break; + case Hdarwin: + asmbmacho(); + break; + case Hlinux: + case Hfreebsd: + case Hopenbsd: + /* elf amd-64 */ + + eh = getElfEhdr(); + startva = INITTEXT - HEADR; + + /* This null SHdr must appear before all others */ + newElfShdr(elfstr[ElfStrEmpty]); + + /* program header info */ + pph = newElfPhdr(); + pph->type = PT_PHDR; + pph->flags = PF_R + PF_X; + pph->off = eh->ehsize; + pph->vaddr = INITTEXT - HEADR + pph->off; + pph->paddr = INITTEXT - HEADR + pph->off; + pph->align = INITRND; + + /* + * PHDR must be in a loaded segment. Adjust the text + * segment boundaries downwards to include it. + */ + o = segtext.vaddr - pph->vaddr; + segtext.vaddr -= o; + segtext.len += o; + o = segtext.fileoff - pph->off; + segtext.fileoff -= o; + segtext.filelen += o; + + if(!debug['d']) { + /* interpreter */ + sh = newElfShdr(elfstr[ElfStrInterp]); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC; + sh->addralign = 1; + if(interpreter == nil) { + switch(HEADTYPE) { + case Hlinux: + interpreter = linuxdynld; + break; + case Hfreebsd: + interpreter = freebsddynld; + break; + case Hopenbsd: + interpreter = openbsddynld; + break; + } + } + elfinterp(sh, startva, interpreter); + + ph = newElfPhdr(); + ph->type = PT_INTERP; + ph->flags = PF_R; + phsh(ph, sh); + } + + elfphload(&segtext); + elfphload(&segdata); + + /* Dynamic linking sections */ + if (!debug['d']) { /* -d suppresses dynamic loader format */ + /* S headers for dynamic linking */ + sh = newElfShdr(elfstr[ElfStrGot]); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC+SHF_WRITE; + sh->entsize = 8; + sh->addralign = 8; + shsym(sh, lookup(".got", 0)); + + sh = newElfShdr(elfstr[ElfStrGotPlt]); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC+SHF_WRITE; + sh->entsize = 8; + sh->addralign = 8; + shsym(sh, lookup(".got.plt", 0)); + + dynsym = eh->shnum; + sh = newElfShdr(elfstr[ElfStrDynsym]); + sh->type = SHT_DYNSYM; + sh->flags = SHF_ALLOC; + sh->entsize = ELF64SYMSIZE; + sh->addralign = 8; + sh->link = dynsym+1; // dynstr + // sh->info = index of first non-local symbol (number of local symbols) + shsym(sh, lookup(".dynsym", 0)); + + sh = newElfShdr(elfstr[ElfStrDynstr]); + sh->type = SHT_STRTAB; + sh->flags = SHF_ALLOC; + sh->addralign = 1; + shsym(sh, lookup(".dynstr", 0)); + + if(elfverneed) { + sh = newElfShdr(elfstr[ElfStrGnuVersion]); + sh->type = SHT_GNU_VERSYM; + sh->flags = SHF_ALLOC; + sh->addralign = 2; + sh->link = dynsym; + sh->entsize = 2; + shsym(sh, lookup(".gnu.version", 0)); + + sh = newElfShdr(elfstr[ElfStrGnuVersionR]); + sh->type = SHT_GNU_VERNEED; + sh->flags = SHF_ALLOC; + sh->addralign = 8; + sh->info = elfverneed; + sh->link = dynsym+1; // dynstr + shsym(sh, lookup(".gnu.version_r", 0)); + } + + sh = newElfShdr(elfstr[ElfStrRelaPlt]); + sh->type = SHT_RELA; + sh->flags = SHF_ALLOC; + sh->entsize = ELF64RELASIZE; + sh->addralign = 8; + sh->link = dynsym; + sh->info = eh->shnum; // .plt + shsym(sh, lookup(".rela.plt", 0)); + + sh = newElfShdr(elfstr[ElfStrPlt]); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC+SHF_EXECINSTR; + sh->entsize = 16; + sh->addralign = 4; + shsym(sh, lookup(".plt", 0)); + + sh = newElfShdr(elfstr[ElfStrHash]); + sh->type = SHT_HASH; + sh->flags = SHF_ALLOC; + sh->entsize = 4; + sh->addralign = 8; + sh->link = dynsym; + shsym(sh, lookup(".hash", 0)); + + sh = newElfShdr(elfstr[ElfStrRela]); + sh->type = SHT_RELA; + sh->flags = SHF_ALLOC; + sh->entsize = ELF64RELASIZE; + sh->addralign = 8; + sh->link = dynsym; + shsym(sh, lookup(".rela", 0)); + + /* sh and PT_DYNAMIC for .dynamic section */ + sh = newElfShdr(elfstr[ElfStrDynamic]); + sh->type = SHT_DYNAMIC; + sh->flags = SHF_ALLOC+SHF_WRITE; + sh->entsize = 16; + sh->addralign = 8; + sh->link = dynsym+1; // dynstr + shsym(sh, lookup(".dynamic", 0)); + ph = newElfPhdr(); + ph->type = PT_DYNAMIC; + ph->flags = PF_R + PF_W; + phsh(ph, sh); + + /* + * Thread-local storage segment (really just size). + */ + if(tlsoffset != 0) { + ph = newElfPhdr(); + ph->type = PT_TLS; + ph->flags = PF_R; + ph->memsz = -tlsoffset; + ph->align = 8; + } + } + + ph = newElfPhdr(); + ph->type = PT_GNU_STACK; + ph->flags = PF_W+PF_R; + ph->align = 8; + + sh = newElfShstrtab(elfstr[ElfStrShstrtab]); + sh->type = SHT_STRTAB; + sh->addralign = 1; + shsym(sh, lookup(".shstrtab", 0)); + + if(elftextsh != eh->shnum) + diag("elftextsh = %d, want %d", elftextsh, eh->shnum); + for(sect=segtext.sect; sect!=nil; sect=sect->next) + elfshbits(sect); + for(sect=segdata.sect; sect!=nil; sect=sect->next) + elfshbits(sect); + + if (!debug['s']) { + sh = newElfShdr(elfstr[ElfStrSymtab]); + sh->type = SHT_SYMTAB; + sh->off = symo; + sh->size = symsize; + sh->addralign = 8; + sh->entsize = 24; + sh->link = eh->shnum; // link to strtab + + sh = newElfShdr(elfstr[ElfStrStrtab]); + sh->type = SHT_STRTAB; + sh->off = symo+symsize; + sh->size = elfstrsize; + sh->addralign = 1; + + dwarfaddelfheaders(); + } + + /* Main header */ + eh->ident[EI_MAG0] = '\177'; + eh->ident[EI_MAG1] = 'E'; + eh->ident[EI_MAG2] = 'L'; + eh->ident[EI_MAG3] = 'F'; + if(HEADTYPE == Hfreebsd) + eh->ident[EI_OSABI] = ELFOSABI_FREEBSD; + else if(HEADTYPE == Hopenbsd) + eh->ident[EI_OSABI] = ELFOSABI_OPENBSD; + eh->ident[EI_CLASS] = ELFCLASS64; + eh->ident[EI_DATA] = ELFDATA2LSB; + eh->ident[EI_VERSION] = EV_CURRENT; + + eh->type = ET_EXEC; + eh->machine = EM_X86_64; + eh->version = EV_CURRENT; + eh->entry = entryvalue(); + + pph->filesz = eh->phnum * eh->phentsize; + pph->memsz = pph->filesz; + + cseek(0); + a = 0; + a += elfwritehdr(); + a += elfwritephdrs(); + a += elfwriteshdrs(); + cflush(); + if(a+elfwriteinterp() > ELFRESERVE) + diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); + break; + case Hwindows: + asmbpe(); + break; + } + cflush(); +} + +vlong +rnd(vlong v, vlong r) +{ + vlong c; + + if(r <= 0) + return v; + v += r - 1; + c = v % r; + if(c < 0) + c += r; + v -= c; + return v; +} + +void +genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) +{ + Auto *a; + Sym *s; + + s = lookup("etext", 0); + if(s->type == STEXT) + put(s, s->name, 'T', s->value, s->size, s->version, 0); + + for(s=allsym; s!=S; s=s->allsym) { + if(s->hide) + continue; + switch(s->type&~SSUB) { + case SCONST: + case SRODATA: + case SDATA: + case SELFROSECT: + case SMACHOGOT: + case STYPE: + case SSTRING: + case SGOSTRING: + case SWINDOWS: + if(!s->reachable) + continue; + put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype); + continue; + + case SBSS: + if(!s->reachable) + continue; + put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype); + continue; + + case SFILE: + put(nil, s->name, 'f', s->value, 0, s->version, 0); + continue; + } + } + + for(s = textp; s != nil; s = s->next) { + if(s->text == nil) + continue; + + /* filenames first */ + for(a=s->autom; a; a=a->link) + if(a->type == D_FILE) + put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0); + else + if(a->type == D_FILE1) + put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0); + + put(s, s->name, 'T', s->value, s->size, s->version, s->gotype); + + /* frame, auto and param after */ + put(nil, ".frame", 'm', s->text->to.offset+8, 0, 0, 0); + + for(a=s->autom; a; a=a->link) + if(a->type == D_AUTO) + put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype); + else + if(a->type == D_PARAM) + put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype); + } + if(debug['v'] || debug['n']) + Bprint(&bso, "symsize = %ud\n", symsize); + Bflush(&bso); +} diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go new file mode 100644 index 000000000..b8a6013d6 --- /dev/null +++ b/src/cmd/6l/doc.go @@ -0,0 +1,53 @@ +// 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. + +/* + +6l is a modified version of the Plan 9 linker. The original is documented at + + http://plan9.bell-labs.com/magic/man2html/1/2l + +Its target architecture is the x86-64, referred to by these tools as amd64. +It reads files in .6 format generated by 6g, 6c, and 6a and emits +a binary called 6.out by default. + +Major changes include: + - support for ELF and Mach-O binary files + - support for segmented stacks (this feature is implemented here, not in the compilers). + + +Original options are listed in the link above. + +Options new in this version: + +-d + Elide the dynamic linking header. With this option, the binary + is statically linked and does not refer to dynld. Without this option + (the default), the binary's contents are identical but it is loaded with dynld. +-e + Emit an extra ELF-compatible symbol table useful with tools such as + nm, gdb, and oprofile. This option makes the binary file considerably larger. +-Hdarwin + Write Apple Mach-O binaries (default when $GOOS is darwin) +-Hlinux + Write Linux ELF binaries (default when $GOOS is linux) +-Hfreebsd + Write FreeBSD ELF binaries (default when $GOOS is freebsd) +-Hopenbsd + Write OpenBSD ELF binaries (default when $GOOS is openbsd) +-Hwindows + Write Windows PE32+ binaries (default when $GOOS is windows) +-I interpreter + Set the ELF dynamic linker to use. +-L dir1 -L dir2 + Search for libraries (package files) in dir1, dir2, etc. + The default is the single location $GOROOT/pkg/$GOOS_amd64. +-r dir1:dir2:... + Set the dynamic linker search path when using ELF. +-V + Print the linker version. + + +*/ +package documentation diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h new file mode 100644 index 000000000..b291d5f3d --- /dev/null +++ b/src/cmd/6l/l.h @@ -0,0 +1,421 @@ +// Inferno utils/6l/l.h +// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include "6.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +enum +{ + thechar = '6', + PtrSize = 8 +}; + +#define P ((Prog*)0) +#define S ((Sym*)0) +#define TNAME (cursym?cursym->name:noname) + +typedef struct Adr Adr; +typedef struct Prog Prog; +typedef struct Sym Sym; +typedef struct Auto Auto; +typedef struct Optab Optab; +typedef struct Movtab Movtab; +typedef struct Reloc Reloc; + +struct Adr +{ + union + { + vlong u0offset; + char u0scon[8]; + Prog *u0cond; /* not used, but should be D_BRANCH */ + Ieee u0ieee; + char *u0sbig; + } u0; + Sym* sym; + short type; + char index; + char scale; +}; + +#define offset u0.u0offset +#define scon u0.u0scon +#define cond u0.u0cond +#define ieee u0.u0ieee +#define sbig u0.u0sbig + +struct Reloc +{ + int32 off; + uchar siz; + int32 type; + int64 add; + Sym* sym; +}; + +struct Prog +{ + Adr from; + Adr to; + Prog* forwd; + Prog* comefrom; + Prog* link; + Prog* pcond; /* work on this */ + vlong pc; + int32 spadj; + int32 line; + short as; + char ft; /* oclass cache */ + char tt; + uchar mark; /* work on these */ + uchar back; + + char width; /* fake for DATA */ + char mode; /* 16, 32, or 64 */ +}; +#define datasize from.scale +#define textflag from.scale +#define iscall(p) ((p)->as == ACALL) + +struct Auto +{ + Sym* asym; + Auto* link; + int32 aoffset; + short type; + Sym* gotype; +}; +struct Sym +{ + char* name; + short type; + short version; + uchar dupok; + uchar reachable; + uchar dynexport; + uchar special; + uchar stkcheck; + uchar hide; + int32 dynid; + int32 sig; + int32 plt; + int32 got; + Sym* hash; // in hash table + Sym* allsym; // in all symbol list + Sym* next; // in text or data list + Sym* sub; // in SSUB list + Sym* outer; // container of sub + vlong value; + vlong size; + Sym* gotype; + char* file; + char* dynimpname; + char* dynimplib; + char* dynimpvers; + + // STEXT + Auto* autom; + Prog* text; + + // SDATA, SBSS + uchar* p; + int32 np; + int32 maxp; + Reloc* r; + int32 nr; + int32 maxr; +}; +struct Optab +{ + short as; + uchar* ytab; + uchar prefix; + uchar op[20]; +}; +struct Movtab +{ + short as; + uchar ft; + uchar tt; + uchar code; + uchar op[4]; +}; + +enum +{ + MINSIZ = 8, + STRINGSZ = 200, + MINLC = 1, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ + + Yxxx = 0, + Ynone, + Yi0, + Yi1, + Yi8, + Ys32, + Yi32, + Yi64, + Yiauto, + Yal, + Ycl, + Yax, + Ycx, + Yrb, + Yrl, + Yrf, + Yf0, + Yrx, + Ymb, + Yml, + Ym, + Ybr, + Ycol, + + Ycs, Yss, Yds, Yes, Yfs, Ygs, + Ygdtr, Yidtr, Yldtr, Ymsw, Ytask, + Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8, + Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7, + Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64, + Ymr, Ymm, + Yxr, Yxm, + Ymax, + + Zxxx = 0, + + Zlit, + Zlitm_r, + Z_rp, + Zbr, + Zcall, + Zib_, + Zib_rp, + Zibo_m, + Zibo_m_xm, + Zil_, + Zil_rp, + Ziq_rp, + Zilo_m, + Ziqo_m, + Zjmp, + Zloop, + Zo_iw, + Zm_o, + Zm_r, + 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 escape */ + Pb = 0xfe, /* byte operands */ + Pf2 = 0xf2, /* xmm escape 1 */ + Pf3 = 0xf3, /* xmm escape 2 */ + Pw = 0x48, /* Rex.w */ + Py = 0x80, /* defaults to 64-bit mode */ + + Rxf = 1<<9, /* internal flag for Rxr on from */ + Rxt = 1<<8, /* internal flag for Rxr on to */ + Rxw = 1<<3, /* =1, 64-bit operand size */ + Rxr = 1<<2, /* extend modrm reg */ + Rxx = 1<<1, /* extend sib index */ + Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */ + + Maxand = 10, /* in -a output width of the byte codes */ +}; + +#pragma varargck type "A" uint +#pragma varargck type "D" Adr* +#pragma varargck type "I" uchar* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int +#pragma varargck type "S" char* +#pragma varargck type "i" char* + +EXTERN int32 HEADR; +EXTERN int32 HEADTYPE; +EXTERN int32 INITRND; +EXTERN vlong INITTEXT; +EXTERN vlong INITDAT; +EXTERN char* INITENTRY; /* entry point */ +EXTERN char* pcstr; +EXTERN Auto* curauto; +EXTERN Auto* curhist; +EXTERN Prog* curp; +EXTERN Sym* cursym; +EXTERN Sym* datap; +EXTERN vlong elfdatsize; +EXTERN char debug[128]; +EXTERN char literal[32]; +EXTERN Sym* textp; +EXTERN Sym* etextp; +EXTERN char ycover[Ymax*Ymax]; +EXTERN uchar* andptr; +EXTERN uchar* rexptr; +EXTERN uchar and[30]; +EXTERN int reg[D_NONE]; +EXTERN int regrex[D_NONE+1]; +EXTERN int32 lcsize; +EXTERN int nerrors; +EXTERN char* noname; +EXTERN char* outfile; +EXTERN vlong pc; +EXTERN char* interpreter; +EXTERN char* rpath; +EXTERN int32 spsize; +EXTERN Sym* symlist; +EXTERN int32 symsize; +EXTERN int tlsoffset; +EXTERN int version; +EXTERN Prog zprg; +EXTERN int dtype; +EXTERN char* paramspace; +EXTERN Sym* adrgotype; // type symbol on last Adr read +EXTERN Sym* fromgotype; // type symbol on last p->from read + +EXTERN vlong textstksiz; +EXTERN vlong textarg; + +extern Optab optab[]; +extern Optab* opindex[]; +extern char* anames[]; + +int Aconv(Fmt*); +int Dconv(Fmt*); +int Iconv(Fmt*); +int Pconv(Fmt*); +int Rconv(Fmt*); +int Sconv(Fmt*); +void addhist(int32, int); +void addstackmark(void); +Prog* appendp(Prog*); +void asmb(void); +void asmdyn(void); +void asmins(Prog*); +void asmsym(void); +void asmelfsym(void); +vlong atolwhex(char*); +Prog* brchain(Prog*); +Prog* brloop(Prog*); +void buildop(void); +Prog* copyp(Prog*); +double cputime(void); +void datblk(int32, int32); +void deadcode(void); +void diag(char*, ...); +void dodata(void); +void doelf(void); +void domacho(void); +void doprof1(void); +void doprof2(void); +void dostkoff(void); +vlong entryvalue(void); +void follow(void); +void gethunk(void); +void gotypestrings(void); +void listinit(void); +Sym* lookup(char*, int); +void lputb(int32); +void lputl(int32); +void instinit(void); +void main(int, char*[]); +void* mysbrk(uint32); +Prog* newtext(Prog*, Sym*); +void nopout(Prog*); +int opsize(Prog*); +void patch(void); +Prog* prg(void); +void parsetextconst(vlong); +int relinv(int); +vlong rnd(vlong, vlong); +void span(void); +void undef(void); +vlong symaddr(Sym*); +void vputb(uint64); +void vputl(uint64); +void wputb(uint16); +void wputl(uint16); +void xdefine(char*, int, vlong); + +void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32); +void machsymseg(uint32, uint32); +void machsect(char*, char*, vlong, vlong, uint32, uint32, uint32, uint32, uint32); +void machstack(vlong); +void machdylink(void); +uint32 machheadr(void); + +/* Native is little-endian */ +#define LPUT(a) lputl(a) +#define WPUT(a) wputl(a) +#define VPUT(a) vputl(a) + +#pragma varargck type "D" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int +#pragma varargck type "Z" char* +#pragma varargck type "A" int +#pragma varargck argpos diag 1 + +/* Used by ../ld/dwarf.c */ +enum +{ + DWARFREGSP = 7 +}; diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c new file mode 100644 index 000000000..f39efa2e8 --- /dev/null +++ b/src/cmd/6l/list.c @@ -0,0 +1,458 @@ +// 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" + +static Prog* bigP; + +void +listinit(void) +{ + + fmtinstall('R', Rconv); + fmtinstall('A', Aconv); + fmtinstall('D', Dconv); + fmtinstall('S', Sconv); + fmtinstall('P', Pconv); + fmtinstall('I', Iconv); +} + +int +Pconv(Fmt *fp) +{ + Prog *p; + + p = va_arg(fp->args, Prog*); + bigP = p; + switch(p->as) { + case ATEXT: + if(p->from.scale) { + fmtprint(fp, "(%d) %A %D,%d,%D", + p->line, p->as, &p->from, p->from.scale, &p->to); + break; + } + default: + fmtprint(fp, "(%d) %A %D,%D", + p->line, p->as, &p->from, &p->to); + break; + case ADATA: + case AINIT_: + case ADYNT_: + fmtprint(fp, "(%d) %A %D/%d,%D", + p->line, p->as, &p->from, p->from.scale, &p->to); + break; + } + bigP = P; + return 0; +} + +int +Aconv(Fmt *fp) +{ + int i; + + i = va_arg(fp->args, int); + return fmtstrcpy(fp, anames[i]); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ], s[STRINGSZ]; + Adr *a; + int i; + + a = va_arg(fp->args, Adr*); + i = a->type; + + if(fp->flags & FmtLong) { + if(i != D_CONST) { + // ATEXT dst is not constant + snprint(str, sizeof(str), "!!%D", a); + goto brk; + } + parsetextconst(a->offset); + if(textarg == 0) { + snprint(str, sizeof(str), "$%lld", textstksiz); + goto brk; + } + snprint(str, sizeof(str), "$%lld-%lld", textstksiz, textarg); + goto brk; + } + + if(i >= D_INDIR) { + if(a->offset) + snprint(str, sizeof(str), "%lld(%R)", a->offset, i-D_INDIR); + else + snprint(str, sizeof(str), "(%R)", i-D_INDIR); + goto brk; + } + switch(i) { + + default: + if(a->offset) + snprint(str, sizeof(str), "$%lld,%R", a->offset, i); + else + snprint(str, sizeof(str), "%R", i); + break; + + case D_NONE: + str[0] = 0; + break; + + case D_BRANCH: + if(bigP != P && bigP->pcond != P) + if(a->sym != S) + snprint(str, sizeof(str), "%llux+%s", bigP->pcond->pc, + a->sym->name); + else + snprint(str, sizeof(str), "%llux", bigP->pcond->pc); + else + snprint(str, sizeof(str), "%lld(PC)", a->offset); + break; + + case D_EXTERN: + if(a->sym) { + snprint(str, sizeof(str), "%s+%lld(SB)", a->sym->name, a->offset); + break; + } + snprint(str, sizeof(str), "!!noname!!+%lld(SB)", a->offset); + break; + + case D_STATIC: + if(a->sym) { + snprint(str, sizeof(str), "%s<%d>+%lld(SB)", a->sym->name, + a->sym->version, a->offset); + break; + } + snprint(str, sizeof(str), "!!noname!!<999>+%lld(SB)", a->offset); + break; + + case D_AUTO: + if(a->sym) { + snprint(str, sizeof(str), "%s+%lld(SP)", a->sym->name, a->offset); + break; + } + snprint(str, sizeof(str), "!!noname!!+%lld(SP)", a->offset); + break; + + case D_PARAM: + if(a->sym) { + snprint(str, sizeof(str), "%s+%lld(%s)", a->sym->name, a->offset, paramspace); + break; + } + snprint(str, sizeof(str), "!!noname!!+%lld(%s)", a->offset, paramspace); + break; + + case D_CONST: + snprint(str, sizeof(str), "$%lld", a->offset); + break; + + case D_FCONST: + snprint(str, sizeof(str), "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l); + break; + + case D_SCONST: + snprint(str, sizeof(str), "$\"%S\"", a->scon); + break; + + case D_ADDR: + a->type = a->index; + a->index = D_NONE; + snprint(str, sizeof(str), "$%D", a); + a->index = a->type; + a->type = D_ADDR; + goto conv; + } +brk: + if(a->index != D_NONE) { + snprint(s, sizeof(s), "(%R*%d)", a->index, a->scale); + strcat(str, s); + } +conv: + fmtstrcpy(fp, str); +// if(a->gotype) +// fmtprint(fp, "«%s»", a->gotype->name); + return 0; + +} + +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", + + "NONE", /* [D_NONE] */ +}; + +int +Rconv(Fmt *fp) +{ + char str[STRINGSZ]; + int r; + + r = va_arg(fp->args, int); + if(r >= D_AL && r <= D_NONE) + snprint(str, sizeof(str), "%s", regstr[r-D_AL]); + else + snprint(str, sizeof(str), "gok(%d)", r); + + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<sizeof(double); i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + default: + if(c < 040 || c >= 0177) + break; /* not portable */ + p[-1] = c; + continue; + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +int +Iconv(Fmt *fp) +{ + int i, n; + uchar *p; + char *s; + Fmt fmt; + + n = fp->prec; + fp->prec = 0; + if(!(fp->flags&FmtPrec) || n < 0) + return fmtstrcpy(fp, "%I"); + fp->flags &= ~FmtPrec; + p = va_arg(fp->args, uchar*); + + // format into temporary buffer and + // call fmtstrcpy to handle padding. + fmtstrinit(&fmt); + for(i=0; i<n; i++) + fmtprint(&fmt, "%.2ux", *p++); + s = fmtstrflush(&fmt); + fmtstrcpy(fp, s); + free(s); + return 0; +} + +void +diag(char *fmt, ...) +{ + char buf[STRINGSZ], *tn, *sep; + va_list arg; + + tn = ""; + sep = ""; + if(cursym != S) { + tn = cursym->name; + sep = ": "; + } + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + print("%s%s%s\n", tn, sep, buf); + + nerrors++; + if(nerrors > 20) { + print("too many errors\n"); + errorexit(); + } +} + +void +parsetextconst(vlong arg) +{ + textstksiz = arg & 0xffffffffLL; + if(textstksiz & 0x80000000LL) + textstksiz = -(-textstksiz & 0xffffffffLL); + + textarg = (arg >> 32) & 0xffffffffLL; + if(textarg & 0x80000000LL) + textarg = 0; + textarg = (textarg+7) & ~7LL; +} diff --git a/src/cmd/6l/mkenam b/src/cmd/6l/mkenam new file mode 100644 index 000000000..3001dbe93 --- /dev/null +++ b/src/cmd/6l/mkenam @@ -0,0 +1,45 @@ +# Inferno utils/6c/mkenam +# http://code.google.com/p/inferno-os/source/browse/utils/6c/mkenam +# +# 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. + +awk ' +BEGIN { + print "char* anames[] =" + print "{" +} + +/^ A/ { + name=$1 + sub(/,/, "", name) + sub(/^A/, "", name) + print "\t\"" name "\"," +} + +END { print "};" } +' ../6l/6.out.h >enam.c diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c new file mode 100644 index 000000000..a7ef58db4 --- /dev/null +++ b/src/cmd/6l/obj.c @@ -0,0 +1,765 @@ +// Inferno utils/6l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Reading object files. + +#define EXTERN +#include "l.h" +#include "../ld/lib.h" +#include "../ld/elf.h" +#include "../ld/macho.h" +#include "../ld/dwarf.h" +#include "../ld/pe.h" +#include <ar.h> + +char *noname = "<none>"; +char* thestring = "amd64"; +char* paramspace = "FP"; + +Header headers[] = { + "plan9x32", Hplan9x32, + "plan9", Hplan9x64, + "elf", Helf, + "darwin", Hdarwin, + "linux", Hlinux, + "freebsd", Hfreebsd, + "openbsd", Hopenbsd, + "windows", Hwindows, + "windowsgui", Hwindows, + 0, 0 +}; + +/* + * -Hplan9x32 -T4136 -R4096 is plan9 64-bit format + * -Hplan9 -T4128 -R4096 is plan9 32-bit format + * -Helf -T0x80110000 -R4096 is ELF32 + * -Hdarwin -Tx -Rx is apple MH-exec + * -Hlinux -Tx -Rx is linux elf-exec + * -Hfreebsd -Tx -Rx is FreeBSD elf-exec + * -Hopenbsd -Tx -Rx is OpenBSD elf-exec + * -Hwindows -Tx -Rx is MS Windows PE32+ + * + * options used: 189BLQSWabcjlnpsvz + */ + +void +usage(void) +{ + fprint(2, "usage: 6l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.6\n"); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + int c; + + Binit(&bso, 1, OWRITE); + listinit(); + memset(debug, 0, sizeof(debug)); + nerrors = 0; + outfile = nil; + HEADTYPE = -1; + INITTEXT = -1; + INITDAT = -1; + INITRND = -1; + INITENTRY = 0; + + ARGBEGIN { + default: + c = ARGC(); + if(c == 'l') + usage(); + if(c >= 0 && c < sizeof(debug)) + debug[c]++; + break; + case 'o': /* output to (next arg) */ + outfile = EARGF(usage()); + break; + case 'E': + INITENTRY = EARGF(usage()); + break; + case 'H': + HEADTYPE = headtype(EARGF(usage())); + break; + case 'I': + interpreter = EARGF(usage()); + break; + case 'L': + Lflag(EARGF(usage())); + break; + case 'T': + INITTEXT = atolwhex(EARGF(usage())); + break; + case 'D': + INITDAT = atolwhex(EARGF(usage())); + break; + case 'R': + INITRND = atolwhex(EARGF(usage())); + break; + case 'r': + rpath = EARGF(usage()); + break; + case 'V': + print("%cl version %s\n", thechar, getgoversion()); + errorexit(); + } ARGEND + + if(argc != 1) + usage(); + + mywhatsys(); // get goos + + if(HEADTYPE == -1) + HEADTYPE = headtype(goos); + + if(outfile == nil) { + if(HEADTYPE == Hwindows) + outfile = "6.out.exe"; + else + outfile = "6.out"; + } + + libinit(); + + switch(HEADTYPE) { + default: + diag("unknown -H option"); + errorexit(); + case Hplan9x32: /* plan 9 */ + HEADR = 32L+8L; + if(INITTEXT == -1) + INITTEXT = 4096+HEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case Hplan9x64: /* plan 9 */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 4096+32; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case Helf: /* elf32 executable */ + HEADR = rnd(52L+3*32L, 16); + if(INITTEXT == -1) + INITTEXT = 0x80110000L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case Hdarwin: /* apple MACH */ + /* + * OS X system constant - offset from 0(GS) to our TLS. + * Explained in ../../libcgo/darwin_amd64.c. + */ + tlsoffset = 0x8a0; + machoinit(); + HEADR = INITIAL_MACHO_HEADR; + if(INITRND == -1) + INITRND = 4096; + if(INITTEXT == -1) + INITTEXT = 4096+HEADR; + if(INITDAT == -1) + INITDAT = 0; + break; + case Hlinux: /* elf64 executable */ + case Hfreebsd: /* freebsd */ + case Hopenbsd: /* openbsd */ + /* + * ELF uses TLS offset negative from FS. + * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS). + * Also known to ../../pkg/runtime/linux/amd64/sys.s + * and ../../libcgo/linux_amd64.s. + */ + tlsoffset = -16; + elfinit(); + HEADR = ELFRESERVE; + if(INITTEXT == -1) + INITTEXT = (1<<22)+HEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case Hwindows: /* PE executable */ + peinit(); + HEADR = PEFILEHEADR; + if(INITTEXT == -1) + INITTEXT = PEBASE+PESECTHEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = PESECTALIGN; + break; + } + if(INITDAT != 0 && INITRND != 0) + print("warning: -D0x%llux is ignored because of -R0x%ux\n", + INITDAT, INITRND); + if(debug['v']) + Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n", + HEADTYPE, INITTEXT, INITDAT, INITRND); + Bflush(&bso); + instinit(); + + zprg.link = P; + zprg.pcond = P; + zprg.back = 2; + zprg.as = AGOK; + zprg.from.type = D_NONE; + zprg.from.index = D_NONE; + zprg.from.scale = 1; + zprg.to = zprg.from; + zprg.mode = 64; + + pcstr = "%.6llux "; + nuxiinit(); + histgen = 0; + pc = 0; + dtype = 4; + version = 0; + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); + + addlibpath("command line", "command line", argv[0], "main"); + loadlib(); + deadcode(); + patch(); + follow(); + doelf(); + if(HEADTYPE == Hdarwin) + domacho(); + dostkoff(); + dostkcheck(); + paramspace = "SP"; /* (FP) now (SP) on output */ + if(debug['p']) + if(debug['1']) + doprof1(); + else + doprof2(); + span(); + if(HEADTYPE == Hwindows) + dope(); + addexport(); + textaddress(); + pclntab(); + symtab(); + dodata(); + address(); + doweak(); + reloc(); + asmb(); + undef(); + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + Bprint(&bso, "%d symbols\n", nsymbol); + Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); + Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); + } + Bflush(&bso); + + errorexit(); +} + +static Sym* +zsym(char *pn, Biobuf *f, Sym *h[]) +{ + int o; + + o = BGETC(f); + if(o < 0 || o >= NSYM || h[o] == nil) + mangle(pn); + return h[o]; +} + +static void +zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[]) +{ + int t; + int32 l; + Sym *s; + Auto *u; + + t = BGETC(f); + a->index = D_NONE; + a->scale = 0; + if(t & T_INDEX) { + a->index = BGETC(f); + a->scale = BGETC(f); + } + a->offset = 0; + if(t & T_OFFSET) { + a->offset = Bget4(f); + if(t & T_64) { + a->offset &= 0xFFFFFFFFULL; + a->offset |= (vlong)Bget4(f) << 32; + } + } + a->sym = S; + if(t & T_SYM) + a->sym = zsym(pn, f, h); + a->type = D_NONE; + if(t & T_FCONST) { + a->ieee.l = Bget4(f); + a->ieee.h = Bget4(f); + a->type = D_FCONST; + } else + if(t & T_SCONST) { + Bread(f, a->scon, NSNAME); + a->type = D_SCONST; + } + if(t & T_TYPE) + a->type = BGETC(f); + if(a->type < 0 || a->type >= D_SIZE) + mangle(pn); + adrgotype = S; + if(t & T_GOTYPE) + adrgotype = zsym(pn, f, h); + s = a->sym; + t = a->type; + if(t == D_INDIR+D_GS) + a->offset += tlsoffset; + if(t != D_AUTO && t != D_PARAM) { + if(s && adrgotype) + s->gotype = adrgotype; + return; + } + l = a->offset; + for(u=curauto; u; u=u->link) { + if(u->asym == s) + if(u->type == t) { + if(u->aoffset > l) + u->aoffset = l; + if(adrgotype) + u->gotype = adrgotype; + return; + } + } + + switch(t) { + case D_FILE: + case D_FILE1: + case D_AUTO: + case D_PARAM: + if(s == S) + mangle(pn); + } + + u = mal(sizeof(*u)); + u->link = curauto; + curauto = u; + u->asym = s; + u->aoffset = l; + u->type = t; + u->gotype = adrgotype; +} + +void +nopout(Prog *p) +{ + p->as = ANOP; + p->from.type = D_NONE; + p->to.type = D_NONE; +} + +void +ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) +{ + vlong ipc; + Prog *p; + int v, o, r, skip, mode; + Sym *h[NSYM], *s; + uint32 sig; + char *name, *x; + int ntext; + vlong eof; + char src[1024]; + Prog *lastp; + + lastp = nil; + ntext = 0; + eof = Boffset(f) + len; + src[0] = 0; + +newloop: + memset(h, 0, sizeof(h)); + version++; + histfrogp = 0; + ipc = pc; + skip = 0; + mode = 64; + +loop: + if(f->state == Bracteof || Boffset(f) >= eof) + goto eof; + o = BGETC(f); + if(o == Beof) + goto eof; + o |= BGETC(f) << 8; + if(o <= AXXX || o >= ALAST) { + if(o < 0) + goto eof; + diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); + print(" probably not a .6 file\n"); + errorexit(); + } + + if(o == ANAME || o == ASIGNAME) { + sig = 0; + if(o == ASIGNAME) + sig = Bget4(f); + v = BGETC(f); /* type */ + o = BGETC(f); /* sym */ + r = 0; + if(v == D_STATIC) + r = version; + name = Brdline(f, '\0'); + if(name == nil) { + if(Blinelen(f) > 0) { + fprint(2, "%s: name too long\n", pn); + errorexit(); + } + goto eof; + } + x = expandpkg(name, pkg); + s = lookup(x, r); + if(x != name) + free(x); + + if(debug['S'] && r == 0) + sig = 1729; + if(sig != 0){ + if(s->sig != 0 && s->sig != sig) + diag("incompatible type signatures" + "%ux(%s) and %ux(%s) for %s", + s->sig, s->file, sig, pn, s->name); + s->sig = sig; + s->file = pn; + } + + if(debug['W']) + print(" ANAME %s\n", s->name); + if(o < 0 || o >= nelem(h)) + mangle(pn); + h[o] = s; + if((v == D_EXTERN || v == D_STATIC) && s->type == 0) + s->type = SXREF; + if(v == D_FILE) { + if(s->type != SFILE) { + histgen++; + s->type = SFILE; + s->value = histgen; + } + if(histfrogp < MAXHIST) { + histfrog[histfrogp] = s; + histfrogp++; + } else + collapsefrog(s); + dwarfaddfrag(s->value, s->name); + } + goto loop; + } + + p = mal(sizeof(*p)); + p->as = o; + p->line = Bget4(f); + p->back = 2; + p->mode = mode; + p->ft = 0; + p->tt = 0; + zaddr(pn, f, &p->from, h); + fromgotype = adrgotype; + zaddr(pn, f, &p->to, h); + + switch(p->as) { + case ATEXT: + case ADATA: + case AGLOBL: + if(p->from.sym == S) + mangle(pn); + break; + } + + if(debug['W']) + print("%P\n", p); + + switch(p->as) { + case AHISTORY: + if(p->to.offset == -1) { + addlib(src, pn); + histfrogp = 0; + goto loop; + } + if(src[0] == '\0') + copyhistfrog(src, sizeof src); + addhist(p->line, D_FILE); /* 'z' */ + if(p->to.offset) + addhist(p->to.offset, D_FILE1); /* 'Z' */ + histfrogp = 0; + goto loop; + + case AEND: + histtoauto(); + if(cursym != nil && cursym->text) + cursym->autom = curauto; + curauto = 0; + cursym = nil; + if(Boffset(f) == eof) + return; + goto newloop; + + case AGLOBL: + s = p->from.sym; + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->size = 0; + } + if(s->type != SBSS && !s->dupok) { + diag("%s: redefinition: %s in %s", + pn, s->name, TNAME); + s->type = SBSS; + s->size = 0; + } + if(p->to.offset > s->size) + s->size = p->to.offset; + if(p->from.scale & DUPOK) + s->dupok = 1; + if(p->from.scale & RODATA) + s->type = SRODATA; + goto loop; + + case ADATA: + // Assume that AGLOBL comes after ADATA. + // If we've seen an AGLOBL that said this sym was DUPOK, + // ignore any more ADATA we see, which must be + // redefinitions. + s = p->from.sym; + if(s->dupok) { +// if(debug['v']) +// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); + goto loop; + } + if(s->file == nil) + s->file = pn; + else if(s->file != pn) { + diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); + errorexit(); + } + savedata(s, p, pn); + unmal(p, sizeof *p); + goto loop; + + case AGOK: + diag("%s: GOK opcode in %s", pn, TNAME); + pc++; + goto loop; + + case ATEXT: + s = p->from.sym; + if(s->text != nil) { + diag("%s: %s: redefinition", pn, s->name); + return; + } + if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { + /* redefinition, so file has probably been seen before */ + if(debug['v']) + Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name); + return; + } + if(cursym != nil && cursym->text) { + histtoauto(); + cursym->autom = curauto; + curauto = 0; + } + skip = 0; + if(etextp) + etextp->next = s; + else + textp = s; + etextp = s; + s->text = p; + cursym = s; + if(s->type != 0 && s->type != SXREF) { + if(p->from.scale & DUPOK) { + skip = 1; + goto casdef; + } + diag("%s: redefinition: %s\n%P", pn, s->name, p); + } + if(fromgotype) { + if(s->gotype && s->gotype != fromgotype) + diag("%s: type mismatch for %s", pn, s->name); + s->gotype = fromgotype; + } + s->type = STEXT; + s->value = pc; + lastp = p; + p->pc = pc++; + goto loop; + + case AMODE: + if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){ + switch((int)p->from.offset){ + case 16: case 32: case 64: + mode = p->from.offset; + break; + } + } + goto loop; + + case AFMOVF: + case AFADDF: + case AFSUBF: + case AFSUBRF: + case AFMULF: + case AFDIVF: + case AFDIVRF: + case AFCOMF: + case AFCOMFP: + case AMOVSS: + case AADDSS: + case ASUBSS: + case AMULSS: + case ADIVSS: + case ACOMISS: + case AUCOMISS: + if(skip) + goto casdef; + if(p->from.type == D_FCONST) { + /* size sb 9 max */ + sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SDATA; + adduint32(s, ieeedtof(&p->from.ieee)); + s->reachable = 0; + } + p->from.type = D_EXTERN; + p->from.sym = s; + p->from.offset = 0; + } + goto casdef; + + case AFMOVD: + case AFADDD: + case AFSUBD: + case AFSUBRD: + case AFMULD: + case AFDIVD: + case AFDIVRD: + case AFCOMD: + case AFCOMDP: + case AMOVSD: + case AADDSD: + case ASUBSD: + case AMULSD: + case ADIVSD: + case ACOMISD: + case AUCOMISD: + if(skip) + goto casdef; + if(p->from.type == D_FCONST) { + /* size sb 18 max */ + sprint(literal, "$%ux.%ux", + p->from.ieee.l, p->from.ieee.h); + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SDATA; + adduint32(s, p->from.ieee.l); + adduint32(s, p->from.ieee.h); + s->reachable = 0; + } + p->from.type = D_EXTERN; + p->from.sym = s; + p->from.offset = 0; + } + goto casdef; + + casdef: + default: + if(skip) + nopout(p); + p->pc = pc; + pc++; + + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + if(lastp == nil) { + if(p->as != ANOP) + diag("unexpected instruction: %P", p); + goto loop; + } + lastp->link = p; + lastp = p; + goto loop; + } + +eof: + diag("truncated object file: %s", pn); +} + +Prog* +prg(void) +{ + Prog *p; + + p = mal(sizeof(*p)); + + *p = zprg; + return p; +} + +Prog* +copyp(Prog *q) +{ + Prog *p; + + p = prg(); + *p = *q; + return p; +} + +Prog* +appendp(Prog *q) +{ + Prog *p; + + p = prg(); + p->link = q->link; + q->link = p; + p->line = q->line; + p->mode = q->mode; + return p; +} diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c new file mode 100644 index 000000000..36806ec4b --- /dev/null +++ b/src/cmd/6l/optab.c @@ -0,0 +1,1279 @@ +// Inferno utils/6l/optab.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/optab.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "l.h" + +uchar ynone[] = +{ + Ynone, Ynone, Zlit, 1, + 0 +}; +uchar ytext[] = +{ + Ymb, Yi64, Zpseudo,1, + 0 +}; +uchar ynop[] = +{ + Ynone, Ynone, Zpseudo,1, + Ynone, Yml, Zpseudo,1, + Ynone, Yrf, Zpseudo,1, + Yml, Ynone, Zpseudo,1, + Yrf, Ynone, Zpseudo,1, + 0 +}; +uchar yxorb[] = +{ + Yi32, Yal, Zib_, 1, + Yi32, Ymb, Zibo_m, 2, + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +uchar yxorl[] = +{ + Yi8, Yml, Zibo_m, 2, + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar yaddl[] = +{ + Yi8, Yml, Zibo_m, 2, + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar yincb[] = +{ + Ynone, Ymb, Zo_m, 2, + 0 +}; +uchar yincw[] = +{ + Ynone, Yml, Zo_m, 2, + 0 +}; +uchar yincl[] = +{ + Ynone, Yml, Zo_m, 2, + 0 +}; +uchar ycmpb[] = +{ + Yal, Yi32, Z_ib, 1, + Ymb, Yi32, Zm_ibo, 2, + Ymb, Yrb, Zm_r, 1, + Yrb, Ymb, Zr_m, 1, + 0 +}; +uchar ycmpl[] = +{ + Yml, Yi8, Zm_ibo, 2, + Yax, Yi32, Z_il, 1, + Yml, Yi32, Zm_ilo, 2, + Yml, Yrl, Zm_r, 1, + Yrl, Yml, Zr_m, 1, + 0 +}; +uchar yshb[] = +{ + Yi1, Ymb, Zo_m, 2, + Yi32, Ymb, Zibo_m, 2, + Ycx, Ymb, Zo_m, 2, + 0 +}; +uchar yshl[] = +{ + Yi1, Yml, Zo_m, 2, + Yi32, Yml, Zibo_m, 2, + Ycl, Yml, Zo_m, 2, + Ycx, Yml, Zo_m, 2, + 0 +}; +uchar ytestb[] = +{ + Yi32, Yal, Zib_, 1, + Yi32, Ymb, Zibo_m, 2, + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +uchar ytestl[] = +{ + Yi32, Yax, Zil_, 1, + Yi32, Yml, Zilo_m, 2, + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar ymovb[] = +{ + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + Yi32, Yrb, Zib_rp, 1, + Yi32, Ymb, Zibo_m, 2, + 0 +}; +uchar ymbs[] = +{ + Ymb, Ynone, Zm_o, 2, + 0 +}; +uchar ybtl[] = +{ + Yi8, Yml, Zibo_m, 2, + Yrl, Yml, Zr_m, 1, + 0 +}; +uchar ymovw[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + Yi0, Yrl, Zclr, 1, + Yi32, Yrl, Zil_rp, 1, + Yi32, Yml, Zilo_m, 2, + Yiauto, Yrl, Zaut_r, 2, + 0 +}; +uchar ymovl[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + Yi0, Yrl, Zclr, 1, + Yi32, Yrl, Zil_rp, 1, + Yi32, Yml, Zilo_m, 2, + Yml, Ymr, Zm_r_xm, 1, // MMX MOVD + Ymr, Yml, Zr_m_xm, 1, // MMX MOVD + Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit) + Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit) + Yiauto, Yrl, Zaut_r, 2, + 0 +}; +uchar yret[] = +{ + Ynone, Ynone, Zo_iw, 1, + Yi32, Ynone, Zo_iw, 1, + 0 +}; +uchar ymovq[] = +{ + Yrl, Yml, Zr_m, 1, // 0x89 + Yml, Yrl, Zm_r, 1, // 0x8b + Yi0, Yrl, Zclr, 1, // 0x31 + Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0) + Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate + Yi32, Yml, Zilo_m, 2, // 0xc7,(0) + Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding) + Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ + Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD + Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD + Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q + Yxr, Ym, Zr_m_xm_nr, 2, // MOVQ xmm store + Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load + Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store + Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ + 0 +}; +uchar ym_rl[] = +{ + Ym, Yrl, Zm_r, 1, + 0 +}; +uchar yrl_m[] = +{ + Yrl, Ym, Zr_m, 1, + 0 +}; +uchar ymb_rl[] = +{ + Ymb, Yrl, Zmb_r, 1, + 0 +}; +uchar yml_rl[] = +{ + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar yrl_ml[] = +{ + Yrl, Yml, Zr_m, 1, + 0 +}; +uchar yml_mb[] = +{ + Yrb, Ymb, Zr_m, 1, + Ymb, Yrb, Zm_r, 1, + 0 +}; +uchar yrb_mb[] = +{ + Yrb, Ymb, Zr_m, 1, + 0 +}; +uchar yml_ml[] = +{ + Yrl, Yml, Zr_m, 1, + Yml, Yrl, Zm_r, 1, + 0 +}; +uchar ydivl[] = +{ + Yml, Ynone, Zm_o, 2, + 0 +}; +uchar ydivb[] = +{ + Ymb, Ynone, Zm_o, 2, + 0 +}; +uchar yimul[] = +{ + Yml, Ynone, Zm_o, 2, + Yi8, Yrl, Zib_rr, 1, + Yi32, Yrl, Zil_rr, 1, + Yml, Yrl, Zm_r, 2, + 0 +}; +uchar ybyte[] = +{ + Yi64, Ynone, Zbyte, 1, + 0 +}; +uchar yin[] = +{ + Yi32, Ynone, Zib_, 1, + Ynone, Ynone, Zlit, 1, + 0 +}; +uchar yint[] = +{ + Yi32, Ynone, Zib_, 1, + 0 +}; +uchar ypushl[] = +{ + Yrl, Ynone, Zrp_, 1, + Ym, Ynone, Zm_o, 2, + Yi8, Ynone, Zib_, 1, + Yi32, Ynone, Zil_, 1, + 0 +}; +uchar ypopl[] = +{ + Ynone, Yrl, Z_rp, 1, + Ynone, Ym, Zo_m, 2, + 0 +}; +uchar yscond[] = +{ + Ynone, Ymb, Zo_m, 2, + 0 +}; +uchar yjcond[] = +{ + Ynone, Ybr, Zbr, 1, + 0 +}; +uchar yloop[] = +{ + Ynone, Ybr, Zloop, 1, + 0 +}; +uchar ycall[] = +{ + Ynone, Yml, Zo_m64, 2, + Ynone, Ybr, Zcall, 1, + 0 +}; +uchar yjmp[] = +{ + Ynone, Yml, Zo_m64, 2, + Ynone, Ybr, Zjmp, 1, + 0 +}; + +uchar yfmvd[] = +{ + Ym, Yf0, Zm_o, 2, + Yf0, Ym, Zo_m, 2, + Yrf, Yf0, Zm_o, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfmvdp[] = +{ + Yf0, Ym, Zo_m, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfmvf[] = +{ + Ym, Yf0, Zm_o, 2, + Yf0, Ym, Zo_m, 2, + 0 +}; +uchar yfmvx[] = +{ + Ym, Yf0, Zm_o, 2, + 0 +}; +uchar yfmvp[] = +{ + Yf0, Ym, Zo_m, 2, + 0 +}; +uchar yfadd[] = +{ + Ym, Yf0, Zm_o, 2, + Yrf, Yf0, Zm_o, 2, + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfaddp[] = +{ + Yf0, Yrf, Zo_m, 2, + 0 +}; +uchar yfxch[] = +{ + Yf0, Yrf, Zo_m, 2, + Yrf, Yf0, Zm_o, 2, + 0 +}; +uchar ycompp[] = +{ + Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */ + 0 +}; +uchar ystsw[] = +{ + Ynone, Ym, Zo_m, 2, + Ynone, Yax, Zlit, 1, + 0 +}; +uchar ystcw[] = +{ + Ynone, Ym, Zo_m, 2, + Ym, Ynone, Zm_o, 2, + 0 +}; +uchar ysvrs[] = +{ + Ynone, Ym, Zo_m, 2, + Ym, Ynone, Zm_o, 2, + 0 +}; +uchar ymm[] = +{ + Ymm, Ymr, Zm_r_xm, 1, + Yxm, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yxm[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxcvm1[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + Yxm, Ymr, Zm_r_xm, 2, + 0 +}; +uchar yxcvm2[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + Ymm, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yxmq[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yxr[] = +{ + Yxr, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxr_ml[] = +{ + Yxr, Yml, Zr_m_xm, 1, + 0 +}; +uchar ymr[] = +{ + Ymr, Ymr, Zm_r, 1, + 0 +}; +uchar ymr_ml[] = +{ + Ymr, Yml, Zr_m_xm, 1, + 0 +}; +uchar yxcmp[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxcmpi[] = +{ + Yxm, Yxr, Zm_r_i_xm, 2, + 0 +}; +uchar yxmov[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + Yxr, Yxm, Zr_m_xm, 1, + 0 +}; +uchar yxcvfl[] = +{ + Yxm, Yrl, Zm_r_xm, 1, + 0 +}; +uchar yxcvlf[] = +{ + Yml, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxcvfq[] = +{ + Yxm, Yrl, Zm_r_xm, 2, + 0 +}; +uchar yxcvqf[] = +{ + Yml, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yps[] = +{ + Ymm, Ymr, Zm_r_xm, 1, + Yi8, Ymr, Zibo_m_xm, 2, + Yxm, Yxr, Zm_r_xm, 2, + Yi8, Yxr, Zibo_m_xm, 3, + 0 +}; +uchar yxrrl[] = +{ + Yxr, Yrl, Zm_r, 1, + 0 +}; +uchar ymfp[] = +{ + Ymm, Ymr, Zm_r_3d, 1, + 0, +}; +uchar ymrxr[] = +{ + Ymr, Yxr, Zm_r, 1, + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +uchar ymshuf[] = +{ + Ymm, Ymr, Zibm_r, 1, + 0 +}; +uchar yxshuf[] = +{ + Yxm, Yxr, Zibm_r, 1, + 0 +}; +uchar yextrw[] = +{ + Yxr, Yrl, Zibm_r, 1, + 0 +}; +uchar ypsdq[] = +{ + Yi8, Yxr, Zibo_m, 2, + 0 +}; +uchar ymskb[] = +{ + Yxr, Yrl, Zm_r_xm, 2, + Ymr, Yrl, Zm_r_xm, 1, + 0 +}; +uchar ycrc32l[] = +{ + Yml, Yrl, Zlitm_r, 0, +}; + +/* + * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32, + * and p->from and p->to as operands (Adr*). The linker scans optab to find + * the entry with the given p->as and then looks through the ytable for that + * instruction (the second field in the optab struct) for a line whose first + * two values match the Ytypes of the p->from and p->to operands. The function + * oclass in span.c computes the specific Ytype of an operand and then the set + * of more general Ytypes that it satisfies is implied by the ycover table, set + * up in instinit. For example, oclass distinguishes the constants 0 and 1 + * from the more general 8-bit constants, but instinit says + * + * ycover[Yi0*Ymax + Ys32] = 1; + * ycover[Yi1*Ymax + Ys32] = 1; + * ycover[Yi8*Ymax + Ys32] = 1; + * + * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32) + * if that's what an instruction can handle. + * + * In parallel with the scan through the ytable for the appropriate line, there + * is a z pointer that starts out pointing at the strange magic byte list in + * the Optab struct. With each step past a non-matching ytable line, z + * advances by the 4th entry in the line. When a matching line is found, that + * z pointer has the extra data to use in laying down the instruction bytes. + * The actual bytes laid down are a function of the 3rd entry in the line (that + * is, the Ztype) and the z bytes. + * + * For example, let's look at AADDL. The optab line says: + * { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + * + * and yaddl says + * uchar yaddl[] = + * { + * Yi8, Yml, Zibo_m, 2, + * Yi32, Yax, Zil_, 1, + * Yi32, Yml, Zilo_m, 2, + * Yrl, Yml, Zr_m, 1, + * Yml, Yrl, Zm_r, 1, + * 0 + * }; + * + * so there are 5 possible types of ADDL instruction that can be laid down, and + * possible states used to lay them down (Ztype and z pointer, assuming z + * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are: + * + * Yi8, Yml -> Zibo_m, z (0x83, 00) + * Yi32, Yax -> Zil_, z+2 (0x05) + * Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00) + * Yrl, Yml -> Zr_m, z+2+1+2 (0x01) + * Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03) + * + * The Pconstant in the optab line controls the prefix bytes to emit. That's + * relatively straightforward as this program goes. + * + * The switch on t[2] in doasm implements the various Z cases. Zibo_m, for + * example, is an opcode byte (z[0]) then an asmando (which is some kind of + * encoded addressing mode for the Yml arg), and then a single immediate byte. + * Zilo_m is the same but a long (32-bit) immediate. + */ +Optab optab[] = +/* as, ytab, andproto, opcode */ +{ + { AXXX }, + { AAAA, ynone, P32, 0x37 }, + { AAAD, ynone, P32, 0xd5,0x0a }, + { AAAM, ynone, P32, 0xd4,0x0a }, + { AAAS, ynone, P32, 0x3f }, + { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 }, + { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, + { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 }, + { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADDPD, yxm, Pq, 0x58 }, + { AADDPS, yxm, Pm, 0x58 }, + { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADDSD, yxm, Pf2, 0x58 }, + { AADDSS, yxm, Pf3, 0x58 }, + { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + { AADJSP }, + { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 }, + { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AANDNPD, yxm, Pq, 0x55 }, + { AANDNPS, yxm, Pm, 0x55 }, + { AANDPD, yxm, Pq, 0x54 }, + { AANDPS, yxm, Pq, 0x54 }, + { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, + { AARPL, yrl_ml, P32, 0x63 }, + { ABOUNDL, yrl_m, P32, 0x62 }, + { ABOUNDW, yrl_m, Pe, 0x62 }, + { ABSFL, yml_rl, Pm, 0xbc }, + { ABSFQ, yml_rl, Pw, 0x0f,0xbc }, + { ABSFW, yml_rl, Pq, 0xbc }, + { ABSRL, yml_rl, Pm, 0xbd }, + { ABSRQ, yml_rl, Pw, 0x0f,0xbd }, + { ABSRW, yml_rl, Pq, 0xbd }, + { ABTCL, ybtl, Pm, 0xba,(07),0xbb }, + { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb }, + { ABTCW, ybtl, Pq, 0xba,(07),0xbb }, + { ABTL, ybtl, Pm, 0xba,(04),0xa3 }, + { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3}, + { ABTRL, ybtl, Pm, 0xba,(06),0xb3 }, + { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 }, + { ABTRW, ybtl, Pq, 0xba,(06),0xb3 }, + { ABTSL, ybtl, Pm, 0xba,(05),0xab }, + { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab }, + { ABTSW, ybtl, Pq, 0xba,(05),0xab }, + { ABTW, ybtl, Pq, 0xba,(04),0xa3 }, + { ABYTE, ybyte, Px, 1 }, + { ACALL, ycall, Px, 0xff,(02),0xe8 }, + { ACDQ, ynone, Px, 0x99 }, + { ACLC, ynone, Px, 0xf8 }, + { ACLD, ynone, Px, 0xfc }, + { ACLI, ynone, Px, 0xfa }, + { ACLTS, ynone, Pm, 0x06 }, + { ACMC, ynone, Px, 0xf5 }, + { ACMOVLCC, yml_rl, Pm, 0x43 }, + { ACMOVLCS, yml_rl, Pm, 0x42 }, + { ACMOVLEQ, yml_rl, Pm, 0x44 }, + { ACMOVLGE, yml_rl, Pm, 0x4d }, + { ACMOVLGT, yml_rl, Pm, 0x4f }, + { ACMOVLHI, yml_rl, Pm, 0x47 }, + { ACMOVLLE, yml_rl, Pm, 0x4e }, + { ACMOVLLS, yml_rl, Pm, 0x46 }, + { ACMOVLLT, yml_rl, Pm, 0x4c }, + { ACMOVLMI, yml_rl, Pm, 0x48 }, + { ACMOVLNE, yml_rl, Pm, 0x45 }, + { ACMOVLOC, yml_rl, Pm, 0x41 }, + { ACMOVLOS, yml_rl, Pm, 0x40 }, + { ACMOVLPC, yml_rl, Pm, 0x4b }, + { ACMOVLPL, yml_rl, Pm, 0x49 }, + { ACMOVLPS, yml_rl, Pm, 0x4a }, + { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 }, + { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 }, + { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 }, + { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d }, + { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f }, + { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 }, + { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e }, + { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 }, + { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c }, + { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 }, + { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 }, + { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 }, + { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 }, + { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b }, + { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 }, + { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a }, + { ACMOVWCC, yml_rl, Pq, 0x43 }, + { ACMOVWCS, yml_rl, Pq, 0x42 }, + { ACMOVWEQ, yml_rl, Pq, 0x44 }, + { ACMOVWGE, yml_rl, Pq, 0x4d }, + { ACMOVWGT, yml_rl, Pq, 0x4f }, + { ACMOVWHI, yml_rl, Pq, 0x47 }, + { ACMOVWLE, yml_rl, Pq, 0x4e }, + { ACMOVWLS, yml_rl, Pq, 0x46 }, + { ACMOVWLT, yml_rl, Pq, 0x4c }, + { ACMOVWMI, yml_rl, Pq, 0x48 }, + { ACMOVWNE, yml_rl, Pq, 0x45 }, + { ACMOVWOC, yml_rl, Pq, 0x41 }, + { ACMOVWOS, yml_rl, Pq, 0x40 }, + { ACMOVWPC, yml_rl, Pq, 0x4b }, + { ACMOVWPL, yml_rl, Pq, 0x49 }, + { ACMOVWPS, yml_rl, Pq, 0x4a }, + { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a }, + { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACMPPD, yxcmpi, Px, Pe,0xc2 }, + { ACMPPS, yxcmpi, Pm, 0xc2,0 }, + { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACMPSB, ynone, Pb, 0xa6 }, + { ACMPSD, yxcmpi, Px, Pf2,0xc2 }, + { ACMPSL, ynone, Px, 0xa7 }, + { ACMPSQ, ynone, Pw, 0xa7 }, + { ACMPSS, yxcmpi, Px, Pf3,0xc2 }, + { ACMPSW, ynone, Pe, 0xa7 }, + { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, + { ACOMISD, yxcmp, Pe, 0x2f }, + { ACOMISS, yxcmp, Pm, 0x2f }, + { ACPUID, ynone, Pm, 0xa2 }, + { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a }, + { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, }, + { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d }, + { ACVTPD2PS, yxm, Pe, 0x5a }, + { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d }, + { ACVTPS2PD, yxm, Pm, 0x5a }, + { API2FW, ymfp, Px, 0x0c }, + { ACVTSD2SL, yxcvfl, Pf2, 0x2d }, + { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d }, + { ACVTSD2SS, yxm, Pf2, 0x5a }, + { ACVTSL2SD, yxcvlf, Pf2, 0x2a }, + { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a }, + { ACVTSL2SS, yxcvlf, Pf3, 0x2a }, + { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a }, + { ACVTSS2SD, yxm, Pf3, 0x5a }, + { ACVTSS2SL, yxcvfl, Pf3, 0x2d }, + { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d }, + { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c }, + { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c }, + { ACVTTSD2SL, yxcvfl, Pf2, 0x2c }, + { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c }, + { ACVTTSS2SL, yxcvfl, Pf3, 0x2c }, + { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c }, + { ACWD, ynone, Pe, 0x99 }, + { ACQO, ynone, Pw, 0x99 }, + { ADAA, ynone, P32, 0x27 }, + { ADAS, ynone, P32, 0x2f }, + { ADATA }, + { ADECB, yincb, Pb, 0xfe,(01) }, + { ADECL, yincl, Px, 0xff,(01) }, + { ADECQ, yincl, Pw, 0xff,(01) }, + { ADECW, yincw, Pe, 0xff,(01) }, + { ADIVB, ydivb, Pb, 0xf6,(06) }, + { ADIVL, ydivl, Px, 0xf7,(06) }, + { ADIVPD, yxm, Pe, 0x5e }, + { ADIVPS, yxm, Pm, 0x5e }, + { ADIVQ, ydivl, Pw, 0xf7,(06) }, + { ADIVSD, yxm, Pf2, 0x5e }, + { ADIVSS, yxm, Pf3, 0x5e }, + { ADIVW, ydivl, Pe, 0xf7,(06) }, + { AEMMS, ynone, Pm, 0x77 }, + { AENTER }, /* botch */ + { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) }, + { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) }, + { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) }, + { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) }, + { AGLOBL }, + { AGOK }, + { AHISTORY }, + { AHLT, ynone, Px, 0xf4 }, + { AIDIVB, ydivb, Pb, 0xf6,(07) }, + { AIDIVL, ydivl, Px, 0xf7,(07) }, + { AIDIVQ, ydivl, Pw, 0xf7,(07) }, + { AIDIVW, ydivl, Pe, 0xf7,(07) }, + { AIMULB, ydivb, Pb, 0xf6,(05) }, + { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf }, + { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf }, + { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf }, + { 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 }, + { AJCXZ, yloop, Px, 0xe3 }, + { AJEQ, yjcond, Px, 0x74,0x84 }, + { AJGE, yjcond, Px, 0x7d,0x8d }, + { AJGT, yjcond, Px, 0x7f,0x8f }, + { AJHI, yjcond, Px, 0x77,0x87 }, + { AJLE, yjcond, Px, 0x7e,0x8e }, + { AJLS, yjcond, Px, 0x76,0x86 }, + { AJLT, yjcond, Px, 0x7c,0x8c }, + { AJMI, yjcond, Px, 0x78,0x88 }, + { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 }, + { AJNE, yjcond, Px, 0x75,0x85 }, + { AJOC, yjcond, Px, 0x71,0x81,(00) }, + { AJOS, yjcond, Px, 0x70,0x80,(00) }, + { AJPC, yjcond, Px, 0x7b,0x8b }, + { AJPL, yjcond, Px, 0x79,0x89 }, + { AJPS, yjcond, Px, 0x7a,0x8a }, + { ALAHF, ynone, Px, 0x9f }, + { ALARL, yml_rl, Pm, 0x02 }, + { ALARW, yml_rl, Pq, 0x02 }, + { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) }, + { ALEAL, ym_rl, Px, 0x8d }, + { ALEAQ, ym_rl, Pw, 0x8d }, + { ALEAVEL, ynone, P32, 0xc9 }, + { ALEAVEQ, ynone, Py, 0xc9 }, + { ALEAVEW, ynone, Pe, 0xc9 }, + { ALEAW, ym_rl, Pe, 0x8d }, + { ALOCK, ynone, Px, 0xf0 }, + { ALODSB, ynone, Pb, 0xac }, + { ALODSL, ynone, Px, 0xad }, + { ALODSQ, ynone, Pw, 0xad }, + { ALODSW, ynone, Pe, 0xad }, + { ALONG, ybyte, Px, 4 }, + { ALOOP, yloop, Px, 0xe2 }, + { ALOOPEQ, yloop, Px, 0xe1 }, + { ALOOPNE, yloop, Px, 0xe0 }, + { ALSLL, yml_rl, Pm, 0x03 }, + { ALSLW, yml_rl, Pq, 0x03 }, + { AMASKMOVOU, yxr, Pe, 0xf7 }, + { AMASKMOVQ, ymr, Pm, 0xf7 }, + { AMAXPD, yxm, Pe, 0x5f }, + { AMAXPS, yxm, Pm, 0x5f }, + { AMAXSD, yxm, Pf2, 0x5f }, + { AMAXSS, yxm, Pf3, 0x5f }, + { AMINPD, yxm, Pe, 0x5d }, + { AMINPS, yxm, Pm, 0x5d }, + { AMINSD, yxm, Pf2, 0x5d }, + { AMINSS, yxm, Pf3, 0x5d }, + { AMOVAPD, yxmov, Pe, 0x28,0x29 }, + { AMOVAPS, yxmov, Pm, 0x28,0x29 }, + { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) }, + { AMOVBLSX, ymb_rl, Pm, 0xbe }, + { AMOVBLZX, ymb_rl, Pm, 0xb6 }, + { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe }, + { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 }, + { AMOVBWSX, ymb_rl, Pq, 0xbe }, + { AMOVBWZX, ymb_rl, Pq, 0xb6 }, + { AMOVO, yxmov, Pe, 0x6f,0x7f }, + { AMOVOU, yxmov, Pf3, 0x6f,0x7f }, + { AMOVHLPS, yxr, Pm, 0x12 }, + { AMOVHPD, yxmov, Pe, 0x16,0x17 }, + { AMOVHPS, yxmov, Pm, 0x16,0x17 }, + { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e }, + { 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,Pe,0xd6,Pe,0x6e,Pe,0x7e }, + { 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) }, + { AMOVWLSX, yml_rl, Pm, 0xbf }, + { AMOVWLZX, yml_rl, Pm, 0xb7 }, + { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf }, + { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 }, + { AMULB, ydivb, Pb, 0xf6,(04) }, + { AMULL, ydivl, Px, 0xf7,(04) }, + { AMULPD, yxm, Pe, 0x59 }, + { AMULPS, yxm, Ym, 0x59 }, + { AMULQ, ydivl, Pw, 0xf7,(04) }, + { AMULSD, yxm, Pf2, 0x59 }, + { AMULSS, yxm, Pf3, 0x59 }, + { AMULW, ydivl, Pe, 0xf7,(04) }, + { ANAME }, + { ANEGB, yscond, Pb, 0xf6,(03) }, + { ANEGL, yscond, Px, 0xf7,(03) }, + { ANEGQ, yscond, Pw, 0xf7,(03) }, + { ANEGW, yscond, Pe, 0xf7,(03) }, + { ANOP, ynop, Px, 0,0 }, + { ANOTB, yscond, Pb, 0xf6,(02) }, + { ANOTL, yscond, Px, 0xf7,(02) }, + { ANOTQ, yscond, Pw, 0xf7,(02) }, + { ANOTW, yscond, Pe, 0xf7,(02) }, + { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a }, + { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, + { AORPD, yxm, Pq, 0x56 }, + { AORPS, yxm, Pm, 0x56 }, + { AORQ, yxorl, Pw, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, + { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, + { AOUTB, yin, Pb, 0xe6,0xee }, + { AOUTL, yin, Px, 0xe7,0xef }, + { AOUTSB, ynone, Pb, 0x6e }, + { AOUTSL, ynone, Px, 0x6f }, + { AOUTSW, ynone, Pe, 0x6f }, + { AOUTW, yin, Pe, 0xe7,0xef }, + { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b }, + { APACKSSWB, ymm, Py, 0x63,Pe,0x63 }, + { APACKUSWB, ymm, Py, 0x67,Pe,0x67 }, + { APADDB, ymm, Py, 0xfc,Pe,0xfc }, + { APADDL, ymm, Py, 0xfe,Pe,0xfe }, + { APADDQ, yxm, Pe, 0xd4 }, + { APADDSB, ymm, Py, 0xec,Pe,0xec }, + { APADDSW, ymm, Py, 0xed,Pe,0xed }, + { APADDUSB, ymm, Py, 0xdc,Pe,0xdc }, + { APADDUSW, ymm, Py, 0xdd,Pe,0xdd }, + { APADDW, ymm, Py, 0xfd,Pe,0xfd }, + { APAND, ymm, Py, 0xdb,Pe,0xdb }, + { APANDN, ymm, Py, 0xdf,Pe,0xdf }, + { APAUSE, ynone, Px, 0xf3,0x90 }, + { APAVGB, ymm, Py, 0xe0,Pe,0xe0 }, + { APAVGW, ymm, Py, 0xe3,Pe,0xe3 }, + { APCMPEQB, ymm, Py, 0x74,Pe,0x74 }, + { APCMPEQL, ymm, Py, 0x76,Pe,0x76 }, + { APCMPEQW, ymm, Py, 0x75,Pe,0x75 }, + { APCMPGTB, ymm, Py, 0x64,Pe,0x64 }, + { APCMPGTL, ymm, Py, 0x66,Pe,0x66 }, + { APCMPGTW, ymm, Py, 0x65,Pe,0x65 }, + { APEXTRW, yextrw, Pq, 0xc5 }, + { 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, yextrw, Pq, 0xc4 }, + { 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 }, + { APSHUFL, yxshuf, Pq, 0x70 }, + { APSHUFLW, yxshuf, Pf2, 0x70 }, + { APSHUFW, ymshuf, Pm, 0x70 }, + { 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,0x7e,(06) }, + { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) }, + { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) }, + { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) }, + { APSRLO, ypsdq, Pq, 0x73,(03) }, + { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) }, + { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) }, + { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) }, + { APSUBB, yxm, Pe, 0xf8 }, + { APSUBL, yxm, Pe, 0xfa }, + { APSUBQ, yxm, Pe, 0xfb }, + { APSUBSB, yxm, Pe, 0xe8 }, + { APSUBSW, yxm, Pe, 0xe9 }, + { APSUBUSB, yxm, Pe, 0xd8 }, + { APSUBUSW, yxm, Pe, 0xd9 }, + { APSUBW, yxm, Pe, 0xf9 }, + { APSWAPL, ymfp, Px, 0xbb }, + { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 }, + { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a }, + { APUNPCKHQDQ, yxm, Pe, 0x6d }, + { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 }, + { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 }, + { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 }, + { APUNPCKLQDQ, yxm, Pe, 0x6c }, + { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 }, + { APUSHAL, ynone, P32, 0x60 }, + { APUSHAW, ynone, Pe, 0x60 }, + { APUSHFL, ynone, P32, 0x9c }, + { APUSHFQ, ynone, Py, 0x9c }, + { APUSHFW, ynone, Pe, 0x9c }, + { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 }, + { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 }, + { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 }, + { APXOR, ymm, Py, 0xef,Pe,0xef }, + { AQUAD, ybyte, Px, 8 }, + { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) }, + { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, + { ARCPPS, yxm, Pm, 0x53 }, + { ARCPSS, yxm, Pf3, 0x53 }, + { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) }, + { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, + { ARCRQ, yshl, Pw, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, + { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, + { AREP, ynone, Px, 0xf3 }, + { AREPN, ynone, Px, 0xf2 }, + { ARET, ynone, Px, 0xc3 }, + { ARETFW, yret, Pe, 0xcb,0xca }, + { ARETFL, yret, Px, 0xcb,0xca }, + { ARETFQ, yret, Pw, 0xcb,0xca }, + { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) }, + { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, + { AROLQ, yshl, Pw, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, + { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, + { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) }, + { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, + { ARSQRTPS, yxm, Pm, 0x52 }, + { ARSQRTSS, yxm, Pf3, 0x52 }, + { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */ + { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, + { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASALQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) }, + { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, + { ASARQ, yshl, Pw, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, + { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, + { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a }, + { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, + { ASBBQ, yxorl, Pw, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, + { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, + { ASCASB, ynone, Pb, 0xae }, + { ASCASL, ynone, Px, 0xaf }, + { ASCASQ, ynone, Pw, 0xaf }, + { ASCASW, ynone, Pe, 0xaf }, + { ASETCC, yscond, Pm, 0x93,(00) }, + { ASETCS, yscond, Pm, 0x92,(00) }, + { ASETEQ, yscond, Pm, 0x94,(00) }, + { ASETGE, yscond, Pm, 0x9d,(00) }, + { ASETGT, yscond, Pm, 0x9f,(00) }, + { ASETHI, yscond, Pm, 0x97,(00) }, + { ASETLE, yscond, Pm, 0x9e,(00) }, + { ASETLS, yscond, Pm, 0x96,(00) }, + { ASETLT, yscond, Pm, 0x9c,(00) }, + { ASETMI, yscond, Pm, 0x98,(00) }, + { ASETNE, yscond, Pm, 0x95,(00) }, + { ASETOC, yscond, Pm, 0x91,(00) }, + { ASETOS, yscond, Pm, 0x90,(00) }, + { ASETPC, yscond, Pm, 0x96,(00) }, + { ASETPL, yscond, Pm, 0x99,(00) }, + { ASETPS, yscond, Pm, 0x9a,(00) }, + { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, + { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASHLQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, + { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) }, + { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, + { ASHUFPD, yxshuf, Pq, 0xc6 }, + { ASHUFPS, yxshuf, Pm, 0xc6 }, + { 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, yml_ml, Px, 0x87,0x87 }, + { AXCHGQ, yml_ml, Pw, 0x87,0x87 }, + { AXCHGW, yml_ml, Pe, 0x87,0x87 }, + { AXLAT, ynone, Px, 0xd7 }, + { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 }, + { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, + { 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}, + + { AEND }, + 0 +}; + +Optab* opindex[ALAST+1]; + +/* +AMOVD 0f 6e/r mmx,reg/mem32[mem64-rex?] +AMOVD 0f 7e/r reg/mem32[64],mmx STORE +AMOVQ 0f 6f/r mmx1,mmx2/mem64 +AMOVQ 0f 7f/r mmx1/mem64,mmx2 +*/ diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c new file mode 100644 index 000000000..d9e0b2fc1 --- /dev/null +++ b/src/cmd/6l/pass.c @@ -0,0 +1,722 @@ +// Inferno utils/6l/pass.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Code and data passes. + +#include "l.h" +#include "../ld/lib.h" +#include "../../pkg/runtime/stack.h" + +static void xfol(Prog*, Prog**); + +Prog* +brchain(Prog *p) +{ + int i; + + for(i=0; i<20; i++) { + if(p == P || p->as != AJMP) + return p; + p = p->pcond; + } + return P; +} + +void +follow(void) +{ + Prog *firstp, *lastp; + + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + + for(cursym = textp; cursym != nil; cursym = cursym->next) { + firstp = prg(); + lastp = firstp; + xfol(cursym->text, &lastp); + lastp->link = nil; + cursym->text = firstp->link; + } +} + +static int +nofollow(int a) +{ + switch(a) { + case AJMP: + case ARET: + case AIRETL: + case AIRETQ: + case AIRETW: + case ARETFL: + case ARETFQ: + case ARETFW: + return 1; + } + return 0; +} + +static int +pushpop(int a) +{ + switch(a) { + case APUSHL: + case APUSHFL: + case APUSHQ: + case APUSHFQ: + case APUSHW: + case APUSHFW: + case APOPL: + case APOPFL: + case APOPQ: + case APOPFQ: + case APOPW: + case APOPFW: + return 1; + } + return 0; +} + +static void +xfol(Prog *p, Prog **last) +{ + Prog *q; + int i; + enum as a; + +loop: + if(p == P) + return; + if(p->as == AJMP) + if((q = p->pcond) != P && q->as != ATEXT) { + /* mark instruction as done and continue layout at target of jump */ + p->mark = 1; + p = q; + if(p->mark == 0) + goto loop; + } + if(p->mark) { + /* + * p goes here, but already used it elsewhere. + * copy up to 4 instructions or else branch to other copy. + */ + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == P) + break; + if(q == *last) + break; + a = q->as; + if(a == ANOP) { + i--; + continue; + } + if(nofollow(a) || pushpop(a)) + break; // NOTE(rsc): arm does goto copy + if(q->pcond == P || q->pcond->mark) + continue; + if(a == ACALL || a == ALOOP) + continue; + for(;;) { + if(p->as == ANOP) { + p = p->link; + continue; + } + q = copyp(p); + p = p->link; + q->mark = 1; + (*last)->link = q; + *last = q; + if(q->as != a || q->pcond == P || q->pcond->mark) + continue; + + q->as = relinv(q->as); + p = q->pcond; + q->pcond = q->link; + q->link = p; + xfol(q->link, last); + p = q->link; + if(p->mark) + return; + goto loop; + } + } /* */ + q = prg(); + q->as = AJMP; + q->line = p->line; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->pcond = p; + p = q; + } + + /* emit p */ + p->mark = 1; + (*last)->link = p; + *last = p; + a = p->as; + + /* continue loop with what comes after p */ + if(nofollow(a)) + return; + if(p->pcond != P && a != ACALL) { + /* + * some kind of conditional branch. + * recurse to follow one path. + * continue loop on the other. + */ + q = brchain(p->link); + if(q != P && q->mark) + if(a != ALOOP) { + p->as = relinv(a); + p->link = p->pcond; + p->pcond = q; + } + xfol(p->link, last); + q = brchain(p->pcond); + if(q->mark) { + p->pcond = q; + return; + } + p = q; + goto loop; + } + p = p->link; + goto loop; +} + +Prog* +byteq(int v) +{ + Prog *p; + + p = prg(); + p->as = ABYTE; + p->from.type = D_CONST; + p->from.offset = v&0xff; + return p; +} + +int +relinv(int a) +{ + + switch(a) { + case AJEQ: return AJNE; + case AJNE: return AJEQ; + case AJLE: return AJGT; + case AJLS: return AJHI; + case AJLT: return AJGE; + case AJMI: return AJPL; + case AJGE: return AJLT; + case AJPL: return AJMI; + case AJGT: return AJLE; + case AJHI: return AJLS; + case AJCS: return AJCC; + case AJCC: return AJCS; + case AJPS: return AJPC; + case AJPC: return AJPS; + case AJOS: return AJOC; + case AJOC: return AJOS; + } + diag("unknown relation: %s in %s", anames[a], TNAME); + errorexit(); + return a; +} + +void +patch(void) +{ + int32 c; + Prog *p, *q; + Sym *s; + int32 vexit; + + if(debug['v']) + Bprint(&bso, "%5.2f mkfwd\n", cputime()); + Bflush(&bso); + mkfwd(); + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + + s = lookup("exit", 0); + vexit = s->value; + for(cursym = textp; cursym != nil; cursym = cursym->next) + for(p = cursym->text; p != P; p = p->link) { + if(HEADTYPE == Hwindows) { + // Windows + // Convert + // op n(GS), reg + // to + // MOVL 0x58(GS), reg + // op n(reg), reg + // The purpose of this patch is to fix some accesses + // to extern register variables (TLS) on Windows, as + // a different method is used to access them. + if(p->from.type == D_INDIR+D_GS + && p->to.type >= D_AX && p->to.type <= D_DI + && p->from.offset <= 8) { + q = appendp(p); + q->from = p->from; + q->from.type = D_INDIR + p->to.type; + q->to = p->to; + q->as = p->as; + p->as = AMOVQ; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0x58; + } + } + if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd + || HEADTYPE == Hopenbsd) { + // ELF uses FS instead of GS. + if(p->from.type == D_INDIR+D_GS) + p->from.type = D_INDIR+D_FS; + if(p->to.type == D_INDIR+D_GS) + p->to.type = D_INDIR+D_FS; + } + if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) { + s = p->to.sym; + if(s) { + if(debug['c']) + Bprint(&bso, "%s calls %s\n", TNAME, s->name); + if((s->type&~SSUB) != STEXT) { + /* diag prints TNAME first */ + diag("undefined: %s", s->name); + s->type = STEXT; + s->value = vexit; + continue; // avoid more error messages + } + if(s->text == nil) + continue; + p->to.type = D_BRANCH; + p->to.offset = s->text->pc; + p->pcond = s->text; + continue; + } + } + if(p->to.type != D_BRANCH) + continue; + c = p->to.offset; + for(q = cursym->text; q != P;) { + if(c == q->pc) + break; + if(q->forwd != P && c >= q->forwd->pc) + q = q->forwd; + else + q = q->link; + } + if(q == P) { + diag("branch out of range in %s (%#ux)\n%P [%s]", + TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>"); + p->to.type = D_NONE; + } + p->pcond = q; + } + + for(cursym = textp; cursym != nil; cursym = cursym->next) + for(p = cursym->text; p != P; p = p->link) { + p->mark = 0; /* initialization for follow */ + if(p->pcond != P) { + p->pcond = brloop(p->pcond); + if(p->pcond != P) + if(p->to.type == D_BRANCH) + p->to.offset = p->pcond->pc; + } + } +} + +Prog* +brloop(Prog *p) +{ + int c; + Prog *q; + + c = 0; + for(q = p; q != P; q = q->pcond) { + if(q->as != AJMP) + break; + c++; + if(c >= 5000) + return P; + } + return q; +} + +static char* +morename[] = +{ + "runtime.morestack00", + "runtime.morestack10", + "runtime.morestack01", + "runtime.morestack11", + + "runtime.morestack8", + "runtime.morestack16", + "runtime.morestack24", + "runtime.morestack32", + "runtime.morestack40", + "runtime.morestack48", +}; +Prog* pmorestack[nelem(morename)]; +Sym* symmorestack[nelem(morename)]; + +void +dostkoff(void) +{ + Prog *p, *q, *q1; + int32 autoffset, deltasp; + int a, pcsize; + uint32 moreconst1, moreconst2, i; + + for(i=0; i<nelem(morename); i++) { + symmorestack[i] = lookup(morename[i], 0); + if(symmorestack[i]->type != STEXT) + diag("morestack trampoline not defined - %s", morename[i]); + pmorestack[i] = symmorestack[i]->text; + } + + for(cursym = textp; cursym != nil; cursym = cursym->next) { + if(cursym->text == nil || cursym->text->link == nil) + continue; + + p = cursym->text; + parsetextconst(p->to.offset); + autoffset = textstksiz; + if(autoffset < 0) + autoffset = 0; + + q = P; + if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) + diag("nosplit func likely to overflow stack"); + + if(!(p->from.scale & NOSPLIT)) { + p = appendp(p); // load g into CX + p->as = AMOVQ; + if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd + || HEADTYPE == Hopenbsd) // ELF uses FS + p->from.type = D_INDIR+D_FS; + else + p->from.type = D_INDIR+D_GS; + p->from.offset = tlsoffset+0; + p->to.type = D_CX; + if(HEADTYPE == Hwindows) { + // movq %gs:0x58, %rcx + // movq (%rcx), %rcx + p->as = AMOVQ; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0x58; + p->to.type = D_CX; + + + p = appendp(p); + p->as = AMOVQ; + p->from.type = D_INDIR+D_CX; + p->from.offset = 0; + p->to.type = D_CX; + } + + if(debug['K']) { + // 6l -K means check not only for stack + // overflow but stack underflow. + // On underflow, INT 3 (breakpoint). + // Underflow itself is rare but this also + // catches out-of-sync stack guard info + + p = appendp(p); + p->as = ACMPQ; + p->from.type = D_INDIR+D_CX; + p->from.offset = 8; + p->to.type = D_SP; + + p = appendp(p); + p->as = AJHI; + p->to.type = D_BRANCH; + p->to.offset = 4; + q1 = p; + + p = appendp(p); + p->as = AINT; + p->from.type = D_CONST; + p->from.offset = 3; + + p = appendp(p); + p->as = ANOP; + q1->pcond = p; + } + + if(autoffset < StackBig) { // do we need to call morestack? + if(autoffset <= StackSmall) { + // small stack + p = appendp(p); + p->as = ACMPQ; + p->from.type = D_SP; + p->to.type = D_INDIR+D_CX; + } else { + // large stack + p = appendp(p); + p->as = ALEAQ; + p->from.type = D_INDIR+D_SP; + p->from.offset = -(autoffset-StackSmall); + p->to.type = D_AX; + + p = appendp(p); + p->as = ACMPQ; + p->from.type = D_AX; + p->to.type = D_INDIR+D_CX; + } + + // common + p = appendp(p); + p->as = AJHI; + p->to.type = D_BRANCH; + p->to.offset = 4; + q = p; + } + + /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */ + moreconst1 = 0; + if(autoffset+160+textarg > 4096) + moreconst1 = (autoffset+160) & ~7LL; + moreconst2 = textarg; + + // 4 varieties varieties (const1==0 cross const2==0) + // and 6 subvarieties of (const1==0 and const2!=0) + p = appendp(p); + if(moreconst1 == 0 && moreconst2 == 0) { + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = pmorestack[0]; + p->to.sym = symmorestack[0]; + } else + if(moreconst1 != 0 && moreconst2 == 0) { + p->as = AMOVL; + p->from.type = D_CONST; + p->from.offset = moreconst1; + p->to.type = D_AX; + + p = appendp(p); + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = pmorestack[1]; + p->to.sym = symmorestack[1]; + } else + if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { + i = moreconst2/8 + 3; + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = pmorestack[i]; + p->to.sym = symmorestack[i]; + } else + if(moreconst1 == 0 && moreconst2 != 0) { + p->as = AMOVL; + p->from.type = D_CONST; + p->from.offset = moreconst2; + p->to.type = D_AX; + + p = appendp(p); + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = pmorestack[2]; + p->to.sym = symmorestack[2]; + } else { + p->as = AMOVQ; + p->from.type = D_CONST; + p->from.offset = (uint64)moreconst2 << 32; + p->from.offset |= moreconst1; + p->to.type = D_AX; + + p = appendp(p); + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = pmorestack[3]; + p->to.sym = symmorestack[3]; + } + } + + if(q != P) + q->pcond = p->link; + + if(autoffset) { + p = appendp(p); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = autoffset; + p->spadj = autoffset; + if(q != P) + q->pcond = p; + } + deltasp = autoffset; + + if(debug['K'] > 1 && autoffset) { + // 6l -KK means double-check for stack overflow + // even after calling morestack and even if the + // function is marked as nosplit. + p = appendp(p); + p->as = AMOVQ; + p->from.type = D_INDIR+D_CX; + p->from.offset = 0; + p->to.type = D_BX; + + p = appendp(p); + p->as = ASUBQ; + p->from.type = D_CONST; + p->from.offset = StackSmall+32; + p->to.type = D_BX; + + p = appendp(p); + p->as = ACMPQ; + p->from.type = D_SP; + p->to.type = D_BX; + + p = appendp(p); + p->as = AJHI; + p->to.type = D_BRANCH; + q1 = p; + + p = appendp(p); + p->as = AINT; + p->from.type = D_CONST; + p->from.offset = 3; + + p = appendp(p); + p->as = ANOP; + q1->pcond = p; + } + + for(; p != P; p = p->link) { + pcsize = p->mode/8; + a = p->from.type; + if(a == D_AUTO) + p->from.offset += deltasp; + if(a == D_PARAM) + p->from.offset += deltasp + pcsize; + a = p->to.type; + if(a == D_AUTO) + p->to.offset += deltasp; + if(a == D_PARAM) + p->to.offset += deltasp + pcsize; + + switch(p->as) { + default: + continue; + case APUSHL: + case APUSHFL: + deltasp += 4; + p->spadj = 4; + continue; + case APUSHQ: + case APUSHFQ: + deltasp += 8; + p->spadj = 8; + continue; + case APUSHW: + case APUSHFW: + deltasp += 2; + p->spadj = 2; + continue; + case APOPL: + case APOPFL: + deltasp -= 4; + p->spadj = -4; + continue; + case APOPQ: + case APOPFQ: + deltasp -= 8; + p->spadj = -8; + continue; + case APOPW: + case APOPFW: + deltasp -= 2; + p->spadj = -2; + continue; + case ARET: + break; + } + + if(autoffset != deltasp) + diag("unbalanced PUSH/POP"); + + if(autoffset) { + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = -autoffset; + p->spadj = -autoffset; + p = appendp(p); + p->as = ARET; + // If there are instructions following + // this ARET, they come from a branch + // with the same stackframe, so undo + // the cleanup. + p->spadj = +autoffset; + } + } + } +} + +vlong +atolwhex(char *s) +{ + vlong n; + int f; + + n = 0; + f = 0; + while(*s == ' ' || *s == '\t') + s++; + if(*s == '-' || *s == '+') { + if(*s++ == '-') + f = 1; + while(*s == ' ' || *s == '\t') + s++; + } + if(s[0]=='0' && s[1]){ + if(s[1]=='x' || s[1]=='X'){ + s += 2; + for(;;){ + if(*s >= '0' && *s <= '9') + n = n*16 + *s++ - '0'; + else if(*s >= 'a' && *s <= 'f') + n = n*16 + *s++ - 'a' + 10; + else if(*s >= 'A' && *s <= 'F') + n = n*16 + *s++ - 'A' + 10; + else + break; + } + } else + while(*s >= '0' && *s <= '7') + n = n*8 + *s++ - '0'; + } else + while(*s >= '0' && *s <= '9') + n = n*10 + *s++ - '0'; + if(f) + n = -n; + return n; +} diff --git a/src/cmd/6l/prof.c b/src/cmd/6l/prof.c new file mode 100644 index 000000000..862ce080c --- /dev/null +++ b/src/cmd/6l/prof.c @@ -0,0 +1,171 @@ +// Inferno utils/6l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Profiling. + +#include "l.h" +#include "../ld/lib.h" + +void +doprof1(void) +{ +#ifdef NOTDEF + Sym *s; + int32 n; + Prog *p, *q; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 1\n", cputime()); + Bflush(&bso); + s = lookup("__mcount", 0); + n = 1; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + p = cursym->text; + q = prg(); + q->line = p->line; + q->link = datap; + datap = q; + q->as = ADATA; + q->from.type = D_EXTERN; + q->from.offset = n*4; + q->from.sym = s; + q->from.scale = 4; + q->to = p->from; + q->to.type = D_CONST; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AADDL; + p->from.type = D_CONST; + p->from.offset = 1; + p->to.type = D_EXTERN; + p->to.sym = s; + p->to.offset = n*4 + 4; + + n += 2; + } + q = prg(); + q->line = 0; + q->link = datap; + datap = q; + + q->as = ADATA; + q->from.type = D_EXTERN; + q->from.sym = s; + q->from.scale = 4; + q->to.type = D_CONST; + q->to.offset = n; + + s->type = SBSS; + s->size = n*4; +#endif +} + +void +doprof2(void) +{ + Sym *s2, *s4; + Prog *p, *q, *ps2, *ps4; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 2\n", cputime()); + Bflush(&bso); + + s2 = lookup("_profin", 0); + s4 = lookup("_profout", 0); + if(s2->type != STEXT || s4->type != STEXT) { + diag("_profin/_profout not defined"); + return; + } + + ps2 = P; + ps4 = P; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + p = cursym->text; + if(p->from.sym == s2) { + p->from.scale = 1; + ps2 = p; + } + if(p->from.sym == s4) { + p->from.scale = 1; + ps4 = p; + } + } + for(cursym = textp; cursym != nil; cursym = cursym->next) { + p = cursym->text; + + if(p->from.scale & NOPROF) /* dont profile */ + continue; + + /* + * JMPL profin + */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = ps2; + p->to.sym = s2; + + for(; p; p=p->link) { + if(p->as == ARET) { + /* + * RET + */ + q = prg(); + q->as = ARET; + q->from = p->from; + q->to = p->to; + q->link = p->link; + p->link = q; + + /* + * JAL profout + */ + p->as = ACALL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->pcond = ps4; + p->to.sym = s4; + + p = q; + } + } + } +} diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c new file mode 100644 index 000000000..5d13ad44b --- /dev/null +++ b/src/cmd/6l/span.c @@ -0,0 +1,1747 @@ +// Inferno utils/6l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Instruction layout. + +#include "l.h" +#include "../ld/lib.h" + +static int rexflag; +static int asmode; +static vlong vaddr(Adr*, Reloc*); + +void +span1(Sym *s) +{ + Prog *p, *q; + int32 c, v, loop; + uchar *bp; + int n, m, i; + + cursym = s; + + if(s->p != nil) + return; + + for(p = s->text; p != P; p = p->link) { + p->back = 2; // use short branches first time through + if((q = p->pcond) != P && (q->back & 2)) + p->back |= 1; // backward jump + + if(p->as == AADJSP) { + p->to.type = D_SP; + v = -p->from.offset; + p->from.offset = v; + p->as = p->mode != 64? AADDL: AADDQ; + if(v < 0) { + p->as = p->mode != 64? ASUBL: ASUBQ; + v = -v; + p->from.offset = v; + } + if(v == 0) + p->as = ANOP; + } + } + + n = 0; + do { + loop = 0; + memset(s->r, 0, s->nr*sizeof s->r[0]); + s->nr = 0; + s->np = 0; + c = 0; + for(p = s->text; p != P; p = p->link) { + p->pc = c; + + // process forward jumps to p + for(q = p->comefrom; q != P; q = q->forwd) { + v = p->pc - (q->pc + q->mark); + if(q->back & 2) { // short + if(v > 127) { + loop++; + q->back ^= 2; + } + s->p[q->pc+1] = v; + } else { + bp = s->p + q->pc + q->mark - 4; + *bp++ = v; + *bp++ = v>>8; + *bp++ = v>>16; + *bp = v>>24; + } + } + p->comefrom = P; + + asmins(p); + p->pc = c; + m = andptr-and; + symgrow(s, p->pc+m); + memmove(s->p+p->pc, and, m); + p->mark = m; + c += m; + } + if(++n > 20) { + diag("span must be looping"); + errorexit(); + } + } while(loop); + s->size = c; + + if(debug['a'] > 1) { + print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0); + for(i=0; i<s->np; i++) { + print(" %.2ux", s->p[i]); + if(i%16 == 15) + print("\n %.6ux", i+1); + } + if(i%16) + print("\n"); + + for(i=0; i<s->nr; i++) { + Reloc *r; + + r = &s->r[i]; + print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add); + } + } +} + +void +span(void) +{ + Prog *p, *q; + int32 v; + int n; + + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + + // NOTE(rsc): If we get rid of the globals we should + // be able to parallelize these iterations. + for(cursym = textp; cursym != nil; cursym = cursym->next) { + if(cursym->p != nil) + continue; + // TODO: move into span1 + for(p = cursym->text; p != P; p = p->link) { + n = 0; + if(p->to.type == D_BRANCH) + if(p->pcond == P) + p->pcond = p; + if((q = p->pcond) != P) + if(q->back != 2) + n = 1; + p->back = n; + if(p->as == AADJSP) { + p->to.type = D_SP; + v = -p->from.offset; + p->from.offset = v; + p->as = p->mode != 64? AADDL: AADDQ; + if(v < 0) { + p->as = p->mode != 64? ASUBL: ASUBQ; + v = -v; + p->from.offset = v; + } + if(v == 0) + p->as = ANOP; + } + } + span1(cursym); + } +} + +void +xdefine(char *p, int t, vlong v) +{ + Sym *s; + + s = lookup(p, 0); + s->type = t; + s->value = v; + s->reachable = 1; + s->special = 1; +} + +void +instinit(void) +{ + int c, i; + + for(i=1; optab[i].as; i++) { + c = optab[i].as; + if(opindex[c] != nil) { + diag("phase error in optab: %d (%A)", i, c); + errorexit(); + } + opindex[c] = &optab[i]; + } + + for(i=0; i<Ymax; i++) + ycover[i*Ymax + i] = 1; + + ycover[Yi0*Ymax + Yi8] = 1; + ycover[Yi1*Ymax + Yi8] = 1; + + ycover[Yi0*Ymax + Ys32] = 1; + ycover[Yi1*Ymax + Ys32] = 1; + ycover[Yi8*Ymax + Ys32] = 1; + + ycover[Yi0*Ymax + Yi32] = 1; + ycover[Yi1*Ymax + Yi32] = 1; + ycover[Yi8*Ymax + Yi32] = 1; + ycover[Ys32*Ymax + Yi32] = 1; + + ycover[Yi0*Ymax + Yi64] = 1; + ycover[Yi1*Ymax + Yi64] = 1; + ycover[Yi8*Ymax + Yi64] = 1; + ycover[Ys32*Ymax + Yi64] = 1; + ycover[Yi32*Ymax + Yi64] = 1; + + ycover[Yal*Ymax + Yrb] = 1; + ycover[Ycl*Ymax + Yrb] = 1; + ycover[Yax*Ymax + Yrb] = 1; + ycover[Ycx*Ymax + Yrb] = 1; + ycover[Yrx*Ymax + Yrb] = 1; + ycover[Yrl*Ymax + Yrb] = 1; + + ycover[Ycl*Ymax + Ycx] = 1; + + ycover[Yax*Ymax + Yrx] = 1; + ycover[Ycx*Ymax + Yrx] = 1; + + ycover[Yax*Ymax + Yrl] = 1; + ycover[Ycx*Ymax + Yrl] = 1; + ycover[Yrx*Ymax + Yrl] = 1; + + ycover[Yf0*Ymax + Yrf] = 1; + + ycover[Yal*Ymax + Ymb] = 1; + ycover[Ycl*Ymax + Ymb] = 1; + ycover[Yax*Ymax + Ymb] = 1; + ycover[Ycx*Ymax + Ymb] = 1; + ycover[Yrx*Ymax + Ymb] = 1; + ycover[Yrb*Ymax + Ymb] = 1; + ycover[Yrl*Ymax + Ymb] = 1; + ycover[Ym*Ymax + Ymb] = 1; + + ycover[Yax*Ymax + Yml] = 1; + ycover[Ycx*Ymax + Yml] = 1; + ycover[Yrx*Ymax + Yml] = 1; + ycover[Yrl*Ymax + Yml] = 1; + ycover[Ym*Ymax + Yml] = 1; + + ycover[Yax*Ymax + Ymm] = 1; + ycover[Ycx*Ymax + Ymm] = 1; + ycover[Yrx*Ymax + Ymm] = 1; + ycover[Yrl*Ymax + Ymm] = 1; + ycover[Ym*Ymax + Ymm] = 1; + ycover[Ymr*Ymax + Ymm] = 1; + + ycover[Yax*Ymax + Yxm] = 1; + ycover[Ycx*Ymax + Yxm] = 1; + ycover[Yrx*Ymax + Yxm] = 1; + ycover[Yrl*Ymax + Yxm] = 1; + ycover[Ym*Ymax + Yxm] = 1; + ycover[Yxr*Ymax + Yxm] = 1; + + for(i=0; i<D_NONE; i++) { + reg[i] = -1; + if(i >= D_AL && i <= D_R15B) { + reg[i] = (i-D_AL) & 7; + if(i >= D_SPB && i <= D_DIB) + regrex[i] = 0x40; + if(i >= D_R8B && i <= D_R15B) + regrex[i] = Rxr | Rxx | Rxb; + } + if(i >= D_AH && i<= D_BH) + reg[i] = 4 + ((i-D_AH) & 7); + if(i >= D_AX && i <= D_R15) { + reg[i] = (i-D_AX) & 7; + if(i >= D_R8) + regrex[i] = Rxr | Rxx | Rxb; + } + if(i >= D_F0 && i <= D_F0+7) + reg[i] = (i-D_F0) & 7; + if(i >= D_M0 && i <= D_M0+7) + reg[i] = (i-D_M0) & 7; + if(i >= D_X0 && i <= D_X0+15) { + reg[i] = (i-D_X0) & 7; + if(i >= D_X0+8) + regrex[i] = Rxr | Rxx | Rxb; + } + if(i >= D_CR+8 && i <= D_CR+15) + regrex[i] = Rxr; + } +} + +int +prefixof(Adr *a) +{ + switch(a->type) { + case D_INDIR+D_CS: + return 0x2e; + case D_INDIR+D_DS: + return 0x3e; + case D_INDIR+D_ES: + return 0x26; + case D_INDIR+D_FS: + return 0x64; + case D_INDIR+D_GS: + return 0x65; + } + return 0; +} + +int +oclass(Adr *a) +{ + vlong v; + int32 l; + + if(a->type >= D_INDIR || a->index != D_NONE) { + if(a->index != D_NONE && a->scale == 0) { + if(a->type == D_ADDR) { + switch(a->index) { + case D_EXTERN: + case D_STATIC: + return Yi32; /* TO DO: Yi64 */ + case D_AUTO: + case D_PARAM: + return Yiauto; + } + return Yxxx; + } + return Ycol; + } + return Ym; + } + switch(a->type) + { + case D_AL: + return Yal; + + case D_AX: + return Yax; + +/* + case D_SPB: +*/ + case D_BPB: + case D_SIB: + case D_DIB: + case D_R8B: + case D_R9B: + case D_R10B: + case D_R11B: + case D_R12B: + case D_R13B: + case D_R14B: + case D_R15B: + if(asmode != 64) + return Yxxx; + case D_DL: + case D_BL: + case D_AH: + case D_CH: + case D_DH: + case D_BH: + return Yrb; + + case D_CL: + return Ycl; + + case D_CX: + return Ycx; + + case D_DX: + case D_BX: + return Yrx; + + case D_R8: /* not really Yrl */ + case D_R9: + case D_R10: + case D_R11: + case D_R12: + case D_R13: + case D_R14: + case D_R15: + if(asmode != 64) + return Yxxx; + case D_SP: + case D_BP: + case D_SI: + case D_DI: + return Yrl; + + case D_F0+0: + return Yf0; + + case D_F0+1: + case D_F0+2: + case D_F0+3: + case D_F0+4: + case D_F0+5: + case D_F0+6: + case D_F0+7: + return Yrf; + + case D_M0+0: + case D_M0+1: + case D_M0+2: + case D_M0+3: + case D_M0+4: + case D_M0+5: + case D_M0+6: + case D_M0+7: + return Ymr; + + case D_X0+0: + case D_X0+1: + case D_X0+2: + case D_X0+3: + case D_X0+4: + case D_X0+5: + case D_X0+6: + case D_X0+7: + case D_X0+8: + case D_X0+9: + case D_X0+10: + case D_X0+11: + case D_X0+12: + case D_X0+13: + case D_X0+14: + case D_X0+15: + return Yxr; + + case D_NONE: + return Ynone; + + case D_CS: return Ycs; + case D_SS: return Yss; + case D_DS: return Yds; + case D_ES: return Yes; + case D_FS: return Yfs; + case D_GS: return Ygs; + + case D_GDTR: return Ygdtr; + case D_IDTR: return Yidtr; + case D_LDTR: return Yldtr; + case D_MSW: return Ymsw; + case D_TASK: return Ytask; + + case D_CR+0: return Ycr0; + case D_CR+1: return Ycr1; + case D_CR+2: return Ycr2; + case D_CR+3: return Ycr3; + case D_CR+4: return Ycr4; + case D_CR+5: return Ycr5; + case D_CR+6: return Ycr6; + case D_CR+7: return Ycr7; + case D_CR+8: return Ycr8; + + case D_DR+0: return Ydr0; + case D_DR+1: return Ydr1; + case D_DR+2: return Ydr2; + case D_DR+3: return Ydr3; + case D_DR+4: return Ydr4; + case D_DR+5: return Ydr5; + case D_DR+6: return Ydr6; + case D_DR+7: return Ydr7; + + case D_TR+0: return Ytr0; + case D_TR+1: return Ytr1; + case D_TR+2: return Ytr2; + case D_TR+3: return Ytr3; + case D_TR+4: return Ytr4; + case D_TR+5: return Ytr5; + case D_TR+6: return Ytr6; + case D_TR+7: return Ytr7; + + case D_EXTERN: + case D_STATIC: + case D_AUTO: + case D_PARAM: + return Ym; + + case D_CONST: + case D_ADDR: + if(a->sym == S) { + v = a->offset; + if(v == 0) + return Yi0; + if(v == 1) + return Yi1; + if(v >= -128 && v <= 127) + return Yi8; + l = v; + if((vlong)l == v) + return Ys32; /* can sign extend */ + if((v>>32) == 0) + return Yi32; /* unsigned */ + return Yi64; + } + return Yi32; /* TO DO: D_ADDR as Yi64 */ + + case D_BRANCH: + return Ybr; + } + return Yxxx; +} + +void +asmidx(int scale, int index, int base) +{ + int i; + + switch(index) { + default: + goto bad; + + case D_NONE: + i = 4 << 3; + goto bas; + + case D_R8: + case D_R9: + case D_R10: + case D_R11: + case D_R12: + case D_R13: + case D_R14: + case D_R15: + if(asmode != 64) + goto bad; + case D_AX: + case D_CX: + case D_DX: + case D_BX: + case D_BP: + case D_SI: + case D_DI: + i = reg[index] << 3; + break; + } + switch(scale) { + default: + goto bad; + case 1: + break; + case 2: + i |= (1<<6); + break; + case 4: + i |= (2<<6); + break; + case 8: + i |= (3<<6); + break; + } +bas: + switch(base) { + default: + goto bad; + case D_NONE: /* must be mod=00 */ + i |= 5; + break; + case D_R8: + case D_R9: + case D_R10: + case D_R11: + case D_R12: + case D_R13: + case D_R14: + case D_R15: + if(asmode != 64) + goto bad; + case D_AX: + case D_CX: + case D_DX: + case D_BX: + case D_SP: + case D_BP: + case D_SI: + case D_DI: + i |= reg[base]; + break; + } + *andptr++ = i; + return; +bad: + diag("asmidx: bad address %d/%d/%d", scale, index, base); + *andptr++ = 0; + return; +} + +static void +put4(int32 v) +{ + andptr[0] = v; + andptr[1] = v>>8; + andptr[2] = v>>16; + andptr[3] = v>>24; + andptr += 4; +} + +static void +relput4(Prog *p, Adr *a) +{ + vlong v; + Reloc rel, *r; + + v = vaddr(a, &rel); + if(rel.siz != 0) { + if(rel.siz != 4) + diag("bad reloc"); + r = addrel(cursym); + *r = rel; + r->off = p->pc + andptr - and; + } + put4(v); +} + +static void +put8(vlong v) +{ + andptr[0] = v; + andptr[1] = v>>8; + andptr[2] = v>>16; + andptr[3] = v>>24; + andptr[4] = v>>32; + andptr[5] = v>>40; + andptr[6] = v>>48; + andptr[7] = v>>56; + andptr += 8; +} + +/* +static void +relput8(Prog *p, Adr *a) +{ + vlong v; + Reloc rel, *r; + + v = vaddr(a, &rel); + if(rel.siz != 0) { + r = addrel(cursym); + *r = rel; + r->siz = 8; + r->off = p->pc + andptr - and; + } + put8(v); +} +*/ + +vlong +symaddr(Sym *s) +{ + if(!s->reachable) + diag("unreachable symbol in symaddr - %s", s->name); + return s->value; +} + +static vlong +vaddr(Adr *a, Reloc *r) +{ + int t; + vlong v; + Sym *s; + + if(r != nil) + memset(r, 0, sizeof *r); + + t = a->type; + v = a->offset; + if(t == D_ADDR) + t = a->index; + switch(t) { + case D_STATIC: + case D_EXTERN: + s = a->sym; + if(!s->reachable) + diag("unreachable symbol in vaddr - %s", s->name); + if(r == nil) { + diag("need reloc for %D", a); + errorexit(); + } + r->type = D_ADDR; + r->siz = 4; // TODO: 8 for external symbols + r->off = -1; // caller must fill in + r->sym = s; + r->add = v; + v = 0; + } + return v; +} + +static void +asmandsz(Adr *a, int r, int rex, int m64) +{ + int32 v; + int t, scale; + Reloc rel; + + USED(m64); + rex &= (0x40 | Rxr); + v = a->offset; + t = a->type; + rel.siz = 0; + if(a->index != D_NONE) { + if(t < D_INDIR) { + switch(t) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + t = D_NONE; + v = vaddr(a, &rel); + break; + case D_AUTO: + case D_PARAM: + t = D_SP; + break; + } + } else + t -= D_INDIR; + rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex; + if(t == D_NONE) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a->scale, a->index, t); + goto putrelv; + } + if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a->scale, a->index, t); + return; + } + if(v >= -128 && v < 128 && rel.siz == 0) { + *andptr++ = (1 << 6) | (4 << 0) | (r << 3); + asmidx(a->scale, a->index, t); + *andptr++ = v; + return; + } + *andptr++ = (2 << 6) | (4 << 0) | (r << 3); + asmidx(a->scale, a->index, t); + goto putrelv; + } + if(t >= D_AL && t <= D_X0+15) { + if(v) + goto bad; + *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); + rexflag |= (regrex[t] & (0x40 | Rxb)) | rex; + return; + } + + scale = a->scale; + if(t < D_INDIR) { + switch(a->type) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + t = D_NONE; + v = vaddr(a, &rel); + break; + case D_AUTO: + case D_PARAM: + t = D_SP; + break; + } + scale = 1; + } else + t -= D_INDIR; + + rexflag |= (regrex[t] & Rxb) | rex; + if(t == D_NONE || (D_CS <= t && t <= D_GS)) { + if(asmode != 64){ + *andptr++ = (0 << 6) | (5 << 0) | (r << 3); + goto putrelv; + } + /* temporary */ + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */ + *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */ + goto putrelv; + } + if(t == D_SP || t == D_R12) { + if(v == 0) { + *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); + asmidx(scale, D_NONE, t); + return; + } + if(v >= -128 && v < 128) { + *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3); + asmidx(scale, D_NONE, t); + *andptr++ = v; + return; + } + *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + asmidx(scale, D_NONE, t); + goto putrelv; + } + if(t >= D_AX && t <= D_R15) { + if(v == 0 && t != D_BP && t != D_R13) { + *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); + return; + } + if(v >= -128 && v < 128) { + andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3); + andptr[1] = v; + andptr += 2; + return; + } + *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + goto putrelv; + } + goto bad; + +putrelv: + if(rel.siz != 0) { + Reloc *r; + + if(rel.siz != 4) { + diag("bad rel"); + goto bad; + } + r = addrel(cursym); + *r = rel; + r->off = curp->pc + andptr - and; + } + put4(v); + return; + +bad: + diag("asmand: bad address %D", a); + return; +} + +void +asmand(Adr *a, Adr *ra) +{ + asmandsz(a, reg[ra->type], regrex[ra->type], 0); +} + +void +asmando(Adr *a, int o) +{ + asmandsz(a, o, 0, 0); +} + +static void +bytereg(Adr *a, char *t) +{ + if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) { + a->type = D_AL + (a->type-D_AX); + *t = 0; + } +} + +#define E 0xff +Movtab ymovtab[] = +{ +/* push */ + {APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0}, + {APUSHL, Yss, Ynone, 0, 0x16,E,0,0}, + {APUSHL, Yds, Ynone, 0, 0x1e,E,0,0}, + {APUSHL, Yes, Ynone, 0, 0x06,E,0,0}, + {APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0}, + {APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0}, + {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0}, + {APUSHQ, Ygs, Ynone, 0, 0x0f,0xa8,E,0}, + + {APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0}, + {APUSHW, Yss, Ynone, 0, Pe,0x16,E,0}, + {APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0}, + {APUSHW, Yes, Ynone, 0, Pe,0x06,E,0}, + {APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E}, + {APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E}, + +/* pop */ + {APOPL, Ynone, Yds, 0, 0x1f,E,0,0}, + {APOPL, Ynone, Yes, 0, 0x07,E,0,0}, + {APOPL, Ynone, Yss, 0, 0x17,E,0,0}, + {APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0}, + {APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0}, + {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0}, + {APOPQ, Ynone, Ygs, 0, 0x0f,0xa9,E,0}, + + {APOPW, Ynone, Yds, 0, Pe,0x1f,E,0}, + {APOPW, Ynone, Yes, 0, Pe,0x07,E,0}, + {APOPW, Ynone, Yss, 0, Pe,0x17,E,0}, + {APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E}, + {APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E}, + +/* mov seg */ + {AMOVW, Yes, Yml, 1, 0x8c,0,0,0}, + {AMOVW, Ycs, Yml, 1, 0x8c,1,0,0}, + {AMOVW, Yss, Yml, 1, 0x8c,2,0,0}, + {AMOVW, Yds, Yml, 1, 0x8c,3,0,0}, + {AMOVW, Yfs, Yml, 1, 0x8c,4,0,0}, + {AMOVW, Ygs, Yml, 1, 0x8c,5,0,0}, + + {AMOVW, Yml, Yes, 2, 0x8e,0,0,0}, + {AMOVW, Yml, Ycs, 2, 0x8e,1,0,0}, + {AMOVW, Yml, Yss, 2, 0x8e,2,0,0}, + {AMOVW, Yml, Yds, 2, 0x8e,3,0,0}, + {AMOVW, Yml, Yfs, 2, 0x8e,4,0,0}, + {AMOVW, Yml, Ygs, 2, 0x8e,5,0,0}, + +/* mov cr */ + {AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0}, + {AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0}, + {AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0}, + {AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0}, + {AMOVL, Ycr8, Yml, 3, 0x0f,0x20,8,0}, + {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0}, + {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0}, + {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0}, + {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0}, + {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,0}, + + {AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0}, + {AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0}, + {AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0}, + {AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0}, + {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0}, + {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0}, + {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0}, + {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0}, + {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0}, + {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,0}, + +/* mov dr */ + {AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0}, + {AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0}, + {AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0}, + {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0}, + {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0}, + {AMOVQ, Ydr7, Yml, 3, 0x0f,0x21,7,0}, + + {AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0}, + {AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0}, + {AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0}, + {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0}, + {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0}, + {AMOVQ, Yml, Ydr7, 4, 0x0f,0x23,7,0}, + +/* mov tr */ + {AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0}, + {AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0}, + + {AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E}, + {AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E}, + +/* lgdt, sgdt, lidt, sidt */ + {AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0}, + {AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0}, + {AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0}, + {AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0}, + {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0}, + {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0}, + {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0}, + {AMOVQ, Yidtr, Ym, 3, 0x0f,0x01,1,0}, + +/* lldt, sldt */ + {AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0}, + {AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0}, + +/* lmsw, smsw */ + {AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0}, + {AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0}, + +/* ltr, str */ + {AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0}, + {AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0}, + +/* load full pointer */ + {AMOVL, Yml, Ycol, 5, 0,0,0,0}, + {AMOVW, Yml, Ycol, 5, Pe,0,0,0}, + +/* double shift */ + {ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0}, + {ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0}, + {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0}, + {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0}, + {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0}, + {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,0}, + 0 +}; + +int +isax(Adr *a) +{ + + switch(a->type) { + case D_AX: + case D_AL: + case D_AH: + case D_INDIR+D_AX: + return 1; + } + if(a->index == D_AX) + return 1; + return 0; +} + +void +subreg(Prog *p, int from, int to) +{ + + if(debug['Q']) + print("\n%P s/%R/%R/\n", p, from, to); + + if(p->from.type == from) + p->from.type = to; + if(p->to.type == from) + p->to.type = to; + + if(p->from.index == from) + p->from.index = to; + if(p->to.index == from) + p->to.index = to; + + from += D_INDIR; + if(p->from.type == from) + p->from.type = to+D_INDIR; + if(p->to.type == from) + p->to.type = to+D_INDIR; + + if(debug['Q']) + print("%P\n", p); +} + +static int +mediaop(Optab *o, int op, int osize, int z) +{ + switch(op){ + case Pm: + case Pe: + case Pf2: + case Pf3: + if(osize != 1){ + if(op != Pm) + *andptr++ = op; + *andptr++ = Pm; + op = o->op[++z]; + break; + } + default: + if(andptr == and || andptr[-1] != Pm) + *andptr++ = Pm; + break; + } + *andptr++ = op; + return z; +} + +void +doasm(Prog *p) +{ + Optab *o; + Prog *q, pp; + uchar *t; + Movtab *mo; + int z, op, ft, tt, xo, l, pre; + vlong v; + Reloc rel, *r; + Adr *a; + + curp = p; // TODO + + o = opindex[p->as]; + if(o == nil) { + diag("asmins: missing op %P", p); + return; + } + + pre = prefixof(&p->from); + if(pre) + *andptr++ = pre; + pre = prefixof(&p->to); + if(pre) + *andptr++ = pre; + + if(p->ft == 0) + p->ft = oclass(&p->from); + if(p->tt == 0) + p->tt = oclass(&p->to); + + ft = p->ft * Ymax; + tt = p->tt * Ymax; + + t = o->ytab; + if(t == 0) { + diag("asmins: noproto %P", p); + return; + } + xo = o->op[0] == 0x0f; + for(z=0; *t; z+=t[3]+xo,t+=4) + if(ycover[ft+t[0]]) + if(ycover[tt+t[1]]) + goto found; + goto domov; + +found: + switch(o->prefix) { + case Pq: /* 16 bit escape and opcode escape */ + *andptr++ = Pe; + *andptr++ = Pm; + break; + + case Pf2: /* xmm opcode escape */ + case Pf3: + *andptr++ = o->prefix; + *andptr++ = Pm; + break; + + case Pm: /* opcode escape */ + *andptr++ = Pm; + break; + + case Pe: /* 16 bit escape */ + *andptr++ = Pe; + break; + + case Pw: /* 64-bit escape */ + if(p->mode != 64) + diag("asmins: illegal 64: %P", p); + rexflag |= Pw; + break; + + case Pb: /* botch */ + bytereg(&p->from, &p->ft); + bytereg(&p->to, &p->tt); + break; + + case P32: /* 32 bit but illegal if 64-bit mode */ + if(p->mode == 64) + diag("asmins: illegal in 64-bit mode: %P", p); + break; + + case Py: /* 64-bit only, no prefix */ + if(p->mode != 64) + diag("asmins: illegal in %d-bit mode: %P", p->mode, p); + break; + } + + op = o->op[z]; + if(op == 0x0f) { + *andptr++ = op; + op = o->op[++z]; + } + switch(t[2]) { + default: + diag("asmins: unknown z %d %P", t[2], p); + return; + + case Zpseudo: + break; + + case Zlit: + for(; op = o->op[z]; z++) + *andptr++ = op; + break; + + case Zlitm_r: + for(; op = o->op[z]; z++) + *andptr++ = op; + asmand(&p->from, &p->to); + break; + + case Zmb_r: + bytereg(&p->from, &p->ft); + /* fall through */ + case Zm_r: + *andptr++ = op; + asmand(&p->from, &p->to); + break; + + case Zm_r_xm: + mediaop(o, op, t[3], z); + asmand(&p->from, &p->to); + break; + + case Zm_r_xm_nr: + rexflag = 0; + mediaop(o, op, t[3], z); + asmand(&p->from, &p->to); + break; + + case Zm_r_i_xm: + mediaop(o, op, t[3], z); + asmand(&p->from, &p->to); + *andptr++ = p->to.offset; + break; + + case Zm_r_3d: + *andptr++ = 0x0f; + *andptr++ = 0x0f; + asmand(&p->from, &p->to); + *andptr++ = op; + break; + + case Zibm_r: + *andptr++ = op; + asmand(&p->from, &p->to); + *andptr++ = p->to.offset; + break; + + case Zaut_r: + *andptr++ = 0x8d; /* leal */ + if(p->from.type != D_ADDR) + diag("asmins: Zaut sb type ADDR"); + p->from.type = p->from.index; + p->from.index = D_NONE; + asmand(&p->from, &p->to); + p->from.index = p->from.type; + p->from.type = D_ADDR; + break; + + case Zm_o: + *andptr++ = op; + asmando(&p->from, o->op[z+1]); + break; + + case Zr_m: + *andptr++ = op; + asmand(&p->to, &p->from); + break; + + case Zr_m_xm: + mediaop(o, op, t[3], z); + asmand(&p->to, &p->from); + break; + + case Zr_m_xm_nr: + rexflag = 0; + mediaop(o, op, t[3], z); + asmand(&p->to, &p->from); + break; + + case Zr_m_i_xm: + mediaop(o, op, t[3], z); + asmand(&p->to, &p->from); + *andptr++ = p->from.offset; + break; + + case Zo_m: + *andptr++ = op; + asmando(&p->to, o->op[z+1]); + break; + + case Zo_m64: + *andptr++ = op; + asmandsz(&p->to, o->op[z+1], 0, 1); + break; + + case Zm_ibo: + *andptr++ = op; + asmando(&p->from, o->op[z+1]); + *andptr++ = vaddr(&p->to, nil); + break; + + case Zibo_m: + *andptr++ = op; + asmando(&p->to, o->op[z+1]); + *andptr++ = vaddr(&p->from, nil); + break; + + case Zibo_m_xm: + z = mediaop(o, op, t[3], z); + asmando(&p->to, o->op[z+1]); + *andptr++ = vaddr(&p->from, nil); + break; + + case Z_ib: + case Zib_: + if(t[2] == Zib_) + a = &p->from; + else + a = &p->to; + *andptr++ = op; + *andptr++ = vaddr(a, nil); + break; + + case Zib_rp: + rexflag |= regrex[p->to.type] & (Rxb|0x40); + *andptr++ = op + reg[p->to.type]; + *andptr++ = vaddr(&p->from, nil); + break; + + case Zil_rp: + rexflag |= regrex[p->to.type] & Rxb; + *andptr++ = op + reg[p->to.type]; + if(o->prefix == Pe) { + v = vaddr(&p->from, nil); + *andptr++ = v; + *andptr++ = v>>8; + } + else + relput4(p, &p->from); + break; + + case Zo_iw: + *andptr++ = op; + if(p->from.type != D_NONE){ + v = vaddr(&p->from, nil); + *andptr++ = v; + *andptr++ = v>>8; + } + break; + + case Ziq_rp: + v = vaddr(&p->from, &rel); + l = v>>32; + if(l == 0 && rel.siz != 8){ + //p->mark |= 0100; + //print("zero: %llux %P\n", v, p); + rexflag &= ~(0x40|Rxw); + rexflag |= regrex[p->to.type] & Rxb; + *andptr++ = 0xb8 + reg[p->to.type]; + if(rel.type != 0) { + r = addrel(cursym); + *r = rel; + r->off = p->pc + andptr - and; + } + put4(v); + }else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */ + //p->mark |= 0100; + //print("sign: %llux %P\n", v, p); + *andptr ++ = 0xc7; + asmando(&p->to, 0); + put4(v); + }else{ /* need all 8 */ + //print("all: %llux %P\n", v, p); + rexflag |= regrex[p->to.type] & Rxb; + *andptr++ = op + reg[p->to.type]; + if(rel.type != 0) { + r = addrel(cursym); + *r = rel; + r->off = p->pc + andptr - and; + } + put8(v); + } + break; + + case Zib_rr: + *andptr++ = op; + asmand(&p->to, &p->to); + *andptr++ = vaddr(&p->from, nil); + break; + + case Z_il: + case Zil_: + if(t[2] == Zil_) + a = &p->from; + else + a = &p->to; + *andptr++ = op; + if(o->prefix == Pe) { + v = vaddr(a, nil); + *andptr++ = v; + *andptr++ = v>>8; + } + else + relput4(p, a); + break; + + case Zm_ilo: + case Zilo_m: + *andptr++ = op; + if(t[2] == Zilo_m) { + a = &p->from; + asmando(&p->to, o->op[z+1]); + } else { + a = &p->to; + asmando(&p->from, o->op[z+1]); + } + if(o->prefix == Pe) { + v = vaddr(a, nil); + *andptr++ = v; + *andptr++ = v>>8; + } + else + relput4(p, a); + break; + + case Zil_rr: + *andptr++ = op; + asmand(&p->to, &p->to); + if(o->prefix == Pe) { + v = vaddr(&p->from, nil); + *andptr++ = v; + *andptr++ = v>>8; + } + else + relput4(p, &p->from); + break; + + case Z_rp: + rexflag |= regrex[p->to.type] & (Rxb|0x40); + *andptr++ = op + reg[p->to.type]; + break; + + case Zrp_: + rexflag |= regrex[p->from.type] & (Rxb|0x40); + *andptr++ = op + reg[p->from.type]; + break; + + case Zclr: + *andptr++ = op; + asmand(&p->to, &p->to); + break; + + case Zcall: + q = p->pcond; + if(q == nil) { + diag("call without target"); + errorexit(); + } + if(q->as != ATEXT) { + // Could handle this case by making D_PCREL + // record the Prog* instead of the Sym*, but let's + // wait until the need arises. + diag("call of non-TEXT %P", q); + errorexit(); + } + *andptr++ = op; + r = addrel(cursym); + r->off = p->pc + andptr - and; + r->sym = q->from.sym; + r->type = D_PCREL; + r->siz = 4; + put4(0); + break; + + case Zbr: + case Zjmp: + // TODO: jump across functions needs reloc + q = p->pcond; + if(q == nil) { + diag("jmp/branch without target"); + errorexit(); + } + if(q->as == ATEXT) { + if(t[2] == Zbr) { + diag("branch to ATEXT"); + errorexit(); + } + *andptr++ = o->op[z+1]; + r = addrel(cursym); + r->off = p->pc + andptr - and; + r->sym = q->from.sym; + r->type = D_PCREL; + r->siz = 4; + put4(0); + break; + } + // Assumes q is in this function. + // TODO: Check in input, preserve in brchain. + + // Fill in backward jump now. + if(p->back & 1) { + v = q->pc - (p->pc + 2); + if(v >= -128) { + *andptr++ = op; + *andptr++ = v; + } else { + v -= 5-2; + if(t[2] == Zbr) { + *andptr++ = 0x0f; + v--; + } + *andptr++ = o->op[z+1]; + *andptr++ = v; + *andptr++ = v>>8; + *andptr++ = v>>16; + *andptr++ = v>>24; + } + break; + } + + // Annotate target; will fill in later. + p->forwd = q->comefrom; + q->comefrom = p; + if(p->back & 2) { // short + *andptr++ = op; + *andptr++ = 0; + } else { + if(t[2] == Zbr) + *andptr++ = 0x0f; + *andptr++ = o->op[z+1]; + *andptr++ = 0; + *andptr++ = 0; + *andptr++ = 0; + *andptr++ = 0; + } + break; + +/* + v = q->pc - p->pc - 2; + if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) { + *andptr++ = op; + *andptr++ = v; + } else { + v -= 5-2; + if(t[2] == Zbr) { + *andptr++ = 0x0f; + v--; + } + *andptr++ = o->op[z+1]; + *andptr++ = v; + *andptr++ = v>>8; + *andptr++ = v>>16; + *andptr++ = v>>24; + } +*/ + break; + + case Zloop: + q = p->pcond; + if(q == nil) { + diag("loop without target"); + errorexit(); + } + v = q->pc - p->pc - 2; + if(v < -128 && v > 127) + diag("loop too far: %P", p); + *andptr++ = op; + *andptr++ = v; + break; + + case Zbyte: + v = vaddr(&p->from, &rel); + if(rel.siz != 0) { + rel.siz = op; + r = addrel(cursym); + *r = rel; + r->off = p->pc + andptr - and; + } + *andptr++ = v; + if(op > 1) { + *andptr++ = v>>8; + if(op > 2) { + *andptr++ = v>>16; + *andptr++ = v>>24; + if(op > 4) { + *andptr++ = v>>32; + *andptr++ = v>>40; + *andptr++ = v>>48; + *andptr++ = v>>56; + } + } + } + break; + } + return; + +domov: + for(mo=ymovtab; mo->as; mo++) + if(p->as == mo->as) + if(ycover[ft+mo->ft]) + if(ycover[tt+mo->tt]){ + t = mo->op; + goto mfound; + } +bad: + if(p->mode != 64){ + /* + * here, the assembly has failed. + * if its a byte instruction that has + * unaddressable registers, try to + * exchange registers and reissue the + * instruction with the operands renamed. + */ + pp = *p; + z = p->from.type; + if(z >= D_BP && z <= D_DI) { + if(isax(&p->to)) { + *andptr++ = 0x87; /* xchg lhs,bx */ + asmando(&p->from, reg[D_BX]); + subreg(&pp, z, D_BX); + doasm(&pp); + *andptr++ = 0x87; /* xchg lhs,bx */ + asmando(&p->from, reg[D_BX]); + } else { + *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ + subreg(&pp, z, D_AX); + doasm(&pp); + *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ + } + return; + } + z = p->to.type; + if(z >= D_BP && z <= D_DI) { + if(isax(&p->from)) { + *andptr++ = 0x87; /* xchg rhs,bx */ + asmando(&p->to, reg[D_BX]); + subreg(&pp, z, D_BX); + doasm(&pp); + *andptr++ = 0x87; /* xchg rhs,bx */ + asmando(&p->to, reg[D_BX]); + } else { + *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ + subreg(&pp, z, D_AX); + doasm(&pp); + *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ + } + return; + } + } + diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p); + return; + +mfound: + switch(mo->code) { + default: + diag("asmins: unknown mov %d %P", mo->code, p); + break; + + case 0: /* lit */ + for(z=0; t[z]!=E; z++) + *andptr++ = t[z]; + break; + + case 1: /* r,m */ + *andptr++ = t[0]; + asmando(&p->to, t[1]); + break; + + case 2: /* m,r */ + *andptr++ = t[0]; + asmando(&p->from, t[1]); + break; + + case 3: /* r,m - 2op */ + *andptr++ = t[0]; + *andptr++ = t[1]; + asmando(&p->to, t[2]); + rexflag |= regrex[p->from.type] & (Rxr|0x40); + break; + + case 4: /* m,r - 2op */ + *andptr++ = t[0]; + *andptr++ = t[1]; + asmando(&p->from, t[2]); + rexflag |= regrex[p->to.type] & (Rxr|0x40); + break; + + case 5: /* load full pointer, trash heap */ + if(t[0]) + *andptr++ = t[0]; + switch(p->to.index) { + default: + goto bad; + case D_DS: + *andptr++ = 0xc5; + break; + case D_SS: + *andptr++ = 0x0f; + *andptr++ = 0xb2; + break; + case D_ES: + *andptr++ = 0xc4; + break; + case D_FS: + *andptr++ = 0x0f; + *andptr++ = 0xb4; + break; + case D_GS: + *andptr++ = 0x0f; + *andptr++ = 0xb5; + break; + } + asmand(&p->from, &p->to); + break; + + case 6: /* double shift */ + if(t[0] == Pw){ + if(p->mode != 64) + diag("asmins: illegal 64: %P", p); + rexflag |= Pw; + t++; + }else if(t[0] == Pe){ + *andptr++ = Pe; + t++; + } + z = p->from.type; + switch(z) { + default: + goto bad; + case D_CONST: + *andptr++ = 0x0f; + *andptr++ = t[0]; + asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0); + *andptr++ = p->from.offset; + break; + case D_CL: + case D_CX: + *andptr++ = 0x0f; + *andptr++ = t[1]; + asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0); + break; + } + break; + } +} + +void +asmins(Prog *p) +{ + int n, np, c; + Reloc *r; + + rexflag = 0; + andptr = and; + asmode = p->mode; + doasm(p); + if(rexflag){ + /* + * as befits the whole approach of the architecture, + * the rex prefix must appear before the first opcode byte + * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but + * before the 0f opcode escape!), or it might be ignored. + * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'. + */ + if(p->mode != 64) + diag("asmins: illegal in mode %d: %P", p->mode, p); + n = andptr - and; + for(np = 0; np < n; np++) { + c = and[np]; + if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26) + break; + } + for(r=cursym->r+cursym->nr; r-- > cursym->r; ) { + if(r->off < p->pc) + break; + r->off++; + } + memmove(and+np+1, and+np, n-np); + and[np] = 0x40 | rexflag; + andptr++; + } +} |