summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2013-12-08 22:49:37 -0500
committerRuss Cox <rsc@golang.org>2013-12-08 22:49:37 -0500
commitdb891ed81b87470f047575a6387a99d45ead1021 (patch)
tree3dca678ac325eef538b714089b7ae04bac651ec4 /src
parent8ae8d979d4cc7cdc7576d7f7ef63c5dc819b6522 (diff)
downloadgo-db891ed81b87470f047575a6387a99d45ead1021.tar.gz
liblink: create new library based on linker code
There is an enormous amount of code moving around in this CL, but the code is the same, and it is invoked in the same ways. This CL is preparation for the new linker structure, not the new structure itself. The new library's definition is in include/link.h. The main change is the use of a Link structure to hold all the linker-relevant state, replacing the smattering of global variables. The Link structure should both make it clearer which state must be carried around and make it possible to parallelize more easily later. The main body of the linker has moved into the architecture-independent cmd/ld directory. That includes the list of known header types, so the distinction between Hplan9x32 and Hplan9x64 is removed (no other header type distinguished 32- and 64-bit formats), and code for unused formats such as ipaq kernels has been deleted. The code being deleted from 5l, 6l, and 8l reappears in liblink or in ld. Because multiple files are being merged in the liblink directory, it is not possible to show the diffs nicely in hg. The Prog and Addr structures have been unified into an architecture-independent form and moved to link.h, where they will be shared by all tools: the assemblers, the compilers, and the linkers. The unification makes it possible to write architecture-independent traversal of Prog lists, among other benefits. The Sym structures cannot be unified: they are too fundamentally different between the linker and the compilers. Instead, liblink defines an LSym - a linker Sym - to be used in the Prog and Addr structures, and the linker now refers exclusively to LSyms. The compilers will keep using their own syms but will fill out the corresponding LSyms in the Prog and Addr structures. Although code from 5l, 6l, and 8l is now in a single library, the code has been arranged so that only one architecture needs to be linked into a particular program: 5l will not contain the code needed for x86 instruction layout, for example. The object file writing code in liblink/obj.c is from cmd/gc/obj.c. Preparation for golang.org/s/go13linker work. This CL does not build by itself. It depends on 35740044 and will be submitted at the same time. R=iant CC=golang-dev https://codereview.appspot.com/35790044
Diffstat (limited to 'src')
-rw-r--r--src/cmd/5l/5.out.h85
-rw-r--r--src/cmd/5l/asm.c1495
-rw-r--r--src/cmd/5l/l.h350
-rw-r--r--src/cmd/5l/list.c40
-rw-r--r--src/cmd/5l/noop.c671
-rw-r--r--src/cmd/5l/obj.c724
-rw-r--r--src/cmd/5l/optab.c277
-rw-r--r--src/cmd/5l/pass.c409
-rw-r--r--src/cmd/5l/prof.c211
-rw-r--r--src/cmd/5l/softfloat.c91
-rw-r--r--src/cmd/5l/span.c937
-rw-r--r--src/cmd/6l/6.out.h12
-rw-r--r--src/cmd/6l/asm.c234
-rw-r--r--src/cmd/6l/l.h365
-rw-r--r--src/cmd/6l/list.c22
-rw-r--r--src/cmd/6l/obj.c670
-rw-r--r--src/cmd/6l/optab.c1372
-rw-r--r--src/cmd/6l/pass.c991
-rw-r--r--src/cmd/6l/prof.c171
-rw-r--r--src/cmd/6l/span.c1846
-rw-r--r--src/cmd/8l/8.out.h12
-rw-r--r--src/cmd/8l/asm.c343
-rw-r--r--src/cmd/8l/l.h331
-rw-r--r--src/cmd/8l/list.c22
-rw-r--r--src/cmd/8l/obj.c674
-rw-r--r--src/cmd/8l/optab.c1032
-rw-r--r--src/cmd/8l/pass.c858
-rw-r--r--src/cmd/8l/prof.c173
-rw-r--r--src/cmd/8l/span.c1507
-rw-r--r--src/cmd/ld/data.c535
-rw-r--r--src/cmd/ld/decodesym.c62
-rw-r--r--src/cmd/ld/dwarf.c86
-rw-r--r--src/cmd/ld/dwarf.h2
-rw-r--r--src/cmd/ld/elf.c184
-rw-r--r--src/cmd/ld/elf.h14
-rw-r--r--src/cmd/ld/go.c83
-rw-r--r--src/cmd/ld/ldelf.c42
-rw-r--r--src/cmd/ld/ldmacho.c34
-rw-r--r--src/cmd/ld/ldpe.c36
-rw-r--r--src/cmd/ld/lib.c1306
-rw-r--r--src/cmd/ld/lib.h383
-rw-r--r--src/cmd/ld/macho.c106
-rw-r--r--src/cmd/ld/pass.c104
-rw-r--r--src/cmd/ld/pcln.c258
-rw-r--r--src/cmd/ld/pe.c40
-rw-r--r--src/cmd/ld/pe.h2
-rw-r--r--src/cmd/ld/pobj.c223
-rw-r--r--src/cmd/ld/symtab.c50
-rw-r--r--src/liblink/Makefile5
-rw-r--r--src/liblink/asm5.c2443
-rw-r--r--src/liblink/asm6.c3289
-rw-r--r--src/liblink/asm8.c2571
-rw-r--r--src/liblink/data.c366
-rw-r--r--src/liblink/go.c74
-rw-r--r--src/liblink/ld.c572
-rw-r--r--src/liblink/obj.c403
-rw-r--r--src/liblink/obj5.c1187
-rw-r--r--src/liblink/obj6.c1078
-rw-r--r--src/liblink/obj8.c937
-rw-r--r--src/liblink/pass.c115
-rw-r--r--src/liblink/pcln.c298
-rw-r--r--src/liblink/rdobj5.c585
-rw-r--r--src/liblink/rdobj6.c495
-rw-r--r--src/liblink/rdobj8.c466
-rw-r--r--src/liblink/sym.c158
65 files changed, 16814 insertions, 17703 deletions
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index ebbadde2c..f832f2af8 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -234,62 +234,53 @@ enum as
#define SHIFT_AR 2<<5
#define SHIFT_RR 3<<5
+enum
+{
/* type/name */
-#define D_GOK 0
-#define D_NONE 1
+ D_GOK = 0,
+ D_NONE = 1,
/* type */
-#define D_BRANCH (D_NONE+1)
-#define D_OREG (D_NONE+2)
-#define D_CONST (D_NONE+7)
-#define D_FCONST (D_NONE+8)
-#define D_SCONST (D_NONE+9)
-#define D_PSR (D_NONE+10)
-#define D_REG (D_NONE+12)
-#define D_FREG (D_NONE+13)
-#define D_FILE (D_NONE+16)
-#define D_OCONST (D_NONE+17)
-#define D_FILE1 (D_NONE+18)
-
-#define D_SHIFT (D_NONE+19)
-#define D_FPCR (D_NONE+20)
-#define D_REGREG (D_NONE+21) // (reg, reg)
-#define D_ADDR (D_NONE+22)
-
-#define D_SBIG (D_NONE+23)
-#define D_CONST2 (D_NONE+24)
-
-#define D_REGREG2 (D_NONE+25) // reg, reg
+ D_BRANCH = (D_NONE+1),
+ D_OREG = (D_NONE+2),
+ D_CONST = (D_NONE+7),
+ D_FCONST = (D_NONE+8),
+ D_SCONST = (D_NONE+9),
+ D_PSR = (D_NONE+10),
+ D_REG = (D_NONE+12),
+ D_FREG = (D_NONE+13),
+ D_FILE = (D_NONE+16),
+ D_OCONST = (D_NONE+17),
+ D_FILE1 = (D_NONE+18),
+
+ D_SHIFT = (D_NONE+19),
+ D_FPCR = (D_NONE+20),
+ D_REGREG = (D_NONE+21), // (reg, reg)
+ D_ADDR = (D_NONE+22),
+
+ D_SBIG = (D_NONE+23),
+ D_CONST2 = (D_NONE+24),
+
+ D_REGREG2 = (D_NONE+25), // reg, reg
/* name */
-#define D_EXTERN (D_NONE+3)
-#define D_STATIC (D_NONE+4)
-#define D_AUTO (D_NONE+5)
-#define D_PARAM (D_NONE+6)
+ D_EXTERN = (D_NONE+3),
+ D_STATIC = (D_NONE+4),
+ D_AUTO = (D_NONE+5),
+ D_PARAM = (D_NONE+6),
/* internal only */
-#define D_SIZE (D_NONE+40)
-#define D_PCREL (D_NONE+41)
-#define D_GOTOFF (D_NONE+42) // R_ARM_GOTOFF
-#define D_PLT0 (D_NONE+43) // R_ARM_PLT32, 1st inst: add ip, pc, #0xNN00000
-#define D_PLT1 (D_NONE+44) // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000
-#define D_PLT2 (D_NONE+45) // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]!
-#define D_CALL (D_NONE+46) // R_ARM_PLT32/R_ARM_CALL/R_ARM_JUMP24, bl xxxxx or b yyyyy
-#define D_TLS (D_NONE+47) // R_ARM_TLS_LE32
+ D_SIZE = (D_NONE+40),
+ D_PCREL = (D_NONE+41),
+ D_GOTOFF = (D_NONE+42), // R_ARM_GOTOFF
+ D_PLT0 = (D_NONE+43), // R_ARM_PLT32, 1st inst: add ip, pc, #0xNN00000
+ D_PLT1 = (D_NONE+44), // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000
+ D_PLT2 = (D_NONE+45), // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]!
+ D_CALL = (D_NONE+46), // R_ARM_PLT32/R_ARM_CALL/R_ARM_JUMP24, bl xxxxx or b yyyyy
+ D_TLS = (D_NONE+47), // R_ARM_TLS_LE32
+};
/*
* this is the ranlib header
*/
#define SYMDEF "__.GOSYMDEF"
-
-/*
- * this is the simulated IEEE floating point
- */
-typedef struct ieee Ieee;
-struct ieee
-{
- int32 l; /* contains ls-man 0xffffffff */
- int32 h; /* contains sign 0x80000000
- exp 0x7ff00000
- ms-man 0x000fffff */
-};
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 33cdf8096..85600cabf 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -35,7 +35,6 @@
#include "../ld/elf.h"
#include "../ld/dwarf.h"
-static Prog *PP;
char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI
char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
@@ -43,35 +42,18 @@ char openbsddynld[] = "XXX";
char netbsddynld[] = "/libexec/ld.elf_so";
char dragonflydynld[] = "XXX";
-int32
-entryvalue(void)
-{
- char *a;
- Sym *s;
-
- a = INITENTRY;
- if(*a >= '0' && *a <= '9')
- return atolwhex(a);
- s = lookup(a, 0);
- if(s->type == 0)
- return INITTEXT;
- if(s->type != STEXT)
- diag("entry not text: %s", s->name);
- return s->value;
-}
-
static int
needlib(char *name)
{
char *p;
- Sym *s;
+ LSym *s;
if(*name == '\0')
return 0;
/* reuse hash code in symbol table */
p = smprint(".dynlib.%s", name);
- s = lookup(p, 0);
+ s = linklookup(ctxt, p, 0);
free(p);
if(s->type == 0) {
s->type = 100; // avoid SDATA, etc.
@@ -82,9 +64,9 @@ needlib(char *name)
int nelfsym = 1;
-static void addpltsym(Sym*);
-static void addgotsym(Sym*);
-static void addgotsyminternal(Sym*);
+static void addpltsym(Link*, LSym*);
+static void addgotsym(Link*, LSym*);
+static void addgotsyminternal(Link*, LSym*);
// Preserve highest 8 bits of a, and do addition to lower 24-bit
// of a and b; used to adjust ARM branch intruction's target
@@ -95,19 +77,19 @@ braddoff(int32 a, int32 b)
}
void
-adddynrela(Sym *rel, Sym *s, Reloc *r)
+adddynrela(LSym *rel, LSym *s, Reloc *r)
{
- addaddrplus(rel, s, r->off);
- adduint32(rel, R_ARM_RELATIVE);
+ addaddrplus(ctxt, rel, s, r->off);
+ adduint32(ctxt, rel, R_ARM_RELATIVE);
}
void
-adddynrel(Sym *s, Reloc *r)
+adddynrel(LSym *s, Reloc *r)
{
- Sym *targ, *rel;
+ LSym *targ, *rel;
targ = r->sym;
- cursym = s;
+ ctxt->cursym = s;
switch(r->type) {
default:
@@ -121,8 +103,8 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_ARM_PLT32:
r->type = D_CALL;
if(targ->type == SDYNIMPORT) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = braddoff(r->add, targ->plt / 4);
}
return;
@@ -134,9 +116,9 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL
if(targ->type != SDYNIMPORT) {
- addgotsyminternal(targ);
+ addgotsyminternal(ctxt, targ);
} else {
- addgotsym(targ);
+ addgotsym(ctxt, targ);
}
r->type = D_CONST; // write r->add during relocsym
r->sym = S;
@@ -145,12 +127,12 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P
if(targ->type != SDYNIMPORT) {
- addgotsyminternal(targ);
+ addgotsyminternal(ctxt, targ);
} else {
- addgotsym(targ);
+ addgotsym(ctxt, targ);
}
r->type = D_PCREL;
- r->sym = lookup(".got", 0);
+ r->sym = linklookup(ctxt, ".got", 0);
r->add += targ->got + 4;
return;
@@ -160,15 +142,15 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL
r->type = D_PCREL;
- r->sym = lookup(".got", 0);
+ r->sym = linklookup(ctxt, ".got", 0);
r->add += 4;
return;
case 256 + R_ARM_CALL:
r->type = D_CALL;
if(targ->type == SDYNIMPORT) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = braddoff(r->add, targ->plt / 4);
}
return;
@@ -197,8 +179,8 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_ARM_JUMP24:
r->type = D_CALL;
if(targ->type == SDYNIMPORT) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = braddoff(r->add, targ->plt / 4);
}
return;
@@ -210,8 +192,8 @@ adddynrel(Sym *s, Reloc *r)
switch(r->type) {
case D_PCREL:
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
return;
@@ -219,10 +201,10 @@ adddynrel(Sym *s, Reloc *r)
if(s->type != SDATA)
break;
if(iself) {
- adddynsym(targ);
- rel = lookup(".rel", 0);
- addaddrplus(rel, s, r->off);
- adduint32(rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc
+ adddynsym(ctxt, targ);
+ rel = linklookup(ctxt, ".rel", 0);
+ addaddrplus(ctxt, rel, s, r->off);
+ adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc
r->type = D_CONST; // write r->add during relocsym
r->sym = S;
return;
@@ -230,7 +212,7 @@ adddynrel(Sym *s, Reloc *r)
break;
}
- cursym = s;
+ ctxt->cursym = s;
diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}
@@ -287,26 +269,26 @@ elfreloc1(Reloc *r, vlong sectoff)
void
elfsetupplt(void)
{
- Sym *plt, *got;
+ LSym *plt, *got;
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
+ got = linklookup(ctxt, ".got.plt", 0);
if(plt->size == 0) {
// str lr, [sp, #-4]!
- adduint32(plt, 0xe52de004);
+ adduint32(ctxt, plt, 0xe52de004);
// ldr lr, [pc, #4]
- adduint32(plt, 0xe59fe004);
+ adduint32(ctxt, plt, 0xe59fe004);
// add lr, pc, lr
- adduint32(plt, 0xe08fe00e);
+ adduint32(ctxt, plt, 0xe08fe00e);
// ldr pc, [lr, #8]!
- adduint32(plt, 0xe5bef008);
+ adduint32(ctxt, plt, 0xe5bef008);
// .word &GLOBAL_OFFSET_TABLE[0] - .
- addpcrelplus(plt, got, 4);
+ addpcrelplus(ctxt, plt, got, 4);
// the first .plt entry requires 3 .plt.got entries
- adduint32(got, 0);
- adduint32(got, 0);
- adduint32(got, 0);
+ adduint32(ctxt, got, 0);
+ adduint32(ctxt, got, 0);
+ adduint32(ctxt, got, 0);
}
}
@@ -321,9 +303,9 @@ machoreloc1(Reloc *r, vlong sectoff)
int
-archreloc(Reloc *r, Sym *s, vlong *val)
+archreloc(Reloc *r, LSym *s, vlong *val)
{
- Sym *rs;
+ LSym *rs;
if(linkmode == LinkExternal) {
switch(r->type) {
@@ -356,23 +338,23 @@ archreloc(Reloc *r, Sym *s, vlong *val)
*val = r->add;
return 0;
case D_GOTOFF:
- *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
+ *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
return 0;
// The following three arch specific relocations are only for generation of
// Linux/ARM ELF's PLT entry (3 assembler instruction)
case D_PLT0: // add ip, pc, #0xXX00000
- if (symaddr(lookup(".got.plt", 0)) < symaddr(lookup(".plt", 0)))
+ if (symaddr(linklookup(ctxt, ".got.plt", 0)) < symaddr(linklookup(ctxt, ".plt", 0)))
diag(".got.plt should be placed after .plt section.");
*val = 0xe28fc600U +
- (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add) >> 20));
+ (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add) >> 20));
return 0;
case D_PLT1: // add ip, ip, #0xYY000
*val = 0xe28cca00U +
- (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 4) >> 12));
+ (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 4) >> 12));
return 0;
case D_PLT2: // ldr pc, [ip, #0xZZZ]!
*val = 0xe5bcf000U +
- (0xfff & (uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 8));
+ (0xfff & (uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 8));
return 0;
case D_CALL: // bl XXXXXX or b YYYYYY
*val = braddoff((0xff000000U & (uint32)r->add),
@@ -384,7 +366,7 @@ archreloc(Reloc *r, Sym *s, vlong *val)
}
static Reloc *
-addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ)
+addpltreloc(Link *ctxt, LSym *plt, LSym *got, LSym *sym, int typ)
{
Reloc *r;
@@ -397,25 +379,25 @@ addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ)
plt->reachable = 1;
plt->size += 4;
- symgrow(plt, plt->size);
+ symgrow(ctxt, plt, plt->size);
return r;
}
static void
-addpltsym(Sym *s)
+addpltsym(Link *ctxt, LSym *s)
{
- Sym *plt, *got, *rel;
+ LSym *plt, *got, *rel;
if(s->plt >= 0)
return;
- adddynsym(s);
+ adddynsym(ctxt, s);
if(iself) {
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
- rel = lookup(".rel.plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
+ got = linklookup(ctxt, ".got.plt", 0);
+ rel = linklookup(ctxt, ".rel.plt", 0);
if(plt->size == 0)
elfsetupplt();
@@ -424,34 +406,34 @@ addpltsym(Sym *s)
// In theory, all GOT should point to the first PLT entry,
// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
// dynamic linker won't, so we'd better do it ourselves.
- addaddrplus(got, plt, 0);
+ addaddrplus(ctxt, got, plt, 0);
// .plt entry, this depends on the .got entry
s->plt = plt->size;
- addpltreloc(plt, got, s, D_PLT0); // add lr, pc, #0xXX00000
- addpltreloc(plt, got, s, D_PLT1); // add lr, lr, #0xYY000
- addpltreloc(plt, got, s, D_PLT2); // ldr pc, [lr, #0xZZZ]!
+ addpltreloc(ctxt, plt, got, s, D_PLT0); // add lr, pc, #0xXX00000
+ addpltreloc(ctxt, plt, got, s, D_PLT1); // add lr, lr, #0xYY000
+ addpltreloc(ctxt, plt, got, s, D_PLT2); // ldr pc, [lr, #0xZZZ]!
// rel
- addaddrplus(rel, got, s->got);
- adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT));
+ addaddrplus(ctxt, rel, got, s->got);
+ adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT));
} else {
diag("addpltsym: unsupported binary format");
}
}
static void
-addgotsyminternal(Sym *s)
+addgotsyminternal(Link *ctxt, LSym *s)
{
- Sym *got;
+ LSym *got;
if(s->got >= 0)
return;
- got = lookup(".got", 0);
+ got = linklookup(ctxt, ".got", 0);
s->got = got->size;
- addaddrplus(got, s, 0);
+ addaddrplus(ctxt, got, s, 0);
if(iself) {
;
@@ -461,31 +443,31 @@ addgotsyminternal(Sym *s)
}
static void
-addgotsym(Sym *s)
+addgotsym(Link *ctxt, LSym *s)
{
- Sym *got, *rel;
+ LSym *got, *rel;
if(s->got >= 0)
return;
- adddynsym(s);
- got = lookup(".got", 0);
+ adddynsym(ctxt, s);
+ got = linklookup(ctxt, ".got", 0);
s->got = got->size;
- adduint32(got, 0);
+ adduint32(ctxt, got, 0);
if(iself) {
- rel = lookup(".rel", 0);
- addaddrplus(rel, got, s->got);
- adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT));
+ rel = linklookup(ctxt, ".rel", 0);
+ addaddrplus(ctxt, rel, got, s->got);
+ adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT));
} else {
diag("addgotsym: unsupported binary format");
}
}
void
-adddynsym(Sym *s)
+adddynsym(Link *ctxt, LSym *s)
{
- Sym *d;
+ LSym *d;
int t;
char *name;
@@ -495,20 +477,20 @@ adddynsym(Sym *s)
if(iself) {
s->dynid = nelfsym++;
- d = lookup(".dynsym", 0);
+ d = linklookup(ctxt, ".dynsym", 0);
/* name */
name = s->extname;
- adduint32(d, addstring(lookup(".dynstr", 0), name));
+ adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
/* value */
if(s->type == SDYNIMPORT)
- adduint32(d, 0);
+ adduint32(ctxt, d, 0);
else
- addaddr(d, s);
+ addaddr(ctxt, d, s);
/* size */
- adduint32(d, 0);
+ adduint32(ctxt, d, 0);
/* type */
t = STB_GLOBAL << 4;
@@ -516,12 +498,12 @@ adddynsym(Sym *s)
t |= STT_FUNC;
else
t |= STT_OBJECT;
- adduint8(d, t);
- adduint8(d, 0);
+ adduint8(ctxt, d, t);
+ adduint8(ctxt, d, 0);
/* shndx */
if(s->type == SDYNIMPORT)
- adduint16(d, SHN_UNDEF);
+ adduint16(ctxt, d, SHN_UNDEF);
else {
switch(s->type) {
default:
@@ -538,7 +520,7 @@ adddynsym(Sym *s)
t = 14;
break;
}
- adduint16(d, t);
+ adduint16(ctxt, d, t);
}
} else {
diag("adddynsym: unsupported binary format");
@@ -548,39 +530,27 @@ adddynsym(Sym *s)
void
adddynlib(char *lib)
{
- Sym *s;
+ LSym *s;
if(!needlib(lib))
return;
if(iself) {
- s = lookup(".dynstr", 0);
+ s = linklookup(ctxt, ".dynstr", 0);
if(s->size == 0)
addstring(s, "");
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
} else {
diag("adddynlib: unsupported binary format");
}
}
-vlong
-datoff(vlong addr)
-{
- if(addr >= segdata.vaddr)
- return addr - segdata.vaddr + segdata.fileoff;
- if(addr >= segtext.vaddr)
- return addr - segtext.vaddr + segtext.fileoff;
- diag("datoff %#x", addr);
- return 0;
-}
-
void
asmb(void)
{
- int32 t;
uint32 symo;
Section *sect;
- Sym *sym;
+ LSym *sym;
int i;
if(debug['v'])
@@ -627,13 +597,7 @@ asmb(void)
default:
if(iself)
goto ElfSym;
- case Hnoheader:
- case Hrisc:
- case Hixp1200:
- case Hipaq:
- debug['s'] = 1;
- break;
- case Hplan9x32:
+ case Hplan9:
symo = HEADR+segtext.len+segdata.filelen;
break;
ElfSym:
@@ -659,11 +623,11 @@ asmb(void)
elfemitreloc();
}
break;
- case Hplan9x32:
+ case Hplan9:
asmplan9sym();
cflush();
- sym = lookup("pclntab", 0);
+ sym = linklookup(ctxt, "pclntab", 0);
if(sym != nil) {
lcsize = sym->np;
for(i=0; i < lcsize; i++)
@@ -675,46 +639,14 @@ asmb(void)
}
}
- cursym = nil;
+ ctxt->cursym = nil;
if(debug['v'])
Bprint(&bso, "%5.2f header\n", cputime());
Bflush(&bso);
cseek(0L);
switch(HEADTYPE) {
default:
- case Hnoheader: /* no header */
- break;
- case Hrisc: /* aif for risc os */
- lputl(0xe1a00000); /* NOP - decompress code */
- lputl(0xe1a00000); /* NOP - relocation code */
- lputl(0xeb000000 + 12); /* BL - zero init code */
- lputl(0xeb000000 +
- (entryvalue()
- - INITTEXT
- + HEADR
- - 12
- - 8) / 4); /* BL - entry code */
-
- lputl(0xef000011); /* SWI - exit code */
- lputl(segtext.filelen+HEADR); /* text size */
- lputl(segdata.filelen); /* data size */
- lputl(0); /* sym size */
-
- lputl(segdata.len - segdata.filelen); /* bss size */
- lputl(0); /* sym type */
- lputl(INITTEXT-HEADR); /* text addr */
- lputl(0); /* workspace - ignored */
-
- lputl(32); /* addr mode / data addr flag */
- lputl(0); /* data addr */
- for(t=0; t<2; t++)
- lputl(0); /* reserved */
-
- for(t=0; t<15; t++)
- lputl(0xe1a00000); /* NOP - zero init code */
- lputl(0xe1a0f00e); /* B (R14) - zero init return */
- break;
- case Hplan9x32: /* plan 9 */
+ case Hplan9: /* plan 9 */
lput(0x647); /* magic */
lput(segtext.filelen); /* sizes */
lput(segdata.filelen);
@@ -724,14 +656,6 @@ asmb(void)
lput(0L);
lput(lcsize);
break;
- case Hixp1200: /* boot for IXP1200 */
- break;
- case Hipaq: /* boot for ipaq */
- lputl(0xe3300000); /* nop */
- lputl(0xe3300000); /* nop */
- lputl(0xe3300000); /* nop */
- lputl(0xe3300000); /* nop */
- break;
case Hlinux:
case Hfreebsd:
case Hnetbsd:
@@ -808,1224 +732,17 @@ nopstat(char *f, Count *c)
(double)(c->outof - c->count)/c->outof);
}
-void
-asmout(Prog *p, Optab *o, int32 *out, Sym *gmsym)
-{
- int32 o1, o2, o3, o4, o5, o6, v;
- int r, rf, rt, rt2;
- Reloc *rel;
-
-PP = p;
- o1 = 0;
- o2 = 0;
- o3 = 0;
- o4 = 0;
- o5 = 0;
- o6 = 0;
- armsize += o->size;
-if(debug['P']) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type);
- switch(o->type) {
- default:
- diag("unknown asm %d", o->type);
- prasm(p);
- break;
-
- case 0: /* pseudo ops */
-if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr);
- break;
-
- case 1: /* op R,[R],R */
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(p->as == AMOVB || p->as == AMOVH || p->as == AMOVW || p->as == AMVN)
- r = 0;
- else
- if(r == NREG)
- r = rt;
- o1 |= rf | (r<<16) | (rt<<12);
- break;
-
- case 2: /* movbu $I,[R],R */
- aclass(&p->from);
- o1 = oprrr(p->as, p->scond);
- o1 |= immrot(instoffset);
- rt = p->to.reg;
- r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == NREG)
- r = rt;
- o1 |= (r<<16) | (rt<<12);
- break;
-
- case 3: /* add R<<[IR],[R],R */
- mov:
- aclass(&p->from);
- o1 = oprrr(p->as, p->scond);
- o1 |= p->from.offset;
- rt = p->to.reg;
- r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == NREG)
- r = rt;
- o1 |= (r<<16) | (rt<<12);
- break;
-
- case 4: /* add $I,[R],R */
- aclass(&p->from);
- o1 = oprrr(AADD, p->scond);
- o1 |= immrot(instoffset);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 |= r << 16;
- o1 |= p->to.reg << 12;
- break;
-
- case 5: /* bra s */
- o1 = opbra(p->as, p->scond);
- v = -8;
- if(p->to.sym != S && p->to.sym->type != 0) {
- rel = addrel(cursym);
- rel->off = pc - cursym->value;
- rel->siz = 4;
- rel->sym = p->to.sym;
- rel->add = o1 | ((v >> 2) & 0xffffff);
- rel->type = D_CALL;
- break;
- }
- if(p->cond != P)
- v = (p->cond->pc - pc) - 8;
- o1 |= (v >> 2) & 0xffffff;
- break;
-
- case 6: /* b ,O(R) -> add $O,R,PC */
- aclass(&p->to);
- o1 = oprrr(AADD, p->scond);
- o1 |= immrot(instoffset);
- o1 |= p->to.reg << 16;
- o1 |= REGPC << 12;
- break;
-
- case 7: /* bl (R) -> blx R */
- aclass(&p->to);
- if(instoffset != 0)
- diag("%P: doesn't support BL offset(REG) where offset != 0", p);
- o1 = oprrr(ABL, p->scond);
- o1 |= p->to.reg;
- break;
-
- case 8: /* sll $c,[R],R -> mov (R<<$c),R */
- aclass(&p->from);
- o1 = oprrr(p->as, p->scond);
- r = p->reg;
- if(r == NREG)
- r = p->to.reg;
- o1 |= r;
- o1 |= (instoffset&31) << 7;
- o1 |= p->to.reg << 12;
- break;
-
- case 9: /* sll R,[R],R -> mov (R<<R),R */
- o1 = oprrr(p->as, p->scond);
- r = p->reg;
- if(r == NREG)
- r = p->to.reg;
- o1 |= r;
- o1 |= (p->from.reg << 8) | (1<<4);
- o1 |= p->to.reg << 12;
- break;
-
- case 10: /* swi [$con] */
- o1 = oprrr(p->as, p->scond);
- if(p->to.type != D_NONE) {
- aclass(&p->to);
- o1 |= instoffset & 0xffffff;
- }
- break;
-
- case 11: /* word */
- aclass(&p->to);
- o1 = instoffset;
- if(p->to.sym != S) {
- rel = addrel(cursym);
- rel->off = pc - cursym->value;
- rel->siz = 4;
- rel->sym = p->to.sym;
- rel->add = p->to.offset;
- if(rel->sym == gmsym) {
- rel->type = D_TLS;
- if(flag_shared)
- rel->add += pc - p->pcrel->pc - 8 - rel->siz;
- rel->xadd = rel->add;
- rel->xsym = rel->sym;
- } else if(flag_shared) {
- rel->type = D_PCREL;
- rel->add += pc - p->pcrel->pc - 8;
- } else
- rel->type = D_ADDR;
- o1 = 0;
- }
- break;
-
- case 12: /* movw $lcon, reg */
- o1 = omvl(p, &p->from, p->to.reg);
- if(o->flag & LPCREL) {
- o2 = oprrr(AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12;
- }
- break;
-
- case 13: /* op $lcon, [R], R */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- o2 = oprrr(p->as, p->scond);
- o2 |= REGTMP;
- r = p->reg;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == NREG)
- r = p->to.reg;
- o2 |= r << 16;
- if(p->to.type != D_NONE)
- o2 |= p->to.reg << 12;
- break;
-
- case 14: /* movb/movbu/movh/movhu R,R */
- o1 = oprrr(ASLL, p->scond);
-
- if(p->as == AMOVBU || p->as == AMOVHU)
- o2 = oprrr(ASRL, p->scond);
- else
- o2 = oprrr(ASRA, p->scond);
-
- r = p->to.reg;
- o1 |= (p->from.reg)|(r<<12);
- o2 |= (r)|(r<<12);
- if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) {
- o1 |= (24<<7);
- o2 |= (24<<7);
- } else {
- o1 |= (16<<7);
- o2 |= (16<<7);
- }
- break;
-
- case 15: /* mul r,[r,]r */
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- r = p->reg;
- if(r == NREG)
- r = rt;
- if(rt == r) {
- r = rf;
- rf = rt;
- }
- if(0)
- if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) {
- diag("bad registers in MUL");
- prasm(p);
- }
- o1 |= (rf<<8) | r | (rt<<16);
- break;
-
-
- case 16: /* div r,[r,]r */
- o1 = 0xf << 28;
- o2 = 0;
- break;
-
- case 17:
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- rt2 = p->to.offset;
- r = p->reg;
- o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12);
- break;
-
- case 20: /* mov/movb/movbu R,O(R) */
- aclass(&p->to);
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o1 = osr(p->as, p->from.reg, instoffset, r, p->scond);
- break;
-
- case 21: /* mov/movbu O(R),R -> lr */
- aclass(&p->from);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 = olr(instoffset, r, p->to.reg, p->scond);
- if(p->as != AMOVW)
- o1 |= 1<<22;
- break;
-
- case 30: /* mov/movb/movbu R,L(R) */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o2 = osrr(p->from.reg, REGTMP,r, p->scond);
- if(p->as != AMOVW)
- o2 |= 1<<22;
- break;
-
- case 31: /* mov/movbu L(R),R -> lr[b] */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o2 = olrr(REGTMP,r, p->to.reg, p->scond);
- if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB)
- o2 |= 1<<22;
- break;
-
- case 34: /* mov $lacon,R */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
-
- o2 = oprrr(AADD, p->scond);
- o2 |= REGTMP;
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o2 |= r << 16;
- if(p->to.type != D_NONE)
- o2 |= p->to.reg << 12;
- break;
-
- case 35: /* mov PSR,R */
- o1 = (2<<23) | (0xf<<16) | (0<<0);
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= (p->from.reg & 1) << 22;
- o1 |= p->to.reg << 12;
- break;
-
- case 36: /* mov R,PSR */
- o1 = (2<<23) | (0x29f<<12) | (0<<4);
- if(p->scond & C_FBIT)
- o1 ^= 0x010 << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= (p->to.reg & 1) << 22;
- o1 |= p->from.reg << 0;
- break;
-
- case 37: /* mov $con,PSR */
- aclass(&p->from);
- o1 = (2<<23) | (0x29f<<12) | (0<<4);
- if(p->scond & C_FBIT)
- o1 ^= 0x010 << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= immrot(instoffset);
- o1 |= (p->to.reg & 1) << 22;
- o1 |= p->from.reg << 0;
- break;
-
- case 38: /* movm $con,oreg -> stm */
- o1 = (0x4 << 25);
- o1 |= p->from.offset & 0xffff;
- o1 |= p->to.reg << 16;
- aclass(&p->to);
- goto movm;
-
- case 39: /* movm oreg,$con -> ldm */
- o1 = (0x4 << 25) | (1 << 20);
- o1 |= p->to.offset & 0xffff;
- o1 |= p->from.reg << 16;
- aclass(&p->from);
- movm:
- if(instoffset != 0)
- diag("offset must be zero in MOVM");
- o1 |= (p->scond & C_SCOND) << 28;
- if(p->scond & C_PBIT)
- o1 |= 1 << 24;
- if(p->scond & C_UBIT)
- o1 |= 1 << 23;
- if(p->scond & C_SBIT)
- o1 |= 1 << 22;
- if(p->scond & C_WBIT)
- o1 |= 1 << 21;
- break;
-
- case 40: /* swp oreg,reg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in SWP");
- o1 = (0x2<<23) | (0x9<<4);
- if(p->as != ASWPW)
- o1 |= 1 << 22;
- o1 |= p->from.reg << 16;
- o1 |= p->reg << 0;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
-
- case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
- o1 = 0xe8fd8000;
- break;
-
- case 50: /* floating point store */
- v = regoff(&p->to);
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p);
- break;
-
- case 51: /* floating point load */
- v = regoff(&p->from);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
- break;
-
- case 52: /* floating point store, int32 offset UGLY */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
- o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
- break;
-
- case 53: /* floating point load, int32 offset UGLY */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
- o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
- break;
-
- case 54: /* floating point arith */
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- r = p->reg;
- if(r == NREG) {
- r = rt;
- if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD)
- r = 0;
- }
- o1 |= rf | (r<<16) | (rt<<12);
- break;
-
- case 56: /* move to FP[CS]R */
- o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
- o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
- break;
-
- case 57: /* move from FP[CS]R */
- o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
- o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20);
- break;
- case 58: /* movbu R,R */
- o1 = oprrr(AAND, p->scond);
- o1 |= immrot(0xff);
- rt = p->to.reg;
- r = p->from.reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(r == NREG)
- r = rt;
- o1 |= (r<<16) | (rt<<12);
- break;
-
- case 59: /* movw/bu R<<I(R),R -> ldr indexed */
- if(p->from.reg == NREG) {
- if(p->as != AMOVW)
- diag("byte MOV from shifter operand");
- goto mov;
- }
- if(p->from.offset&(1<<4))
- diag("bad shift in LDR");
- o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
- if(p->as == AMOVBU)
- o1 |= 1<<22;
- break;
-
- case 60: /* movb R(R),R -> ldrsb indexed */
- if(p->from.reg == NREG) {
- diag("byte MOV from shifter operand");
- goto mov;
- }
- if(p->from.offset&(~0xf))
- diag("bad shift in LDRSB");
- o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
- o1 ^= (1<<5)|(1<<6);
- break;
-
- case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
- if(p->to.reg == NREG)
- diag("MOV to shifter operand");
- o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond);
- if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU)
- o1 |= 1<<22;
- break;
-
- case 62: /* case R -> movw R<<2(PC),PC */
- if(o->flag & LPCREL) {
- o1 = oprrr(AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12;
- o2 = olrr(REGTMP, REGPC, REGTMP, p->scond);
- o2 |= 2<<7;
- o3 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12;
- } else {
- o1 = olrr(p->from.reg, REGPC, REGPC, p->scond);
- o1 |= 2<<7;
- }
- break;
-
- case 63: /* bcase */
- if(p->cond != P) {
- rel = addrel(cursym);
- rel->off = pc - cursym->value;
- rel->siz = 4;
- if(p->to.sym != S && p->to.sym->type != 0) {
- rel->sym = p->to.sym;
- rel->add = p->to.offset;
- } else {
- rel->sym = cursym;
- rel->add = p->cond->pc - cursym->value;
- }
- if(o->flag & LPCREL) {
- rel->type = D_PCREL;
- rel->add += pc - p->pcrel->pc - 16 + rel->siz;
- } else
- rel->type = D_ADDR;
- o1 = 0;
- }
- break;
-
- /* reloc ops */
- case 64: /* mov/movb/movbu R,addr */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
- }
- break;
-
- case 65: /* mov/movbu addr,R */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- o2 = olr(0, REGTMP, p->to.reg, p->scond);
- if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB)
- o2 |= 1<<22;
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
- }
- break;
-
- case 68: /* floating point store -> ADDR */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
- }
- break;
-
- case 69: /* floating point load <- ADDR */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
- }
- break;
-
- /* ArmV4 ops: */
- case 70: /* movh/movhu R,O(R) -> strh */
- aclass(&p->to);
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o1 = oshr(p->from.reg, instoffset, r, p->scond);
- break;
- case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
- aclass(&p->from);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 = olhr(instoffset, r, p->to.reg, p->scond);
- if(p->as == AMOVB || p->as == AMOVBS)
- o1 ^= (1<<5)|(1<<6);
- else if(p->as == AMOVH || p->as == AMOVHS)
- o1 ^= (1<<6);
- break;
- case 72: /* movh/movhu R,L(R) -> strh */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o2 = oshrr(p->from.reg, REGTMP,r, p->scond);
- break;
- case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o2 = olhrr(REGTMP, r, p->to.reg, p->scond);
- if(p->as == AMOVB || p->as == AMOVBS)
- o2 ^= (1<<5)|(1<<6);
- else if(p->as == AMOVH || p->as == AMOVHS)
- o2 ^= (1<<6);
- break;
- case 74: /* bx $I */
- diag("ABX $I");
- break;
- case 75: /* bx O(R) */
- aclass(&p->to);
- if(instoffset != 0)
- diag("non-zero offset in ABX");
-/*
- o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
- o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R
-*/
- // p->to.reg may be REGLINK
- o1 = oprrr(AADD, p->scond);
- o1 |= immrot(instoffset);
- o1 |= p->to.reg << 16;
- o1 |= REGTMP << 12;
- o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
- o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
- break;
- case 76: /* bx O(R) when returning from fn*/
- diag("ABXRET");
- break;
- case 77: /* ldrex oreg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in LDREX");
- o1 = (0x19<<20) | (0xf9f);
- o1 |= p->from.reg << 16;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
- case 78: /* strex reg,oreg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in STREX");
- o1 = (0x18<<20) | (0xf90);
- o1 |= p->from.reg << 16;
- o1 |= p->reg << 0;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
- case 80: /* fmov zfcon,freg */
- if(p->as == AMOVD) {
- o1 = 0xeeb00b00; // VMOV imm 64
- o2 = oprrr(ASUBD, p->scond);
- } else {
- o1 = 0x0eb00a00; // VMOV imm 32
- o2 = oprrr(ASUBF, p->scond);
- }
- v = 0x70; // 1.0
- r = p->to.reg;
-
- // movf $1.0, r
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= r << 12;
- o1 |= (v&0xf) << 0;
- o1 |= (v&0xf0) << 12;
-
- // subf r,r,r
- o2 |= r | (r<<16) | (r<<12);
- break;
- case 81: /* fmov sfcon,freg */
- o1 = 0x0eb00a00; // VMOV imm 32
- if(p->as == AMOVD)
- o1 = 0xeeb00b00; // VMOV imm 64
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= p->to.reg << 12;
- v = chipfloat(&p->from.ieee);
- o1 |= (v&0xf) << 0;
- o1 |= (v&0xf0) << 12;
- break;
- case 82: /* fcmp freg,freg, */
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->reg<<12) | (p->from.reg<<0);
- o2 = 0x0ef1fa10; // VMRS R15
- o2 |= (p->scond & C_SCOND) << 28;
- break;
- case 83: /* fcmp freg,, */
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->from.reg<<12) | (1<<16);
- o2 = 0x0ef1fa10; // VMRS R15
- o2 |= (p->scond & C_SCOND) << 28;
- break;
- case 84: /* movfw freg,freg - truncate float-to-fix */
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->from.reg<<0);
- o1 |= (p->to.reg<<12);
- break;
- case 85: /* movwf freg,freg - fix-to-float */
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->from.reg<<0);
- o1 |= (p->to.reg<<12);
- break;
- case 86: /* movfw freg,reg - truncate float-to-fix */
- // macro for movfw freg,FTMP; movw FTMP,reg
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->from.reg<<0);
- o1 |= (FREGTMP<<12);
- o2 = oprrr(AMOVFW+AEND, p->scond);
- o2 |= (FREGTMP<<16);
- o2 |= (p->to.reg<<12);
- break;
- case 87: /* movwf reg,freg - fix-to-float */
- // macro for movw reg,FTMP; movwf FTMP,freg
- o1 = oprrr(AMOVWF+AEND, p->scond);
- o1 |= (p->from.reg<<12);
- o1 |= (FREGTMP<<16);
- o2 = oprrr(p->as, p->scond);
- o2 |= (FREGTMP<<0);
- o2 |= (p->to.reg<<12);
- break;
- case 88: /* movw reg,freg */
- o1 = oprrr(AMOVWF+AEND, p->scond);
- o1 |= (p->from.reg<<12);
- o1 |= (p->to.reg<<16);
- break;
- case 89: /* movw freg,reg */
- o1 = oprrr(AMOVFW+AEND, p->scond);
- o1 |= (p->from.reg<<16);
- o1 |= (p->to.reg<<12);
- break;
- case 90: /* tst reg */
- o1 = oprrr(ACMP+AEND, p->scond);
- o1 |= p->from.reg<<16;
- break;
- case 91: /* ldrexd oreg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in LDREX");
- o1 = (0x1b<<20) | (0xf9f);
- o1 |= p->from.reg << 16;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
- case 92: /* strexd reg,oreg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in STREX");
- o1 = (0x1a<<20) | (0xf90);
- o1 |= p->from.reg << 16;
- o1 |= p->reg << 0;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
- case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- o2 = olhr(0, REGTMP, p->to.reg, p->scond);
- if(p->as == AMOVB || p->as == AMOVBS)
- o2 ^= (1<<5)|(1<<6);
- else if(p->as == AMOVH || p->as == AMOVHS)
- o2 ^= (1<<6);
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
- }
- break;
- case 94: /* movh/movhu R,addr -> strh */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- o2 = oshr(p->from.reg, 0, REGTMP, p->scond);
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
- }
- break;
- case 95: /* PLD off(reg) */
- o1 = 0xf5d0f000;
- o1 |= p->from.reg << 16;
- if(p->from.offset < 0) {
- o1 &= ~(1 << 23);
- o1 |= (-p->from.offset) & 0xfff;
- } else
- o1 |= p->from.offset & 0xfff;
- break;
- case 96: /* UNDEF */
- // This is supposed to be something that stops execution.
- // It's not supposed to be reached, ever, but if it is, we'd
- // like to be able to tell how we got there. Assemble as
- // 0xf7fabcfd which is guranteed to raise undefined instruction
- // exception.
- o1 = 0xf7fabcfd;
- break;
- case 97: /* CLZ Rm, Rd */
- o1 = oprrr(p->as, p->scond);
- o1 |= p->to.reg << 12;
- o1 |= p->from.reg;
- break;
- case 98: /* MULW{T,B} Rs, Rm, Rd */
- o1 = oprrr(p->as, p->scond);
- o1 |= p->to.reg << 16;
- o1 |= p->from.reg << 8;
- o1 |= p->reg;
- break;
- case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
- o1 = oprrr(p->as, p->scond);
- o1 |= p->to.reg << 12;
- o1 |= p->from.reg << 8;
- o1 |= p->reg;
- o1 |= p->to.offset << 16;
- break;
- }
-
- out[0] = o1;
- out[1] = o2;
- out[2] = o3;
- out[3] = o4;
- out[4] = o5;
- out[5] = o6;
- return;
-
-#ifdef NOTDEF
- v = p->pc;
- switch(o->size) {
- default:
- if(debug['a'])
- Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
- break;
- case 4:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
- lputl(o1);
- break;
- case 8:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p);
- lputl(o1);
- lputl(o2);
- break;
- case 12:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- break;
- case 16:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n",
- v, o1, o2, o3, o4, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- lputl(o4);
- break;
- case 20:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
- v, o1, o2, o3, o4, o5, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- lputl(o4);
- lputl(o5);
- break;
- case 24:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
- v, o1, o2, o3, o4, o5, o6, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- lputl(o4);
- lputl(o5);
- lputl(o6);
- break;
- }
-#endif
-}
-
-int32
-oprrr(int a, int sc)
-{
- int32 o;
-
- o = (sc & C_SCOND) << 28;
- if(sc & C_SBIT)
- o |= 1 << 20;
- if(sc & (C_PBIT|C_WBIT))
- diag(".P/.W on dp instruction");
- switch(a) {
- case AMULU:
- case AMUL: return o | (0x0<<21) | (0x9<<4);
- case AMULA: return o | (0x1<<21) | (0x9<<4);
- case AMULLU: return o | (0x4<<21) | (0x9<<4);
- case AMULL: return o | (0x6<<21) | (0x9<<4);
- case AMULALU: return o | (0x5<<21) | (0x9<<4);
- case AMULAL: return o | (0x7<<21) | (0x9<<4);
- case AAND: return o | (0x0<<21);
- case AEOR: return o | (0x1<<21);
- case ASUB: return o | (0x2<<21);
- case ARSB: return o | (0x3<<21);
- case AADD: return o | (0x4<<21);
- case AADC: return o | (0x5<<21);
- case ASBC: return o | (0x6<<21);
- case ARSC: return o | (0x7<<21);
- case ATST: return o | (0x8<<21) | (1<<20);
- case ATEQ: return o | (0x9<<21) | (1<<20);
- case ACMP: return o | (0xa<<21) | (1<<20);
- case ACMN: return o | (0xb<<21) | (1<<20);
- case AORR: return o | (0xc<<21);
- case AMOVB:
- case AMOVH:
- case AMOVW: return o | (0xd<<21);
- case ABIC: return o | (0xe<<21);
- case AMVN: return o | (0xf<<21);
- case ASLL: return o | (0xd<<21) | (0<<5);
- case ASRL: return o | (0xd<<21) | (1<<5);
- case ASRA: return o | (0xd<<21) | (2<<5);
- case ASWI: return o | (0xf<<24);
-
- case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4);
- case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4);
- case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4);
- case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4);
- case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4);
- case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4);
- case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4);
- case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4);
- case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4);
- case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4);
- case AABSD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (0xc<<4);
- case AABSF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (0xc<<4);
- case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4);
- case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4);
-
- case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4);
- case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4);
-
- case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
- (1<<8); // dtof
- case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
- (0<<8); // dtof
-
- case AMOVWF:
- if((sc & C_UBIT) == 0)
- o |= 1<<7; /* signed */
- return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
- (0<<18) | (0<<8); // toint, double
- case AMOVWD:
- if((sc & C_UBIT) == 0)
- o |= 1<<7; /* signed */
- return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
- (0<<18) | (1<<8); // toint, double
-
- case AMOVFW:
- if((sc & C_UBIT) == 0)
- o |= 1<<16; /* signed */
- return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
- (1<<18) | (0<<8) | (1<<7); // toint, double, trunc
- case AMOVDW:
- if((sc & C_UBIT) == 0)
- o |= 1<<16; /* signed */
- return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
- (1<<18) | (1<<8) | (1<<7); // toint, double, trunc
-
- case AMOVWF+AEND: // copy WtoF
- return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4);
- case AMOVFW+AEND: // copy FtoW
- return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
- case ACMP+AEND: // cmp imm
- return o | (0x3<<24) | (0x5<<20);
-
- case ACLZ:
- // CLZ doesn't support .S
- return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4);
-
- case AMULWT:
- return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4);
- case AMULWB:
- return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4);
- case AMULAWT:
- return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4);
- case AMULAWB:
- return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4);
-
- case ABL: // BLX REG
- return (o & (0xf<<28)) | (0x12fff3 << 4);
- }
- diag("bad rrr %d", a);
- prasm(curp);
- return 0;
-}
-
-int32
-opbra(int a, int sc)
-{
-
- if(sc & (C_SBIT|C_PBIT|C_WBIT))
- diag(".S/.P/.W on bra instruction");
- sc &= C_SCOND;
- if(a == ABL)
- return (sc<<28)|(0x5<<25)|(0x1<<24);
- if(sc != 0xe)
- diag(".COND on bcond instruction");
- switch(a) {
- case ABEQ: return (0x0<<28)|(0x5<<25);
- case ABNE: return (0x1<<28)|(0x5<<25);
- case ABCS: return (0x2<<28)|(0x5<<25);
- case ABHS: return (0x2<<28)|(0x5<<25);
- case ABCC: return (0x3<<28)|(0x5<<25);
- case ABLO: return (0x3<<28)|(0x5<<25);
- case ABMI: return (0x4<<28)|(0x5<<25);
- case ABPL: return (0x5<<28)|(0x5<<25);
- case ABVS: return (0x6<<28)|(0x5<<25);
- case ABVC: return (0x7<<28)|(0x5<<25);
- case ABHI: return (0x8<<28)|(0x5<<25);
- case ABLS: return (0x9<<28)|(0x5<<25);
- case ABGE: return (0xa<<28)|(0x5<<25);
- case ABLT: return (0xb<<28)|(0x5<<25);
- case ABGT: return (0xc<<28)|(0x5<<25);
- case ABLE: return (0xd<<28)|(0x5<<25);
- case AB: return (0xe<<28)|(0x5<<25);
- }
- diag("bad bra %A", a);
- prasm(curp);
- return 0;
-}
-
int32
-olr(int32 v, int b, int r, int sc)
-{
- int32 o;
-
- if(sc & C_SBIT)
- diag(".S on LDR/STR instruction");
- o = (sc & C_SCOND) << 28;
- if(!(sc & C_PBIT))
- o |= 1 << 24;
- if(!(sc & C_UBIT))
- o |= 1 << 23;
- if(sc & C_WBIT)
- o |= 1 << 21;
- o |= (1<<26) | (1<<20);
- if(v < 0) {
- if(sc & C_UBIT) diag(".U on neg offset");
- v = -v;
- o ^= 1 << 23;
- }
- if(v >= (1<<12) || v < 0)
- diag("literal span too large: %d (R%d)\n%P", v, b, PP);
- o |= v;
- o |= b << 16;
- o |= r << 12;
- return o;
-}
-
-int32
-olhr(int32 v, int b, int r, int sc)
-{
- int32 o;
-
- if(sc & C_SBIT)
- diag(".S on LDRH/STRH instruction");
- o = (sc & C_SCOND) << 28;
- if(!(sc & C_PBIT))
- o |= 1 << 24;
- if(sc & C_WBIT)
- o |= 1 << 21;
- o |= (1<<23) | (1<<20)|(0xb<<4);
- if(v < 0) {
- v = -v;
- o ^= 1 << 23;
- }
- if(v >= (1<<8) || v < 0)
- diag("literal span too large: %d (R%d)\n%P", v, b, PP);
- o |= (v&0xf)|((v>>4)<<8)|(1<<22);
- o |= b << 16;
- o |= r << 12;
- return o;
-}
-
-int32
-osr(int a, int r, int32 v, int b, int sc)
-{
- int32 o;
-
- o = olr(v, b, r, sc) ^ (1<<20);
- if(a != AMOVW)
- o |= 1<<22;
- return o;
-}
-
-int32
-oshr(int r, int32 v, int b, int sc)
-{
- int32 o;
-
- o = olhr(v, b, r, sc) ^ (1<<20);
- return o;
-}
-
-
-int32
-osrr(int r, int i, int b, int sc)
-{
-
- return olr(i, b, r, sc) ^ ((1<<25) | (1<<20));
-}
-
-int32
-oshrr(int r, int i, int b, int sc)
-{
- return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20));
-}
-
-int32
-olrr(int i, int b, int r, int sc)
-{
-
- return olr(i, b, r, sc) ^ (1<<25);
-}
-
-int32
-olhrr(int i, int b, int r, int sc)
-{
- return olhr(i, b, r, sc) ^ (1<<22);
-}
-
-int32
-ofsr(int a, int r, int32 v, int b, int sc, Prog *p)
-{
- int32 o;
-
- if(sc & C_SBIT)
- diag(".S on FLDR/FSTR instruction");
- o = (sc & C_SCOND) << 28;
- if(!(sc & C_PBIT))
- o |= 1 << 24;
- if(sc & C_WBIT)
- o |= 1 << 21;
- o |= (6<<25) | (1<<24) | (1<<23) | (10<<8);
- if(v < 0) {
- v = -v;
- o ^= 1 << 23;
- }
- if(v & 3)
- diag("odd offset for floating point op: %d\n%P", v, p);
- else
- if(v >= (1<<10) || v < 0)
- diag("literal span too large: %d\n%P", v, p);
- o |= (v>>2) & 0xFF;
- o |= b << 16;
- o |= r << 12;
-
- switch(a) {
- default:
- diag("bad fst %A", a);
- case AMOVD:
- o |= 1 << 8;
- case AMOVF:
- break;
- }
- return o;
-}
-
-int32
-omvl(Prog *p, Adr *a, int dr)
-{
- int32 v, o1;
- if(!p->cond) {
- aclass(a);
- v = immrot(~instoffset);
- if(v == 0) {
- diag("missing literal");
- prasm(p);
- return 0;
- }
- o1 = oprrr(AMVN, p->scond&C_SCOND);
- o1 |= v;
- o1 |= dr << 12;
- } else {
- v = p->cond->pc - p->pc - 8;
- o1 = olr(v, REGPC, dr, p->scond&C_SCOND);
- }
- return o1;
-}
-
-int
-chipzero(Ieee *e)
-{
- // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
- if(goarm < 7 || e->l != 0 || e->h != 0)
- return -1;
- return 0;
-}
-
-int
-chipfloat(Ieee *e)
-{
- int n;
- ulong h;
-
- // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
- if(goarm < 7)
- goto no;
-
- if(e->l != 0 || (e->h&0xffff) != 0)
- goto no;
- h = e->h & 0x7fc00000;
- if(h != 0x40000000 && h != 0x3fc00000)
- goto no;
- n = 0;
-
- // sign bit (a)
- if(e->h & 0x80000000)
- n |= 1<<7;
-
- // exp sign bit (b)
- if(h == 0x3fc00000)
- n |= 1<<6;
-
- // rest of exp and mantissa (cd-efgh)
- n |= (e->h >> 16) & 0x3f;
-
-//print("match %.8lux %.8lux %d\n", e->l, e->h, n);
- return n;
-
-no:
- return -1;
+rnd(int32 v, int32 r)
+{
+ int32 c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
}
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index ae4b05ba1..25f581047 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -31,6 +31,7 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
+#include <link.h>
#include "5.out.h"
enum
@@ -51,167 +52,13 @@ enum
#define dynptrsize 0
-typedef struct Adr Adr;
-typedef struct Sym Sym;
-typedef struct Autom Auto;
-typedef struct Prog Prog;
-typedef struct Reloc Reloc;
-typedef struct Optab Optab;
-typedef struct Oprang Oprang;
-typedef uchar Opcross[32][2][32];
-typedef struct Count Count;
-
#define P ((Prog*)0)
-#define S ((Sym*)0)
-#define TNAME (cursym?cursym->name:noname)
-
-struct Adr
-{
- union
- {
- struct {
- int32 u0offset;
- int32 u0offset2; // argsize
- } u0off;
- char* u0sval;
- Ieee u0ieee;
- char* u0sbig;
- } u0;
- Sym* sym;
- Sym* gotype;
- char type;
- char reg;
- char name;
- char class;
-};
-
-#define offset u0.u0off.u0offset
-#define offset2 u0.u0off.u0offset2
-#define sval u0.u0sval
-#define scon sval
-#define ieee u0.u0ieee
-#define sbig u0.u0sbig
-
-struct Reloc
-{
- int32 off;
- uchar siz;
- uchar done;
- int16 type;
- int32 add;
- int32 xadd;
- Sym* sym;
- Sym* xsym;
-};
-
-struct Prog
-{
- Adr from;
- Adr to;
- union
- {
- int32 u0regused;
- Prog* u0forwd;
- } u0;
- Prog* cond;
- Prog* link;
- Prog* pcrel;
- int32 pc;
- int32 line;
- int32 spadj;
- uchar mark;
- uchar optab;
- uchar as;
- uchar scond;
- uchar reg;
- uchar align; // unused
-};
-
-#define regused u0.u0regused
-#define forwd u0.u0forwd
-#define datasize reg
-#define textflag reg
-
-#define iscall(p) ((p)->as == ABL)
-
-struct Sym
-{
- char* name;
- char* extname; // name used in external object files
- short type;
- short version;
- uchar dupok;
- uchar reachable;
- uchar cgoexport;
- uchar leaf;
- int32 dynid;
- int32 plt;
- int32 got;
- int32 value;
- int32 sig;
- int32 size;
- int32 align; // if non-zero, required alignment in bytes
- int32 elfsym;
- int32 locals; // size of stack frame locals area
- int32 args; // size of stack frame incoming arguments area
- uchar special;
- uchar fnptr; // used as fn ptr
- uchar stkcheck;
- uchar hide;
- Sym* hash; // in hash table
- Sym* allsym; // in all symbol list
- Sym* next; // in text or data list
- Sym* sub; // in SSUB list
- Sym* outer; // container of sub
- Sym* gotype;
- Sym* reachparent;
- Sym* queue;
- char* file;
- char* dynimplib;
- char* dynimpvers;
- struct Section* sect;
- struct Hist* hist;
-
- // STEXT
- Auto* autom;
- Prog* text;
-
- // SDATA, SBSS
- uchar* p;
- int32 np;
- int32 maxp;
- Reloc* r;
- int32 nr;
- int32 maxr;
-};
+#define S ((LSym*)0)
+#define TNAME (ctxt->cursym?ctxt->cursym->name:noname)
#define SIGNINTERN (1729*325*1729)
-struct Autom
-{
- Sym* asym;
- Auto* link;
- int32 aoffset;
- short type;
- Sym* gotype;
-};
-struct Optab
-{
- char as;
- uchar a1;
- char a2;
- uchar a3;
- uchar type;
- char size;
- char param;
- char flag;
- uchar pcrelsiz;
-};
-struct Oprang
-{
- Optab* start;
- Optab* stop;
-};
+typedef struct Count Count;
struct Count
{
int32 count;
@@ -220,10 +67,17 @@ struct Count
enum
{
- LFROM = 1<<0,
- LTO = 1<<1,
- LPOOL = 1<<2,
- LPCREL = 1<<3,
+/* mark flags */
+ FOLL = 1<<0,
+ LABEL = 1<<1,
+ LEAF = 1<<2,
+
+ STRINGSZ = 200,
+ MINSIZ = 64,
+ NENT = 100,
+ MAXIO = 8192,
+ MAXHIST = 40, /* limit of path elements for history symbols */
+ MINLC = 4,
C_NONE = 0,
C_REG,
@@ -260,7 +114,7 @@ enum
C_HFOREG,
C_SOREG,
C_ROREG,
- C_SROREG, /* both S and R */
+ C_SROREG, /* both nil and R */
C_LOREG,
C_PC,
@@ -270,179 +124,61 @@ enum
C_ADDR, /* reference to relocatable address */
C_GOK,
-
-/* mark flags */
- FOLL = 1<<0,
- LABEL = 1<<1,
- LEAF = 1<<2,
-
- STRINGSZ = 200,
- MINSIZ = 64,
- NENT = 100,
- MAXIO = 8192,
- MAXHIST = 40, /* limit of path elements for history symbols */
- MINLC = 4,
};
#ifndef COFFCVT
-EXTERN int32 HEADR; /* length of header */
-EXTERN int HEADTYPE; /* type of header */
-EXTERN int32 INITDAT; /* data location */
-EXTERN int32 INITRND; /* data round above text location */
-EXTERN int32 INITTEXT; /* text location */
-EXTERN char* INITENTRY; /* entry point */
EXTERN int32 autosize;
-EXTERN Auto* curauto;
-EXTERN Auto* curhist;
-EXTERN Prog* curp;
-EXTERN Sym* cursym;
-EXTERN Sym* datap;
+EXTERN LSym* datap;
EXTERN int debug[128];
-EXTERN Sym* etextp;
EXTERN char* noname;
EXTERN Prog* lastp;
EXTERN int32 lcsize;
EXTERN char literal[32];
EXTERN int nerrors;
EXTERN int32 instoffset;
-EXTERN Opcross opcross[8];
-EXTERN Oprang oprange[ALAST];
-EXTERN char* outfile;
-EXTERN int32 pc;
-EXTERN uchar repop[ALAST];
-EXTERN char* interpreter;
EXTERN char* rpath;
EXTERN uint32 stroffset;
EXTERN int32 symsize;
-EXTERN Sym* textp;
-EXTERN char xcmp[C_GOK+1][C_GOK+1];
-EXTERN Prog zprg;
-EXTERN int dtype;
-EXTERN int tlsoffset;
EXTERN int armsize;
-EXTERN int goarm;
-EXTERN Sym* adrgotype; // type symbol on last Adr read
-EXTERN Sym* fromgotype; // type symbol on last p->from read
-
-extern char* anames[];
-extern Optab optab[];
-
-void addpool(Prog*, Adr*);
-EXTERN Prog* blitrl;
-EXTERN Prog* elitrl;
-
-EXTERN int goarm;
-
-void initdiv(void);
-EXTERN Prog* prog_div;
-EXTERN Prog* prog_divu;
-EXTERN Prog* prog_mod;
-EXTERN Prog* prog_modu;
#pragma varargck type "A" int
#pragma varargck type "C" int
-#pragma varargck type "D" Adr*
+#pragma varargck type "D" Addr*
#pragma varargck type "I" uchar*
-#pragma varargck type "N" Adr*
+#pragma varargck type "N" Addr*
#pragma varargck type "P" Prog*
#pragma varargck type "S" char*
#pragma varargck type "Z" char*
#pragma varargck type "i" char*
-int Aconv(Fmt*);
-int Cconv(Fmt*);
-int Dconv(Fmt*);
-int Iconv(Fmt*);
-int Nconv(Fmt*);
-int Oconv(Fmt*);
-int Pconv(Fmt*);
-int Sconv(Fmt*);
-int aclass(Adr*);
-void addhist(int32, int);
-Prog* appendp(Prog*);
+int Aconv(Fmt *fp);
+int Cconv(Fmt *fp);
+int Dconv(Fmt *fp);
+int Iconv(Fmt *fp);
+int Nconv(Fmt *fp);
+int Oconv(Fmt *fp);
+int Pconv(Fmt *fp);
+int Sconv(Fmt *fp);
+void adddynlib(char *lib);
+void adddynrel(LSym *s, Reloc *r);
+void adddynrela(LSym *rel, LSym *s, Reloc *r);
+void adddynsym(Link *ctxt, LSym *s);
+int archreloc(Reloc *r, LSym *s, vlong *val);
void asmb(void);
-void asmout(Prog*, Optab*, int32*, Sym*);
-int32 atolwhex(char*);
-Prog* brloop(Prog*);
-void buildop(void);
-void buildrep(int, int);
-void cflush(void);
-int chipzero(Ieee*);
-int chipfloat(Ieee*);
-int cmp(int, int);
-int compound(Prog*);
-double cputime(void);
-void diag(char*, ...);
-void divsig(void);
-void dodata(void);
-void doprof1(void);
-void doprof2(void);
-int32 entryvalue(void);
-void exchange(Prog*);
-void follow(void);
-void hputl(int);
-int isnop(Prog*);
+void cput(int32 c);
+void diag(char *fmt, ...);
+int elfreloc1(Reloc *r, vlong sectoff);
+void elfsetupplt(void);
+void hput(int32 l);
void listinit(void);
-Sym* lookup(char*, int);
-void cput(int);
-void hput(int32);
-void lput(int32);
-void lputb(int32);
-void lputl(int32);
-void* mysbrk(uint32);
-void names(void);
-void nocache(Prog*);
-int ocmp(const void*, const void*);
-int32 opirr(int);
-Optab* oplook(Prog*);
-int32 oprrr(int, int);
-int32 olr(int32, int, int, int);
-int32 olhr(int32, int, int, int);
-int32 olrr(int, int, int, int);
-int32 olhrr(int, int, int, int);
-int32 osr(int, int, int32, int, int);
-int32 oshr(int, int32, int, int);
-int32 ofsr(int, int, int32, int, int, Prog*);
-int32 osrr(int, int, int, int);
-int32 oshrr(int, int, int, int);
-int32 omvl(Prog*, Adr*, int);
-void patch(void);
-void prasm(Prog*);
-void prepend(Prog*, Prog*);
-Prog* prg(void);
-int pseudo(Prog*);
-int32 regoff(Adr*);
-int relinv(int);
-int32 rnd(int32, int32);
-void softfloat(void);
-void span(void);
-void strnput(char*, int);
-int32 symaddr(Sym*);
-void undef(void);
-void vputb(uint64);
-void vputl(uint64);
-void wputb(uint16);
-void wput(int32);
-void wputl(ushort w);
-void xdefine(char*, int, int32);
+void lput(int32 l);
+int machoreloc1(Reloc *r, vlong sectoff);
+void main(int argc, char *argv[]);
void noops(void);
-int32 immrot(uint32);
-int32 immaddr(int32);
-int32 opbra(int, int);
-int brextra(Prog*);
-int isbranch(Prog*);
-void doelf(void);
-void dozerostk(void); // used by -Z
-
-vlong addaddr(Sym *s, Sym *t);
-vlong addsize(Sym *s, Sym *t);
-vlong addstring(Sym *s, char *str);
-vlong adduint16(Sym *s, uint16 v);
-vlong adduint32(Sym *s, uint32 v);
-vlong adduint64(Sym *s, uint64 v);
-vlong adduint8(Sym *s, uint8 v);
-vlong adduintxx(Sym *s, uint64 v, int wid);
+void nopstat(char *f, Count *c);
+int32 rnd(int32 v, int32 r);
+void wput(int32 l);
/* Native is little-endian */
#define LPUT(a) lputl(a)
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
index 7502a3b81..02a957579 100644
--- a/src/cmd/5l/list.c
+++ b/src/cmd/5l/list.c
@@ -47,11 +47,7 @@ listinit(void)
fmtinstall('I', Iconv);
}
-void
-prasm(Prog *p)
-{
- print("%P\n", p);
-}
+static Prog *curp;
int
Pconv(Fmt *fp)
@@ -64,7 +60,7 @@ Pconv(Fmt *fp)
a = p->as;
switch(a) {
default:
- fmtprint(fp, "(%d)", p->line);
+ fmtprint(fp, "(%d)", p->lineno);
if(p->reg == NREG && p->as != AGLOBL)
fmtprint(fp, " %A%C %D,%D",
a, p->scond, &p->from, &p->to);
@@ -80,22 +76,22 @@ Pconv(Fmt *fp)
case ASWPW:
case ASWPBU:
fmtprint(fp, "(%d) %A%C R%d,%D,%D",
- p->line, a, p->scond, p->reg, &p->from, &p->to);
+ p->lineno, a, p->scond, p->reg, &p->from, &p->to);
break;
case ADATA:
case AINIT_:
case ADYNT_:
fmtprint(fp, "(%d) %A%C %D/%d,%D",
- p->line, a, p->scond, &p->from, p->reg, &p->to);
+ p->lineno, a, p->scond, &p->from, p->reg, &p->to);
break;
case AWORD:
- fmtprint(fp, "(%d) WORD %D", p->line, &p->to);
+ fmtprint(fp, "(%d) WORD %D", p->lineno, &p->to);
break;
case ADWORD:
- fmtprint(fp, "(%d) DWORD %D %D", p->line, &p->from, &p->to);
+ fmtprint(fp, "(%d) DWORD %D %D", p->lineno, &p->from, &p->to);
break;
}
@@ -114,7 +110,7 @@ Aconv(Fmt *fp)
a = va_arg(fp->args, int);
s = "???";
if(a >= AXXX && a < ALAST)
- s = anames[a];
+ s = anames5[a];
return fmtstrcpy(fp, s);
}
@@ -162,10 +158,10 @@ Dconv(Fmt *fp)
{
char str[STRINGSZ];
const char *op;
- Adr *a;
+ Addr *a;
int32 v;
- a = va_arg(fp->args, Adr*);
+ a = va_arg(fp->args, Addr*);
switch(a->type) {
default:
@@ -271,8 +267,8 @@ Dconv(Fmt *fp)
break;
case D_BRANCH: /* botch */
- if(curp->cond != P) {
- v = curp->cond->pc;
+ if(curp->pcond != P) {
+ v = curp->pcond->pc;
if(a->sym != S)
snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v);
else
@@ -285,11 +281,11 @@ Dconv(Fmt *fp)
break;
case D_FCONST:
- snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee));
+ snprint(str, sizeof str, "$%.17g", a->u.dval);
break;
case D_SCONST:
- snprint(str, sizeof str, "$\"%S\"", a->sval);
+ snprint(str, sizeof str, "$\"%S\"", a->u.sval);
break;
}
return fmtstrcpy(fp, str);
@@ -299,10 +295,10 @@ int
Nconv(Fmt *fp)
{
char str[STRINGSZ];
- Adr *a;
- Sym *s;
+ Addr *a;
+ LSym *s;
- a = va_arg(fp->args, Adr*);
+ a = va_arg(fp->args, Addr*);
s = a->sym;
switch(a->name) {
default:
@@ -478,8 +474,8 @@ diag(char *fmt, ...)
tn = "";
sep = "";
- if(cursym != S) {
- tn = cursym->name;
+ if(ctxt->cursym != S) {
+ tn = ctxt->cursym->name;
sep = ": ";
}
va_start(arg, fmt);
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
index 305ed684e..d42c86289 100644
--- a/src/cmd/5l/noop.c
+++ b/src/cmd/5l/noop.c
@@ -32,677 +32,12 @@
#include "l.h"
#include "../ld/lib.h"
-#include "../../pkg/runtime/stack.h"
-
-static Sym* sym_div;
-static Sym* sym_divu;
-static Sym* sym_mod;
-static Sym* sym_modu;
-static Sym* symmorestack;
-static Prog* pmorestack;
-
-static Prog* stacksplit(Prog*, int32);
-
-static void
-linkcase(Prog *casep)
-{
- Prog *p;
-
- for(p = casep; p != P; p = p->link){
- if(p->as == ABCASE) {
- for(; p != P && p->as == ABCASE; p = p->link)
- p->pcrel = casep;
- break;
- }
- }
-}
void
noops(void)
{
- Prog *p, *q, *q1, *q2;
- int o;
- Sym *tlsfallback, *gmsym;
-
- /*
- * find leaf subroutines
- * strip NOPs
- * expand RET
- * expand BECOME pseudo
- * fixup TLS
- */
-
- if(debug['v'])
- Bprint(&bso, "%5.2f noops\n", cputime());
- Bflush(&bso);
-
- symmorestack = lookup("runtime.morestack", 0);
- if(symmorestack->type != STEXT) {
- diag("runtime·morestack not defined");
- errorexit();
- }
- pmorestack = symmorestack->text;
- pmorestack->reg |= NOSPLIT;
-
- tlsfallback = lookup("runtime.read_tls_fallback", 0);
- gmsym = S;
- if(linkmode == LinkExternal)
- gmsym = lookup("runtime.tlsgm", 0);
- q = P;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- switch(p->as) {
- case ACASE:
- if(flag_shared)
- linkcase(p);
- break;
-
- case ATEXT:
- p->mark |= LEAF;
- break;
-
- case ARET:
- break;
-
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- q = p;
- if(prog_div == P)
- initdiv();
- cursym->text->mark &= ~LEAF;
- continue;
-
- case ANOP:
- q1 = p->link;
- q->link = q1; /* q is non-nop */
- if(q1 != P)
- q1->mark |= p->mark;
- continue;
-
- case ABL:
- case ABX:
- cursym->text->mark &= ~LEAF;
-
- case ABCASE:
- case AB:
-
- case ABEQ:
- case ABNE:
- case ABCS:
- case ABHS:
- case ABCC:
- case ABLO:
- case ABMI:
- case ABPL:
- case ABVS:
- case ABVC:
- case ABHI:
- case ABLS:
- case ABGE:
- case ABLT:
- case ABGT:
- case ABLE:
- q1 = p->cond;
- if(q1 != P) {
- while(q1->as == ANOP) {
- q1 = q1->link;
- p->cond = q1;
- }
- }
- break;
- case AWORD:
- // Rewrite TLS register fetch: MRC 15, 0, <reg>, C13, C0, 3
- if((p->to.offset & 0xffff0fff) == 0xee1d0f70) {
- if(HEADTYPE == Hopenbsd) {
- p->as = ARET;
- } else if(goarm < 7) {
- if(tlsfallback->type != STEXT) {
- diag("runtime·read_tls_fallback not defined");
- errorexit();
- }
- // BL runtime.read_tls_fallback(SB)
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->to.sym = tlsfallback;
- p->cond = tlsfallback->text;
- p->to.offset = 0;
- cursym->text->mark &= ~LEAF;
- }
- if(linkmode == LinkExternal) {
- // runtime.tlsgm is relocated with R_ARM_TLS_LE32
- // and $runtime.tlsgm will contain the TLS offset.
- //
- // MOV $runtime.tlsgm+tlsoffset(SB), REGTMP
- // ADD REGTMP, <reg>
- //
- // In shared mode, runtime.tlsgm is relocated with
- // R_ARM_TLS_IE32 and runtime.tlsgm(SB) will point
- // to the GOT entry containing the TLS offset.
- //
- // MOV runtime.tlsgm(SB), REGTMP
- // ADD REGTMP, <reg>
- // SUB -tlsoffset, <reg>
- //
- // The SUB compensates for tlsoffset
- // used in runtime.save_gm and runtime.load_gm.
- q = p;
- p = appendp(p);
- p->as = AMOVW;
- p->scond = 14;
- p->reg = NREG;
- if(flag_shared) {
- p->from.type = D_OREG;
- p->from.offset = 0;
- } else {
- p->from.type = D_CONST;
- p->from.offset = tlsoffset;
- }
- p->from.sym = gmsym;
- p->from.name = D_EXTERN;
- p->to.type = D_REG;
- p->to.reg = REGTMP;
- p->to.offset = 0;
-
- p = appendp(p);
- p->as = AADD;
- p->scond = 14;
- p->reg = NREG;
- p->from.type = D_REG;
- p->from.reg = REGTMP;
- p->to.type = D_REG;
- p->to.reg = (q->to.offset & 0xf000) >> 12;
- p->to.offset = 0;
-
- if(flag_shared) {
- p = appendp(p);
- p->as = ASUB;
- p->scond = 14;
- p->reg = NREG;
- p->from.type = D_CONST;
- p->from.offset = -tlsoffset;
- p->to.type = D_REG;
- p->to.reg = (q->to.offset & 0xf000) >> 12;
- p->to.offset = 0;
- }
- }
- }
- }
- q = p;
- }
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- o = p->as;
- switch(o) {
- case ATEXT:
- autosize = p->to.offset + 4;
- if(autosize <= 4)
- if(cursym->text->mark & LEAF) {
- p->to.offset = -4;
- autosize = 0;
- }
-
- if(!autosize && !(cursym->text->mark & LEAF)) {
- if(debug['v'])
- Bprint(&bso, "save suppressed in: %s\n",
- cursym->name);
- Bflush(&bso);
- cursym->text->mark |= LEAF;
- }
- if(cursym->text->mark & LEAF) {
- cursym->leaf = 1;
- if(!autosize)
- break;
- }
-
- if(!(p->reg & NOSPLIT))
- p = stacksplit(p, autosize); // emit split check
-
- // MOVW.W R14,$-autosize(SP)
- p = appendp(p);
- p->as = AMOVW;
- p->scond |= C_WBIT;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_OREG;
- p->to.offset = -autosize;
- p->to.reg = REGSP;
- p->spadj = autosize;
-
- if(cursym->text->reg & WRAPPER) {
- // g->panicwrap += autosize;
- // MOVW panicwrap_offset(g), R3
- // ADD $autosize, R3
- // MOVW R3 panicwrap_offset(g)
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.reg = REGG;
- p->from.offset = 2*PtrSize;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- p = appendp(p);
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = autosize;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = 3;
- p->to.type = D_OREG;
- p->to.reg = REGG;
- p->to.offset = 2*PtrSize;
- }
- break;
-
- case ARET:
- nocache(p);
- if(cursym->text->mark & LEAF) {
- if(!autosize) {
- p->as = AB;
- p->from = zprg.from;
- if(p->to.sym) { // retjmp
- p->to.type = D_BRANCH;
- p->cond = p->to.sym->text;
- } else {
- p->to.type = D_OREG;
- p->to.offset = 0;
- p->to.reg = REGLINK;
- }
- break;
- }
- }
-
- if(cursym->text->reg & WRAPPER) {
- int cond;
-
- // Preserve original RET's cond, to allow RET.EQ
- // in the implementation of reflect.call.
- cond = p->scond;
- p->scond = C_SCOND_NONE;
-
- // g->panicwrap -= autosize;
- // MOVW panicwrap_offset(g), R3
- // SUB $autosize, R3
- // MOVW R3 panicwrap_offset(g)
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.reg = REGG;
- p->from.offset = 2*PtrSize;
- p->to.type = D_REG;
- p->to.reg = 3;
- p = appendp(p);
-
- p->as = ASUB;
- p->from.type = D_CONST;
- p->from.offset = autosize;
- p->to.type = D_REG;
- p->to.reg = 3;
- p = appendp(p);
-
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = 3;
- p->to.type = D_OREG;
- p->to.reg = REGG;
- p->to.offset = 2*PtrSize;
- p = appendp(p);
-
- p->scond = cond;
- }
-
- p->as = AMOVW;
- p->scond |= C_PBIT;
- p->from.type = D_OREG;
- p->from.offset = autosize;
- p->from.reg = REGSP;
- p->to.type = D_REG;
- p->to.reg = REGPC;
- // If there are instructions following
- // this ARET, they come from a branch
- // with the same stackframe, so no spadj.
-
- if(p->to.sym) { // retjmp
- p->to.reg = REGLINK;
- q2 = appendp(p);
- q2->as = AB;
- q2->to.type = D_BRANCH;
- q2->to.sym = p->to.sym;
- q2->cond = p->to.sym->text;
- p->to.sym = nil;
- p = q2;
- }
- break;
-
- case AADD:
- if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
- p->spadj = -p->from.offset;
- break;
-
- case ASUB:
- if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
- p->spadj = p->from.offset;
- break;
-
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- if(debug['M'])
- break;
- if(p->from.type != D_REG)
- break;
- if(p->to.type != D_REG)
- break;
- q1 = p;
-
- /* MOV a,4(SP) */
- p = appendp(p);
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = q1->from.reg;
- p->to.type = D_OREG;
- p->to.reg = REGSP;
- p->to.offset = 4;
-
- /* MOV b,REGTMP */
- p = appendp(p);
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = q1->reg;
- if(q1->reg == NREG)
- p->from.reg = q1->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGTMP;
- p->to.offset = 0;
-
- /* CALL appropriate */
- p = appendp(p);
- p->as = ABL;
- p->line = q1->line;
- p->to.type = D_BRANCH;
- p->cond = p;
- switch(o) {
- case ADIV:
- p->cond = prog_div;
- p->to.sym = sym_div;
- break;
- case ADIVU:
- p->cond = prog_divu;
- p->to.sym = sym_divu;
- break;
- case AMOD:
- p->cond = prog_mod;
- p->to.sym = sym_mod;
- break;
- case AMODU:
- p->cond = prog_modu;
- p->to.sym = sym_modu;
- break;
- }
+ LSym *s;
- /* MOV REGTMP, b */
- p = appendp(p);
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = REGTMP;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = q1->to.reg;
-
- /* ADD $8,SP */
- p = appendp(p);
- p->as = AADD;
- p->line = q1->line;
- p->from.type = D_CONST;
- p->from.reg = NREG;
- p->from.offset = 8;
- p->reg = NREG;
- p->to.type = D_REG;
- p->to.reg = REGSP;
- p->spadj = -8;
-
- /* Keep saved LR at 0(SP) after SP change. */
- /* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */
- /* TODO: Remove SP adjustments; see issue 6699. */
- q1->as = AMOVW;
- q1->from.type = D_OREG;
- q1->from.reg = REGSP;
- q1->from.offset = 0;
- q1->reg = NREG;
- q1->to.type = D_REG;
- q1->to.reg = REGTMP;
-
- /* SUB $8,SP */
- q1 = appendp(q1);
- q1->as = AMOVW;
- q1->from.type = D_REG;
- q1->from.reg = REGTMP;
- q1->reg = NREG;
- q1->to.type = D_OREG;
- q1->to.reg = REGSP;
- q1->to.offset = -8;
- q1->scond |= C_WBIT;
- q1->spadj = 8;
-
- break;
- case AMOVW:
- if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
- p->spadj = -p->to.offset;
- if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
- p->spadj = -p->from.offset;
- if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
- p->spadj = -p->from.offset;
- break;
- }
- }
- }
-}
-
-static Prog*
-stacksplit(Prog *p, int32 framesize)
-{
- int32 arg;
-
- // MOVW g_stackguard(g), R1
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.reg = REGG;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- if(framesize <= StackSmall) {
- // small stack: SP < stackguard
- // CMP stackguard, SP
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->reg = REGSP;
- } else if(framesize <= StackBig) {
- // large stack: SP-framesize < stackguard-StackSmall
- // MOVW $-framesize(SP), R2
- // CMP stackguard, R2
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.reg = REGSP;
- p->from.offset = -framesize;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->reg = 2;
- } else {
- // Such a large stack we need to protect against wraparound
- // if SP is close to zero.
- // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
- // The +StackGuard on both sides is required to keep the left side positive:
- // SP is allowed to be slightly below stackguard. See stack.h.
- // CMP $StackPreempt, R1
- // MOVW.NE $StackGuard(SP), R2
- // SUB.NE R1, R2
- // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
- // CMP.NE R3, R2
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_CONST;
- p->from.offset = (uint32)StackPreempt;
- p->reg = 1;
-
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.reg = REGSP;
- p->from.offset = StackGuard;
- p->to.type = D_REG;
- p->to.reg = 2;
- p->scond = C_SCOND_NE;
-
- p = appendp(p);
- p->as = ASUB;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->to.type = D_REG;
- p->to.reg = 2;
- p->scond = C_SCOND_NE;
-
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.offset = framesize + (StackGuard - StackSmall);
- p->to.type = D_REG;
- p->to.reg = 3;
- p->scond = C_SCOND_NE;
-
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 3;
- p->reg = 2;
- p->scond = C_SCOND_NE;
- }
-
- // MOVW.LS $framesize, R1
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LS;
- p->from.type = D_CONST;
- p->from.offset = framesize;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // MOVW.LS $args, R2
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LS;
- p->from.type = D_CONST;
- arg = cursym->text->to.offset2;
- if(arg == 1) // special marker for known 0
- arg = 0;
- if(arg&3)
- diag("misaligned argument size in stack split");
- p->from.offset = arg;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- // MOVW.LS R14, R3
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LS;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted
- p = appendp(p);
- p->as = ABL;
- p->scond = C_SCOND_LS;
- p->to.type = D_BRANCH;
- p->to.sym = symmorestack;
- p->cond = pmorestack;
-
- // BLS start
- p = appendp(p);
- p->as = ABLS;
- p->to.type = D_BRANCH;
- p->cond = cursym->text->link;
-
- return p;
-}
-
-static void
-sigdiv(char *n)
-{
- Sym *s;
-
- s = lookup(n, 0);
- if(s->type == STEXT)
- if(s->sig == 0)
- s->sig = SIGNINTERN;
-}
-
-void
-divsig(void)
-{
- sigdiv("_div");
- sigdiv("_divu");
- sigdiv("_mod");
- sigdiv("_modu");
-}
-
-void
-initdiv(void)
-{
- Sym *s2, *s3, *s4, *s5;
-
- if(prog_div != P)
- return;
- sym_div = s2 = lookup("_div", 0);
- sym_divu = s3 = lookup("_divu", 0);
- sym_mod = s4 = lookup("_mod", 0);
- sym_modu = s5 = lookup("_modu", 0);
- prog_div = s2->text;
- prog_divu = s3->text;
- prog_mod = s4->text;
- prog_modu = s5->text;
- if(prog_div == P) {
- diag("undefined: %s", s2->name);
- prog_div = cursym->text;
- }
- if(prog_divu == P) {
- diag("undefined: %s", s3->name);
- prog_divu = cursym->text;
- }
- if(prog_mod == P) {
- diag("undefined: %s", s4->name);
- prog_mod = cursym->text;
- }
- if(prog_modu == P) {
- diag("undefined: %s", s5->name);
- prog_modu = cursym->text;
- }
-}
-
-void
-nocache(Prog *p)
-{
- p->optab = 0;
- p->from.class = 0;
- p->to.class = 0;
+ for(s = ctxt->textp; s != nil; s = s->next)
+ ctxt->arch->addstacksplit(ctxt, s);
}
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index 80f5787dc..96198f99c 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -30,120 +30,19 @@
// Reading object files.
-#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
#include "../ld/dwarf.h"
#include <ar.h>
-#ifndef DEFAULT
-#define DEFAULT '9'
-#endif
-
-char *noname = "<none>";
-char *thestring = "arm";
-
-Header headers[] = {
- "noheader", Hnoheader,
- "risc", Hrisc,
- "plan9", Hplan9x32,
- "ixp1200", Hixp1200,
- "ipaq", Hipaq,
- "linux", Hlinux,
- "freebsd", Hfreebsd,
- "netbsd", Hnetbsd,
- 0, 0
-};
-
-/*
- * -Hrisc -T0x10005000 -R4 is aif for risc os
- * -Hplan9 -T4128 -R4096 is plan9 format
- * -Hixp1200 is IXP1200 (raw)
- * -Hipaq -T0xC0008010 -R1024 is ipaq
- * -Hlinux -Tx -Rx is linux elf
- * -Hfreebsd is freebsd elf
- * -Hnetbsd is netbsd elf
- */
+char *thestring = "arm";
+LinkArch *thelinkarch = &linkarm;
void
-main(int argc, char *argv[])
+archinit(void)
{
- char *p;
- Sym *s;
-
- Binit(&bso, 1, OWRITE);
- listinit();
- nerrors = 0;
- outfile = "5.out";
- HEADTYPE = -1;
- INITTEXT = -1;
- INITDAT = -1;
- INITRND = -1;
- INITENTRY = 0;
- linkmode = LinkAuto;
- nuxiinit();
-
- p = getgoarm();
- if(p != nil)
- goarm = atoi(p);
- else
- goarm = 6;
- if(goarm == 5)
- debug['F'] = 1;
-
- flagcount("1", "use alternate profiling code", &debug['1']);
- flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
- flagstr("E", "sym: entry symbol", &INITENTRY);
- flagint32("D", "addr: data address", &INITDAT);
- flagcount("G", "debug pseudo-ops", &debug['G']);
- flagfn1("I", "interp: set ELF interp", setinterp);
- flagfn1("L", "dir: add dir to library path", Lflag);
- flagfn1("H", "head: header type", setheadtype);
- flagcount("K", "add stack underflow checks", &debug['K']);
- flagcount("M", "disable software div/mod", &debug['M']);
- flagcount("O", "print pc-line tables", &debug['O']);
- flagcount("P", "debug code generation", &debug['P']);
- flagint32("R", "rnd: address rounding", &INITRND);
- flagint32("T", "addr: text address", &INITTEXT);
- flagfn0("V", "print version and exit", doversion);
- flagcount("W", "disassemble input", &debug['W']);
- flagfn2("X", "name value: define string data", addstrdata);
- flagcount("Z", "clear stack frame on entry", &debug['Z']);
- flagcount("a", "disassemble output", &debug['a']);
- flagcount("c", "dump call graph", &debug['c']);
- flagcount("d", "disable dynamic executable", &debug['d']);
- flagstr("extld", "linker to run in external mode", &extld);
- flagstr("extldflags", "flags for external linker", &extldflags);
- flagcount("f", "ignore version mismatch", &debug['f']);
- flagcount("g", "disable go package data checks", &debug['g']);
- flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
- flagstr("k", "sym: set field tracking symbol", &tracksym);
- flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
- flagcount("n", "dump symbol table", &debug['n']);
- flagstr("o", "outfile: set output file", &outfile);
- flagcount("p", "insert profiling code", &debug['p']);
- flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
- flagcount("race", "enable race detector", &flag_race);
- flagcount("s", "disable symbol table", &debug['s']);
- flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared);
- flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
- flagcount("u", "reject unsafe packages", &debug['u']);
- flagcount("v", "print link trace", &debug['v']);
- flagcount("w", "disable DWARF generation", &debug['w']);
-
- flagparse(&argc, &argv, usage);
-
- if(argc != 1)
- usage();
-
- if(flag_shared)
- linkmode = LinkExternal;
-
- mywhatsys();
-
- if(HEADTYPE == -1)
- HEADTYPE = headtype(goos);
+ LSym *s;
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
// Go was built; see ../../make.bash.
@@ -161,31 +60,11 @@ main(int argc, char *argv[])
break;
}
- libinit();
-
switch(HEADTYPE) {
default:
diag("unknown -H option");
errorexit();
- case Hnoheader: /* no header */
- HEADR = 0L;
- if(INITTEXT == -1)
- INITTEXT = 0;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- break;
- case Hrisc: /* aif for risc os */
- HEADR = 128L;
- if(INITTEXT == -1)
- INITTEXT = 0x10005000 + HEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- break;
- case Hplan9x32: /* plan 9 */
+ case Hplan9: /* plan 9 */
HEADR = 32L;
if(INITTEXT == -1)
INITTEXT = 4128;
@@ -194,29 +73,11 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
- case Hixp1200: /* boot for IXP1200 */
- HEADR = 0L;
- if(INITTEXT == -1)
- INITTEXT = 0x0;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- break;
- case Hipaq: /* boot for ipaq */
- HEADR = 16L;
- if(INITTEXT == -1)
- INITTEXT = 0xC0008010;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 1024;
- break;
case Hlinux: /* arm elf */
case Hfreebsd:
case Hnetbsd:
debug['d'] = 0; // with dynamic linking
- tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m
+ ctxt->tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m
// this number is known to ../../pkg/runtime/rt0_*_arm.s
elfinit();
HEADR = ELFRESERVE;
@@ -231,578 +92,9 @@ main(int argc, char *argv[])
if(INITDAT != 0 && INITRND != 0)
print("warning: -D0x%ux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
- if(debug['v'])
- Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
- HEADTYPE, INITTEXT, INITDAT, INITRND);
- Bflush(&bso);
- zprg.as = AGOK;
- zprg.scond = 14;
- zprg.reg = NREG;
- zprg.from.name = D_NONE;
- zprg.from.type = D_NONE;
- zprg.from.reg = NREG;
- zprg.to = zprg.from;
- buildop();
- histgen = 0;
- pc = 0;
- dtype = 4;
-
- version = 0;
- cbp = buf.cbuf;
- cbc = sizeof(buf.cbuf);
// embed goarm to runtime.goarm
- s = lookup("runtime.goarm", 0);
+ s = linklookup(ctxt, "runtime.goarm", 0);
s->dupok = 1;
- adduint8(s, goarm);
-
- addlibpath("command line", "command line", argv[0], "main");
- loadlib();
-
- // mark some functions that are only referenced after linker code editing
- if(debug['F'])
- mark(rlookup("_sfloat", 0));
- mark(lookup("runtime.read_tls_fallback", 0));
- deadcode();
- if(textp == nil) {
- diag("no code");
- errorexit();
- }
-
- patch();
- if(debug['p'])
- if(debug['1'])
- doprof1();
- else
- doprof2();
- doelf();
- follow();
- softfloat();
- // 5l -Z means zero the stack frame on entry.
- // This slows down function calls but can help avoid
- // false positives in garbage collection.
- if(debug['Z'])
- dozerostk();
- noops(); // generate stack split prolog, handle div/mod, etc.
- dostkcheck();
- span();
- addexport();
- // textaddress() functionality is handled in span()
- pclntab();
- symtab();
- dodata();
- address();
- doweak();
- reloc();
- asmb();
- undef();
- hostlink();
-
- if(debug['c'])
- print("ARM size = %d\n", armsize);
- if(debug['v']) {
- Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
- Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
- }
- Bflush(&bso);
- errorexit();
-}
-
-static Sym*
-zsym(char *pn, Biobuf *f, Sym *h[])
-{
- int o;
-
- o = BGETC(f);
- if(o == 0)
- return S;
- if(o < 0 || o >= NSYM || h[o] == nil)
- mangle(pn);
- return h[o];
-}
-
-static void
-zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
-{
- int i, c;
- int32 l;
- Sym *s;
- Auto *u;
-
- a->type = BGETC(f);
- a->reg = BGETC(f);
- c = BGETC(f);
- if(c < 0 || c > NSYM){
- print("sym out of range: %d\n", c);
- BPUTC(f, ALAST+1);
- return;
- }
- a->sym = h[c];
- a->name = BGETC(f);
- adrgotype = zsym(pn, f, h);
-
- if((schar)a->reg < 0 || a->reg > NREG) {
- print("register out of range %d\n", a->reg);
- BPUTC(f, ALAST+1);
- return; /* force real diagnostic */
- }
-
- if(a->type == D_CONST || a->type == D_OCONST) {
- if(a->name == D_EXTERN || a->name == D_STATIC) {
- s = a->sym;
- if(s != S && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) {
- if(0 && !s->fnptr && s->name[0] != '.')
- print("%s used as function pointer\n", s->name);
- s->fnptr = 1; // over the top cos of SXREF
- }
- }
- }
-
- switch(a->type) {
- default:
- print("unknown type %d\n", a->type);
- BPUTC(f, ALAST+1);
- return; /* force real diagnostic */
-
- case D_NONE:
- case D_REG:
- case D_FREG:
- case D_PSR:
- case D_FPCR:
- break;
-
- case D_REGREG:
- case D_REGREG2:
- a->offset = BGETC(f);
- break;
-
- case D_CONST2:
- a->offset2 = BGETLE4(f); // fall through
- case D_BRANCH:
- case D_OREG:
- case D_CONST:
- case D_OCONST:
- case D_SHIFT:
- a->offset = BGETLE4(f);
- break;
-
- case D_SCONST:
- a->sval = mal(NSNAME);
- Bread(f, a->sval, NSNAME);
- break;
-
- case D_FCONST:
- a->ieee.l = BGETLE4(f);
- a->ieee.h = BGETLE4(f);
- break;
- }
- s = a->sym;
- if(s == S)
- return;
- i = a->name;
- if(i != D_AUTO && i != D_PARAM) {
- if(s && adrgotype)
- s->gotype = adrgotype;
- return;
- }
-
- l = a->offset;
- for(u=curauto; u; u=u->link)
- if(u->asym == s)
- if(u->type == i) {
- if(u->aoffset > l)
- u->aoffset = l;
- if(adrgotype)
- u->gotype = adrgotype;
- return;
- }
-
- u = mal(sizeof(Auto));
- u->link = curauto;
- curauto = u;
- u->asym = s;
- u->aoffset = l;
- u->type = i;
- u->gotype = adrgotype;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from.type = D_NONE;
- p->to.type = D_NONE;
-}
-
-void
-ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
-{
- int32 ipc;
- Prog *p;
- Sym *h[NSYM], *s;
- int v, o, r, skip;
- uint32 sig;
- char *name;
- int ntext;
- int32 eof;
- char src[1024], *x;
- Prog *lastp;
-
- lastp = nil;
- ntext = 0;
- eof = Boffset(f) + len;
- src[0] = 0;
- pn = estrdup(pn); // we keep it in Sym* references
-
-newloop:
- memset(h, 0, sizeof(h));
- version++;
- histfrogp = 0;
- ipc = pc;
- skip = 0;
-
-loop:
- if(f->state == Bracteof || Boffset(f) >= eof)
- goto eof;
- o = BGETC(f);
- if(o == Beof)
- goto eof;
-
- if(o <= AXXX || o >= ALAST) {
- diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
- print(" probably not a .5 file\n");
- errorexit();
- }
- if(o == ANAME || o == ASIGNAME) {
- sig = 0;
- if(o == ASIGNAME)
- sig = BGETLE4(f);
- v = BGETC(f); /* type */
- o = BGETC(f); /* sym */
- r = 0;
- if(v == D_STATIC)
- r = version;
- name = Brdline(f, '\0');
- if(name == nil) {
- if(Blinelen(f) > 0) {
- fprint(2, "%s: name too long\n", pn);
- errorexit();
- }
- goto eof;
- }
- x = expandpkg(name, pkg);
- s = lookup(x, r);
- if(x != name)
- free(x);
-
- if(sig != 0){
- if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name);
- s->sig = sig;
- s->file = pn;
- }
-
- if(debug['W'])
- print(" ANAME %s\n", s->name);
- if(o < 0 || o >= nelem(h)) {
- fprint(2, "%s: mangled input file\n", pn);
- errorexit();
- }
- h[o] = s;
- if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
- s->type = SXREF;
- if(v == D_FILE) {
- if(s->type != SFILE) {
- histgen++;
- s->type = SFILE;
- s->value = histgen;
- }
- if(histfrogp < MAXHIST) {
- histfrog[histfrogp] = s;
- histfrogp++;
- } else
- collapsefrog(s);
- dwarfaddfrag(s->value, s->name);
- }
- goto loop;
- }
-
- p = mal(sizeof(Prog));
- p->as = o;
- p->scond = BGETC(f);
- p->reg = BGETC(f);
- p->line = BGETLE4(f);
-
- zaddr(pn, f, &p->from, h);
- fromgotype = adrgotype;
- zaddr(pn, f, &p->to, h);
-
- if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG)
- diag("register out of range %A %d", p->as, p->reg);
-
- p->link = P;
- p->cond = P;
-
- if(debug['W'])
- print("%P\n", p);
-
- switch(o) {
- case AHISTORY:
- if(p->to.offset == -1) {
- addlib(src, pn);
- histfrogp = 0;
- goto loop;
- }
- if(src[0] == '\0')
- copyhistfrog(src, sizeof src);
- addhist(p->line, D_FILE); /* 'z' */
- if(p->to.offset)
- addhist(p->to.offset, D_FILE1); /* 'Z' */
- savehist(p->line, p->to.offset);
- histfrogp = 0;
- goto loop;
-
- case AEND:
- histtoauto();
- if(cursym != nil && cursym->text)
- cursym->autom = curauto;
- curauto = 0;
- cursym = nil;
- if(Boffset(f) == eof)
- return;
- goto newloop;
-
- case AGLOBL:
- s = p->from.sym;
- if(s == S) {
- diag("GLOBL must have a name\n%P", p);
- errorexit();
- }
- if(s->type == 0 || s->type == SXREF) {
- s->type = SBSS;
- s->value = 0;
- }
- if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
- diag("redefinition: %s\n%P", s->name, p);
- s->type = SBSS;
- s->value = 0;
- }
- if(p->to.offset > s->size)
- s->size = p->to.offset;
- if(p->reg & DUPOK)
- s->dupok = 1;
- if(p->reg & RODATA)
- s->type = SRODATA;
- else if(p->reg & NOPTR)
- s->type = SNOPTRBSS;
- break;
-
- case ADATA:
- // Assume that AGLOBL comes after ADATA.
- // If we've seen an AGLOBL that said this sym was DUPOK,
- // ignore any more ADATA we see, which must be
- // redefinitions.
- s = p->from.sym;
- if(s->dupok) {
-// if(debug['v'])
-// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
- goto loop;
- }
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
- savedata(s, p, pn);
- unmal(p, sizeof *p);
- break;
-
- case AGOK:
- diag("unknown opcode\n%P", p);
- p->pc = pc;
- pc++;
- break;
-
- case ATYPE:
- if(skip)
- goto casedef;
- pc++;
- goto loop;
-
- case ATEXT:
- if(cursym != nil && cursym->text) {
- histtoauto();
- cursym->autom = curauto;
- curauto = 0;
- }
- s = p->from.sym;
- if(s == S) {
- diag("TEXT must have a name\n%P", p);
- errorexit();
- }
- cursym = s;
- if(s->type != 0 && s->type != SXREF && (p->reg & DUPOK)) {
- skip = 1;
- goto casedef;
- }
- if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
- /* redefinition, so file has probably been seen before */
- if(debug['v'])
- Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
- return;
- }
- skip = 0;
- if(s->type != 0 && s->type != SXREF)
- diag("redefinition: %s\n%P", s->name, p);
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- if(fromgotype) {
- if(s->gotype && s->gotype != fromgotype)
- diag("%s: type mismatch for %s", pn, s->name);
- s->gotype = fromgotype;
- }
- etextp = s;
- p->align = 4;
- autosize = (p->to.offset+3L) & ~3L;
- p->to.offset = autosize;
- autosize += 4;
- s->type = STEXT;
- s->hist = gethist();
- s->text = p;
- s->value = pc;
- s->args = p->to.offset2;
- lastp = p;
- p->pc = pc;
- pc++;
- break;
-
- case ASUB:
- if(p->from.type == D_CONST)
- if(p->from.name == D_NONE)
- if(p->from.offset < 0) {
- p->from.offset = -p->from.offset;
- p->as = AADD;
- }
- goto casedef;
-
- case AADD:
- if(p->from.type == D_CONST)
- if(p->from.name == D_NONE)
- if(p->from.offset < 0) {
- p->from.offset = -p->from.offset;
- p->as = ASUB;
- }
- goto casedef;
-
- case AMOVWD:
- case AMOVWF:
- case AMOVDW:
- case AMOVFW:
- case AMOVFD:
- case AMOVDF:
- // case AMOVF:
- // case AMOVD:
- case ACMPF:
- case ACMPD:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- goto casedef;
-
- case AMOVF:
- if(skip)
- goto casedef;
-
- if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
- (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
- /* size sb 9 max */
- sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(s, ieeedtof(&p->from.ieee));
- s->reachable = 0;
- }
- p->from.type = D_OREG;
- p->from.sym = s;
- p->from.name = D_EXTERN;
- p->from.offset = 0;
- }
- goto casedef;
-
- case AMOVD:
- if(skip)
- goto casedef;
-
- if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
- (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
- /* size sb 18 max */
- sprint(literal, "$%ux.%ux",
- p->from.ieee.l, p->from.ieee.h);
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(s, p->from.ieee.l);
- adduint32(s, p->from.ieee.h);
- s->reachable = 0;
- }
- p->from.type = D_OREG;
- p->from.sym = s;
- p->from.name = D_EXTERN;
- p->from.offset = 0;
- }
- goto casedef;
-
- default:
- casedef:
- if(skip)
- nopout(p);
- p->pc = pc;
- pc++;
- if(p->to.type == D_BRANCH)
- p->to.offset += ipc;
- if(lastp == nil) {
- if(p->as != ANOP)
- diag("unexpected instruction: %P", p);
- break;
- }
- lastp->link = p;
- lastp = p;
- break;
- }
- goto loop;
-
-eof:
- diag("truncated object file: %s", pn);
-}
-
-Prog*
-prg(void)
-{
- Prog *p;
-
- p = mal(sizeof(Prog));
- *p = zprg;
- return p;
-}
-
-Prog*
-appendp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- p->link = q->link;
- q->link = p;
- p->line = q->line;
- return p;
+ adduint8(ctxt, s, goarm);
}
diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c
deleted file mode 100644
index 3d05d6d09..000000000
--- a/src/cmd/5l/optab.c
+++ /dev/null
@@ -1,277 +0,0 @@
-// Inferno utils/5l/optab.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/optab.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "l.h"
-
-Optab optab[] =
-{
- /* struct Optab:
- OPCODE, from, prog->reg, to, type,size,param,flag */
- { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
- { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
-
- { AADD, C_REG, C_REG, C_REG, 1, 4, 0 },
- { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 },
-
- { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 },
- { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 },
- { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 },
- { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 },
- { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 },
-
- { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 },
- { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
- { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
- { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 },
-
- { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP },
-
- { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL },
- { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
- { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 },
- { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
-
- { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL },
- { ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0 },
- { ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0 },
- { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 },
- { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 },
-
- { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 },
- { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 },
-
- { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 },
- { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 },
-
- { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 },
- { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 },
- { ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 },
-
- { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 },
-
- { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 },
- { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM },
- { AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4},
-
- { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 },
- { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 },
- { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 },
- { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 },
- { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM },
- { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
- { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
- { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM },
-
- { AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0 },
- { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 },
- { AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0 },
- { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 },
-
- { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 },
- { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 },
-
- { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 },
- { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 },
-
- { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 },
- { AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0 },
-
- { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
- { AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
- { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
- { AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
- { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
-
- { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
- { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
- { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
- { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
-
- { AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
- { AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
- { AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
- { AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
- { AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
- { AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
- { AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
- { AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
-
- { AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
- { AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
- { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 },
- { AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
- { AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
- { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 },
-
- { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM },
-
- { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 },
- { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 },
-
- { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 },
- { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 },
-
- { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 },
-
- { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 },
-
- { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP },
- { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 },
-
- { AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP },
- { AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 },
-
- { AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO },
- { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO },
-
- { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM },
- { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM },
-
- { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4 },
- { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4},
-
- { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
- { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 },
- { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
-
- { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 },
- { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 },
-
- { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
- { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
-
- { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 },
- { AMOVBS, C_SHIFT,C_NONE, C_REG, 60, 4, 0 },
-
- { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
- { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
- { AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
- { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
-
- { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8 },
- { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, LPCREL, 0 },
-
- { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
- { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
- { AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
- { AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
- { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
- { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
-
- { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
- { AMOVBS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVBS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
- { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
- { AMOVHS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVHS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
- { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
-
- { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
- { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
- { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
- { AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
- { AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
- { AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
- { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
- { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
-
- { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
- { AMOVBS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVBS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
- { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
- { AMOVHS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVHS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
- { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
-
- { ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 },
- { ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 },
-
- { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 8, 0 },
- { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 },
-
- { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 },
- { ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0 },
-
- { AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0 },
- { AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0 },
-
- { AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0 },
- { AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0 },
-
- { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 },
- { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 },
-
- { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 },
-
- { ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 },
- { ASTREXD, C_SOREG,C_REG, C_REG, 92, 4, 0 },
-
- { APLD, C_SOREG,C_NONE, C_NONE, 95, 4, 0 },
-
- { AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0 },
-
- { ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0 },
-
- { AMULWT, C_REG, C_REG, C_REG, 98, 4, 0 },
- { AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0 },
-
- { AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0 },
- { APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0 },
- { AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0 },
-
- { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
-};
diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c
deleted file mode 100644
index cd8897989..000000000
--- a/src/cmd/5l/pass.c
+++ /dev/null
@@ -1,409 +0,0 @@
-// Inferno utils/5l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/pass.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Code and data passes.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-static void xfol(Prog*, Prog**);
-
-Prog*
-brchain(Prog *p)
-{
- int i;
-
- for(i=0; i<20; i++) {
- if(p == P || p->as != AB)
- return p;
- p = p->cond;
- }
- return P;
-}
-
-int
-relinv(int a)
-{
- switch(a) {
- case ABEQ: return ABNE;
- case ABNE: return ABEQ;
- case ABCS: return ABCC;
- case ABHS: return ABLO;
- case ABCC: return ABCS;
- case ABLO: return ABHS;
- case ABMI: return ABPL;
- case ABPL: return ABMI;
- case ABVS: return ABVC;
- case ABVC: return ABVS;
- case ABHI: return ABLS;
- case ABLS: return ABHI;
- case ABGE: return ABLT;
- case ABLT: return ABGE;
- case ABGT: return ABLE;
- case ABLE: return ABGT;
- }
- diag("unknown relation: %s", anames[a]);
- return a;
-}
-
-void
-follow(void)
-{
- Prog *firstp, *lastp;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f follow\n", cputime());
- Bflush(&bso);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- firstp = prg();
- lastp = firstp;
- xfol(cursym->text, &lastp);
- lastp->link = nil;
- cursym->text = firstp->link;
- }
-}
-
-static void
-xfol(Prog *p, Prog **last)
-{
- Prog *q, *r;
- int a, i;
-
-loop:
- if(p == P)
- return;
- a = p->as;
- if(a == AB) {
- q = p->cond;
- if(q != P && q->as != ATEXT) {
- p->mark |= FOLL;
- p = q;
- if(!(p->mark & FOLL))
- goto loop;
- }
- }
- if(p->mark & FOLL) {
- for(i=0,q=p; i<4; i++,q=q->link) {
- if(q == *last || q == nil)
- break;
- a = q->as;
- if(a == ANOP) {
- i--;
- continue;
- }
- if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF)
- goto copy;
- if(q->cond == P || (q->cond->mark&FOLL))
- continue;
- if(a != ABEQ && a != ABNE)
- continue;
- copy:
- for(;;) {
- r = prg();
- *r = *p;
- if(!(r->mark&FOLL))
- print("can't happen 1\n");
- r->mark |= FOLL;
- if(p != q) {
- p = p->link;
- (*last)->link = r;
- *last = r;
- continue;
- }
- (*last)->link = r;
- *last = r;
- if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF)
- return;
- r->as = ABNE;
- if(a == ABNE)
- r->as = ABEQ;
- r->cond = p->link;
- r->link = p->cond;
- if(!(r->link->mark&FOLL))
- xfol(r->link, last);
- if(!(r->cond->mark&FOLL))
- print("can't happen 2\n");
- return;
- }
- }
- a = AB;
- q = prg();
- q->as = a;
- q->line = p->line;
- q->to.type = D_BRANCH;
- q->to.offset = p->pc;
- q->cond = p;
- p = q;
- }
- p->mark |= FOLL;
- (*last)->link = p;
- *last = p;
- if(a == AB || (a == ARET && p->scond == 14) || a == ARFE || a == AUNDEF){
- return;
- }
- if(p->cond != P)
- if(a != ABL && a != ABX && p->link != P) {
- q = brchain(p->link);
- if(a != ATEXT && a != ABCASE)
- if(q != P && (q->mark&FOLL)) {
- p->as = relinv(a);
- p->link = p->cond;
- p->cond = q;
- }
- xfol(p->link, last);
- q = brchain(p->cond);
- if(q == P)
- q = p->cond;
- if(q->mark&FOLL) {
- p->cond = q;
- return;
- }
- p = q;
- goto loop;
- }
- p = p->link;
- goto loop;
-}
-
-void
-patch(void)
-{
- int32 c, vexit;
- Prog *p, *q;
- Sym *s;
- int a;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f patch\n", cputime());
- Bflush(&bso);
- mkfwd();
- s = lookup("exit", 0);
- vexit = s->value;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- a = p->as;
- if((a == ABL || a == ABX || a == AB || a == ARET) &&
- p->to.type != D_BRANCH && p->to.sym != S) {
- s = p->to.sym;
- if(s->text == nil)
- continue;
- switch(s->type&SMASK) {
- default:
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- case STEXT:
- p->to.offset = s->value;
- p->to.type = D_BRANCH;
- p->cond = s->text;
- continue;
- }
- }
- if(p->to.type != D_BRANCH)
- continue;
- c = p->to.offset;
- for(q = cursym->text; q != P;) {
- if(c == q->pc)
- break;
- if(q->forwd != P && c >= q->forwd->pc)
- q = q->forwd;
- else
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range %d\n%P", c, p);
- p->to.type = D_NONE;
- }
- p->cond = q;
- }
- }
- if(flag_shared) {
- s = lookup("init_array", 0);
- s->type = SINITARR;
- s->reachable = 1;
- s->hide = 1;
- addaddr(s, lookup(INITENTRY, 0));
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- if(p->cond != P) {
- p->cond = brloop(p->cond);
- if(p->cond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->cond->pc;
- }
- }
- }
-}
-
-Prog*
-brloop(Prog *p)
-{
- Prog *q;
- int c;
-
- for(c=0; p!=P;) {
- if(p->as != AB)
- return p;
- q = p->cond;
- if(q <= p) {
- c++;
- if(q == p || c > 5000)
- break;
- }
- p = q;
- }
- return P;
-}
-
-int32
-atolwhex(char *s)
-{
- int32 n;
- int f;
-
- n = 0;
- f = 0;
- while(*s == ' ' || *s == '\t')
- s++;
- if(*s == '-' || *s == '+') {
- if(*s++ == '-')
- f = 1;
- while(*s == ' ' || *s == '\t')
- s++;
- }
- if(s[0]=='0' && s[1]){
- if(s[1]=='x' || s[1]=='X'){
- s += 2;
- for(;;){
- if(*s >= '0' && *s <= '9')
- n = n*16 + *s++ - '0';
- else if(*s >= 'a' && *s <= 'f')
- n = n*16 + *s++ - 'a' + 10;
- else if(*s >= 'A' && *s <= 'F')
- n = n*16 + *s++ - 'A' + 10;
- else
- break;
- }
- } else
- while(*s >= '0' && *s <= '7')
- n = n*8 + *s++ - '0';
- } else
- while(*s >= '0' && *s <= '9')
- n = n*10 + *s++ - '0';
- if(f)
- n = -n;
- return n;
-}
-
-int32
-rnd(int32 v, int32 r)
-{
- int32 c;
-
- if(r <= 0)
- return v;
- v += r - 1;
- c = v % r;
- if(c < 0)
- c += r;
- v -= c;
- return v;
-}
-
-void
-dozerostk(void)
-{
- Prog *p, *pl;
- int32 autoffset;
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->text->link == nil)
- continue;
- p = cursym->text;
- autoffset = p->to.offset;
- if(autoffset < 0)
- autoffset = 0;
- if(autoffset && !(p->reg&NOSPLIT)) {
- // MOVW $4(R13), R1
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.reg = 13;
- p->from.offset = 4;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // MOVW $n(R13), R2
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.reg = 13;
- p->from.offset = 4 + autoffset;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- // MOVW $0, R3
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- // L:
- // MOVW.P R3, 0(R1) +4
- // CMP R1, R2
- // BNE L
- p = pl = appendp(p);
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = 3;
- p->to.type = D_OREG;
- p->to.reg = 1;
- p->to.offset = 4;
- p->scond |= C_PBIT;
-
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->reg = 2;
-
- p = appendp(p);
- p->as = ABNE;
- p->to.type = D_BRANCH;
- p->cond = pl;
- }
- }
-}
diff --git a/src/cmd/5l/prof.c b/src/cmd/5l/prof.c
deleted file mode 100644
index 225a52435..000000000
--- a/src/cmd/5l/prof.c
+++ /dev/null
@@ -1,211 +0,0 @@
-// Inferno utils/5l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Profiling.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-doprof1(void)
-{
-#ifdef NOTDEF // TODO(rsc)
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_OREG;
- q->from.name = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->reg = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.name = D_EXTERN;
- p->from.sym = s;
- p->from.offset = n*4 + 4;
- p->to.type = D_REG;
- p->to.reg = REGTMP;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_REG;
- p->to.reg = REGTMP;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = REGTMP;
- p->to.type = D_OREG;
- p->to.name = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_OREG;
- q->from.name = D_EXTERN;
- q->from.sym = s;
- q->reg = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->value = n*4;
-#endif
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
- ps2 = P;
- ps4 = P;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- if(cursym == s2) {
- ps2 = p;
- p->reg = 1;
- }
- if(cursym == s4) {
- ps4 = p;
- p->reg = 1;
- }
- }
- for(cursym = textp; cursym != nil; cursym = cursym->next)
- for(p = cursym->text; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->reg & NOPROF) {
- for(;;) {
- q = p->link;
- if(q == P)
- break;
- if(q->as == ATEXT)
- break;
- p = q;
- }
- continue;
- }
-
- /*
- * BL profin, R2
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->cond = ps2;
- p->to.sym = s2;
-
- continue;
- }
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * BL profout
- */
- p->as = ABL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->cond = ps4;
- p->to.sym = s4;
-
- p = q;
-
- continue;
- }
- }
-}
diff --git a/src/cmd/5l/softfloat.c b/src/cmd/5l/softfloat.c
deleted file mode 100644
index de6481c71..000000000
--- a/src/cmd/5l/softfloat.c
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-// Software floating point.
-
-void
-softfloat(void)
-{
- Prog *p, *next, *psfloat;
- Sym *symsfloat;
- int wasfloat;
-
- if(!debug['F'])
- return;
-
- symsfloat = lookup("_sfloat", 0);
- psfloat = P;
- if(symsfloat->type == STEXT)
- psfloat = symsfloat->text;
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- wasfloat = 0;
- for(p = cursym->text; p != P; p = p->link)
- if(p->cond != P)
- p->cond->mark |= LABEL;
- for(p = cursym->text; p != P; p = p->link) {
- switch(p->as) {
- case AMOVW:
- if(p->to.type == D_FREG || p->from.type == D_FREG)
- goto soft;
- goto notsoft;
-
- case AMOVWD:
- case AMOVWF:
- case AMOVDW:
- case AMOVFW:
- case AMOVFD:
- case AMOVDF:
- case AMOVF:
- case AMOVD:
-
- case ACMPF:
- case ACMPD:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- case ASQRTF:
- case ASQRTD:
- case AABSF:
- case AABSD:
- goto soft;
-
- default:
- goto notsoft;
-
- soft:
- if (psfloat == P)
- diag("floats used with _sfloat not defined");
- if (!wasfloat || (p->mark&LABEL)) {
- next = prg();
- *next = *p;
-
- // BL _sfloat(SB)
- *p = zprg;
- p->link = next;
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->to.sym = symsfloat;
- p->cond = psfloat;
- p->line = next->line;
-
- p = next;
- wasfloat = 1;
- }
- break;
-
- notsoft:
- wasfloat = 0;
- }
- }
- }
-}
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
deleted file mode 100644
index e7cc0b4b1..000000000
--- a/src/cmd/5l/span.c
+++ /dev/null
@@ -1,937 +0,0 @@
-// Inferno utils/5l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Instruction layout.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-static struct {
- uint32 start;
- uint32 size;
- uint32 extra;
-} pool;
-
-int checkpool(Prog*, int);
-int flushpool(Prog*, int, int);
-
-int
-isbranch(Prog *p)
-{
- int as = p->as;
- return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX;
-}
-
-static int
-scan(Prog *op, Prog *p, int c)
-{
- Prog *q;
-
- for(q = op->link; q != p && q != P; q = q->link){
- q->pc = c;
- c += oplook(q)->size;
- nocache(q);
- }
- return c;
-}
-
-/* size of a case statement including jump table */
-static int32
-casesz(Prog *p)
-{
- int jt = 0;
- int32 n = 0;
- Optab *o;
-
- for( ; p != P; p = p->link){
- if(p->as == ABCASE)
- jt = 1;
- else if(jt)
- break;
- o = oplook(p);
- n += o->size;
- }
- return n;
-}
-
-void
-span(void)
-{
- Prog *p, *op;
- Optab *o;
- int m, bflag, i, v;
- int32 c, otxt, out[6];
- Section *sect;
- uchar *bp;
- Sym *sub, *gmsym;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
- Bflush(&bso);
-
- sect = addsection(&segtext, ".text", 05);
- lookup("text", 0)->sect = sect;
- lookup("etext", 0)->sect = sect;
-
- bflag = 0;
- c = INITTEXT;
- otxt = c;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- cursym->sect = sect;
- p = cursym->text;
- if(p == P || p->link == P) { // handle external functions and ELF section symbols
- if(cursym->type & SSUB)
- continue;
- if(cursym->align != 0)
- c = rnd(c, cursym->align);
- cursym->value = 0;
- for(sub = cursym; sub != S; sub = sub->sub) {
- sub->value += c;
- for(p = sub->text; p != P; p = p->link)
- p->pc += sub->value;
- }
- c += cursym->size;
- continue;
- }
- p->pc = c;
- cursym->value = c;
-
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- /* need passes to resolve branches */
- if(c-otxt >= 1L<<17)
- bflag = 1;
- otxt = c;
-
- for(op = p, p = p->link; p != P; op = p, p = p->link) {
- curp = p;
- p->pc = c;
- o = oplook(p);
- m = o->size;
- // must check literal pool here in case p generates many instructions
- if(blitrl){
- if(checkpool(op, p->as == ACASE ? casesz(p) : m))
- c = p->pc = scan(op, p, c);
- }
- if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) {
- diag("zero-width instruction\n%P", p);
- continue;
- }
- switch(o->flag & (LFROM|LTO|LPOOL)) {
- case LFROM:
- addpool(p, &p->from);
- break;
- case LTO:
- addpool(p, &p->to);
- break;
- case LPOOL:
- if ((p->scond&C_SCOND) == 14)
- flushpool(p, 0, 0);
- break;
- }
- if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
- flushpool(p, 0, 0);
- c += m;
- }
- if(blitrl){
- if(checkpool(op, 0))
- c = scan(op, P, c);
- }
- cursym->size = c - cursym->value;
- }
-
- /*
- * if any procedure is large enough to
- * generate a large SBRA branch, then
- * generate extra passes putting branches
- * around jmps to fix. this is rare.
- */
- while(bflag) {
- if(debug['v'])
- Bprint(&bso, "%5.2f span1\n", cputime());
- bflag = 0;
- c = INITTEXT;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(!cursym->text || !cursym->text->link)
- continue;
- cursym->value = c;
- for(p = cursym->text; p != P; p = p->link) {
- curp = p;
- p->pc = c;
- o = oplook(p);
-/* very large branches
- if(o->type == 6 && p->cond) {
- otxt = p->cond->pc - c;
- if(otxt < 0)
- otxt = -otxt;
- if(otxt >= (1L<<17) - 10) {
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = p->cond;
- p->cond = q;
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = q->link->link;
- bflag = 1;
- }
- }
- */
- m = o->size;
- if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) {
- if(p->as == ATEXT) {
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- continue;
- }
- diag("zero-width instruction\n%P", p);
- continue;
- }
- c += m;
- }
- cursym->size = c - cursym->value;
- }
- }
-
- c = rnd(c, 8);
-
- /*
- * lay out the code. all the pc-relative code references,
- * even cross-function, are resolved now;
- * only data references need to be relocated.
- * with more work we could leave cross-function
- * code references to be relocated too, and then
- * perhaps we'd be able to parallelize the span loop above.
- */
- gmsym = S;
- if(linkmode == LinkExternal)
- gmsym = lookup("runtime.tlsgm", 0);
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- if(p == P || p->link == P)
- continue;
- autosize = p->to.offset + 4;
- symgrow(cursym, cursym->size);
-
- bp = cursym->p;
- for(p = p->link; p != P; p = p->link) {
- pc = p->pc;
- curp = p;
- o = oplook(p);
- asmout(p, o, out, gmsym);
- for(i=0; i<o->size/4; i++) {
- v = out[i];
- *bp++ = v;
- *bp++ = v>>8;
- *bp++ = v>>16;
- *bp++ = v>>24;
- }
- }
- }
- sect->vaddr = INITTEXT;
- sect->len = c - INITTEXT;
-}
-
-/*
- * when the first reference to the literal pool threatens
- * to go out of range of a 12-bit PC-relative offset,
- * drop the pool now, and branch round it.
- * this happens only in extended basic blocks that exceed 4k.
- */
-int
-checkpool(Prog *p, int sz)
-{
- if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
- return flushpool(p, 1, 0);
- else if(p->link == P)
- return flushpool(p, 2, 0);
- return 0;
-}
-
-int
-flushpool(Prog *p, int skip, int force)
-{
- Prog *q;
-
- if(blitrl) {
- if(skip){
- if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
- q = prg();
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = p->link;
- q->link = blitrl;
- q->line = p->line;
- blitrl = q;
- }
- else if(!force && (p->pc+pool.size-pool.start < 2048))
- return 0;
- elitrl->link = p->link;
- p->link = blitrl;
- // BUG(minux): how to correctly handle line number for constant pool entries?
- // for now, we set line number to the last instruction preceding them at least
- // this won't bloat the .debug_line tables
- while(blitrl) {
- blitrl->line = p->line;
- blitrl = blitrl->link;
- }
- blitrl = 0; /* BUG: should refer back to values until out-of-range */
- elitrl = 0;
- pool.size = 0;
- pool.start = 0;
- pool.extra = 0;
- return 1;
- }
- return 0;
-}
-
-void
-addpool(Prog *p, Adr *a)
-{
- Prog *q, t;
- int c;
-
- c = aclass(a);
-
- t = zprg;
- t.as = AWORD;
-
- switch(c) {
- default:
- t.to = *a;
- if(flag_shared && t.to.sym != S)
- t.pcrel = p;
- break;
-
- case C_SROREG:
- case C_LOREG:
- case C_ROREG:
- case C_FOREG:
- case C_SOREG:
- case C_HOREG:
- case C_FAUTO:
- case C_SAUTO:
- case C_LAUTO:
- case C_LACON:
- t.to.type = D_CONST;
- t.to.offset = instoffset;
- break;
- }
-
- if(t.pcrel == P) {
- for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */
- if(q->pcrel == P && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
- p->cond = q;
- return;
- }
- }
-
- q = prg();
- *q = t;
- q->pc = pool.size;
-
- if(blitrl == P) {
- blitrl = q;
- pool.start = p->pc;
- q->align = 4;
- } else
- elitrl->link = q;
- elitrl = q;
- pool.size += 4;
-
- p->cond = q;
-}
-
-void
-xdefine(char *p, int t, int32 v)
-{
- Sym *s;
-
- s = lookup(p, 0);
- s->type = t;
- s->value = v;
- s->reachable = 1;
- s->special = 1;
-}
-
-int32
-regoff(Adr *a)
-{
-
- instoffset = 0;
- aclass(a);
- return instoffset;
-}
-
-int32
-immrot(uint32 v)
-{
- int i;
-
- for(i=0; i<16; i++) {
- if((v & ~0xff) == 0)
- return (i<<8) | v | (1<<25);
- v = (v<<2) | (v>>30);
- }
- return 0;
-}
-
-int32
-immaddr(int32 v)
-{
- if(v >= 0 && v <= 0xfff)
- return (v & 0xfff) |
- (1<<24) | /* pre indexing */
- (1<<23); /* pre indexing, up */
- if(v >= -0xfff && v < 0)
- return (-v & 0xfff) |
- (1<<24); /* pre indexing */
- return 0;
-}
-
-int
-immfloat(int32 v)
-{
- return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */
-}
-
-int
-immhalf(int32 v)
-{
- if(v >= 0 && v <= 0xff)
- return v|
- (1<<24)| /* pre indexing */
- (1<<23); /* pre indexing, up */
- if(v >= -0xff && v < 0)
- return (-v & 0xff)|
- (1<<24); /* pre indexing */
- return 0;
-}
-
-int32
-symaddr(Sym *s)
-{
- if(!s->reachable)
- diag("unreachable symbol in symaddr - %s", s->name);
- return s->value;
-}
-
-int
-aclass(Adr *a)
-{
- Sym *s;
- int t;
-
- switch(a->type) {
- case D_NONE:
- return C_NONE;
-
- case D_REG:
- return C_REG;
-
- case D_REGREG:
- return C_REGREG;
-
- case D_REGREG2:
- return C_REGREG2;
-
- case D_SHIFT:
- return C_SHIFT;
-
- case D_FREG:
- return C_FREG;
-
- case D_FPCR:
- return C_FCR;
-
- case D_OREG:
- switch(a->name) {
- case D_EXTERN:
- case D_STATIC:
- if(a->sym == 0 || a->sym->name == 0) {
- print("null sym external\n");
- print("%D\n", a);
- return C_GOK;
- }
- instoffset = 0; // s.b. unused but just in case
- return C_ADDR;
-
- case D_AUTO:
- instoffset = autosize + a->offset;
- t = immaddr(instoffset);
- if(t){
- if(immhalf(instoffset))
- return immfloat(t) ? C_HFAUTO : C_HAUTO;
- if(immfloat(t))
- return C_FAUTO;
- return C_SAUTO;
- }
- return C_LAUTO;
-
- case D_PARAM:
- instoffset = autosize + a->offset + 4L;
- t = immaddr(instoffset);
- if(t){
- if(immhalf(instoffset))
- return immfloat(t) ? C_HFAUTO : C_HAUTO;
- if(immfloat(t))
- return C_FAUTO;
- return C_SAUTO;
- }
- return C_LAUTO;
- case D_NONE:
- instoffset = a->offset;
- t = immaddr(instoffset);
- if(t) {
- if(immhalf(instoffset)) /* n.b. that it will also satisfy immrot */
- return immfloat(t) ? C_HFOREG : C_HOREG;
- if(immfloat(t))
- return C_FOREG; /* n.b. that it will also satisfy immrot */
- t = immrot(instoffset);
- if(t)
- return C_SROREG;
- if(immhalf(instoffset))
- return C_HOREG;
- return C_SOREG;
- }
- t = immrot(instoffset);
- if(t)
- return C_ROREG;
- return C_LOREG;
- }
- return C_GOK;
-
- case D_PSR:
- return C_PSR;
-
- case D_OCONST:
- switch(a->name) {
- case D_EXTERN:
- case D_STATIC:
- instoffset = 0; // s.b. unused but just in case
- return C_ADDR;
- }
- return C_GOK;
-
- case D_FCONST:
- if(chipzero(&a->ieee) >= 0)
- return C_ZFCON;
- if(chipfloat(&a->ieee) >= 0)
- return C_SFCON;
- return C_LFCON;
-
- case D_CONST:
- case D_CONST2:
- switch(a->name) {
-
- case D_NONE:
- instoffset = a->offset;
- if(a->reg != NREG)
- goto aconsize;
-
- t = immrot(instoffset);
- if(t)
- return C_RCON;
- t = immrot(~instoffset);
- if(t)
- return C_NCON;
- return C_LCON;
-
- case D_EXTERN:
- case D_STATIC:
- s = a->sym;
- if(s == S)
- break;
- instoffset = 0; // s.b. unused but just in case
- return C_LCONADDR;
-
- case D_AUTO:
- instoffset = autosize + a->offset;
- goto aconsize;
-
- case D_PARAM:
- instoffset = autosize + a->offset + 4L;
- aconsize:
- t = immrot(instoffset);
- if(t)
- return C_RACON;
- return C_LACON;
- }
- return C_GOK;
-
- case D_BRANCH:
- return C_SBRA;
- }
- return C_GOK;
-}
-
-Optab*
-oplook(Prog *p)
-{
- int a1, a2, a3, r;
- char *c1, *c3;
- Optab *o, *e;
-
- a1 = p->optab;
- if(a1)
- return optab+(a1-1);
- a1 = p->from.class;
- if(a1 == 0) {
- a1 = aclass(&p->from) + 1;
- p->from.class = a1;
- }
- a1--;
- a3 = p->to.class;
- if(a3 == 0) {
- a3 = aclass(&p->to) + 1;
- p->to.class = a3;
- }
- a3--;
- a2 = C_NONE;
- if(p->reg != NREG)
- a2 = C_REG;
- r = p->as;
- o = oprange[r].start;
- if(o == 0) {
- a1 = opcross[repop[r]][a1][a2][a3];
- if(a1) {
- p->optab = a1+1;
- return optab+a1;
- }
- o = oprange[r].stop; /* just generate an error */
- }
- if(debug['O']) {
- print("oplook %A %O %O %O\n",
- (int)p->as, a1, a2, a3);
- print(" %d %d\n", p->from.type, p->to.type);
- }
- e = oprange[r].stop;
- c1 = xcmp[a1];
- c3 = xcmp[a3];
- for(; o<e; o++)
- if(o->a2 == a2)
- if(c1[o->a1])
- if(c3[o->a3]) {
- p->optab = (o-optab)+1;
- return o;
- }
- diag("illegal combination %A %O %O %O, %d %d",
- p->as, a1, a2, a3, p->from.type, p->to.type);
- prasm(p);
- if(o == 0)
- o = optab;
- return o;
-}
-
-int
-cmp(int a, int b)
-{
-
- if(a == b)
- return 1;
- switch(a) {
- case C_LCON:
- if(b == C_RCON || b == C_NCON)
- return 1;
- break;
- case C_LACON:
- if(b == C_RACON)
- return 1;
- break;
- case C_LFCON:
- if(b == C_ZFCON || b == C_SFCON)
- return 1;
- break;
-
- case C_HFAUTO:
- return b == C_HAUTO || b == C_FAUTO;
- case C_FAUTO:
- case C_HAUTO:
- return b == C_HFAUTO;
- case C_SAUTO:
- return cmp(C_HFAUTO, b);
- case C_LAUTO:
- return cmp(C_SAUTO, b);
-
- case C_HFOREG:
- return b == C_HOREG || b == C_FOREG;
- case C_FOREG:
- case C_HOREG:
- return b == C_HFOREG;
- case C_SROREG:
- return cmp(C_SOREG, b) || cmp(C_ROREG, b);
- case C_SOREG:
- case C_ROREG:
- return b == C_SROREG || cmp(C_HFOREG, b);
- case C_LOREG:
- return cmp(C_SROREG, b);
-
- case C_LBRA:
- if(b == C_SBRA)
- return 1;
- break;
-
- case C_HREG:
- return cmp(C_SP, b) || cmp(C_PC, b);
-
- }
- return 0;
-}
-
-int
-ocmp(const void *a1, const void *a2)
-{
- Optab *p1, *p2;
- int n;
-
- p1 = (Optab*)a1;
- p2 = (Optab*)a2;
- n = p1->as - p2->as;
- if(n)
- return n;
- n = p1->a1 - p2->a1;
- if(n)
- return n;
- n = p1->a2 - p2->a2;
- if(n)
- return n;
- n = p1->a3 - p2->a3;
- if(n)
- return n;
- return 0;
-}
-
-void
-buildop(void)
-{
- int i, n, r;
-
- for(i=0; i<C_GOK; i++)
- for(n=0; n<C_GOK; n++)
- xcmp[i][n] = cmp(n, i);
- for(n=0; optab[n].as != AXXX; n++) {
- if((optab[n].flag & LPCREL) != 0) {
- if(flag_shared)
- optab[n].size += optab[n].pcrelsiz;
- else
- optab[n].flag &= ~LPCREL;
- }
- }
- qsort(optab, n, sizeof(optab[0]), ocmp);
- for(i=0; i<n; i++) {
- r = optab[i].as;
- oprange[r].start = optab+i;
- while(optab[i].as == r)
- i++;
- oprange[r].stop = optab+i;
- i--;
-
- switch(r)
- {
- default:
- diag("unknown op in build: %A", r);
- errorexit();
- case AADD:
- oprange[AAND] = oprange[r];
- oprange[AEOR] = oprange[r];
- oprange[ASUB] = oprange[r];
- oprange[ARSB] = oprange[r];
- oprange[AADC] = oprange[r];
- oprange[ASBC] = oprange[r];
- oprange[ARSC] = oprange[r];
- oprange[AORR] = oprange[r];
- oprange[ABIC] = oprange[r];
- break;
- case ACMP:
- oprange[ATEQ] = oprange[r];
- oprange[ACMN] = oprange[r];
- break;
- case AMVN:
- break;
- case ABEQ:
- oprange[ABNE] = oprange[r];
- oprange[ABCS] = oprange[r];
- oprange[ABHS] = oprange[r];
- oprange[ABCC] = oprange[r];
- oprange[ABLO] = oprange[r];
- oprange[ABMI] = oprange[r];
- oprange[ABPL] = oprange[r];
- oprange[ABVS] = oprange[r];
- oprange[ABVC] = oprange[r];
- oprange[ABHI] = oprange[r];
- oprange[ABLS] = oprange[r];
- oprange[ABGE] = oprange[r];
- oprange[ABLT] = oprange[r];
- oprange[ABGT] = oprange[r];
- oprange[ABLE] = oprange[r];
- break;
- case ASLL:
- oprange[ASRL] = oprange[r];
- oprange[ASRA] = oprange[r];
- break;
- case AMUL:
- oprange[AMULU] = oprange[r];
- break;
- case ADIV:
- oprange[AMOD] = oprange[r];
- oprange[AMODU] = oprange[r];
- oprange[ADIVU] = oprange[r];
- break;
- case AMOVW:
- case AMOVB:
- case AMOVBS:
- case AMOVBU:
- case AMOVH:
- case AMOVHS:
- case AMOVHU:
- break;
- case ASWPW:
- oprange[ASWPBU] = oprange[r];
- break;
- case AB:
- case ABL:
- case ABX:
- case ABXRET:
- case ASWI:
- case AWORD:
- case AMOVM:
- case ARFE:
- case ATEXT:
- case AUSEFIELD:
- case ACASE:
- case ABCASE:
- case ATYPE:
- break;
- case AADDF:
- oprange[AADDD] = oprange[r];
- oprange[ASUBF] = oprange[r];
- oprange[ASUBD] = oprange[r];
- oprange[AMULF] = oprange[r];
- oprange[AMULD] = oprange[r];
- oprange[ADIVF] = oprange[r];
- oprange[ADIVD] = oprange[r];
- oprange[ASQRTF] = oprange[r];
- oprange[ASQRTD] = oprange[r];
- oprange[AMOVFD] = oprange[r];
- oprange[AMOVDF] = oprange[r];
- oprange[AABSF] = oprange[r];
- oprange[AABSD] = oprange[r];
- break;
-
- case ACMPF:
- oprange[ACMPD] = oprange[r];
- break;
-
- case AMOVF:
- oprange[AMOVD] = oprange[r];
- break;
-
- case AMOVFW:
- oprange[AMOVDW] = oprange[r];
- break;
-
- case AMOVWF:
- oprange[AMOVWD] = oprange[r];
- break;
-
- case AMULL:
- oprange[AMULAL] = oprange[r];
- oprange[AMULLU] = oprange[r];
- oprange[AMULALU] = oprange[r];
- break;
-
- case AMULWT:
- oprange[AMULWB] = oprange[r];
- break;
-
- case AMULAWT:
- oprange[AMULAWB] = oprange[r];
- break;
-
- case AMULA:
- case ALDREX:
- case ASTREX:
- case ALDREXD:
- case ASTREXD:
- case ATST:
- case APLD:
- case AUNDEF:
- case ACLZ:
- case AFUNCDATA:
- case APCDATA:
- break;
- }
- }
-}
-
-/*
-void
-buildrep(int x, int as)
-{
- Opcross *p;
- Optab *e, *s, *o;
- int a1, a2, a3, n;
-
- if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
- diag("assumptions fail in buildrep");
- errorexit();
- }
- repop[as] = x;
- p = (opcross + x);
- s = oprange[as].start;
- e = oprange[as].stop;
- for(o=e-1; o>=s; o--) {
- n = o-optab;
- for(a2=0; a2<2; a2++) {
- if(a2) {
- if(o->a2 == C_NONE)
- continue;
- } else
- if(o->a2 != C_NONE)
- continue;
- for(a1=0; a1<32; a1++) {
- if(!xcmp[a1][o->a1])
- continue;
- for(a3=0; a3<32; a3++)
- if(xcmp[a3][o->a3])
- (*p)[a1][a2][a3] = n;
- }
- }
- }
- oprange[as].start = 0;
-}
-*/
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
index 64c8ac2fe..f5ade5a34 100644
--- a/src/cmd/6l/6.out.h
+++ b/src/cmd/6l/6.out.h
@@ -891,15 +891,3 @@ enum
* this is the ranlib header
*/
#define SYMDEF "__.GOSYMDEF"
-
-/*
- * this is the simulated IEEE floating point
- */
-typedef struct ieee Ieee;
-struct ieee
-{
- int32 l; /* contains ls-man 0xffffffff */
- int32 h; /* contains sign 0x80000000
- exp 0x7ff00000
- ms-man 0x000fffff */
-};
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index a09cc9727..084e2cc6a 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -47,46 +47,18 @@ char dragonflydynld[] = "/usr/libexec/ld-elf.so.2";
char zeroes[32];
-vlong
-entryvalue(void)
-{
- char *a;
- Sym *s;
-
- a = INITENTRY;
- if(*a >= '0' && *a <= '9')
- return atolwhex(a);
- s = lookup(a, 0);
- if(s->type == 0)
- return INITTEXT;
- if(s->type != STEXT)
- diag("entry not text: %s", s->name);
- return s->value;
-}
-
-vlong
-datoff(vlong addr)
-{
- if(addr >= segdata.vaddr)
- return addr - segdata.vaddr + segdata.fileoff;
- if(addr >= segtext.vaddr)
- return addr - segtext.vaddr + segtext.fileoff;
- diag("datoff %#llx", addr);
- return 0;
-}
-
static int
needlib(char *name)
{
char *p;
- Sym *s;
+ LSym *s;
if(*name == '\0')
return 0;
/* reuse hash code in symbol table */
p = smprint(".elfload.%s", name);
- s = lookup(p, 0);
+ s = linklookup(ctxt, p, 0);
free(p);
if(s->type == 0) {
s->type = 100; // avoid SDATA, etc.
@@ -97,24 +69,24 @@ needlib(char *name)
int nelfsym = 1;
-static void addpltsym(Sym*);
-static void addgotsym(Sym*);
+static void addpltsym(LSym*);
+static void addgotsym(LSym*);
void
-adddynrela(Sym *rela, Sym *s, Reloc *r)
+adddynrela(LSym *rela, LSym *s, Reloc *r)
{
- addaddrplus(rela, s, r->off);
- adduint64(rela, R_X86_64_RELATIVE);
- addaddrplus(rela, r->sym, r->add); // Addend
+ addaddrplus(ctxt, rela, s, r->off);
+ adduint64(ctxt, rela, R_X86_64_RELATIVE);
+ addaddrplus(ctxt, rela, r->sym, r->add); // Addend
}
void
-adddynrel(Sym *s, Reloc *r)
+adddynrel(LSym *s, Reloc *r)
{
- Sym *targ, *rela, *got;
+ LSym *targ, *rela, *got;
targ = r->sym;
- cursym = s;
+ ctxt->cursym = s;
switch(r->type) {
default:
@@ -139,7 +111,7 @@ adddynrel(Sym *s, Reloc *r)
r->add += 4;
if(targ->type == SDYNIMPORT) {
addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add += targ->plt;
}
return;
@@ -159,7 +131,7 @@ adddynrel(Sym *s, Reloc *r)
}
addgotsym(targ);
r->type = D_PCREL;
- r->sym = lookup(".got", 0);
+ r->sym = linklookup(ctxt, ".got", 0);
r->add += 4;
r->add += targ->got;
return;
@@ -183,7 +155,7 @@ adddynrel(Sym *s, Reloc *r)
case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
if(targ->type == SDYNIMPORT) {
addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
r->type = D_PCREL;
return;
@@ -217,7 +189,7 @@ adddynrel(Sym *s, Reloc *r)
diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
addgotsym(targ);
r->type = D_PCREL;
- r->sym = lookup(".got", 0);
+ r->sym = linklookup(ctxt, ".got", 0);
r->add += targ->got;
return;
}
@@ -229,7 +201,7 @@ adddynrel(Sym *s, Reloc *r)
switch(r->type) {
case D_PCREL:
addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
return;
@@ -237,14 +209,14 @@ adddynrel(Sym *s, Reloc *r)
if(s->type != SDATA)
break;
if(iself) {
- adddynsym(targ);
- rela = lookup(".rela", 0);
- addaddrplus(rela, s, r->off);
+ adddynsym(ctxt, targ);
+ rela = linklookup(ctxt, ".rela", 0);
+ addaddrplus(ctxt, rela, s, r->off);
if(r->siz == 8)
- adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
+ adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
else
- adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
- adduint64(rela, r->add);
+ adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
+ adduint64(ctxt, rela, r->add);
r->type = 256; // ignore during relocsym
return;
}
@@ -259,22 +231,22 @@ adddynrel(Sym *s, Reloc *r)
// just in case the C code assigns to the variable,
// and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs.
- adddynsym(targ);
- got = lookup(".got", 0);
+ adddynsym(ctxt, targ);
+ got = linklookup(ctxt, ".got", 0);
s->type = got->type | SSUB;
s->outer = got;
s->sub = got->sub;
got->sub = s;
s->value = got->size;
- adduint64(got, 0);
- adduint32(lookup(".linkedit.got", 0), targ->dynid);
+ adduint64(ctxt, got, 0);
+ adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid);
r->type = 256; // ignore during relocsym
return;
}
break;
}
- cursym = s;
+ ctxt->cursym = s;
diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}
@@ -325,7 +297,7 @@ int
machoreloc1(Reloc *r, vlong sectoff)
{
uint32 v;
- Sym *rs;
+ LSym *rs;
rs = r->xsym;
@@ -379,7 +351,7 @@ machoreloc1(Reloc *r, vlong sectoff)
}
int
-archreloc(Reloc *r, Sym *s, vlong *val)
+archreloc(Reloc *r, LSym *s, vlong *val)
{
USED(r);
USED(s);
@@ -390,68 +362,68 @@ archreloc(Reloc *r, Sym *s, vlong *val)
void
elfsetupplt(void)
{
- Sym *plt, *got;
+ LSym *plt, *got;
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
+ got = linklookup(ctxt, ".got.plt", 0);
if(plt->size == 0) {
// pushq got+8(IP)
- adduint8(plt, 0xff);
- adduint8(plt, 0x35);
- addpcrelplus(plt, got, 8);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x35);
+ addpcrelplus(ctxt, plt, got, 8);
// jmpq got+16(IP)
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addpcrelplus(plt, got, 16);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x25);
+ addpcrelplus(ctxt, plt, got, 16);
// nopl 0(AX)
- adduint32(plt, 0x00401f0f);
+ adduint32(ctxt, plt, 0x00401f0f);
// assume got->size == 0 too
- addaddrplus(got, lookup(".dynamic", 0), 0);
- adduint64(got, 0);
- adduint64(got, 0);
+ addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
+ adduint64(ctxt, got, 0);
+ adduint64(ctxt, got, 0);
}
}
static void
-addpltsym(Sym *s)
+addpltsym(LSym *s)
{
if(s->plt >= 0)
return;
- adddynsym(s);
+ adddynsym(ctxt, s);
if(iself) {
- Sym *plt, *got, *rela;
+ LSym *plt, *got, *rela;
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
- rela = lookup(".rela.plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
+ got = linklookup(ctxt, ".got.plt", 0);
+ rela = linklookup(ctxt, ".rela.plt", 0);
if(plt->size == 0)
elfsetupplt();
// jmpq *got+size(IP)
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addpcrelplus(plt, got, got->size);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x25);
+ addpcrelplus(ctxt, plt, got, got->size);
// add to got: pointer to current pos in plt
- addaddrplus(got, plt, plt->size);
+ addaddrplus(ctxt, got, plt, plt->size);
// pushq $x
- adduint8(plt, 0x68);
- adduint32(plt, (got->size-24-8)/8);
+ adduint8(ctxt, plt, 0x68);
+ adduint32(ctxt, plt, (got->size-24-8)/8);
// jmpq .plt
- adduint8(plt, 0xe9);
- adduint32(plt, -(plt->size+4));
+ adduint8(ctxt, plt, 0xe9);
+ adduint32(ctxt, plt, -(plt->size+4));
// rela
- addaddrplus(rela, got, got->size-8);
- adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
- adduint64(rela, 0);
+ addaddrplus(ctxt, rela, got, got->size-8);
+ adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
+ adduint64(ctxt, rela, 0);
s->plt = plt->size - 16;
} else if(HEADTYPE == Hdarwin) {
@@ -465,53 +437,53 @@ addpltsym(Sym *s)
// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
// has details about what we're avoiding.
- Sym *plt;
+ LSym *plt;
addgotsym(s);
- plt = lookup(".plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
- adduint32(lookup(".linkedit.plt", 0), s->dynid);
+ adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid);
// jmpq *got+size(IP)
s->plt = plt->size;
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addpcrelplus(plt, lookup(".got", 0), s->got);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x25);
+ addpcrelplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got);
} else {
diag("addpltsym: unsupported binary format");
}
}
static void
-addgotsym(Sym *s)
+addgotsym(LSym *s)
{
- Sym *got, *rela;
+ LSym *got, *rela;
if(s->got >= 0)
return;
- adddynsym(s);
- got = lookup(".got", 0);
+ adddynsym(ctxt, s);
+ got = linklookup(ctxt, ".got", 0);
s->got = got->size;
- adduint64(got, 0);
+ adduint64(ctxt, got, 0);
if(iself) {
- rela = lookup(".rela", 0);
- addaddrplus(rela, got, s->got);
- adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
- adduint64(rela, 0);
+ rela = linklookup(ctxt, ".rela", 0);
+ addaddrplus(ctxt, rela, got, s->got);
+ adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
+ adduint64(ctxt, rela, 0);
} else if(HEADTYPE == Hdarwin) {
- adduint32(lookup(".linkedit.got", 0), s->dynid);
+ adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
} else {
diag("addgotsym: unsupported binary format");
}
}
void
-adddynsym(Sym *s)
+adddynsym(Link *ctxt, LSym *s)
{
- Sym *d;
+ LSym *d;
int t;
char *name;
@@ -521,24 +493,24 @@ adddynsym(Sym *s)
if(iself) {
s->dynid = nelfsym++;
- d = lookup(".dynsym", 0);
+ d = linklookup(ctxt, ".dynsym", 0);
name = s->extname;
- adduint32(d, addstring(lookup(".dynstr", 0), name));
+ adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
/* type */
t = STB_GLOBAL << 4;
if(s->cgoexport && (s->type&SMASK) == STEXT)
t |= STT_FUNC;
else
t |= STT_OBJECT;
- adduint8(d, t);
+ adduint8(ctxt, d, t);
/* reserved */
- adduint8(d, 0);
+ adduint8(ctxt, d, 0);
/* section where symbol is defined */
if(s->type == SDYNIMPORT)
- adduint16(d, SHN_UNDEF);
+ adduint16(ctxt, d, SHN_UNDEF);
else {
switch(s->type) {
default:
@@ -555,21 +527,21 @@ adddynsym(Sym *s)
t = 14;
break;
}
- adduint16(d, t);
+ adduint16(ctxt, d, t);
}
/* value */
if(s->type == SDYNIMPORT)
- adduint64(d, 0);
+ adduint64(ctxt, d, 0);
else
- addaddr(d, s);
+ addaddr(ctxt, d, s);
/* size of object */
- adduint64(d, s->size);
+ adduint64(ctxt, d, s->size);
if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) {
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
- addstring(lookup(".dynstr", 0), s->dynimplib));
+ elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED,
+ addstring(linklookup(ctxt, ".dynstr", 0), s->dynimplib));
}
} else if(HEADTYPE == Hdarwin) {
diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
@@ -583,16 +555,16 @@ adddynsym(Sym *s)
void
adddynlib(char *lib)
{
- Sym *s;
+ LSym *s;
if(!needlib(lib))
return;
if(iself) {
- s = lookup(".dynstr", 0);
+ s = linklookup(ctxt, ".dynstr", 0);
if(s->size == 0)
addstring(s, "");
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
} else if(HEADTYPE == Hdarwin) {
machoadddynlib(lib);
} else {
@@ -607,7 +579,7 @@ asmb(void)
int i;
vlong vl, symo, dwarfoff, machlink;
Section *sect;
- Sym *sym;
+ LSym *sym;
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
@@ -662,8 +634,7 @@ asmb(void)
switch(HEADTYPE) {
default:
diag("unknown header type %d", HEADTYPE);
- case Hplan9x32:
- case Hplan9x64:
+ case Hplan9:
case Helf:
break;
case Hdarwin:
@@ -690,7 +661,7 @@ asmb(void)
Bflush(&bso);
switch(HEADTYPE) {
default:
- case Hplan9x64:
+ case Hplan9:
case Helf:
debug['s'] = 1;
symo = HEADR+segtext.len+segdata.filelen;
@@ -729,11 +700,11 @@ asmb(void)
elfemitreloc();
}
break;
- case Hplan9x64:
+ case Hplan9:
asmplan9sym();
cflush();
- sym = lookup("pclntab", 0);
+ sym = linklookup(ctxt, "pclntab", 0);
if(sym != nil) {
lcsize = sym->np;
for(i=0; i < lcsize; i++)
@@ -761,7 +732,7 @@ asmb(void)
cseek(0L);
switch(HEADTYPE) {
default:
- case Hplan9x64: /* plan9 */
+ case Hplan9: /* plan9 */
magic = 4*26*26+7;
magic |= 0x00008000; /* fat header */
lputb(magic); /* magic */
@@ -775,17 +746,6 @@ asmb(void)
lputb(lcsize); /* line offsets */
vputb(vl); /* va of entry */
break;
- case Hplan9x32: /* plan9 */
- magic = 4*26*26+7;
- lputb(magic); /* magic */
- lputb(segtext.filelen); /* sizes */
- lputb(segdata.filelen);
- lputb(segdata.len - segdata.filelen);
- lputb(symsize); /* nsyms */
- lputb(entryvalue()); /* va of entry */
- lputb(spsize); /* sp offsets */
- lputb(lcsize); /* line offsets */
- break;
case Hdarwin:
asmbmacho();
break;
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index ecab867e4..d2a8d94b1 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -31,6 +31,7 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
+#include <link.h>
#include "6.out.h"
#ifndef EXTERN
@@ -64,146 +65,8 @@ enum
};
#define P ((Prog*)0)
-#define S ((Sym*)0)
-#define TNAME (cursym?cursym->name:noname)
-
-typedef struct Adr Adr;
-typedef struct Prog Prog;
-typedef struct Sym Sym;
-typedef struct Auto Auto;
-typedef struct Optab Optab;
-typedef struct Movtab Movtab;
-typedef struct Reloc Reloc;
-
-struct Adr
-{
- union
- {
- vlong u0offset;
- char u0scon[8];
- Prog *u0cond; /* not used, but should be D_BRANCH */
- Ieee u0ieee;
- char *u0sbig;
- } u0;
- Sym* sym;
- short type;
- char index;
- char scale;
-};
-
-#define offset u0.u0offset
-#define scon u0.u0scon
-#define cond u0.u0cond
-#define ieee u0.u0ieee
-#define sbig u0.u0sbig
-
-struct Reloc
-{
- int32 off;
- uchar siz;
- uchar done;
- int32 type;
- int64 add;
- int64 xadd;
- Sym* sym;
- Sym* xsym;
-};
-
-struct Prog
-{
- Adr from;
- Adr to;
- Prog* forwd;
- Prog* comefrom;
- Prog* link;
- Prog* pcond; /* work on this */
- vlong pc;
- int32 spadj;
- int32 line;
- short as;
- char ft; /* oclass cache */
- char tt;
- uchar mark; /* work on these */
- uchar back;
-
- char width; /* fake for DATA */
- char mode; /* 16, 32, or 64 */
-};
-#define datasize from.scale
-#define textflag from.scale
-#define iscall(p) ((p)->as == ACALL)
-
-struct Auto
-{
- Sym* asym;
- Auto* link;
- int32 aoffset;
- short type;
- Sym* gotype;
-};
-struct Sym
-{
- char* name;
- char* extname; // name used in external object files
- short type;
- short version;
- uchar dupok;
- uchar reachable;
- uchar cgoexport;
- uchar special;
- uchar stkcheck;
- uchar hide;
- int32 dynid;
- int32 sig;
- int32 plt;
- int32 got;
- int32 align; // if non-zero, required alignment in bytes
- int32 elfsym;
- int32 args; // size of stack frame incoming arguments area
- Sym* hash; // in hash table
- Sym* allsym; // in all symbol list
- Sym* next; // in text or data list
- Sym* sub; // in SSUB list
- Sym* outer; // container of sub
- Sym* reachparent;
- Sym* queue;
- vlong value;
- vlong size;
- Sym* gotype;
- char* file;
- char* dynimplib;
- char* dynimpvers;
- struct Section* sect;
- struct Hist* hist; // for ATEXT
-
- // STEXT
- Auto* autom;
- Prog* text;
-
- // SDATA, SBSS
- uchar* p;
- int32 np;
- int32 maxp;
- Reloc* r;
- int32 nr;
- int32 maxr;
-};
-struct Optab
-{
- short as;
- uchar* ytab;
- uchar prefix;
- uchar op[23];
-};
-struct Movtab
-{
- short as;
- uchar ft;
- uchar tt;
- uchar code;
- uchar op[4];
-};
-
+#define S ((LSym*)0)
+#define TNAME (ctxt->cursym?ctxt->cursym->name:noname)
enum
{
MINSIZ = 8,
@@ -211,233 +74,55 @@ enum
MINLC = 1,
MAXIO = 8192,
MAXHIST = 40, /* limit of path elements for history symbols */
-
- Yxxx = 0,
- Ynone,
- Yi0,
- Yi1,
- Yi8,
- Ys32,
- Yi32,
- Yi64,
- Yiauto,
- Yal,
- Ycl,
- Yax,
- Ycx,
- Yrb,
- Yrl,
- Yrf,
- Yf0,
- Yrx,
- Ymb,
- Yml,
- Ym,
- Ybr,
- Ycol,
-
- Ycs, Yss, Yds, Yes, Yfs, Ygs,
- Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
- Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8,
- Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
- Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64,
- Ymr, Ymm,
- Yxr, Yxm,
- Ymax,
-
- Zxxx = 0,
-
- Zlit,
- Zlitm_r,
- Z_rp,
- Zbr,
- Zcall,
- Zib_,
- Zib_rp,
- Zibo_m,
- Zibo_m_xm,
- Zil_,
- Zil_rp,
- Ziq_rp,
- Zilo_m,
- Ziqo_m,
- Zjmp,
- Zloop,
- Zo_iw,
- Zm_o,
- Zm_r,
- Zm2_r,
- Zm_r_xm,
- Zm_r_i_xm,
- Zm_r_3d,
- Zm_r_xm_nr,
- Zr_m_xm_nr,
- Zibm_r, /* mmx1,mmx2/mem64,imm8 */
- Zmb_r,
- Zaut_r,
- Zo_m,
- Zo_m64,
- Zpseudo,
- Zr_m,
- Zr_m_xm,
- Zr_m_i_xm,
- Zrp_,
- Z_ib,
- Z_il,
- Zm_ibo,
- Zm_ilo,
- Zib_rr,
- Zil_rr,
- Zclr,
- Zbyte,
- Zmax,
-
- Px = 0,
- P32 = 0x32, /* 32-bit only */
- Pe = 0x66, /* operand escape */
- Pm = 0x0f, /* 2byte opcode escape */
- Pq = 0xff, /* both escapes: 66 0f */
- Pb = 0xfe, /* byte operands */
- Pf2 = 0xf2, /* xmm escape 1: f2 0f */
- Pf3 = 0xf3, /* xmm escape 2: f3 0f */
- Pq3 = 0x67, /* xmm escape 3: 66 48 0f */
- Pw = 0x48, /* Rex.w */
- Py = 0x80, /* defaults to 64-bit mode */
-
- Rxf = 1<<9, /* internal flag for Rxr on from */
- Rxt = 1<<8, /* internal flag for Rxr on to */
- Rxw = 1<<3, /* =1, 64-bit operand size */
- Rxr = 1<<2, /* extend modrm reg */
- Rxx = 1<<1, /* extend sib index */
- Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */
-
- Maxand = 10, /* in -a output width of the byte codes */
};
#pragma varargck type "A" uint
-#pragma varargck type "D" Adr*
+#pragma varargck type "D" Addr*
#pragma varargck type "I" uchar*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "S" char*
#pragma varargck type "i" char*
-EXTERN int32 HEADR;
-EXTERN int32 HEADTYPE;
-EXTERN int32 INITRND;
-EXTERN int64 INITTEXT;
-EXTERN int64 INITDAT;
-EXTERN char* INITENTRY; /* entry point */
-EXTERN char* pcstr;
-EXTERN Auto* curauto;
-EXTERN Auto* curhist;
-EXTERN Prog* curp;
-EXTERN Sym* cursym;
-EXTERN Sym* datap;
+EXTERN LSym* datap;
EXTERN int debug[128];
EXTERN char literal[32];
-EXTERN Sym* textp;
-EXTERN Sym* etextp;
-EXTERN char ycover[Ymax*Ymax];
-EXTERN uchar* andptr;
-EXTERN uchar* rexptr;
-EXTERN uchar and[30];
-EXTERN int reg[D_NONE];
-EXTERN int regrex[D_NONE+1];
EXTERN int32 lcsize;
-EXTERN int nerrors;
-EXTERN char* noname;
-EXTERN char* outfile;
-EXTERN vlong pc;
-EXTERN char* interpreter;
EXTERN char* rpath;
EXTERN int32 spsize;
-EXTERN Sym* symlist;
+EXTERN LSym* symlist;
EXTERN int32 symsize;
-EXTERN int tlsoffset;
-EXTERN Prog zprg;
-EXTERN int dtype;
-EXTERN char* paramspace;
-EXTERN Sym* adrgotype; // type symbol on last Adr read
-EXTERN Sym* fromgotype; // type symbol on last p->from read
EXTERN vlong textstksiz;
EXTERN vlong textarg;
-extern Optab optab[];
-extern Optab* opindex[];
-extern char* anames[];
-
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Iconv(Fmt*);
-int Pconv(Fmt*);
-int Rconv(Fmt*);
-int Sconv(Fmt*);
-void addhist(int32, int);
-void addstackmark(void);
-Prog* appendp(Prog*);
+int Aconv(Fmt *fp);
+int Dconv(Fmt *fp);
+int Iconv(Fmt *fp);
+int Pconv(Fmt *fp);
+int Rconv(Fmt *fp);
+int Sconv(Fmt *fp);
+void adddynlib(char *lib);
+void adddynrel(LSym *s, Reloc *r);
+void adddynrela(LSym *rela, LSym *s, Reloc *r);
+void adddynsym(Link *ctxt, LSym *s);
+int archreloc(Reloc *r, LSym *s, vlong *val);
void asmb(void);
-void asmdyn(void);
-void asmins(Prog*);
-void asmsym(void);
-void asmelfsym(void);
-vlong atolwhex(char*);
-Prog* brchain(Prog*);
-Prog* brloop(Prog*);
-void buildop(void);
-Prog* copyp(Prog*);
-double cputime(void);
-void datblk(int32, int32);
-void deadcode(void);
-void diag(char*, ...);
-void dodata(void);
-void doelf(void);
-void domacho(void);
-void doprof1(void);
-void doprof2(void);
-void dostkoff(void);
-vlong entryvalue(void);
-void follow(void);
-void gethunk(void);
-void gotypestrings(void);
+void diag(char *fmt, ...);
+int elfreloc1(Reloc *r, vlong sectoff);
+void elfsetupplt(void);
void listinit(void);
-Sym* lookup(char*, int);
-void lputb(int32);
-void lputl(int32);
-void instinit(void);
-void main(int, char*[]);
-void* mysbrk(uint32);
-Prog* newtext(Prog*, Sym*);
-void nopout(Prog*);
-int opsize(Prog*);
-void patch(void);
-Prog* prg(void);
-void parsetextconst(vlong);
-int relinv(int);
-vlong rnd(vlong, vlong);
-void span(void);
-void undef(void);
-vlong symaddr(Sym*);
-void vputb(uint64);
-void vputl(uint64);
-void wputb(uint16);
-void wputl(uint16);
-void xdefine(char*, int, vlong);
-
-void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32);
-void machsymseg(uint32, uint32);
-void machsect(char*, char*, vlong, vlong, uint32, uint32, uint32, uint32, uint32);
-void machstack(vlong);
-void machdylink(void);
-uint32 machheadr(void);
+int machoreloc1(Reloc *r, vlong sectoff);
+void main(int argc, char *argv[]);
+void parsetextconst(vlong arg);
+vlong rnd(vlong v, vlong r);
/* Native is little-endian */
#define LPUT(a) lputl(a)
#define WPUT(a) wputl(a)
#define VPUT(a) vputl(a)
-#pragma varargck type "D" Adr*
+#pragma varargck type "D" Addr*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "Z" char*
diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c
index 5040e4327..4a7b0d04a 100644
--- a/src/cmd/6l/list.c
+++ b/src/cmd/6l/list.c
@@ -58,21 +58,21 @@ Pconv(Fmt *fp)
case ATEXT:
if(p->from.scale) {
fmtprint(fp, "(%d) %A %D,%d,%lD",
- p->line, p->as, &p->from, p->from.scale, &p->to);
+ p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
}
fmtprint(fp, "(%d) %A %D,%lD",
- p->line, p->as, &p->from, &p->to);
+ p->lineno, p->as, &p->from, &p->to);
break;
default:
fmtprint(fp, "(%d) %A %D,%D",
- p->line, p->as, &p->from, &p->to);
+ p->lineno, p->as, &p->from, &p->to);
break;
case ADATA:
case AINIT_:
case ADYNT_:
fmtprint(fp, "(%d) %A %D/%d,%D",
- p->line, p->as, &p->from, p->from.scale, &p->to);
+ p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
}
bigP = P;
@@ -85,17 +85,17 @@ Aconv(Fmt *fp)
int i;
i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
+ return fmtstrcpy(fp, anames6[i]);
}
int
Dconv(Fmt *fp)
{
char str[STRINGSZ], s[STRINGSZ];
- Adr *a;
+ Addr *a;
int i;
- a = va_arg(fp->args, Adr*);
+ a = va_arg(fp->args, Addr*);
i = a->type;
if(fp->flags & FmtLong) {
@@ -182,11 +182,11 @@ Dconv(Fmt *fp)
break;
case D_FCONST:
- snprint(str, sizeof(str), "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
+ snprint(str, sizeof(str), "$(%.17g)", a->u.dval);
break;
case D_SCONST:
- snprint(str, sizeof(str), "$\"%S\"", a->scon);
+ snprint(str, sizeof(str), "$\"%S\"", a->u.sval);
break;
case D_ADDR:
@@ -431,8 +431,8 @@ diag(char *fmt, ...)
tn = "";
sep = "";
- if(cursym != S) {
- tn = cursym->name;
+ if(ctxt->cursym != S) {
+ tn = ctxt->cursym->name;
sep = ": ";
}
va_start(arg, fmt);
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
index ae649a74b..ac3273f93 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/obj.c
@@ -30,7 +30,6 @@
// Reading object files.
-#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
@@ -39,104 +38,12 @@
#include "../ld/pe.h"
#include <ar.h>
-char *noname = "<none>";
char* thestring = "amd64";
-char* paramspace = "FP";
-
-Header headers[] = {
- "plan9x32", Hplan9x32,
- "plan9", Hplan9x64,
- "elf", Helf,
- "darwin", Hdarwin,
- "dragonfly", Hdragonfly,
- "linux", Hlinux,
- "freebsd", Hfreebsd,
- "netbsd", Hnetbsd,
- "openbsd", Hopenbsd,
- "windows", Hwindows,
- "windowsgui", Hwindows,
- 0, 0
-};
-
-/*
- * -Hplan9x32 -T4128 -R4096 is plan9 32-bit format
- * -Hplan9 -T0x200028 -R0x200000 is plan9 64-bit format
- * -Helf -T0x80110000 -R4096 is ELF32
- * -Hdarwin -Tx -Rx is apple MH-exec
- * -Hdragonfly -Tx -Rx is DragonFly elf-exec
- * -Hlinux -Tx -Rx is linux elf-exec
- * -Hfreebsd -Tx -Rx is FreeBSD elf-exec
- * -Hnetbsd -Tx -Rx is NetBSD elf-exec
- * -Hopenbsd -Tx -Rx is OpenBSD elf-exec
- * -Hwindows -Tx -Rx is MS Windows PE32+
- */
+LinkArch* thelinkarch = &linkamd64;
void
-main(int argc, char *argv[])
+archinit(void)
{
- Binit(&bso, 1, OWRITE);
- listinit();
- memset(debug, 0, sizeof(debug));
- nerrors = 0;
- outfile = nil;
- HEADTYPE = -1;
- INITTEXT = -1;
- INITDAT = -1;
- INITRND = -1;
- INITENTRY = 0;
- linkmode = LinkAuto;
- nuxiinit();
-
- flagcount("1", "use alternate profiling code", &debug['1']);
- flagcount("8", "assume 64-bit addresses", &debug['8']);
- flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
- flagint64("D", "addr: data address", &INITDAT);
- flagstr("E", "sym: entry symbol", &INITENTRY);
- flagfn1("I", "interp: set ELF interp", setinterp);
- flagfn1("L", "dir: add dir to library path", Lflag);
- flagfn1("H", "head: header type", setheadtype);
- flagcount("K", "add stack underflow checks", &debug['K']);
- flagcount("O", "print pc-line tables", &debug['O']);
- flagcount("Q", "debug byte-register code gen", &debug['Q']);
- flagint32("R", "rnd: address rounding", &INITRND);
- flagcount("S", "check type signatures", &debug['S']);
- flagint64("T", "addr: text address", &INITTEXT);
- flagfn0("V", "print version and exit", doversion);
- flagcount("W", "disassemble input", &debug['W']);
- flagfn2("X", "name value: define string data", addstrdata);
- flagcount("Z", "clear stack frame on entry", &debug['Z']);
- flagcount("a", "disassemble output", &debug['a']);
- flagcount("c", "dump call graph", &debug['c']);
- flagcount("d", "disable dynamic executable", &debug['d']);
- flagstr("extld", "linker to run in external mode", &extld);
- flagstr("extldflags", "flags for external linker", &extldflags);
- flagcount("f", "ignore version mismatch", &debug['f']);
- flagcount("g", "disable go package data checks", &debug['g']);
- flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
- flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
- flagstr("k", "sym: set field tracking symbol", &tracksym);
- flagcount("n", "dump symbol table", &debug['n']);
- flagstr("o", "outfile: set output file", &outfile);
- flagcount("p", "insert profiling code", &debug['p']);
- flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
- flagcount("race", "enable race detector", &flag_race);
- flagcount("s", "disable symbol table", &debug['s']);
- flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared);
- flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
- flagcount("u", "reject unsafe packages", &debug['u']);
- flagcount("v", "print link trace", &debug['v']);
- flagcount("w", "disable DWARF generation", &debug['w']);
-
- flagparse(&argc, &argv, usage);
-
- if(argc != 1)
- usage();
-
- mywhatsys(); // get goos
-
- if(HEADTYPE == -1)
- HEADTYPE = headtype(goos);
-
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
// Go was built; see ../../make.bash.
if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
@@ -160,30 +67,13 @@ main(int argc, char *argv[])
case Hopenbsd:
break;
}
-
- if(outfile == nil) {
- if(HEADTYPE == Hwindows)
- outfile = "6.out.exe";
- else
- outfile = "6.out";
- }
-
- libinit();
+ ctxt->linkmode = linkmode;
switch(HEADTYPE) {
default:
diag("unknown -H option");
errorexit();
- case Hplan9x32: /* plan 9 */
- HEADR = 32L;
- if(INITTEXT == -1)
- INITTEXT = 4096+HEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
- case Hplan9x64: /* plan 9 */
+ case Hplan9: /* plan 9 */
HEADR = 32L + 8L;
if(INITTEXT == -1)
INITTEXT = 0x200000+HEADR;
@@ -206,7 +96,7 @@ main(int argc, char *argv[])
* OS X system constant - offset from 0(GS) to our TLS.
* Explained in ../../pkg/runtime/cgo/gcc_darwin_amd64.c.
*/
- tlsoffset = 0x8a0;
+ ctxt->tlsoffset = 0x8a0;
machoinit();
HEADR = INITIAL_MACHO_HEADR;
if(INITRND == -1)
@@ -227,7 +117,7 @@ main(int argc, char *argv[])
* Also known to ../../pkg/runtime/sys_linux_amd64.s
* and ../../pkg/runtime/cgo/gcc_linux_amd64.c.
*/
- tlsoffset = -16;
+ ctxt->tlsoffset = -16;
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
@@ -251,552 +141,4 @@ main(int argc, char *argv[])
if(INITDAT != 0 && INITRND != 0)
print("warning: -D0x%llux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
- if(debug['v'])
- Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
- HEADTYPE, INITTEXT, INITDAT, INITRND);
- Bflush(&bso);
- instinit();
-
- zprg.link = P;
- zprg.pcond = P;
- zprg.back = 2;
- zprg.as = AGOK;
- zprg.from.type = D_NONE;
- zprg.from.index = D_NONE;
- zprg.from.scale = 1;
- zprg.to = zprg.from;
- zprg.mode = 64;
-
- pcstr = "%.6llux ";
- histgen = 0;
- pc = 0;
- dtype = 4;
- version = 0;
- cbp = buf.cbuf;
- cbc = sizeof(buf.cbuf);
-
- addlibpath("command line", "command line", argv[0], "main");
- loadlib();
- deadcode();
- patch();
- follow();
- doelf();
- if(HEADTYPE == Hdarwin)
- domacho();
- dostkoff();
- dostkcheck();
- paramspace = "SP"; /* (FP) now (SP) on output */
- if(debug['p'])
- if(debug['1'])
- doprof1();
- else
- doprof2();
- span();
- if(HEADTYPE == Hwindows)
- dope();
- addexport();
- textaddress();
- pclntab();
- symtab();
- dodata();
- address();
- doweak();
- reloc();
- asmb();
- undef();
- hostlink();
- if(debug['v']) {
- Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%d symbols\n", nsymbol);
- Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
- Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
- }
- Bflush(&bso);
-
- errorexit();
-}
-
-static Sym*
-zsym(char *pn, Biobuf *f, Sym *h[])
-{
- int o;
-
- o = BGETC(f);
- if(o < 0 || o >= NSYM || h[o] == nil)
- mangle(pn);
- return h[o];
-}
-
-static void
-zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
-{
- int t;
- int32 l;
- Sym *s;
- Auto *u;
-
- t = BGETC(f);
- a->index = D_NONE;
- a->scale = 0;
- if(t & T_INDEX) {
- a->index = BGETC(f);
- a->scale = BGETC(f);
- }
- a->offset = 0;
- if(t & T_OFFSET) {
- a->offset = BGETLE4(f);
- if(t & T_64) {
- a->offset &= 0xFFFFFFFFULL;
- a->offset |= (uvlong)BGETLE4(f) << 32;
- }
- }
- a->sym = S;
- if(t & T_SYM)
- a->sym = zsym(pn, f, h);
- a->type = D_NONE;
- if(t & T_FCONST) {
- a->ieee.l = BGETLE4(f);
- a->ieee.h = BGETLE4(f);
- a->type = D_FCONST;
- } else
- if(t & T_SCONST) {
- Bread(f, a->scon, NSNAME);
- a->type = D_SCONST;
- }
- if(t & T_TYPE)
- a->type = BGETC(f);
- if(a->type < 0 || a->type >= D_SIZE)
- mangle(pn);
- adrgotype = S;
- if(t & T_GOTYPE)
- adrgotype = zsym(pn, f, h);
- s = a->sym;
- t = a->type;
- if(t == D_INDIR+D_GS || a->index == D_GS)
- a->offset += tlsoffset;
- if(t != D_AUTO && t != D_PARAM) {
- if(s && adrgotype)
- s->gotype = adrgotype;
- return;
- }
- l = a->offset;
- for(u=curauto; u; u=u->link) {
- if(u->asym == s)
- if(u->type == t) {
- if(u->aoffset > l)
- u->aoffset = l;
- if(adrgotype)
- u->gotype = adrgotype;
- return;
- }
- }
-
- switch(t) {
- case D_FILE:
- case D_FILE1:
- case D_AUTO:
- case D_PARAM:
- if(s == S)
- mangle(pn);
- }
-
- u = mal(sizeof(*u));
- u->link = curauto;
- curauto = u;
- u->asym = s;
- u->aoffset = l;
- u->type = t;
- u->gotype = adrgotype;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from.type = D_NONE;
- p->to.type = D_NONE;
-}
-
-void
-ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
-{
- vlong ipc;
- Prog *p;
- int v, o, r, skip, mode;
- Sym *h[NSYM], *s;
- uint32 sig;
- char *name, *x;
- int ntext;
- vlong eof;
- char src[1024];
- Prog *lastp;
-
- lastp = nil;
- ntext = 0;
- eof = Boffset(f) + len;
- src[0] = 0;
- pn = estrdup(pn); // we keep it in Sym* references
-
-newloop:
- memset(h, 0, sizeof(h));
- version++;
- histfrogp = 0;
- ipc = pc;
- skip = 0;
- mode = 64;
-
-loop:
- if(f->state == Bracteof || Boffset(f) >= eof)
- goto eof;
- o = BGETC(f);
- if(o == Beof)
- goto eof;
- o |= BGETC(f) << 8;
- if(o <= AXXX || o >= ALAST) {
- if(o < 0)
- goto eof;
- diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
- print(" probably not a .6 file\n");
- errorexit();
- }
-
- if(o == ANAME || o == ASIGNAME) {
- sig = 0;
- if(o == ASIGNAME)
- sig = BGETLE4(f);
- v = BGETC(f); /* type */
- o = BGETC(f); /* sym */
- r = 0;
- if(v == D_STATIC)
- r = version;
- name = Brdline(f, '\0');
- if(name == nil) {
- if(Blinelen(f) > 0) {
- fprint(2, "%s: name too long\n", pn);
- errorexit();
- }
- goto eof;
- }
- x = expandpkg(name, pkg);
- s = lookup(x, r);
- if(x != name)
- free(x);
-
- if(debug['S'] && r == 0)
- sig = 1729;
- if(sig != 0){
- if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures "
- "%ux(%s) and %ux(%s) for %s",
- s->sig, s->file, sig, pn, s->name);
- s->sig = sig;
- s->file = pn;
- }
-
- if(debug['W'])
- print(" ANAME %s\n", s->name);
- if(o < 0 || o >= nelem(h))
- mangle(pn);
- h[o] = s;
- if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
- s->type = SXREF;
- if(v == D_FILE) {
- if(s->type != SFILE) {
- histgen++;
- s->type = SFILE;
- s->value = histgen;
- }
- if(histfrogp < MAXHIST) {
- histfrog[histfrogp] = s;
- histfrogp++;
- } else
- collapsefrog(s);
- dwarfaddfrag(s->value, s->name);
- }
- goto loop;
- }
-
- p = mal(sizeof(*p));
- p->as = o;
- p->line = BGETLE4(f);
- p->back = 2;
- p->mode = mode;
- zaddr(pn, f, &p->from, h);
- fromgotype = adrgotype;
- zaddr(pn, f, &p->to, h);
-
- switch(p->as) {
- case ATEXT:
- case ADATA:
- case AGLOBL:
- if(p->from.sym == S)
- mangle(pn);
- break;
- }
-
- if(debug['W'])
- print("%P\n", p);
-
- switch(p->as) {
- case AHISTORY:
- if(p->to.offset == -1) {
- addlib(src, pn);
- histfrogp = 0;
- goto loop;
- }
- if(src[0] == '\0')
- copyhistfrog(src, sizeof src);
- addhist(p->line, D_FILE); /* 'z' */
- if(p->to.offset)
- addhist(p->to.offset, D_FILE1); /* 'Z' */
- savehist(p->line, p->to.offset);
- histfrogp = 0;
- goto loop;
-
- case AEND:
- histtoauto();
- if(cursym != nil && cursym->text)
- cursym->autom = curauto;
- curauto = 0;
- cursym = nil;
- if(Boffset(f) == eof)
- return;
- goto newloop;
-
- case AGLOBL:
- s = p->from.sym;
- if(s->type == 0 || s->type == SXREF) {
- s->type = SBSS;
- s->size = 0;
- }
- if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
- diag("%s: redefinition: %s in %s",
- pn, s->name, TNAME);
- s->type = SBSS;
- s->size = 0;
- }
- if(p->to.offset > s->size)
- s->size = p->to.offset;
- if(p->from.scale & DUPOK)
- s->dupok = 1;
- if(p->from.scale & RODATA)
- s->type = SRODATA;
- else if(p->from.scale & NOPTR)
- s->type = SNOPTRBSS;
- goto loop;
-
- case ADATA:
- // Assume that AGLOBL comes after ADATA.
- // If we've seen an AGLOBL that said this sym was DUPOK,
- // ignore any more ADATA we see, which must be
- // redefinitions.
- s = p->from.sym;
- if(s->dupok) {
-// if(debug['v'])
-// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
- goto loop;
- }
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
- savedata(s, p, pn);
- unmal(p, sizeof *p);
- goto loop;
-
- case AGOK:
- diag("%s: GOK opcode in %s", pn, TNAME);
- pc++;
- goto loop;
-
- case ATYPE:
- if(skip)
- goto casdef;
- pc++;
- goto loop;
-
- case ATEXT:
- s = p->from.sym;
- if(s->text != nil) {
- if(p->from.scale & DUPOK) {
- skip = 1;
- goto casdef;
- }
- diag("%s: %s: redefinition", pn, s->name);
- return;
- }
- if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
- /* redefinition, so file has probably been seen before */
- if(debug['v'])
- Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
- return;
- }
- if(cursym != nil && cursym->text) {
- histtoauto();
- cursym->autom = curauto;
- curauto = 0;
- }
- skip = 0;
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- s->text = p;
- cursym = s;
- if(s->type != 0 && s->type != SXREF) {
- if(p->from.scale & DUPOK) {
- skip = 1;
- goto casdef;
- }
- diag("%s: redefinition: %s\n%P", pn, s->name, p);
- }
- if(fromgotype) {
- if(s->gotype && s->gotype != fromgotype)
- diag("%s: type mismatch for %s", pn, s->name);
- s->gotype = fromgotype;
- }
- s->type = STEXT;
- s->hist = gethist();
- s->value = pc;
- s->args = p->to.offset >> 32;
- lastp = p;
- p->pc = pc++;
- goto loop;
-
- case AMODE:
- if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){
- switch((int)p->from.offset){
- case 16: case 32: case 64:
- mode = p->from.offset;
- break;
- }
- }
- goto loop;
-
- case AFMOVF:
- case AFADDF:
- case AFSUBF:
- case AFSUBRF:
- case AFMULF:
- case AFDIVF:
- case AFDIVRF:
- case AFCOMF:
- case AFCOMFP:
- case AMOVSS:
- case AADDSS:
- case ASUBSS:
- case AMULSS:
- case ADIVSS:
- case ACOMISS:
- case AUCOMISS:
- if(skip)
- goto casdef;
- if(p->from.type == D_FCONST) {
- /* size sb 9 max */
- sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(s, ieeedtof(&p->from.ieee));
- s->reachable = 0;
- }
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- goto casdef;
-
- case AFMOVD:
- case AFADDD:
- case AFSUBD:
- case AFSUBRD:
- case AFMULD:
- case AFDIVD:
- case AFDIVRD:
- case AFCOMD:
- case AFCOMDP:
- case AMOVSD:
- case AADDSD:
- case ASUBSD:
- case AMULSD:
- case ADIVSD:
- case ACOMISD:
- case AUCOMISD:
- if(skip)
- goto casdef;
- if(p->from.type == D_FCONST) {
- /* size sb 18 max */
- sprint(literal, "$%ux.%ux",
- p->from.ieee.l, p->from.ieee.h);
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(s, p->from.ieee.l);
- adduint32(s, p->from.ieee.h);
- s->reachable = 0;
- }
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- goto casdef;
-
- casdef:
- default:
- if(skip)
- nopout(p);
- p->pc = pc;
- pc++;
-
- if(p->to.type == D_BRANCH)
- p->to.offset += ipc;
- if(lastp == nil) {
- if(p->as != ANOP)
- diag("unexpected instruction: %P", p);
- goto loop;
- }
- lastp->link = p;
- lastp = p;
- goto loop;
- }
-
-eof:
- diag("truncated object file: %s", pn);
-}
-
-Prog*
-prg(void)
-{
- Prog *p;
-
- p = mal(sizeof(*p));
-
- *p = zprg;
- return p;
-}
-
-Prog*
-copyp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- *p = *q;
- return p;
-}
-
-Prog*
-appendp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- p->link = q->link;
- q->link = p;
- p->line = q->line;
- p->mode = q->mode;
- return p;
}
diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c
deleted file mode 100644
index f48c6c329..000000000
--- a/src/cmd/6l/optab.c
+++ /dev/null
@@ -1,1372 +0,0 @@
-// Inferno utils/6l/optab.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/optab.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "l.h"
-
-uchar ynone[] =
-{
- Ynone, Ynone, Zlit, 1,
- 0
-};
-uchar ytext[] =
-{
- Ymb, Yi64, Zpseudo,1,
- 0
-};
-uchar ynop[] =
-{
- Ynone, Ynone, Zpseudo,0,
- Ynone, Yiauto, Zpseudo,0,
- Ynone, Yml, Zpseudo,0,
- Ynone, Yrf, Zpseudo,0,
- Ynone, Yxr, Zpseudo,0,
- Yiauto, Ynone, Zpseudo,0,
- Yml, Ynone, Zpseudo,0,
- Yrf, Ynone, Zpseudo,0,
- Yxr, Ynone, Zpseudo,1,
- 0
-};
-uchar yfuncdata[] =
-{
- Yi32, Ym, Zpseudo, 0,
- 0
-};
-uchar ypcdata[] =
-{
- Yi32, Yi32, Zpseudo, 0,
- 0
-};
-uchar yxorb[] =
-{
- Yi32, Yal, Zib_, 1,
- Yi32, Ymb, Zibo_m, 2,
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar yxorl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yaddl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yincb[] =
-{
- Ynone, Ymb, Zo_m, 2,
- 0
-};
-uchar yincw[] =
-{
- Ynone, Yml, Zo_m, 2,
- 0
-};
-uchar yincl[] =
-{
- Ynone, Yml, Zo_m, 2,
- 0
-};
-uchar ycmpb[] =
-{
- Yal, Yi32, Z_ib, 1,
- Ymb, Yi32, Zm_ibo, 2,
- Ymb, Yrb, Zm_r, 1,
- Yrb, Ymb, Zr_m, 1,
- 0
-};
-uchar ycmpl[] =
-{
- Yml, Yi8, Zm_ibo, 2,
- Yax, Yi32, Z_il, 1,
- Yml, Yi32, Zm_ilo, 2,
- Yml, Yrl, Zm_r, 1,
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar yshb[] =
-{
- Yi1, Ymb, Zo_m, 2,
- Yi32, Ymb, Zibo_m, 2,
- Ycx, Ymb, Zo_m, 2,
- 0
-};
-uchar yshl[] =
-{
- Yi1, Yml, Zo_m, 2,
- Yi32, Yml, Zibo_m, 2,
- Ycl, Yml, Zo_m, 2,
- Ycx, Yml, Zo_m, 2,
- 0
-};
-uchar ytestb[] =
-{
- Yi32, Yal, Zib_, 1,
- Yi32, Ymb, Zibo_m, 2,
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar ytestl[] =
-{
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar ymovb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- Yi32, Yrb, Zib_rp, 1,
- Yi32, Ymb, Zibo_m, 2,
- 0
-};
-uchar ymbs[] =
-{
- Ymb, Ynone, Zm_o, 2,
- 0
-};
-uchar ybtl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar ymovw[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- Yi0, Yrl, Zclr, 1,
- Yi32, Yrl, Zil_rp, 1,
- Yi32, Yml, Zilo_m, 2,
- Yiauto, Yrl, Zaut_r, 2,
- 0
-};
-uchar ymovl[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- Yi0, Yrl, Zclr, 1,
- Yi32, Yrl, Zil_rp, 1,
- Yi32, Yml, Zilo_m, 2,
- Yml, Ymr, Zm_r_xm, 1, // MMX MOVD
- Ymr, Yml, Zr_m_xm, 1, // MMX MOVD
- Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit)
- Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit)
- Yiauto, Yrl, Zaut_r, 2,
- 0
-};
-uchar yret[] =
-{
- Ynone, Ynone, Zo_iw, 1,
- Yi32, Ynone, Zo_iw, 1,
- 0
-};
-uchar ymovq[] =
-{
- Yrl, Yml, Zr_m, 1, // 0x89
- Yml, Yrl, Zm_r, 1, // 0x8b
- Yi0, Yrl, Zclr, 1, // 0x31
- Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0)
- Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate
- Yi32, Yml, Zilo_m, 2, // 0xc7,(0)
- Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding)
- Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ
- Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD
- Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD
- Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q
- Yxm, Yxr, Zm_r_xm_nr, 2, // MOVQ xmm1/m64 -> xmm2
- Yxr, Yxm, Zr_m_xm_nr, 2, // MOVQ xmm1 -> xmm2/m64
- Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load
- Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store
- Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ
- 0
-};
-uchar ym_rl[] =
-{
- Ym, Yrl, Zm_r, 1,
- 0
-};
-uchar yrl_m[] =
-{
- Yrl, Ym, Zr_m, 1,
- 0
-};
-uchar ymb_rl[] =
-{
- Ymb, Yrl, Zmb_r, 1,
- 0
-};
-uchar yml_rl[] =
-{
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yrl_ml[] =
-{
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar yml_mb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar yrb_mb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- 0
-};
-uchar yxchg[] =
-{
- Yax, Yrl, Z_rp, 1,
- Yrl, Yax, Zrp_, 1,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar ydivl[] =
-{
- Yml, Ynone, Zm_o, 2,
- 0
-};
-uchar ydivb[] =
-{
- Ymb, Ynone, Zm_o, 2,
- 0
-};
-uchar yimul[] =
-{
- Yml, Ynone, Zm_o, 2,
- Yi8, Yrl, Zib_rr, 1,
- Yi32, Yrl, Zil_rr, 1,
- Yml, Yrl, Zm_r, 2,
- 0
-};
-uchar yimul3[] =
-{
- Yml, Yrl, Zibm_r, 2,
- 0
-};
-uchar ybyte[] =
-{
- Yi64, Ynone, Zbyte, 1,
- 0
-};
-uchar yin[] =
-{
- Yi32, Ynone, Zib_, 1,
- Ynone, Ynone, Zlit, 1,
- 0
-};
-uchar yint[] =
-{
- Yi32, Ynone, Zib_, 1,
- 0
-};
-uchar ypushl[] =
-{
- Yrl, Ynone, Zrp_, 1,
- Ym, Ynone, Zm_o, 2,
- Yi8, Ynone, Zib_, 1,
- Yi32, Ynone, Zil_, 1,
- 0
-};
-uchar ypopl[] =
-{
- Ynone, Yrl, Z_rp, 1,
- Ynone, Ym, Zo_m, 2,
- 0
-};
-uchar ybswap[] =
-{
- Ynone, Yrl, Z_rp, 2,
- 0,
-};
-uchar yscond[] =
-{
- Ynone, Ymb, Zo_m, 2,
- 0
-};
-uchar yjcond[] =
-{
- Ynone, Ybr, Zbr, 0,
- Yi0, Ybr, Zbr, 0,
- Yi1, Ybr, Zbr, 1,
- 0
-};
-uchar yloop[] =
-{
- Ynone, Ybr, Zloop, 1,
- 0
-};
-uchar ycall[] =
-{
- Ynone, Yml, Zo_m64, 0,
- Yrx, Yrx, Zo_m64, 2,
- Ynone, Ybr, Zcall, 1,
- 0
-};
-uchar yjmp[] =
-{
- Ynone, Yml, Zo_m64, 2,
- Ynone, Ybr, Zjmp, 1,
- 0
-};
-
-uchar yfmvd[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yf0, Ym, Zo_m, 2,
- Yrf, Yf0, Zm_o, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfmvdp[] =
-{
- Yf0, Ym, Zo_m, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfmvf[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yf0, Ym, Zo_m, 2,
- 0
-};
-uchar yfmvx[] =
-{
- Ym, Yf0, Zm_o, 2,
- 0
-};
-uchar yfmvp[] =
-{
- Yf0, Ym, Zo_m, 2,
- 0
-};
-uchar yfadd[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yrf, Yf0, Zm_o, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfaddp[] =
-{
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfxch[] =
-{
- Yf0, Yrf, Zo_m, 2,
- Yrf, Yf0, Zm_o, 2,
- 0
-};
-uchar ycompp[] =
-{
- Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
- 0
-};
-uchar ystsw[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ynone, Yax, Zlit, 1,
- 0
-};
-uchar ystcw[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ym, Ynone, Zm_o, 2,
- 0
-};
-uchar ysvrs[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ym, Ynone, Zm_o, 2,
- 0
-};
-uchar ymm[] =
-{
- Ymm, Ymr, Zm_r_xm, 1,
- Yxm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxm[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcvm1[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- Yxm, Ymr, Zm_r_xm, 2,
- 0
-};
-uchar yxcvm2[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- Ymm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxmq[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxr[] =
-{
- Yxr, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxr_ml[] =
-{
- Yxr, Yml, Zr_m_xm, 1,
- 0
-};
-uchar ymr[] =
-{
- Ymr, Ymr, Zm_r, 1,
- 0
-};
-uchar ymr_ml[] =
-{
- Ymr, Yml, Zr_m_xm, 1,
- 0
-};
-uchar yxcmp[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcmpi[] =
-{
- Yxm, Yxr, Zm_r_i_xm, 2,
- 0
-};
-uchar yxmov[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- Yxr, Yxm, Zr_m_xm, 1,
- 0
-};
-uchar yxcvfl[] =
-{
- Yxm, Yrl, Zm_r_xm, 1,
- 0
-};
-uchar yxcvlf[] =
-{
- Yml, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcvfq[] =
-{
- Yxm, Yrl, Zm_r_xm, 2,
- 0
-};
-uchar yxcvqf[] =
-{
- Yml, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yps[] =
-{
- Ymm, Ymr, Zm_r_xm, 1,
- Yi8, Ymr, Zibo_m_xm, 2,
- Yxm, Yxr, Zm_r_xm, 2,
- Yi8, Yxr, Zibo_m_xm, 3,
- 0
-};
-uchar yxrrl[] =
-{
- Yxr, Yrl, Zm_r, 1,
- 0
-};
-uchar ymfp[] =
-{
- Ymm, Ymr, Zm_r_3d, 1,
- 0,
-};
-uchar ymrxr[] =
-{
- Ymr, Yxr, Zm_r, 1,
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar ymshuf[] =
-{
- Ymm, Ymr, Zibm_r, 2,
- 0
-};
-uchar ymshufb[] =
-{
- Yxm, Yxr, Zm2_r, 2,
- 0
-};
-uchar yxshuf[] =
-{
- Yxm, Yxr, Zibm_r, 2,
- 0
-};
-uchar yextrw[] =
-{
- Yxr, Yrl, Zibm_r, 2,
- 0
-};
-uchar yinsrw[] =
-{
- Yml, Yxr, Zibm_r, 2,
- 0
-};
-uchar yinsr[] =
-{
- Ymm, Yxr, Zibm_r, 3,
- 0
-};
-uchar ypsdq[] =
-{
- Yi8, Yxr, Zibo_m, 2,
- 0
-};
-uchar ymskb[] =
-{
- Yxr, Yrl, Zm_r_xm, 2,
- Ymr, Yrl, Zm_r_xm, 1,
- 0
-};
-uchar ycrc32l[] =
-{
- Yml, Yrl, Zlitm_r, 0,
-};
-uchar yprefetch[] =
-{
- Ym, Ynone, Zm_o, 2,
- 0,
-};
-uchar yaes[] =
-{
- Yxm, Yxr, Zlitm_r, 2,
- 0
-};
-uchar yaes2[] =
-{
- Yxm, Yxr, Zibm_r, 2,
- 0
-};
-
-/*
- * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32,
- * and p->from and p->to as operands (Adr*). The linker scans optab to find
- * the entry with the given p->as and then looks through the ytable for that
- * instruction (the second field in the optab struct) for a line whose first
- * two values match the Ytypes of the p->from and p->to operands. The function
- * oclass in span.c computes the specific Ytype of an operand and then the set
- * of more general Ytypes that it satisfies is implied by the ycover table, set
- * up in instinit. For example, oclass distinguishes the constants 0 and 1
- * from the more general 8-bit constants, but instinit says
- *
- * ycover[Yi0*Ymax + Ys32] = 1;
- * ycover[Yi1*Ymax + Ys32] = 1;
- * ycover[Yi8*Ymax + Ys32] = 1;
- *
- * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32)
- * if that's what an instruction can handle.
- *
- * In parallel with the scan through the ytable for the appropriate line, there
- * is a z pointer that starts out pointing at the strange magic byte list in
- * the Optab struct. With each step past a non-matching ytable line, z
- * advances by the 4th entry in the line. When a matching line is found, that
- * z pointer has the extra data to use in laying down the instruction bytes.
- * The actual bytes laid down are a function of the 3rd entry in the line (that
- * is, the Ztype) and the z bytes.
- *
- * For example, let's look at AADDL. The optab line says:
- * { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- *
- * and yaddl says
- * uchar yaddl[] =
- * {
- * Yi8, Yml, Zibo_m, 2,
- * Yi32, Yax, Zil_, 1,
- * Yi32, Yml, Zilo_m, 2,
- * Yrl, Yml, Zr_m, 1,
- * Yml, Yrl, Zm_r, 1,
- * 0
- * };
- *
- * so there are 5 possible types of ADDL instruction that can be laid down, and
- * possible states used to lay them down (Ztype and z pointer, assuming z
- * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are:
- *
- * Yi8, Yml -> Zibo_m, z (0x83, 00)
- * Yi32, Yax -> Zil_, z+2 (0x05)
- * Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00)
- * Yrl, Yml -> Zr_m, z+2+1+2 (0x01)
- * Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03)
- *
- * The Pconstant in the optab line controls the prefix bytes to emit. That's
- * relatively straightforward as this program goes.
- *
- * The switch on t[2] in doasm implements the various Z cases. Zibo_m, for
- * example, is an opcode byte (z[0]) then an asmando (which is some kind of
- * encoded addressing mode for the Yml arg), and then a single immediate byte.
- * Zilo_m is the same but a long (32-bit) immediate.
- */
-Optab optab[] =
-/* as, ytab, andproto, opcode */
-{
- { AXXX },
- { AAAA, ynone, P32, 0x37 },
- { AAAD, ynone, P32, 0xd5,0x0a },
- { AAAM, ynone, P32, 0xd4,0x0a },
- { AAAS, ynone, P32, 0x3f },
- { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
- { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 },
- { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADDPD, yxm, Pq, 0x58 },
- { AADDPS, yxm, Pm, 0x58 },
- { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADDSD, yxm, Pf2, 0x58 },
- { AADDSS, yxm, Pf3, 0x58 },
- { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADJSP },
- { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
- { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AANDNPD, yxm, Pq, 0x55 },
- { AANDNPS, yxm, Pm, 0x55 },
- { AANDPD, yxm, Pq, 0x54 },
- { AANDPS, yxm, Pq, 0x54 },
- { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AARPL, yrl_ml, P32, 0x63 },
- { ABOUNDL, yrl_m, P32, 0x62 },
- { ABOUNDW, yrl_m, Pe, 0x62 },
- { ABSFL, yml_rl, Pm, 0xbc },
- { ABSFQ, yml_rl, Pw, 0x0f,0xbc },
- { ABSFW, yml_rl, Pq, 0xbc },
- { ABSRL, yml_rl, Pm, 0xbd },
- { ABSRQ, yml_rl, Pw, 0x0f,0xbd },
- { ABSRW, yml_rl, Pq, 0xbd },
- { ABSWAPL, ybswap, Px, 0x0f,0xc8 },
- { ABSWAPQ, ybswap, Pw, 0x0f,0xc8 },
- { ABTCL, ybtl, Pm, 0xba,(07),0xbb },
- { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb },
- { ABTCW, ybtl, Pq, 0xba,(07),0xbb },
- { ABTL, ybtl, Pm, 0xba,(04),0xa3 },
- { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3},
- { ABTRL, ybtl, Pm, 0xba,(06),0xb3 },
- { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 },
- { ABTRW, ybtl, Pq, 0xba,(06),0xb3 },
- { ABTSL, ybtl, Pm, 0xba,(05),0xab },
- { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab },
- { ABTSW, ybtl, Pq, 0xba,(05),0xab },
- { ABTW, ybtl, Pq, 0xba,(04),0xa3 },
- { ABYTE, ybyte, Px, 1 },
- { ACALL, ycall, Px, 0xff,(02),0xe8 },
- { ACDQ, ynone, Px, 0x99 },
- { ACLC, ynone, Px, 0xf8 },
- { ACLD, ynone, Px, 0xfc },
- { ACLI, ynone, Px, 0xfa },
- { ACLTS, ynone, Pm, 0x06 },
- { ACMC, ynone, Px, 0xf5 },
- { ACMOVLCC, yml_rl, Pm, 0x43 },
- { ACMOVLCS, yml_rl, Pm, 0x42 },
- { ACMOVLEQ, yml_rl, Pm, 0x44 },
- { ACMOVLGE, yml_rl, Pm, 0x4d },
- { ACMOVLGT, yml_rl, Pm, 0x4f },
- { ACMOVLHI, yml_rl, Pm, 0x47 },
- { ACMOVLLE, yml_rl, Pm, 0x4e },
- { ACMOVLLS, yml_rl, Pm, 0x46 },
- { ACMOVLLT, yml_rl, Pm, 0x4c },
- { ACMOVLMI, yml_rl, Pm, 0x48 },
- { ACMOVLNE, yml_rl, Pm, 0x45 },
- { ACMOVLOC, yml_rl, Pm, 0x41 },
- { ACMOVLOS, yml_rl, Pm, 0x40 },
- { ACMOVLPC, yml_rl, Pm, 0x4b },
- { ACMOVLPL, yml_rl, Pm, 0x49 },
- { ACMOVLPS, yml_rl, Pm, 0x4a },
- { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 },
- { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 },
- { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 },
- { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d },
- { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f },
- { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 },
- { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e },
- { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 },
- { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c },
- { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 },
- { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 },
- { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 },
- { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 },
- { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b },
- { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 },
- { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a },
- { ACMOVWCC, yml_rl, Pq, 0x43 },
- { ACMOVWCS, yml_rl, Pq, 0x42 },
- { ACMOVWEQ, yml_rl, Pq, 0x44 },
- { ACMOVWGE, yml_rl, Pq, 0x4d },
- { ACMOVWGT, yml_rl, Pq, 0x4f },
- { ACMOVWHI, yml_rl, Pq, 0x47 },
- { ACMOVWLE, yml_rl, Pq, 0x4e },
- { ACMOVWLS, yml_rl, Pq, 0x46 },
- { ACMOVWLT, yml_rl, Pq, 0x4c },
- { ACMOVWMI, yml_rl, Pq, 0x48 },
- { ACMOVWNE, yml_rl, Pq, 0x45 },
- { ACMOVWOC, yml_rl, Pq, 0x41 },
- { ACMOVWOS, yml_rl, Pq, 0x40 },
- { ACMOVWPC, yml_rl, Pq, 0x4b },
- { ACMOVWPL, yml_rl, Pq, 0x49 },
- { ACMOVWPS, yml_rl, Pq, 0x4a },
- { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
- { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACMPPD, yxcmpi, Px, Pe,0xc2 },
- { ACMPPS, yxcmpi, Pm, 0xc2,0 },
- { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACMPSB, ynone, Pb, 0xa6 },
- { ACMPSD, yxcmpi, Px, Pf2,0xc2 },
- { ACMPSL, ynone, Px, 0xa7 },
- { ACMPSQ, ynone, Pw, 0xa7 },
- { ACMPSS, yxcmpi, Px, Pf3,0xc2 },
- { ACMPSW, ynone, Pe, 0xa7 },
- { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACOMISD, yxcmp, Pe, 0x2f },
- { ACOMISS, yxcmp, Pm, 0x2f },
- { ACPUID, ynone, Pm, 0xa2 },
- { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a },
- { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, },
- { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d },
- { ACVTPD2PS, yxm, Pe, 0x5a },
- { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d },
- { ACVTPS2PD, yxm, Pm, 0x5a },
- { API2FW, ymfp, Px, 0x0c },
- { ACVTSD2SL, yxcvfl, Pf2, 0x2d },
- { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d },
- { ACVTSD2SS, yxm, Pf2, 0x5a },
- { ACVTSL2SD, yxcvlf, Pf2, 0x2a },
- { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a },
- { ACVTSL2SS, yxcvlf, Pf3, 0x2a },
- { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a },
- { ACVTSS2SD, yxm, Pf3, 0x5a },
- { ACVTSS2SL, yxcvfl, Pf3, 0x2d },
- { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d },
- { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c },
- { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c },
- { ACVTTSD2SL, yxcvfl, Pf2, 0x2c },
- { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c },
- { ACVTTSS2SL, yxcvfl, Pf3, 0x2c },
- { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c },
- { ACWD, ynone, Pe, 0x99 },
- { ACQO, ynone, Pw, 0x99 },
- { ADAA, ynone, P32, 0x27 },
- { ADAS, ynone, P32, 0x2f },
- { ADATA },
- { ADECB, yincb, Pb, 0xfe,(01) },
- { ADECL, yincl, Px, 0xff,(01) },
- { ADECQ, yincl, Pw, 0xff,(01) },
- { ADECW, yincw, Pe, 0xff,(01) },
- { ADIVB, ydivb, Pb, 0xf6,(06) },
- { ADIVL, ydivl, Px, 0xf7,(06) },
- { ADIVPD, yxm, Pe, 0x5e },
- { ADIVPS, yxm, Pm, 0x5e },
- { ADIVQ, ydivl, Pw, 0xf7,(06) },
- { ADIVSD, yxm, Pf2, 0x5e },
- { ADIVSS, yxm, Pf3, 0x5e },
- { ADIVW, ydivl, Pe, 0xf7,(06) },
- { AEMMS, ynone, Pm, 0x77 },
- { AENTER }, /* botch */
- { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) },
- { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) },
- { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) },
- { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) },
- { AGLOBL },
- { AGOK },
- { AHISTORY },
- { AHLT, ynone, Px, 0xf4 },
- { AIDIVB, ydivb, Pb, 0xf6,(07) },
- { AIDIVL, ydivl, Px, 0xf7,(07) },
- { AIDIVQ, ydivl, Pw, 0xf7,(07) },
- { AIDIVW, ydivl, Pe, 0xf7,(07) },
- { AIMULB, ydivb, Pb, 0xf6,(05) },
- { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf },
- { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf },
- { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf },
- { AIMUL3Q, yimul3, Pw, 0x6b,(00) },
- { AINB, yin, Pb, 0xe4,0xec },
- { AINCB, yincb, Pb, 0xfe,(00) },
- { AINCL, yincl, Px, 0xff,(00) },
- { AINCQ, yincl, Pw, 0xff,(00) },
- { AINCW, yincw, Pe, 0xff,(00) },
- { AINL, yin, Px, 0xe5,0xed },
- { AINSB, ynone, Pb, 0x6c },
- { AINSL, ynone, Px, 0x6d },
- { AINSW, ynone, Pe, 0x6d },
- { AINT, yint, Px, 0xcd },
- { AINTO, ynone, P32, 0xce },
- { AINW, yin, Pe, 0xe5,0xed },
- { AIRETL, ynone, Px, 0xcf },
- { AIRETQ, ynone, Pw, 0xcf },
- { AIRETW, ynone, Pe, 0xcf },
- { AJCC, yjcond, Px, 0x73,0x83,(00) },
- { AJCS, yjcond, Px, 0x72,0x82 },
- { AJCXZL, yloop, Px, 0xe3 },
- { AJCXZQ, yloop, Px, 0xe3 },
- { AJEQ, yjcond, Px, 0x74,0x84 },
- { AJGE, yjcond, Px, 0x7d,0x8d },
- { AJGT, yjcond, Px, 0x7f,0x8f },
- { AJHI, yjcond, Px, 0x77,0x87 },
- { AJLE, yjcond, Px, 0x7e,0x8e },
- { AJLS, yjcond, Px, 0x76,0x86 },
- { AJLT, yjcond, Px, 0x7c,0x8c },
- { AJMI, yjcond, Px, 0x78,0x88 },
- { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
- { AJNE, yjcond, Px, 0x75,0x85 },
- { AJOC, yjcond, Px, 0x71,0x81,(00) },
- { AJOS, yjcond, Px, 0x70,0x80,(00) },
- { AJPC, yjcond, Px, 0x7b,0x8b },
- { AJPL, yjcond, Px, 0x79,0x89 },
- { AJPS, yjcond, Px, 0x7a,0x8a },
- { ALAHF, ynone, Px, 0x9f },
- { ALARL, yml_rl, Pm, 0x02 },
- { ALARW, yml_rl, Pq, 0x02 },
- { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) },
- { ALEAL, ym_rl, Px, 0x8d },
- { ALEAQ, ym_rl, Pw, 0x8d },
- { ALEAVEL, ynone, P32, 0xc9 },
- { ALEAVEQ, ynone, Py, 0xc9 },
- { ALEAVEW, ynone, Pe, 0xc9 },
- { ALEAW, ym_rl, Pe, 0x8d },
- { ALOCK, ynone, Px, 0xf0 },
- { ALODSB, ynone, Pb, 0xac },
- { ALODSL, ynone, Px, 0xad },
- { ALODSQ, ynone, Pw, 0xad },
- { ALODSW, ynone, Pe, 0xad },
- { ALONG, ybyte, Px, 4 },
- { ALOOP, yloop, Px, 0xe2 },
- { ALOOPEQ, yloop, Px, 0xe1 },
- { ALOOPNE, yloop, Px, 0xe0 },
- { ALSLL, yml_rl, Pm, 0x03 },
- { ALSLW, yml_rl, Pq, 0x03 },
- { AMASKMOVOU, yxr, Pe, 0xf7 },
- { AMASKMOVQ, ymr, Pm, 0xf7 },
- { AMAXPD, yxm, Pe, 0x5f },
- { AMAXPS, yxm, Pm, 0x5f },
- { AMAXSD, yxm, Pf2, 0x5f },
- { AMAXSS, yxm, Pf3, 0x5f },
- { AMINPD, yxm, Pe, 0x5d },
- { AMINPS, yxm, Pm, 0x5d },
- { AMINSD, yxm, Pf2, 0x5d },
- { AMINSS, yxm, Pf3, 0x5d },
- { AMOVAPD, yxmov, Pe, 0x28,0x29 },
- { AMOVAPS, yxmov, Pm, 0x28,0x29 },
- { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
- { AMOVBLSX, ymb_rl, Pm, 0xbe },
- { AMOVBLZX, ymb_rl, Pm, 0xb6 },
- { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe },
- { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 },
- { AMOVBWSX, ymb_rl, Pq, 0xbe },
- { AMOVBWZX, ymb_rl, Pq, 0xb6 },
- { AMOVO, yxmov, Pe, 0x6f,0x7f },
- { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
- { AMOVHLPS, yxr, Pm, 0x12 },
- { AMOVHPD, yxmov, Pe, 0x16,0x17 },
- { AMOVHPS, yxmov, Pm, 0x16,0x17 },
- { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e,0 },
- { AMOVLHPS, yxr, Pm, 0x16 },
- { AMOVLPD, yxmov, Pe, 0x12,0x13 },
- { AMOVLPS, yxmov, Pm, 0x12,0x13 },
- { AMOVLQSX, yml_rl, Pw, 0x63 },
- { AMOVLQZX, yml_rl, Px, 0x8b },
- { AMOVMSKPD, yxrrl, Pq, 0x50 },
- { AMOVMSKPS, yxrrl, Pm, 0x50 },
- { AMOVNTO, yxr_ml, Pe, 0xe7 },
- { AMOVNTPD, yxr_ml, Pe, 0x2b },
- { AMOVNTPS, yxr_ml, Pm, 0x2b },
- { AMOVNTQ, ymr_ml, Pm, 0xe7 },
- { AMOVQ, ymovq, Pw, 0x89, 0x8b, 0x31, 0xc7,(00), 0xb8, 0xc7,(00), 0x6f, 0x7f, 0x6e, 0x7e, Pf2,0xd6, Pf3,0x7e, Pe,0xd6, Pe,0x6e, Pe,0x7e,0 },
- { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e },
- { AMOVSB, ynone, Pb, 0xa4 },
- { AMOVSD, yxmov, Pf2, 0x10,0x11 },
- { AMOVSL, ynone, Px, 0xa5 },
- { AMOVSQ, ynone, Pw, 0xa5 },
- { AMOVSS, yxmov, Pf3, 0x10,0x11 },
- { AMOVSW, ynone, Pe, 0xa5 },
- { AMOVUPD, yxmov, Pe, 0x10,0x11 },
- { AMOVUPS, yxmov, Pm, 0x10,0x11 },
- { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00),0 },
- { AMOVWLSX, yml_rl, Pm, 0xbf },
- { AMOVWLZX, yml_rl, Pm, 0xb7 },
- { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf },
- { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 },
- { AMULB, ydivb, Pb, 0xf6,(04) },
- { AMULL, ydivl, Px, 0xf7,(04) },
- { AMULPD, yxm, Pe, 0x59 },
- { AMULPS, yxm, Ym, 0x59 },
- { AMULQ, ydivl, Pw, 0xf7,(04) },
- { AMULSD, yxm, Pf2, 0x59 },
- { AMULSS, yxm, Pf3, 0x59 },
- { AMULW, ydivl, Pe, 0xf7,(04) },
- { ANAME },
- { ANEGB, yscond, Pb, 0xf6,(03) },
- { ANEGL, yscond, Px, 0xf7,(03) },
- { ANEGQ, yscond, Pw, 0xf7,(03) },
- { ANEGW, yscond, Pe, 0xf7,(03) },
- { ANOP, ynop, Px, 0,0 },
- { ANOTB, yscond, Pb, 0xf6,(02) },
- { ANOTL, yscond, Px, 0xf7,(02) },
- { ANOTQ, yscond, Pw, 0xf7,(02) },
- { ANOTW, yscond, Pe, 0xf7,(02) },
- { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
- { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AORPD, yxm, Pq, 0x56 },
- { AORPS, yxm, Pm, 0x56 },
- { AORQ, yxorl, Pw, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AOUTB, yin, Pb, 0xe6,0xee },
- { AOUTL, yin, Px, 0xe7,0xef },
- { AOUTSB, ynone, Pb, 0x6e },
- { AOUTSL, ynone, Px, 0x6f },
- { AOUTSW, ynone, Pe, 0x6f },
- { AOUTW, yin, Pe, 0xe7,0xef },
- { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b },
- { APACKSSWB, ymm, Py, 0x63,Pe,0x63 },
- { APACKUSWB, ymm, Py, 0x67,Pe,0x67 },
- { APADDB, ymm, Py, 0xfc,Pe,0xfc },
- { APADDL, ymm, Py, 0xfe,Pe,0xfe },
- { APADDQ, yxm, Pe, 0xd4 },
- { APADDSB, ymm, Py, 0xec,Pe,0xec },
- { APADDSW, ymm, Py, 0xed,Pe,0xed },
- { APADDUSB, ymm, Py, 0xdc,Pe,0xdc },
- { APADDUSW, ymm, Py, 0xdd,Pe,0xdd },
- { APADDW, ymm, Py, 0xfd,Pe,0xfd },
- { APAND, ymm, Py, 0xdb,Pe,0xdb },
- { APANDN, ymm, Py, 0xdf,Pe,0xdf },
- { APAUSE, ynone, Px, 0xf3,0x90 },
- { APAVGB, ymm, Py, 0xe0,Pe,0xe0 },
- { APAVGW, ymm, Py, 0xe3,Pe,0xe3 },
- { APCMPEQB, ymm, Py, 0x74,Pe,0x74 },
- { APCMPEQL, ymm, Py, 0x76,Pe,0x76 },
- { APCMPEQW, ymm, Py, 0x75,Pe,0x75 },
- { APCMPGTB, ymm, Py, 0x64,Pe,0x64 },
- { APCMPGTL, ymm, Py, 0x66,Pe,0x66 },
- { APCMPGTW, ymm, Py, 0x65,Pe,0x65 },
- { APEXTRW, yextrw, Pq, 0xc5,(00) },
- { APF2IL, ymfp, Px, 0x1d },
- { APF2IW, ymfp, Px, 0x1c },
- { API2FL, ymfp, Px, 0x0d },
- { APFACC, ymfp, Px, 0xae },
- { APFADD, ymfp, Px, 0x9e },
- { APFCMPEQ, ymfp, Px, 0xb0 },
- { APFCMPGE, ymfp, Px, 0x90 },
- { APFCMPGT, ymfp, Px, 0xa0 },
- { APFMAX, ymfp, Px, 0xa4 },
- { APFMIN, ymfp, Px, 0x94 },
- { APFMUL, ymfp, Px, 0xb4 },
- { APFNACC, ymfp, Px, 0x8a },
- { APFPNACC, ymfp, Px, 0x8e },
- { APFRCP, ymfp, Px, 0x96 },
- { APFRCPIT1, ymfp, Px, 0xa6 },
- { APFRCPI2T, ymfp, Px, 0xb6 },
- { APFRSQIT1, ymfp, Px, 0xa7 },
- { APFRSQRT, ymfp, Px, 0x97 },
- { APFSUB, ymfp, Px, 0x9a },
- { APFSUBR, ymfp, Px, 0xaa },
- { APINSRW, yinsrw, Pq, 0xc4,(00) },
- { APINSRD, yinsr, Pq, 0x3a, 0x22, (00) },
- { APINSRQ, yinsr, Pq3, 0x3a, 0x22, (00) },
- { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 },
- { APMAXSW, yxm, Pe, 0xee },
- { APMAXUB, yxm, Pe, 0xde },
- { APMINSW, yxm, Pe, 0xea },
- { APMINUB, yxm, Pe, 0xda },
- { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 },
- { APMULHRW, ymfp, Px, 0xb7 },
- { APMULHUW, ymm, Py, 0xe4,Pe,0xe4 },
- { APMULHW, ymm, Py, 0xe5,Pe,0xe5 },
- { APMULLW, ymm, Py, 0xd5,Pe,0xd5 },
- { APMULULQ, ymm, Py, 0xf4,Pe,0xf4 },
- { APOPAL, ynone, P32, 0x61 },
- { APOPAW, ynone, Pe, 0x61 },
- { APOPFL, ynone, P32, 0x9d },
- { APOPFQ, ynone, Py, 0x9d },
- { APOPFW, ynone, Pe, 0x9d },
- { APOPL, ypopl, P32, 0x58,0x8f,(00) },
- { APOPQ, ypopl, Py, 0x58,0x8f,(00) },
- { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
- { APOR, ymm, Py, 0xeb,Pe,0xeb },
- { APSADBW, yxm, Pq, 0xf6 },
- { APSHUFHW, yxshuf, Pf3, 0x70,(00) },
- { APSHUFL, yxshuf, Pq, 0x70,(00) },
- { APSHUFLW, yxshuf, Pf2, 0x70,(00) },
- { APSHUFW, ymshuf, Pm, 0x70,(00) },
- { APSHUFB, ymshufb,Pq, 0x38, 0x00 },
- { APSLLO, ypsdq, Pq, 0x73,(07) },
- { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) },
- { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06) },
- { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) },
- { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) },
- { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) },
- { APSRLO, ypsdq, Pq, 0x73,(03) },
- { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) },
- { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) },
- { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) },
- { APSUBB, yxm, Pe, 0xf8 },
- { APSUBL, yxm, Pe, 0xfa },
- { APSUBQ, yxm, Pe, 0xfb },
- { APSUBSB, yxm, Pe, 0xe8 },
- { APSUBSW, yxm, Pe, 0xe9 },
- { APSUBUSB, yxm, Pe, 0xd8 },
- { APSUBUSW, yxm, Pe, 0xd9 },
- { APSUBW, yxm, Pe, 0xf9 },
- { APSWAPL, ymfp, Px, 0xbb },
- { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 },
- { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a },
- { APUNPCKHQDQ, yxm, Pe, 0x6d },
- { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 },
- { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 },
- { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 },
- { APUNPCKLQDQ, yxm, Pe, 0x6c },
- { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 },
- { APUSHAL, ynone, P32, 0x60 },
- { APUSHAW, ynone, Pe, 0x60 },
- { APUSHFL, ynone, P32, 0x9c },
- { APUSHFQ, ynone, Py, 0x9c },
- { APUSHFW, ynone, Pe, 0x9c },
- { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 },
- { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 },
- { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
- { APXOR, ymm, Py, 0xef,Pe,0xef },
- { AQUAD, ybyte, Px, 8 },
- { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
- { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCPPS, yxm, Pm, 0x53 },
- { ARCPSS, yxm, Pf3, 0x53 },
- { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
- { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { ARCRQ, yshl, Pw, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { AREP, ynone, Px, 0xf3 },
- { AREPN, ynone, Px, 0xf2 },
- { ARET, ynone, Px, 0xc3 },
- { ARETFW, yret, Pe, 0xcb,0xca },
- { ARETFL, yret, Px, 0xcb,0xca },
- { ARETFQ, yret, Pw, 0xcb,0xca },
- { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
- { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { AROLQ, yshl, Pw, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
- { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ARSQRTPS, yxm, Pm, 0x52 },
- { ARSQRTSS, yxm, Pf3, 0x52 },
- { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */
- { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
- { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASALQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
- { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASARQ, yshl, Pw, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
- { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASBBQ, yxorl, Pw, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASCASB, ynone, Pb, 0xae },
- { ASCASL, ynone, Px, 0xaf },
- { ASCASQ, ynone, Pw, 0xaf },
- { ASCASW, ynone, Pe, 0xaf },
- { ASETCC, yscond, Pm, 0x93,(00) },
- { ASETCS, yscond, Pm, 0x92,(00) },
- { ASETEQ, yscond, Pm, 0x94,(00) },
- { ASETGE, yscond, Pm, 0x9d,(00) },
- { ASETGT, yscond, Pm, 0x9f,(00) },
- { ASETHI, yscond, Pm, 0x97,(00) },
- { ASETLE, yscond, Pm, 0x9e,(00) },
- { ASETLS, yscond, Pm, 0x96,(00) },
- { ASETLT, yscond, Pm, 0x9c,(00) },
- { ASETMI, yscond, Pm, 0x98,(00) },
- { ASETNE, yscond, Pm, 0x95,(00) },
- { ASETOC, yscond, Pm, 0x91,(00) },
- { ASETOS, yscond, Pm, 0x90,(00) },
- { ASETPC, yscond, Pm, 0x96,(00) },
- { ASETPL, yscond, Pm, 0x99,(00) },
- { ASETPS, yscond, Pm, 0x9a,(00) },
- { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
- { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHLQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
- { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASHUFPD, yxshuf, Pq, 0xc6,(00) },
- { ASHUFPS, yxshuf, Pm, 0xc6,(00) },
- { ASQRTPD, yxm, Pe, 0x51 },
- { ASQRTPS, yxm, Pm, 0x51 },
- { ASQRTSD, yxm, Pf2, 0x51 },
- { ASQRTSS, yxm, Pf3, 0x51 },
- { ASTC, ynone, Px, 0xf9 },
- { ASTD, ynone, Px, 0xfd },
- { ASTI, ynone, Px, 0xfb },
- { ASTMXCSR, ysvrs, Pm, 0xae,(03),0xae,(03) },
- { ASTOSB, ynone, Pb, 0xaa },
- { ASTOSL, ynone, Px, 0xab },
- { ASTOSQ, ynone, Pw, 0xab },
- { ASTOSW, ynone, Pe, 0xab },
- { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
- { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASUBPD, yxm, Pe, 0x5c },
- { ASUBPS, yxm, Pm, 0x5c },
- { ASUBQ, yaddl, Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASUBSD, yxm, Pf2, 0x5c },
- { ASUBSS, yxm, Pf3, 0x5c },
- { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASWAPGS, ynone, Pm, 0x01,0xf8 },
- { ASYSCALL, ynone, Px, 0x0f,0x05 }, /* fast syscall */
- { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
- { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
- { ATESTQ, ytestl, Pw, 0xa9,0xf7,(00),0x85,0x85 },
- { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
- { ATEXT, ytext, Px },
- { AUCOMISD, yxcmp, Pe, 0x2e },
- { AUCOMISS, yxcmp, Pm, 0x2e },
- { AUNPCKHPD, yxm, Pe, 0x15 },
- { AUNPCKHPS, yxm, Pm, 0x15 },
- { AUNPCKLPD, yxm, Pe, 0x14 },
- { AUNPCKLPS, yxm, Pm, 0x14 },
- { AVERR, ydivl, Pm, 0x00,(04) },
- { AVERW, ydivl, Pm, 0x00,(05) },
- { AWAIT, ynone, Px, 0x9b },
- { AWORD, ybyte, Px, 2 },
- { AXCHGB, yml_mb, Pb, 0x86,0x86 },
- { AXCHGL, yxchg, Px, 0x90,0x90,0x87,0x87 },
- { AXCHGQ, yxchg, Pw, 0x90,0x90,0x87,0x87 },
- { AXCHGW, yxchg, Pe, 0x90,0x90,0x87,0x87 },
- { AXLAT, ynone, Px, 0xd7 },
- { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
- { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
- { AXORPD, yxm, Pe, 0x57 },
- { AXORPS, yxm, Pm, 0x57 },
- { AXORQ, yxorl, Pw, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
- { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
-
- { AFMOVB, yfmvx, Px, 0xdf,(04) },
- { AFMOVBP, yfmvp, Px, 0xdf,(06) },
- { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
- { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
- { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
- { AFMOVFP, yfmvp, Px, 0xd9,(03) },
- { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
- { AFMOVLP, yfmvp, Px, 0xdb,(03) },
- { AFMOVV, yfmvx, Px, 0xdf,(05) },
- { AFMOVVP, yfmvp, Px, 0xdf,(07) },
- { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
- { AFMOVWP, yfmvp, Px, 0xdf,(03) },
- { AFMOVX, yfmvx, Px, 0xdb,(05) },
- { AFMOVXP, yfmvp, Px, 0xdb,(07) },
-
- { AFCOMB },
- { AFCOMBP },
- { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
- { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
- { AFCOMDPP, ycompp, Px, 0xde,(03) },
- { AFCOMF, yfmvx, Px, 0xd8,(02) },
- { AFCOMFP, yfmvx, Px, 0xd8,(03) },
- { AFCOML, yfmvx, Px, 0xda,(02) },
- { AFCOMLP, yfmvx, Px, 0xda,(03) },
- { AFCOMW, yfmvx, Px, 0xde,(02) },
- { AFCOMWP, yfmvx, Px, 0xde,(03) },
-
- { AFUCOM, ycompp, Px, 0xdd,(04) },
- { AFUCOMP, ycompp, Px, 0xdd,(05) },
- { AFUCOMPP, ycompp, Px, 0xda,(13) },
-
- { AFADDDP, yfaddp, Px, 0xde,(00) },
- { AFADDW, yfmvx, Px, 0xde,(00) },
- { AFADDL, yfmvx, Px, 0xda,(00) },
- { AFADDF, yfmvx, Px, 0xd8,(00) },
- { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
-
- { AFMULDP, yfaddp, Px, 0xde,(01) },
- { AFMULW, yfmvx, Px, 0xde,(01) },
- { AFMULL, yfmvx, Px, 0xda,(01) },
- { AFMULF, yfmvx, Px, 0xd8,(01) },
- { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
-
- { AFSUBDP, yfaddp, Px, 0xde,(05) },
- { AFSUBW, yfmvx, Px, 0xde,(04) },
- { AFSUBL, yfmvx, Px, 0xda,(04) },
- { AFSUBF, yfmvx, Px, 0xd8,(04) },
- { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
-
- { AFSUBRDP, yfaddp, Px, 0xde,(04) },
- { AFSUBRW, yfmvx, Px, 0xde,(05) },
- { AFSUBRL, yfmvx, Px, 0xda,(05) },
- { AFSUBRF, yfmvx, Px, 0xd8,(05) },
- { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
-
- { AFDIVDP, yfaddp, Px, 0xde,(07) },
- { AFDIVW, yfmvx, Px, 0xde,(06) },
- { AFDIVL, yfmvx, Px, 0xda,(06) },
- { AFDIVF, yfmvx, Px, 0xd8,(06) },
- { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
-
- { AFDIVRDP, yfaddp, Px, 0xde,(06) },
- { AFDIVRW, yfmvx, Px, 0xde,(07) },
- { AFDIVRL, yfmvx, Px, 0xda,(07) },
- { AFDIVRF, yfmvx, Px, 0xd8,(07) },
- { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
-
- { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
- { AFFREE },
- { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
- { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
- { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
- { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
- { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
- { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
- { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
- { AF2XM1, ynone, Px, 0xd9, 0xf0 },
- { AFABS, ynone, Px, 0xd9, 0xe1 },
- { AFCHS, ynone, Px, 0xd9, 0xe0 },
- { AFCLEX, ynone, Px, 0xdb, 0xe2 },
- { AFCOS, ynone, Px, 0xd9, 0xff },
- { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
- { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
- { AFINIT, ynone, Px, 0xdb, 0xe3 },
- { AFLD1, ynone, Px, 0xd9, 0xe8 },
- { AFLDL2E, ynone, Px, 0xd9, 0xea },
- { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
- { AFLDLG2, ynone, Px, 0xd9, 0xec },
- { AFLDLN2, ynone, Px, 0xd9, 0xed },
- { AFLDPI, ynone, Px, 0xd9, 0xeb },
- { AFLDZ, ynone, Px, 0xd9, 0xee },
- { AFNOP, ynone, Px, 0xd9, 0xd0 },
- { AFPATAN, ynone, Px, 0xd9, 0xf3 },
- { AFPREM, ynone, Px, 0xd9, 0xf8 },
- { AFPREM1, ynone, Px, 0xd9, 0xf5 },
- { AFPTAN, ynone, Px, 0xd9, 0xf2 },
- { AFRNDINT, ynone, Px, 0xd9, 0xfc },
- { AFSCALE, ynone, Px, 0xd9, 0xfd },
- { AFSIN, ynone, Px, 0xd9, 0xfe },
- { AFSINCOS, ynone, Px, 0xd9, 0xfb },
- { AFSQRT, ynone, Px, 0xd9, 0xfa },
- { AFTST, ynone, Px, 0xd9, 0xe4 },
- { AFXAM, ynone, Px, 0xd9, 0xe5 },
- { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
- { AFYL2X, ynone, Px, 0xd9, 0xf1 },
- { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
-
- { ACMPXCHGB, yrb_mb, Pb, 0x0f,0xb0 },
- { ACMPXCHGL, yrl_ml, Px, 0x0f,0xb1 },
- { ACMPXCHGW, yrl_ml, Pe, 0x0f,0xb1 },
- { ACMPXCHGQ, yrl_ml, Pw, 0x0f,0xb1 },
- { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
- { AINVD, ynone, Pm, 0x08 },
- { AINVLPG, ymbs, Pm, 0x01,(07) },
- { ALFENCE, ynone, Pm, 0xae,0xe8 },
- { AMFENCE, ynone, Pm, 0xae,0xf0 },
- { AMOVNTIL, yrl_ml, Pm, 0xc3 },
- { AMOVNTIQ, yrl_ml, Pw, 0x0f,0xc3 },
- { ARDMSR, ynone, Pm, 0x32 },
- { ARDPMC, ynone, Pm, 0x33 },
- { ARDTSC, ynone, Pm, 0x31 },
- { ARSM, ynone, Pm, 0xaa },
- { ASFENCE, ynone, Pm, 0xae,0xf8 },
- { ASYSRET, ynone, Pm, 0x07 },
- { AWBINVD, ynone, Pm, 0x09 },
- { AWRMSR, ynone, Pm, 0x30 },
-
- { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
- { AXADDL, yrl_ml, Px, 0x0f,0xc1 },
- { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 },
- { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
-
- { ACRC32B, ycrc32l,Px, 0xf2,0x0f,0x38,0xf0,0 },
- { ACRC32Q, ycrc32l,Pw, 0xf2,0x0f,0x38,0xf1,0 },
-
- { APREFETCHT0, yprefetch, Pm, 0x18,(01) },
- { APREFETCHT1, yprefetch, Pm, 0x18,(02) },
- { APREFETCHT2, yprefetch, Pm, 0x18,(03) },
- { APREFETCHNTA, yprefetch, Pm, 0x18,(00) },
-
- { AMOVQL, yrl_ml, Px, 0x89 },
-
- { AUNDEF, ynone, Px, 0x0f, 0x0b },
-
- { AAESENC, yaes, Pq, 0x38,0xdc,(0) },
- { AAESENCLAST, yaes, Pq, 0x38,0xdd,(0) },
- { AAESDEC, yaes, Pq, 0x38,0xde,(0) },
- { AAESDECLAST, yaes, Pq, 0x38,0xdf,(0) },
- { AAESIMC, yaes, Pq, 0x38,0xdb,(0) },
- { AAESKEYGENASSIST, yaes2, Pq, 0x3a,0xdf,(0) },
-
- { APSHUFD, yaes2, Pq, 0x70,(0) },
- { APCLMULQDQ, yxshuf, Pq, 0x3a,0x44,0 },
-
- { AUSEFIELD, ynop, Px, 0,0 },
- { ATYPE },
- { AFUNCDATA, yfuncdata, Px, 0,0 },
- { APCDATA, ypcdata, Px, 0,0 },
- { ACHECKNIL },
- { AFATVARDEF },
-
- { AEND },
- 0
-};
-
-Optab* opindex[ALAST+1];
-
-/*
-AMOVD 0f 6e/r mmx,reg/mem32[mem64-rex?]
-AMOVD 0f 7e/r reg/mem32[64],mmx STORE
-AMOVQ 0f 6f/r mmx1,mmx2/mem64
-AMOVQ 0f 7f/r mmx1/mem64,mmx2
-*/
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
deleted file mode 100644
index 1be3c18fe..000000000
--- a/src/cmd/6l/pass.c
+++ /dev/null
@@ -1,991 +0,0 @@
-// Inferno utils/6l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Code and data passes.
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../../pkg/runtime/stack.h"
-
-static void xfol(Prog*, Prog**);
-
-Prog*
-brchain(Prog *p)
-{
- int i;
-
- for(i=0; i<20; i++) {
- if(p == P || p->as != AJMP)
- return p;
- p = p->pcond;
- }
- return P;
-}
-
-void
-follow(void)
-{
- Prog *firstp, *lastp;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f follow\n", cputime());
- Bflush(&bso);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- firstp = prg();
- lastp = firstp;
- xfol(cursym->text, &lastp);
- lastp->link = nil;
- cursym->text = firstp->link;
- }
-}
-
-static int
-nofollow(int a)
-{
- switch(a) {
- case AJMP:
- case ARET:
- case AIRETL:
- case AIRETQ:
- case AIRETW:
- case ARETFL:
- case ARETFQ:
- case ARETFW:
- case AUNDEF:
- return 1;
- }
- return 0;
-}
-
-static int
-pushpop(int a)
-{
- switch(a) {
- case APUSHL:
- case APUSHFL:
- case APUSHQ:
- case APUSHFQ:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPQ:
- case APOPFQ:
- case APOPW:
- case APOPFW:
- return 1;
- }
- return 0;
-}
-
-static void
-xfol(Prog *p, Prog **last)
-{
- Prog *q;
- int i;
- enum as a;
-
-loop:
- if(p == P)
- return;
- if(p->as == AJMP)
- if((q = p->pcond) != P && q->as != ATEXT) {
- /* mark instruction as done and continue layout at target of jump */
- p->mark = 1;
- p = q;
- if(p->mark == 0)
- goto loop;
- }
- if(p->mark) {
- /*
- * p goes here, but already used it elsewhere.
- * copy up to 4 instructions or else branch to other copy.
- */
- for(i=0,q=p; i<4; i++,q=q->link) {
- if(q == P)
- break;
- if(q == *last)
- break;
- a = q->as;
- if(a == ANOP) {
- i--;
- continue;
- }
- if(nofollow(a) || pushpop(a))
- break; // NOTE(rsc): arm does goto copy
- if(q->pcond == P || q->pcond->mark)
- continue;
- if(a == ACALL || a == ALOOP)
- continue;
- for(;;) {
- if(p->as == ANOP) {
- p = p->link;
- continue;
- }
- q = copyp(p);
- p = p->link;
- q->mark = 1;
- (*last)->link = q;
- *last = q;
- if(q->as != a || q->pcond == P || q->pcond->mark)
- continue;
-
- q->as = relinv(q->as);
- p = q->pcond;
- q->pcond = q->link;
- q->link = p;
- xfol(q->link, last);
- p = q->link;
- if(p->mark)
- return;
- goto loop;
- }
- } /* */
- q = prg();
- q->as = AJMP;
- q->line = p->line;
- q->to.type = D_BRANCH;
- q->to.offset = p->pc;
- q->pcond = p;
- p = q;
- }
-
- /* emit p */
- p->mark = 1;
- (*last)->link = p;
- *last = p;
- a = p->as;
-
- /* continue loop with what comes after p */
- if(nofollow(a))
- return;
- if(p->pcond != P && a != ACALL) {
- /*
- * some kind of conditional branch.
- * recurse to follow one path.
- * continue loop on the other.
- */
- if((q = brchain(p->pcond)) != P)
- p->pcond = q;
- if((q = brchain(p->link)) != P)
- p->link = q;
- if(p->from.type == D_CONST) {
- if(p->from.offset == 1) {
- /*
- * expect conditional jump to be taken.
- * rewrite so that's the fall-through case.
- */
- p->as = relinv(a);
- q = p->link;
- p->link = p->pcond;
- p->pcond = q;
- }
- } else {
- q = p->link;
- if(q->mark)
- if(a != ALOOP) {
- p->as = relinv(a);
- p->link = p->pcond;
- p->pcond = q;
- }
- }
- xfol(p->link, last);
- if(p->pcond->mark)
- return;
- p = p->pcond;
- goto loop;
- }
- p = p->link;
- goto loop;
-}
-
-Prog*
-byteq(int v)
-{
- Prog *p;
-
- p = prg();
- p->as = ABYTE;
- p->from.type = D_CONST;
- p->from.offset = v&0xff;
- return p;
-}
-
-int
-relinv(int a)
-{
-
- switch(a) {
- case AJEQ: return AJNE;
- case AJNE: return AJEQ;
- case AJLE: return AJGT;
- case AJLS: return AJHI;
- case AJLT: return AJGE;
- case AJMI: return AJPL;
- case AJGE: return AJLT;
- case AJPL: return AJMI;
- case AJGT: return AJLE;
- case AJHI: return AJLS;
- case AJCS: return AJCC;
- case AJCC: return AJCS;
- case AJPS: return AJPC;
- case AJPC: return AJPS;
- case AJOS: return AJOC;
- case AJOC: return AJOS;
- }
- diag("unknown relation: %s in %s", anames[a], TNAME);
- errorexit();
- return a;
-}
-
-void
-patch(void)
-{
- int32 c;
- Prog *p, *q;
- Sym *s;
- int32 vexit;
- Sym *gmsym;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f mkfwd\n", cputime());
- Bflush(&bso);
- mkfwd();
- if(debug['v'])
- Bprint(&bso, "%5.2f patch\n", cputime());
- Bflush(&bso);
-
- if(flag_shared) {
- s = lookup("init_array", 0);
- s->type = SINITARR;
- s->reachable = 1;
- s->hide = 1;
- addaddr(s, lookup(INITENTRY, 0));
- }
-
- gmsym = lookup("runtime.tlsgm", 0);
- if(linkmode != LinkExternal)
- gmsym->reachable = 0;
- s = lookup("exit", 0);
- vexit = s->value;
- for(cursym = textp; cursym != nil; cursym = cursym->next)
- for(p = cursym->text; p != P; p = p->link) {
- if(HEADTYPE == Hwindows) {
- // Windows
- // Convert
- // op n(GS), reg
- // to
- // MOVL 0x28(GS), reg
- // op n(reg), reg
- // The purpose of this patch is to fix some accesses
- // to extern register variables (TLS) on Windows, as
- // a different method is used to access them.
- if(p->from.type == D_INDIR+D_GS
- && p->to.type >= D_AX && p->to.type <= D_DI
- && p->from.offset <= 8) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0x28;
- }
- }
- if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
- || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
- || HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) {
- // ELF uses FS instead of GS.
- if(p->from.type == D_INDIR+D_GS)
- p->from.type = D_INDIR+D_FS;
- if(p->to.type == D_INDIR+D_GS)
- p->to.type = D_INDIR+D_FS;
- if(p->from.index == D_GS)
- p->from.index = D_FS;
- if(p->to.index == D_GS)
- p->to.index = D_FS;
- }
- if(!flag_shared) {
- // Convert g() or m() accesses of the form
- // op n(reg)(GS*1), reg
- // to
- // op n(GS*1), reg
- if(p->from.index == D_FS || p->from.index == D_GS) {
- p->from.type = D_INDIR + p->from.index;
- p->from.index = D_NONE;
- }
- // Convert g() or m() accesses of the form
- // op reg, n(reg)(GS*1)
- // to
- // op reg, n(GS*1)
- if(p->to.index == D_FS || p->to.index == D_GS) {
- p->to.type = D_INDIR + p->to.index;
- p->to.index = D_NONE;
- }
- // Convert get_tls access of the form
- // op runtime.tlsgm(SB), reg
- // to
- // NOP
- if(gmsym != S && p->from.sym == gmsym) {
- p->as = ANOP;
- p->from.type = D_NONE;
- p->to.type = D_NONE;
- p->from.sym = nil;
- p->to.sym = nil;
- continue;
- }
- } else {
- // Convert TLS reads of the form
- // op n(GS), reg
- // to
- // MOVQ $runtime.tlsgm(SB), reg
- // op n(reg)(GS*1), reg
- if((p->from.type == D_INDIR+D_FS || p->from.type == D_INDIR + D_GS) && p->to.type >= D_AX && p->to.type <= D_DI) {
- q = appendp(p);
- q->to = p->to;
- q->as = p->as;
- q->from.type = D_INDIR+p->to.type;
- q->from.index = p->from.type - D_INDIR;
- q->from.scale = 1;
- q->from.offset = p->from.offset;
- p->as = AMOVQ;
- p->from.type = D_EXTERN;
- p->from.sym = gmsym;
- p->from.offset = 0;
- }
- }
- if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
- s = p->to.sym;
- if(s) {
- if(debug['c'])
- Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- if((s->type&SMASK) != STEXT) {
- /* diag prints TNAME first */
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- }
- if(s->text == nil)
- continue;
- p->to.type = D_BRANCH;
- p->to.offset = s->text->pc;
- p->pcond = s->text;
- continue;
- }
- }
- if(p->to.type != D_BRANCH)
- continue;
- c = p->to.offset;
- for(q = cursym->text; q != P;) {
- if(c == q->pc)
- break;
- if(q->forwd != P && c >= q->forwd->pc)
- q = q->forwd;
- else
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range in %s (%#ux)\n%P [%s]",
- TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
- p->to.type = D_NONE;
- }
- p->pcond = q;
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next)
- for(p = cursym->text; p != P; p = p->link) {
- p->mark = 0; /* initialization for follow */
- if(p->pcond != P) {
- p->pcond = brloop(p->pcond);
- if(p->pcond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->pcond->pc;
- }
- }
-}
-
-Prog*
-brloop(Prog *p)
-{
- int c;
- Prog *q;
-
- c = 0;
- for(q = p; q != P; q = q->pcond) {
- if(q->as != AJMP)
- break;
- c++;
- if(c >= 5000)
- return P;
- }
- return q;
-}
-
-static char*
-morename[] =
-{
- "runtime.morestack00",
- "runtime.morestack10",
- "runtime.morestack01",
- "runtime.morestack11",
-
- "runtime.morestack8",
- "runtime.morestack16",
- "runtime.morestack24",
- "runtime.morestack32",
- "runtime.morestack40",
- "runtime.morestack48",
-};
-Prog* pmorestack[nelem(morename)];
-Sym* symmorestack[nelem(morename)];
-Sym* gmsym;
-
-static Prog* load_g_cx(Prog*);
-static Prog* stacksplit(Prog*, int32, Prog**);
-
-void
-dostkoff(void)
-{
- Prog *p, *q, *q1;
- int32 autoffset, deltasp;
- int a, pcsize;
- uint32 i;
-
- gmsym = lookup("runtime.tlsgm", 0);
- for(i=0; i<nelem(morename); i++) {
- symmorestack[i] = lookup(morename[i], 0);
- if(symmorestack[i]->type != STEXT)
- diag("morestack trampoline not defined - %s", morename[i]);
- pmorestack[i] = symmorestack[i]->text;
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->text->link == nil)
- continue;
-
- p = cursym->text;
- parsetextconst(p->to.offset);
- autoffset = textstksiz;
- if(autoffset < 0)
- autoffset = 0;
-
- if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) {
- for(q = p; q != P; q = q->link)
- if(q->as == ACALL)
- goto noleaf;
- p->from.scale |= NOSPLIT;
- noleaf:;
- }
-
- if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
- diag("nosplit func likely to overflow stack");
-
- q = P;
- if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
- p = appendp(p);
- p = load_g_cx(p); // load g into CX
- }
- if(!(cursym->text->from.scale & NOSPLIT))
- p = stacksplit(p, autoffset, &q); // emit split check
-
- if(autoffset) {
- p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- p->spadj = autoffset;
- } else {
- // zero-byte stack adjustment.
- // Insert a fake non-zero adjustment so that stkcheck can
- // recognize the end of the stack-splitting prolog.
- p = appendp(p);
- p->as = ANOP;
- p->spadj = -PtrSize;
- p = appendp(p);
- p->as = ANOP;
- p->spadj = PtrSize;
- }
- if(q != P)
- q->pcond = p;
- deltasp = autoffset;
-
- if(cursym->text->from.scale & WRAPPER) {
- // g->panicwrap += autoffset + PtrSize;
- p = appendp(p);
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = autoffset + PtrSize;
- p->to.type = D_INDIR+D_CX;
- p->to.offset = 2*PtrSize;
- }
-
- if(debug['K'] > 1 && autoffset) {
- // 6l -KK means double-check for stack overflow
- // even after calling morestack and even if the
- // function is marked as nosplit.
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = ASUBQ;
- p->from.type = D_CONST;
- p->from.offset = StackSmall+32;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
-
- p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- }
-
- if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
- // 6l -Z means zero the stack frame on entry.
- // This slows down function calls but can help avoid
- // false positives in garbage collection.
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_SP;
- p->to.type = D_DI;
-
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_CONST;
- p->from.offset = autoffset/8;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_CONST;
- p->from.offset = 0;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = AREP;
-
- p = appendp(p);
- p->as = ASTOSQ;
- }
-
- for(; p != P; p = p->link) {
- pcsize = p->mode/8;
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + pcsize;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + pcsize;
-
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- p->spadj = 4;
- continue;
- case APUSHQ:
- case APUSHFQ:
- deltasp += 8;
- p->spadj = 8;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- p->spadj = 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- p->spadj = -4;
- continue;
- case APOPQ:
- case APOPFQ:
- deltasp -= 8;
- p->spadj = -8;
- continue;
- case APOPW:
- case APOPFW:
- deltasp -= 2;
- p->spadj = -2;
- continue;
- case ARET:
- break;
- }
-
- if(autoffset != deltasp)
- diag("unbalanced PUSH/POP");
-
- if(cursym->text->from.scale & WRAPPER) {
- p = load_g_cx(p);
- p = appendp(p);
- // g->panicwrap -= autoffset + PtrSize;
- p->as = ASUBL;
- p->from.type = D_CONST;
- p->from.offset = autoffset + PtrSize;
- p->to.type = D_INDIR+D_CX;
- p->to.offset = 2*PtrSize;
- p = appendp(p);
- p->as = ARET;
- }
-
- if(autoffset) {
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = -autoffset;
- p->spadj = -autoffset;
- p = appendp(p);
- p->as = ARET;
- // If there are instructions following
- // this ARET, they come from a branch
- // with the same stackframe, so undo
- // the cleanup.
- p->spadj = +autoffset;
- }
- if(p->to.sym) // retjmp
- p->as = AJMP;
- }
- }
-}
-
-// Append code to p to load g into cx.
-// Overwrites p with the first instruction (no first appendp).
-// Overwriting p is unusual but it lets use this in both the
-// prologue (caller must call appendp first) and in the epilogue.
-// Returns last new instruction.
-static Prog*
-load_g_cx(Prog *p)
-{
- if(flag_shared) {
- // Load TLS offset with MOVQ $runtime.tlsgm(SB), CX
- p->as = AMOVQ;
- p->from.type = D_EXTERN;
- p->from.sym = gmsym;
- p->to.type = D_CX;
- p = appendp(p);
- }
- p->as = AMOVQ;
- if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
- || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
- || HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly)
- // ELF uses FS
- p->from.type = D_INDIR+D_FS;
- else
- p->from.type = D_INDIR+D_GS;
- if(flag_shared) {
- // Add TLS offset stored in CX
- p->from.index = p->from.type - D_INDIR;
- p->from.type = D_INDIR + D_CX;
- }
- p->from.offset = tlsoffset+0;
- p->to.type = D_CX;
- if(HEADTYPE == Hwindows) {
- // movq %gs:0x28, %rcx
- // movq (%rcx), %rcx
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0x28;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_CX;
- }
- return p;
-}
-
-// Append code to p to check for stack split.
-// Appends to (does not overwrite) p.
-// Assumes g is in CX.
-// Returns last new instruction.
-// On return, *jmpok is the instruction that should jump
-// to the stack frame allocation if no split is needed.
-static Prog*
-stacksplit(Prog *p, int32 framesize, Prog **jmpok)
-{
- Prog *q, *q1;
- uint32 moreconst1, moreconst2, i;
-
- if(debug['K']) {
- // 6l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 8;
- p->to.type = D_SP;
-
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
-
- p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- }
-
- q = P;
- q1 = P;
- if(framesize <= StackSmall) {
- // small stack: SP <= stackguard
- // CMPQ SP, stackguard
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_CX;
- } else if(framesize <= StackBig) {
- // large stack: SP-framesize <= stackguard-StackSmall
- // LEAQ -xxx(SP), AX
- // CMPQ AX, stackguard
- p = appendp(p);
- p->as = ALEAQ;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(framesize-StackSmall);
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_CX;
- } else {
- // Such a large stack we need to protect against wraparound.
- // If SP is close to zero:
- // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
- // The +StackGuard on both sides is required to keep the left side positive:
- // SP is allowed to be slightly below stackguard. See stack.h.
- //
- // Preemption sets stackguard to StackPreempt, a very large value.
- // That breaks the math above, so we have to check for that explicitly.
- // MOVQ stackguard, CX
- // CMPQ CX, $StackPreempt
- // JEQ label-of-call-to-morestack
- // LEAQ StackGuard(SP), AX
- // SUBQ CX, AX
- // CMPQ AX, $(framesize+(StackGuard-StackSmall))
-
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_SI;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SI;
- p->to.type = D_CONST;
- p->to.offset = StackPreempt;
-
- p = appendp(p);
- p->as = AJEQ;
- p->to.type = D_BRANCH;
- q1 = p;
-
- p = appendp(p);
- p->as = ALEAQ;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = StackGuard;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ASUBQ;
- p->from.type = D_SI;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_AX;
- p->to.type = D_CONST;
- p->to.offset = framesize+(StackGuard-StackSmall);
- }
-
- // common
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- q = p;
-
- // If we ask for more stack, we'll get a minimum of StackMin bytes.
- // We need a stack frame large enough to hold the top-of-stack data,
- // the function arguments+results, our caller's PC, our frame,
- // a word for the return PC of the next call, and then the StackLimit bytes
- // that must be available on entry to any function called from a function
- // that did a stack check. If StackMin is enough, don't ask for a specific
- // amount: then we can use the custom functions and save a few
- // instructions.
- moreconst1 = 0;
- if(StackTop + textarg + PtrSize + framesize + PtrSize + StackLimit >= StackMin)
- moreconst1 = framesize;
- moreconst2 = textarg;
- if(moreconst2 == 1) // special marker
- moreconst2 = 0;
- if((moreconst2&7) != 0)
- diag("misaligned argument size in stack split");
- // 4 varieties varieties (const1==0 cross const2==0)
- // and 6 subvarieties of (const1==0 and const2!=0)
- p = appendp(p);
- if(moreconst1 == 0 && moreconst2 == 0) {
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[0];
- p->to.sym = symmorestack[0];
- } else
- if(moreconst1 != 0 && moreconst2 == 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst1;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[1];
- p->to.sym = symmorestack[1];
- } else
- if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
- i = moreconst2/8 + 3;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[i];
- p->to.sym = symmorestack[i];
- } else
- if(moreconst1 == 0 && moreconst2 != 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst2;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[2];
- p->to.sym = symmorestack[2];
- } else {
- p->as = AMOVQ;
- p->from.type = D_CONST;
- p->from.offset = (uint64)moreconst2 << 32;
- p->from.offset |= moreconst1;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[3];
- p->to.sym = symmorestack[3];
- }
-
- p = appendp(p);
- p->as = AJMP;
- p->to.type = D_BRANCH;
- p->pcond = cursym->text->link;
-
- if(q != P)
- q->pcond = p->link;
- if(q1 != P)
- q1->pcond = q->link;
-
- *jmpok = q;
- return p;
-}
-
-vlong
-atolwhex(char *s)
-{
- vlong n;
- int f;
-
- n = 0;
- f = 0;
- while(*s == ' ' || *s == '\t')
- s++;
- if(*s == '-' || *s == '+') {
- if(*s++ == '-')
- f = 1;
- while(*s == ' ' || *s == '\t')
- s++;
- }
- if(s[0]=='0' && s[1]){
- if(s[1]=='x' || s[1]=='X'){
- s += 2;
- for(;;){
- if(*s >= '0' && *s <= '9')
- n = n*16 + *s++ - '0';
- else if(*s >= 'a' && *s <= 'f')
- n = n*16 + *s++ - 'a' + 10;
- else if(*s >= 'A' && *s <= 'F')
- n = n*16 + *s++ - 'A' + 10;
- else
- break;
- }
- } else
- while(*s >= '0' && *s <= '7')
- n = n*8 + *s++ - '0';
- } else
- while(*s >= '0' && *s <= '9')
- n = n*10 + *s++ - '0';
- if(f)
- n = -n;
- return n;
-}
diff --git a/src/cmd/6l/prof.c b/src/cmd/6l/prof.c
deleted file mode 100644
index 862ce080c..000000000
--- a/src/cmd/6l/prof.c
+++ /dev/null
@@ -1,171 +0,0 @@
-// Inferno utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Profiling.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-doprof1(void)
-{
-#ifdef NOTDEF
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->from.scale = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.sym = s;
- q->from.scale = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->size = n*4;
-#endif
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
-
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
-
- ps2 = P;
- ps4 = P;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- if(p->from.sym == s2) {
- p->from.scale = 1;
- ps2 = p;
- }
- if(p->from.sym == s4) {
- p->from.scale = 1;
- ps4 = p;
- }
- }
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
-
- if(p->from.scale & NOPROF) /* dont profile */
- continue;
-
- /*
- * JMPL profin
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = ps2;
- p->to.sym = s2;
-
- for(; p; p=p->link) {
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * JAL profout
- */
- p->as = ACALL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->pcond = ps4;
- p->to.sym = s4;
-
- p = q;
- }
- }
- }
-}
diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c
deleted file mode 100644
index 74f11d635..000000000
--- a/src/cmd/6l/span.c
+++ /dev/null
@@ -1,1846 +0,0 @@
-// Inferno utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Instruction layout.
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/elf.h"
-
-static int rexflag;
-static int asmode;
-static vlong vaddr(Adr*, Reloc*);
-
-// single-instruction no-ops of various lengths.
-// constructed by hand and disassembled with gdb to verify.
-// see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion.
-static uchar nop[][16] = {
- {0x90},
- {0x66, 0x90},
- {0x0F, 0x1F, 0x00},
- {0x0F, 0x1F, 0x40, 0x00},
- {0x0F, 0x1F, 0x44, 0x00, 0x00},
- {0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00},
- {0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00},
- {0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
-};
-
-static void
-fillnop(uchar *p, int n)
-{
- int m;
-
- while(n > 0) {
- m = n;
- if(m > nelem(nop))
- m = nelem(nop);
- memmove(p, nop[m-1], m);
- p += m;
- n -= m;
- }
-}
-
-void
-span1(Sym *s)
-{
- Prog *p, *q;
- int32 c, v, loop;
- uchar *bp;
- int n, m, i;
-
- cursym = s;
-
- if(s->p != nil)
- return;
-
- for(p = s->text; p != P; p = p->link) {
- p->back = 2; // use short branches first time through
- if((q = p->pcond) != P && (q->back & 2)) {
- p->back |= 1; // backward jump
- q->back |= 4; // loop head
- }
-
- if(p->as == AADJSP) {
- p->to.type = D_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = p->mode != 64? AADDL: AADDQ;
- if(v < 0) {
- p->as = p->mode != 64? ASUBL: ASUBQ;
- v = -v;
- p->from.offset = v;
- }
- if(v == 0)
- p->as = ANOP;
- }
- }
-
- n = 0;
- do {
- loop = 0;
- memset(s->r, 0, s->nr*sizeof s->r[0]);
- s->nr = 0;
- s->np = 0;
- c = 0;
- for(p = s->text; p != P; p = p->link) {
- if((p->back & 4) && (c&(LoopAlign-1)) != 0) {
- // pad with NOPs
- v = -c&(LoopAlign-1);
- if(v <= MaxLoopPad) {
- symgrow(s, c+v);
- fillnop(s->p+c, v);
- c += v;
- }
- }
-
- p->pc = c;
-
- // process forward jumps to p
- for(q = p->comefrom; q != P; q = q->forwd) {
- v = p->pc - (q->pc + q->mark);
- if(q->back & 2) { // short
- if(v > 127) {
- loop++;
- q->back ^= 2;
- }
- if(q->as == AJCXZL)
- s->p[q->pc+2] = v;
- else
- s->p[q->pc+1] = v;
- } else {
- bp = s->p + q->pc + q->mark - 4;
- *bp++ = v;
- *bp++ = v>>8;
- *bp++ = v>>16;
- *bp = v>>24;
- }
- }
- p->comefrom = P;
-
- asmins(p);
- p->pc = c;
- m = andptr-and;
- symgrow(s, p->pc+m);
- memmove(s->p+p->pc, and, m);
- p->mark = m;
- c += m;
- }
- if(++n > 20) {
- diag("span must be looping");
- errorexit();
- }
- } while(loop);
- s->size = c;
-
- if(debug['a'] > 1) {
- print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
- for(i=0; i<s->np; i++) {
- print(" %.2ux", s->p[i]);
- if(i%16 == 15)
- print("\n %.6ux", i+1);
- }
- if(i%16)
- print("\n");
-
- for(i=0; i<s->nr; i++) {
- Reloc *r;
-
- r = &s->r[i];
- print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
- }
- }
-}
-
-void
-span(void)
-{
- Prog *p, *q;
- int32 v;
- int n;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
-
- // NOTE(rsc): If we get rid of the globals we should
- // be able to parallelize these iterations.
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->p != nil)
- continue;
- // TODO: move into span1
- for(p = cursym->text; p != P; p = p->link) {
- n = 0;
- if(p->to.type == D_BRANCH)
- if(p->pcond == P)
- p->pcond = p;
- if((q = p->pcond) != P)
- if(q->back != 2)
- n = 1;
- p->back = n;
- if(p->as == AADJSP) {
- p->to.type = D_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = p->mode != 64? AADDL: AADDQ;
- if(v < 0) {
- p->as = p->mode != 64? ASUBL: ASUBQ;
- v = -v;
- p->from.offset = v;
- }
- if(v == 0)
- p->as = ANOP;
- }
- }
- span1(cursym);
- }
-}
-
-void
-xdefine(char *p, int t, vlong v)
-{
- Sym *s;
-
- s = lookup(p, 0);
- s->type = t;
- s->value = v;
- s->reachable = 1;
- s->special = 1;
-}
-
-void
-instinit(void)
-{
- int c, i;
-
- for(i=1; optab[i].as; i++) {
- c = optab[i].as;
- if(opindex[c] != nil) {
- diag("phase error in optab: %d (%A)", i, c);
- errorexit();
- }
- opindex[c] = &optab[i];
- }
-
- for(i=0; i<Ymax; i++)
- ycover[i*Ymax + i] = 1;
-
- ycover[Yi0*Ymax + Yi8] = 1;
- ycover[Yi1*Ymax + Yi8] = 1;
-
- ycover[Yi0*Ymax + Ys32] = 1;
- ycover[Yi1*Ymax + Ys32] = 1;
- ycover[Yi8*Ymax + Ys32] = 1;
-
- ycover[Yi0*Ymax + Yi32] = 1;
- ycover[Yi1*Ymax + Yi32] = 1;
- ycover[Yi8*Ymax + Yi32] = 1;
- ycover[Ys32*Ymax + Yi32] = 1;
-
- ycover[Yi0*Ymax + Yi64] = 1;
- ycover[Yi1*Ymax + Yi64] = 1;
- ycover[Yi8*Ymax + Yi64] = 1;
- ycover[Ys32*Ymax + Yi64] = 1;
- ycover[Yi32*Ymax + Yi64] = 1;
-
- ycover[Yal*Ymax + Yrb] = 1;
- ycover[Ycl*Ymax + Yrb] = 1;
- ycover[Yax*Ymax + Yrb] = 1;
- ycover[Ycx*Ymax + Yrb] = 1;
- ycover[Yrx*Ymax + Yrb] = 1;
- ycover[Yrl*Ymax + Yrb] = 1;
-
- ycover[Ycl*Ymax + Ycx] = 1;
-
- ycover[Yax*Ymax + Yrx] = 1;
- ycover[Ycx*Ymax + Yrx] = 1;
-
- ycover[Yax*Ymax + Yrl] = 1;
- ycover[Ycx*Ymax + Yrl] = 1;
- ycover[Yrx*Ymax + Yrl] = 1;
-
- ycover[Yf0*Ymax + Yrf] = 1;
-
- ycover[Yal*Ymax + Ymb] = 1;
- ycover[Ycl*Ymax + Ymb] = 1;
- ycover[Yax*Ymax + Ymb] = 1;
- ycover[Ycx*Ymax + Ymb] = 1;
- ycover[Yrx*Ymax + Ymb] = 1;
- ycover[Yrb*Ymax + Ymb] = 1;
- ycover[Yrl*Ymax + Ymb] = 1;
- ycover[Ym*Ymax + Ymb] = 1;
-
- ycover[Yax*Ymax + Yml] = 1;
- ycover[Ycx*Ymax + Yml] = 1;
- ycover[Yrx*Ymax + Yml] = 1;
- ycover[Yrl*Ymax + Yml] = 1;
- ycover[Ym*Ymax + Yml] = 1;
-
- ycover[Yax*Ymax + Ymm] = 1;
- ycover[Ycx*Ymax + Ymm] = 1;
- ycover[Yrx*Ymax + Ymm] = 1;
- ycover[Yrl*Ymax + Ymm] = 1;
- ycover[Ym*Ymax + Ymm] = 1;
- ycover[Ymr*Ymax + Ymm] = 1;
-
- ycover[Ym*Ymax + Yxm] = 1;
- ycover[Yxr*Ymax + Yxm] = 1;
-
- for(i=0; i<D_NONE; i++) {
- reg[i] = -1;
- if(i >= D_AL && i <= D_R15B) {
- reg[i] = (i-D_AL) & 7;
- if(i >= D_SPB && i <= D_DIB)
- regrex[i] = 0x40;
- if(i >= D_R8B && i <= D_R15B)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_AH && i<= D_BH)
- reg[i] = 4 + ((i-D_AH) & 7);
- if(i >= D_AX && i <= D_R15) {
- reg[i] = (i-D_AX) & 7;
- if(i >= D_R8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_F0 && i <= D_F0+7)
- reg[i] = (i-D_F0) & 7;
- if(i >= D_M0 && i <= D_M0+7)
- reg[i] = (i-D_M0) & 7;
- if(i >= D_X0 && i <= D_X0+15) {
- reg[i] = (i-D_X0) & 7;
- if(i >= D_X0+8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_CR+8 && i <= D_CR+15)
- regrex[i] = Rxr;
- }
-}
-
-int
-prefixof(Adr *a)
-{
- switch(a->type) {
- case D_INDIR+D_CS:
- return 0x2e;
- case D_INDIR+D_DS:
- return 0x3e;
- case D_INDIR+D_ES:
- return 0x26;
- case D_INDIR+D_FS:
- return 0x64;
- case D_INDIR+D_GS:
- return 0x65;
- }
- switch(a->index) {
- case D_CS:
- return 0x2e;
- case D_DS:
- return 0x3e;
- case D_ES:
- return 0x26;
- case D_FS:
- return 0x64;
- case D_GS:
- return 0x65;
- }
- return 0;
-}
-
-int
-oclass(Adr *a)
-{
- vlong v;
- int32 l;
-
- if(a->type >= D_INDIR || a->index != D_NONE) {
- if(a->index != D_NONE && a->scale == 0) {
- if(a->type == D_ADDR) {
- switch(a->index) {
- case D_EXTERN:
- case D_STATIC:
- if(flag_shared)
- return Yiauto;
- else
- return Yi32; /* TO DO: Yi64 */
- case D_AUTO:
- case D_PARAM:
- return Yiauto;
- }
- return Yxxx;
- }
- return Ycol;
- }
- return Ym;
- }
- switch(a->type)
- {
- case D_AL:
- return Yal;
-
- case D_AX:
- return Yax;
-
-/*
- case D_SPB:
-*/
- case D_BPB:
- case D_SIB:
- case D_DIB:
- case D_R8B:
- case D_R9B:
- case D_R10B:
- case D_R11B:
- case D_R12B:
- case D_R13B:
- case D_R14B:
- case D_R15B:
- if(asmode != 64)
- return Yxxx;
- case D_DL:
- case D_BL:
- case D_AH:
- case D_CH:
- case D_DH:
- case D_BH:
- return Yrb;
-
- case D_CL:
- return Ycl;
-
- case D_CX:
- return Ycx;
-
- case D_DX:
- case D_BX:
- return Yrx;
-
- case D_R8: /* not really Yrl */
- case D_R9:
- case D_R10:
- case D_R11:
- case D_R12:
- case D_R13:
- case D_R14:
- case D_R15:
- if(asmode != 64)
- return Yxxx;
- case D_SP:
- case D_BP:
- case D_SI:
- case D_DI:
- return Yrl;
-
- case D_F0+0:
- return Yf0;
-
- case D_F0+1:
- case D_F0+2:
- case D_F0+3:
- case D_F0+4:
- case D_F0+5:
- case D_F0+6:
- case D_F0+7:
- return Yrf;
-
- case D_M0+0:
- case D_M0+1:
- case D_M0+2:
- case D_M0+3:
- case D_M0+4:
- case D_M0+5:
- case D_M0+6:
- case D_M0+7:
- return Ymr;
-
- case D_X0+0:
- case D_X0+1:
- case D_X0+2:
- case D_X0+3:
- case D_X0+4:
- case D_X0+5:
- case D_X0+6:
- case D_X0+7:
- case D_X0+8:
- case D_X0+9:
- case D_X0+10:
- case D_X0+11:
- case D_X0+12:
- case D_X0+13:
- case D_X0+14:
- case D_X0+15:
- return Yxr;
-
- case D_NONE:
- return Ynone;
-
- case D_CS: return Ycs;
- case D_SS: return Yss;
- case D_DS: return Yds;
- case D_ES: return Yes;
- case D_FS: return Yfs;
- case D_GS: return Ygs;
-
- case D_GDTR: return Ygdtr;
- case D_IDTR: return Yidtr;
- case D_LDTR: return Yldtr;
- case D_MSW: return Ymsw;
- case D_TASK: return Ytask;
-
- case D_CR+0: return Ycr0;
- case D_CR+1: return Ycr1;
- case D_CR+2: return Ycr2;
- case D_CR+3: return Ycr3;
- case D_CR+4: return Ycr4;
- case D_CR+5: return Ycr5;
- case D_CR+6: return Ycr6;
- case D_CR+7: return Ycr7;
- case D_CR+8: return Ycr8;
-
- case D_DR+0: return Ydr0;
- case D_DR+1: return Ydr1;
- case D_DR+2: return Ydr2;
- case D_DR+3: return Ydr3;
- case D_DR+4: return Ydr4;
- case D_DR+5: return Ydr5;
- case D_DR+6: return Ydr6;
- case D_DR+7: return Ydr7;
-
- case D_TR+0: return Ytr0;
- case D_TR+1: return Ytr1;
- case D_TR+2: return Ytr2;
- case D_TR+3: return Ytr3;
- case D_TR+4: return Ytr4;
- case D_TR+5: return Ytr5;
- case D_TR+6: return Ytr6;
- case D_TR+7: return Ytr7;
-
- case D_EXTERN:
- case D_STATIC:
- case D_AUTO:
- case D_PARAM:
- return Ym;
-
- case D_CONST:
- case D_ADDR:
- if(a->sym == S) {
- v = a->offset;
- if(v == 0)
- return Yi0;
- if(v == 1)
- return Yi1;
- if(v >= -128 && v <= 127)
- return Yi8;
- l = v;
- if((vlong)l == v)
- return Ys32; /* can sign extend */
- if((v>>32) == 0)
- return Yi32; /* unsigned */
- return Yi64;
- }
- return Yi32; /* TO DO: D_ADDR as Yi64 */
-
- case D_BRANCH:
- return Ybr;
- }
- return Yxxx;
-}
-
-void
-asmidx(int scale, int index, int base)
-{
- int i;
-
- switch(index) {
- default:
- goto bad;
-
- case D_NONE:
- i = 4 << 3;
- goto bas;
-
- case D_R8:
- case D_R9:
- case D_R10:
- case D_R11:
- case D_R12:
- case D_R13:
- case D_R14:
- case D_R15:
- if(asmode != 64)
- goto bad;
- case D_AX:
- case D_CX:
- case D_DX:
- case D_BX:
- case D_BP:
- case D_SI:
- case D_DI:
- i = reg[index] << 3;
- break;
- }
- switch(scale) {
- default:
- goto bad;
- case 1:
- break;
- case 2:
- i |= (1<<6);
- break;
- case 4:
- i |= (2<<6);
- break;
- case 8:
- i |= (3<<6);
- break;
- }
-bas:
- switch(base) {
- default:
- goto bad;
- case D_NONE: /* must be mod=00 */
- i |= 5;
- break;
- case D_R8:
- case D_R9:
- case D_R10:
- case D_R11:
- case D_R12:
- case D_R13:
- case D_R14:
- case D_R15:
- if(asmode != 64)
- goto bad;
- case D_AX:
- case D_CX:
- case D_DX:
- case D_BX:
- case D_SP:
- case D_BP:
- case D_SI:
- case D_DI:
- i |= reg[base];
- break;
- }
- *andptr++ = i;
- return;
-bad:
- diag("asmidx: bad address %d/%d/%d", scale, index, base);
- *andptr++ = 0;
- return;
-}
-
-static void
-put4(int32 v)
-{
- andptr[0] = v;
- andptr[1] = v>>8;
- andptr[2] = v>>16;
- andptr[3] = v>>24;
- andptr += 4;
-}
-
-static void
-relput4(Prog *p, Adr *a)
-{
- vlong v;
- Reloc rel, *r;
-
- v = vaddr(a, &rel);
- if(rel.siz != 0) {
- if(rel.siz != 4)
- diag("bad reloc");
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- put4(v);
-}
-
-static void
-put8(vlong v)
-{
- andptr[0] = v;
- andptr[1] = v>>8;
- andptr[2] = v>>16;
- andptr[3] = v>>24;
- andptr[4] = v>>32;
- andptr[5] = v>>40;
- andptr[6] = v>>48;
- andptr[7] = v>>56;
- andptr += 8;
-}
-
-/*
-static void
-relput8(Prog *p, Adr *a)
-{
- vlong v;
- Reloc rel, *r;
-
- v = vaddr(a, &rel);
- if(rel.siz != 0) {
- r = addrel(cursym);
- *r = rel;
- r->siz = 8;
- r->off = p->pc + andptr - and;
- }
- put8(v);
-}
-*/
-
-vlong
-symaddr(Sym *s)
-{
- if(!s->reachable)
- diag("unreachable symbol in symaddr - %s", s->name);
- return s->value;
-}
-
-static vlong
-vaddr(Adr *a, Reloc *r)
-{
- int t;
- vlong v;
- Sym *s;
-
- if(r != nil)
- memset(r, 0, sizeof *r);
-
- t = a->type;
- v = a->offset;
- if(t == D_ADDR)
- t = a->index;
- switch(t) {
- case D_STATIC:
- case D_EXTERN:
- s = a->sym;
- if(!s->reachable)
- diag("unreachable symbol in vaddr - %s", s->name);
- if(r == nil) {
- diag("need reloc for %D", a);
- errorexit();
- }
- r->siz = 4; // TODO: 8 for external symbols
- r->off = -1; // caller must fill in
- r->sym = s;
- r->add = v;
- v = 0;
- if(flag_shared) {
- if(s->type == STLSBSS) {
- r->xadd = r->add - r->siz;
- r->type = D_TLS;
- r->xsym = s;
- } else
- r->type = D_PCREL;
- } else
- r->type = D_ADDR;
- }
- return v;
-}
-
-static void
-asmandsz(Adr *a, int r, int rex, int m64)
-{
- int32 v;
- int t, scale;
- Reloc rel;
-
- USED(m64);
- rex &= (0x40 | Rxr);
- v = a->offset;
- t = a->type;
- rel.siz = 0;
- if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) {
- if(t < D_INDIR) {
- switch(t) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- if(flag_shared)
- goto bad;
- t = D_NONE;
- v = vaddr(a, &rel);
- break;
- case D_AUTO:
- case D_PARAM:
- t = D_SP;
- break;
- }
- } else
- t -= D_INDIR;
- rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- goto putrelv;
- }
- if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- goto putrelv;
- }
- if(t >= D_AL && t <= D_X0+15) {
- if(v)
- goto bad;
- *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
- rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
- return;
- }
-
- scale = a->scale;
- if(t < D_INDIR) {
- switch(a->type) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- t = D_NONE;
- v = vaddr(a, &rel);
- break;
- case D_AUTO:
- case D_PARAM:
- t = D_SP;
- break;
- }
- scale = 1;
- } else
- t -= D_INDIR;
-
- rexflag |= (regrex[t] & Rxb) | rex;
- if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
- if(flag_shared && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || asmode != 64) {
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- goto putrelv;
- }
- /* temporary */
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
- *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
- goto putrelv;
- }
- if(t == D_SP || t == D_R12) {
- if(v == 0) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- goto putrelv;
- }
- if(t >= D_AX && t <= D_R15) {
- if(v == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- goto putrelv;
- }
- goto bad;
-
-putrelv:
- if(rel.siz != 0) {
- Reloc *r;
-
- if(rel.siz != 4) {
- diag("bad rel");
- goto bad;
- }
- r = addrel(cursym);
- *r = rel;
- r->off = curp->pc + andptr - and;
- } else if(iself && linkmode == LinkExternal && a->type == D_INDIR+D_FS
- && HEADTYPE != Hopenbsd) {
- Reloc *r;
- Sym *s;
-
- r = addrel(cursym);
- r->off = curp->pc + andptr - and;
- r->add = a->offset-tlsoffset;
- r->xadd = r->add;
- r->siz = 4;
- r->type = D_TLS;
- s = lookup("runtime.tlsgm", 0);
- r->sym = s;
- r->xsym = s;
- v = 0;
- }
-
- put4(v);
- return;
-
-bad:
- diag("asmand: bad address %D", a);
- return;
-}
-
-void
-asmand(Adr *a, Adr *ra)
-{
- asmandsz(a, reg[ra->type], regrex[ra->type], 0);
-}
-
-void
-asmando(Adr *a, int o)
-{
- asmandsz(a, o, 0, 0);
-}
-
-static void
-bytereg(Adr *a, char *t)
-{
- if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) {
- a->type = D_AL + (a->type-D_AX);
- *t = 0;
- }
-}
-
-#define E 0xff
-Movtab ymovtab[] =
-{
-/* push */
- {APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0},
- {APUSHL, Yss, Ynone, 0, 0x16,E,0,0},
- {APUSHL, Yds, Ynone, 0, 0x1e,E,0,0},
- {APUSHL, Yes, Ynone, 0, 0x06,E,0,0},
- {APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
- {APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
- {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
- {APUSHQ, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
-
- {APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0},
- {APUSHW, Yss, Ynone, 0, Pe,0x16,E,0},
- {APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0},
- {APUSHW, Yes, Ynone, 0, Pe,0x06,E,0},
- {APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E},
- {APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E},
-
-/* pop */
- {APOPL, Ynone, Yds, 0, 0x1f,E,0,0},
- {APOPL, Ynone, Yes, 0, 0x07,E,0,0},
- {APOPL, Ynone, Yss, 0, 0x17,E,0,0},
- {APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
- {APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
- {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
- {APOPQ, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
-
- {APOPW, Ynone, Yds, 0, Pe,0x1f,E,0},
- {APOPW, Ynone, Yes, 0, Pe,0x07,E,0},
- {APOPW, Ynone, Yss, 0, Pe,0x17,E,0},
- {APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E},
- {APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E},
-
-/* mov seg */
- {AMOVW, Yes, Yml, 1, 0x8c,0,0,0},
- {AMOVW, Ycs, Yml, 1, 0x8c,1,0,0},
- {AMOVW, Yss, Yml, 1, 0x8c,2,0,0},
- {AMOVW, Yds, Yml, 1, 0x8c,3,0,0},
- {AMOVW, Yfs, Yml, 1, 0x8c,4,0,0},
- {AMOVW, Ygs, Yml, 1, 0x8c,5,0,0},
-
- {AMOVW, Yml, Yes, 2, 0x8e,0,0,0},
- {AMOVW, Yml, Ycs, 2, 0x8e,1,0,0},
- {AMOVW, Yml, Yss, 2, 0x8e,2,0,0},
- {AMOVW, Yml, Yds, 2, 0x8e,3,0,0},
- {AMOVW, Yml, Yfs, 2, 0x8e,4,0,0},
- {AMOVW, Yml, Ygs, 2, 0x8e,5,0,0},
-
-/* mov cr */
- {AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0},
- {AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0},
- {AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0},
- {AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0},
- {AMOVL, Ycr8, Yml, 3, 0x0f,0x20,8,0},
- {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0},
- {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0},
- {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0},
- {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0},
- {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,0},
-
- {AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0},
- {AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0},
- {AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0},
- {AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0},
- {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0},
- {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0},
- {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0},
- {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0},
- {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0},
- {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,0},
-
-/* mov dr */
- {AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0},
- {AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0},
- {AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0},
- {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0},
- {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0},
- {AMOVQ, Ydr7, Yml, 3, 0x0f,0x21,7,0},
-
- {AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0},
- {AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0},
- {AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0},
- {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0},
- {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0},
- {AMOVQ, Yml, Ydr7, 4, 0x0f,0x23,7,0},
-
-/* mov tr */
- {AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0},
- {AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0},
-
- {AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E},
- {AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E},
-
-/* lgdt, sgdt, lidt, sidt */
- {AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
- {AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
- {AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0},
- {AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0},
- {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
- {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
- {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0},
- {AMOVQ, Yidtr, Ym, 3, 0x0f,0x01,1,0},
-
-/* lldt, sldt */
- {AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0},
- {AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0},
-
-/* lmsw, smsw */
- {AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0},
- {AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0},
-
-/* ltr, str */
- {AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0},
- {AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0},
-
-/* load full pointer */
- {AMOVL, Yml, Ycol, 5, 0,0,0,0},
- {AMOVW, Yml, Ycol, 5, Pe,0,0,0},
-
-/* double shift */
- {ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0},
- {ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0},
- {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0},
- {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0},
- {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0},
- {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,0},
- 0
-};
-
-int
-isax(Adr *a)
-{
-
- switch(a->type) {
- case D_AX:
- case D_AL:
- case D_AH:
- case D_INDIR+D_AX:
- return 1;
- }
- if(a->index == D_AX)
- return 1;
- return 0;
-}
-
-void
-subreg(Prog *p, int from, int to)
-{
-
- if(debug['Q'])
- print("\n%P s/%R/%R/\n", p, from, to);
-
- if(p->from.type == from)
- p->from.type = to;
- if(p->to.type == from)
- p->to.type = to;
-
- if(p->from.index == from)
- p->from.index = to;
- if(p->to.index == from)
- p->to.index = to;
-
- from += D_INDIR;
- if(p->from.type == from)
- p->from.type = to+D_INDIR;
- if(p->to.type == from)
- p->to.type = to+D_INDIR;
-
- if(debug['Q'])
- print("%P\n", p);
-}
-
-static int
-mediaop(Optab *o, int op, int osize, int z)
-{
- switch(op){
- case Pm:
- case Pe:
- case Pf2:
- case Pf3:
- if(osize != 1){
- if(op != Pm)
- *andptr++ = op;
- *andptr++ = Pm;
- op = o->op[++z];
- break;
- }
- default:
- if(andptr == and || andptr[-1] != Pm)
- *andptr++ = Pm;
- break;
- }
- *andptr++ = op;
- return z;
-}
-
-void
-doasm(Prog *p)
-{
- Optab *o;
- Prog *q, pp;
- uchar *t;
- Movtab *mo;
- int z, op, ft, tt, xo, l, pre;
- vlong v;
- Reloc rel, *r;
- Adr *a;
-
- curp = p; // TODO
-
- o = opindex[p->as];
- if(o == nil) {
- diag("asmins: missing op %P", p);
- return;
- }
-
- pre = prefixof(&p->from);
- if(pre)
- *andptr++ = pre;
- pre = prefixof(&p->to);
- if(pre)
- *andptr++ = pre;
-
- if(p->ft == 0)
- p->ft = oclass(&p->from);
- if(p->tt == 0)
- p->tt = oclass(&p->to);
-
- ft = p->ft * Ymax;
- tt = p->tt * Ymax;
-
- t = o->ytab;
- if(t == 0) {
- diag("asmins: noproto %P", p);
- return;
- }
- xo = o->op[0] == 0x0f;
- for(z=0; *t; z+=t[3]+xo,t+=4)
- if(ycover[ft+t[0]])
- if(ycover[tt+t[1]])
- goto found;
- goto domov;
-
-found:
- switch(o->prefix) {
- case Pq: /* 16 bit escape and opcode escape */
- *andptr++ = Pe;
- *andptr++ = Pm;
- break;
- case Pq3: /* 16 bit escape, Rex.w, and opcode escape */
- *andptr++ = Pe;
- *andptr++ = Pw;
- *andptr++ = Pm;
- break;
-
- case Pf2: /* xmm opcode escape */
- case Pf3:
- *andptr++ = o->prefix;
- *andptr++ = Pm;
- break;
-
- case Pm: /* opcode escape */
- *andptr++ = Pm;
- break;
-
- case Pe: /* 16 bit escape */
- *andptr++ = Pe;
- break;
-
- case Pw: /* 64-bit escape */
- if(p->mode != 64)
- diag("asmins: illegal 64: %P", p);
- rexflag |= Pw;
- break;
-
- case Pb: /* botch */
- bytereg(&p->from, &p->ft);
- bytereg(&p->to, &p->tt);
- break;
-
- case P32: /* 32 bit but illegal if 64-bit mode */
- if(p->mode == 64)
- diag("asmins: illegal in 64-bit mode: %P", p);
- break;
-
- case Py: /* 64-bit only, no prefix */
- if(p->mode != 64)
- diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
- break;
- }
-
- if(z >= nelem(o->op))
- sysfatal("asmins bad table %P", p);
- op = o->op[z];
- if(op == 0x0f) {
- *andptr++ = op;
- op = o->op[++z];
- }
- switch(t[2]) {
- default:
- diag("asmins: unknown z %d %P", t[2], p);
- return;
-
- case Zpseudo:
- break;
-
- case Zlit:
- for(; op = o->op[z]; z++)
- *andptr++ = op;
- break;
-
- case Zlitm_r:
- for(; op = o->op[z]; z++)
- *andptr++ = op;
- asmand(&p->from, &p->to);
- break;
-
- case Zmb_r:
- bytereg(&p->from, &p->ft);
- /* fall through */
- case Zm_r:
- *andptr++ = op;
- asmand(&p->from, &p->to);
- break;
- case Zm2_r:
- *andptr++ = op;
- *andptr++ = o->op[z+1];
- asmand(&p->from, &p->to);
- break;
-
- case Zm_r_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->from, &p->to);
- break;
-
- case Zm_r_xm_nr:
- rexflag = 0;
- mediaop(o, op, t[3], z);
- asmand(&p->from, &p->to);
- break;
-
- case Zm_r_i_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->from, &p->to);
- *andptr++ = p->to.offset;
- break;
-
- case Zm_r_3d:
- *andptr++ = 0x0f;
- *andptr++ = 0x0f;
- asmand(&p->from, &p->to);
- *andptr++ = op;
- break;
-
- case Zibm_r:
- while ((op = o->op[z++]) != 0)
- *andptr++ = op;
- asmand(&p->from, &p->to);
- *andptr++ = p->to.offset;
- break;
-
- case Zaut_r:
- *andptr++ = 0x8d; /* leal */
- if(p->from.type != D_ADDR)
- diag("asmins: Zaut sb type ADDR");
- p->from.type = p->from.index;
- p->from.index = D_NONE;
- asmand(&p->from, &p->to);
- p->from.index = p->from.type;
- p->from.type = D_ADDR;
- break;
-
- case Zm_o:
- *andptr++ = op;
- asmando(&p->from, o->op[z+1]);
- break;
-
- case Zr_m:
- *andptr++ = op;
- asmand(&p->to, &p->from);
- break;
-
- case Zr_m_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->to, &p->from);
- break;
-
- case Zr_m_xm_nr:
- rexflag = 0;
- mediaop(o, op, t[3], z);
- asmand(&p->to, &p->from);
- break;
-
- case Zr_m_i_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->to, &p->from);
- *andptr++ = p->from.offset;
- break;
-
- case Zo_m:
- *andptr++ = op;
- asmando(&p->to, o->op[z+1]);
- break;
-
- case Zo_m64:
- *andptr++ = op;
- asmandsz(&p->to, o->op[z+1], 0, 1);
- break;
-
- case Zm_ibo:
- *andptr++ = op;
- asmando(&p->from, o->op[z+1]);
- *andptr++ = vaddr(&p->to, nil);
- break;
-
- case Zibo_m:
- *andptr++ = op;
- asmando(&p->to, o->op[z+1]);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Zibo_m_xm:
- z = mediaop(o, op, t[3], z);
- asmando(&p->to, o->op[z+1]);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Z_ib:
- case Zib_:
- if(t[2] == Zib_)
- a = &p->from;
- else
- a = &p->to;
- *andptr++ = op;
- *andptr++ = vaddr(a, nil);
- break;
-
- case Zib_rp:
- rexflag |= regrex[p->to.type] & (Rxb|0x40);
- *andptr++ = op + reg[p->to.type];
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Zil_rp:
- rexflag |= regrex[p->to.type] & Rxb;
- *andptr++ = op + reg[p->to.type];
- if(o->prefix == Pe) {
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, &p->from);
- break;
-
- case Zo_iw:
- *andptr++ = op;
- if(p->from.type != D_NONE){
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- break;
-
- case Ziq_rp:
- v = vaddr(&p->from, &rel);
- l = v>>32;
- if(l == 0 && rel.siz != 8){
- //p->mark |= 0100;
- //print("zero: %llux %P\n", v, p);
- rexflag &= ~(0x40|Rxw);
- rexflag |= regrex[p->to.type] & Rxb;
- *andptr++ = 0xb8 + reg[p->to.type];
- if(rel.type != 0) {
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- put4(v);
- }else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */
- //p->mark |= 0100;
- //print("sign: %llux %P\n", v, p);
- *andptr ++ = 0xc7;
- asmando(&p->to, 0);
- put4(v);
- }else{ /* need all 8 */
- //print("all: %llux %P\n", v, p);
- rexflag |= regrex[p->to.type] & Rxb;
- *andptr++ = op + reg[p->to.type];
- if(rel.type != 0) {
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- put8(v);
- }
- break;
-
- case Zib_rr:
- *andptr++ = op;
- asmand(&p->to, &p->to);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Z_il:
- case Zil_:
- if(t[2] == Zil_)
- a = &p->from;
- else
- a = &p->to;
- *andptr++ = op;
- if(o->prefix == Pe) {
- v = vaddr(a, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, a);
- break;
-
- case Zm_ilo:
- case Zilo_m:
- *andptr++ = op;
- if(t[2] == Zilo_m) {
- a = &p->from;
- asmando(&p->to, o->op[z+1]);
- } else {
- a = &p->to;
- asmando(&p->from, o->op[z+1]);
- }
- if(o->prefix == Pe) {
- v = vaddr(a, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, a);
- break;
-
- case Zil_rr:
- *andptr++ = op;
- asmand(&p->to, &p->to);
- if(o->prefix == Pe) {
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, &p->from);
- break;
-
- case Z_rp:
- rexflag |= regrex[p->to.type] & (Rxb|0x40);
- *andptr++ = op + reg[p->to.type];
- break;
-
- case Zrp_:
- rexflag |= regrex[p->from.type] & (Rxb|0x40);
- *andptr++ = op + reg[p->from.type];
- break;
-
- case Zclr:
- *andptr++ = op;
- asmand(&p->to, &p->to);
- break;
-
- case Zcall:
- q = p->pcond;
- if(q == nil) {
- diag("call without target");
- errorexit();
- }
- if(q->as != ATEXT) {
- // Could handle this case by making D_PCREL
- // record the Prog* instead of the Sym*, but let's
- // wait until the need arises.
- diag("call of non-TEXT %P", q);
- errorexit();
- }
- *andptr++ = op;
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->sym = q->from.sym;
- r->type = D_PCREL;
- r->siz = 4;
- put4(0);
- break;
-
- case Zbr:
- case Zjmp:
- case Zloop:
- // TODO: jump across functions needs reloc
- q = p->pcond;
- if(q == nil) {
- diag("jmp/branch/loop without target");
- errorexit();
- }
- if(q->as == ATEXT) {
- if(t[2] == Zbr) {
- diag("branch to ATEXT");
- errorexit();
- }
- *andptr++ = o->op[z+1];
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->sym = q->from.sym;
- r->type = D_PCREL;
- r->siz = 4;
- put4(0);
- break;
- }
- // Assumes q is in this function.
- // TODO: Check in input, preserve in brchain.
-
- // Fill in backward jump now.
- if(p->back & 1) {
- v = q->pc - (p->pc + 2);
- if(v >= -128) {
- if(p->as == AJCXZL)
- *andptr++ = 0x67;
- *andptr++ = op;
- *andptr++ = v;
- } else if(t[2] == Zloop) {
- diag("loop too far: %P", p);
- } else {
- v -= 5-2;
- if(t[2] == Zbr) {
- *andptr++ = 0x0f;
- v--;
- }
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
- break;
- }
-
- // Annotate target; will fill in later.
- p->forwd = q->comefrom;
- q->comefrom = p;
- if(p->back & 2) { // short
- if(p->as == AJCXZL)
- *andptr++ = 0x67;
- *andptr++ = op;
- *andptr++ = 0;
- } else if(t[2] == Zloop) {
- diag("loop too far: %P", p);
- } else {
- if(t[2] == Zbr)
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *andptr++ = 0;
- *andptr++ = 0;
- *andptr++ = 0;
- *andptr++ = 0;
- }
- break;
-
-/*
- v = q->pc - p->pc - 2;
- if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
- *andptr++ = op;
- *andptr++ = v;
- } else {
- v -= 5-2;
- if(t[2] == Zbr) {
- *andptr++ = 0x0f;
- v--;
- }
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
-*/
- break;
-
- case Zbyte:
- v = vaddr(&p->from, &rel);
- if(rel.siz != 0) {
- rel.siz = op;
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- *andptr++ = v;
- if(op > 1) {
- *andptr++ = v>>8;
- if(op > 2) {
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- if(op > 4) {
- *andptr++ = v>>32;
- *andptr++ = v>>40;
- *andptr++ = v>>48;
- *andptr++ = v>>56;
- }
- }
- }
- break;
- }
- return;
-
-domov:
- for(mo=ymovtab; mo->as; mo++)
- if(p->as == mo->as)
- if(ycover[ft+mo->ft])
- if(ycover[tt+mo->tt]){
- t = mo->op;
- goto mfound;
- }
-bad:
- if(p->mode != 64){
- /*
- * here, the assembly has failed.
- * if its a byte instruction that has
- * unaddressable registers, try to
- * exchange registers and reissue the
- * instruction with the operands renamed.
- */
- pp = *p;
- z = p->from.type;
- if(z >= D_BP && z <= D_DI) {
- if(isax(&p->to) || p->to.type == D_NONE) {
- // We certainly don't want to exchange
- // with AX if the op is MUL or DIV.
- *andptr++ = 0x87; /* xchg lhs,bx */
- asmando(&p->from, reg[D_BX]);
- subreg(&pp, z, D_BX);
- doasm(&pp);
- *andptr++ = 0x87; /* xchg lhs,bx */
- asmando(&p->from, reg[D_BX]);
- } else {
- *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- subreg(&pp, z, D_AX);
- doasm(&pp);
- *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- }
- return;
- }
- z = p->to.type;
- if(z >= D_BP && z <= D_DI) {
- if(isax(&p->from)) {
- *andptr++ = 0x87; /* xchg rhs,bx */
- asmando(&p->to, reg[D_BX]);
- subreg(&pp, z, D_BX);
- doasm(&pp);
- *andptr++ = 0x87; /* xchg rhs,bx */
- asmando(&p->to, reg[D_BX]);
- } else {
- *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- subreg(&pp, z, D_AX);
- doasm(&pp);
- *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- }
- return;
- }
- }
- diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p);
- return;
-
-mfound:
- switch(mo->code) {
- default:
- diag("asmins: unknown mov %d %P", mo->code, p);
- break;
-
- case 0: /* lit */
- for(z=0; t[z]!=E; z++)
- *andptr++ = t[z];
- break;
-
- case 1: /* r,m */
- *andptr++ = t[0];
- asmando(&p->to, t[1]);
- break;
-
- case 2: /* m,r */
- *andptr++ = t[0];
- asmando(&p->from, t[1]);
- break;
-
- case 3: /* r,m - 2op */
- *andptr++ = t[0];
- *andptr++ = t[1];
- asmando(&p->to, t[2]);
- rexflag |= regrex[p->from.type] & (Rxr|0x40);
- break;
-
- case 4: /* m,r - 2op */
- *andptr++ = t[0];
- *andptr++ = t[1];
- asmando(&p->from, t[2]);
- rexflag |= regrex[p->to.type] & (Rxr|0x40);
- break;
-
- case 5: /* load full pointer, trash heap */
- if(t[0])
- *andptr++ = t[0];
- switch(p->to.index) {
- default:
- goto bad;
- case D_DS:
- *andptr++ = 0xc5;
- break;
- case D_SS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb2;
- break;
- case D_ES:
- *andptr++ = 0xc4;
- break;
- case D_FS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb4;
- break;
- case D_GS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb5;
- break;
- }
- asmand(&p->from, &p->to);
- break;
-
- case 6: /* double shift */
- if(t[0] == Pw){
- if(p->mode != 64)
- diag("asmins: illegal 64: %P", p);
- rexflag |= Pw;
- t++;
- }else if(t[0] == Pe){
- *andptr++ = Pe;
- t++;
- }
- z = p->from.type;
- switch(z) {
- default:
- goto bad;
- case D_CONST:
- *andptr++ = 0x0f;
- *andptr++ = t[0];
- asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
- *andptr++ = p->from.offset;
- break;
- case D_CL:
- case D_CX:
- *andptr++ = 0x0f;
- *andptr++ = t[1];
- asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
- break;
- }
- break;
- }
-}
-
-void
-asmins(Prog *p)
-{
- int n, np, c;
- Reloc *r;
-
- rexflag = 0;
- andptr = and;
- asmode = p->mode;
- doasm(p);
- if(rexflag){
- /*
- * as befits the whole approach of the architecture,
- * the rex prefix must appear before the first opcode byte
- * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but
- * before the 0f opcode escape!), or it might be ignored.
- * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
- */
- if(p->mode != 64)
- diag("asmins: illegal in mode %d: %P", p->mode, p);
- n = andptr - and;
- for(np = 0; np < n; np++) {
- c = and[np];
- if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
- break;
- }
- memmove(and+np+1, and+np, n-np);
- and[np] = 0x40 | rexflag;
- andptr++;
- }
- n = andptr - and;
- for(r=cursym->r+cursym->nr; r-- > cursym->r; ) {
- if(r->off < p->pc)
- break;
- if(rexflag)
- r->off++;
- if(r->type == D_PCREL)
- r->add -= p->pc + n - (r->off + r->siz);
- }
-}
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
index a28115eb4..8319482ca 100644
--- a/src/cmd/8l/8.out.h
+++ b/src/cmd/8l/8.out.h
@@ -677,15 +677,3 @@ enum
* this is the ranlib header
*/
#define SYMDEF "__.GOSYMDEF"
-
-/*
- * this is the simulated IEEE floating point
- */
-typedef struct ieee Ieee;
-struct ieee
-{
- int32 l; /* contains ls-man 0xffffffff */
- int32 h; /* contains sign 0x80000000
- exp 0x7ff00000
- ms-man 0x000fffff */
-};
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index 3be37ea22..46e8e47ec 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -43,46 +43,18 @@ char openbsddynld[] = "/usr/libexec/ld.so";
char netbsddynld[] = "/usr/libexec/ld.elf_so";
char dragonflydynld[] = "/usr/libexec/ld-elf.so.2";
-int32
-entryvalue(void)
-{
- char *a;
- Sym *s;
-
- a = INITENTRY;
- if(*a >= '0' && *a <= '9')
- return atolwhex(a);
- s = lookup(a, 0);
- if(s->type == 0)
- return INITTEXT;
- if(s->type != STEXT)
- diag("entry not text: %s", s->name);
- return s->value;
-}
-
-vlong
-datoff(vlong addr)
-{
- if(addr >= segdata.vaddr)
- return addr - segdata.vaddr + segdata.fileoff;
- if(addr >= segtext.vaddr)
- return addr - segtext.vaddr + segtext.fileoff;
- diag("datoff %#llx", addr);
- return 0;
-}
-
static int
needlib(char *name)
{
char *p;
- Sym *s;
+ LSym *s;
if(*name == '\0')
return 0;
/* reuse hash code in symbol table */
p = smprint(".dynlib.%s", name);
- s = lookup(p, 0);
+ s = linklookup(ctxt, p, 0);
free(p);
if(s->type == 0) {
s->type = 100; // avoid SDATA, etc.
@@ -93,11 +65,11 @@ needlib(char *name)
int nelfsym = 1;
-static void addpltsym(Sym*);
-static void addgotsym(Sym*);
+static void addpltsym(Link*, LSym*);
+static void addgotsym(Link*, LSym*);
void
-adddynrela(Sym *rela, Sym *s, Reloc *r)
+adddynrela(LSym *rela, LSym *s, Reloc *r)
{
USED(rela);
USED(s);
@@ -106,12 +78,12 @@ adddynrela(Sym *rela, Sym *s, Reloc *r)
}
void
-adddynrel(Sym *s, Reloc *r)
+adddynrel(LSym *s, Reloc *r)
{
- Sym *targ, *rel, *got;
+ LSym *targ, *rel, *got;
targ = r->sym;
- cursym = s;
+ ctxt->cursym = s;
switch(r->type) {
default:
@@ -135,8 +107,8 @@ adddynrel(Sym *s, Reloc *r)
r->type = D_PCREL;
r->add += 4;
if(targ->type == SDYNIMPORT) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add += targ->plt;
}
return;
@@ -153,7 +125,7 @@ adddynrel(Sym *s, Reloc *r)
r->type = D_GOTOFF;
return;
}
- addgotsym(targ);
+ addgotsym(ctxt, targ);
r->type = D_CONST; // write r->add during relocsym
r->sym = S;
r->add += targ->got;
@@ -165,7 +137,7 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_386_GOTPC:
r->type = D_PCREL;
- r->sym = lookup(".got", 0);
+ r->sym = linklookup(ctxt, ".got", 0);
r->add += 4;
return;
@@ -183,8 +155,8 @@ adddynrel(Sym *s, Reloc *r)
case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
if(targ->type == SDYNIMPORT) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
r->type = D_PCREL;
return;
@@ -204,8 +176,8 @@ adddynrel(Sym *s, Reloc *r)
r->type = D_PCREL;
return;
}
- addgotsym(targ);
- r->sym = lookup(".got", 0);
+ addgotsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".got", 0);
r->add += targ->got;
r->type = D_PCREL;
return;
@@ -217,8 +189,8 @@ adddynrel(Sym *s, Reloc *r)
switch(r->type) {
case D_PCREL:
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
return;
@@ -226,10 +198,10 @@ adddynrel(Sym *s, Reloc *r)
if(s->type != SDATA)
break;
if(iself) {
- adddynsym(targ);
- rel = lookup(".rel", 0);
- addaddrplus(rel, s, r->off);
- adduint32(rel, ELF32_R_INFO(targ->dynid, R_386_32));
+ adddynsym(ctxt, targ);
+ rel = linklookup(ctxt, ".rel", 0);
+ addaddrplus(ctxt, rel, s, r->off);
+ adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_386_32));
r->type = D_CONST; // write r->add during relocsym
r->sym = S;
return;
@@ -245,22 +217,22 @@ adddynrel(Sym *s, Reloc *r)
// just in case the C code assigns to the variable,
// and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs.
- adddynsym(targ);
- got = lookup(".got", 0);
+ adddynsym(ctxt, targ);
+ got = linklookup(ctxt, ".got", 0);
s->type = got->type | SSUB;
s->outer = got;
s->sub = got->sub;
got->sub = s;
s->value = got->size;
- adduint32(got, 0);
- adduint32(lookup(".linkedit.got", 0), targ->dynid);
+ adduint32(ctxt, got, 0);
+ adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid);
r->type = 256; // ignore during relocsym
return;
}
break;
}
- cursym = s;
+ ctxt->cursym = s;
diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}
@@ -304,7 +276,7 @@ int
machoreloc1(Reloc *r, vlong sectoff)
{
uint32 v;
- Sym *rs;
+ LSym *rs;
rs = r->xsym;
@@ -358,7 +330,7 @@ machoreloc1(Reloc *r, vlong sectoff)
}
int
-archreloc(Reloc *r, Sym *s, vlong *val)
+archreloc(Reloc *r, LSym *s, vlong *val)
{
USED(s);
if(linkmode == LinkExternal)
@@ -368,7 +340,7 @@ archreloc(Reloc *r, Sym *s, vlong *val)
*val = r->add;
return 0;
case D_GOTOFF:
- *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
+ *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
return 0;
}
return -1;
@@ -377,119 +349,119 @@ archreloc(Reloc *r, Sym *s, vlong *val)
void
elfsetupplt(void)
{
- Sym *plt, *got;
+ LSym *plt, *got;
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
+ got = linklookup(ctxt, ".got.plt", 0);
if(plt->size == 0) {
// pushl got+4
- adduint8(plt, 0xff);
- adduint8(plt, 0x35);
- addaddrplus(plt, got, 4);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x35);
+ addaddrplus(ctxt, plt, got, 4);
// jmp *got+8
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addaddrplus(plt, got, 8);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x25);
+ addaddrplus(ctxt, plt, got, 8);
// zero pad
- adduint32(plt, 0);
+ adduint32(ctxt, plt, 0);
// assume got->size == 0 too
- addaddrplus(got, lookup(".dynamic", 0), 0);
- adduint32(got, 0);
- adduint32(got, 0);
+ addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
+ adduint32(ctxt, got, 0);
+ adduint32(ctxt, got, 0);
}
}
static void
-addpltsym(Sym *s)
+addpltsym(Link *ctxt, LSym *s)
{
- Sym *plt, *got, *rel;
+ LSym *plt, *got, *rel;
if(s->plt >= 0)
return;
- adddynsym(s);
+ adddynsym(ctxt, s);
if(iself) {
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
- rel = lookup(".rel.plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
+ got = linklookup(ctxt, ".got.plt", 0);
+ rel = linklookup(ctxt, ".rel.plt", 0);
if(plt->size == 0)
elfsetupplt();
// jmpq *got+size
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addaddrplus(plt, got, got->size);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x25);
+ addaddrplus(ctxt, plt, got, got->size);
// add to got: pointer to current pos in plt
- addaddrplus(got, plt, plt->size);
+ addaddrplus(ctxt, got, plt, plt->size);
// pushl $x
- adduint8(plt, 0x68);
- adduint32(plt, rel->size);
+ adduint8(ctxt, plt, 0x68);
+ adduint32(ctxt, plt, rel->size);
// jmp .plt
- adduint8(plt, 0xe9);
- adduint32(plt, -(plt->size+4));
+ adduint8(ctxt, plt, 0xe9);
+ adduint32(ctxt, plt, -(plt->size+4));
// rel
- addaddrplus(rel, got, got->size-4);
- adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
+ addaddrplus(ctxt, rel, got, got->size-4);
+ adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
s->plt = plt->size - 16;
} else if(HEADTYPE == Hdarwin) {
// Same laziness as in 6l.
- Sym *plt;
+ LSym *plt;
- plt = lookup(".plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
- addgotsym(s);
+ addgotsym(ctxt, s);
- adduint32(lookup(".linkedit.plt", 0), s->dynid);
+ adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid);
// jmpq *got+size(IP)
s->plt = plt->size;
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addaddrplus(plt, lookup(".got", 0), s->got);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x25);
+ addaddrplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got);
} else {
diag("addpltsym: unsupported binary format");
}
}
static void
-addgotsym(Sym *s)
+addgotsym(Link *ctxt, LSym *s)
{
- Sym *got, *rel;
+ LSym *got, *rel;
if(s->got >= 0)
return;
- adddynsym(s);
- got = lookup(".got", 0);
+ adddynsym(ctxt, s);
+ got = linklookup(ctxt, ".got", 0);
s->got = got->size;
- adduint32(got, 0);
+ adduint32(ctxt, got, 0);
if(iself) {
- rel = lookup(".rel", 0);
- addaddrplus(rel, got, s->got);
- adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
+ rel = linklookup(ctxt, ".rel", 0);
+ addaddrplus(ctxt, rel, got, s->got);
+ adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
} else if(HEADTYPE == Hdarwin) {
- adduint32(lookup(".linkedit.got", 0), s->dynid);
+ adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
} else {
diag("addgotsym: unsupported binary format");
}
}
void
-adddynsym(Sym *s)
+adddynsym(Link *ctxt, LSym *s)
{
- Sym *d;
+ LSym *d;
int t;
char *name;
@@ -499,20 +471,20 @@ adddynsym(Sym *s)
if(iself) {
s->dynid = nelfsym++;
- d = lookup(".dynsym", 0);
+ d = linklookup(ctxt, ".dynsym", 0);
/* name */
name = s->extname;
- adduint32(d, addstring(lookup(".dynstr", 0), name));
+ adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
/* value */
if(s->type == SDYNIMPORT)
- adduint32(d, 0);
+ adduint32(ctxt, d, 0);
else
- addaddr(d, s);
+ addaddr(ctxt, d, s);
/* size */
- adduint32(d, 0);
+ adduint32(ctxt, d, 0);
/* type */
t = STB_GLOBAL << 4;
@@ -520,12 +492,12 @@ adddynsym(Sym *s)
t |= STT_FUNC;
else
t |= STT_OBJECT;
- adduint8(d, t);
- adduint8(d, 0);
+ adduint8(ctxt, d, t);
+ adduint8(ctxt, d, 0);
/* shndx */
if(s->type == SDYNIMPORT)
- adduint16(d, SHN_UNDEF);
+ adduint16(ctxt, d, SHN_UNDEF);
else {
switch(s->type) {
default:
@@ -542,7 +514,7 @@ adddynsym(Sym *s)
t = 14;
break;
}
- adduint16(d, t);
+ adduint16(ctxt, d, t);
}
} else if(HEADTYPE == Hdarwin) {
diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
@@ -556,16 +528,16 @@ adddynsym(Sym *s)
void
adddynlib(char *lib)
{
- Sym *s;
+ LSym *s;
if(!needlib(lib))
return;
if(iself) {
- s = lookup(".dynstr", 0);
+ s = linklookup(ctxt, ".dynstr", 0);
if(s->size == 0)
addstring(s, "");
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
} else if(HEADTYPE == Hdarwin) {
machoadddynlib(lib);
} else if(HEADTYPE != Hwindows) {
@@ -576,10 +548,10 @@ adddynlib(char *lib)
void
asmb(void)
{
- int32 v, magic;
+ int32 magic;
uint32 symo, dwarfoff, machlink;
Section *sect;
- Sym *sym;
+ LSym *sym;
int i;
if(debug['v'])
@@ -641,18 +613,7 @@ asmb(void)
default:
if(iself)
goto Elfsym;
- case Hgarbunix:
- symo = rnd(HEADR+segtext.filelen, 8192)+segdata.filelen;
- break;
- case Hunixcoff:
- symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
- break;
- case Hplan9x32:
- symo = HEADR+segtext.filelen+segdata.filelen;
- break;
- case Hmsdoscom:
- case Hmsdosexe:
- debug['s'] = 1;
+ case Hplan9:
symo = HEADR+segtext.filelen+segdata.filelen;
break;
case Hdarwin:
@@ -685,11 +646,11 @@ asmb(void)
elfemitreloc();
}
break;
- case Hplan9x32:
+ case Hplan9:
asmplan9sym();
cflush();
- sym = lookup("pclntab", 0);
+ sym = linklookup(ctxt, "pclntab", 0);
if(sym != nil) {
lcsize = sym->np;
for(i=0; i < lcsize; i++)
@@ -715,96 +676,7 @@ asmb(void)
cseek(0L);
switch(HEADTYPE) {
default:
- case Hgarbunix: /* garbage */
- lputb(0x160L<<16); /* magic and sections */
- lputb(0L); /* time and date */
- lputb(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen);
- lputb(symsize); /* nsyms */
- lputb((0x38L<<16)|7L); /* size of optional hdr and flags */
- lputb((0413<<16)|0437L); /* magic and version */
- lputb(rnd(HEADR+segtext.filelen, 4096)); /* sizes */
- lputb(segdata.filelen);
- lputb(segdata.len - segdata.filelen);
- lputb(entryvalue()); /* va of entry */
- lputb(INITTEXT-HEADR); /* va of base of text */
- lputb(segdata.vaddr); /* va of base of data */
- lputb(segdata.vaddr+segdata.filelen); /* va of base of bss */
- lputb(~0L); /* gp reg mask */
- lputb(0L);
- lputb(0L);
- lputb(0L);
- lputb(0L);
- lputb(~0L); /* gp value ?? */
- break;
- case Hunixcoff: /* unix coff */
- /*
- * file header
- */
- lputl(0x0004014c); /* 4 sections, magic */
- lputl(0); /* unix time stamp */
- lputl(0); /* symbol table */
- lputl(0); /* nsyms */
- lputl(0x0003001c); /* flags, sizeof a.out header */
- /*
- * a.out header
- */
- lputl(0x10b); /* magic, version stamp */
- lputl(rnd(segtext.filelen, INITRND)); /* text sizes */
- lputl(segdata.filelen); /* data sizes */
- lputl(segdata.len - segdata.filelen); /* bss sizes */
- lputb(entryvalue()); /* va of entry */
- lputl(INITTEXT); /* text start */
- lputl(segdata.vaddr); /* data start */
- /*
- * text section header
- */
- s8put(".text");
- lputl(HEADR); /* pa */
- lputl(HEADR); /* va */
- lputl(segtext.filelen); /* text size */
- lputl(HEADR); /* file offset */
- lputl(0); /* relocation */
- lputl(0); /* line numbers */
- lputl(0); /* relocation, line numbers */
- lputl(0x20); /* flags text only */
- /*
- * data section header
- */
- s8put(".data");
- lputl(segdata.vaddr); /* pa */
- lputl(segdata.vaddr); /* va */
- lputl(segdata.filelen); /* data size */
- lputl(HEADR+segtext.filelen); /* file offset */
- lputl(0); /* relocation */
- lputl(0); /* line numbers */
- lputl(0); /* relocation, line numbers */
- lputl(0x40); /* flags data only */
- /*
- * bss section header
- */
- s8put(".bss");
- lputl(segdata.vaddr+segdata.filelen); /* pa */
- lputl(segdata.vaddr+segdata.filelen); /* va */
- lputl(segdata.len - segdata.filelen); /* bss size */
- lputl(0); /* file offset */
- lputl(0); /* relocation */
- lputl(0); /* line numbers */
- lputl(0); /* relocation, line numbers */
- lputl(0x80); /* flags bss only */
- /*
- * comment section header
- */
- s8put(".comment");
- lputl(0); /* pa */
- lputl(0); /* va */
- lputl(symsize+lcsize); /* comment size */
- lputl(HEADR+segtext.filelen+segdata.filelen); /* file offset */
- lputl(HEADR+segtext.filelen+segdata.filelen); /* offset of syms */
- lputl(HEADR+segtext.filelen+segdata.filelen+symsize);/* offset of line numbers */
- lputl(0); /* relocation, line numbers */
- lputl(0x200); /* flags comment only */
- break;
- case Hplan9x32: /* plan9 */
+ case Hplan9: /* plan9 */
magic = 4*11*11+7;
lputb(magic); /* magic */
lputb(segtext.filelen); /* sizes */
@@ -815,31 +687,6 @@ asmb(void)
lputb(spsize); /* sp offsets */
lputb(lcsize); /* line offsets */
break;
- case Hmsdoscom:
- /* MS-DOS .COM */
- break;
- case Hmsdosexe:
- /* fake MS-DOS .EXE */
- v = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
- wputl(0x5A4D); /* 'MZ' */
- wputl(v % 512); /* bytes in last page */
- wputl(rnd(v, 512)/512); /* total number of pages */
- wputl(0x0000); /* number of reloc items */
- v = rnd(HEADR-(INITTEXT & 0xFFFF), 16);
- wputl(v/16); /* size of header */
- wputl(0x0000); /* minimum allocation */
- wputl(0xFFFF); /* maximum allocation */
- wputl(0x0000); /* initial ss value */
- wputl(0x0100); /* initial sp value */
- wputl(0x0000); /* complemented checksum */
- v = entryvalue();
- wputl(v); /* initial ip value (!) */
- wputl(0x0000); /* initial cs value */
- wputl(0x0000);
- wputl(0x0000);
- wputl(0x003E); /* reloc table offset */
- wputl(0x0000); /* overlay number */
- break;
case Hdarwin:
asmbmacho();
break;
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index 814aa1458..928e2e49a 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -31,6 +31,7 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
+#include <link.h>
#include "8.out.h"
#ifndef EXTERN
@@ -47,136 +48,8 @@ enum
};
#define P ((Prog*)0)
-#define S ((Sym*)0)
-#define TNAME (cursym?cursym->name:noname)
-
-typedef struct Adr Adr;
-typedef struct Prog Prog;
-typedef struct Sym Sym;
-typedef struct Auto Auto;
-typedef struct Optab Optab;
-typedef struct Reloc Reloc;
-
-struct Adr
-{
- union
- {
- int32 u0offset;
- char u0scon[8];
- Prog *u0cond; /* not used, but should be D_BRANCH */
- Ieee u0ieee;
- char *u0sbig;
- } u0;
- Sym* sym;
- short type;
- uchar index;
- char scale;
- int32 offset2;
-};
-
-#define offset u0.u0offset
-#define scon u0.u0scon
-#define cond u0.u0cond
-#define ieee u0.u0ieee
-#define sbig u0.u0sbig
-
-struct Reloc
-{
- int32 off;
- uchar siz;
- uchar done;
- int32 type;
- int32 add;
- int32 xadd;
- Sym* sym;
- Sym* xsym;
-};
-
-struct Prog
-{
- Adr from;
- Adr to;
- Prog* forwd;
- Prog* comefrom;
- Prog* link;
- Prog* pcond; /* work on this */
- int32 pc;
- int32 spadj;
- int32 line;
- short as;
- char width; /* fake for DATA */
- char ft; /* oclass cache */
- char tt;
- uchar mark; /* work on these */
- uchar back;
- uchar bigjmp;
-};
-#define datasize from.scale
-#define textflag from.scale
-#define iscall(p) ((p)->as == ACALL)
-
-struct Auto
-{
- Sym* asym;
- Auto* link;
- int32 aoffset;
- short type;
- Sym* gotype;
-};
-struct Sym
-{
- char* name;
- char* extname; // name used in external object files
- short type;
- short version;
- uchar dupok;
- uchar reachable;
- uchar cgoexport;
- uchar special;
- uchar stkcheck;
- uchar hide;
- int32 value;
- int32 size;
- int32 sig;
- int32 dynid;
- int32 plt;
- int32 got;
- int32 align; // if non-zero, required alignment in bytes
- int32 elfsym;
- int32 args; // size of stack frame incoming arguments area
- Sym* hash; // in hash table
- Sym* allsym; // in all symbol list
- Sym* next; // in text or data list
- Sym* sub; // in sub list
- Sym* outer; // container of sub
- Sym* gotype;
- Sym* reachparent;
- Sym* queue;
- char* file;
- char* dynimplib;
- char* dynimpvers;
- struct Section* sect;
- struct Hist* hist; // for ATEXT
-
- // STEXT
- Auto* autom;
- Prog* text;
-
- // SDATA, SBSS
- uchar* p;
- int32 np;
- int32 maxp;
- Reloc* r;
- int32 nr;
- int32 maxr;
-};
-struct Optab
-{
- short as;
- uchar* ytab;
- uchar prefix;
- uchar op[13];
-};
+#define S ((LSym*)0)
+#define TNAME (ctxt->cursym?ctxt->cursym->name:noname)
enum
{
@@ -185,202 +58,50 @@ enum
MINLC = 1,
MAXIO = 8192,
MAXHIST = 40, /* limit of path elements for history symbols */
-
- Yxxx = 0,
- Ynone,
- Yi0,
- Yi1,
- Yi8,
- Yi32,
- Yiauto,
- Yal,
- Ycl,
- Yax,
- Ycx,
- Yrb,
- Yrl,
- Yrf,
- Yf0,
- Yrx,
- Ymb,
- Yml,
- Ym,
- Ybr,
- Ycol,
-
- Ycs, Yss, Yds, Yes, Yfs, Ygs,
- Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
- Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7,
- Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
- Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7,
- Ymr, Ymm,
- Yxr, Yxm,
- Ymax,
-
- Zxxx = 0,
-
- Zlit,
- Zlitm_r,
- Z_rp,
- Zbr,
- Zcall,
- Zcallcon,
- Zcallind,
- Zib_,
- Zib_rp,
- Zibo_m,
- Zil_,
- Zil_rp,
- Zilo_m,
- Zjmp,
- Zjmpcon,
- Zloop,
- Zm_o,
- Zm_r,
- Zm2_r,
- Zm_r_xm,
- Zm_r_i_xm,
- Zaut_r,
- Zo_m,
- Zpseudo,
- Zr_m,
- Zr_m_xm,
- Zr_m_i_xm,
- Zrp_,
- Z_ib,
- Z_il,
- Zm_ibo,
- Zm_ilo,
- Zib_rr,
- Zil_rr,
- Zclr,
- Zibm_r, /* mmx1,mmx2/mem64,imm8 */
- Zbyte,
- Zmov,
- Zmax,
-
- Px = 0,
- Pe = 0x66, /* operand escape */
- Pm = 0x0f, /* 2byte opcode escape */
- Pq = 0xff, /* both escape */
- Pb = 0xfe, /* byte operands */
- Pf2 = 0xf2, /* xmm escape 1 */
- Pf3 = 0xf3, /* xmm escape 2 */
};
#pragma varargck type "A" int
-#pragma varargck type "D" Adr*
+#pragma varargck type "D" Addr*
#pragma varargck type "I" uchar*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "S" char*
-#pragma varargck type "Y" Sym*
+#pragma varargck type "Y" LSym*
#pragma varargck type "Z" char*
#pragma varargck type "i" char*
-EXTERN int32 HEADR;
-EXTERN int32 HEADTYPE;
-EXTERN int32 INITRND;
-EXTERN int32 INITTEXT;
-EXTERN int32 INITDAT;
-EXTERN char* INITENTRY; /* entry point */
-EXTERN char* pcstr;
-EXTERN Auto* curauto;
-EXTERN Auto* curhist;
-EXTERN Prog* curp;
-EXTERN Sym* cursym;
-EXTERN Sym* datap;
+EXTERN LSym* datap;
EXTERN int debug[128];
EXTERN char literal[32];
-EXTERN Sym* etextp;
EXTERN Prog* firstp;
-EXTERN uchar ycover[Ymax*Ymax];
-EXTERN uchar* andptr;
-EXTERN uchar and[100];
-EXTERN char reg[D_NONE];
EXTERN int32 lcsize;
-EXTERN int maxop;
-EXTERN int nerrors;
-EXTERN char* noname;
-EXTERN int32 pc;
EXTERN char* rpath;
EXTERN int32 spsize;
-EXTERN Sym* symlist;
+EXTERN LSym* symlist;
EXTERN int32 symsize;
-EXTERN Sym* textp;
EXTERN int32 textsize;
-EXTERN Prog zprg;
-EXTERN int dtype;
-EXTERN int tlsoffset;
-EXTERN Sym* adrgotype; // type symbol on last Adr read
-EXTERN Sym* fromgotype; // type symbol on last p->from read
-extern Optab optab[];
-extern char* anames[];
-
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Iconv(Fmt*);
-int Pconv(Fmt*);
-int Rconv(Fmt*);
-int Sconv(Fmt*);
-void addhist(int32, int);
-Prog* appendp(Prog*);
+int Aconv(Fmt *fp);
+int Dconv(Fmt *fp);
+int Iconv(Fmt *fp);
+int Pconv(Fmt *fp);
+int Rconv(Fmt *fp);
+int Sconv(Fmt *fp);
+void adddynlib(char *lib);
+void adddynrel(LSym *s, Reloc *r);
+void adddynrela(LSym *rela, LSym *s, Reloc *r);
+void adddynsym(Link *ctxt, LSym *s);
+int archreloc(Reloc *r, LSym *s, vlong *val);
void asmb(void);
-void asmdyn(void);
-void asmins(Prog*);
-void asmsym(void);
-int32 atolwhex(char*);
-Prog* brchain(Prog*);
-Prog* brloop(Prog*);
-void cflush(void);
-Prog* copyp(Prog*);
-vlong cpos(void);
-double cputime(void);
-void diag(char*, ...);
-void dodata(void);
-void doelf(void);
-void doprof1(void);
-void doprof2(void);
-void dostkoff(void);
-int32 entryvalue(void);
-void follow(void);
-void instinit(void);
+void diag(char *fmt, ...);
+int elfreloc1(Reloc *r, vlong sectoff);
+void elfsetupplt(void);
void listinit(void);
-Sym* lookup(char*, int);
-void lputb(int32);
-void lputl(int32);
-void vputl(uint64);
-void strnput(char*, int);
-void main(int, char*[]);
-void* mal(uint32);
-int opsize(Prog*);
-void patch(void);
-Prog* prg(void);
-int relinv(int);
-int32 rnd(int32, int32);
-void s8put(char*);
-void span(void);
-void undef(void);
-int32 symaddr(Sym*);
-void wput(ushort);
-void wputl(ushort);
-void xdefine(char*, int, int32);
-
-uint32 machheadr(void);
-vlong addaddr(Sym *s, Sym *t);
-vlong addsize(Sym *s, Sym *t);
-vlong addstring(Sym *s, char *str);
-vlong adduint16(Sym *s, uint16 v);
-vlong adduint32(Sym *s, uint32 v);
-vlong adduint64(Sym *s, uint64 v);
-vlong adduint8(Sym *s, uint8 v);
-vlong adduintxx(Sym *s, uint64 v, int wid);
-
-/*
- * go.c
- */
-void deadcode(void);
+int machoreloc1(Reloc *r, vlong sectoff);
+void main(int argc, char *argv[]);
+int32 rnd(int32 v, int32 r);
+void s8put(char *n);
+char* xsymname(LSym *s);
/* Native is little-endian */
#define LPUT(a) lputl(a)
diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c
index e2a2ec5ed..8e57b4af1 100644
--- a/src/cmd/8l/list.c
+++ b/src/cmd/8l/list.c
@@ -58,18 +58,18 @@ Pconv(Fmt *fp)
case ATEXT:
if(p->from.scale) {
fmtprint(fp, "(%d) %A %D,%d,%D",
- p->line, p->as, &p->from, p->from.scale, &p->to);
+ p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
}
default:
fmtprint(fp, "(%d) %A %D,%D",
- p->line, p->as, &p->from, &p->to);
+ p->lineno, p->as, &p->from, &p->to);
break;
case ADATA:
case AINIT_:
case ADYNT_:
fmtprint(fp, "(%d) %A %D/%d,%D",
- p->line, p->as, &p->from, p->from.scale, &p->to);
+ p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
}
bigP = P;
@@ -82,11 +82,11 @@ Aconv(Fmt *fp)
int i;
i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
+ return fmtstrcpy(fp, anames8[i]);
}
char*
-xsymname(Sym *s)
+xsymname(LSym *s)
{
if(s == nil)
return "!!noname!!";
@@ -97,10 +97,10 @@ int
Dconv(Fmt *fp)
{
char str[STRINGSZ], s[STRINGSZ];
- Adr *a;
+ Addr *a;
int i;
- a = va_arg(fp->args, Adr*);
+ a = va_arg(fp->args, Addr*);
i = a->type;
if(i >= D_INDIR && i < 2*D_INDIR) {
if(a->offset)
@@ -159,11 +159,11 @@ Dconv(Fmt *fp)
break;
case D_FCONST:
- snprint(str, sizeof str, "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
+ snprint(str, sizeof str, "$(%.17g)", a->u.dval);
break;
case D_SCONST:
- snprint(str, sizeof str, "$\"%S\"", a->scon);
+ snprint(str, sizeof str, "$\"%S\"", a->u.sval);
break;
case D_ADDR:
@@ -361,8 +361,8 @@ diag(char *fmt, ...)
tn = "";
sep = "";
- if(cursym != S) {
- tn = cursym->name;
+ if(ctxt->cursym != S) {
+ tn = ctxt->cursym->name;
sep = ": ";
}
va_start(arg, fmt);
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index 3fdc41381..e588060be 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -30,7 +30,6 @@
// Reading object files.
-#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
@@ -39,110 +38,12 @@
#include "../ld/pe.h"
#include <ar.h>
-#ifndef DEFAULT
-#define DEFAULT '9'
-#endif
-
-char *noname = "<none>";
-char *thestring = "386";
-
-Header headers[] = {
- "garbunix", Hgarbunix,
- "unixcoff", Hunixcoff,
- "plan9", Hplan9x32,
- "msdoscom", Hmsdoscom,
- "msdosexe", Hmsdosexe,
- "darwin", Hdarwin,
- "dragonfly", Hdragonfly,
- "linux", Hlinux,
- "freebsd", Hfreebsd,
- "netbsd", Hnetbsd,
- "openbsd", Hopenbsd,
- "windows", Hwindows,
- "windowsgui", Hwindows,
- 0, 0
-};
-
-/*
- * -Hgarbunix -T0x40004C -D0x10000000 is garbage unix
- * -Hunixcoff -T0xd0 -R4 is unix coff
- * -Hplan9 -T4128 -R4096 is plan9 format
- * -Hmsdoscom -Tx -Rx is MS-DOS .COM
- * -Hmsdosexe -Tx -Rx is fake MS-DOS .EXE
- * -Hdarwin -Tx -Rx is Apple Mach-O
- * -Hdragonfly -Tx -Rx is DragonFly ELF32
- * -Hlinux -Tx -Rx is Linux ELF32
- * -Hfreebsd -Tx -Rx is FreeBSD ELF32
- * -Hnetbsd -Tx -Rx is NetBSD ELF32
- * -Hopenbsd -Tx -Rx is OpenBSD ELF32
- * -Hwindows -Tx -Rx is MS Windows PE32
- */
+char* thestring = "386";
+LinkArch* thelinkarch = &link386;
void
-main(int argc, char *argv[])
+archinit(void)
{
- Binit(&bso, 1, OWRITE);
- listinit();
- memset(debug, 0, sizeof(debug));
- nerrors = 0;
- outfile = nil;
- HEADTYPE = -1;
- INITTEXT = -1;
- INITDAT = -1;
- INITRND = -1;
- INITENTRY = 0;
- linkmode = LinkAuto;
- nuxiinit();
-
- flagcount("1", "use alternate profiling code", &debug['1']);
- flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
- flagstr("E", "sym: entry symbol", &INITENTRY);
- flagint32("D", "addr: data address", &INITDAT);
- flagfn1("I", "interp: set ELF interp", setinterp);
- flagfn1("L", "dir: add dir to library path", Lflag);
- flagfn1("H", "head: header type", setheadtype);
- flagcount("K", "add stack underflow checks", &debug['K']);
- flagcount("O", "print pc-line tables", &debug['O']);
- flagcount("Q", "debug byte-register code gen", &debug['Q']);
- flagint32("R", "rnd: address rounding", &INITRND);
- flagcount("S", "check type signatures", &debug['S']);
- flagint32("T", "addr: text address", &INITTEXT);
- flagfn0("V", "print version and exit", doversion);
- flagcount("W", "disassemble input", &debug['W']);
- flagfn2("X", "name value: define string data", addstrdata);
- flagcount("Z", "clear stack frame on entry", &debug['Z']);
- flagcount("a", "disassemble output", &debug['a']);
- flagcount("c", "dump call graph", &debug['c']);
- flagcount("d", "disable dynamic executable", &debug['d']);
- flagstr("extld", "linker to run in external mode", &extld);
- flagstr("extldflags", "flags for external linker", &extldflags);
- flagcount("f", "ignore version mismatch", &debug['f']);
- flagcount("g", "disable go package data checks", &debug['g']);
- flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
- flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
- flagstr("k", "sym: set field tracking symbol", &tracksym);
- flagstr("o", "outfile: set output file", &outfile);
- flagcount("p", "insert profiling code", &debug['p']);
- flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
- flagcount("race", "enable race detector", &flag_race);
- flagcount("s", "disable symbol table", &debug['s']);
- flagcount("n", "dump symbol table", &debug['n']);
- flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
- flagcount("u", "reject unsafe packages", &debug['u']);
- flagcount("v", "print link trace", &debug['v']);
- flagcount("w", "disable DWARF generation", &debug['w']);
- // TODO: link mode flag
-
- flagparse(&argc, &argv, usage);
-
- if(argc != 1)
- usage();
-
- mywhatsys(); // get goos
-
- if(HEADTYPE == -1)
- HEADTYPE = headtype(goos);
-
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
// Go was built; see ../../make.bash.
if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
@@ -163,41 +64,15 @@ main(int argc, char *argv[])
case Hopenbsd:
break;
}
-
- if(outfile == nil) {
- if(HEADTYPE == Hwindows)
- outfile = "8.out.exe";
- else
- outfile = "8.out";
- }
-
- libinit();
+ ctxt->linkmode = linkmode;
switch(HEADTYPE) {
default:
diag("unknown -H option");
errorexit();
- case Hgarbunix: /* this is garbage */
- HEADR = 20L+56L;
- if(INITTEXT == -1)
- INITTEXT = 0x40004CL;
- if(INITDAT == -1)
- INITDAT = 0x10000000L;
- if(INITRND == -1)
- INITRND = 0;
- break;
- case Hunixcoff: /* is unix coff */
- HEADR = 0xd0L;
- if(INITTEXT == -1)
- INITTEXT = 0xd0;
- if(INITDAT == -1)
- INITDAT = 0x400000;
- if(INITRND == -1)
- INITRND = 0;
- break;
- case Hplan9x32: /* plan 9 */
- tlsoffset = -8;
+ case Hplan9: /* plan 9 */
+ ctxt->tlsoffset = -8;
HEADR = 32L;
if(INITTEXT == -1)
INITTEXT = 4096+32;
@@ -206,33 +81,12 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
- case Hmsdoscom: /* MS-DOS .COM */
- HEADR = 0;
- if(INITTEXT == -1)
- INITTEXT = 0x0100;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- break;
- case Hmsdosexe: /* fake MS-DOS .EXE */
- HEADR = 0x200;
- if(INITTEXT == -1)
- INITTEXT = 0x0100;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- HEADR += (INITTEXT & 0xFFFF);
- if(debug['v'])
- Bprint(&bso, "HEADR = 0x%d\n", HEADR);
- break;
case Hdarwin: /* apple MACH */
/*
* OS X system constant - offset from %gs to our TLS.
* Explained in ../../pkg/runtime/cgo/gcc_darwin_386.c.
*/
- tlsoffset = 0x468;
+ ctxt->tlsoffset = 0x468;
machoinit();
HEADR = INITIAL_MACHO_HEADR;
if(INITTEXT == -1)
@@ -253,7 +107,7 @@ main(int argc, char *argv[])
* Also known to ../../pkg/runtime/sys_linux_386.s
* and ../../pkg/runtime/cgo/gcc_linux_386.c.
*/
- tlsoffset = -8;
+ ctxt->tlsoffset = -8;
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
@@ -277,516 +131,4 @@ main(int argc, char *argv[])
if(INITDAT != 0 && INITRND != 0)
print("warning: -D0x%ux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
- if(debug['v'])
- Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
- HEADTYPE, INITTEXT, INITDAT, INITRND);
- Bflush(&bso);
-
- instinit();
- zprg.link = P;
- zprg.pcond = P;
- zprg.back = 2;
- zprg.as = AGOK;
- zprg.from.type = D_NONE;
- zprg.from.index = D_NONE;
- zprg.from.scale = 1;
- zprg.to = zprg.from;
-
- pcstr = "%.6ux ";
- histgen = 0;
- pc = 0;
- dtype = 4;
- version = 0;
- cbp = buf.cbuf;
- cbc = sizeof(buf.cbuf);
-
- addlibpath("command line", "command line", argv[0], "main");
- loadlib();
- deadcode();
- patch();
- follow();
- doelf();
- if(HEADTYPE == Hdarwin)
- domacho();
- if(HEADTYPE == Hwindows)
- dope();
- dostkoff();
- dostkcheck();
- if(debug['p'])
- if(debug['1'])
- doprof1();
- else
- doprof2();
- span();
- addexport();
- textaddress();
- pclntab();
- symtab();
- dodata();
- address();
- doweak();
- reloc();
- asmb();
- undef();
- hostlink();
-
- if(debug['v']) {
- Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%d symbols\n", nsymbol);
- Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
- Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
- }
- Bflush(&bso);
-
- errorexit();
-}
-
-static Sym*
-zsym(char *pn, Biobuf *f, Sym *h[])
-{
- int o;
-
- o = BGETC(f);
- if(o < 0 || o >= NSYM || h[o] == nil)
- mangle(pn);
- return h[o];
-}
-
-static void
-zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
-{
- int t;
- int32 l;
- Sym *s;
- Auto *u;
-
- t = BGETC(f);
- a->index = D_NONE;
- a->scale = 0;
- if(t & T_INDEX) {
- a->index = BGETC(f);
- a->scale = BGETC(f);
- }
- a->type = D_NONE;
- a->offset = 0;
- if(t & T_OFFSET)
- a->offset = BGETLE4(f);
- a->offset2 = 0;
- if(t & T_OFFSET2) {
- a->offset2 = BGETLE4(f);
- a->type = D_CONST2;
- }
- a->sym = S;
- if(t & T_SYM)
- a->sym = zsym(pn, f, h);
- if(t & T_FCONST) {
- a->ieee.l = BGETLE4(f);
- a->ieee.h = BGETLE4(f);
- a->type = D_FCONST;
- } else
- if(t & T_SCONST) {
- Bread(f, a->scon, NSNAME);
- a->type = D_SCONST;
- }
- if(t & T_TYPE)
- a->type = BGETC(f);
- adrgotype = S;
- if(t & T_GOTYPE)
- adrgotype = zsym(pn, f, h);
-
- t = a->type;
- if(t == D_INDIR+D_GS)
- a->offset += tlsoffset;
-
- s = a->sym;
- if(s == S)
- return;
- if(t != D_AUTO && t != D_PARAM) {
- if(adrgotype)
- s->gotype = adrgotype;
- return;
- }
- l = a->offset;
- for(u=curauto; u; u=u->link) {
- if(u->asym == s)
- if(u->type == t) {
- if(u->aoffset > l)
- u->aoffset = l;
- if(adrgotype)
- u->gotype = adrgotype;
- return;
- }
- }
-
- u = mal(sizeof(*u));
- u->link = curauto;
- curauto = u;
- u->asym = s;
- u->aoffset = l;
- u->type = t;
- u->gotype = adrgotype;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from.type = D_NONE;
- p->to.type = D_NONE;
-}
-
-void
-ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
-{
- int32 ipc;
- Prog *p;
- int v, o, r, skip;
- Sym *h[NSYM], *s;
- uint32 sig;
- int ntext;
- int32 eof;
- char *name, *x;
- char src[1024];
- Prog *lastp;
-
- lastp = nil;
- ntext = 0;
- eof = Boffset(f) + len;
- src[0] = 0;
- pn = estrdup(pn); // we keep it in Sym* references
-
-newloop:
- memset(h, 0, sizeof(h));
- version++;
- histfrogp = 0;
- ipc = pc;
- skip = 0;
-
-loop:
- if(f->state == Bracteof || Boffset(f) >= eof)
- goto eof;
- o = BGETC(f);
- if(o == Beof)
- goto eof;
- o |= BGETC(f) << 8;
- if(o <= AXXX || o >= ALAST) {
- if(o < 0)
- goto eof;
- diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
- print(" probably not a .%c file\n", thechar);
- errorexit();
- }
-
- if(o == ANAME || o == ASIGNAME) {
- sig = 0;
- if(o == ASIGNAME)
- sig = BGETLE4(f);
- v = BGETC(f); /* type */
- o = BGETC(f); /* sym */
- r = 0;
- if(v == D_STATIC)
- r = version;
- name = Brdline(f, '\0');
- if(name == nil) {
- if(Blinelen(f) > 0) {
- fprint(2, "%s: name too long\n", pn);
- errorexit();
- }
- goto eof;
- }
- x = expandpkg(name, pkg);
- s = lookup(x, r);
- if(x != name)
- free(x);
-
- if(debug['S'] && r == 0)
- sig = 1729;
- if(sig != 0){
- if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures "
- "%ux(%s) and %ux(%s) for %s",
- s->sig, s->file, sig, pn, s->name);
- s->sig = sig;
- s->file = pn;
- }
-
- if(debug['W'])
- print(" ANAME %s\n", s->name);
- if(o < 0 || o >= nelem(h))
- mangle(pn);
- h[o] = s;
- if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
- s->type = SXREF;
- if(v == D_FILE) {
- if(s->type != SFILE) {
- histgen++;
- s->type = SFILE;
- s->value = histgen;
- }
- if(histfrogp < MAXHIST) {
- histfrog[histfrogp] = s;
- histfrogp++;
- } else
- collapsefrog(s);
- dwarfaddfrag(s->value, s->name);
- }
- goto loop;
- }
-
- p = mal(sizeof(*p));
- p->as = o;
- p->line = BGETLE4(f);
- p->back = 2;
- zaddr(pn, f, &p->from, h);
- fromgotype = adrgotype;
- zaddr(pn, f, &p->to, h);
-
- if(debug['W'])
- print("%P\n", p);
-
- switch(p->as) {
- case AHISTORY:
- if(p->to.offset == -1) {
- addlib(src, pn);
- histfrogp = 0;
- goto loop;
- }
- if(src[0] == '\0')
- copyhistfrog(src, sizeof src);
- addhist(p->line, D_FILE); /* 'z' */
- if(p->to.offset)
- addhist(p->to.offset, D_FILE1); /* 'Z' */
- savehist(p->line, p->to.offset);
- histfrogp = 0;
- goto loop;
-
- case AEND:
- histtoauto();
- if(cursym != nil && cursym->text)
- cursym->autom = curauto;
- curauto = 0;
- cursym = nil;
- if(Boffset(f) == eof)
- return;
- goto newloop;
-
- case AGLOBL:
- s = p->from.sym;
- if(s->type == 0 || s->type == SXREF) {
- s->type = SBSS;
- s->size = 0;
- }
- if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
- diag("%s: redefinition: %s in %s",
- pn, s->name, TNAME);
- s->type = SBSS;
- s->size = 0;
- }
- if(p->to.offset > s->size)
- s->size = p->to.offset;
- if(p->from.scale & DUPOK)
- s->dupok = 1;
- if(p->from.scale & RODATA)
- s->type = SRODATA;
- else if(p->from.scale & NOPTR)
- s->type = SNOPTRBSS;
- goto loop;
-
- case ADATA:
- // Assume that AGLOBL comes after ADATA.
- // If we've seen an AGLOBL that said this sym was DUPOK,
- // ignore any more ADATA we see, which must be
- // redefinitions.
- s = p->from.sym;
- if(s->dupok) {
-// if(debug['v'])
-// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
- goto loop;
- }
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
- savedata(s, p, pn);
- unmal(p, sizeof *p);
- goto loop;
-
- case AGOK:
- diag("%s: GOK opcode in %s", pn, TNAME);
- pc++;
- goto loop;
-
- case ATYPE:
- if(skip)
- goto casdef;
- pc++;
- goto loop;
-
- case ATEXT:
- s = p->from.sym;
- if(s->text != nil) {
- if(p->from.scale & DUPOK) {
- skip = 1;
- goto casdef;
- }
- diag("%s: %s: redefinition", pn, s->name);
- return;
- }
- if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
- /* redefinition, so file has probably been seen before */
- if(debug['v'])
- diag("skipping: %s: redefinition: %s", pn, s->name);
- return;
- }
- if(cursym != nil && cursym->text) {
- histtoauto();
- cursym->autom = curauto;
- curauto = 0;
- }
- skip = 0;
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- s->text = p;
- cursym = s;
- if(s->type != 0 && s->type != SXREF) {
- if(p->from.scale & DUPOK) {
- skip = 1;
- goto casdef;
- }
- diag("%s: redefinition: %s\n%P", pn, s->name, p);
- }
- s->type = STEXT;
- s->hist = gethist();
- s->value = pc;
- s->args = p->to.offset2;
- lastp = p;
- p->pc = pc++;
- goto loop;
-
- case AFMOVF:
- case AFADDF:
- case AFSUBF:
- case AFSUBRF:
- case AFMULF:
- case AFDIVF:
- case AFDIVRF:
- case AFCOMF:
- case AFCOMFP:
- case AMOVSS:
- case AADDSS:
- case ASUBSS:
- case AMULSS:
- case ADIVSS:
- case ACOMISS:
- case AUCOMISS:
- if(skip)
- goto casdef;
- if(p->from.type == D_FCONST) {
- /* size sb 9 max */
- sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(s, ieeedtof(&p->from.ieee));
- s->reachable = 0;
- }
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- goto casdef;
-
- case AFMOVD:
- case AFADDD:
- case AFSUBD:
- case AFSUBRD:
- case AFMULD:
- case AFDIVD:
- case AFDIVRD:
- case AFCOMD:
- case AFCOMDP:
- case AMOVSD:
- case AADDSD:
- case ASUBSD:
- case AMULSD:
- case ADIVSD:
- case ACOMISD:
- case AUCOMISD:
- if(skip)
- goto casdef;
- if(p->from.type == D_FCONST) {
- /* size sb 18 max */
- sprint(literal, "$%ux.%ux",
- p->from.ieee.l, p->from.ieee.h);
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(s, p->from.ieee.l);
- adduint32(s, p->from.ieee.h);
- s->reachable = 0;
- }
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- goto casdef;
-
- casdef:
- default:
- if(skip)
- nopout(p);
- p->pc = pc;
- pc++;
-
- if(p->to.type == D_BRANCH)
- p->to.offset += ipc;
- if(lastp == nil) {
- if(p->as != ANOP)
- diag("unexpected instruction: %P", p);
- goto loop;
- }
- lastp->link = p;
- lastp = p;
- goto loop;
- }
-
-eof:
- diag("truncated object file: %s", pn);
-}
-
-Prog*
-prg(void)
-{
- Prog *p;
-
- p = mal(sizeof(Prog));
- *p = zprg;
- return p;
-}
-
-Prog*
-copyp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- *p = *q;
- return p;
-}
-
-Prog*
-appendp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- p->link = q->link;
- q->link = p;
- p->line = q->line;
- return p;
}
diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c
deleted file mode 100644
index 19952e5f9..000000000
--- a/src/cmd/8l/optab.c
+++ /dev/null
@@ -1,1032 +0,0 @@
-// Inferno utils/8l/optab.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/optab.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "l.h"
-
-uchar ynone[] =
-{
- Ynone, Ynone, Zlit, 1,
- 0
-};
-uchar ytext[] =
-{
- Ymb, Yi32, Zpseudo,1,
- 0
-};
-uchar ynop[] =
-{
- Ynone, Ynone, Zpseudo,1,
- Ynone, Yml, Zpseudo,1,
- Ynone, Yrf, Zpseudo,1,
- Yml, Ynone, Zpseudo,1,
- Yrf, Ynone, Zpseudo,1,
- 0
-};
-uchar yfuncdata[] =
-{
- Yi32, Ym, Zpseudo, 0,
- 0
-};
-uchar ypcdata[] =
-{
- Yi32, Yi32, Zpseudo, 0,
- 0,
-};
-uchar yxorb[] =
-{
- Yi32, Yal, Zib_, 1,
- Yi32, Ymb, Zibo_m, 2,
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar yxorl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yaddl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yincb[] =
-{
- Ynone, Ymb, Zo_m, 2,
- 0
-};
-uchar yincl[] =
-{
- Ynone, Yrl, Z_rp, 1,
- Ynone, Yml, Zo_m, 2,
- 0
-};
-uchar ycmpb[] =
-{
- Yal, Yi32, Z_ib, 1,
- Ymb, Yi32, Zm_ibo, 2,
- Ymb, Yrb, Zm_r, 1,
- Yrb, Ymb, Zr_m, 1,
- 0
-};
-uchar ycmpl[] =
-{
- Yml, Yi8, Zm_ibo, 2,
- Yax, Yi32, Z_il, 1,
- Yml, Yi32, Zm_ilo, 2,
- Yml, Yrl, Zm_r, 1,
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar yshb[] =
-{
- Yi1, Ymb, Zo_m, 2,
- Yi32, Ymb, Zibo_m, 2,
- Ycx, Ymb, Zo_m, 2,
- 0
-};
-uchar yshl[] =
-{
- Yi1, Yml, Zo_m, 2,
- Yi32, Yml, Zibo_m, 2,
- Ycl, Yml, Zo_m, 2,
- Ycx, Yml, Zo_m, 2,
- 0
-};
-uchar ytestb[] =
-{
- Yi32, Yal, Zib_, 1,
- Yi32, Ymb, Zibo_m, 2,
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar ytestl[] =
-{
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar ymovb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- Yi32, Yrb, Zib_rp, 1,
- Yi32, Ymb, Zibo_m, 2,
- 0
-};
-uchar ymovw[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- Yi0, Yrl, Zclr, 1+2,
-// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
- Yi32, Yrl, Zil_rp, 1,
- Yi32, Yml, Zilo_m, 2,
- Yiauto, Yrl, Zaut_r, 1,
- 0
-};
-uchar ymovl[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- Yi0, Yrl, Zclr, 1+2,
-// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
- Yi32, Yrl, Zil_rp, 1,
- Yi32, Yml, Zilo_m, 2,
- Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit)
- Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit)
- Yiauto, Yrl, Zaut_r, 1,
- 0
-};
-uchar ymovq[] =
-{
- Yml, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar ym_rl[] =
-{
- Ym, Yrl, Zm_r, 1,
- 0
-};
-uchar yrl_m[] =
-{
- Yrl, Ym, Zr_m, 1,
- 0
-};
-uchar ymb_rl[] =
-{
- Ymb, Yrl, Zm_r, 1,
- 0
-};
-uchar yml_rl[] =
-{
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yrb_mb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- 0
-};
-uchar yrl_ml[] =
-{
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar yml_mb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar yxchg[] =
-{
- Yax, Yrl, Z_rp, 1,
- Yrl, Yax, Zrp_, 1,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar ydivl[] =
-{
- Yml, Ynone, Zm_o, 2,
- 0
-};
-uchar ydivb[] =
-{
- Ymb, Ynone, Zm_o, 2,
- 0
-};
-uchar yimul[] =
-{
- Yml, Ynone, Zm_o, 2,
- Yi8, Yrl, Zib_rr, 1,
- Yi32, Yrl, Zil_rr, 1,
- 0
-};
-uchar ybyte[] =
-{
- Yi32, Ynone, Zbyte, 1,
- 0
-};
-uchar yin[] =
-{
- Yi32, Ynone, Zib_, 1,
- Ynone, Ynone, Zlit, 1,
- 0
-};
-uchar yint[] =
-{
- Yi32, Ynone, Zib_, 1,
- 0
-};
-uchar ypushl[] =
-{
- Yrl, Ynone, Zrp_, 1,
- Ym, Ynone, Zm_o, 2,
- Yi8, Ynone, Zib_, 1,
- Yi32, Ynone, Zil_, 1,
- 0
-};
-uchar ypopl[] =
-{
- Ynone, Yrl, Z_rp, 1,
- Ynone, Ym, Zo_m, 2,
- 0
-};
-uchar ybswap[] =
-{
- Ynone, Yrl, Z_rp, 1,
- 0,
-};
-uchar yscond[] =
-{
- Ynone, Ymb, Zo_m, 2,
- 0
-};
-uchar yjcond[] =
-{
- Ynone, Ybr, Zbr, 0,
- Yi0, Ybr, Zbr, 0,
- Yi1, Ybr, Zbr, 1,
- 0
-};
-uchar yloop[] =
-{
- Ynone, Ybr, Zloop, 1,
- 0
-};
-uchar ycall[] =
-{
- Ynone, Yml, Zo_m, 0,
- Yrx, Yrx, Zo_m, 2,
- Ynone, Ycol, Zcallind, 2,
- Ynone, Ybr, Zcall, 0,
- Ynone, Yi32, Zcallcon, 1,
- 0
-};
-uchar yjmp[] =
-{
- Ynone, Yml, Zo_m, 2,
- Ynone, Ybr, Zjmp, 0,
- Ynone, Yi32, Zjmpcon, 1,
- 0
-};
-
-uchar yfmvd[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yf0, Ym, Zo_m, 2,
- Yrf, Yf0, Zm_o, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfmvdp[] =
-{
- Yf0, Ym, Zo_m, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfmvf[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yf0, Ym, Zo_m, 2,
- 0
-};
-uchar yfmvx[] =
-{
- Ym, Yf0, Zm_o, 2,
- 0
-};
-uchar yfmvp[] =
-{
- Yf0, Ym, Zo_m, 2,
- 0
-};
-uchar yfcmv[] =
-{
- Yrf, Yf0, Zm_o, 2,
- 0
-};
-uchar yfadd[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yrf, Yf0, Zm_o, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfaddp[] =
-{
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfxch[] =
-{
- Yf0, Yrf, Zo_m, 2,
- Yrf, Yf0, Zm_o, 2,
- 0
-};
-uchar ycompp[] =
-{
- Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
- 0
-};
-uchar ystsw[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ynone, Yax, Zlit, 1,
- 0
-};
-uchar ystcw[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ym, Ynone, Zm_o, 2,
- 0
-};
-uchar ysvrs[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ym, Ynone, Zm_o, 2,
- 0
-};
-uchar ymskb[] =
-{
- Yxr, Yrl, Zm_r_xm, 2,
- Ymr, Yrl, Zm_r_xm, 1,
- 0
-};
-uchar yxm[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcvm1[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- Yxm, Ymr, Zm_r_xm, 2,
- 0
-};
-uchar yxcvm2[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- Ymm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxmq[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxr[] =
-{
- Yxr, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxr_ml[] =
-{
- Yxr, Yml, Zr_m_xm, 1,
- 0
-};
-uchar yxcmp[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcmpi[] =
-{
- Yxm, Yxr, Zm_r_i_xm, 2,
- 0
-};
-uchar yxmov[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- Yxr, Yxm, Zr_m_xm, 1,
- 0
-};
-uchar yxcvfl[] =
-{
- Yxm, Yrl, Zm_r_xm, 1,
- 0
-};
-uchar yxcvlf[] =
-{
- Yml, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcvfq[] =
-{
- Yxm, Yrl, Zm_r_xm, 2,
- 0
-};
-uchar yxcvqf[] =
-{
- Yml, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxrrl[] =
-{
- Yxr, Yrl, Zm_r, 1,
- 0
-};
-uchar yprefetch[] =
-{
- Ym, Ynone, Zm_o, 2,
- 0,
-};
-uchar yaes[] =
-{
- Yxm, Yxr, Zlitm_r, 2,
- 0
-};
-uchar yinsrd[] =
-{
- Yml, Yxr, Zibm_r, 2,
- 0
-};
-uchar ymshufb[] =
-{
- Yxm, Yxr, Zm2_r, 2,
- 0
-};
-
-Optab optab[] =
-/* as, ytab, andproto, opcode */
-{
- { AXXX },
- { AAAA, ynone, Px, 0x37 },
- { AAAD, ynone, Px, 0xd5,0x0a },
- { AAAM, ynone, Px, 0xd4,0x0a },
- { AAAS, ynone, Px, 0x3f },
- { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
- { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADDB, yxorb, Px, 0x04,0x80,(00),0x00,0x02 },
- { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADJSP },
- { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
- { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AARPL, yrl_ml, Px, 0x63 },
- { ABOUNDL, yrl_m, Px, 0x62 },
- { ABOUNDW, yrl_m, Pe, 0x62 },
- { ABSFL, yml_rl, Pm, 0xbc },
- { ABSFW, yml_rl, Pq, 0xbc },
- { ABSRL, yml_rl, Pm, 0xbd },
- { ABSRW, yml_rl, Pq, 0xbd },
- { ABTL, yml_rl, Pm, 0xa3 },
- { ABTW, yml_rl, Pq, 0xa3 },
- { ABTCL, yml_rl, Pm, 0xbb },
- { ABTCW, yml_rl, Pq, 0xbb },
- { ABTRL, yml_rl, Pm, 0xb3 },
- { ABTRW, yml_rl, Pq, 0xb3 },
- { ABTSL, yml_rl, Pm, 0xab },
- { ABTSW, yml_rl, Pq, 0xab },
- { ABYTE, ybyte, Px, 1 },
- { ACALL, ycall, Px, 0xff,(02),0xff,(0x15),0xe8 },
- { ACLC, ynone, Px, 0xf8 },
- { ACLD, ynone, Px, 0xfc },
- { ACLI, ynone, Px, 0xfa },
- { ACLTS, ynone, Pm, 0x06 },
- { ACMC, ynone, Px, 0xf5 },
- { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
- { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACMPSB, ynone, Pb, 0xa6 },
- { ACMPSL, ynone, Px, 0xa7 },
- { ACMPSW, ynone, Pe, 0xa7 },
- { ADAA, ynone, Px, 0x27 },
- { ADAS, ynone, Px, 0x2f },
- { ADATA },
- { ADECB, yincb, Pb, 0xfe,(01) },
- { ADECL, yincl, Px, 0x48,0xff,(01) },
- { ADECW, yincl, Pe, 0x48,0xff,(01) },
- { ADIVB, ydivb, Pb, 0xf6,(06) },
- { ADIVL, ydivl, Px, 0xf7,(06) },
- { ADIVW, ydivl, Pe, 0xf7,(06) },
- { AENTER }, /* botch */
- { AGLOBL },
- { AGOK },
- { AHISTORY },
- { AHLT, ynone, Px, 0xf4 },
- { AIDIVB, ydivb, Pb, 0xf6,(07) },
- { AIDIVL, ydivl, Px, 0xf7,(07) },
- { AIDIVW, ydivl, Pe, 0xf7,(07) },
- { AIMULB, ydivb, Pb, 0xf6,(05) },
- { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69 },
- { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69 },
- { AINB, yin, Pb, 0xe4,0xec },
- { AINL, yin, Px, 0xe5,0xed },
- { AINW, yin, Pe, 0xe5,0xed },
- { AINCB, yincb, Pb, 0xfe,(00) },
- { AINCL, yincl, Px, 0x40,0xff,(00) },
- { AINCW, yincl, Pe, 0x40,0xff,(00) },
- { AINSB, ynone, Pb, 0x6c },
- { AINSL, ynone, Px, 0x6d },
- { AINSW, ynone, Pe, 0x6d },
- { AINT, yint, Px, 0xcd },
- { AINTO, ynone, Px, 0xce },
- { AIRETL, ynone, Px, 0xcf },
- { AIRETW, ynone, Pe, 0xcf },
- { AJCC, yjcond, Px, 0x73,0x83,(00) },
- { AJCS, yjcond, Px, 0x72,0x82 },
- { AJCXZL, yloop, Px, 0xe3 },
- { AJCXZW, yloop, Px, 0xe3 },
- { AJEQ, yjcond, Px, 0x74,0x84 },
- { AJGE, yjcond, Px, 0x7d,0x8d },
- { AJGT, yjcond, Px, 0x7f,0x8f },
- { AJHI, yjcond, Px, 0x77,0x87 },
- { AJLE, yjcond, Px, 0x7e,0x8e },
- { AJLS, yjcond, Px, 0x76,0x86 },
- { AJLT, yjcond, Px, 0x7c,0x8c },
- { AJMI, yjcond, Px, 0x78,0x88 },
- { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
- { AJNE, yjcond, Px, 0x75,0x85 },
- { AJOC, yjcond, Px, 0x71,0x81,(00) },
- { AJOS, yjcond, Px, 0x70,0x80,(00) },
- { AJPC, yjcond, Px, 0x7b,0x8b },
- { AJPL, yjcond, Px, 0x79,0x89 },
- { AJPS, yjcond, Px, 0x7a,0x8a },
- { ALAHF, ynone, Px, 0x9f },
- { ALARL, yml_rl, Pm, 0x02 },
- { ALARW, yml_rl, Pq, 0x02 },
- { ALEAL, ym_rl, Px, 0x8d },
- { ALEAW, ym_rl, Pe, 0x8d },
- { ALEAVEL, ynone, Px, 0xc9 },
- { ALEAVEW, ynone, Pe, 0xc9 },
- { ALOCK, ynone, Px, 0xf0 },
- { ALODSB, ynone, Pb, 0xac },
- { ALODSL, ynone, Px, 0xad },
- { ALODSW, ynone, Pe, 0xad },
- { ALONG, ybyte, Px, 4 },
- { ALOOP, yloop, Px, 0xe2 },
- { ALOOPEQ, yloop, Px, 0xe1 },
- { ALOOPNE, yloop, Px, 0xe0 },
- { ALSLL, yml_rl, Pm, 0x03 },
- { ALSLW, yml_rl, Pq, 0x03 },
- { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
- { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),Pe,0x6e,Pe,0x7e,0 },
- { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),0 },
- { AMOVQ, ymovq, Pf3, 0x7e },
- { AMOVBLSX, ymb_rl, Pm, 0xbe },
- { AMOVBLZX, ymb_rl, Pm, 0xb6 },
- { AMOVBWSX, ymb_rl, Pq, 0xbe },
- { AMOVBWZX, ymb_rl, Pq, 0xb6 },
- { AMOVWLSX, yml_rl, Pm, 0xbf },
- { AMOVWLZX, yml_rl, Pm, 0xb7 },
- { AMOVSB, ynone, Pb, 0xa4 },
- { AMOVSL, ynone, Px, 0xa5 },
- { AMOVSW, ynone, Pe, 0xa5 },
- { AMULB, ydivb, Pb, 0xf6,(04) },
- { AMULL, ydivl, Px, 0xf7,(04) },
- { AMULW, ydivl, Pe, 0xf7,(04) },
- { ANAME },
- { ANEGB, yscond, Px, 0xf6,(03) },
- { ANEGL, yscond, Px, 0xf7,(03) },
- { ANEGW, yscond, Pe, 0xf7,(03) },
- { ANOP, ynop, Px,0,0 },
- { ANOTB, yscond, Px, 0xf6,(02) },
- { ANOTL, yscond, Px, 0xf7,(02) },
- { ANOTW, yscond, Pe, 0xf7,(02) },
- { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
- { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AOUTB, yin, Pb, 0xe6,0xee },
- { AOUTL, yin, Px, 0xe7,0xef },
- { AOUTW, yin, Pe, 0xe7,0xef },
- { AOUTSB, ynone, Pb, 0x6e },
- { AOUTSL, ynone, Px, 0x6f },
- { AOUTSW, ynone, Pe, 0x6f },
- { APAUSE, ynone, Px, 0xf3,0x90 },
- { APOPAL, ynone, Px, 0x61 },
- { APOPAW, ynone, Pe, 0x61 },
- { APOPFL, ynone, Px, 0x9d },
- { APOPFW, ynone, Pe, 0x9d },
- { APOPL, ypopl, Px, 0x58,0x8f,(00) },
- { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
- { APUSHAL, ynone, Px, 0x60 },
- { APUSHAW, ynone, Pe, 0x60 },
- { APUSHFL, ynone, Px, 0x9c },
- { APUSHFW, ynone, Pe, 0x9c },
- { APUSHL, ypushl, Px, 0x50,0xff,(06),0x6a,0x68 },
- { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
- { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
- { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
- { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { AREP, ynone, Px, 0xf3 },
- { AREPN, ynone, Px, 0xf2 },
- { ARET, ynone, Px, 0xc3 },
- { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
- { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
- { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ASAHF, ynone, Px, 0x9e },
- { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
- { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
- { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
- { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASCASB, ynone, Pb, 0xae },
- { ASCASL, ynone, Px, 0xaf },
- { ASCASW, ynone, Pe, 0xaf },
- { ASETCC, yscond, Pm, 0x93,(00) },
- { ASETCS, yscond, Pm, 0x92,(00) },
- { ASETEQ, yscond, Pm, 0x94,(00) },
- { ASETGE, yscond, Pm, 0x9d,(00) },
- { ASETGT, yscond, Pm, 0x9f,(00) },
- { ASETHI, yscond, Pm, 0x97,(00) },
- { ASETLE, yscond, Pm, 0x9e,(00) },
- { ASETLS, yscond, Pm, 0x96,(00) },
- { ASETLT, yscond, Pm, 0x9c,(00) },
- { ASETMI, yscond, Pm, 0x98,(00) },
- { ASETNE, yscond, Pm, 0x95,(00) },
- { ASETOC, yscond, Pm, 0x91,(00) },
- { ASETOS, yscond, Pm, 0x90,(00) },
- { ASETPC, yscond, Pm, 0x96,(00) },
- { ASETPL, yscond, Pm, 0x99,(00) },
- { ASETPS, yscond, Pm, 0x9a,(00) },
- { ACDQ, ynone, Px, 0x99 },
- { ACWD, ynone, Pe, 0x99 },
- { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
- { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
- { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASTC, ynone, Px, 0xf9 },
- { ASTD, ynone, Px, 0xfd },
- { ASTI, ynone, Px, 0xfb },
- { ASTOSB, ynone, Pb, 0xaa },
- { ASTOSL, ynone, Px, 0xab },
- { ASTOSW, ynone, Pe, 0xab },
- { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
- { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASYSCALL, ynone, Px, 0xcd,100 },
- { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
- { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
- { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
- { ATEXT, ytext, Px },
- { AVERR, ydivl, Pm, 0x00,(04) },
- { AVERW, ydivl, Pm, 0x00,(05) },
- { AWAIT, ynone, Px, 0x9b },
- { AWORD, ybyte, Px, 2 },
- { AXCHGB, yml_mb, Pb, 0x86,0x86 },
- { AXCHGL, yxchg, Px, 0x90,0x90,0x87,0x87 },
- { AXCHGW, yxchg, Pe, 0x90,0x90,0x87,0x87 },
- { AXLAT, ynone, Px, 0xd7 },
- { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
- { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
- { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
-
- { AFMOVB, yfmvx, Px, 0xdf,(04) },
- { AFMOVBP, yfmvp, Px, 0xdf,(06) },
- { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
- { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
- { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
- { AFMOVFP, yfmvp, Px, 0xd9,(03) },
- { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
- { AFMOVLP, yfmvp, Px, 0xdb,(03) },
- { AFMOVV, yfmvx, Px, 0xdf,(05) },
- { AFMOVVP, yfmvp, Px, 0xdf,(07) },
- { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
- { AFMOVWP, yfmvp, Px, 0xdf,(03) },
- { AFMOVX, yfmvx, Px, 0xdb,(05) },
- { AFMOVXP, yfmvp, Px, 0xdb,(07) },
-
- { AFCOMB },
- { AFCOMBP },
- { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
- { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
- { AFCOMDPP, ycompp, Px, 0xde,(03) },
- { AFCOMF, yfmvx, Px, 0xd8,(02) },
- { AFCOMFP, yfmvx, Px, 0xd8,(03) },
- { AFCOMI, yfmvx, Px, 0xdb,(06) },
- { AFCOMIP, yfmvx, Px, 0xdf,(06) },
- { AFCOML, yfmvx, Px, 0xda,(02) },
- { AFCOMLP, yfmvx, Px, 0xda,(03) },
- { AFCOMW, yfmvx, Px, 0xde,(02) },
- { AFCOMWP, yfmvx, Px, 0xde,(03) },
-
- { AFUCOM, ycompp, Px, 0xdd,(04) },
- { AFUCOMI, ycompp, Px, 0xdb,(05) },
- { AFUCOMIP, ycompp, Px, 0xdf,(05) },
- { AFUCOMP, ycompp, Px, 0xdd,(05) },
- { AFUCOMPP, ycompp, Px, 0xda,(13) },
-
- { AFADDDP, yfaddp, Px, 0xde,(00) },
- { AFADDW, yfmvx, Px, 0xde,(00) },
- { AFADDL, yfmvx, Px, 0xda,(00) },
- { AFADDF, yfmvx, Px, 0xd8,(00) },
- { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
-
- { AFMULDP, yfaddp, Px, 0xde,(01) },
- { AFMULW, yfmvx, Px, 0xde,(01) },
- { AFMULL, yfmvx, Px, 0xda,(01) },
- { AFMULF, yfmvx, Px, 0xd8,(01) },
- { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
-
- { AFSUBDP, yfaddp, Px, 0xde,(05) },
- { AFSUBW, yfmvx, Px, 0xde,(04) },
- { AFSUBL, yfmvx, Px, 0xda,(04) },
- { AFSUBF, yfmvx, Px, 0xd8,(04) },
- { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
-
- { AFSUBRDP, yfaddp, Px, 0xde,(04) },
- { AFSUBRW, yfmvx, Px, 0xde,(05) },
- { AFSUBRL, yfmvx, Px, 0xda,(05) },
- { AFSUBRF, yfmvx, Px, 0xd8,(05) },
- { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
-
- { AFDIVDP, yfaddp, Px, 0xde,(07) },
- { AFDIVW, yfmvx, Px, 0xde,(06) },
- { AFDIVL, yfmvx, Px, 0xda,(06) },
- { AFDIVF, yfmvx, Px, 0xd8,(06) },
- { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
-
- { AFDIVRDP, yfaddp, Px, 0xde,(06) },
- { AFDIVRW, yfmvx, Px, 0xde,(07) },
- { AFDIVRL, yfmvx, Px, 0xda,(07) },
- { AFDIVRF, yfmvx, Px, 0xd8,(07) },
- { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
-
- { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
- { AFFREE },
- { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
- { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
- { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
- { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
- { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
- { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
- { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
- { AF2XM1, ynone, Px, 0xd9, 0xf0 },
- { AFABS, ynone, Px, 0xd9, 0xe1 },
- { AFCHS, ynone, Px, 0xd9, 0xe0 },
- { AFCLEX, ynone, Px, 0xdb, 0xe2 },
- { AFCOS, ynone, Px, 0xd9, 0xff },
- { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
- { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
- { AFINIT, ynone, Px, 0xdb, 0xe3 },
- { AFLD1, ynone, Px, 0xd9, 0xe8 },
- { AFLDL2E, ynone, Px, 0xd9, 0xea },
- { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
- { AFLDLG2, ynone, Px, 0xd9, 0xec },
- { AFLDLN2, ynone, Px, 0xd9, 0xed },
- { AFLDPI, ynone, Px, 0xd9, 0xeb },
- { AFLDZ, ynone, Px, 0xd9, 0xee },
- { AFNOP, ynone, Px, 0xd9, 0xd0 },
- { AFPATAN, ynone, Px, 0xd9, 0xf3 },
- { AFPREM, ynone, Px, 0xd9, 0xf8 },
- { AFPREM1, ynone, Px, 0xd9, 0xf5 },
- { AFPTAN, ynone, Px, 0xd9, 0xf2 },
- { AFRNDINT, ynone, Px, 0xd9, 0xfc },
- { AFSCALE, ynone, Px, 0xd9, 0xfd },
- { AFSIN, ynone, Px, 0xd9, 0xfe },
- { AFSINCOS, ynone, Px, 0xd9, 0xfb },
- { AFSQRT, ynone, Px, 0xd9, 0xfa },
- { AFTST, ynone, Px, 0xd9, 0xe4 },
- { AFXAM, ynone, Px, 0xd9, 0xe5 },
- { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
- { AFYL2X, ynone, Px, 0xd9, 0xf1 },
- { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
- { AEND },
- { ADYNT_ },
- { AINIT_ },
- { ASIGNAME },
- { ACMPXCHGB, yrb_mb, Pm, 0xb0 },
- { ACMPXCHGL, yrl_ml, Pm, 0xb1 },
- { ACMPXCHGW, yrl_ml, Pm, 0xb1 },
- { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
-
- { ACPUID, ynone, Pm, 0xa2 },
- { ARDTSC, ynone, Pm, 0x31 },
-
- { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
- { AXADDL, yrl_ml, Pm, 0xc1 },
- { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
-
- { ACMOVLCC, yml_rl, Pm, 0x43 },
- { ACMOVLCS, yml_rl, Pm, 0x42 },
- { ACMOVLEQ, yml_rl, Pm, 0x44 },
- { ACMOVLGE, yml_rl, Pm, 0x4d },
- { ACMOVLGT, yml_rl, Pm, 0x4f },
- { ACMOVLHI, yml_rl, Pm, 0x47 },
- { ACMOVLLE, yml_rl, Pm, 0x4e },
- { ACMOVLLS, yml_rl, Pm, 0x46 },
- { ACMOVLLT, yml_rl, Pm, 0x4c },
- { ACMOVLMI, yml_rl, Pm, 0x48 },
- { ACMOVLNE, yml_rl, Pm, 0x45 },
- { ACMOVLOC, yml_rl, Pm, 0x41 },
- { ACMOVLOS, yml_rl, Pm, 0x40 },
- { ACMOVLPC, yml_rl, Pm, 0x4b },
- { ACMOVLPL, yml_rl, Pm, 0x49 },
- { ACMOVLPS, yml_rl, Pm, 0x4a },
- { ACMOVWCC, yml_rl, Pq, 0x43 },
- { ACMOVWCS, yml_rl, Pq, 0x42 },
- { ACMOVWEQ, yml_rl, Pq, 0x44 },
- { ACMOVWGE, yml_rl, Pq, 0x4d },
- { ACMOVWGT, yml_rl, Pq, 0x4f },
- { ACMOVWHI, yml_rl, Pq, 0x47 },
- { ACMOVWLE, yml_rl, Pq, 0x4e },
- { ACMOVWLS, yml_rl, Pq, 0x46 },
- { ACMOVWLT, yml_rl, Pq, 0x4c },
- { ACMOVWMI, yml_rl, Pq, 0x48 },
- { ACMOVWNE, yml_rl, Pq, 0x45 },
- { ACMOVWOC, yml_rl, Pq, 0x41 },
- { ACMOVWOS, yml_rl, Pq, 0x40 },
- { ACMOVWPC, yml_rl, Pq, 0x4b },
- { ACMOVWPL, yml_rl, Pq, 0x49 },
- { ACMOVWPS, yml_rl, Pq, 0x4a },
-
- { AFCMOVCC, yfcmv, Px, 0xdb,(00) },
- { AFCMOVCS, yfcmv, Px, 0xda,(00) },
- { AFCMOVEQ, yfcmv, Px, 0xda,(01) },
- { AFCMOVHI, yfcmv, Px, 0xdb,(02) },
- { AFCMOVLS, yfcmv, Px, 0xda,(02) },
- { AFCMOVNE, yfcmv, Px, 0xdb,(01) },
- { AFCMOVNU, yfcmv, Px, 0xdb,(03) },
- { AFCMOVUN, yfcmv, Px, 0xda,(03) },
-
- { ALFENCE, ynone, Pm, 0xae,0xe8 },
- { AMFENCE, ynone, Pm, 0xae,0xf0 },
- { ASFENCE, ynone, Pm, 0xae,0xf8 },
-
- { AEMMS, ynone, Pm, 0x77 },
-
- { APREFETCHT0, yprefetch, Pm, 0x18,(01) },
- { APREFETCHT1, yprefetch, Pm, 0x18,(02) },
- { APREFETCHT2, yprefetch, Pm, 0x18,(03) },
- { APREFETCHNTA, yprefetch, Pm, 0x18,(00) },
-
- { ABSWAPL, ybswap, Pm, 0xc8 },
-
- { AUNDEF, ynone, Px, 0x0f, 0x0b },
-
- { AADDPD, yxm, Pq, 0x58 },
- { AADDPS, yxm, Pm, 0x58 },
- { AADDSD, yxm, Pf2, 0x58 },
- { AADDSS, yxm, Pf3, 0x58 },
- { AANDNPD, yxm, Pq, 0x55 },
- { AANDNPS, yxm, Pm, 0x55 },
- { AANDPD, yxm, Pq, 0x54 },
- { AANDPS, yxm, Pq, 0x54 },
- { ACMPPD, yxcmpi, Px, Pe,0xc2 },
- { ACMPPS, yxcmpi, Pm, 0xc2,0 },
- { ACMPSD, yxcmpi, Px, Pf2,0xc2 },
- { ACMPSS, yxcmpi, Px, Pf3,0xc2 },
- { ACOMISD, yxcmp, Pe, 0x2f },
- { ACOMISS, yxcmp, Pm, 0x2f },
- { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a },
- { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, },
- { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d },
- { ACVTPD2PS, yxm, Pe, 0x5a },
- { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d },
- { ACVTPS2PD, yxm, Pm, 0x5a },
- { ACVTSD2SL, yxcvfl, Pf2, 0x2d },
- { ACVTSD2SS, yxm, Pf2, 0x5a },
- { ACVTSL2SD, yxcvlf, Pf2, 0x2a },
- { ACVTSL2SS, yxcvlf, Pf3, 0x2a },
- { ACVTSS2SD, yxm, Pf3, 0x5a },
- { ACVTSS2SL, yxcvfl, Pf3, 0x2d },
- { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c },
- { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c },
- { ACVTTSD2SL, yxcvfl, Pf2, 0x2c },
- { ACVTTSS2SL, yxcvfl, Pf3, 0x2c },
- { ADIVPD, yxm, Pe, 0x5e },
- { ADIVPS, yxm, Pm, 0x5e },
- { ADIVSD, yxm, Pf2, 0x5e },
- { ADIVSS, yxm, Pf3, 0x5e },
- { AMASKMOVOU, yxr, Pe, 0xf7 },
- { AMAXPD, yxm, Pe, 0x5f },
- { AMAXPS, yxm, Pm, 0x5f },
- { AMAXSD, yxm, Pf2, 0x5f },
- { AMAXSS, yxm, Pf3, 0x5f },
- { AMINPD, yxm, Pe, 0x5d },
- { AMINPS, yxm, Pm, 0x5d },
- { AMINSD, yxm, Pf2, 0x5d },
- { AMINSS, yxm, Pf3, 0x5d },
- { AMOVAPD, yxmov, Pe, 0x28,0x29 },
- { AMOVAPS, yxmov, Pm, 0x28,0x29 },
- { AMOVO, yxmov, Pe, 0x6f,0x7f },
- { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
- { AMOVHLPS, yxr, Pm, 0x12 },
- { AMOVHPD, yxmov, Pe, 0x16,0x17 },
- { AMOVHPS, yxmov, Pm, 0x16,0x17 },
- { AMOVLHPS, yxr, Pm, 0x16 },
- { AMOVLPD, yxmov, Pe, 0x12,0x13 },
- { AMOVLPS, yxmov, Pm, 0x12,0x13 },
- { AMOVMSKPD, yxrrl, Pq, 0x50 },
- { AMOVMSKPS, yxrrl, Pm, 0x50 },
- { AMOVNTO, yxr_ml, Pe, 0xe7 },
- { AMOVNTPD, yxr_ml, Pe, 0x2b },
- { AMOVNTPS, yxr_ml, Pm, 0x2b },
- { AMOVSD, yxmov, Pf2, 0x10,0x11 },
- { AMOVSS, yxmov, Pf3, 0x10,0x11 },
- { AMOVUPD, yxmov, Pe, 0x10,0x11 },
- { AMOVUPS, yxmov, Pm, 0x10,0x11 },
- { AMULPD, yxm, Pe, 0x59 },
- { AMULPS, yxm, Ym, 0x59 },
- { AMULSD, yxm, Pf2, 0x59 },
- { AMULSS, yxm, Pf3, 0x59 },
- { AORPD, yxm, Pq, 0x56 },
- { AORPS, yxm, Pm, 0x56 },
- { APADDQ, yxm, Pe, 0xd4 },
- { APAND, yxm, Pe, 0xdb },
- { APCMPEQB, yxmq, Pe ,0x74 },
- { APMAXSW, yxm, Pe, 0xee },
- { APMAXUB, yxm, Pe, 0xde },
- { APMINSW, yxm, Pe, 0xea },
- { APMINUB, yxm, Pe, 0xda },
- { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 },
- { APSADBW, yxm, Pq, 0xf6 },
- { APSUBB, yxm, Pe, 0xf8 },
- { APSUBL, yxm, Pe, 0xfa },
- { APSUBQ, yxm, Pe, 0xfb },
- { APSUBSB, yxm, Pe, 0xe8 },
- { APSUBSW, yxm, Pe, 0xe9 },
- { APSUBUSB, yxm, Pe, 0xd8 },
- { APSUBUSW, yxm, Pe, 0xd9 },
- { APSUBW, yxm, Pe, 0xf9 },
- { APUNPCKHQDQ, yxm, Pe, 0x6d },
- { APUNPCKLQDQ, yxm, Pe, 0x6c },
- { ARCPPS, yxm, Pm, 0x53 },
- { ARCPSS, yxm, Pf3, 0x53 },
- { ARSQRTPS, yxm, Pm, 0x52 },
- { ARSQRTSS, yxm, Pf3, 0x52 },
- { ASQRTPD, yxm, Pe, 0x51 },
- { ASQRTPS, yxm, Pm, 0x51 },
- { ASQRTSD, yxm, Pf2, 0x51 },
- { ASQRTSS, yxm, Pf3, 0x51 },
- { ASUBPD, yxm, Pe, 0x5c },
- { ASUBPS, yxm, Pm, 0x5c },
- { ASUBSD, yxm, Pf2, 0x5c },
- { ASUBSS, yxm, Pf3, 0x5c },
- { AUCOMISD, yxcmp, Pe, 0x2e },
- { AUCOMISS, yxcmp, Pm, 0x2e },
- { AUNPCKHPD, yxm, Pe, 0x15 },
- { AUNPCKHPS, yxm, Pm, 0x15 },
- { AUNPCKLPD, yxm, Pe, 0x14 },
- { AUNPCKLPS, yxm, Pm, 0x14 },
- { AXORPD, yxm, Pe, 0x57 },
- { AXORPS, yxm, Pm, 0x57 },
-
- { AAESENC, yaes, Pq, 0x38,0xdc,(0) },
- { APINSRD, yinsrd, Pq, 0x3a, 0x22, (00) },
- { APSHUFB, ymshufb,Pq, 0x38, 0x00 },
-
- { AUSEFIELD, ynop, Px, 0,0 },
- { ATYPE },
- { AFUNCDATA, yfuncdata, Px, 0,0 },
- { APCDATA, ypcdata, Px, 0,0 },
- { ACHECKNIL },
- { AFATVARDEF },
-
- 0
-};
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
deleted file mode 100644
index 1eaf78fe0..000000000
--- a/src/cmd/8l/pass.c
+++ /dev/null
@@ -1,858 +0,0 @@
-// Inferno utils/8l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Code and data passes.
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../../pkg/runtime/stack.h"
-
-static void xfol(Prog*, Prog**);
-
-Prog*
-brchain(Prog *p)
-{
- int i;
-
- for(i=0; i<20; i++) {
- if(p == P || p->as != AJMP)
- return p;
- p = p->pcond;
- }
- return P;
-}
-
-void
-follow(void)
-{
- Prog *firstp, *lastp;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f follow\n", cputime());
- Bflush(&bso);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- firstp = prg();
- lastp = firstp;
- xfol(cursym->text, &lastp);
- lastp->link = nil;
- cursym->text = firstp->link;
- }
-}
-
-static int
-nofollow(int a)
-{
- switch(a) {
- case AJMP:
- case ARET:
- case AIRETL:
- case AIRETW:
- case AUNDEF:
- return 1;
- }
- return 0;
-}
-
-static int
-pushpop(int a)
-{
- switch(a) {
- case APUSHL:
- case APUSHFL:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPW:
- case APOPFW:
- return 1;
- }
- return 0;
-}
-
-static void
-xfol(Prog *p, Prog **last)
-{
- Prog *q;
- int i;
- enum as a;
-
-loop:
- if(p == P)
- return;
- if(p->as == AJMP)
- if((q = p->pcond) != P && q->as != ATEXT) {
- /* mark instruction as done and continue layout at target of jump */
- p->mark = 1;
- p = q;
- if(p->mark == 0)
- goto loop;
- }
- if(p->mark) {
- /*
- * p goes here, but already used it elsewhere.
- * copy up to 4 instructions or else branch to other copy.
- */
- for(i=0,q=p; i<4; i++,q=q->link) {
- if(q == P)
- break;
- if(q == *last)
- break;
- a = q->as;
- if(a == ANOP) {
- i--;
- continue;
- }
- if(nofollow(a) || pushpop(a))
- break; // NOTE(rsc): arm does goto copy
- if(q->pcond == P || q->pcond->mark)
- continue;
- if(a == ACALL || a == ALOOP)
- continue;
- for(;;) {
- if(p->as == ANOP) {
- p = p->link;
- continue;
- }
- q = copyp(p);
- p = p->link;
- q->mark = 1;
- (*last)->link = q;
- *last = q;
- if(q->as != a || q->pcond == P || q->pcond->mark)
- continue;
-
- q->as = relinv(q->as);
- p = q->pcond;
- q->pcond = q->link;
- q->link = p;
- xfol(q->link, last);
- p = q->link;
- if(p->mark)
- return;
- goto loop;
- }
- } /* */
- q = prg();
- q->as = AJMP;
- q->line = p->line;
- q->to.type = D_BRANCH;
- q->to.offset = p->pc;
- q->pcond = p;
- p = q;
- }
-
- /* emit p */
- p->mark = 1;
- (*last)->link = p;
- *last = p;
- a = p->as;
-
- /* continue loop with what comes after p */
- if(nofollow(a))
- return;
- if(p->pcond != P && a != ACALL) {
- /*
- * some kind of conditional branch.
- * recurse to follow one path.
- * continue loop on the other.
- */
- if((q = brchain(p->pcond)) != P)
- p->pcond = q;
- if((q = brchain(p->link)) != P)
- p->link = q;
- if(p->from.type == D_CONST) {
- if(p->from.offset == 1) {
- /*
- * expect conditional jump to be taken.
- * rewrite so that's the fall-through case.
- */
- p->as = relinv(a);
- q = p->link;
- p->link = p->pcond;
- p->pcond = q;
- }
- } else {
- q = p->link;
- if(q->mark)
- if(a != ALOOP) {
- p->as = relinv(a);
- p->link = p->pcond;
- p->pcond = q;
- }
- }
- xfol(p->link, last);
- if(p->pcond->mark)
- return;
- p = p->pcond;
- goto loop;
- }
- p = p->link;
- goto loop;
-}
-
-int
-relinv(int a)
-{
-
- switch(a) {
- case AJEQ: return AJNE;
- case AJNE: return AJEQ;
- case AJLE: return AJGT;
- case AJLS: return AJHI;
- case AJLT: return AJGE;
- case AJMI: return AJPL;
- case AJGE: return AJLT;
- case AJPL: return AJMI;
- case AJGT: return AJLE;
- case AJHI: return AJLS;
- case AJCS: return AJCC;
- case AJCC: return AJCS;
- case AJPS: return AJPC;
- case AJPC: return AJPS;
- case AJOS: return AJOC;
- case AJOC: return AJOS;
- }
- diag("unknown relation: %s in %s", anames[a], TNAME);
- return a;
-}
-
-void
-patch(void)
-{
- int32 c;
- Prog *p, *q;
- Sym *s;
- int32 vexit;
- Sym *plan9_tos;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f mkfwd\n", cputime());
- Bflush(&bso);
- mkfwd();
- if(debug['v'])
- Bprint(&bso, "%5.2f patch\n", cputime());
- Bflush(&bso);
- s = lookup("exit", 0);
- vexit = s->value;
-
- plan9_tos = S;
- if(HEADTYPE == Hplan9x32)
- plan9_tos = lookup("_tos", 0);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- if(HEADTYPE == Hwindows) {
- // Convert
- // op n(GS), reg
- // to
- // MOVL 0x14(FS), reg
- // op n(reg), reg
- // The purpose of this patch is to fix some accesses
- // to extern register variables (TLS) on Windows, as
- // a different method is used to access them.
- if(p->from.type == D_INDIR+D_GS
- && p->to.type >= D_AX && p->to.type <= D_DI) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x14;
- }
- }
- if(HEADTYPE == Hlinux) {
- // Running binaries under Xen requires using
- // MOVL 0(GS), reg
- // and then off(reg) instead of saying off(GS) directly
- // when the offset is negative.
- // In external mode we just produce a reloc.
- if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
- && p->to.type >= D_AX && p->to.type <= D_DI) {
- if(linkmode != LinkExternal) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0;
- } else {
- // Add signals to relocate.
- p->from.index = D_GS;
- p->from.scale = 1;
- }
- }
- }
- if(HEADTYPE == Hplan9x32) {
- if(p->from.type == D_INDIR+D_GS
- && p->to.type >= D_AX && p->to.type <= D_DI) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_EXTERN;
- p->from.sym = plan9_tos;
- p->from.offset = 0;
- }
- }
- if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
- s = p->to.sym;
- if(p->to.type == D_INDIR+D_ADDR) {
- /* skip check if this is an indirect call (CALL *symbol(SB)) */
- continue;
- } else if(s) {
- if(debug['c'])
- Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- if((s->type&SMASK) != STEXT) {
- /* diag prints TNAME first */
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- }
- if(s->text == nil)
- continue;
- p->to.type = D_BRANCH;
- p->to.offset = s->text->pc;
- p->pcond = s->text;
- continue;
- }
- }
- if(p->to.type != D_BRANCH)
- continue;
- c = p->to.offset;
- for(q = cursym->text; q != P;) {
- if(c == q->pc)
- break;
- if(q->forwd != P && c >= q->forwd->pc)
- q = q->forwd;
- else
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range in %s (%#ux)\n%P [%s]",
- TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
- p->to.type = D_NONE;
- }
- p->pcond = q;
- }
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->p != nil)
- continue;
-
- for(p = cursym->text; p != P; p = p->link) {
- p->mark = 0; /* initialization for follow */
- if(p->pcond != P) {
- p->pcond = brloop(p->pcond);
- if(p->pcond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->pcond->pc;
- }
- }
- }
-}
-
-Prog*
-brloop(Prog *p)
-{
- int c;
- Prog *q;
-
- c = 0;
- for(q = p; q != P; q = q->pcond) {
- if(q->as != AJMP)
- break;
- c++;
- if(c >= 5000)
- return P;
- }
- return q;
-}
-
-static Prog* load_g_cx(Prog*);
-static Prog* stacksplit(Prog*, int32, Prog**);
-
-static Sym *plan9_tos;
-static Prog *pmorestack;
-static Sym *symmorestack;
-
-void
-dostkoff(void)
-{
- Prog *p, *q;
- int32 autoffset, deltasp;
- int a;
-
- pmorestack = P;
- symmorestack = lookup("runtime.morestack", 0);
-
- if(symmorestack->type != STEXT)
- diag("runtime.morestack not defined");
- else {
- pmorestack = symmorestack->text;
- symmorestack->text->from.scale |= NOSPLIT;
- }
-
- plan9_tos = S;
- if(HEADTYPE == Hplan9x32)
- plan9_tos = lookup("_tos", 0);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->text->link == nil)
- continue;
-
- p = cursym->text;
- autoffset = p->to.offset;
- if(autoffset < 0)
- autoffset = 0;
-
- q = P;
-
- if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
- p = appendp(p);
- p = load_g_cx(p); // load g into CX
- }
- if(!(cursym->text->from.scale & NOSPLIT))
- p = stacksplit(p, autoffset, &q); // emit split check
-
- if(autoffset) {
- p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- p->spadj = autoffset;
- } else {
- // zero-byte stack adjustment.
- // Insert a fake non-zero adjustment so that stkcheck can
- // recognize the end of the stack-splitting prolog.
- p = appendp(p);
- p->as = ANOP;
- p->spadj = -PtrSize;
- p = appendp(p);
- p->as = ANOP;
- p->spadj = PtrSize;
- }
- if(q != P)
- q->pcond = p;
- deltasp = autoffset;
-
- if(cursym->text->from.scale & WRAPPER) {
- // g->panicwrap += autoffset + PtrSize;
- p = appendp(p);
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = autoffset + PtrSize;
- p->to.type = D_INDIR+D_CX;
- p->to.offset = 2*PtrSize;
- }
-
- if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
- // 8l -Z means zero the stack frame on entry.
- // This slows down function calls but can help avoid
- // false positives in garbage collection.
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_SP;
- p->to.type = D_DI;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = autoffset/4;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = 0;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = AREP;
-
- p = appendp(p);
- p->as = ASTOSL;
- }
-
- for(; p != P; p = p->link) {
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + 4;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + 4;
-
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- p->spadj = 4;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- p->spadj = 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- p->spadj = -4;
- continue;
- case APOPW:
- case APOPFW:
- deltasp -= 2;
- p->spadj = -2;
- continue;
- case ARET:
- break;
- }
-
- if(autoffset != deltasp)
- diag("unbalanced PUSH/POP");
-
- if(cursym->text->from.scale & WRAPPER) {
- p = load_g_cx(p);
- p = appendp(p);
- // g->panicwrap -= autoffset + PtrSize;
- p->as = ASUBL;
- p->from.type = D_CONST;
- p->from.offset = autoffset + PtrSize;
- p->to.type = D_INDIR+D_CX;
- p->to.offset = 2*PtrSize;
- p = appendp(p);
- p->as = ARET;
- }
-
- if(autoffset) {
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = -autoffset;
- p->spadj = -autoffset;
- p = appendp(p);
- p->as = ARET;
- // If there are instructions following
- // this ARET, they come from a branch
- // with the same stackframe, so undo
- // the cleanup.
- p->spadj = +autoffset;
- }
- if(p->to.sym) // retjmp
- p->as = AJMP;
- }
- }
-}
-
-// Append code to p to load g into cx.
-// Overwrites p with the first instruction (no first appendp).
-// Overwriting p is unusual but it lets use this in both the
-// prologue (caller must call appendp first) and in the epilogue.
-// Returns last new instruction.
-static Prog*
-load_g_cx(Prog *p)
-{
- switch(HEADTYPE) {
- case Hwindows:
- p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x14;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_CX;
- break;
-
- case Hlinux:
- if(linkmode != LinkExternal) {
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- } else {
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- p->from.index = D_GS;
- p->from.scale = 1;
- }
- break;
-
- case Hplan9x32:
- p->as = AMOVL;
- p->from.type = D_EXTERN;
- p->from.sym = plan9_tos;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- break;
-
- default:
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- }
- return p;
-}
-
-// Append code to p to check for stack split.
-// Appends to (does not overwrite) p.
-// Assumes g is in CX.
-// Returns last new instruction.
-// On return, *jmpok is the instruction that should jump
-// to the stack frame allocation if no split is needed.
-static Prog*
-stacksplit(Prog *p, int32 framesize, Prog **jmpok)
-{
- Prog *q, *q1;
- int arg;
-
- if(debug['K']) {
- // 8l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info.
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 4;
- p->to.type = D_SP;
-
- p = appendp(p);
- p->as = AJCC;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
-
- p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- }
- q1 = P;
-
- if(framesize <= StackSmall) {
- // small stack: SP <= stackguard
- // CMPL SP, stackguard
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_CX;
- } else if(framesize <= StackBig) {
- // large stack: SP-framesize <= stackguard-StackSmall
- // LEAL -(framesize-StackSmall)(SP), AX
- // CMPL AX, stackguard
- p = appendp(p);
- p->as = ALEAL;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(framesize-StackSmall);
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_CX;
- } else {
- // Such a large stack we need to protect against wraparound
- // if SP is close to zero.
- // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
- // The +StackGuard on both sides is required to keep the left side positive:
- // SP is allowed to be slightly below stackguard. See stack.h.
- //
- // Preemption sets stackguard to StackPreempt, a very large value.
- // That breaks the math above, so we have to check for that explicitly.
- // MOVL stackguard, CX
- // CMPL CX, $StackPreempt
- // JEQ label-of-call-to-morestack
- // LEAL StackGuard(SP), AX
- // SUBL stackguard, AX
- // CMPL AX, $(framesize+(StackGuard-StackSmall))
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_SI;
-
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_SI;
- p->to.type = D_CONST;
- p->to.offset = (uint32)StackPreempt;
-
- p = appendp(p);
- p->as = AJEQ;
- p->to.type = D_BRANCH;
- q1 = p;
-
- p = appendp(p);
- p->as = ALEAL;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = StackGuard;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ASUBL;
- p->from.type = D_SI;
- p->from.offset = 0;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_AX;
- p->to.type = D_CONST;
- p->to.offset = framesize+(StackGuard-StackSmall);
- }
-
- // common
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q = p;
-
- p = appendp(p); // save frame size in DI
- p->as = AMOVL;
- p->to.type = D_DI;
- p->from.type = D_CONST;
-
- // If we ask for more stack, we'll get a minimum of StackMin bytes.
- // We need a stack frame large enough to hold the top-of-stack data,
- // the function arguments+results, our caller's PC, our frame,
- // a word for the return PC of the next call, and then the StackLimit bytes
- // that must be available on entry to any function called from a function
- // that did a stack check. If StackMin is enough, don't ask for a specific
- // amount: then we can use the custom functions and save a few
- // instructions.
- if(StackTop + cursym->text->to.offset2 + PtrSize + framesize + PtrSize + StackLimit >= StackMin)
- p->from.offset = (framesize+7) & ~7LL;
-
- arg = cursym->text->to.offset2;
- if(arg == 1) // special marker for known 0
- arg = 0;
- if(arg&3)
- diag("misaligned argument size in stack split");
- p = appendp(p); // save arg size in AX
- p->as = AMOVL;
- p->to.type = D_AX;
- p->from.type = D_CONST;
- p->from.offset = arg;
-
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack;
- p->to.sym = symmorestack;
-
- p = appendp(p);
- p->as = AJMP;
- p->to.type = D_BRANCH;
- p->pcond = cursym->text->link;
-
- if(q != P)
- q->pcond = p->link;
- if(q1 != P)
- q1->pcond = q->link;
-
- *jmpok = q;
- return p;
-}
-
-int32
-atolwhex(char *s)
-{
- int32 n;
- int f;
-
- n = 0;
- f = 0;
- while(*s == ' ' || *s == '\t')
- s++;
- if(*s == '-' || *s == '+') {
- if(*s++ == '-')
- f = 1;
- while(*s == ' ' || *s == '\t')
- s++;
- }
- if(s[0]=='0' && s[1]){
- if(s[1]=='x' || s[1]=='X'){
- s += 2;
- for(;;){
- if(*s >= '0' && *s <= '9')
- n = n*16 + *s++ - '0';
- else if(*s >= 'a' && *s <= 'f')
- n = n*16 + *s++ - 'a' + 10;
- else if(*s >= 'A' && *s <= 'F')
- n = n*16 + *s++ - 'A' + 10;
- else
- break;
- }
- } else
- while(*s >= '0' && *s <= '7')
- n = n*8 + *s++ - '0';
- } else
- while(*s >= '0' && *s <= '9')
- n = n*10 + *s++ - '0';
- if(f)
- n = -n;
- return n;
-}
diff --git a/src/cmd/8l/prof.c b/src/cmd/8l/prof.c
deleted file mode 100644
index d99c5e408..000000000
--- a/src/cmd/8l/prof.c
+++ /dev/null
@@ -1,173 +0,0 @@
-// Inferno utils/8l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Profiling.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-doprof1(void)
-{
-#ifdef NOTDEF // TODO(rsc)
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->from.scale = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.sym = s;
- q->from.scale = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->size = n*4;
-#endif
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
-
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
-
- ps2 = P;
- ps4 = P;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- if(p->from.sym == s2) {
- p->from.scale = 1;
- ps2 = p;
- }
- if(p->from.sym == s4) {
- p->from.scale = 1;
- ps4 = p;
- }
- }
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
-
- if(p->from.scale & NOPROF) /* dont profile */
- continue;
-
- /*
- * JMPL profin
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = ps2;
- p->to.sym = s2;
-
- for(; p; p=p->link) {
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * JAL profout
- */
- p->as = ACALL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->pcond = ps4;
- p->to.sym = s4;
-
- p = q;
- }
- }
- }
-}
diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c
deleted file mode 100644
index acf973cab..000000000
--- a/src/cmd/8l/span.c
+++ /dev/null
@@ -1,1507 +0,0 @@
-// Inferno utils/8l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/span.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Instruction layout.
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/elf.h"
-
-static int32 vaddr(Adr*, Reloc*);
-
-void
-span1(Sym *s)
-{
- Prog *p, *q;
- int32 c, v, loop;
- uchar *bp;
- int n, m, i;
-
- cursym = s;
-
- for(p = s->text; p != P; p = p->link) {
- p->back = 2; // use short branches first time through
- if((q = p->pcond) != P && (q->back & 2))
- p->back |= 1; // backward jump
-
- if(p->as == AADJSP) {
- p->to.type = D_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = AADDL;
- if(v < 0) {
- p->as = ASUBL;
- v = -v;
- p->from.offset = v;
- }
- if(v == 0)
- p->as = ANOP;
- }
- }
-
- n = 0;
- do {
- loop = 0;
- memset(s->r, 0, s->nr*sizeof s->r[0]);
- s->nr = 0;
- s->np = 0;
- c = 0;
- for(p = s->text; p != P; p = p->link) {
- p->pc = c;
-
- // process forward jumps to p
- for(q = p->comefrom; q != P; q = q->forwd) {
- v = p->pc - (q->pc + q->mark);
- if(q->back & 2) { // short
- if(v > 127) {
- loop++;
- q->back ^= 2;
- }
- if(q->as == AJCXZW)
- s->p[q->pc+2] = v;
- else
- s->p[q->pc+1] = v;
- } else {
- bp = s->p + q->pc + q->mark - 4;
- *bp++ = v;
- *bp++ = v>>8;
- *bp++ = v>>16;
- *bp = v>>24;
- }
- }
- p->comefrom = P;
-
- asmins(p);
- p->pc = c;
- m = andptr-and;
- symgrow(s, p->pc+m);
- memmove(s->p+p->pc, and, m);
- p->mark = m;
- c += m;
- }
- if(++n > 20) {
- diag("span must be looping");
- errorexit();
- }
- } while(loop);
- s->size = c;
-
- if(debug['a'] > 1) {
- print("span1 %s %d (%d tries)\n %.6ux", s->name, s->size, n, 0);
- for(i=0; i<s->np; i++) {
- print(" %.2ux", s->p[i]);
- if(i%16 == 15)
- print("\n %.6ux", i+1);
- }
- if(i%16)
- print("\n");
-
- for(i=0; i<s->nr; i++) {
- Reloc *r;
-
- r = &s->r[i];
- print(" rel %#.4ux/%d %s%+d\n", r->off, r->siz, r->sym->name, r->add);
- }
- }
-}
-
-void
-span(void)
-{
- Prog *p, *q;
- int32 v;
- int n;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
-
- // NOTE(rsc): If we get rid of the globals we should
- // be able to parallelize these iterations.
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->text->link == nil)
- continue;
-
- // TODO: move into span1
- for(p = cursym->text; p != P; p = p->link) {
- n = 0;
- if(p->to.type == D_BRANCH)
- if(p->pcond == P)
- p->pcond = p;
- if((q = p->pcond) != P)
- if(q->back != 2)
- n = 1;
- p->back = n;
- if(p->as == AADJSP) {
- p->to.type = D_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = AADDL;
- if(v < 0) {
- p->as = ASUBL;
- v = -v;
- p->from.offset = v;
- }
- if(v == 0)
- p->as = ANOP;
- }
- }
- span1(cursym);
- }
-}
-
-void
-xdefine(char *p, int t, int32 v)
-{
- Sym *s;
-
- s = lookup(p, 0);
- s->type = t;
- s->value = v;
- s->reachable = 1;
- s->special = 1;
-}
-
-void
-instinit(void)
-{
- int i;
-
- for(i=1; optab[i].as; i++)
- if(i != optab[i].as) {
- diag("phase error in optab: at %A found %A", i, optab[i].as);
- errorexit();
- }
- maxop = i;
-
- for(i=0; i<Ymax; i++)
- ycover[i*Ymax + i] = 1;
-
- ycover[Yi0*Ymax + Yi8] = 1;
- ycover[Yi1*Ymax + Yi8] = 1;
-
- ycover[Yi0*Ymax + Yi32] = 1;
- ycover[Yi1*Ymax + Yi32] = 1;
- ycover[Yi8*Ymax + Yi32] = 1;
-
- ycover[Yal*Ymax + Yrb] = 1;
- ycover[Ycl*Ymax + Yrb] = 1;
- ycover[Yax*Ymax + Yrb] = 1;
- ycover[Ycx*Ymax + Yrb] = 1;
- ycover[Yrx*Ymax + Yrb] = 1;
-
- ycover[Yax*Ymax + Yrx] = 1;
- ycover[Ycx*Ymax + Yrx] = 1;
-
- ycover[Yax*Ymax + Yrl] = 1;
- ycover[Ycx*Ymax + Yrl] = 1;
- ycover[Yrx*Ymax + Yrl] = 1;
-
- ycover[Yf0*Ymax + Yrf] = 1;
-
- ycover[Yal*Ymax + Ymb] = 1;
- ycover[Ycl*Ymax + Ymb] = 1;
- ycover[Yax*Ymax + Ymb] = 1;
- ycover[Ycx*Ymax + Ymb] = 1;
- ycover[Yrx*Ymax + Ymb] = 1;
- ycover[Yrb*Ymax + Ymb] = 1;
- ycover[Ym*Ymax + Ymb] = 1;
-
- ycover[Yax*Ymax + Yml] = 1;
- ycover[Ycx*Ymax + Yml] = 1;
- ycover[Yrx*Ymax + Yml] = 1;
- ycover[Yrl*Ymax + Yml] = 1;
- ycover[Ym*Ymax + Yml] = 1;
-
- ycover[Yax*Ymax + Ymm] = 1;
- ycover[Ycx*Ymax + Ymm] = 1;
- ycover[Yrx*Ymax + Ymm] = 1;
- ycover[Yrl*Ymax + Ymm] = 1;
- ycover[Ym*Ymax + Ymm] = 1;
- ycover[Ymr*Ymax + Ymm] = 1;
-
- ycover[Ym*Ymax + Yxm] = 1;
- ycover[Yxr*Ymax + Yxm] = 1;
-
- for(i=0; i<D_NONE; i++) {
- reg[i] = -1;
- if(i >= D_AL && i <= D_BH)
- reg[i] = (i-D_AL) & 7;
- if(i >= D_AX && i <= D_DI)
- reg[i] = (i-D_AX) & 7;
- if(i >= D_F0 && i <= D_F0+7)
- reg[i] = (i-D_F0) & 7;
- if(i >= D_X0 && i <= D_X0+7)
- reg[i] = (i-D_X0) & 7;
- }
-}
-
-int
-prefixof(Adr *a)
-{
- switch(a->type) {
- case D_INDIR+D_CS:
- return 0x2e;
- case D_INDIR+D_DS:
- return 0x3e;
- case D_INDIR+D_ES:
- return 0x26;
- case D_INDIR+D_FS:
- return 0x64;
- case D_INDIR+D_GS:
- return 0x65;
- }
- return 0;
-}
-
-int
-oclass(Adr *a)
-{
- int32 v;
-
- if((a->type >= D_INDIR && a->type < 2*D_INDIR) || a->index != D_NONE) {
- if(a->index != D_NONE && a->scale == 0) {
- if(a->type == D_ADDR) {
- switch(a->index) {
- case D_EXTERN:
- case D_STATIC:
- return Yi32;
- case D_AUTO:
- case D_PARAM:
- return Yiauto;
- }
- return Yxxx;
- }
- //if(a->type == D_INDIR+D_ADDR)
- // print("*Ycol\n");
- return Ycol;
- }
- return Ym;
- }
- switch(a->type)
- {
- case D_AL:
- return Yal;
-
- case D_AX:
- return Yax;
-
- case D_CL:
- case D_DL:
- case D_BL:
- case D_AH:
- case D_CH:
- case D_DH:
- case D_BH:
- return Yrb;
-
- case D_CX:
- return Ycx;
-
- case D_DX:
- case D_BX:
- return Yrx;
-
- case D_SP:
- case D_BP:
- case D_SI:
- case D_DI:
- return Yrl;
-
- case D_F0+0:
- return Yf0;
-
- case D_F0+1:
- case D_F0+2:
- case D_F0+3:
- case D_F0+4:
- case D_F0+5:
- case D_F0+6:
- case D_F0+7:
- return Yrf;
-
- case D_X0+0:
- case D_X0+1:
- case D_X0+2:
- case D_X0+3:
- case D_X0+4:
- case D_X0+5:
- case D_X0+6:
- case D_X0+7:
- return Yxr;
-
- case D_NONE:
- return Ynone;
-
- case D_CS: return Ycs;
- case D_SS: return Yss;
- case D_DS: return Yds;
- case D_ES: return Yes;
- case D_FS: return Yfs;
- case D_GS: return Ygs;
-
- case D_GDTR: return Ygdtr;
- case D_IDTR: return Yidtr;
- case D_LDTR: return Yldtr;
- case D_MSW: return Ymsw;
- case D_TASK: return Ytask;
-
- case D_CR+0: return Ycr0;
- case D_CR+1: return Ycr1;
- case D_CR+2: return Ycr2;
- case D_CR+3: return Ycr3;
- case D_CR+4: return Ycr4;
- case D_CR+5: return Ycr5;
- case D_CR+6: return Ycr6;
- case D_CR+7: return Ycr7;
-
- case D_DR+0: return Ydr0;
- case D_DR+1: return Ydr1;
- case D_DR+2: return Ydr2;
- case D_DR+3: return Ydr3;
- case D_DR+4: return Ydr4;
- case D_DR+5: return Ydr5;
- case D_DR+6: return Ydr6;
- case D_DR+7: return Ydr7;
-
- case D_TR+0: return Ytr0;
- case D_TR+1: return Ytr1;
- case D_TR+2: return Ytr2;
- case D_TR+3: return Ytr3;
- case D_TR+4: return Ytr4;
- case D_TR+5: return Ytr5;
- case D_TR+6: return Ytr6;
- case D_TR+7: return Ytr7;
-
- case D_EXTERN:
- case D_STATIC:
- case D_AUTO:
- case D_PARAM:
- return Ym;
-
- case D_CONST:
- case D_CONST2:
- case D_ADDR:
- if(a->sym == S) {
- v = a->offset;
- if(v == 0)
- return Yi0;
- if(v == 1)
- return Yi1;
- if(v >= -128 && v <= 127)
- return Yi8;
- }
- return Yi32;
-
- case D_BRANCH:
- return Ybr;
- }
- return Yxxx;
-}
-
-void
-asmidx(int scale, int index, int base)
-{
- int i;
-
- switch(index) {
- default:
- goto bad;
-
- case D_NONE:
- i = 4 << 3;
- goto bas;
-
- case D_AX:
- case D_CX:
- case D_DX:
- case D_BX:
- case D_BP:
- case D_SI:
- case D_DI:
- i = reg[index] << 3;
- break;
- }
- switch(scale) {
- default:
- goto bad;
- case 1:
- break;
- case 2:
- i |= (1<<6);
- break;
- case 4:
- i |= (2<<6);
- break;
- case 8:
- i |= (3<<6);
- break;
- }
-bas:
- switch(base) {
- default:
- goto bad;
- case D_NONE: /* must be mod=00 */
- i |= 5;
- break;
- case D_AX:
- case D_CX:
- case D_DX:
- case D_BX:
- case D_SP:
- case D_BP:
- case D_SI:
- case D_DI:
- i |= reg[base];
- break;
- }
- *andptr++ = i;
- return;
-bad:
- diag("asmidx: bad address %d,%d,%d", scale, index, base);
- *andptr++ = 0;
- return;
-}
-
-static void
-put4(int32 v)
-{
- andptr[0] = v;
- andptr[1] = v>>8;
- andptr[2] = v>>16;
- andptr[3] = v>>24;
- andptr += 4;
-}
-
-static void
-relput4(Prog *p, Adr *a)
-{
- vlong v;
- Reloc rel, *r;
-
- v = vaddr(a, &rel);
- if(rel.siz != 0) {
- if(rel.siz != 4)
- diag("bad reloc");
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- put4(v);
-}
-
-int32
-symaddr(Sym *s)
-{
- if(!s->reachable)
- diag("unreachable symbol in symaddr - %s", s->name);
- return s->value;
-}
-
-static int32
-vaddr(Adr *a, Reloc *r)
-{
- int t;
- int32 v;
- Sym *s;
-
- if(r != nil)
- memset(r, 0, sizeof *r);
-
- t = a->type;
- v = a->offset;
- if(t == D_ADDR)
- t = a->index;
- switch(t) {
- case D_STATIC:
- case D_EXTERN:
- s = a->sym;
- if(s != nil) {
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- if(r == nil) {
- diag("need reloc for %D", a);
- errorexit();
- }
- r->type = D_ADDR;
- r->siz = 4;
- r->off = -1;
- r->sym = s;
- r->add = v;
- v = 0;
- }
- }
- return v;
-}
-
-static int
-istls(Adr *a)
-{
- if(HEADTYPE == Hlinux)
- return a->index == D_GS;
- return a->type == D_INDIR+D_GS;
-}
-
-void
-asmand(Adr *a, int r)
-{
- int32 v;
- int t, scale;
- Reloc rel;
-
- v = a->offset;
- t = a->type;
- rel.siz = 0;
- if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) {
- if(t < D_INDIR || t >= 2*D_INDIR) {
- switch(t) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- t = D_NONE;
- v = vaddr(a, &rel);
- break;
- case D_AUTO:
- case D_PARAM:
- t = D_SP;
- break;
- }
- } else
- t -= D_INDIR;
-
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- goto putrelv;
- }
- if(v == 0 && rel.siz == 0 && t != D_BP) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- goto putrelv;
- }
- if(t >= D_AL && t <= D_F7 || t >= D_X0 && t <= D_X7) {
- if(v)
- goto bad;
- *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
-
- scale = a->scale;
- if(t < D_INDIR || t >= 2*D_INDIR) {
- switch(a->type) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- t = D_NONE;
- v = vaddr(a, &rel);
- break;
- case D_AUTO:
- case D_PARAM:
- t = D_SP;
- break;
- }
- scale = 1;
- } else
- t -= D_INDIR;
-
- if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- goto putrelv;
- }
- if(t == D_SP) {
- if(v == 0 && rel.siz == 0) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- goto putrelv;
- }
- if(t >= D_AX && t <= D_DI) {
- if(v == 0 && rel.siz == 0 && t != D_BP) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0 && a->index != D_FS && a->index != D_GS) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- goto putrelv;
- }
- goto bad;
-
-putrelv:
- if(rel.siz != 0) {
- Reloc *r;
-
- if(rel.siz != 4) {
- diag("bad rel");
- goto bad;
- }
- r = addrel(cursym);
- *r = rel;
- r->off = curp->pc + andptr - and;
- } else if(iself && linkmode == LinkExternal && istls(a) && HEADTYPE != Hopenbsd) {
- Reloc *r;
- Sym *s;
-
- r = addrel(cursym);
- r->off = curp->pc + andptr - and;
- r->add = a->offset-tlsoffset;
- r->xadd = r->add;
- r->siz = 4;
- r->type = D_TLS;
- s = lookup("runtime.tlsgm", 0);
- r->sym = s;
- r->xsym = s;
- v = 0;
- }
-
- put4(v);
- return;
-
-bad:
- diag("asmand: bad address %D", a);
- return;
-}
-
-#define E 0xff
-uchar ymovtab[] =
-{
-/* push */
- APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0,
- APUSHL, Yss, Ynone, 0, 0x16,E,0,0,
- APUSHL, Yds, Ynone, 0, 0x1e,E,0,0,
- APUSHL, Yes, Ynone, 0, 0x06,E,0,0,
- APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0,
- APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0,
-
- APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0,
- APUSHW, Yss, Ynone, 0, Pe,0x16,E,0,
- APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0,
- APUSHW, Yes, Ynone, 0, Pe,0x06,E,0,
- APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E,
- APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E,
-
-/* pop */
- APOPL, Ynone, Yds, 0, 0x1f,E,0,0,
- APOPL, Ynone, Yes, 0, 0x07,E,0,0,
- APOPL, Ynone, Yss, 0, 0x17,E,0,0,
- APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0,
- APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0,
-
- APOPW, Ynone, Yds, 0, Pe,0x1f,E,0,
- APOPW, Ynone, Yes, 0, Pe,0x07,E,0,
- APOPW, Ynone, Yss, 0, Pe,0x17,E,0,
- APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E,
- APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E,
-
-/* mov seg */
- AMOVW, Yes, Yml, 1, 0x8c,0,0,0,
- AMOVW, Ycs, Yml, 1, 0x8c,1,0,0,
- AMOVW, Yss, Yml, 1, 0x8c,2,0,0,
- AMOVW, Yds, Yml, 1, 0x8c,3,0,0,
- AMOVW, Yfs, Yml, 1, 0x8c,4,0,0,
- AMOVW, Ygs, Yml, 1, 0x8c,5,0,0,
-
- AMOVW, Yml, Yes, 2, 0x8e,0,0,0,
- AMOVW, Yml, Ycs, 2, 0x8e,1,0,0,
- AMOVW, Yml, Yss, 2, 0x8e,2,0,0,
- AMOVW, Yml, Yds, 2, 0x8e,3,0,0,
- AMOVW, Yml, Yfs, 2, 0x8e,4,0,0,
- AMOVW, Yml, Ygs, 2, 0x8e,5,0,0,
-
-/* mov cr */
- AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0,
- AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0,
- AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0,
- AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0,
-
- AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0,
- AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0,
- AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0,
- AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0,
-
-/* mov dr */
- AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0,
- AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0,
- AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0,
-
- AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0,
- AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0,
- AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0,
-
-/* mov tr */
- AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0,
- AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0,
-
- AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E,
- AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E,
-
-/* lgdt, sgdt, lidt, sidt */
- AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0,
- AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0,
- AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0,
- AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0,
-
-/* lldt, sldt */
- AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0,
- AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0,
-
-/* lmsw, smsw */
- AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0,
- AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0,
-
-/* ltr, str */
- AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0,
- AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0,
-
-/* load full pointer */
- AMOVL, Yml, Ycol, 5, 0,0,0,0,
- AMOVW, Yml, Ycol, 5, Pe,0,0,0,
-
-/* double shift */
- ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0,
- ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0,
-
-/* extra imul */
- AIMULW, Yml, Yrl, 7, Pq,0xaf,0,0,
- AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0,
- 0
-};
-
-// byteswapreg returns a byte-addressable register (AX, BX, CX, DX)
-// which is not referenced in a->type.
-// If a is empty, it returns BX to account for MULB-like instructions
-// that might use DX and AX.
-int
-byteswapreg(Adr *a)
-{
- int cana, canb, canc, cand;
-
- cana = canb = canc = cand = 1;
-
- switch(a->type) {
- case D_NONE:
- cana = cand = 0;
- break;
- case D_AX:
- case D_AL:
- case D_AH:
- case D_INDIR+D_AX:
- cana = 0;
- break;
- case D_BX:
- case D_BL:
- case D_BH:
- case D_INDIR+D_BX:
- canb = 0;
- break;
- case D_CX:
- case D_CL:
- case D_CH:
- case D_INDIR+D_CX:
- canc = 0;
- break;
- case D_DX:
- case D_DL:
- case D_DH:
- case D_INDIR+D_DX:
- cand = 0;
- break;
- }
- switch(a->index) {
- case D_AX:
- cana = 0;
- break;
- case D_BX:
- canb = 0;
- break;
- case D_CX:
- canc = 0;
- break;
- case D_DX:
- cand = 0;
- break;
- }
- if(cana)
- return D_AX;
- if(canb)
- return D_BX;
- if(canc)
- return D_CX;
- if(cand)
- return D_DX;
-
- diag("impossible byte register");
- errorexit();
- return 0;
-}
-
-void
-subreg(Prog *p, int from, int to)
-{
-
- if(debug['Q'])
- print("\n%P s/%R/%R/\n", p, from, to);
-
- if(p->from.type == from) {
- p->from.type = to;
- p->ft = 0;
- }
- if(p->to.type == from) {
- p->to.type = to;
- p->tt = 0;
- }
-
- if(p->from.index == from) {
- p->from.index = to;
- p->ft = 0;
- }
- if(p->to.index == from) {
- p->to.index = to;
- p->tt = 0;
- }
-
- from += D_INDIR;
- if(p->from.type == from) {
- p->from.type = to+D_INDIR;
- p->ft = 0;
- }
- if(p->to.type == from) {
- p->to.type = to+D_INDIR;
- p->tt = 0;
- }
-
- if(debug['Q'])
- print("%P\n", p);
-}
-
-static int
-mediaop(Optab *o, int op, int osize, int z)
-{
- switch(op){
- case Pm:
- case Pe:
- case Pf2:
- case Pf3:
- if(osize != 1){
- if(op != Pm)
- *andptr++ = op;
- *andptr++ = Pm;
- op = o->op[++z];
- break;
- }
- default:
- if(andptr == and || andptr[-1] != Pm)
- *andptr++ = Pm;
- break;
- }
- *andptr++ = op;
- return z;
-}
-
-void
-doasm(Prog *p)
-{
- Optab *o;
- Prog *q, pp;
- uchar *t;
- int z, op, ft, tt, breg;
- int32 v, pre;
- Reloc rel, *r;
- Adr *a;
-
- curp = p; // TODO
-
- pre = prefixof(&p->from);
- if(pre)
- *andptr++ = pre;
- pre = prefixof(&p->to);
- if(pre)
- *andptr++ = pre;
-
- if(p->ft == 0)
- p->ft = oclass(&p->from);
- if(p->tt == 0)
- p->tt = oclass(&p->to);
-
- ft = p->ft * Ymax;
- tt = p->tt * Ymax;
- o = &optab[p->as];
- t = o->ytab;
- if(t == 0) {
- diag("asmins: noproto %P", p);
- return;
- }
- for(z=0; *t; z+=t[3],t+=4)
- if(ycover[ft+t[0]])
- if(ycover[tt+t[1]])
- goto found;
- goto domov;
-
-found:
- switch(o->prefix) {
- case Pq: /* 16 bit escape and opcode escape */
- *andptr++ = Pe;
- *andptr++ = Pm;
- break;
-
- case Pf2: /* xmm opcode escape */
- case Pf3:
- *andptr++ = o->prefix;
- *andptr++ = Pm;
- break;
-
- case Pm: /* opcode escape */
- *andptr++ = Pm;
- break;
-
- case Pe: /* 16 bit escape */
- *andptr++ = Pe;
- break;
-
- case Pb: /* botch */
- break;
- }
-
- op = o->op[z];
- switch(t[2]) {
- default:
- diag("asmins: unknown z %d %P", t[2], p);
- return;
-
- case Zpseudo:
- break;
-
- case Zlit:
- for(; op = o->op[z]; z++)
- *andptr++ = op;
- break;
-
- case Zlitm_r:
- for(; op = o->op[z]; z++)
- *andptr++ = op;
- asmand(&p->from, reg[p->to.type]);
- break;
-
- case Zm_r:
- *andptr++ = op;
- asmand(&p->from, reg[p->to.type]);
- break;
-
- case Zm2_r:
- *andptr++ = op;
- *andptr++ = o->op[z+1];
- asmand(&p->from, reg[p->to.type]);
- break;
-
- case Zm_r_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->from, reg[p->to.type]);
- break;
-
- case Zm_r_i_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->from, reg[p->to.type]);
- *andptr++ = p->to.offset;
- break;
-
- case Zibm_r:
- while ((op = o->op[z++]) != 0)
- *andptr++ = op;
- asmand(&p->from, reg[p->to.type]);
- *andptr++ = p->to.offset;
- break;
-
- case Zaut_r:
- *andptr++ = 0x8d; /* leal */
- if(p->from.type != D_ADDR)
- diag("asmins: Zaut sb type ADDR");
- p->from.type = p->from.index;
- p->from.index = D_NONE;
- p->ft = 0;
- asmand(&p->from, reg[p->to.type]);
- p->from.index = p->from.type;
- p->from.type = D_ADDR;
- p->ft = 0;
- break;
-
- case Zm_o:
- *andptr++ = op;
- asmand(&p->from, o->op[z+1]);
- break;
-
- case Zr_m:
- *andptr++ = op;
- asmand(&p->to, reg[p->from.type]);
- break;
-
- case Zr_m_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->to, reg[p->from.type]);
- break;
-
- case Zr_m_i_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->to, reg[p->from.type]);
- *andptr++ = p->from.offset;
- break;
-
- case Zo_m:
- *andptr++ = op;
- asmand(&p->to, o->op[z+1]);
- break;
-
- case Zm_ibo:
- *andptr++ = op;
- asmand(&p->from, o->op[z+1]);
- *andptr++ = vaddr(&p->to, nil);
- break;
-
- case Zibo_m:
- *andptr++ = op;
- asmand(&p->to, o->op[z+1]);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Z_ib:
- case Zib_:
- if(t[2] == Zib_)
- a = &p->from;
- else
- a = &p->to;
- v = vaddr(a, nil);
- *andptr++ = op;
- *andptr++ = v;
- break;
-
- case Zib_rp:
- *andptr++ = op + reg[p->to.type];
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Zil_rp:
- *andptr++ = op + reg[p->to.type];
- if(o->prefix == Pe) {
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, &p->from);
- break;
-
- case Zib_rr:
- *andptr++ = op;
- asmand(&p->to, reg[p->to.type]);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Z_il:
- case Zil_:
- if(t[2] == Zil_)
- a = &p->from;
- else
- a = &p->to;
- *andptr++ = op;
- if(o->prefix == Pe) {
- v = vaddr(a, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, a);
- break;
-
- case Zm_ilo:
- case Zilo_m:
- *andptr++ = op;
- if(t[2] == Zilo_m) {
- a = &p->from;
- asmand(&p->to, o->op[z+1]);
- } else {
- a = &p->to;
- asmand(&p->from, o->op[z+1]);
- }
- if(o->prefix == Pe) {
- v = vaddr(a, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, a);
- break;
-
- case Zil_rr:
- *andptr++ = op;
- asmand(&p->to, reg[p->to.type]);
- if(o->prefix == Pe) {
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, &p->from);
- break;
-
- case Z_rp:
- *andptr++ = op + reg[p->to.type];
- break;
-
- case Zrp_:
- *andptr++ = op + reg[p->from.type];
- break;
-
- case Zclr:
- *andptr++ = op;
- asmand(&p->to, reg[p->to.type]);
- break;
-
- case Zcall:
- q = p->pcond;
- if(q == nil) {
- diag("call without target");
- errorexit();
- }
- if(q->as != ATEXT) {
- // Could handle this case by making D_PCREL
- // record the Prog* instead of the Sym*, but let's
- // wait until the need arises.
- diag("call of non-TEXT %P", q);
- errorexit();
- }
- *andptr++ = op;
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->type = D_PCREL;
- r->siz = 4;
- r->sym = q->from.sym;
- put4(0);
- break;
-
- case Zbr:
- case Zjmp:
- case Zloop:
- q = p->pcond;
- if(q == nil) {
- diag("jmp/branch/loop without target");
- errorexit();
- }
- if(q->as == ATEXT) {
- // jump out of function
- if(t[2] == Zbr) {
- diag("branch to ATEXT");
- errorexit();
- }
- *andptr++ = o->op[z+1];
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->sym = q->from.sym;
- r->type = D_PCREL;
- r->siz = 4;
- put4(0);
- break;
- }
-
- // Assumes q is in this function.
- // TODO: Check in input, preserve in brchain.
-
- // Fill in backward jump now.
- if(p->back & 1) {
- v = q->pc - (p->pc + 2);
- if(v >= -128) {
- if(p->as == AJCXZW)
- *andptr++ = 0x67;
- *andptr++ = op;
- *andptr++ = v;
- } else if(t[2] == Zloop) {
- diag("loop too far: %P", p);
- } else {
- v -= 5-2;
- if(t[2] == Zbr) {
- *andptr++ = 0x0f;
- v--;
- }
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
- break;
- }
-
- // Annotate target; will fill in later.
- p->forwd = q->comefrom;
- q->comefrom = p;
- if(p->back & 2) { // short
- if(p->as == AJCXZW)
- *andptr++ = 0x67;
- *andptr++ = op;
- *andptr++ = 0;
- } else if(t[2] == Zloop) {
- diag("loop too far: %P", p);
- } else {
- if(t[2] == Zbr)
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *andptr++ = 0;
- *andptr++ = 0;
- *andptr++ = 0;
- *andptr++ = 0;
- }
- break;
-
- case Zcallcon:
- case Zjmpcon:
- if(t[2] == Zcallcon)
- *andptr++ = op;
- else
- *andptr++ = o->op[z+1];
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->type = D_PCREL;
- r->siz = 4;
- r->add = p->to.offset;
- put4(0);
- break;
-
- case Zcallind:
- *andptr++ = op;
- *andptr++ = o->op[z+1];
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->type = D_ADDR;
- r->siz = 4;
- r->add = p->to.offset;
- r->sym = p->to.sym;
- put4(0);
- break;
-
- case Zbyte:
- v = vaddr(&p->from, &rel);
- if(rel.siz != 0) {
- rel.siz = op;
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- *andptr++ = v;
- if(op > 1) {
- *andptr++ = v>>8;
- if(op > 2) {
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
- }
- break;
-
- case Zmov:
- goto domov;
- }
- return;
-
-domov:
- for(t=ymovtab; *t; t+=8)
- if(p->as == t[0])
- if(ycover[ft+t[1]])
- if(ycover[tt+t[2]])
- goto mfound;
-bad:
- /*
- * here, the assembly has failed.
- * if its a byte instruction that has
- * unaddressable registers, try to
- * exchange registers and reissue the
- * instruction with the operands renamed.
- */
- pp = *p;
- z = p->from.type;
- if(z >= D_BP && z <= D_DI) {
- if((breg = byteswapreg(&p->to)) != D_AX) {
- *andptr++ = 0x87; /* xchg lhs,bx */
- asmand(&p->from, reg[breg]);
- subreg(&pp, z, breg);
- doasm(&pp);
- *andptr++ = 0x87; /* xchg lhs,bx */
- asmand(&p->from, reg[breg]);
- } else {
- *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- subreg(&pp, z, D_AX);
- doasm(&pp);
- *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- }
- return;
- }
- z = p->to.type;
- if(z >= D_BP && z <= D_DI) {
- if((breg = byteswapreg(&p->from)) != D_AX) {
- *andptr++ = 0x87; /* xchg rhs,bx */
- asmand(&p->to, reg[breg]);
- subreg(&pp, z, breg);
- doasm(&pp);
- *andptr++ = 0x87; /* xchg rhs,bx */
- asmand(&p->to, reg[breg]);
- } else {
- *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- subreg(&pp, z, D_AX);
- doasm(&pp);
- *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- }
- return;
- }
- diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
- return;
-
-mfound:
- switch(t[3]) {
- default:
- diag("asmins: unknown mov %d %P", t[3], p);
- break;
-
- case 0: /* lit */
- for(z=4; t[z]!=E; z++)
- *andptr++ = t[z];
- break;
-
- case 1: /* r,m */
- *andptr++ = t[4];
- asmand(&p->to, t[5]);
- break;
-
- case 2: /* m,r */
- *andptr++ = t[4];
- asmand(&p->from, t[5]);
- break;
-
- case 3: /* r,m - 2op */
- *andptr++ = t[4];
- *andptr++ = t[5];
- asmand(&p->to, t[6]);
- break;
-
- case 4: /* m,r - 2op */
- *andptr++ = t[4];
- *andptr++ = t[5];
- asmand(&p->from, t[6]);
- break;
-
- case 5: /* load full pointer, trash heap */
- if(t[4])
- *andptr++ = t[4];
- switch(p->to.index) {
- default:
- goto bad;
- case D_DS:
- *andptr++ = 0xc5;
- break;
- case D_SS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb2;
- break;
- case D_ES:
- *andptr++ = 0xc4;
- break;
- case D_FS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb4;
- break;
- case D_GS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb5;
- break;
- }
- asmand(&p->from, reg[p->to.type]);
- break;
-
- case 6: /* double shift */
- z = p->from.type;
- switch(z) {
- default:
- goto bad;
- case D_CONST:
- *andptr++ = 0x0f;
- *andptr++ = t[4];
- asmand(&p->to, reg[p->from.index]);
- *andptr++ = p->from.offset;
- break;
- case D_CL:
- case D_CX:
- *andptr++ = 0x0f;
- *andptr++ = t[5];
- asmand(&p->to, reg[p->from.index]);
- break;
- }
- break;
-
- case 7: /* imul rm,r */
- if(t[4] == Pq) {
- *andptr++ = Pe;
- *andptr++ = Pm;
- } else
- *andptr++ = t[4];
- *andptr++ = t[5];
- asmand(&p->from, reg[p->to.type]);
- break;
- }
-}
-
-void
-asmins(Prog *p)
-{
- andptr = and;
- doasm(p);
- if(andptr > and+sizeof and) {
- print("and[] is too short - %ld byte instruction\n", andptr - and);
- errorexit();
- }
-}
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 30d7c8185..ac28041fb 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -38,15 +38,14 @@
#include "../../pkg/runtime/mgc0.h"
void dynreloc(void);
-static vlong addaddrplus4(Sym *s, Sym *t, vlong add);
/*
* divide-and-conquer list-link
- * sort of Sym* structures.
+ * sort of LSym* structures.
* Used for the data block.
*/
int
-datcmp(Sym *s1, Sym *s2)
+datcmp(LSym *s1, LSym *s2)
{
if(s1->type != s2->type)
return (int)s1->type - (int)s2->type;
@@ -58,11 +57,11 @@ datcmp(Sym *s1, Sym *s2)
return strcmp(s1->name, s2->name);
}
-Sym*
-listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off)
+LSym*
+listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off)
{
- Sym *l1, *l2, *le;
- #define NEXT(l) (*(Sym**)((char*)(l)+off))
+ LSym *l1, *l2, *le;
+ #define NEXT(l) (*(LSym**)((char*)(l)+off))
if(l == 0 || NEXT(l) == 0)
return l;
@@ -128,31 +127,17 @@ listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off)
#undef NEXT
}
-Reloc*
-addrel(Sym *s)
-{
- if(s->nr >= s->maxr) {
- if(s->maxr == 0)
- s->maxr = 4;
- else
- s->maxr <<= 1;
- s->r = erealloc(s->r, s->maxr*sizeof s->r[0]);
- memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
- }
- return &s->r[s->nr++];
-}
-
void
-relocsym(Sym *s)
+relocsym(LSym *s)
{
Reloc *r;
- Sym *rs;
+ LSym *rs;
Prog p;
int32 i, off, siz, fl;
vlong o;
uchar *cast;
- cursym = s;
+ ctxt->cursym = s;
memset(&p, 0, sizeof p);
for(r=s->r; r<s->r+s->nr; r++) {
r->done = 1;
@@ -218,7 +203,7 @@ relocsym(Sym *s)
break;
case D_PCREL:
// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
- if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != cursym->sect) {
+ if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != ctxt->cursym->sect) {
r->done = 0;
// set up addend for eventual relocation via outer symbol.
@@ -264,7 +249,7 @@ relocsym(Sym *s)
//print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "<nil>", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o);
switch(siz) {
default:
- cursym = s;
+ ctxt->cursym = s;
diag("bad reloc size %#ux for %s", siz, r->sym->name);
case 4:
if(r->type == D_PCREL) {
@@ -291,27 +276,27 @@ relocsym(Sym *s)
void
reloc(void)
{
- Sym *s;
+ LSym *s;
if(debug['v'])
Bprint(&bso, "%5.2f reloc\n", cputime());
Bflush(&bso);
- for(s=textp; s!=S; s=s->next)
+ for(s=ctxt->textp; s!=S; s=s->next)
relocsym(s);
for(s=datap; s!=S; s=s->next)
relocsym(s);
}
void
-dynrelocsym(Sym *s)
+dynrelocsym(LSym *s)
{
Reloc *r;
if(HEADTYPE == Hwindows) {
- Sym *rel, *targ;
+ LSym *rel, *targ;
- rel = lookup(".rel", 0);
+ rel = linklookup(ctxt, ".rel", 0);
if(s == rel)
return;
for(r=s->r; r<s->r+s->nr; r++) {
@@ -323,17 +308,17 @@ dynrelocsym(Sym *s)
// jmp *addr
if(thechar == '8') {
- adduint8(rel, 0xff);
- adduint8(rel, 0x25);
- addaddr(rel, targ);
- adduint8(rel, 0x90);
- adduint8(rel, 0x90);
+ adduint8(ctxt, rel, 0xff);
+ adduint8(ctxt, rel, 0x25);
+ addaddr(ctxt, rel, targ);
+ adduint8(ctxt, rel, 0x90);
+ adduint8(ctxt, rel, 0x90);
} else {
- adduint8(rel, 0xff);
- adduint8(rel, 0x24);
- adduint8(rel, 0x25);
- addaddrplus4(rel, targ, 0);
- adduint8(rel, 0x90);
+ adduint8(ctxt, rel, 0xff);
+ adduint8(ctxt, rel, 0x24);
+ adduint8(ctxt, rel, 0x25);
+ addaddrplus4(ctxt, rel, targ, 0);
+ adduint8(ctxt, rel, 0x90);
}
} else if(r->sym->plt >= 0) {
r->sym = rel;
@@ -352,7 +337,7 @@ dynrelocsym(Sym *s)
void
dynreloc(void)
{
- Sym *s;
+ LSym *s;
// -d suppresses dynamic loader format, so we may as well not
// compute these sections or mark their symbols as reachable.
@@ -362,7 +347,7 @@ dynreloc(void)
Bprint(&bso, "%5.2f reloc\n", cputime());
Bflush(&bso);
- for(s=textp; s!=S; s=s->next)
+ for(s=ctxt->textp; s!=S; s=s->next)
dynrelocsym(s);
for(s=datap; s!=S; s=s->next)
dynrelocsym(s);
@@ -370,118 +355,10 @@ dynreloc(void)
elfdynhash();
}
-void
-symgrow(Sym *s, int32 siz)
-{
- if(s->np >= siz)
- return;
-
- if(s->np > s->maxp) {
- cursym = s;
- diag("corrupt symbol data: np=%lld > maxp=%lld", (vlong)s->np, (vlong)s->maxp);
- errorexit();
- }
-
- if(s->maxp < siz) {
- if(s->maxp == 0)
- s->maxp = 8;
- while(s->maxp < siz)
- s->maxp <<= 1;
- s->p = erealloc(s->p, s->maxp);
- memset(s->p+s->np, 0, s->maxp-s->np);
- }
- s->np = siz;
-}
-
-void
-savedata(Sym *s, Prog *p, char *pn)
-{
- int32 off, siz, i, fl;
- uchar *cast;
- vlong o;
- Reloc *r;
-
- off = p->from.offset;
- siz = p->datasize;
- if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
- mangle(pn);
- symgrow(s, off+siz);
-
- switch(p->to.type) {
- default:
- diag("bad data: %P", p);
- break;
-
- case D_FCONST:
- switch(siz) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (uchar*)&fl;
- for(i=0; i<4; i++)
- s->p[off+i] = cast[fnuxi4[i]];
- break;
- case 8:
- cast = (uchar*)&p->to.ieee;
- for(i=0; i<8; i++)
- s->p[off+i] = cast[fnuxi8[i]];
- break;
- }
- break;
-
- case D_SCONST:
- for(i=0; i<siz; i++)
- s->p[off+i] = p->to.scon[i];
- break;
-
- case D_CONST:
- if(p->to.sym)
- goto Addr;
- o = p->to.offset;
- fl = o;
- cast = (uchar*)&fl;
- switch(siz) {
- default:
- diag("bad nuxi %d\n%P", siz, p);
- break;
- case 1:
- s->p[off] = cast[inuxi1[0]];
- break;
- case 2:
- for(i=0; i<2; i++)
- s->p[off+i] = cast[inuxi2[i]];
- break;
- case 4:
- for(i=0; i<4; i++)
- s->p[off+i] = cast[inuxi4[i]];
- break;
- case 8:
- cast = (uchar*)&o;
- for(i=0; i<8; i++)
- s->p[off+i] = cast[inuxi8[i]];
- break;
- }
- break;
-
- case D_ADDR:
- case D_SIZE:
- Addr:
- r = addrel(s);
- r->off = off;
- r->siz = siz;
- r->sym = p->to.sym;
- r->type = p->to.type;
- if(r->type != D_SIZE)
- r->type = D_ADDR;
- r->add = p->to.offset;
- break;
- }
-}
-
static void
-blk(Sym *start, int32 addr, int32 size)
+blk(LSym *start, int32 addr, int32 size)
{
- Sym *sym;
+ LSym *sym;
int32 eaddr;
uchar *p, *ep;
@@ -499,7 +376,7 @@ blk(Sym *start, int32 addr, int32 size)
diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type);
errorexit();
}
- cursym = sym;
+ ctxt->cursym = sym;
for(; addr < sym->value; addr++)
cput(0);
p = sym->p;
@@ -523,7 +400,7 @@ blk(Sym *start, int32 addr, int32 size)
void
codeblk(int32 addr, int32 size)
{
- Sym *sym;
+ LSym *sym;
int32 eaddr, n, epc;
Prog *p;
uchar *q;
@@ -531,13 +408,13 @@ codeblk(int32 addr, int32 size)
if(debug['a'])
Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
- blk(textp, addr, size);
+ blk(ctxt->textp, addr, size);
/* again for printing */
if(!debug['a'])
return;
- for(sym = textp; sym != nil; sym = sym->next) {
+ for(sym = ctxt->textp; sym != nil; sym = sym->next) {
if(!sym->reachable)
continue;
if(sym->value >= addr)
@@ -600,7 +477,7 @@ codeblk(int32 addr, int32 size)
void
datblk(int32 addr, int32 size)
{
- Sym *sym;
+ LSym *sym;
int32 i, eaddr;
uchar *p, *ep;
char *typ, *rsname;
@@ -682,28 +559,28 @@ strnput(char *s, int n)
void
addstrdata(char *name, char *value)
{
- Sym *s, *sp;
+ LSym *s, *sp;
char *p;
p = smprint("%s.str", name);
- sp = lookup(p, 0);
+ sp = linklookup(ctxt, p, 0);
free(p);
addstring(sp, value);
- s = lookup(name, 0);
+ s = linklookup(ctxt, name, 0);
s->size = 0;
s->dupok = 1;
- addaddr(s, sp);
- adduint32(s, strlen(value));
+ addaddr(ctxt, s, sp);
+ adduint32(ctxt, s, strlen(value));
if(PtrSize == 8)
- adduint32(s, 0); // round struct to pointer width
+ adduint32(ctxt, s, 0); // round struct to pointer width
// in case reachability has already been computed
sp->reachable = s->reachable;
}
vlong
-addstring(Sym *s, char *str)
+addstring(LSym *s, char *str)
{
int n;
int32 r;
@@ -715,230 +592,18 @@ addstring(Sym *s, char *str)
n = strlen(str)+1;
if(strcmp(s->name, ".shstrtab") == 0)
elfsetstring(str, r);
- symgrow(s, r+n);
+ symgrow(ctxt, s, r+n);
memmove(s->p+r, str, n);
s->size += n;
return r;
}
-vlong
-setuintxx(Sym *s, vlong off, uint64 v, vlong wid)
-{
- int32 i, fl;
- vlong o;
- uchar *cast;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- if(s->size < off+wid) {
- s->size = off+wid;
- symgrow(s, s->size);
- }
- fl = v;
- cast = (uchar*)&fl;
- switch(wid) {
- case 1:
- s->p[off] = cast[inuxi1[0]];
- break;
- case 2:
- for(i=0; i<2; i++)
- s->p[off+i] = cast[inuxi2[i]];
- break;
- case 4:
- for(i=0; i<4; i++)
- s->p[off+i] = cast[inuxi4[i]];
- break;
- case 8:
- o = v;
- cast = (uchar*)&o;
- for(i=0; i<8; i++)
- s->p[off+i] = cast[inuxi8[i]];
- break;
- }
- return off+wid;
-}
-
-vlong
-adduintxx(Sym *s, uint64 v, int wid)
-{
- vlong off;
-
- off = s->size;
- setuintxx(s, off, v, wid);
- return off;
-}
-
-vlong
-adduint8(Sym *s, uint8 v)
-{
- return adduintxx(s, v, 1);
-}
-
-vlong
-adduint16(Sym *s, uint16 v)
-{
- return adduintxx(s, v, 2);
-}
-
-vlong
-adduint32(Sym *s, uint32 v)
-{
- return adduintxx(s, v, 4);
-}
-
-vlong
-adduint64(Sym *s, uint64 v)
-{
- return adduintxx(s, v, 8);
-}
-
-vlong
-setuint8(Sym *s, vlong r, uint8 v)
-{
- return setuintxx(s, r, v, 1);
-}
-
-vlong
-setuint16(Sym *s, vlong r, uint16 v)
-{
- return setuintxx(s, r, v, 2);
-}
-
-vlong
-setuint32(Sym *s, vlong r, uint32 v)
-{
- return setuintxx(s, r, v, 4);
-}
-
-vlong
-setuint64(Sym *s, vlong r, uint64 v)
-{
- return setuintxx(s, r, v, 8);
-}
-
-vlong
-addaddrplus(Sym *s, Sym *t, vlong add)
-{
- vlong i;
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- i = s->size;
- s->size += PtrSize;
- symgrow(s, s->size);
- r = addrel(s);
- r->sym = t;
- r->off = i;
- r->siz = PtrSize;
- r->type = D_ADDR;
- r->add = add;
- return i + r->siz;
-}
-
-static vlong
-addaddrplus4(Sym *s, Sym *t, vlong add)
-{
- vlong i;
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- i = s->size;
- s->size += 4;
- symgrow(s, s->size);
- r = addrel(s);
- r->sym = t;
- r->off = i;
- r->siz = 4;
- r->type = D_ADDR;
- r->add = add;
- return i + r->siz;
-}
-
-vlong
-addpcrelplus(Sym *s, Sym *t, vlong add)
-{
- vlong i;
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- i = s->size;
- s->size += 4;
- symgrow(s, s->size);
- r = addrel(s);
- r->sym = t;
- r->off = i;
- r->add = add;
- r->type = D_PCREL;
- r->siz = 4;
- return i + r->siz;
-}
-
-vlong
-addaddr(Sym *s, Sym *t)
-{
- return addaddrplus(s, t, 0);
-}
-
-vlong
-setaddrplus(Sym *s, vlong off, Sym *t, vlong add)
-{
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- if(off+PtrSize > s->size) {
- s->size = off + PtrSize;
- symgrow(s, s->size);
- }
- r = addrel(s);
- r->sym = t;
- r->off = off;
- r->siz = PtrSize;
- r->type = D_ADDR;
- r->add = add;
- return off + r->siz;
-}
-
-vlong
-setaddr(Sym *s, vlong off, Sym *t)
-{
- return setaddrplus(s, off, t, 0);
-}
-
-vlong
-addsize(Sym *s, Sym *t)
-{
- vlong i;
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- i = s->size;
- s->size += PtrSize;
- symgrow(s, s->size);
- r = addrel(s);
- r->sym = t;
- r->off = i;
- r->siz = PtrSize;
- r->type = D_SIZE;
- return i + r->siz;
-}
-
void
dosymtype(void)
{
- Sym *s;
+ LSym *s;
- for(s = allsym; s != nil; s = s->allsym) {
+ for(s = ctxt->allsym; s != nil; s = s->allsym) {
if(s->np > 0) {
if(s->type == SBSS)
s->type = SDATA;
@@ -949,7 +614,7 @@ dosymtype(void)
}
static int32
-symalign(Sym *s)
+symalign(LSym *s)
{
int32 align;
@@ -965,7 +630,7 @@ symalign(Sym *s)
}
static vlong
-aligndatsize(vlong datsize, Sym *s)
+aligndatsize(vlong datsize, LSym *s)
{
return rnd(datsize, symalign(s));
}
@@ -973,7 +638,7 @@ aligndatsize(vlong datsize, Sym *s)
// maxalign returns the maximum required alignment for
// the list of symbols s; the list stops when s->type exceeds type.
static int32
-maxalign(Sym *s, int type)
+maxalign(LSym *s, int type)
{
int32 align, max;
@@ -987,10 +652,10 @@ maxalign(Sym *s, int type)
}
static void
-gcaddsym(Sym *gc, Sym *s, vlong off)
+gcaddsym(LSym *gc, LSym *s, vlong off)
{
vlong a;
- Sym *gotype;
+ LSym *gotype;
if(s->size < PtrSize)
return;
@@ -1000,22 +665,22 @@ gcaddsym(Sym *gc, Sym *s, vlong off)
gotype = s->gotype;
if(gotype != nil) {
//print("gcaddsym: %s %d %s\n", s->name, s->size, gotype->name);
- adduintxx(gc, GC_CALL, PtrSize);
- adduintxx(gc, off, PtrSize);
- addpcrelplus(gc, decodetype_gc(gotype), 3*PtrSize+4);
+ adduintxx(ctxt, gc, GC_CALL, PtrSize);
+ adduintxx(ctxt, gc, off, PtrSize);
+ addpcrelplus(ctxt, gc, decodetype_gc(gotype), 3*PtrSize+4);
if(PtrSize == 8)
- adduintxx(gc, 0, 4);
+ adduintxx(ctxt, gc, 0, 4);
} else {
//print("gcaddsym: %s %d <unknown type>\n", s->name, s->size);
for(a = -off&(PtrSize-1); a+PtrSize<=s->size; a+=PtrSize) {
- adduintxx(gc, GC_APTR, PtrSize);
- adduintxx(gc, off+a, PtrSize);
+ adduintxx(ctxt, gc, GC_APTR, PtrSize);
+ adduintxx(ctxt, gc, off+a, PtrSize);
}
}
}
void
-growdatsize(vlong *datsizep, Sym *s)
+growdatsize(vlong *datsizep, LSym *s)
{
vlong datsize;
@@ -1034,24 +699,24 @@ dodata(void)
vlong datsize;
Section *sect;
Segment *segro;
- Sym *s, *last, **l;
- Sym *gcdata1, *gcbss1;
+ LSym *s, *last, **l;
+ LSym *gcdata1, *gcbss1;
if(debug['v'])
Bprint(&bso, "%5.2f dodata\n", cputime());
Bflush(&bso);
- gcdata1 = lookup("gcdata", 0);
- gcbss1 = lookup("gcbss", 0);
+ gcdata1 = linklookup(ctxt, "gcdata", 0);
+ gcbss1 = linklookup(ctxt, "gcbss", 0);
// size of .data and .bss section. the zero value is later replaced by the actual size of the section.
- adduintxx(gcdata1, 0, PtrSize);
- adduintxx(gcbss1, 0, PtrSize);
+ adduintxx(ctxt, gcdata1, 0, PtrSize);
+ adduintxx(ctxt, gcbss1, 0, PtrSize);
last = nil;
datap = nil;
- for(s=allsym; s!=S; s=s->allsym) {
+ for(s=ctxt->allsym; s!=S; s=s->allsym) {
if(!s->reachable || s->special)
continue;
if(STEXT < s->type && s->type < SXREF) {
@@ -1092,7 +757,7 @@ dodata(void)
}
*l = nil;
- datap = listsort(datap, datcmp, offsetof(Sym, next));
+ datap = listsort(datap, datcmp, offsetof(LSym, next));
/*
* allocate sections. list is sorted by type,
@@ -1128,8 +793,8 @@ dodata(void)
sect->align = maxalign(s, SINITARR-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("noptrdata", 0)->sect = sect;
- lookup("enoptrdata", 0)->sect = sect;
+ linklookup(ctxt, "noptrdata", 0)->sect = sect;
+ linklookup(ctxt, "enoptrdata", 0)->sect = sect;
for(; s != nil && s->type < SINITARR; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1159,11 +824,11 @@ dodata(void)
sect->align = maxalign(s, SBSS-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("data", 0)->sect = sect;
- lookup("edata", 0)->sect = sect;
+ linklookup(ctxt, "data", 0)->sect = sect;
+ linklookup(ctxt, "edata", 0)->sect = sect;
for(; s != nil && s->type < SBSS; s = s->next) {
if(s->type == SINITARR) {
- cursym = s;
+ ctxt->cursym = s;
diag("unexpected symbol type %d", s->type);
}
s->sect = sect;
@@ -1175,16 +840,16 @@ dodata(void)
}
sect->len = datsize - sect->vaddr;
- adduintxx(gcdata1, GC_END, PtrSize);
- setuintxx(gcdata1, 0, sect->len, PtrSize);
+ adduintxx(ctxt, gcdata1, GC_END, PtrSize);
+ setuintxx(ctxt, gcdata1, 0, sect->len, PtrSize);
/* bss */
sect = addsection(&segdata, ".bss", 06);
sect->align = maxalign(s, SNOPTRBSS-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("bss", 0)->sect = sect;
- lookup("ebss", 0)->sect = sect;
+ linklookup(ctxt, "bss", 0)->sect = sect;
+ linklookup(ctxt, "ebss", 0)->sect = sect;
for(; s != nil && s->type < SNOPTRBSS; s = s->next) {
s->sect = sect;
datsize = aligndatsize(datsize, s);
@@ -1194,16 +859,16 @@ dodata(void)
}
sect->len = datsize - sect->vaddr;
- adduintxx(gcbss1, GC_END, PtrSize);
- setuintxx(gcbss1, 0, sect->len, PtrSize);
+ adduintxx(ctxt, gcbss1, GC_END, PtrSize);
+ setuintxx(ctxt, gcbss1, 0, sect->len, PtrSize);
/* pointer-free bss */
sect = addsection(&segdata, ".noptrbss", 06);
sect->align = maxalign(s, SNOPTRBSS);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("noptrbss", 0)->sect = sect;
- lookup("enoptrbss", 0)->sect = sect;
+ linklookup(ctxt, "noptrbss", 0)->sect = sect;
+ linklookup(ctxt, "enoptrbss", 0)->sect = sect;
for(; s != nil && s->type == SNOPTRBSS; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1211,7 +876,7 @@ dodata(void)
growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
- lookup("end", 0)->sect = sect;
+ linklookup(ctxt, "end", 0)->sect = sect;
// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
if(datsize != (uint32)datsize) {
@@ -1233,7 +898,7 @@ dodata(void)
}
if(s != nil) {
- cursym = nil;
+ ctxt->cursym = nil;
diag("unexpected symbol type %d for %s", s->type, s->name);
}
@@ -1274,8 +939,8 @@ dodata(void)
sect->align = maxalign(s, STYPELINK-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = 0;
- lookup("rodata", 0)->sect = sect;
- lookup("erodata", 0)->sect = sect;
+ linklookup(ctxt, "rodata", 0)->sect = sect;
+ linklookup(ctxt, "erodata", 0)->sect = sect;
for(; s != nil && s->type < STYPELINK; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1290,8 +955,8 @@ dodata(void)
sect->align = maxalign(s, STYPELINK);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("typelink", 0)->sect = sect;
- lookup("etypelink", 0)->sect = sect;
+ linklookup(ctxt, "typelink", 0)->sect = sect;
+ linklookup(ctxt, "etypelink", 0)->sect = sect;
for(; s != nil && s->type == STYPELINK; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1306,8 +971,8 @@ dodata(void)
sect->align = maxalign(s, SPCLNTAB-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("symtab", 0)->sect = sect;
- lookup("esymtab", 0)->sect = sect;
+ linklookup(ctxt, "symtab", 0)->sect = sect;
+ linklookup(ctxt, "esymtab", 0)->sect = sect;
for(; s != nil && s->type < SPCLNTAB; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1322,8 +987,8 @@ dodata(void)
sect->align = maxalign(s, SELFROSECT-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("pclntab", 0)->sect = sect;
- lookup("epclntab", 0)->sect = sect;
+ linklookup(ctxt, "pclntab", 0)->sect = sect;
+ linklookup(ctxt, "epclntab", 0)->sect = sect;
for(; s != nil && s->type < SELFROSECT; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1368,7 +1033,7 @@ textaddress(void)
uvlong va;
Prog *p;
Section *sect;
- Sym *sym, *sub;
+ LSym *sym, *sub;
addsection(&segtext, ".text", 05);
@@ -1377,11 +1042,11 @@ textaddress(void)
// and then letting threads copy down, but probably not worth it.
sect = segtext.sect;
sect->align = FuncAlign;
- lookup("text", 0)->sect = sect;
- lookup("etext", 0)->sect = sect;
+ linklookup(ctxt, "text", 0)->sect = sect;
+ linklookup(ctxt, "etext", 0)->sect = sect;
va = INITTEXT;
sect->vaddr = va;
- for(sym = textp; sym != nil; sym = sym->next) {
+ for(sym = ctxt->textp; sym != nil; sym = sym->next) {
sym->sect = sect;
if(sym->type & SSUB)
continue;
@@ -1396,7 +1061,7 @@ textaddress(void)
p->pc += sub->value;
}
if(sym->size == 0 && sym->sub != S) {
- cursym = sym;
+ ctxt->cursym = sym;
}
va += sym->size;
}
@@ -1409,7 +1074,7 @@ address(void)
{
Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss;
Section *typelink;
- Sym *sym, *sub;
+ LSym *sym, *sub;
uvlong va;
vlong vlen;
@@ -1451,7 +1116,7 @@ address(void)
segdata.filelen = 0;
if(HEADTYPE == Hwindows)
segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
- if(HEADTYPE == Hplan9x64 || HEADTYPE == Hplan9x32)
+ if(HEADTYPE == Hplan9)
segdata.fileoff = segtext.fileoff + segtext.filelen;
data = nil;
noptr = nil;
@@ -1485,7 +1150,7 @@ address(void)
pclntab = symtab->next;
for(sym = datap; sym != nil; sym = sym->next) {
- cursym = sym;
+ ctxt->cursym = sym;
sym->value += sym->sect->vaddr;
for(sub = sym->sub; sub != nil; sub = sub->sub)
sub->value += sym->value;
@@ -1498,13 +1163,13 @@ address(void)
xdefine("typelink", SRODATA, typelink->vaddr);
xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len);
- sym = lookup("gcdata", 0);
+ sym = linklookup(ctxt, "gcdata", 0);
xdefine("egcdata", SRODATA, symaddr(sym) + sym->size);
- lookup("egcdata", 0)->sect = sym->sect;
+ linklookup(ctxt, "egcdata", 0)->sect = sym->sect;
- sym = lookup("gcbss", 0);
+ sym = linklookup(ctxt, "gcbss", 0);
xdefine("egcbss", SRODATA, symaddr(sym) + sym->size);
- lookup("egcbss", 0)->sect = sym->sect;
+ linklookup(ctxt, "egcbss", 0)->sect = sym->sect;
xdefine("symtab", SRODATA, symtab->vaddr);
xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len);
diff --git a/src/cmd/ld/decodesym.c b/src/cmd/ld/decodesym.c
index ab3f4fbd5..3859d1c6d 100644
--- a/src/cmd/ld/decodesym.c
+++ b/src/cmd/ld/decodesym.c
@@ -11,7 +11,7 @@
// ../gc/reflect.c stuffs in these.
static Reloc*
-decode_reloc(Sym *s, int32 off)
+decode_reloc(LSym *s, int32 off)
{
int i;
@@ -21,8 +21,8 @@ decode_reloc(Sym *s, int32 off)
return nil;
}
-static Sym*
-decode_reloc_sym(Sym *s, int32 off)
+static LSym*
+decode_reloc_sym(LSym *s, int32 off)
{
Reloc *r;
@@ -69,86 +69,86 @@ decode_inuxi(uchar* p, int sz)
// Type.commonType.kind
uint8
-decodetype_kind(Sym *s)
+decodetype_kind(LSym *s)
{
return s->p[1*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f
}
// Type.commonType.size
vlong
-decodetype_size(Sym *s)
+decodetype_size(LSym *s)
{
return decode_inuxi(s->p, PtrSize); // 0x8 / 0x10
}
// Type.commonType.gc
-Sym*
-decodetype_gc(Sym *s)
+LSym*
+decodetype_gc(LSym *s)
{
return decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize);
}
// Type.ArrayType.elem and Type.SliceType.Elem
-Sym*
-decodetype_arrayelem(Sym *s)
+LSym*
+decodetype_arrayelem(LSym *s)
{
return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
}
vlong
-decodetype_arraylen(Sym *s)
+decodetype_arraylen(LSym *s)
{
return decode_inuxi(s->p + CommonSize+PtrSize, PtrSize);
}
// Type.PtrType.elem
-Sym*
-decodetype_ptrelem(Sym *s)
+LSym*
+decodetype_ptrelem(LSym *s)
{
return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
}
// Type.MapType.key, elem
-Sym*
-decodetype_mapkey(Sym *s)
+LSym*
+decodetype_mapkey(LSym *s)
{
return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
}
-Sym*
-decodetype_mapvalue(Sym *s)
+LSym*
+decodetype_mapvalue(LSym *s)
{
return decode_reloc_sym(s, CommonSize+PtrSize); // 0x20 / 0x38
}
// Type.ChanType.elem
-Sym*
-decodetype_chanelem(Sym *s)
+LSym*
+decodetype_chanelem(LSym *s)
{
return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
}
// Type.FuncType.dotdotdot
int
-decodetype_funcdotdotdot(Sym *s)
+decodetype_funcdotdotdot(LSym *s)
{
return s->p[CommonSize];
}
// Type.FuncType.in.len
int
-decodetype_funcincount(Sym *s)
+decodetype_funcincount(LSym *s)
{
return decode_inuxi(s->p + CommonSize+2*PtrSize, IntSize);
}
int
-decodetype_funcoutcount(Sym *s)
+decodetype_funcoutcount(LSym *s)
{
return decode_inuxi(s->p + CommonSize+3*PtrSize + 2*IntSize, IntSize);
}
-Sym*
-decodetype_funcintype(Sym *s, int i)
+LSym*
+decodetype_funcintype(LSym *s, int i)
{
Reloc *r;
@@ -158,8 +158,8 @@ decodetype_funcintype(Sym *s, int i)
return decode_reloc_sym(r->sym, r->add + i * PtrSize);
}
-Sym*
-decodetype_funcouttype(Sym *s, int i)
+LSym*
+decodetype_funcouttype(LSym *s, int i)
{
Reloc *r;
@@ -171,7 +171,7 @@ decodetype_funcouttype(Sym *s, int i)
// Type.StructType.fields.Slice::len
int
-decodetype_structfieldcount(Sym *s)
+decodetype_structfieldcount(LSym *s)
{
return decode_inuxi(s->p + CommonSize + PtrSize, IntSize);
}
@@ -181,7 +181,7 @@ enum {
};
// Type.StructType.fields[]-> name, typ and offset.
char*
-decodetype_structfieldname(Sym *s, int i)
+decodetype_structfieldname(LSym *s, int i)
{
Reloc *r;
@@ -195,21 +195,21 @@ decodetype_structfieldname(Sym *s, int i)
return (char*) r->sym->p + r->add; // the c-string
}
-Sym*
-decodetype_structfieldtype(Sym *s, int i)
+LSym*
+decodetype_structfieldtype(LSym *s, int i)
{
return decode_reloc_sym(s, CommonSize + PtrSize + 2*IntSize + i*StructFieldSize + 2*PtrSize);
}
vlong
-decodetype_structfieldoffs(Sym *s, int i)
+decodetype_structfieldoffs(LSym *s, int i)
{
return decode_inuxi(s->p + CommonSize + PtrSize + 2*IntSize + i*StructFieldSize + 4*PtrSize, IntSize);
}
// InterfaceTYpe.methods.len
vlong
-decodetype_ifacemethodcount(Sym *s)
+decodetype_ifacemethodcount(LSym *s)
{
return decode_inuxi(s->p + CommonSize + PtrSize, IntSize);
}
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index c832bcc94..8170abe33 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -27,19 +27,19 @@
static vlong abbrevo;
static vlong abbrevsize;
-static Sym* abbrevsym;
+static LSym* abbrevsym;
static vlong abbrevsympos;
static vlong lineo;
static vlong linesize;
-static Sym* linesym;
+static LSym* linesym;
static vlong linesympos;
static vlong infoo; // also the base for DWDie->offs and reference attributes.
static vlong infosize;
-static Sym* infosym;
+static LSym* infosym;
static vlong infosympos;
static vlong frameo;
static vlong framesize;
-static Sym* framesym;
+static LSym* framesym;
static vlong framesympos;
static vlong pubnameso;
static vlong pubnamessize;
@@ -50,19 +50,19 @@ static vlong arangessize;
static vlong gdbscripto;
static vlong gdbscriptsize;
-static Sym *infosec;
+static LSym *infosec;
static vlong inforeloco;
static vlong inforelocsize;
-static Sym *arangessec;
+static LSym *arangessec;
static vlong arangesreloco;
static vlong arangesrelocsize;
-static Sym *linesec;
+static LSym *linesec;
static vlong linereloco;
static vlong linerelocsize;
-static Sym *framesec;
+static LSym *framesec;
static vlong framereloco;
static vlong framerelocsize;
@@ -594,7 +594,7 @@ find_or_diag(DWDie *die, char* name)
}
static void
-adddwarfrel(Sym* sec, Sym* sym, vlong offsetbase, int siz, vlong addend)
+adddwarfrel(LSym* sec, LSym* sym, vlong offsetbase, int siz, vlong addend)
{
Reloc *r;
@@ -639,8 +639,8 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
switch(form) {
case DW_FORM_addr: // address
if(linkmode == LinkExternal) {
- value -= ((Sym*)data)->value;
- adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value);
+ value -= ((LSym*)data)->value;
+ adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
break;
}
addrput(value);
@@ -651,8 +651,8 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
cput(1+PtrSize);
cput(DW_OP_addr);
if(linkmode == LinkExternal) {
- value -= ((Sym*)data)->value;
- adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value);
+ value -= ((LSym*)data)->value;
+ adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
break;
}
addrput(value);
@@ -847,7 +847,7 @@ newmemberoffsetattr(DWDie *die, int32 offs)
// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
// location expression that evals to a const.
static void
-newabslocexprattr(DWDie *die, vlong addr, Sym *sym)
+newabslocexprattr(DWDie *die, vlong addr, LSym *sym)
{
newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, (char*)sym);
}
@@ -864,12 +864,12 @@ enum {
static DWDie* defptrto(DWDie *dwtype); // below
// Lookup predefined types
-static Sym*
+static LSym*
lookup_or_diag(char *n)
{
- Sym *s;
+ LSym *s;
- s = rlookup(n, 0);
+ s = linkrlookup(ctxt, n, 0);
if (s == nil || s->size == 0) {
diag("dwarf: missing type: %s", n);
errorexit();
@@ -904,10 +904,10 @@ dotypedef(DWDie *parent, char *name, DWDie *def)
// Define gotype, for composite ones recurse into constituents.
static DWDie*
-defgotype(Sym *gotype)
+defgotype(LSym *gotype)
{
DWDie *die, *fld;
- Sym *s;
+ LSym *s;
char *name, *f;
uint8 kind;
vlong bytesize;
@@ -1335,7 +1335,7 @@ synthesizechantypes(DWDie *die)
// For use with pass.c::genasmsym
static void
-defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
+defdwsymb(LSym* sym, char *s, int t, vlong v, vlong size, int ver, LSym *gotype)
{
DWDie *dv, *dt;
@@ -1607,7 +1607,7 @@ inithist(Auto *a)
absline = a->aoffset;
} else if (a->type == D_FILE1) { // 'Z'
// We could just fixup the current
- // linehist->line, but there doesn't appear to
+ // linehist->lineno, but there doesn't appear to
// be a guarantee that every 'Z' is preceded
// by its own 'z', so do the safe thing and
// update the stack and push a new Linehist
@@ -1719,7 +1719,7 @@ mkvarname(char* name, int da)
// flush previous compilation unit.
static void
-flushunit(DWDie *dwinfo, vlong pc, Sym *pcsym, vlong unitstart, int32 header_length)
+flushunit(DWDie *dwinfo, vlong pc, LSym *pcsym, vlong unitstart, int32 header_length)
{
vlong here;
@@ -1745,7 +1745,7 @@ static void
writelines(void)
{
Prog *q;
- Sym *s, *epcs;
+ LSym *s, *epcs;
Auto *a;
vlong unitstart, headerend, offs;
vlong pc, epc, lc, llc, lline;
@@ -1757,7 +1757,7 @@ writelines(void)
char *n, *nn;
if(linesec == S)
- linesec = lookup(".dwarfline", 0);
+ linesec = linklookup(ctxt, ".dwarfline", 0);
linesec->nr = 0;
unitstart = -1;
@@ -1771,8 +1771,8 @@ writelines(void)
lineo = cpos();
dwinfo = nil;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- s = cursym;
+ for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
+ s = ctxt->cursym;
if(s->text == P)
continue;
@@ -1859,7 +1859,7 @@ writelines(void)
continue;
for(q = s->text; q != P; q = q->link) {
- lh = searchhist(q->line);
+ lh = searchhist(q->lineno);
if (lh == nil) {
diag("dwarf: corrupt history or bad absolute line: %P", q);
continue;
@@ -1870,11 +1870,11 @@ writelines(void)
continue;
}
- lline = lh->line + q->line - lh->absline;
+ lline = lh->line + q->lineno - lh->absline;
if (debug['v'] > 1)
print("%6llux %s[%lld] %P\n", (vlong)q->pc, histfile[lh->file], lline, q);
- if (q->line == lc)
+ if (q->lineno == lc)
continue;
if (currfile != lh->file) {
currfile = lh->file;
@@ -1883,7 +1883,7 @@ writelines(void)
}
putpclcdelta(q->pc - pc, lline - llc);
pc = q->pc;
- lc = q->line;
+ lc = q->lineno;
llc = lline;
}
@@ -1971,11 +1971,11 @@ static void
writeframes(void)
{
Prog *p, *q;
- Sym *s;
+ LSym *s;
vlong fdeo, fdesize, pad, cfa, pc;
if(framesec == S)
- framesec = lookup(".dwarfframe", 0);
+ framesec = linklookup(ctxt, ".dwarfframe", 0);
framesec->nr = 0;
frameo = cpos();
@@ -2003,8 +2003,8 @@ writeframes(void)
}
strnput("", pad);
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- s = cursym;
+ for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
+ s = ctxt->cursym;
if(s->text == nil)
continue;
@@ -2067,11 +2067,11 @@ writeinfo(void)
fwdcount = 0;
if (infosec == S)
- infosec = lookup(".dwarfinfo", 0);
+ infosec = linklookup(ctxt, ".dwarfinfo", 0);
infosec->nr = 0;
if(arangessec == S)
- arangessec = lookup(".dwarfaranges", 0);
+ arangessec = linklookup(ctxt, ".dwarfaranges", 0);
arangessec->nr = 0;
for (compunit = dwroot.child; compunit; compunit = compunit->link) {
@@ -2204,7 +2204,7 @@ writearanges(void)
strnput("", headersize - (4+2+4+1+1)); // align to PtrSize
if(linkmode == LinkExternal)
- adddwarfrel(arangessec, (Sym*)b->data, sectionstart, PtrSize, b->value-((Sym*)b->data)->value);
+ adddwarfrel(arangessec, (LSym*)b->data, sectionstart, PtrSize, b->value-((LSym*)b->data)->value);
else
addrput(b->value);
@@ -2239,7 +2239,7 @@ align(vlong size)
}
static vlong
-writedwarfreloc(Sym* s)
+writedwarfreloc(LSym* s)
{
int i;
vlong start;
@@ -2408,7 +2408,7 @@ enum
vlong elfstrdbg[NElfStrDbg];
void
-dwarfaddshstrings(Sym *shstrtab)
+dwarfaddshstrings(LSym *shstrtab)
{
if(debug['w']) // disable dwarf
return;
@@ -2438,16 +2438,16 @@ dwarfaddshstrings(Sym *shstrtab)
elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rel.debug_frame");
}
- infosym = lookup(".debug_info", 0);
+ infosym = linklookup(ctxt, ".debug_info", 0);
infosym->hide = 1;
- abbrevsym = lookup(".debug_abbrev", 0);
+ abbrevsym = linklookup(ctxt, ".debug_abbrev", 0);
abbrevsym->hide = 1;
- linesym = lookup(".debug_line", 0);
+ linesym = linklookup(ctxt, ".debug_line", 0);
linesym->hide = 1;
- framesym = lookup(".debug_frame", 0);
+ framesym = linklookup(ctxt, ".debug_frame", 0);
framesym->hide = 1;
}
}
diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h
index f0df2f9b1..7952a7436 100644
--- a/src/cmd/ld/dwarf.h
+++ b/src/cmd/ld/dwarf.h
@@ -19,7 +19,7 @@ void dwarfemitdebugsections(void);
* s[ection]h[eader]str[ing]tab. Prerequisite for
* dwarfaddelfheaders().
*/
-void dwarfaddshstrings(Sym *shstrtab);
+void dwarfaddshstrings(LSym *shstrtab);
/*
* Add section headers pointing to the sections emitted in
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
index 6b3638ec5..8c7ca8609 100644
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -287,35 +287,35 @@ elfhash(uchar *name)
}
void
-elfwritedynent(Sym *s, int tag, uint64 val)
+elfwritedynent(LSym *s, int tag, uint64 val)
{
if(elf64) {
- adduint64(s, tag);
- adduint64(s, val);
+ adduint64(ctxt, s, tag);
+ adduint64(ctxt, s, val);
} else {
- adduint32(s, tag);
- adduint32(s, val);
+ adduint32(ctxt, s, tag);
+ adduint32(ctxt, s, val);
}
}
void
-elfwritedynentsym(Sym *s, int tag, Sym *t)
+elfwritedynentsym(LSym *s, int tag, LSym *t)
{
if(elf64)
- adduint64(s, tag);
+ adduint64(ctxt, s, tag);
else
- adduint32(s, tag);
- addaddr(s, t);
+ adduint32(ctxt, s, tag);
+ addaddr(ctxt, s, t);
}
void
-elfwritedynentsymsize(Sym *s, int tag, Sym *t)
+elfwritedynentsymsize(LSym *s, int tag, LSym *t)
{
if(elf64)
- adduint64(s, tag);
+ adduint64(ctxt, s, tag);
else
- adduint32(s, tag);
- addsize(s, t);
+ adduint32(ctxt, s, tag);
+ addsize(ctxt, s, t);
}
int
@@ -561,7 +561,7 @@ haveaux:
void
elfdynhash(void)
{
- Sym *s, *sy, *dynstr;
+ LSym *s, *sy, *dynstr;
int i, j, nbucket, b, nfile;
uint32 hc, *chain, *buckets;
int nsym;
@@ -575,7 +575,7 @@ elfdynhash(void)
return;
nsym = nelfsym;
- s = lookup(".hash", 0);
+ s = linklookup(ctxt, ".hash", 0);
s->type = SELFROSECT;
s->reachable = 1;
@@ -591,14 +591,14 @@ elfdynhash(void)
chain = malloc(nsym * sizeof chain[0]);
buckets = malloc(nbucket * sizeof buckets[0]);
if(need == nil || chain == nil || buckets == nil) {
- cursym = nil;
+ ctxt->cursym = nil;
diag("out of memory");
errorexit();
}
memset(need, 0, nsym * sizeof need[0]);
memset(chain, 0, nsym * sizeof chain[0]);
memset(buckets, 0, nbucket * sizeof buckets[0]);
- for(sy=allsym; sy!=S; sy=sy->allsym) {
+ for(sy=ctxt->allsym; sy!=S; sy=sy->allsym) {
if (sy->dynid <= 0)
continue;
@@ -613,69 +613,69 @@ elfdynhash(void)
buckets[b] = sy->dynid;
}
- adduint32(s, nbucket);
- adduint32(s, nsym);
+ adduint32(ctxt, s, nbucket);
+ adduint32(ctxt, s, nsym);
for(i = 0; i<nbucket; i++)
- adduint32(s, buckets[i]);
+ adduint32(ctxt, s, buckets[i]);
for(i = 0; i<nsym; i++)
- adduint32(s, chain[i]);
+ adduint32(ctxt, s, chain[i]);
free(chain);
free(buckets);
// version symbols
- dynstr = lookup(".dynstr", 0);
- s = lookup(".gnu.version_r", 0);
+ dynstr = linklookup(ctxt, ".dynstr", 0);
+ s = linklookup(ctxt, ".gnu.version_r", 0);
i = 2;
nfile = 0;
for(l=needlib; l; l=l->next) {
nfile++;
// header
- adduint16(s, 1); // table version
+ adduint16(ctxt, s, 1); // table version
j = 0;
for(x=l->aux; x; x=x->next)
j++;
- adduint16(s, j); // aux count
- adduint32(s, addstring(dynstr, l->file)); // file string offset
- adduint32(s, 16); // offset from header to first aux
+ adduint16(ctxt, s, j); // aux count
+ adduint32(ctxt, s, addstring(dynstr, l->file)); // file string offset
+ adduint32(ctxt, s, 16); // offset from header to first aux
if(l->next)
- adduint32(s, 16+j*16); // offset from this header to next
+ adduint32(ctxt, s, 16+j*16); // offset from this header to next
else
- adduint32(s, 0);
+ adduint32(ctxt, s, 0);
for(x=l->aux; x; x=x->next) {
x->num = i++;
// aux struct
- adduint32(s, elfhash((uchar*)x->vers)); // hash
- adduint16(s, 0); // flags
- adduint16(s, x->num); // other - index we refer to this by
- adduint32(s, addstring(dynstr, x->vers)); // version string offset
+ adduint32(ctxt, s, elfhash((uchar*)x->vers)); // hash
+ adduint16(ctxt, s, 0); // flags
+ adduint16(ctxt, s, x->num); // other - index we refer to this by
+ adduint32(ctxt, s, addstring(dynstr, x->vers)); // version string offset
if(x->next)
- adduint32(s, 16); // offset from this aux to next
+ adduint32(ctxt, s, 16); // offset from this aux to next
else
- adduint32(s, 0);
+ adduint32(ctxt, s, 0);
}
}
// version references
- s = lookup(".gnu.version", 0);
+ s = linklookup(ctxt, ".gnu.version", 0);
for(i=0; i<nsym; i++) {
if(i == 0)
- adduint16(s, 0); // first entry - no symbol
+ adduint16(ctxt, s, 0); // first entry - no symbol
else if(need[i] == nil)
- adduint16(s, 1); // global
+ adduint16(ctxt, s, 1); // global
else
- adduint16(s, need[i]->num);
+ adduint16(ctxt, s, need[i]->num);
}
free(need);
- s = lookup(".dynamic", 0);
+ s = linklookup(ctxt, ".dynamic", 0);
elfverneed = nfile;
if(elfverneed) {
- elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0));
+ elfwritedynentsym(s, DT_VERNEED, linklookup(ctxt, ".gnu.version_r", 0));
elfwritedynent(s, DT_VERNEEDNUM, nfile);
- elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0));
+ elfwritedynentsym(s, DT_VERSYM, linklookup(ctxt, ".gnu.version", 0));
}
elfwritedynent(s, DT_NULL, 0);
}
@@ -807,9 +807,9 @@ elfshreloc(Section *sect)
}
void
-elfrelocsect(Section *sect, Sym *first)
+elfrelocsect(Section *sect, LSym *first)
{
- Sym *sym;
+ LSym *sym;
int32 eaddr;
Reloc *r;
@@ -834,7 +834,7 @@ elfrelocsect(Section *sect, Sym *first)
continue;
if(sym->value >= eaddr)
break;
- cursym = sym;
+ ctxt->cursym = sym;
for(r = sym->r; r < sym->r+sym->nr; r++) {
if(r->done)
@@ -861,7 +861,7 @@ elfemitreloc(void)
while(cpos()&7)
cput(0);
- elfrelocsect(segtext.sect, textp);
+ elfrelocsect(segtext.sect, ctxt->textp);
for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
elfrelocsect(sect, datap);
for(sect=segrodata.sect; sect!=nil; sect=sect->next)
@@ -873,13 +873,13 @@ elfemitreloc(void)
void
doelf(void)
{
- Sym *s, *shstrtab, *dynstr;
+ LSym *s, *shstrtab, *dynstr;
if(!iself)
return;
/* predefine strings we need for section headers */
- shstrtab = lookup(".shstrtab", 0);
+ shstrtab = linklookup(ctxt, ".shstrtab", 0);
shstrtab->type = SELFROSECT;
shstrtab->reachable = 1;
@@ -969,7 +969,7 @@ doelf(void)
addstring(shstrtab, ".gnu.version_r");
/* dynamic symbol table - first entry all zeros */
- s = lookup(".dynsym", 0);
+ s = linklookup(ctxt, ".dynsym", 0);
s->type = SELFROSECT;
s->reachable = 1;
if(thechar == '6')
@@ -978,7 +978,7 @@ doelf(void)
s->size += ELF32SYMSIZE;
/* dynamic string table */
- s = lookup(".dynstr", 0);
+ s = linklookup(ctxt, ".dynstr", 0);
s->type = SELFROSECT;
s->reachable = 1;
if(s->size == 0)
@@ -987,85 +987,85 @@ doelf(void)
/* relocation table */
if(thechar == '6')
- s = lookup(".rela", 0);
+ s = linklookup(ctxt, ".rela", 0);
else
- s = lookup(".rel", 0);
+ s = linklookup(ctxt, ".rel", 0);
s->reachable = 1;
s->type = SELFROSECT;
/* global offset table */
- s = lookup(".got", 0);
+ s = linklookup(ctxt, ".got", 0);
s->reachable = 1;
s->type = SELFSECT; // writable
/* hash */
- s = lookup(".hash", 0);
+ s = linklookup(ctxt, ".hash", 0);
s->reachable = 1;
s->type = SELFROSECT;
- s = lookup(".got.plt", 0);
+ s = linklookup(ctxt, ".got.plt", 0);
s->reachable = 1;
s->type = SELFSECT; // writable
- s = lookup(".plt", 0);
+ s = linklookup(ctxt, ".plt", 0);
s->reachable = 1;
s->type = SELFRXSECT;
elfsetupplt();
if(thechar == '6')
- s = lookup(".rela.plt", 0);
+ s = linklookup(ctxt, ".rela.plt", 0);
else
- s = lookup(".rel.plt", 0);
+ s = linklookup(ctxt, ".rel.plt", 0);
s->reachable = 1;
s->type = SELFROSECT;
- s = lookup(".gnu.version", 0);
+ s = linklookup(ctxt, ".gnu.version", 0);
s->reachable = 1;
s->type = SELFROSECT;
- s = lookup(".gnu.version_r", 0);
+ s = linklookup(ctxt, ".gnu.version_r", 0);
s->reachable = 1;
s->type = SELFROSECT;
/* define dynamic elf table */
- s = lookup(".dynamic", 0);
+ s = linklookup(ctxt, ".dynamic", 0);
s->reachable = 1;
s->type = SELFSECT; // writable
/*
* .dynamic table
*/
- elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
- elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
+ elfwritedynentsym(s, DT_HASH, linklookup(ctxt, ".hash", 0));
+ elfwritedynentsym(s, DT_SYMTAB, linklookup(ctxt, ".dynsym", 0));
if(thechar == '6')
elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
else
elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
- elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
- elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
+ elfwritedynentsym(s, DT_STRTAB, linklookup(ctxt, ".dynstr", 0));
+ elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0));
if(thechar == '6') {
- elfwritedynentsym(s, DT_RELA, lookup(".rela", 0));
- elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0));
+ elfwritedynentsym(s, DT_RELA, linklookup(ctxt, ".rela", 0));
+ elfwritedynentsymsize(s, DT_RELASZ, linklookup(ctxt, ".rela", 0));
elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
} else {
- elfwritedynentsym(s, DT_REL, lookup(".rel", 0));
- elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0));
+ elfwritedynentsym(s, DT_REL, linklookup(ctxt, ".rel", 0));
+ elfwritedynentsymsize(s, DT_RELSZ, linklookup(ctxt, ".rel", 0));
elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
}
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
- elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
+ elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0));
if(thechar == '6') {
elfwritedynent(s, DT_PLTREL, DT_RELA);
- elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
- elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
+ elfwritedynentsymsize(s, DT_PLTRELSZ, linklookup(ctxt, ".rela.plt", 0));
+ elfwritedynentsym(s, DT_JMPREL, linklookup(ctxt, ".rela.plt", 0));
} else {
elfwritedynent(s, DT_PLTREL, DT_REL);
- elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
- elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
+ elfwritedynentsymsize(s, DT_PLTRELSZ, linklookup(ctxt, ".rel.plt", 0));
+ elfwritedynentsym(s, DT_JMPREL, linklookup(ctxt, ".rel.plt", 0));
}
elfwritedynent(s, DT_DEBUG, 0);
@@ -1075,7 +1075,7 @@ doelf(void)
}
void
-shsym(ElfShdr *sh, Sym *s)
+shsym(ElfShdr *sh, LSym *s)
{
vlong addr;
addr = symaddr(s);
@@ -1254,13 +1254,13 @@ asmbelf(vlong symo)
sh->addralign = PtrSize;
sh->link = elfshname(".dynstr")->shnum;
// sh->info = index of first non-local symbol (number of local symbols)
- shsym(sh, lookup(".dynsym", 0));
+ shsym(sh, linklookup(ctxt, ".dynsym", 0));
sh = elfshname(".dynstr");
sh->type = SHT_STRTAB;
sh->flags = SHF_ALLOC;
sh->addralign = 1;
- shsym(sh, lookup(".dynstr", 0));
+ shsym(sh, linklookup(ctxt, ".dynstr", 0));
if(elfverneed) {
sh = elfshname(".gnu.version");
@@ -1269,7 +1269,7 @@ asmbelf(vlong symo)
sh->addralign = 2;
sh->link = elfshname(".dynsym")->shnum;
sh->entsize = 2;
- shsym(sh, lookup(".gnu.version", 0));
+ shsym(sh, linklookup(ctxt, ".gnu.version", 0));
sh = elfshname(".gnu.version_r");
sh->type = SHT_GNU_VERNEED;
@@ -1277,7 +1277,7 @@ asmbelf(vlong symo)
sh->addralign = PtrSize;
sh->info = elfverneed;
sh->link = elfshname(".dynstr")->shnum;
- shsym(sh, lookup(".gnu.version_r", 0));
+ shsym(sh, linklookup(ctxt, ".gnu.version_r", 0));
}
switch(eh->machine) {
@@ -1289,7 +1289,7 @@ asmbelf(vlong symo)
sh->addralign = PtrSize;
sh->link = elfshname(".dynsym")->shnum;
sh->info = elfshname(".plt")->shnum;
- shsym(sh, lookup(".rela.plt", 0));
+ shsym(sh, linklookup(ctxt, ".rela.plt", 0));
sh = elfshname(".rela");
sh->type = SHT_RELA;
@@ -1297,7 +1297,7 @@ asmbelf(vlong symo)
sh->entsize = ELF64RELASIZE;
sh->addralign = 8;
sh->link = elfshname(".dynsym")->shnum;
- shsym(sh, lookup(".rela", 0));
+ shsym(sh, linklookup(ctxt, ".rela", 0));
break;
default:
@@ -1306,7 +1306,7 @@ asmbelf(vlong symo)
sh->flags = SHF_ALLOC;
sh->entsize = ELF32RELSIZE;
sh->link = elfshname(".dynsym")->shnum;
- shsym(sh, lookup(".rel.plt", 0));
+ shsym(sh, linklookup(ctxt, ".rel.plt", 0));
sh = elfshname(".rel");
sh->type = SHT_REL;
@@ -1314,7 +1314,7 @@ asmbelf(vlong symo)
sh->entsize = ELF32RELSIZE;
sh->addralign = 4;
sh->link = elfshname(".dynsym")->shnum;
- shsym(sh, lookup(".rel", 0));
+ shsym(sh, linklookup(ctxt, ".rel", 0));
break;
}
@@ -1326,21 +1326,21 @@ asmbelf(vlong symo)
else
sh->entsize = 4;
sh->addralign = 4;
- shsym(sh, lookup(".plt", 0));
+ shsym(sh, linklookup(ctxt, ".plt", 0));
sh = elfshname(".got");
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC+SHF_WRITE;
sh->entsize = PtrSize;
sh->addralign = PtrSize;
- shsym(sh, lookup(".got", 0));
+ shsym(sh, linklookup(ctxt, ".got", 0));
sh = elfshname(".got.plt");
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC+SHF_WRITE;
sh->entsize = PtrSize;
sh->addralign = PtrSize;
- shsym(sh, lookup(".got.plt", 0));
+ shsym(sh, linklookup(ctxt, ".got.plt", 0));
sh = elfshname(".hash");
sh->type = SHT_HASH;
@@ -1348,7 +1348,7 @@ asmbelf(vlong symo)
sh->entsize = 4;
sh->addralign = PtrSize;
sh->link = elfshname(".dynsym")->shnum;
- shsym(sh, lookup(".hash", 0));
+ shsym(sh, linklookup(ctxt, ".hash", 0));
/* sh and PT_DYNAMIC for .dynamic section */
sh = elfshname(".dynamic");
@@ -1357,7 +1357,7 @@ asmbelf(vlong symo)
sh->entsize = 2*PtrSize;
sh->addralign = PtrSize;
sh->link = elfshname(".dynstr")->shnum;
- shsym(sh, lookup(".dynamic", 0));
+ shsym(sh, linklookup(ctxt, ".dynamic", 0));
ph = newElfPhdr();
ph->type = PT_DYNAMIC;
ph->flags = PF_R + PF_W;
@@ -1369,11 +1369,11 @@ asmbelf(vlong symo)
// Do not emit PT_TLS for OpenBSD since ld.so(1) does
// not currently support it. This is handled
// appropriately in runtime/cgo.
- if(tlsoffset != 0 && HEADTYPE != Hopenbsd) {
+ if(ctxt->tlsoffset != 0 && HEADTYPE != Hopenbsd) {
ph = newElfPhdr();
ph->type = PT_TLS;
ph->flags = PF_R;
- ph->memsz = -tlsoffset;
+ ph->memsz = -ctxt->tlsoffset;
ph->align = PtrSize;
}
}
@@ -1394,7 +1394,7 @@ elfobj:
sh = elfshname(".shstrtab");
sh->type = SHT_STRTAB;
sh->addralign = 1;
- shsym(sh, lookup(".shstrtab", 0));
+ shsym(sh, linklookup(ctxt, ".shstrtab", 0));
eh->shstrndx = sh->shnum;
// put these sections early in the list
@@ -1430,7 +1430,7 @@ elfobj:
sh = elfshname(".tbss");
sh->type = SHT_NOBITS;
sh->addralign = PtrSize;
- sh->size = -tlsoffset;
+ sh->size = -ctxt->tlsoffset;
sh->flags = SHF_ALLOC | SHF_TLS | SHF_WRITE;
}
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
index 5b2ff041a..76085c7c6 100644
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -858,7 +858,7 @@ struct Elf64_Shdr {
Elf64_Xword entsize; /* Size of each entry in section. */
int shnum; /* section number, not stored on disk */
- Sym* secsym; /* section symbol, if needed; not on disk */
+ LSym* secsym; /* section symbol, if needed; not on disk */
};
/*
@@ -968,9 +968,9 @@ ElfPhdr *newElfPhdr(void);
uint32 elfwritehdr(void);
uint32 elfwritephdrs(void);
uint32 elfwriteshdrs(void);
-void elfwritedynent(Sym*, int, uint64);
-void elfwritedynentsym(Sym*, int, Sym*);
-void elfwritedynentsymsize(Sym*, int, Sym*);
+void elfwritedynent(LSym*, int, uint64);
+void elfwritedynentsym(LSym*, int, LSym*);
+void elfwritedynentsymsize(LSym*, int, LSym*);
uint32 elfhash(uchar*);
uint64 startelf(void);
uint64 endelf(void);
@@ -994,13 +994,13 @@ ElfShdr* elfshalloc(Section*);
ElfShdr* elfshname(char*);
ElfShdr* elfshreloc(Section*);
void elfsetstring(char*, int);
-void elfaddverneed(Sym*);
+void elfaddverneed(LSym*);
void elfemitreloc(void);
-void shsym(ElfShdr*, Sym*);
+void shsym(ElfShdr*, LSym*);
void phsh(ElfPhdr*, ElfShdr*);
void doelf(void);
void elfsetupplt(void);
-void dwarfaddshstrings(Sym*);
+void dwarfaddshstrings(LSym*);
void dwarfaddelfsectionsyms(void);
void dwarfaddelfheaders(void);
void asmbelf(vlong symo);
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index 39ffa3d87..9950a3886 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -228,39 +228,6 @@ loadpkgdata(char *file, char *pkg, char *data, int len)
free(file);
}
-// replace all "". with pkg.
-char*
-expandpkg(char *t0, char *pkg)
-{
- int n;
- char *p;
- char *w, *w0, *t;
-
- n = 0;
- for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3)
- n++;
-
- if(n == 0)
- return estrdup(t0);
-
- // use malloc, not mal, so that caller can free
- w0 = malloc(strlen(t0) + strlen(pkg)*n);
- if(w0 == nil) {
- diag("out of memory");
- errorexit();
- }
- w = w0;
- for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) {
- memmove(w, t, p - t);
- w += p-t;
- strcpy(w, pkg);
- w += strlen(pkg);
- t = p+2;
- }
- strcpy(w, t);
- return w0;
-}
-
static int
parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp)
{
@@ -413,7 +380,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
char *pend, *next, *p0, *q;
char *f[10], *local, *remote, *lib;
int nf;
- Sym *s;
+ LSym *s;
USED(file);
pend = p + n;
@@ -459,7 +426,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
q = strchr(remote, '#');
if(q)
*q++ = '\0';
- s = lookup(local, 0);
+ s = linklookup(ctxt, local, 0);
if(local != f[1])
free(local);
if(s->type == 0 || s->type == SXREF || s->type == SHOSTOBJ) {
@@ -477,7 +444,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
if(nf != 2)
goto err;
local = f[1];
- s = lookup(local, 0);
+ s = linklookup(ctxt, local, 0);
s->type = SHOSTOBJ;
s->size = 0;
continue;
@@ -496,9 +463,9 @@ loadcgo(char *file, char *pkg, char *p, int n)
else
remote = local;
local = expandpkg(local, pkg);
- s = lookup(local, 0);
+ s = linklookup(ctxt, local, 0);
- if(flag_shared && s == lookup("main", 0))
+ if(flag_shared && s == linklookup(ctxt, "main", 0))
continue;
// export overrides import, for openbsd/cgo.
@@ -562,11 +529,11 @@ err:
nerrors++;
}
-static Sym *markq;
-static Sym *emarkq;
+static LSym *markq;
+static LSym *emarkq;
static void
-mark1(Sym *s, Sym *parent)
+mark1(LSym *s, LSym *parent)
{
if(s == S || s->reachable)
return;
@@ -582,7 +549,7 @@ mark1(Sym *s, Sym *parent)
}
void
-mark(Sym *s)
+mark(LSym *s)
{
mark1(s, nil);
}
@@ -592,7 +559,7 @@ markflood(void)
{
Auto *a;
Prog *p;
- Sym *s;
+ LSym *s;
int i;
for(s=markq; s!=S; s=s->queue) {
@@ -649,7 +616,7 @@ isz(Auto *a)
}
static void
-addz(Sym *s, Auto *z)
+addz(LSym *s, Auto *z)
{
Auto *a, *last;
@@ -674,16 +641,16 @@ void
deadcode(void)
{
int i;
- Sym *s, *last, *p;
+ LSym *s, *last, *p;
Auto *z;
Fmt fmt;
if(debug['v'])
Bprint(&bso, "%5.2f deadcode\n", cputime());
- mark(lookup(INITENTRY, 0));
+ mark(linklookup(ctxt, INITENTRY, 0));
for(i=0; i<nelem(markextra); i++)
- mark(lookup(markextra[i], 0));
+ mark(linklookup(ctxt, markextra[i], 0));
for(i=0; i<ndynexp; i++)
mark(dynexp[i]);
@@ -691,7 +658,7 @@ deadcode(void)
markflood();
// keep each beginning with 'typelink.' if the symbol it points at is being kept.
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(strncmp(s->name, "go.typelink.", 12) == 0)
s->reachable = s->nr==1 && s->r[0].sym->reachable;
}
@@ -699,14 +666,14 @@ deadcode(void)
// remove dead text but keep file information (z symbols).
last = nil;
z = nil;
- for(s = textp; s != nil; s = s->next) {
+ for(s = ctxt->textp; s != nil; s = s->next) {
if(!s->reachable) {
if(isz(s->autom))
z = s->autom;
continue;
}
if(last == nil)
- textp = s;
+ ctxt->textp = s;
else
last->next = s;
last = s;
@@ -717,11 +684,11 @@ deadcode(void)
}
}
if(last == nil)
- textp = nil;
+ ctxt->textp = nil;
else
last->next = nil;
- for(s = allsym; s != S; s = s->allsym)
+ for(s = ctxt->allsym; s != S; s = s->allsym)
if(strncmp(s->name, "go.weak.", 8) == 0) {
s->special = 1; // do not lay out in data segment
s->reachable = 1;
@@ -730,7 +697,7 @@ deadcode(void)
// record field tracking references
fmtstrinit(&fmt);
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(strncmp(s->name, "go.track.", 9) == 0) {
s->special = 1; // do not lay out in data segment
s->hide = 1;
@@ -746,7 +713,7 @@ deadcode(void)
}
if(tracksym == nil)
return;
- s = lookup(tracksym, 0);
+ s = linklookup(ctxt, tracksym, 0);
if(!s->reachable)
return;
addstrdata(tracksym, fmtstrflush(&fmt));
@@ -755,13 +722,13 @@ deadcode(void)
void
doweak(void)
{
- Sym *s, *t;
+ LSym *s, *t;
// resolve weak references only if
// target symbol will be in binary anyway.
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(strncmp(s->name, "go.weak.", 8) == 0) {
- t = rlookup(s->name+8, s->version);
+ t = linkrlookup(ctxt, s->name+8, s->version);
if(t && t->type != 0 && t->reachable) {
s->value = t->value;
s->type = t->type;
@@ -784,7 +751,7 @@ addexport(void)
return;
for(i=0; i<ndynexp; i++)
- adddynsym(dynexp[i]);
+ adddynsym(ctxt, dynexp[i]);
}
/* %Z from gc, for quoting import paths */
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
index 27041bc47..4bc830ef3 100644
--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -258,7 +258,7 @@ struct ElfSect
uint64 align;
uint64 entsize;
uchar *base;
- Sym *sym;
+ LSym *sym;
};
struct ElfObj
@@ -301,7 +301,7 @@ struct ElfSym
uchar type;
uchar other;
uint16 shndx;
- Sym* sym;
+ LSym* sym;
};
uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
@@ -312,7 +312,7 @@ static int readsym(ElfObj*, int i, ElfSym*, int);
static int reltype(char*, int, uchar*);
int
-valuecmp(Sym *a, Sym *b)
+valuecmp(LSym *a, LSym *b)
{
if(a->value < b->value)
return -1;
@@ -336,15 +336,15 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
ElfSym sym;
Endian *e;
Reloc *r, *rp;
- Sym *s;
- Sym **symbols;
+ LSym *s;
+ LSym **symbols;
symbols = nil;
if(debug['v'])
Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn);
- version++;
+ ctxt->version++;
base = Boffset(f);
if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
@@ -529,7 +529,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
goto bad;
name = smprint("%s(%s)", pkg, sect->name);
- s = lookup(name, version);
+ s = linklookup(ctxt, name, ctxt->version);
free(name);
switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
default:
@@ -609,14 +609,14 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
} else {
// build a TEXT instruction with a unique pc
// just to make the rest of the linker happy.
- p = prg();
+ p = ctxt->arch->prg();
p->as = ATEXT;
p->from.type = D_EXTERN;
p->from.sym = s;
- p->textflag = 7;
+ ctxt->arch->settextflag(p, 7);
p->to.type = D_CONST;
p->link = nil;
- p->pc = pc++;
+ p->pc = ctxt->pc++;
s->text = p;
}
}
@@ -629,16 +629,16 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
if(s == S)
continue;
if(s->sub)
- s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
+ s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
if(s->type == STEXT) {
- if(etextp)
- etextp->next = s;
+ if(ctxt->etextp)
+ ctxt->etextp->next = s;
else
- textp = s;
- etextp = s;
+ ctxt->textp = s;
+ ctxt->etextp = s;
for(s = s->sub; s != S; s = s->sub) {
- etextp->next = s;
- etextp = s;
+ ctxt->etextp->next = s;
+ ctxt->etextp = s;
}
}
}
@@ -761,7 +761,7 @@ map(ElfObj *obj, ElfSect *sect)
static int
readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
{
- Sym *s;
+ LSym *s;
if(i >= obj->nsymtab || i < 0) {
werrstr("invalid elf symbol index");
@@ -808,7 +808,7 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
switch(sym->bind) {
case ElfSymBindGlobal:
if(needSym) {
- s = lookup(sym->name, 0);
+ s = linklookup(ctxt, sym->name, 0);
// for global scoped hidden symbols we should insert it into
// symbol hash table, but mark them as hidden.
// __i686.get_pc_thunk.bx is allowed to be duplicated, to
@@ -828,13 +828,13 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
// local names and hidden visiblity global names are unique
// and should only reference by its index, not name, so we
// don't bother to add them into hash table
- s = newsym(sym->name, version);
+ s = linknewsym(ctxt, sym->name, ctxt->version);
s->type |= SHIDDEN;
}
break;
case ElfSymBindWeak:
if(needSym) {
- s = newsym(sym->name, 0);
+ s = linknewsym(ctxt, sym->name, 0);
if(sym->other == 2)
s->type |= SHIDDEN;
}
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
index e0f5405f6..7318381e3 100644
--- a/src/cmd/ld/ldmacho.c
+++ b/src/cmd/ld/ldmacho.c
@@ -102,7 +102,7 @@ struct MachoSect
uint32 flags;
uint32 res1;
uint32 res2;
- Sym *sym;
+ LSym *sym;
MachoRel *rel;
};
@@ -138,7 +138,7 @@ struct MachoSym
uint16 desc;
char kind;
uint64 value;
- Sym *sym;
+ LSym *sym;
};
struct MachoDysymtab
@@ -432,7 +432,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
int64 base;
MachoSect *sect;
MachoRel *rel;
- Sym *s, *s1, *outer;
+ LSym *s, *s1, *outer;
MachoCmd *c;
MachoSymtab *symtab;
MachoDysymtab *dsymtab;
@@ -440,7 +440,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
Reloc *r, *rp;
char *name;
- version++;
+ ctxt->version++;
base = Boffset(f);
if(Bread(f, hdr, sizeof hdr) != sizeof hdr)
goto bad;
@@ -566,7 +566,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
if(strcmp(sect->name, "__eh_frame") == 0)
continue;
name = smprint("%s(%s/%s)", pkg, sect->segname, sect->name);
- s = lookup(name, version);
+ s = linklookup(ctxt, name, ctxt->version);
if(s->type != 0) {
werrstr("duplicate %s/%s", sect->segname, sect->name);
goto bad;
@@ -609,8 +609,8 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
name++;
v = 0;
if(!(sym->type&N_EXT))
- v = version;
- s = lookup(name, v);
+ v = ctxt->version;
+ s = linklookup(ctxt, name, v);
if(!(sym->type&N_EXT))
s->dupok = 1;
sym->sym = s;
@@ -647,14 +647,14 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
// build a TEXT instruction with a unique pc
// just to make the rest of the linker happy.
// TODO: this is too 6l-specific ?
- p = prg();
+ p = ctxt->arch->prg();
p->as = ATEXT;
p->from.type = D_EXTERN;
p->from.sym = s;
- p->textflag = 7;
+ ctxt->arch->settextflag(p, 7);
p->to.type = D_CONST;
p->link = nil;
- p->pc = pc++;
+ p->pc = ctxt->pc++;
s->text = p;
}
sym->sym = s;
@@ -667,7 +667,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
if((s = sect->sym) == S)
continue;
if(s->sub) {
- s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
+ s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
// assign sizes, now that we know symbols in sorted order.
for(s1 = s->sub; s1 != S; s1 = s1->sub) {
@@ -678,14 +678,14 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
}
}
if(s->type == STEXT) {
- if(etextp)
- etextp->next = s;
+ if(ctxt->etextp)
+ ctxt->etextp->next = s;
else
- textp = s;
- etextp = s;
+ ctxt->textp = s;
+ ctxt->etextp = s;
for(s1 = s->sub; s1 != S; s1 = s1->sub) {
- etextp->next = s1;
- etextp = s1;
+ ctxt->etextp->next = s1;
+ ctxt->etextp = s1;
}
}
}
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
index 6bcda2cb6..f7e4bfcdb 100644
--- a/src/cmd/ld/ldpe.c
+++ b/src/cmd/ld/ldpe.c
@@ -102,14 +102,14 @@ struct PeSym {
uint16 type;
uint8 sclass;
uint8 aux;
- Sym* sym;
+ LSym* sym;
};
struct PeSect {
char* name;
uchar* base;
uint64 size;
- Sym* sym;
+ LSym* sym;
IMAGE_SECTION_HEADER sh;
};
@@ -141,7 +141,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
PeSect *sect, *rsect;
IMAGE_SECTION_HEADER sh;
uchar symbuf[18];
- Sym *s;
+ LSym *s;
Reloc *r, *rp;
PeSym *sym;
@@ -150,7 +150,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
sect = nil;
- version++;
+ ctxt->version++;
base = Boffset(f);
obj = mal(sizeof *obj);
@@ -222,7 +222,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
goto bad;
name = smprint("%s(%s)", pkg, sect->name);
- s = lookup(name, version);
+ s = linklookup(ctxt, name, ctxt->version);
free(name);
switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
@@ -372,14 +372,14 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
diag("%s: duplicate definition of %s", pn, s->name);
// build a TEXT instruction with a unique pc
// just to make the rest of the linker happy.
- p = prg();
+ p = ctxt->arch->prg();
p->as = ATEXT;
p->from.type = D_EXTERN;
p->from.sym = s;
- p->textflag = 7;
+ ctxt->arch->settextflag(p, 7);
p->to.type = D_CONST;
p->link = nil;
- p->pc = pc++;
+ p->pc = ctxt->pc++;
s->text = p;
}
}
@@ -391,16 +391,16 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
if(s == S)
continue;
if(s->sub)
- s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
+ s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
if(s->type == STEXT) {
- if(etextp)
- etextp->next = s;
+ if(ctxt->etextp)
+ ctxt->etextp->next = s;
else
- textp = s;
- etextp = s;
+ ctxt->textp = s;
+ ctxt->etextp = s;
for(s = s->sub; s != S; s = s->sub) {
- etextp->next = s;
- etextp = s;
+ ctxt->etextp->next = s;
+ ctxt->etextp = s;
}
}
}
@@ -430,7 +430,7 @@ map(PeObj *obj, PeSect *sect)
static int
readsym(PeObj *obj, int i, PeSym **y)
{
- Sym *s;
+ LSym *s;
PeSym *sym;
char *name, *p;
@@ -464,12 +464,12 @@ readsym(PeObj *obj, int i, PeSym **y)
case IMAGE_SYM_DTYPE_NULL:
switch(sym->sclass) {
case IMAGE_SYM_CLASS_EXTERNAL: //global
- s = lookup(name, 0);
+ s = linklookup(ctxt, name, 0);
break;
case IMAGE_SYM_CLASS_NULL:
case IMAGE_SYM_CLASS_STATIC:
case IMAGE_SYM_CLASS_LABEL:
- s = lookup(name, version);
+ s = linklookup(ctxt, name, ctxt->version);
s->dupok = 1;
break;
default:
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index da522dc0c..56e50acb9 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -32,6 +32,7 @@
#include "l.h"
#include "lib.h"
#include "../ld/elf.h"
+#include "../ld/dwarf.h"
#include "../../pkg/runtime/stack.h"
#include "../../pkg/runtime/funcdata.h"
@@ -48,18 +49,9 @@ int iconv(Fmt*);
char symname[] = SYMDEF;
char pkgname[] = "__.PKGDEF";
-char** libdir;
-int nlibdir = 0;
-static int maxlibdir = 0;
static int cout = -1;
-// symbol version, incremented each time a file is loaded.
-// version==1 is reserved for savehist.
-enum
-{
- HistVersion = 1,
-};
-int version = HistVersion;
+extern int version;
// Set if we see an object compiled by the host compiler that is not
// from a package that is known to support internal linking mode.
@@ -77,15 +69,15 @@ Lflag(char *arg)
{
char **p;
- if(nlibdir >= maxlibdir) {
- if (maxlibdir == 0)
- maxlibdir = 8;
+ if(ctxt->nlibdir >= ctxt->maxlibdir) {
+ if (ctxt->maxlibdir == 0)
+ ctxt->maxlibdir = 8;
else
- maxlibdir *= 2;
- p = erealloc(libdir, maxlibdir * sizeof(*p));
- libdir = p;
+ ctxt->maxlibdir *= 2;
+ p = erealloc(ctxt->libdir, ctxt->maxlibdir * sizeof(*p));
+ ctxt->libdir = p;
}
- libdir[nlibdir++] = arg;
+ ctxt->libdir[ctxt->nlibdir++] = arg;
}
void
@@ -132,7 +124,7 @@ libinit(void)
sprint(INITENTRY, "_rt0_%s_%s_lib", goarch, goos);
}
}
- lookup(INITENTRY, 0)->type = SXREF;
+ linklookup(ctxt, INITENTRY, 0)->type = SXREF;
}
void
@@ -147,158 +139,18 @@ errorexit(void)
}
void
-addlib(char *src, char *obj)
-{
- char name[1024], pname[1024], comp[256], *p;
- int i, search;
-
- if(histfrogp <= 0)
- return;
-
- search = 0;
- if(histfrog[0]->name[1] == '/') {
- sprint(name, "");
- i = 1;
- } else
- if(isalpha((uchar)histfrog[0]->name[1]) && histfrog[0]->name[2] == ':') {
- strcpy(name, histfrog[0]->name+1);
- i = 1;
- } else
- if(histfrog[0]->name[1] == '.') {
- sprint(name, ".");
- i = 0;
- } else {
- sprint(name, "");
- i = 0;
- search = 1;
- }
-
- for(; i<histfrogp; i++) {
- snprint(comp, sizeof comp, "%s", histfrog[i]->name+1);
- for(;;) {
- p = strstr(comp, "$O");
- if(p == 0)
- break;
- memmove(p+1, p+2, strlen(p+2)+1);
- p[0] = thechar;
- }
- for(;;) {
- p = strstr(comp, "$M");
- if(p == 0)
- break;
- if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
- diag("library component too long");
- return;
- }
- memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
- memmove(p, thestring, strlen(thestring));
- }
- if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
- diag("library component too long");
- return;
- }
- if(i > 0 || !search)
- strcat(name, "/");
- strcat(name, comp);
- }
- cleanname(name);
-
- // runtime.a -> runtime
- p = nil;
- if(strlen(name) > 2 && name[strlen(name)-2] == '.') {
- p = name+strlen(name)-2;
- *p = '\0';
- }
-
- // already loaded?
- for(i=0; i<libraryp; i++)
- if(strcmp(library[i].pkg, name) == 0)
- return;
-
- // runtime -> runtime.a for search
- if(p != nil)
- *p = '.';
-
- if(search) {
- // try dot, -L "libdir", and then goroot.
- for(i=0; i<nlibdir; i++) {
- snprint(pname, sizeof pname, "%s/%s", libdir[i], name);
- if(access(pname, AEXIST) >= 0)
- break;
- }
- }else
- strcpy(pname, name);
- cleanname(pname);
-
- /* runtime.a -> runtime */
- if(p != nil)
- *p = '\0';
-
- if(debug['v'] > 1)
- Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
-
- addlibpath(src, obj, pname, name);
-}
-
-/*
- * add library to library list.
- * srcref: src file referring to package
- * objref: object file referring to package
- * file: object file, e.g., /home/rsc/go/pkg/container/vector.a
- * pkg: package import path, e.g. container/vector
- */
-void
-addlibpath(char *srcref, char *objref, char *file, char *pkg)
-{
- int i;
- Library *l;
- char *p;
-
- for(i=0; i<libraryp; i++)
- if(strcmp(file, library[i].file) == 0)
- return;
-
- if(debug['v'] > 1)
- Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
- cputime(), srcref, objref, file, pkg);
-
- if(libraryp == nlibrary){
- nlibrary = 50 + 2*libraryp;
- library = erealloc(library, sizeof library[0] * nlibrary);
- }
-
- l = &library[libraryp++];
-
- p = mal(strlen(objref) + 1);
- strcpy(p, objref);
- l->objref = p;
-
- p = mal(strlen(srcref) + 1);
- strcpy(p, srcref);
- l->srcref = p;
-
- p = mal(strlen(file) + 1);
- strcpy(p, file);
- l->file = p;
-
- p = mal(strlen(pkg) + 1);
- strcpy(p, pkg);
- l->pkg = p;
-}
-
-void
loadinternal(char *name)
{
char pname[1024];
int i, found;
found = 0;
- for(i=0; i<nlibdir; i++) {
- snprint(pname, sizeof pname, "%s/%s.a", libdir[i], name);
+ for(i=0; i<ctxt->nlibdir; i++) {
+ snprint(pname, sizeof pname, "%s/%s.a", ctxt->libdir[i], name);
if(debug['v'])
Bprint(&bso, "searching for %s.a in %s\n", name, pname);
if(access(pname, AEXIST) >= 0) {
- addlibpath("internal", "internal", pname, name);
+ addlibpath(ctxt, "internal", "internal", pname, name);
found = 1;
break;
}
@@ -311,12 +163,12 @@ void
loadlib(void)
{
int i, w, x;
- Sym *s, *gmsym;
+ LSym *s, *gmsym;
if(flag_shared) {
- s = lookup("runtime.islibrary", 0);
+ s = linklookup(ctxt, "runtime.islibrary", 0);
s->dupok = 1;
- adduint8(s, 1);
+ adduint8(ctxt, s, 1);
}
loadinternal("runtime");
@@ -332,17 +184,17 @@ loadlib(void)
loadinternal("runtime/cgo");
// Pretend that we really imported the package.
// This will do no harm if we did in fact import it.
- s = lookup("go.importpath.runtime/cgo.", 0);
+ s = linklookup(ctxt, "go.importpath.runtime/cgo.", 0);
s->type = SDATA;
s->dupok = 1;
s->reachable = 1;
}
- for(i=0; i<libraryp; i++) {
+ for(i=0; i<ctxt->libraryp; i++) {
if(debug['v'] > 1)
- Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref);
- iscgo |= strcmp(library[i].pkg, "runtime/cgo") == 0;
- objfile(library[i].file, library[i].pkg);
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), ctxt->library[i].file, ctxt->library[i].objref);
+ iscgo |= strcmp(ctxt->library[i].pkg, "runtime/cgo") == 0;
+ objfile(ctxt->library[i].file, ctxt->library[i].pkg);
}
if(linkmode == LinkAuto) {
@@ -355,7 +207,7 @@ loadlib(void)
if(linkmode == LinkInternal) {
// Drop all the cgo_import_static declarations.
// Turns out we won't be needing them.
- for(s = allsym; s != S; s = s->allsym)
+ for(s = ctxt->allsym; s != S; s = s->allsym)
if(s->type == SHOSTOBJ) {
// If a symbol was marked both
// cgo_import_static and cgo_import_dynamic,
@@ -368,7 +220,7 @@ loadlib(void)
}
}
- gmsym = lookup("runtime.tlsgm", 0);
+ gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
gmsym->type = STLSBSS;
gmsym->size = 2*PtrSize;
gmsym->hide = 1;
@@ -539,7 +391,7 @@ dowrite(int fd, char *p, int n)
while(n > 0) {
m = write(fd, p, n);
if(m <= 0) {
- cursym = S;
+ ctxt->cursym = S;
diag("write error: %r");
errorexit();
}
@@ -628,7 +480,7 @@ hostobjs(void)
h = &hostobj[i];
f = Bopen(h->file, OREAD);
if(f == nil) {
- cursym = S;
+ ctxt->cursym = S;
diag("cannot reopen %s: %r", h->pn);
errorexit();
}
@@ -744,7 +596,7 @@ hostlink(void)
h = &hostobj[i];
f = Bopen(h->file, OREAD);
if(f == nil) {
- cursym = S;
+ ctxt->cursym = S;
diag("cannot reopen %s: %r", h->pn);
errorexit();
}
@@ -753,7 +605,7 @@ hostlink(void)
argv[argc++] = p;
w = create(p, 1, 0775);
if(w < 0) {
- cursym = S;
+ ctxt->cursym = S;
diag("cannot create %s: %r", p);
errorexit();
}
@@ -765,7 +617,7 @@ hostlink(void)
len -= n;
}
if(close(w) < 0) {
- cursym = S;
+ ctxt->cursym = S;
diag("cannot write %s: %r", p);
errorexit();
}
@@ -798,7 +650,7 @@ hostlink(void)
}
if(runcmd(argv) < 0) {
- cursym = S;
+ ctxt->cursym = S;
diag("%s: running %s failed: %r", argv0, argv[0]);
errorexit();
}
@@ -913,7 +765,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence)
ldpkg(f, pkg, import1 - import0 - 2, pn, whence); // -2 for !\n
Bseek(f, import1, 0);
- ldobj1(f, pkg, eof - Boffset(f), pn);
+ ctxt->arch->ldobj(ctxt, f, pkg, eof - Boffset(f), pn);
free(pn);
return;
@@ -922,318 +774,12 @@ eof:
free(pn);
}
-Sym*
-newsym(char *symb, int v)
-{
- Sym *s;
- int l;
-
- l = strlen(symb) + 1;
- s = mal(sizeof(*s));
- if(debug['v'] > 1)
- Bprint(&bso, "newsym %s\n", symb);
-
- s->dynid = -1;
- s->plt = -1;
- s->got = -1;
- s->name = mal(l + 1);
- memmove(s->name, symb, l);
-
- s->type = 0;
- s->version = v;
- s->value = 0;
- s->sig = 0;
- s->size = 0;
- nsymbol++;
-
- s->allsym = allsym;
- allsym = s;
-
- return s;
-}
-
-static Sym*
-_lookup(char *symb, int v, int creat)
-{
- Sym *s;
- char *p;
- uint32 h;
- int c;
-
- h = v;
- for(p=symb; c = *p; p++)
- h = h+h+h + c;
- // not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it.
- h &= 0xffffff;
- h %= NHASH;
- for(s = hash[h]; s != S; s = s->hash)
- if(strcmp(s->name, symb) == 0)
- return s;
- if(!creat)
- return nil;
-
- s = newsym(symb, v);
- s->extname = s->name;
- s->hash = hash[h];
- hash[h] = s;
-
- return s;
-}
-
-Sym*
-lookup(char *name, int v)
-{
- return _lookup(name, v, 1);
-}
-
-// read-only lookup
-Sym*
-rlookup(char *name, int v)
-{
- return _lookup(name, v, 0);
-}
-
-void
-copyhistfrog(char *buf, int nbuf)
-{
- char *p, *ep;
- int i;
-
- p = buf;
- ep = buf + nbuf;
- for(i=0; i<histfrogp; i++) {
- p = seprint(p, ep, "%s", histfrog[i]->name+1);
- if(i+1<histfrogp && (p == buf || p[-1] != '/'))
- p = seprint(p, ep, "/");
- }
-}
-
-void
-addhist(int32 line, int type)
-{
- Auto *u;
- Sym *s;
- int i, j, k;
-
- u = mal(sizeof(Auto));
- s = mal(sizeof(Sym));
- s->name = mal(2*(histfrogp+1) + 1);
-
- u->asym = s;
- u->type = type;
- u->aoffset = line;
- u->link = curhist;
- curhist = u;
-
- s->name[0] = 0;
- j = 1;
- for(i=0; i<histfrogp; i++) {
- k = histfrog[i]->value;
- s->name[j+0] = k>>8;
- s->name[j+1] = k;
- j += 2;
- }
- s->name[j] = 0;
- s->name[j+1] = 0;
-}
-
-void
-histtoauto(void)
-{
- Auto *l;
-
- while(l = curhist) {
- curhist = l->link;
- l->link = curauto;
- curauto = l;
- }
-}
-
-void
-collapsefrog(Sym *s)
-{
- int i;
-
- /*
- * bad encoding of path components only allows
- * MAXHIST components. if there is an overflow,
- * first try to collapse xxx/..
- */
- for(i=1; i<histfrogp; i++)
- if(strcmp(histfrog[i]->name+1, "..") == 0) {
- memmove(histfrog+i-1, histfrog+i+1,
- (histfrogp-i-1)*sizeof(histfrog[0]));
- histfrogp--;
- goto out;
- }
-
- /*
- * next try to collapse .
- */
- for(i=0; i<histfrogp; i++)
- if(strcmp(histfrog[i]->name+1, ".") == 0) {
- memmove(histfrog+i, histfrog+i+1,
- (histfrogp-i-1)*sizeof(histfrog[0]));
- goto out;
- }
-
- /*
- * last chance, just truncate from front
- */
- memmove(histfrog+0, histfrog+1,
- (histfrogp-1)*sizeof(histfrog[0]));
-
-out:
- histfrog[histfrogp-1] = s;
-}
-
-void
-nuxiinit(void)
-{
- int i, c;
-
- for(i=0; i<4; i++) {
- c = find1(0x04030201L, i+1);
- if(i < 2)
- inuxi2[i] = c;
- if(i < 1)
- inuxi1[i] = c;
- inuxi4[i] = c;
- if(c == i) {
- inuxi8[i] = c;
- inuxi8[i+4] = c+4;
- } else {
- inuxi8[i] = c+4;
- inuxi8[i+4] = c;
- }
- fnuxi4[i] = c;
- fnuxi8[i] = c;
- fnuxi8[i+4] = c+4;
- }
- if(debug['v']) {
- Bprint(&bso, "inuxi = ");
- for(i=0; i<1; i++)
- Bprint(&bso, "%d", inuxi1[i]);
- Bprint(&bso, " ");
- for(i=0; i<2; i++)
- Bprint(&bso, "%d", inuxi2[i]);
- Bprint(&bso, " ");
- for(i=0; i<4; i++)
- Bprint(&bso, "%d", inuxi4[i]);
- Bprint(&bso, " ");
- for(i=0; i<8; i++)
- Bprint(&bso, "%d", inuxi8[i]);
- Bprint(&bso, "\nfnuxi = ");
- for(i=0; i<4; i++)
- Bprint(&bso, "%d", fnuxi4[i]);
- Bprint(&bso, " ");
- for(i=0; i<8; i++)
- Bprint(&bso, "%d", fnuxi8[i]);
- Bprint(&bso, "\n");
- }
- Bflush(&bso);
-}
-
-int
-find1(int32 l, int c)
-{
- char *p;
- int i;
-
- p = (char*)&l;
- for(i=0; i<4; i++)
- if(*p++ == c)
- return i;
- return 0;
-}
-
-int
-find2(int32 l, int c)
-{
- union {
- int32 l;
- short p[2];
- } u;
- short *p;
- int i;
-
- u.l = l;
- p = u.p;
- for(i=0; i<4; i+=2) {
- if(((*p >> 8) & 0xff) == c)
- return i;
- if((*p++ & 0xff) == c)
- return i+1;
- }
- return 0;
-}
-
-int32
-ieeedtof(Ieee *e)
-{
- int exp;
- int32 v;
-
- if(e->h == 0)
- return 0;
- exp = (e->h>>20) & ((1L<<11)-1L);
- exp -= (1L<<10) - 2L;
- v = (e->h & 0xfffffL) << 3;
- v |= (e->l >> 29) & 0x7L;
- if((e->l >> 28) & 1) {
- v++;
- if(v & 0x800000L) {
- v = (v & 0x7fffffL) >> 1;
- exp++;
- }
- }
- if(-148 <= exp && exp <= -126) {
- v |= 1<<23;
- v >>= -125 - exp;
- exp = -126;
- }
- else if(exp < -148 || exp >= 130)
- diag("double fp to single fp overflow: %.17g", ieeedtod(e));
- v |= ((exp + 126) & 0xffL) << 23;
- v |= e->h & 0x80000000L;
- return v;
-}
-
-double
-ieeedtod(Ieee *ieeep)
-{
- Ieee e;
- double fr;
- int exp;
-
- if(ieeep->h & (1L<<31)) {
- e.h = ieeep->h & ~(1L<<31);
- e.l = ieeep->l;
- return -ieeedtod(&e);
- }
- if(ieeep->l == 0 && ieeep->h == 0)
- return 0;
- exp = (ieeep->h>>20) & ((1L<<11)-1L);
- exp -= (1L<<10) - 2L;
- fr = ieeep->l & ((1L<<16)-1L);
- fr /= 1L<<16;
- fr += (ieeep->l>>16) & ((1L<<16)-1L);
- fr /= 1L<<16;
- if(exp == -(1L<<10) - 2L) {
- fr += (ieeep->h & (1L<<20)-1L);
- exp++;
- } else
- fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
- fr /= 1L<<21;
- return ldexp(fr, exp);
-}
-
void
zerosig(char *sp)
{
- Sym *s;
+ LSym *s;
- s = lookup(sp, 0);
+ s = linklookup(ctxt, sp, 0);
s->sig = 0;
}
@@ -1357,13 +903,6 @@ iconv(Fmt *fp)
return 0;
}
-void
-mangle(char *file)
-{
- fprint(2, "%s: mangled input file\n", file);
- errorexit();
-}
-
Section*
addsection(Segment *seg, char *name, int rwx)
{
@@ -1381,235 +920,6 @@ addsection(Segment *seg, char *name, int rwx)
return sect;
}
-void
-addvarint(Sym *s, uint32 val)
-{
- int32 n;
- uint32 v;
- uchar *p;
-
- n = 0;
- for(v = val; v >= 0x80; v >>= 7)
- n++;
- n++;
-
- symgrow(s, s->np+n);
-
- p = s->p + s->np - n;
- for(v = val; v >= 0x80; v >>= 7)
- *p++ = v | 0x80;
- *p = v;
-}
-
-// funcpctab appends to dst a pc-value table mapping the code in func to the values
-// returned by valfunc parameterized by arg. The invocation of valfunc to update the
-// current value is, for each p,
-//
-// val = valfunc(func, val, p, 0, arg);
-// record val as value at p->pc;
-// val = valfunc(func, val, p, 1, arg);
-//
-// where func is the function, val is the current value, p is the instruction being
-// considered, and arg can be used to further parameterize valfunc.
-void
-funcpctab(Sym *dst, Sym *func, char *desc, int32 (*valfunc)(Sym*, int32, Prog*, int32, int32), int32 arg)
-{
- int dbg, i, start;
- int32 oldval, val, started;
- uint32 delta;
- vlong pc;
- Prog *p;
-
- // To debug a specific function, uncomment second line and change name.
- dbg = 0;
- //dbg = strcmp(func->name, "main.main") == 0;
-
- debug['O'] += dbg;
-
- start = dst->np;
-
- if(debug['O'])
- Bprint(&bso, "funcpctab %s -> %s [valfunc=%s]\n", func->name, dst->name, desc);
-
- val = -1;
- oldval = val;
- pc = func->value;
-
- if(debug['O'])
- Bprint(&bso, "%6llux %6d %P\n", pc, val, func->text);
-
- started = 0;
- for(p=func->text; p != P; p = p->link) {
- // Update val. If it's not changing, keep going.
- val = valfunc(func, val, p, 0, arg);
- if(val == oldval && started) {
- val = valfunc(func, val, p, 1, arg);
- if(debug['O'])
- Bprint(&bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
- continue;
- }
-
- // If the pc of the next instruction is the same as the
- // pc of this instruction, this instruction is not a real
- // instruction. Keep going, so that we only emit a delta
- // for a true instruction boundary in the program.
- if(p->link && p->link->pc == p->pc) {
- val = valfunc(func, val, p, 1, arg);
- if(debug['O'])
- Bprint(&bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
- continue;
- }
-
- // The table is a sequence of (value, pc) pairs, where each
- // pair states that the given value is in effect from the current position
- // up to the given pc, which becomes the new current position.
- // To generate the table as we scan over the program instructions,
- // we emit a "(value" when pc == func->value, and then
- // each time we observe a change in value we emit ", pc) (value".
- // When the scan is over, we emit the closing ", pc)".
- //
- // The table is delta-encoded. The value deltas are signed and
- // transmitted in zig-zag form, where a complement bit is placed in bit 0,
- // and the pc deltas are unsigned. Both kinds of deltas are sent
- // as variable-length little-endian base-128 integers,
- // where the 0x80 bit indicates that the integer continues.
-
- if(debug['O'])
- Bprint(&bso, "%6llux %6d %P\n", (vlong)p->pc, val, p);
-
- if(started) {
- addvarint(dst, (p->pc - pc) / MINLC);
- pc = p->pc;
- }
- delta = val - oldval;
- if(delta>>31)
- delta = 1 | ~(delta<<1);
- else
- delta <<= 1;
- addvarint(dst, delta);
- oldval = val;
- started = 1;
- val = valfunc(func, val, p, 1, arg);
- }
-
- if(started) {
- if(debug['O'])
- Bprint(&bso, "%6llux done\n", (vlong)func->value+func->size);
- addvarint(dst, (func->value+func->size - pc) / MINLC);
- addvarint(dst, 0); // terminator
- }
-
- if(debug['O']) {
- Bprint(&bso, "wrote %d bytes\n", dst->np - start);
- for(i=start; i<dst->np; i++)
- Bprint(&bso, " %02ux", dst->p[i]);
- Bprint(&bso, "\n");
- }
-
- debug['O'] -= dbg;
-}
-
-// pctofileline computes either the file number (arg == 0)
-// or the line number (arg == 1) to use at p.
-// Because p->lineno applies to p, phase == 0 (before p)
-// takes care of the update.
-static int32
-pctofileline(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg)
-{
- int32 f, l;
-
- if(p->as == ATEXT || p->as == ANOP || p->as == AUSEFIELD || p->line == 0 || phase == 1)
- return oldval;
- getline(sym->hist, p->line, &f, &l);
- if(f == 0) {
- // print("getline failed for %s %P\n", cursym->name, p);
- return oldval;
- }
- if(arg == 0)
- return f;
- return l;
-}
-
-// pctospadj computes the sp adjustment in effect.
-// It is oldval plus any adjustment made by p itself.
-// The adjustment by p takes effect only after p, so we
-// apply the change during phase == 1.
-static int32
-pctospadj(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg)
-{
- USED(arg);
- USED(sym);
-
- if(oldval == -1) // starting
- oldval = 0;
- if(phase == 0)
- return oldval;
- if(oldval + p->spadj < -10000 || oldval + p->spadj > 1100000000) {
- diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj);
- errorexit();
- }
- return oldval + p->spadj;
-}
-
-// pctopcdata computes the pcdata value in effect at p.
-// A PCDATA instruction sets the value in effect at future
-// non-PCDATA instructions.
-// Since PCDATA instructions have no width in the final code,
-// it does not matter which phase we use for the update.
-static int32
-pctopcdata(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg)
-{
- USED(sym);
-
- if(phase == 0 || p->as != APCDATA || p->from.offset != arg)
- return oldval;
- if((int32)p->to.offset != p->to.offset) {
- diag("overflow in PCDATA instruction: %P", p);
- errorexit();
- }
- return p->to.offset;
-}
-
-#define LOG 5
-void
-mkfwd(void)
-{
- Prog *p;
- int i;
- int32 dwn[LOG], cnt[LOG];
- Prog *lst[LOG];
-
- for(i=0; i<LOG; i++) {
- if(i == 0)
- cnt[i] = 1;
- else
- cnt[i] = LOG * cnt[i-1];
- dwn[i] = 1;
- lst[i] = P;
- }
- i = 0;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- if(p->link == P) {
- if(cursym->next)
- p->forwd = cursym->next->text;
- break;
- }
- i--;
- if(i < 0)
- i = LOG-1;
- p->forwd = P;
- dwn[i]--;
- if(dwn[i] <= 0) {
- dwn[i] = cnt[i];
- if(lst[i] != P)
- lst[i]->forwd = p;
- lst[i] = p;
- }
- }
- }
-}
-
uint16
le16(uchar *b)
{
@@ -1652,7 +962,7 @@ Endian le = { le16, le32, le64 };
typedef struct Chain Chain;
struct Chain
{
- Sym *sym;
+ LSym *sym;
Chain *up;
int limit; // limit on entry to sym
};
@@ -1660,8 +970,8 @@ struct Chain
static int stkcheck(Chain*, int);
static void stkprint(Chain*, int);
static void stkbroke(Chain*, int);
-static Sym *morestack;
-static Sym *newstack;
+static LSym *morestack;
+static LSym *newstack;
enum
{
@@ -1673,16 +983,16 @@ void
dostkcheck(void)
{
Chain ch;
- Sym *s;
+ LSym *s;
- morestack = lookup("runtime.morestack", 0);
- newstack = lookup("runtime.newstack", 0);
+ morestack = linklookup(ctxt, "runtime.morestack", 0);
+ newstack = linklookup(ctxt, "runtime.newstack", 0);
// First the nosplits on their own.
- for(s = textp; s != nil; s = s->next) {
- if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) == 0)
+ for(s = ctxt->textp; s != nil; s = s->next) {
+ if(s->text == nil || s->text->link == nil || (ctxt->arch->textflag(s->text) & NOSPLIT) == 0)
continue;
- cursym = s;
+ ctxt->cursym = s;
ch.up = nil;
ch.sym = s;
ch.limit = StackLimit - CallSize;
@@ -1695,10 +1005,10 @@ dostkcheck(void)
// like newproc and deferproc. We could hard-code
// that knowledge but it's more robust to look at
// the actual call sites.
- for(s = textp; s != nil; s = s->next) {
- if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) != 0)
+ for(s = ctxt->textp; s != nil; s = s->next) {
+ if(s->text == nil || s->text->link == nil || (ctxt->arch->textflag(s->text) & NOSPLIT) != 0)
continue;
- cursym = s;
+ ctxt->cursym = s;
ch.up = nil;
ch.sym = s;
ch.limit = StackLimit - CallSize;
@@ -1711,7 +1021,7 @@ stkcheck(Chain *up, int depth)
{
Chain ch, ch1;
Prog *p;
- Sym *s;
+ LSym *s;
int limit, prolog;
limit = up->limit;
@@ -1732,7 +1042,7 @@ stkcheck(Chain *up, int depth)
// external function.
// should never be called directly.
// only diagnose the direct caller.
- if(depth == 1)
+ if(depth == 1 && s->type != SXREF)
diag("call to external function %s", s->name);
return -1;
}
@@ -1748,7 +1058,7 @@ stkcheck(Chain *up, int depth)
return 0;
ch.up = up;
- prolog = (s->text->textflag & NOSPLIT) == 0;
+ prolog = (ctxt->arch->textflag(s->text) & NOSPLIT) == 0;
for(p = s->text; p != P; p = p->link) {
limit -= p->spadj;
if(prolog && p->spadj != 0) {
@@ -1768,7 +1078,7 @@ stkcheck(Chain *up, int depth)
stkbroke(up, limit);
return -1;
}
- if(iscall(p)) {
+ if(ctxt->arch->iscall(p)) {
limit -= CallSize;
ch.limit = limit;
if(p->to.type == D_BRANCH) {
@@ -1814,7 +1124,7 @@ stkprint(Chain *ch, int limit)
if(ch->up == nil) {
// top of chain. ch->sym != nil.
- if(ch->sym->text->textflag & NOSPLIT)
+ if(ctxt->arch->textflag(ch->sym->text) & NOSPLIT)
print("\t%d\tassumed on entry to %s\n", ch->limit, name);
else
print("\t%d\tguaranteed after split check in %s\n", ch->limit, name);
@@ -1855,25 +1165,15 @@ headstr(int v)
return buf;
}
-void
-undef(void)
-{
- Sym *s;
-
- for(s = allsym; s != S; s = s->allsym)
- if(s->type == SXREF)
- diag("%s(%d): not defined", s->name, s->version);
-}
-
int
Yconv(Fmt *fp)
{
- Sym *s;
+ LSym *s;
Fmt fmt;
int i;
char *str;
- s = va_arg(fp->args, Sym*);
+ s = va_arg(fp->args, LSym*);
if (s == S) {
fmtprint(fp, "<nil>");
} else {
@@ -1985,22 +1285,22 @@ doversion(void)
}
void
-genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
{
Auto *a;
- Sym *s;
+ LSym *s;
int32 off;
// These symbols won't show up in the first loop below because we
// skip STEXT symbols. Normal STEXT symbols are emitted by walking textp.
- s = lookup("text", 0);
+ s = linklookup(ctxt, "text", 0);
if(s->type == STEXT)
put(s, s->name, 'T', s->value, s->size, s->version, 0);
- s = lookup("etext", 0);
+ s = linklookup(ctxt, "etext", 0);
if(s->type == STEXT)
put(s, s->name, 'T', s->value, s->size, s->version, 0);
- for(s=allsym; s!=S; s=s->allsym) {
+ for(s=ctxt->allsym; s!=S; s=s->allsym) {
if(s->hide || (s->name[0] == '.' && s->version == 0 && strcmp(s->name, ".rathole") != 0))
continue;
switch(s->type&SMASK) {
@@ -2036,7 +1336,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
}
}
- for(s = textp; s != nil; s = s->next) {
+ for(s = ctxt->textp; s != nil; s = s->next) {
if(s->text == nil)
continue;
@@ -2075,461 +1375,83 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
Bflush(&bso);
}
-char*
-estrdup(char *p)
-{
- p = strdup(p);
- if(p == nil) {
- cursym = S;
- diag("out of memory");
- errorexit();
- }
- return p;
-}
-
-void*
-erealloc(void *p, long n)
+vlong
+symaddr(LSym *s)
{
- p = realloc(p, n);
- if(p == nil) {
- cursym = S;
- diag("out of memory");
- errorexit();
- }
- return p;
+ if(!s->reachable)
+ diag("unreachable symbol in symaddr - %s", s->name);
+ return s->value;
}
-// Saved history stacks encountered while reading archives.
-// Keeping them allows us to answer virtual lineno -> file:line
-// queries.
-//
-// The history stack is a complex data structure, described best at the
-// bottom of http://plan9.bell-labs.com/magic/man2html/6/a.out.
-// One of the key benefits of interpreting it here is that the runtime
-// does not have to. Perhaps some day the compilers could generate
-// a simpler linker input too.
-
-struct Hist
-{
- int32 line;
- int32 off;
- Sym *file;
-};
-
-static Hist *histcopy;
-static Hist *hist;
-static int32 nhist;
-static int32 maxhist;
-static int32 histdepth;
-static int32 nhistfile;
-static Sym *filesyms;
-
-// savehist processes a single line, off history directive
-// found in the input object file.
void
-savehist(int32 line, int32 off)
+xdefine(char *p, int t, vlong v)
{
- char tmp[1024];
- Sym *file;
- Hist *h;
-
- // NOTE(rsc): We used to do the copyhistfrog first and this
- // condition was if(tmp[0] != '\0') to check for an empty string,
- // implying that histfrogp == 0, implying that this is a history pop.
- // However, on Windows in the misc/cgo test, the linker is
- // presented with an ANAME corresponding to an empty string,
- // that ANAME ends up being the only histfrog, and thus we have
- // a situation where histfrogp > 0 (not a pop) but the path we find
- // is the empty string. Really that shouldn't happen, but it doesn't
- // seem to be bothering anyone yet, and it's easier to fix the condition
- // to test histfrogp than to track down where that empty string is
- // coming from. Probably it is coming from go tool pack's P command.
- if(histfrogp > 0) {
- tmp[0] = '\0';
- copyhistfrog(tmp, sizeof tmp);
- file = lookup(tmp, HistVersion);
- if(file->type != SFILEPATH) {
- file->value = ++nhistfile;
- file->type = SFILEPATH;
- file->next = filesyms;
- filesyms = file;
- }
- } else
- file = nil;
+ LSym *s;
- if(file != nil && line == 1 && off == 0) {
- // start of new stack
- if(histdepth != 0) {
- diag("history stack phase error: unexpected start of new stack depth=%d file=%s", histdepth, tmp);
- errorexit();
- }
- nhist = 0;
- histcopy = nil;
- }
-
- if(nhist >= maxhist) {
- if(maxhist == 0)
- maxhist = 1;
- maxhist *= 2;
- hist = erealloc(hist, maxhist*sizeof hist[0]);
- }
- h = &hist[nhist++];
- h->line = line;
- h->off = off;
- h->file = file;
-
- if(file != nil) {
- if(off == 0)
- histdepth++;
- } else {
- if(off != 0) {
- diag("history stack phase error: bad offset in pop");
- errorexit();
- }
- histdepth--;
- }
+ s = linklookup(ctxt, p, 0);
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
}
-// gethist returns the history stack currently in effect.
-// The result is valid indefinitely.
-Hist*
-gethist(void)
+vlong
+datoff(vlong addr)
{
- if(histcopy == nil) {
- if(nhist == 0)
- return nil;
- histcopy = mal((nhist+1)*sizeof hist[0]);
- memmove(histcopy, hist, nhist*sizeof hist[0]);
- histcopy[nhist].line = -1;
- }
- return histcopy;
+ if(addr >= segdata.vaddr)
+ return addr - segdata.vaddr + segdata.fileoff;
+ if(addr >= segtext.vaddr)
+ return addr - segtext.vaddr + segtext.fileoff;
+ diag("datoff %#llx", addr);
+ return 0;
}
-typedef struct Hstack Hstack;
-struct Hstack
-{
- Hist *h;
- int delta;
-};
-
-// getline sets *f to the file number and *l to the line number
-// of the virtual line number line according to the history stack h.
-void
-getline(Hist *h, int32 line, int32 *f, int32 *l)
+vlong
+entryvalue(void)
{
- Hstack stk[100];
- int nstk, start;
- Hist *top, *h0;
- static Hist *lasth;
- static int32 laststart, lastend, lastdelta, lastfile;
-
- h0 = h;
- *f = 0;
- *l = 0;
- start = 0;
- if(h == nil || line == 0) {
- print("%s: getline: h=%p line=%d\n", cursym->name, h, line);
- return;
- }
-
- // Cache span used during last lookup, so that sequential
- // translation of line numbers in compiled code is efficient.
- if(!debug['O'] && lasth == h && laststart <= line && line < lastend) {
- *f = lastfile;
- *l = line - lastdelta;
- return;
- }
-
- if(debug['O'])
- print("getline %d laststart=%d lastend=%d\n", line, laststart, lastend);
-
- nstk = 0;
- for(; h->line != -1; h++) {
- if(debug['O'])
- print("\t%s %d %d\n", h->file ? h->file->name : "?", h->line, h->off);
-
- if(h->line > line) {
- if(nstk == 0) {
- diag("history stack phase error: empty stack at line %d", (int)line);
- errorexit();
- }
- top = stk[nstk-1].h;
- lasth = h;
- lastfile = top->file->value;
- laststart = start;
- lastend = h->line;
- lastdelta = stk[nstk-1].delta;
- *f = lastfile;
- *l = line - lastdelta;
- if(debug['O'])
- print("\tgot %d %d [%d %d %d]\n", *f, *l, laststart, lastend, lastdelta);
- return;
- }
- if(h->file == nil) {
- // pop included file
- if(nstk == 0) {
- diag("history stack phase error: stack underflow");
- errorexit();
- }
- nstk--;
- if(nstk > 0)
- stk[nstk-1].delta += h->line - stk[nstk].h->line;
- start = h->line;
- } else if(h->off == 0) {
- // push included file
- if(nstk >= nelem(stk)) {
- diag("history stack phase error: stack overflow");
- errorexit();
- }
- start = h->line;
- stk[nstk].h = h;
- stk[nstk].delta = h->line - 1;
- nstk++;
- } else {
- // #line directive
- if(nstk == 0) {
- diag("history stack phase error: stack underflow");
- errorexit();
- }
- stk[nstk-1].h = h;
- stk[nstk-1].delta = h->line - h->off;
- start = h->line;
- }
- if(debug['O'])
- print("\t\tnstk=%d delta=%d\n", nstk, stk[nstk].delta);
- }
+ char *a;
+ LSym *s;
- diag("history stack phase error: cannot find line for %d", line);
- nstk = 0;
- for(h = h0; h->line != -1; h++) {
- print("\t%d %d %s\n", h->line, h->off, h->file ? h->file->name : "");
- if(h->file == nil)
- nstk--;
- else if(h->off == 0)
- nstk++;
- }
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = linklookup(ctxt, a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(s->type != STEXT)
+ diag("entry not text: %s", s->name);
+ return s->value;
}
-// defgostring returns a symbol for the Go string containing text.
-Sym*
-defgostring(char *text)
+static void
+undefsym(LSym *s)
{
- char *p;
- Sym *s;
- int32 n;
-
- n = strlen(text);
- p = smprint("go.string.\"%Z\"", text);
- s = lookup(p, 0);
- if(s->size == 0) {
- s->type = SGOSTRING;
- s->reachable = 1;
- s->size = 2*PtrSize+n;
- symgrow(s, 2*PtrSize+n);
- setaddrplus(s, 0, s, 2*PtrSize);
- setuintxx(s, PtrSize, n, PtrSize);
- memmove(s->p+2*PtrSize, text, n);
- }
- s->reachable = 1;
- return s;
-}
+ int i;
+ Reloc *r;
-// addpctab appends to f a pc-value table, storing its offset at off.
-// The pc-value table is for func and reports the value of valfunc
-// parameterized by arg.
-static int32
-addpctab(Sym *f, int32 off, Sym *func, char *desc, int32 (*valfunc)(Sym*, int32, Prog*, int32, int32), int32 arg)
-{
- int32 start;
-
- start = f->np;
- funcpctab(f, func, desc, valfunc, arg);
- if(start == f->np) {
- // no table
- return setuint32(f, off, 0);
- }
- if((int32)start > (int32)f->np) {
- diag("overflow adding pc-table: symbol too large");
- errorexit();
+ ctxt->cursym = s;
+ for(i=0; i<s->nr; i++) {
+ r = &s->r[i];
+ if(r->sym == nil) // happens for some external ARM relocs
+ continue;
+ if(r->sym->type == Sxxx || r->sym->type == SXREF) {
+ diag("undefined: %s", r->sym->name);
+ continue;
+ }
+ if(!r->sym->reachable)
+ diag("use of unreachable symbol: %s", r->sym->name);
}
- return setuint32(f, off, start);
-}
-
-static int32
-ftabaddstring(Sym *ftab, char *s)
-{
- int32 n, start;
-
- n = strlen(s)+1;
- start = ftab->np;
- symgrow(ftab, start+n+1);
- strcpy((char*)ftab->p + start, s);
- return start;
}
-// pclntab initializes the pclntab symbol with
-// runtime function and file name information.
void
-pclntab(void)
+undef(void)
{
- Prog *p;
- int32 i, n, nfunc, start, funcstart;
- uint32 *havepc, *havefunc;
- Sym *ftab, *s;
- int32 npcdata, nfuncdata, off, end;
- int64 funcdata_bytes;
-
- funcdata_bytes = 0;
- ftab = lookup("pclntab", 0);
- ftab->type = SPCLNTAB;
- ftab->reachable = 1;
-
- // See golang.org/s/go12symtab for the format. Briefly:
- // 8-byte header
- // nfunc [PtrSize bytes]
- // function table, alternating PC and offset to func struct [each entry PtrSize bytes]
- // end PC [PtrSize bytes]
- // offset to file table [4 bytes]
- nfunc = 0;
- for(cursym = textp; cursym != nil; cursym = cursym->next)
- nfunc++;
- symgrow(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4);
- setuint32(ftab, 0, 0xfffffffb);
- setuint8(ftab, 6, MINLC);
- setuint8(ftab, 7, PtrSize);
- setuintxx(ftab, 8, nfunc, PtrSize);
-
- nfunc = 0;
- for(cursym = textp; cursym != nil; cursym = cursym->next, nfunc++) {
- funcstart = ftab->np;
- funcstart += -ftab->np & (PtrSize-1);
-
- setaddr(ftab, 8+PtrSize+nfunc*2*PtrSize, cursym);
- setuintxx(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize);
-
- npcdata = 0;
- nfuncdata = 0;
- for(p = cursym->text; p != P; p = p->link) {
- if(p->as == APCDATA && p->from.offset >= npcdata)
- npcdata = p->from.offset+1;
- if(p->as == AFUNCDATA && p->from.offset >= nfuncdata)
- nfuncdata = p->from.offset+1;
- }
-
- // fixed size of struct, checked below
- off = funcstart;
- end = funcstart + PtrSize + 3*4 + 5*4 + npcdata*4 + nfuncdata*PtrSize;
- if(nfuncdata > 0 && (end&(PtrSize-1)))
- end += 4;
- symgrow(ftab, end);
-
- // entry uintptr
- off = setaddr(ftab, off, cursym);
-
- // name int32
- off = setuint32(ftab, off, ftabaddstring(ftab, cursym->name));
-
- // args int32
- // TODO: Move into funcinfo.
- if(cursym->text == nil)
- off = setuint32(ftab, off, ArgsSizeUnknown);
- else
- off = setuint32(ftab, off, cursym->args);
-
- // frame int32
- // TODO: Remove entirely. The pcsp table is more precise.
- // This is only used by a fallback case during stack walking
- // when a called function doesn't have argument information.
- // We need to make sure everything has argument information
- // and then remove this.
- if(cursym->text == nil)
- off = setuint32(ftab, off, 0);
- else
- off = setuint32(ftab, off, (uint32)cursym->text->to.offset+PtrSize);
-
- // pcsp table (offset int32)
- off = addpctab(ftab, off, cursym, "pctospadj", pctospadj, 0);
-
- // pcfile table (offset int32)
- off = addpctab(ftab, off, cursym, "pctofileline file", pctofileline, 0);
-
- // pcln table (offset int32)
- off = addpctab(ftab, off, cursym, "pctofileline line", pctofileline, 1);
-
- // npcdata int32
- off = setuint32(ftab, off, npcdata);
-
- // nfuncdata int32
- off = setuint32(ftab, off, nfuncdata);
-
- // tabulate which pc and func data we have.
- n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4;
- havepc = mal(n);
- havefunc = havepc + (npcdata+31)/32;
- for(p = cursym->text; p != P; p = p->link) {
- if(p->as == AFUNCDATA) {
- if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1)
- diag("multiple definitions for FUNCDATA $%d", p->from.offset);
- havefunc[p->from.offset/32] |= 1<<(p->from.offset%32);
- }
- if(p->as == APCDATA)
- havepc[p->from.offset/32] |= 1<<(p->from.offset%32);
- }
-
- // pcdata.
- for(i=0; i<npcdata; i++) {
- if(!(havepc[i/32]>>(i%32))&1) {
- off = setuint32(ftab, off, 0);
- continue;
- }
- off = addpctab(ftab, off, cursym, "pctopcdata", pctopcdata, i);
- }
-
- unmal(havepc, n);
-
- // funcdata, must be pointer-aligned and we're only int32-aligned.
- // Unlike pcdata, can gather in a single pass.
- // Missing funcdata will be 0 (nil pointer).
- if(nfuncdata > 0) {
- if(off&(PtrSize-1))
- off += 4;
- for(p = cursym->text; p != P; p = p->link) {
- if(p->as == AFUNCDATA) {
- i = p->from.offset;
- if(p->to.type == D_CONST)
- setuintxx(ftab, off+PtrSize*i, p->to.offset, PtrSize);
- else {
- // TODO: Dedup.
- funcdata_bytes += p->to.sym->size;
- setaddrplus(ftab, off+PtrSize*i, p->to.sym, p->to.offset);
- }
- }
- }
- off += nfuncdata*PtrSize;
- }
-
- if(off != end) {
- diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d)", funcstart, off, end, npcdata, nfuncdata);
- errorexit();
- }
-
- // Final entry of table is just end pc.
- if(cursym->next == nil)
- setaddrplus(ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, cursym, cursym->size);
- }
+ LSym *s;
- // Start file table.
- start = ftab->np;
- start += -ftab->np & (PtrSize-1);
- setuint32(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start);
-
- symgrow(ftab, start+(nhistfile+1)*4);
- setuint32(ftab, start, nhistfile);
- for(s = filesyms; s != S; s = s->next)
- setuint32(ftab, start + s->value*4, ftabaddstring(ftab, s->name));
-
- ftab->size = ftab->np;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes);
-}
+ for(s = ctxt->textp; s != nil; s = s->next)
+ undefsym(s);
+ for(s = datap; s != nil; s = s->next)
+ undefsym(s);
+ if(nerrors > 0)
+ errorexit();
+}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index be95bb46e..63e282511 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -28,68 +28,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-enum
-{
- Sxxx,
-
- /* order here is order in output file */
- /* readonly, executable */
- STEXT,
- SELFRXSECT,
-
- /* readonly, non-executable */
- STYPE,
- SSTRING,
- SGOSTRING,
- SGOFUNC,
- SRODATA,
- SFUNCTAB,
- STYPELINK,
- SSYMTAB, // TODO: move to unmapped section
- SPCLNTAB,
- SELFROSECT,
-
- /* writable, non-executable */
- SMACHOPLT,
- SELFSECT,
- SMACHO, /* Mach-O __nl_symbol_ptr */
- SMACHOGOT,
- SNOPTRDATA,
- SINITARR,
- SDATA,
- SWINDOWS,
- SBSS,
- SNOPTRBSS,
- STLSBSS,
-
- /* not mapped */
- SXREF,
- SMACHOSYMSTR,
- SMACHOSYMTAB,
- SMACHOINDIRECTPLT,
- SMACHOINDIRECTGOT,
- SFILE,
- SFILEPATH,
- SCONST,
- SDYNIMPORT,
- SHOSTOBJ,
-
- SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */
- SMASK = SSUB - 1,
- SHIDDEN = 1<<9, // hidden or local symbol
-
- NHASH = 100003,
-};
-
-typedef struct Library Library;
-struct Library
-{
- char *objref; // object where we found the reference
- char *srcref; // src file where we found the reference
- char *file; // object file
- char *pkg; // import path
-};
-
// Terrible but standard terminology.
// A segment describes a block of file to load into memory.
// A section further describes the pieces of that block for
@@ -125,36 +63,14 @@ struct Section
uvlong rellen;
};
-typedef struct Hist Hist;
-
-#pragma incomplete struct Hist
-
extern char symname[];
-extern char **libdir;
-extern int nlibdir;
-extern int version;
EXTERN char* INITENTRY;
-EXTERN char* thestring;
-EXTERN Library* library;
-EXTERN int libraryp;
-EXTERN int nlibrary;
-EXTERN Sym* hash[NHASH];
-EXTERN Sym* allsym;
-EXTERN Sym* histfrog[MAXHIST];
-EXTERN uchar fnuxi8[8];
-EXTERN uchar fnuxi4[4];
-EXTERN int histfrogp;
-EXTERN int histgen;
-EXTERN uchar inuxi1[1];
-EXTERN uchar inuxi2[2];
-EXTERN uchar inuxi4[4];
-EXTERN uchar inuxi8[8];
+extern char* thestring;
+extern LinkArch* thelinkarch;
EXTERN char* outfile;
-EXTERN int32 nsymbol;
-EXTERN char* thestring;
EXTERN int ndynexp;
-EXTERN Sym** dynexp;
+EXTERN LSym** dynexp;
EXTERN int nldflag;
EXTERN char** ldflag;
EXTERN int havedynamic;
@@ -169,16 +85,20 @@ EXTERN char* tmpdir;
EXTERN char* extld;
EXTERN char* extldflags;
EXTERN int debug_s; // backup old value of debug['s']
+EXTERN Link* ctxt;
+EXTERN int32 HEADR;
+EXTERN int32 HEADTYPE;
+EXTERN int32 INITRND;
+EXTERN int64 INITTEXT;
+EXTERN int64 INITDAT;
+EXTERN char* INITENTRY; /* entry point */
+EXTERN char* noname;
+EXTERN char* paramspace;
+EXTERN int nerrors;
-enum
-{
- LinkAuto = 0,
- LinkInternal,
- LinkExternal,
-};
EXTERN int linkmode;
-// for dynexport field of Sym
+// for dynexport field of LSym
enum
{
CgoExportDynamic = 1<<0,
@@ -190,119 +110,6 @@ EXTERN Segment segrodata;
EXTERN Segment segdata;
EXTERN Segment segdwarf;
-void setlinkmode(char*);
-void addlib(char *src, char *obj);
-void addlibpath(char *srcref, char *objref, char *file, char *pkg);
-Section* addsection(Segment*, char*, int);
-void copyhistfrog(char *buf, int nbuf);
-void addhist(int32 line, int type);
-void savehist(int32 line, int32 off);
-Hist* gethist(void);
-void getline(Hist*, int32 line, int32 *f, int32 *l);
-void asmlc(void);
-void histtoauto(void);
-void collapsefrog(Sym *s);
-Sym* newsym(char *symb, int v);
-Sym* lookup(char *symb, int v);
-Sym* rlookup(char *symb, int v);
-void nuxiinit(void);
-int find1(int32 l, int c);
-int find2(int32 l, int c);
-int32 ieeedtof(Ieee *e);
-double ieeedtod(Ieee *e);
-void undefsym(Sym *s);
-void zerosig(char *sp);
-void readundefs(char *f, int t);
-void loadlib(void);
-void errorexit(void);
-void mangle(char*);
-void objfile(char *file, char *pkg);
-void libinit(void);
-void pclntab(void);
-void symtab(void);
-void Lflag(char *arg);
-void usage(void);
-void adddynrel(Sym*, Reloc*);
-void adddynrela(Sym*, Sym*, Reloc*);
-void ldobj1(Biobuf *f, char*, int64 len, char *pn);
-void ldobj(Biobuf*, char*, int64, char*, char*, int);
-void ldelf(Biobuf*, char*, int64, char*);
-void ldmacho(Biobuf*, char*, int64, char*);
-void ldpe(Biobuf*, char*, int64, char*);
-void ldpkg(Biobuf*, char*, int64, char*, int);
-void mark(Sym *s);
-void mkfwd(void);
-char* expandpkg(char*, char*);
-void deadcode(void);
-Reloc* addrel(Sym*);
-void codeblk(int32, int32);
-void datblk(int32, int32);
-void reloc(void);
-void relocsym(Sym*);
-void savedata(Sym*, Prog*, char*);
-void symgrow(Sym*, int32);
-void addstrdata(char*, char*);
-vlong addstring(Sym*, char*);
-vlong adduint8(Sym*, uint8);
-vlong adduint16(Sym*, uint16);
-vlong adduint32(Sym*, uint32);
-vlong adduint64(Sym*, uint64);
-vlong adduintxx(Sym*, uint64, int);
-vlong addaddr(Sym*, Sym*);
-vlong addaddrplus(Sym*, Sym*, vlong);
-vlong addpcrelplus(Sym*, Sym*, vlong);
-vlong addsize(Sym*, Sym*);
-vlong setaddrplus(Sym*, vlong, Sym*, vlong);
-vlong setaddr(Sym*, vlong, Sym*);
-vlong setuint8(Sym*, vlong, uint8);
-vlong setuint16(Sym*, vlong, uint16);
-vlong setuint32(Sym*, vlong, uint32);
-vlong setuint64(Sym*, vlong, uint64);
-vlong setuintxx(Sym*, vlong, uint64, vlong);
-void asmsym(void);
-void asmelfsym(void);
-void asmplan9sym(void);
-void putelfsectionsym(Sym*, int);
-void putelfsymshndx(vlong, int);
-void strnput(char*, int);
-void dodata(void);
-void dosymtype(void);
-void address(void);
-void textaddress(void);
-void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*));
-vlong datoff(vlong);
-void adddynlib(char*);
-int archreloc(Reloc*, Sym*, vlong*);
-void adddynsym(Sym*);
-void addexport(void);
-void dostkcheck(void);
-void undef(void);
-void doweak(void);
-void setpersrc(Sym*);
-void doversion(void);
-void usage(void);
-void setinterp(char*);
-Sym* listsort(Sym*, int(*cmp)(Sym*, Sym*), int);
-int valuecmp(Sym*, Sym*);
-void hostobjs(void);
-void hostlink(void);
-char* estrdup(char*);
-void* erealloc(void*, long);
-Sym* defgostring(char*);
-
-int pathchar(void);
-void* mal(uint32);
-void unmal(void*, uint32);
-void mywhatsys(void);
-int rbyoff(const void*, const void*);
-
-uint16 le16(uchar*);
-uint32 le32(uchar*);
-uint64 le64(uchar*);
-uint16 be16(uchar*);
-uint32 be32(uchar*);
-uint64 be64(uchar*);
-
typedef struct Endian Endian;
struct Endian
{
@@ -325,28 +132,6 @@ enum {
Pkgdef
};
-/* executable header types */
-enum {
- Hgarbunix = 0, // garbage unix
- Hnoheader, // no header
- Hunixcoff, // unix coff
- Hrisc, // aif for risc os
- Hplan9x32, // plan 9 32-bit format
- Hplan9x64, // plan 9 64-bit format
- Hmsdoscom, // MS-DOS .COM
- Hnetbsd, // NetBSD
- Hmsdosexe, // fake MS-DOS .EXE
- Hixp1200, // IXP1200 (raw)
- Helf, // ELF32
- Hipaq, // ipaq
- Hdarwin, // Apple Mach-O
- Hlinux, // Linux ELF
- Hfreebsd, // FreeBSD ELF
- Hwindows, // MS Windows PE
- Hopenbsd, // OpenBSD ELF
- Hdragonfly, // DragonFly ELF
-};
-
typedef struct Header Header;
struct Header {
char *name;
@@ -356,14 +141,8 @@ struct Header {
EXTERN char* headstring;
extern Header headers[];
-int headtype(char*);
-char* headstr(int);
-void setheadtype(char*);
-
-int Yconv(Fmt*);
-
#pragma varargck type "O" int
-#pragma varargck type "Y" Sym*
+#pragma varargck type "Y" LSym*
// buffered output
@@ -383,29 +162,115 @@ EXTERN char* cbpmax;
if(--cbc <= 0)\
cflush(); }
+EXTERN int goarm;
+
+void Lflag(char *arg);
+int Yconv(Fmt *fp);
+int Zconv(Fmt *fp);
+void addexport(void);
+void address(void);
+Section*addsection(Segment *seg, char *name, int rwx);
+void addstrdata(char *name, char *value);
+vlong addstring(LSym *s, char *str);
+void asmelfsym(void);
+void asmplan9sym(void);
+uint16 be16(uchar *b);
+uint32 be32(uchar *b);
+uint64 be64(uchar *b);
void cflush(void);
+void codeblk(int32 addr, int32 size);
vlong cpos(void);
-void cseek(vlong);
-void cwrite(void*, int);
+void cseek(vlong p);
+void cwrite(void *buf, int n);
+void datblk(int32 addr, int32 size);
+int datcmp(LSym *s1, LSym *s2);
+vlong datoff(vlong addr);
+void deadcode(void);
+LSym* decodetype_arrayelem(LSym *s);
+vlong decodetype_arraylen(LSym *s);
+LSym* decodetype_chanelem(LSym *s);
+int decodetype_funcdotdotdot(LSym *s);
+int decodetype_funcincount(LSym *s);
+LSym* decodetype_funcintype(LSym *s, int i);
+int decodetype_funcoutcount(LSym *s);
+LSym* decodetype_funcouttype(LSym *s, int i);
+LSym* decodetype_gc(LSym *s);
+vlong decodetype_ifacemethodcount(LSym *s);
+uint8 decodetype_kind(LSym *s);
+LSym* decodetype_mapkey(LSym *s);
+LSym* decodetype_mapvalue(LSym *s);
+LSym* decodetype_ptrelem(LSym *s);
+vlong decodetype_size(LSym *s);
+int decodetype_structfieldcount(LSym *s);
+char* decodetype_structfieldname(LSym *s, int i);
+vlong decodetype_structfieldoffs(LSym *s, int i);
+LSym* decodetype_structfieldtype(LSym *s, int i);
+void dodata(void);
+void dostkcheck(void);
+void dostkoff(void);
+void dosymtype(void);
+void doversion(void);
+void doweak(void);
+void dynreloc(void);
+void dynrelocsym(LSym *s);
+vlong entryvalue(void);
+void errorexit(void);
+void follow(void);
+void genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*));
+void growdatsize(vlong *datsizep, LSym *s);
+char* headstr(int v);
+int headtype(char *name);
+void hostlink(void);
+void hostobjs(void);
+int iconv(Fmt *fp);
void importcycles(void);
-int Zconv(Fmt*);
-
-uint8 decodetype_kind(Sym*);
-vlong decodetype_size(Sym*);
-Sym* decodetype_gc(Sym*);
-Sym* decodetype_arrayelem(Sym*);
-vlong decodetype_arraylen(Sym*);
-Sym* decodetype_ptrelem(Sym*);
-Sym* decodetype_mapkey(Sym*);
-Sym* decodetype_mapvalue(Sym*);
-Sym* decodetype_chanelem(Sym*);
-int decodetype_funcdotdotdot(Sym*);
-int decodetype_funcincount(Sym*);
-int decodetype_funcoutcount(Sym*);
-Sym* decodetype_funcintype(Sym*, int);
-Sym* decodetype_funcouttype(Sym*, int);
-int decodetype_structfieldcount(Sym*);
-char* decodetype_structfieldname(Sym*, int);
-Sym* decodetype_structfieldtype(Sym*, int);
-vlong decodetype_structfieldoffs(Sym*, int);
-vlong decodetype_ifacemethodcount(Sym*);
+void ldelf(Biobuf *f, char *pkg, int64 len, char *pn);
+void ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file);
+void ldmacho(Biobuf *f, char *pkg, int64 len, char *pn);
+void ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence);
+void ldpe(Biobuf *f, char *pkg, int64 len, char *pn);
+void ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence);
+uint16 le16(uchar *b);
+uint32 le32(uchar *b);
+uint64 le64(uchar *b);
+void libinit(void);
+LSym* listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off);
+void loadinternal(char *name);
+void loadlib(void);
+void lputb(int32 l);
+void lputl(int32 l);
+void* mal(uint32 n);
+void mark(LSym *s);
+void mywhatsys(void);
+struct ar_hdr;
+int nextar(Biobuf *bp, int off, struct ar_hdr *a);
+void objfile(char *file, char *pkg);
+void patch(void);
+int pathchar(void);
+void pcln(void);
+void pclntab(void);
+void putelfsectionsym(LSym* s, int shndx);
+void putelfsymshndx(vlong sympos, int shndx);
+void putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ);
+int rbyoff(const void *va, const void *vb);
+void reloc(void);
+void relocsym(LSym *s);
+void setheadtype(char *s);
+void setinterp(char *s);
+void setlinkmode(char *arg);
+void span(void);
+void strnput(char *s, int n);
+vlong symaddr(LSym *s);
+void symtab(void);
+void textaddress(void);
+void undef(void);
+void unmal(void *v, uint32 n);
+void usage(void);
+void vputb(uint64 v);
+int valuecmp(LSym *a, LSym *b);
+void vputl(uint64 v);
+void wputb(ushort w);
+void wputl(ushort w);
+void xdefine(char *p, int t, vlong v);
+void zerosig(char *sp);
+void archinit(void);
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index d135a92da..49db83eea 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -25,7 +25,7 @@ enum
};
static int nkind[NumSymKind];
-static Sym** sortsym;
+static LSym** sortsym;
static int nsortsym;
// Amount of space left for adding load commands
@@ -232,37 +232,37 @@ machowrite(void)
void
domacho(void)
{
- Sym *s;
+ LSym *s;
if(debug['d'])
return;
// empirically, string table must begin with " \x00".
- s = lookup(".machosymstr", 0);
+ s = linklookup(ctxt, ".machosymstr", 0);
s->type = SMACHOSYMSTR;
s->reachable = 1;
- adduint8(s, ' ');
- adduint8(s, '\0');
+ adduint8(ctxt, s, ' ');
+ adduint8(ctxt, s, '\0');
- s = lookup(".machosymtab", 0);
+ s = linklookup(ctxt, ".machosymtab", 0);
s->type = SMACHOSYMTAB;
s->reachable = 1;
if(linkmode != LinkExternal) {
- s = lookup(".plt", 0); // will be __symbol_stub
+ s = linklookup(ctxt, ".plt", 0); // will be __symbol_stub
s->type = SMACHOPLT;
s->reachable = 1;
- s = lookup(".got", 0); // will be __nl_symbol_ptr
+ s = linklookup(ctxt, ".got", 0); // will be __nl_symbol_ptr
s->type = SMACHOGOT;
s->reachable = 1;
s->align = 4;
- s = lookup(".linkedit.plt", 0); // indirect table for .plt
+ s = linklookup(ctxt, ".linkedit.plt", 0); // indirect table for .plt
s->type = SMACHOINDIRECTPLT;
s->reachable = 1;
- s = lookup(".linkedit.got", 0); // indirect table for .got
+ s = linklookup(ctxt, ".linkedit.got", 0); // indirect table for .got
s->type = SMACHOINDIRECTGOT;
s->reachable = 1;
}
@@ -334,7 +334,7 @@ machoshbits(MachoSeg *mseg, Section *sect, char *segname)
if(strcmp(sect->name, ".got") == 0) {
msect->name = "__nl_symbol_ptr";
msect->flag = 6; /* section with nonlazy symbol pointers */
- msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
+ msect->res1 = linklookup(ctxt, ".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
}
}
@@ -432,13 +432,13 @@ asmbmacho(void)
}
if(!debug['d']) {
- Sym *s1, *s2, *s3, *s4;
+ LSym *s1, *s2, *s3, *s4;
// must match domacholink below
- s1 = lookup(".machosymtab", 0);
- s2 = lookup(".linkedit.plt", 0);
- s3 = lookup(".linkedit.got", 0);
- s4 = lookup(".machosymstr", 0);
+ s1 = linklookup(ctxt, ".machosymtab", 0);
+ s2 = linklookup(ctxt, ".linkedit.plt", 0);
+ s3 = linklookup(ctxt, ".linkedit.got", 0);
+ s4 = linklookup(ctxt, ".machosymstr", 0);
if(linkmode != LinkExternal) {
ms = newMachoSeg("__LINKEDIT", 0);
@@ -484,7 +484,7 @@ asmbmacho(void)
}
static int
-symkind(Sym *s)
+symkind(LSym *s)
{
if(s->type == SDYNIMPORT)
return SymKindUndef;
@@ -494,7 +494,7 @@ symkind(Sym *s)
}
static void
-addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotype)
+addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype)
{
USED(name);
USED(addr);
@@ -524,11 +524,11 @@ addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotyp
static int
scmp(const void *p1, const void *p2)
{
- Sym *s1, *s2;
+ LSym *s1, *s2;
int k1, k2;
- s1 = *(Sym**)p1;
- s2 = *(Sym**)p2;
+ s1 = *(LSym**)p1;
+ s2 = *(LSym**)p2;
k1 = symkind(s1);
k2 = symkind(s2);
@@ -539,12 +539,12 @@ scmp(const void *p1, const void *p2)
}
static void
-machogenasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+machogenasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
{
- Sym *s;
+ LSym *s;
genasmsym(put);
- for(s=allsym; s; s=s->allsym)
+ for(s=ctxt->allsym; s; s=s->allsym)
if(s->type == SDYNIMPORT || s->type == SHOSTOBJ)
if(s->reachable)
put(s, nil, 'D', 0, 0, 0, nil);
@@ -573,39 +573,39 @@ static void
machosymtab(void)
{
int i;
- Sym *symtab, *symstr, *s, *o;
+ LSym *symtab, *symstr, *s, *o;
- symtab = lookup(".machosymtab", 0);
- symstr = lookup(".machosymstr", 0);
+ symtab = linklookup(ctxt, ".machosymtab", 0);
+ symstr = linklookup(ctxt, ".machosymstr", 0);
for(i=0; i<nsortsym; i++) {
s = sortsym[i];
- adduint32(symtab, symstr->size);
+ adduint32(ctxt, symtab, symstr->size);
// Only add _ to C symbols. Go symbols have dot in the name.
if(strstr(s->extname, ".") == nil)
- adduint8(symstr, '_');
+ adduint8(ctxt, symstr, '_');
addstring(symstr, s->extname);
if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) {
- adduint8(symtab, 0x01); // type N_EXT, external symbol
- adduint8(symtab, 0); // no section
- adduint16(symtab, 0); // desc
- adduintxx(symtab, 0, PtrSize); // no value
+ adduint8(ctxt, symtab, 0x01); // type N_EXT, external symbol
+ adduint8(ctxt, symtab, 0); // no section
+ adduint16(ctxt, symtab, 0); // desc
+ adduintxx(ctxt, symtab, 0, PtrSize); // no value
} else {
if(s->cgoexport)
- adduint8(symtab, 0x0f);
+ adduint8(ctxt, symtab, 0x0f);
else
- adduint8(symtab, 0x0e);
+ adduint8(ctxt, symtab, 0x0e);
o = s;
while(o->outer != nil)
o = o->outer;
if(o->sect == nil) {
diag("missing section for %s", s->name);
- adduint8(symtab, 0);
+ adduint8(ctxt, symtab, 0);
} else
- adduint8(symtab, o->sect->extnum);
- adduint16(symtab, 0); // desc
- adduintxx(symtab, symaddr(s), PtrSize);
+ adduint8(ctxt, symtab, o->sect->extnum);
+ adduint16(ctxt, symtab, 0); // desc
+ adduintxx(ctxt, symtab, symaddr(s), PtrSize);
}
}
}
@@ -615,7 +615,7 @@ machodysymtab(void)
{
int n;
MachoLoad *ml;
- Sym *s1, *s2, *s3;
+ LSym *s1, *s2, *s3;
ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
@@ -639,9 +639,9 @@ machodysymtab(void)
ml->data[11] = 0; /* nextrefsyms */
// must match domacholink below
- s1 = lookup(".machosymtab", 0);
- s2 = lookup(".linkedit.plt", 0);
- s3 = lookup(".linkedit.got", 0);
+ s1 = linklookup(ctxt, ".machosymtab", 0);
+ s2 = linklookup(ctxt, ".linkedit.plt", 0);
+ s3 = linklookup(ctxt, ".linkedit.got", 0);
ml->data[12] = linkoff + s1->size; /* indirectsymoff */
ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */
@@ -655,15 +655,15 @@ vlong
domacholink(void)
{
int size;
- Sym *s1, *s2, *s3, *s4;
+ LSym *s1, *s2, *s3, *s4;
machosymtab();
// write data that will be linkedit section
- s1 = lookup(".machosymtab", 0);
- s2 = lookup(".linkedit.plt", 0);
- s3 = lookup(".linkedit.got", 0);
- s4 = lookup(".machosymstr", 0);
+ s1 = linklookup(ctxt, ".machosymtab", 0);
+ s2 = linklookup(ctxt, ".linkedit.plt", 0);
+ s3 = linklookup(ctxt, ".linkedit.got", 0);
+ s4 = linklookup(ctxt, ".machosymstr", 0);
// Force the linkedit section to end on a 16-byte
// boundary. This allows pure (non-cgo) Go binaries
@@ -683,7 +683,7 @@ domacholink(void)
// any alignment padding itself, working around the
// issue.
while(s4->size%16)
- adduint8(s4, 0);
+ adduint8(ctxt, s4, 0);
size = s1->size + s2->size + s3->size + s4->size;
@@ -702,9 +702,9 @@ domacholink(void)
void
-machorelocsect(Section *sect, Sym *first)
+machorelocsect(Section *sect, LSym *first)
{
- Sym *sym;
+ LSym *sym;
int32 eaddr;
Reloc *r;
@@ -726,7 +726,7 @@ machorelocsect(Section *sect, Sym *first)
continue;
if(sym->value >= eaddr)
break;
- cursym = sym;
+ ctxt->cursym = sym;
for(r = sym->r; r < sym->r+sym->nr; r++) {
if(r->done)
@@ -747,7 +747,7 @@ machoemitreloc(void)
while(cpos()&7)
cput(0);
- machorelocsect(segtext.sect, textp);
+ machorelocsect(segtext.sect, ctxt->textp);
for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
machorelocsect(sect, datap);
for(sect=segdata.sect; sect!=nil; sect=sect->next)
diff --git a/src/cmd/ld/pass.c b/src/cmd/ld/pass.c
new file mode 100644
index 000000000..788b7c75a
--- /dev/null
+++ b/src/cmd/ld/pass.c
@@ -0,0 +1,104 @@
+// Inferno utils/6l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Code and data passes.
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../../pkg/runtime/stack.h"
+
+void
+follow(void)
+{
+ LSym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+
+ for(s = ctxt->textp; s != nil; s = s->next)
+ ctxt->arch->follow(ctxt, s);
+}
+
+void
+patch(void)
+{
+ LSym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f mkfwd\n", cputime());
+ Bflush(&bso);
+ for(s = ctxt->textp; s != nil; s = s->next)
+ mkfwd(s);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+
+ if(flag_shared) {
+ s = linklookup(ctxt, "init_array", 0);
+ s->type = SINITARR;
+ s->reachable = 1;
+ s->hide = 1;
+ addaddr(ctxt, s, linklookup(ctxt, INITENTRY, 0));
+ }
+
+ for(s = ctxt->textp; s != nil; s = s->next)
+ linkpatch(ctxt, s);
+}
+
+void
+dostkoff(void)
+{
+ LSym *s;
+
+ for(s = ctxt->textp; s != nil; s = s->next)
+ ctxt->arch->addstacksplit(ctxt, s);
+}
+
+void
+span(void)
+{
+ LSym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+
+ for(s = ctxt->textp; s != nil; s = s->next)
+ ctxt->arch->assemble(ctxt, s);
+}
+
+void
+pcln(void)
+{
+ LSym *s;
+
+ for(s = ctxt->textp; s != nil; s = s->next)
+ linkpcln(ctxt, s);
+}
diff --git a/src/cmd/ld/pcln.c b/src/cmd/ld/pcln.c
new file mode 100644
index 000000000..5934dbcdf
--- /dev/null
+++ b/src/cmd/ld/pcln.c
@@ -0,0 +1,258 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "l.h"
+#include "lib.h"
+#include "../../pkg/runtime/funcdata.h"
+
+static void
+addvarint(Pcdata *d, uint32 val)
+{
+ int32 n;
+ uint32 v;
+ uchar *p;
+
+ n = 0;
+ for(v = val; v >= 0x80; v >>= 7)
+ n++;
+ n++;
+
+ if(d->n + n > d->m) {
+ d->m = (d->n + n)*2;
+ d->p = erealloc(d->p, d->m);
+ }
+
+ p = d->p + d->n;
+ for(v = val; v >= 0x80; v >>= 7)
+ *p++ = v | 0x80;
+ *p++ = v;
+ d->n += n;
+}
+
+static int32
+addpctab(LSym *ftab, int32 off, Pcdata *d)
+{
+ int32 start;
+
+ start = ftab->np;
+ symgrow(ctxt, ftab, start + d->n);
+ memmove(ftab->p + start, d->p, d->n);
+
+ return setuint32(ctxt, ftab, off, start);
+}
+
+static int32
+ftabaddstring(LSym *ftab, char *s)
+{
+ int32 n, start;
+
+ n = strlen(s)+1;
+ start = ftab->np;
+ symgrow(ctxt, ftab, start+n+1);
+ strcpy((char*)ftab->p + start, s);
+ return start;
+}
+
+static uint32
+getvarint(uchar **pp)
+{
+ uchar *p;
+ int shift;
+ uint32 v;
+
+ v = 0;
+ p = *pp;
+ for(shift = 0;; shift += 7) {
+ v |= (*p & 0x7F) << shift;
+ if(!(*p++ & 0x80))
+ break;
+ }
+ *pp = p;
+ return v;
+}
+
+static void
+renumberfiles(LSym **files, int nfiles, Pcdata *d)
+{
+ int i;
+ LSym *f;
+ Pcdata out;
+ uint32 v;
+ int32 oldval, newval, val, dv;
+ uchar *p;
+
+ // Give files numbers.
+ for(i=0; i<nfiles; i++) {
+ f = files[i];
+ if(f->type != SFILEPATH) {
+ f->value = ++ctxt->nhistfile;
+ f->type = SFILEPATH;
+ f->next = ctxt->filesyms;
+ ctxt->filesyms = f;
+ }
+ }
+
+ oldval = -1;
+ newval = -1;
+ memset(&out, 0, sizeof out);
+ p = d->p;
+ while(p < d->p + d->n) {
+ // value delta
+ v = getvarint(&p);
+ if(v == 0 && p != d->p) {
+ addvarint(&out, 0);
+ break;
+ }
+ dv = (int32)(v>>1) ^ ((int32)(v<<31)>>31);
+ oldval += dv;
+ if(oldval == -1)
+ val = -1;
+ else {
+ if(oldval < 0 || oldval >= nfiles)
+ sysfatal("bad pcdata %d", oldval);
+ val = files[oldval]->value;
+ }
+ dv = val - newval;
+ v = (uint32)(dv<<1) ^ (uint32)(dv>>31);
+ addvarint(&out, v);
+
+ // pc delta
+ v = getvarint(&p);
+ addvarint(&out, v);
+ }
+
+ free(d->p);
+ *d = out;
+}
+
+
+// pclntab initializes the pclntab symbol with
+// runtime function and file name information.
+void
+pclntab(void)
+{
+ int32 i, nfunc, start, funcstart;
+ LSym *ftab, *s;
+ int32 off, end;
+ int64 funcdata_bytes;
+ Pcln *pcln;
+ static Pcln zpcln;
+
+ funcdata_bytes = 0;
+ ftab = linklookup(ctxt, "pclntab", 0);
+ ftab->type = SPCLNTAB;
+ ftab->reachable = 1;
+
+ // See golang.org/s/go12symtab for the format. Briefly:
+ // 8-byte header
+ // nfunc [PtrSize bytes]
+ // function table, alternating PC and offset to func struct [each entry PtrSize bytes]
+ // end PC [PtrSize bytes]
+ // offset to file table [4 bytes]
+ nfunc = 0;
+ for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next)
+ nfunc++;
+ symgrow(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4);
+ setuint32(ctxt, ftab, 0, 0xfffffffb);
+ setuint8(ctxt, ftab, 6, MINLC);
+ setuint8(ctxt, ftab, 7, PtrSize);
+ setuintxx(ctxt, ftab, 8, nfunc, PtrSize);
+
+ nfunc = 0;
+ for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next, nfunc++) {
+ pcln = ctxt->cursym->pcln;
+ if(pcln == nil)
+ pcln = &zpcln;
+
+ funcstart = ftab->np;
+ funcstart += -ftab->np & (PtrSize-1);
+
+ setaddr(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize, ctxt->cursym);
+ setuintxx(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize);
+
+ // fixed size of struct, checked below
+ off = funcstart;
+ end = funcstart + PtrSize + 3*4 + 5*4 + pcln->npcdata*4 + pcln->nfuncdata*PtrSize;
+ if(pcln->nfuncdata > 0 && (end&(PtrSize-1)))
+ end += 4;
+ symgrow(ctxt, ftab, end);
+
+ // entry uintptr
+ off = setaddr(ctxt, ftab, off, ctxt->cursym);
+
+ // name int32
+ off = setuint32(ctxt, ftab, off, ftabaddstring(ftab, ctxt->cursym->name));
+
+ // args int32
+ // TODO: Move into funcinfo.
+ if(ctxt->cursym->text == nil)
+ off = setuint32(ctxt, ftab, off, ArgsSizeUnknown);
+ else
+ off = setuint32(ctxt, ftab, off, ctxt->cursym->args);
+
+ // frame int32
+ // TODO: Remove entirely. The pcsp table is more precise.
+ // This is only used by a fallback case during stack walking
+ // when a called function doesn't have argument information.
+ // We need to make sure everything has argument information
+ // and then remove this.
+ if(ctxt->cursym->text == nil)
+ off = setuint32(ctxt, ftab, off, 0);
+ else
+ off = setuint32(ctxt, ftab, off, (uint32)ctxt->cursym->text->to.offset+PtrSize);
+
+ if(pcln != &zpcln)
+ renumberfiles(pcln->file, pcln->nfile, &pcln->pcfile);
+
+ // pcdata
+ off = addpctab(ftab, off, &pcln->pcsp);
+ off = addpctab(ftab, off, &pcln->pcfile);
+ off = addpctab(ftab, off, &pcln->pcline);
+ off = setuint32(ctxt, ftab, off, pcln->npcdata);
+ off = setuint32(ctxt, ftab, off, pcln->nfuncdata);
+ for(i=0; i<pcln->npcdata; i++)
+ off = addpctab(ftab, off, &pcln->pcdata[i]);
+
+ // funcdata, must be pointer-aligned and we're only int32-aligned.
+ // Missing funcdata will be 0 (nil pointer).
+ if(pcln->nfuncdata > 0) {
+ if(off&(PtrSize-1))
+ off += 4;
+ for(i=0; i<pcln->nfuncdata; i++) {
+ if(pcln->funcdata[i] == nil)
+ setuintxx(ctxt, ftab, off+PtrSize*i, pcln->funcdataoff[i], PtrSize);
+ else {
+ // TODO: Dedup.
+ funcdata_bytes += pcln->funcdata[i]->size;
+ setaddrplus(ctxt, ftab, off+PtrSize*i, pcln->funcdata[i], pcln->funcdataoff[i]);
+ }
+ }
+ off += pcln->nfuncdata*PtrSize;
+ }
+
+ if(off != end) {
+ diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d)", funcstart, off, end, pcln->npcdata, pcln->nfuncdata);
+ errorexit();
+ }
+
+ // Final entry of table is just end pc.
+ if(ctxt->cursym->next == nil)
+ setaddrplus(ctxt, ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, ctxt->cursym, ctxt->cursym->size);
+ }
+
+ // Start file table.
+ start = ftab->np;
+ start += -ftab->np & (PtrSize-1);
+ setuint32(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start);
+
+ symgrow(ctxt, ftab, start+(ctxt->nhistfile+1)*4);
+ setuint32(ctxt, ftab, start, ctxt->nhistfile);
+ for(s = ctxt->filesyms; s != S; s = s->next)
+ setuint32(ctxt, ftab, start + s->value*4, ftabaddstring(ftab, s->name));
+
+ ftab->size = ftab->np;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes);
+}
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index 7b9a596fc..e4848643e 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -37,7 +37,7 @@ static char *symlabels[] = {
"symtab", "esymtab", "pclntab", "epclntab"
};
-static Sym *rsrcsym;
+static LSym *rsrcsym;
static char symnames[256];
static int nextsymoff;
@@ -62,7 +62,7 @@ static IMAGE_DATA_DIRECTORY* dd;
typedef struct Imp Imp;
struct Imp {
- Sym* s;
+ LSym* s;
uvlong off;
Imp* next;
};
@@ -78,7 +78,7 @@ struct Dll {
static Dll* dr;
-static Sym *dexport[1024];
+static LSym *dexport[1024];
static int nexport;
static IMAGE_SECTION_HEADER*
@@ -191,11 +191,11 @@ initdynimport(void)
{
Imp *m;
Dll *d;
- Sym *s, *dynamic;
+ LSym *s, *dynamic;
dr = nil;
m = nil;
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(!s->reachable || s->type != SDYNIMPORT)
continue;
for(d = dr; d != nil; d = d->next) {
@@ -216,7 +216,7 @@ initdynimport(void)
d->ms = m;
}
- dynamic = lookup(".windynamic", 0);
+ dynamic = linklookup(ctxt, ".windynamic", 0);
dynamic->reachable = 1;
dynamic->type = SWINDOWS;
for(d = dr; d != nil; d = d->next) {
@@ -241,10 +241,10 @@ addimports(IMAGE_SECTION_HEADER *datsect)
vlong startoff, endoff;
Imp *m;
Dll *d;
- Sym* dynamic;
+ LSym* dynamic;
startoff = cpos();
- dynamic = lookup(".windynamic", 0);
+ dynamic = linklookup(ctxt, ".windynamic", 0);
// skip import descriptor table (will write it later)
n = 0;
@@ -322,20 +322,20 @@ addimports(IMAGE_SECTION_HEADER *datsect)
static int
scmp(const void *p1, const void *p2)
{
- Sym *s1, *s2;
+ LSym *s1, *s2;
- s1 = *(Sym**)p1;
- s2 = *(Sym**)p2;
+ s1 = *(LSym**)p1;
+ s2 = *(LSym**)p2;
return strcmp(s1->extname, s2->extname);
}
static void
initdynexport(void)
{
- Sym *s;
+ LSym *s;
nexport = 0;
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(!s->reachable || !(s->cgoexport & CgoExportDynamic))
continue;
if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
@@ -410,10 +410,10 @@ addexports(void)
void
dope(void)
{
- Sym *rel;
+ LSym *rel;
/* relocation table */
- rel = lookup(".rel", 0);
+ rel = linklookup(ctxt, ".rel", 0);
rel->reachable = 1;
rel->type = SELFROSECT;
@@ -459,7 +459,7 @@ addsymtable(void)
{
IMAGE_SECTION_HEADER *h;
int i, size;
- Sym *s;
+ LSym *s;
fh.NumberOfSymbols = sizeof(symlabels)/sizeof(symlabels[0]);
size = nextsymoff + 4 + 18*fh.NumberOfSymbols;
@@ -471,7 +471,7 @@ addsymtable(void)
// put COFF symbol table
for (i=0; i<fh.NumberOfSymbols; i++) {
- s = rlookup(symlabels[i], 0);
+ s = linkrlookup(ctxt, symlabels[i], 0);
strnput(s->name, 8);
lputl(datoff(s->value));
wputl(textsect);
@@ -488,7 +488,7 @@ addsymtable(void)
}
void
-setpersrc(Sym *sym)
+setpersrc(LSym *sym)
{
if(rsrcsym != nil)
diag("too many .rsrc sections");
@@ -535,14 +535,14 @@ addexcept(IMAGE_SECTION_HEADER *text)
IMAGE_SECTION_HEADER *pdata, *xdata;
vlong startoff;
uvlong n;
- Sym *sym;
+ LSym *sym;
USED(text);
if(thechar != '6')
return;
// write unwind info
- sym = lookup("runtime.sigtramp", 0);
+ sym = linklookup(ctxt, "runtime.sigtramp", 0);
startoff = cpos();
lputl(9); // version=1, flags=UNW_FLAG_EHANDLER, rest 0
lputl(sym->value - PEBASE);
diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h
index 7aa938829..03ed8d830 100644
--- a/src/cmd/ld/pe.h
+++ b/src/cmd/ld/pe.h
@@ -176,4 +176,4 @@ typedef struct {
IMAGE_DATA_DIRECTORY DataDirectory[16];
} PE64_IMAGE_OPTIONAL_HEADER;
-void setpersrc(Sym *sym);
+void setpersrc(LSym *sym);
diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c
new file mode 100644
index 000000000..8883d3786
--- /dev/null
+++ b/src/cmd/ld/pobj.c
@@ -0,0 +1,223 @@
+// Inferno utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Reading object files.
+
+#define EXTERN
+#include "l.h"
+#include "../ld/lib.h"
+#include "../ld/elf.h"
+#include "../ld/macho.h"
+#include "../ld/dwarf.h"
+#include "../ld/pe.h"
+#include <ar.h>
+
+char *noname = "<none>";
+char* paramspace = "FP";
+
+Header headers[] = {
+ "darwin", Hdarwin,
+ "dragonfly", Hdragonfly,
+ "elf", Helf,
+ "freebsd", Hfreebsd,
+ "linux", Hlinux,
+ "netbsd", Hnetbsd,
+ "openbsd", Hopenbsd,
+ "plan9", Hplan9,
+ "windows", Hwindows,
+ "windowsgui", Hwindows,
+ 0, 0
+};
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+
+ ctxt = linknew(thelinkarch);
+ ctxt->thechar = thechar;
+ ctxt->thestring = thestring;
+ ctxt->diag = diag;
+ ctxt->dwarfaddfrag = dwarfaddfrag;
+ ctxt->bso = &bso;
+
+ Binit(&bso, 1, OWRITE);
+ listinit();
+ memset(debug, 0, sizeof(debug));
+ nerrors = 0;
+ outfile = nil;
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+ linkmode = LinkAuto;
+ nuxiinit();
+
+ if(thechar == '5') {
+ p = getgoarm();
+ if(p != nil)
+ goarm = atoi(p);
+ else
+ goarm = 6;
+ if(goarm == 5)
+ debug['F'] = 1;
+ ctxt->goarm = goarm;
+ }
+
+ flagcount("1", "use alternate profiling code", &debug['1']);
+ if(thechar == '6')
+ flagcount("8", "assume 64-bit addresses", &debug['8']);
+ flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
+ flagint64("D", "addr: data address", &INITDAT);
+ flagstr("E", "sym: entry symbol", &INITENTRY);
+ if(thechar == '5')
+ flagcount("G", "debug pseudo-ops", &debug['G']);
+ flagfn1("I", "interp: set ELF interp", setinterp);
+ flagfn1("L", "dir: add dir to library path", Lflag);
+ flagfn1("H", "head: header type", setheadtype);
+ flagcount("K", "add stack underflow checks", &debug['K']);
+ if(thechar == '5')
+ flagcount("M", "disable software div/mod", &debug['M']);
+ flagcount("O", "print pc-line tables", &debug['O']);
+ flagcount("Q", "debug byte-register code gen", &debug['Q']);
+ if(thechar == '5')
+ flagcount("P", "debug code generation", &debug['P']);
+ flagint32("R", "rnd: address rounding", &INITRND);
+ flagcount("S", "check type signatures", &debug['S']);
+ flagint64("T", "addr: text address", &INITTEXT);
+ flagfn0("V", "print version and exit", doversion);
+ flagcount("W", "disassemble input", &debug['W']);
+ flagfn2("X", "name value: define string data", addstrdata);
+ flagcount("Z", "clear stack frame on entry", &debug['Z']);
+ flagcount("a", "disassemble output", &debug['a']);
+ flagcount("c", "dump call graph", &debug['c']);
+ flagcount("d", "disable dynamic executable", &debug['d']);
+ flagstr("extld", "linker to run in external mode", &extld);
+ flagstr("extldflags", "flags for external linker", &extldflags);
+ flagcount("f", "ignore version mismatch", &debug['f']);
+ flagcount("g", "disable go package data checks", &debug['g']);
+ flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
+ flagstr("k", "sym: set field tracking symbol", &tracksym);
+ flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
+ flagcount("n", "dump symbol table", &debug['n']);
+ flagstr("o", "outfile: set output file", &outfile);
+ flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
+ flagcount("race", "enable race detector", &flag_race);
+ flagcount("s", "disable symbol table", &debug['s']);
+ if(thechar == '5' || thechar == '6')
+ flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared);
+ flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
+ flagcount("u", "reject unsafe packages", &debug['u']);
+ flagcount("v", "print link trace", &debug['v']);
+ flagcount("w", "disable DWARF generation", &debug['w']);
+
+ flagparse(&argc, &argv, usage);
+ ctxt->bso = &bso;
+ ctxt->debugdivmod = debug['M'];
+ ctxt->debugfloat = debug['F'];
+ ctxt->debughist = debug['O'];
+ ctxt->debugpcln = debug['O'];
+ ctxt->debugread = debug['W'];
+ ctxt->debugstack = debug['K'];
+ ctxt->debugvlog = debug['v'];
+
+ if(argc != 1)
+ usage();
+
+ if(outfile == nil) {
+ if(HEADTYPE == Hwindows)
+ outfile = smprint("%c.out.exe", thechar);
+ else
+ outfile = smprint("%c.out", thechar);
+ }
+ libinit(); // creates outfile
+
+ if(HEADTYPE == -1)
+ HEADTYPE = headtype(goos);
+ ctxt->headtype = HEADTYPE;
+
+ archinit();
+ ctxt->linkmode = linkmode;
+ ctxt->debugfloat = debug['F'];
+
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+
+ addlibpath(ctxt, "command line", "command line", argv[0], "main");
+ loadlib();
+
+ if(thechar == '5') {
+ // mark some functions that are only referenced after linker code editing
+ if(debug['F'])
+ mark(linkrlookup(ctxt, "_sfloat", 0));
+ mark(linklookup(ctxt, "runtime.read_tls_fallback", 0));
+ }
+
+ deadcode();
+ patch();
+ follow();
+ dostkoff();
+ paramspace = "SP"; /* (FP) now (SP) on output */
+ span();
+ pcln();
+
+ doelf();
+ if(HEADTYPE == Hdarwin)
+ domacho();
+ dostkcheck();
+ if(HEADTYPE == Hwindows)
+ dope();
+ addexport();
+ textaddress();
+ pclntab();
+ symtab();
+ dodata();
+ address();
+ doweak();
+ reloc();
+ asmb();
+ undef();
+ hostlink();
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%d symbols\n", ctxt->nsymbol);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Addr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+
+ errorexit();
+}
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index c9b4657f7..54e604148 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -86,10 +86,10 @@ static int numelfsym = 1; // 0 is reserved
static int elfbind;
static void
-putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+putelfsym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
{
int bind, type, off;
- Sym *xo;
+ LSym *xo;
USED(go);
switch(t) {
@@ -109,12 +109,12 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
while(xo->outer != nil)
xo = xo->outer;
if(xo->sect == nil) {
- cursym = x;
+ ctxt->cursym = x;
diag("missing section in putelfsym");
return;
}
if(xo->sect->elfsect == nil) {
- cursym = x;
+ ctxt->cursym = x;
diag("missing ELF section in putelfsym");
return;
}
@@ -143,7 +143,7 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
}
void
-putelfsectionsym(Sym* s, int shndx)
+putelfsectionsym(LSym* s, int shndx)
{
putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0);
s->elfsym = numelfsym++;
@@ -170,7 +170,7 @@ putelfsymshndx(vlong sympos, int shndx)
void
asmelfsym(void)
{
- Sym *s;
+ LSym *s;
// the first symbol entry is reserved
putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0);
@@ -181,9 +181,9 @@ asmelfsym(void)
genasmsym(putelfsym);
if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) {
- s = lookup("runtime.tlsgm", 0);
+ s = linklookup(ctxt, "runtime.tlsgm", 0);
if(s->sect == nil) {
- cursym = nil;
+ ctxt->cursym = nil;
diag("missing section for %s", s->name);
errorexit();
}
@@ -195,7 +195,7 @@ asmelfsym(void)
elfglobalsymndx = numelfsym;
genasmsym(putelfsym);
- for(s=allsym; s!=S; s=s->allsym) {
+ for(s=ctxt->allsym; s!=S; s=s->allsym) {
if(s->type != SHOSTOBJ)
continue;
putelfsyment(putelfstr(s->name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0);
@@ -204,7 +204,7 @@ asmelfsym(void)
}
static void
-putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+putplan9sym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
{
int i, l;
@@ -226,7 +226,7 @@ putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
case 'Z':
case 'm':
l = 4;
- if(HEADTYPE == Hplan9x64 && !debug['8']) {
+ if(HEADTYPE == Hplan9 && thechar == '6' && !debug['8']) {
lputb(addr>>32);
l = 8;
}
@@ -263,14 +263,14 @@ asmplan9sym(void)
genasmsym(putplan9sym);
}
-static Sym *symt;
+static LSym *symt;
static void
scput(int b)
{
uchar *p;
- symgrow(symt, symt->size+1);
+ symgrow(ctxt, symt, symt->size+1);
p = symt->p + symt->size;
*p = b;
symt->size++;
@@ -281,7 +281,7 @@ slputb(int32 v)
{
uchar *p;
- symgrow(symt, symt->size+4);
+ symgrow(ctxt, symt, symt->size+4);
p = symt->p + symt->size;
*p++ = v>>24;
*p++ = v>>16;
@@ -295,7 +295,7 @@ slputl(int32 v)
{
uchar *p;
- symgrow(symt, symt->size+4);
+ symgrow(ctxt, symt, symt->size+4);
p = symt->p + symt->size;
*p++ = v;
*p++ = v>>8;
@@ -355,7 +355,7 @@ vputl(uint64 v)
// Emit symbol table entry.
// The table format is described at the top of ../../pkg/runtime/symtab.c.
void
-putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
+putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ)
{
int i, f, c;
vlong v1;
@@ -457,7 +457,7 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
void
symtab(void)
{
- Sym *s, *symtype, *symtypelink, *symgostring, *symgofunc;
+ LSym *s, *symtype, *symtypelink, *symgostring, *symgofunc;
dosymtype();
@@ -482,40 +482,40 @@ symtab(void)
xdefine("esymtab", SRODATA, 0);
// garbage collection symbols
- s = lookup("gcdata", 0);
+ s = linklookup(ctxt, "gcdata", 0);
s->type = SRODATA;
s->size = 0;
s->reachable = 1;
xdefine("egcdata", SRODATA, 0);
- s = lookup("gcbss", 0);
+ s = linklookup(ctxt, "gcbss", 0);
s->type = SRODATA;
s->size = 0;
s->reachable = 1;
xdefine("egcbss", SRODATA, 0);
// pseudo-symbols to mark locations of type, string, and go string data.
- s = lookup("type.*", 0);
+ s = linklookup(ctxt, "type.*", 0);
s->type = STYPE;
s->size = 0;
s->reachable = 1;
symtype = s;
- s = lookup("go.string.*", 0);
+ s = linklookup(ctxt, "go.string.*", 0);
s->type = SGOSTRING;
s->size = 0;
s->reachable = 1;
symgostring = s;
- s = lookup("go.func.*", 0);
+ s = linklookup(ctxt, "go.func.*", 0);
s->type = SGOFUNC;
s->size = 0;
s->reachable = 1;
symgofunc = s;
- symtypelink = lookup("typelink", 0);
+ symtypelink = linklookup(ctxt, "typelink", 0);
- symt = lookup("symtab", 0);
+ symt = linklookup(ctxt, "symtab", 0);
symt->type = SSYMTAB;
symt->size = 0;
symt->reachable = 1;
@@ -524,7 +524,7 @@ symtab(void)
// within a type they sort by size, so the .* symbols
// just defined above will be first.
// hide the specific symbols.
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(!s->reachable || s->special || s->type != SRODATA)
continue;
if(strncmp(s->name, "type.", 5) == 0) {
diff --git a/src/liblink/Makefile b/src/liblink/Makefile
new file mode 100644
index 000000000..2a317462b
--- /dev/null
+++ b/src/liblink/Makefile
@@ -0,0 +1,5 @@
+# Copyright 2013 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../Make.dist
diff --git a/src/liblink/asm5.c b/src/liblink/asm5.c
new file mode 100644
index 000000000..8ed8bea57
--- /dev/null
+++ b/src/liblink/asm5.c
@@ -0,0 +1,2443 @@
+// Inferno utils/5l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Instruction layout.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/5l/5.out.h"
+#include "../pkg/runtime/stack.h"
+
+typedef struct Optab Optab;
+typedef struct Oprang Oprang;
+typedef uchar Opcross[32][2][32];
+
+struct Optab
+{
+ char as;
+ uchar a1;
+ char a2;
+ uchar a3;
+ uchar type;
+ char size;
+ char param;
+ char flag;
+ uchar pcrelsiz;
+};
+struct Oprang
+{
+ Optab* start;
+ Optab* stop;
+};
+
+enum
+{
+ LFROM = 1<<0,
+ LTO = 1<<1,
+ LPOOL = 1<<2,
+ LPCREL = 1<<3,
+
+ C_NONE = 0,
+ C_REG,
+ C_REGREG,
+ C_REGREG2,
+ C_SHIFT,
+ C_FREG,
+ C_PSR,
+ C_FCR,
+
+ C_RCON, /* 0xff rotated */
+ C_NCON, /* ~RCON */
+ C_SCON, /* 0xffff */
+ C_LCON,
+ C_LCONADDR,
+ C_ZFCON,
+ C_SFCON,
+ C_LFCON,
+
+ C_RACON,
+ C_LACON,
+
+ C_SBRA,
+ C_LBRA,
+
+ C_HAUTO, /* halfword insn offset (-0xff to 0xff) */
+ C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */
+ C_HFAUTO, /* both H and F */
+ C_SAUTO, /* -0xfff to 0xfff */
+ C_LAUTO,
+
+ C_HOREG,
+ C_FOREG,
+ C_HFOREG,
+ C_SOREG,
+ C_ROREG,
+ C_SROREG, /* both nil and R */
+ C_LOREG,
+
+ C_PC,
+ C_SP,
+ C_HREG,
+
+ C_ADDR, /* reference to relocatable address */
+
+ C_GOK,
+};
+
+static Optab optab[] =
+{
+ /* struct Optab:
+ OPCODE, from, prog->reg, to, type,size,param,flag */
+ { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
+
+ { AADD, C_REG, C_REG, C_REG, 1, 4, 0 },
+ { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 },
+
+ { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 },
+ { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 },
+ { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 },
+ { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 },
+ { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 },
+
+ { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 },
+ { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
+ { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
+ { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 },
+
+ { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP },
+
+ { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL },
+ { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
+ { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 },
+ { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
+
+ { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL },
+ { ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0 },
+ { ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0 },
+ { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 },
+ { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 },
+
+ { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 },
+ { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 },
+
+ { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 },
+ { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 },
+
+ { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 },
+ { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 },
+ { ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 },
+
+ { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 },
+
+ { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 },
+ { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM },
+ { AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4},
+
+ { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 },
+ { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 },
+ { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 },
+ { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 },
+ { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM },
+ { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
+ { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
+ { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM },
+
+ { AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0 },
+ { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 },
+ { AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0 },
+ { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 },
+
+ { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 },
+ { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 },
+
+ { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 },
+ { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 },
+
+ { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 },
+ { AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
+ { AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
+ { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+ { AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
+ { AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+ { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
+ { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+
+ { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
+ { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
+ { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
+ { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
+ { AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
+ { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
+ { AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
+ { AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
+ { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
+ { AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
+ { AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
+ { AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
+ { AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
+ { AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
+ { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
+
+ { AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
+ { AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
+ { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 },
+ { AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
+ { AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
+ { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 },
+
+ { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM },
+
+ { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 },
+ { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 },
+
+ { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 },
+ { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 },
+
+ { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 },
+
+ { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 },
+
+ { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP },
+ { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 },
+
+ { AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP },
+ { AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 },
+
+ { AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO },
+ { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO },
+
+ { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM },
+ { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM },
+
+ { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4 },
+ { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4},
+
+ { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
+ { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 },
+ { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 },
+ { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 },
+
+ { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
+ { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
+
+ { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 },
+ { AMOVBS, C_SHIFT,C_NONE, C_REG, 60, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+ { AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+ { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+
+ { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8 },
+ { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, LPCREL, 0 },
+
+ { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
+ { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
+ { AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
+ { AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
+ { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
+ { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
+
+ { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVBS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVBS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVHS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVHS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+
+ { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
+ { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
+ { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
+ { AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
+ { AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
+ { AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
+ { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
+ { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
+
+ { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
+ { AMOVBS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVBS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
+ { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
+ { AMOVHS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVHS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
+ { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
+
+ { ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 },
+ { ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 },
+
+ { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 8, 0 },
+ { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 },
+
+ { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 },
+ { ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0 },
+
+ { AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0 },
+ { AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0 },
+
+ { AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0 },
+ { AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 },
+ { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 },
+
+ { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 },
+
+ { ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 },
+ { ASTREXD, C_SOREG,C_REG, C_REG, 92, 4, 0 },
+
+ { APLD, C_SOREG,C_NONE, C_NONE, 95, 4, 0 },
+
+ { AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0 },
+
+ { ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0 },
+
+ { AMULWT, C_REG, C_REG, C_REG, 98, 4, 0 },
+ { AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0 },
+
+ { AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0 },
+ { APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0 },
+ { AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0 },
+
+ { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
+};
+
+static struct {
+ uint32 start;
+ uint32 size;
+ uint32 extra;
+} pool;
+
+static int checkpool(Link*, Prog*, int);
+static int flushpool(Link*, Prog*, int, int);
+static void addpool(Link*, Prog*, Addr*);
+static void asmout(Link*, Prog*, Optab*, int32*, LSym*);
+static Optab* oplook(Link*, Prog*);
+static int32 oprrr(Link*, int, int);
+static int32 olr(Link*, int32, int, int, int);
+static int32 olhr(Link*, int32, int, int, int);
+static int32 olrr(Link*, int, int, int, int);
+static int32 olhrr(Link*, int, int, int, int);
+static int32 osr(Link*, int, int, int32, int, int);
+static int32 oshr(Link*, int, int32, int, int);
+static int32 ofsr(Link*, int, int, int32, int, int, Prog*);
+static int32 osrr(Link*, int, int, int, int);
+static int32 oshrr(Link*, int, int, int, int);
+static int32 omvl(Link*, Prog*, Addr*, int);
+static int32 immaddr(int32);
+static int aclass(Link*, Addr*);
+static int chipzero(Link*, float64);
+static int chipfloat(Link*, float64);
+static int32 immrot(uint32);
+static int32 immaddr(int32);
+static int32 opbra(Link*, int, int);
+
+static Opcross opcross[8];
+static Oprang oprange[ALAST];
+static char xcmp[C_GOK+1][C_GOK+1];
+static uchar repop[ALAST];
+
+static Prog zprg = {
+ .as = AGOK,
+ .scond = 14,
+ .reg = NREG,
+ .from = {
+ .name = D_NONE,
+ .type = D_NONE,
+ .reg = NREG,
+ },
+ .to = {
+ .name = D_NONE,
+ .type = D_NONE,
+ .reg = NREG,
+ },
+};
+
+static void
+nocache(Prog *p)
+{
+ p->optab = 0;
+ p->from.class = 0;
+ p->to.class = 0;
+}
+
+static int
+scan(Link *ctxt, Prog *op, Prog *p, int c)
+{
+ Prog *q;
+
+ for(q = op->link; q != p && q != nil; q = q->link){
+ q->pc = c;
+ c += oplook(ctxt, q)->size;
+ nocache(q);
+ }
+ return c;
+}
+
+/* size of a case statement including jump table */
+static int32
+casesz(Link *ctxt, Prog *p)
+{
+ int jt = 0;
+ int32 n = 0;
+ Optab *o;
+
+ for( ; p != nil; p = p->link){
+ if(p->as == ABCASE)
+ jt = 1;
+ else if(jt)
+ break;
+ o = oplook(ctxt, p);
+ n += o->size;
+ }
+ return n;
+}
+
+static void buildop(Link*);
+
+void
+span5(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *op;
+ Optab *o;
+ int m, bflag, i, v;
+ int32 c, out[6];
+ uchar *bp;
+ LSym *gmsym;
+
+ p = cursym->text;
+ if(p == nil || p->link == nil) // handle external functions and ELF section symbols
+ return;
+
+ if(oprange[AAND].start == nil)
+ buildop(ctxt);
+
+ ctxt->cursym = cursym;
+
+ ctxt->autosize = p->to.offset + 4;
+ c = 0;
+
+ for(op = p, p = p->link; p != nil; op = p, p = p->link) {
+ ctxt->curp = p;
+ p->pc = c;
+ o = oplook(ctxt, p);
+ m = o->size;
+ // must check literal pool here in case p generates many instructions
+ if(ctxt->blitrl){
+ if(checkpool(ctxt, op, p->as == ACASE ? casesz(ctxt, p) : m))
+ c = p->pc = scan(ctxt, op, p, c);
+ }
+ if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) {
+ ctxt->diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ switch(o->flag & (LFROM|LTO|LPOOL)) {
+ case LFROM:
+ addpool(ctxt, p, &p->from);
+ break;
+ case LTO:
+ addpool(ctxt, p, &p->to);
+ break;
+ case LPOOL:
+ if ((p->scond&C_SCOND) == 14)
+ flushpool(ctxt, p, 0, 0);
+ break;
+ }
+ if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
+ flushpool(ctxt, p, 0, 0);
+ c += m;
+ }
+ if(ctxt->blitrl){
+ if(checkpool(ctxt, op, 0))
+ c = scan(ctxt, op, nil, c);
+ }
+ cursym->size = c;
+
+ /*
+ * if any procedure is large enough to
+ * generate a large SBRA branch, then
+ * generate extra passes putting branches
+ * around jmps to fix. this is rare.
+ */
+ do {
+ if(ctxt->debugvlog)
+ Bprint(ctxt->bso, "%5.2f span1\n", cputime());
+ bflag = 0;
+ c = 0;
+ for(p = cursym->text; p != nil; p = p->link) {
+ ctxt->curp = p;
+ p->pc = c;
+ o = oplook(ctxt,p);
+/* very large branches
+ if(o->type == 6 && p->pcond) {
+ otxt = p->pcond->pc - c;
+ if(otxt < 0)
+ otxt = -otxt;
+ if(otxt >= (1L<<17) - 10) {
+ q = ctxt->arch->prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->pcond = p->pcond;
+ p->pcond = q;
+ q = ctxt->arch->prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->pcond = q->link->link;
+ bflag = 1;
+ }
+ }
+ */
+ m = o->size;
+ if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) {
+ if(p->as == ATEXT) {
+ ctxt->autosize = p->to.offset + 4;
+ continue;
+ }
+ ctxt->diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+ cursym->size = c;
+ } while(bflag);
+
+ c += c&4;
+
+ /*
+ * lay out the code. all the pc-relative code references,
+ * even cross-function, are resolved now;
+ * only data references need to be relocated.
+ * with more work we could leave cross-function
+ * code references to be relocated too, and then
+ * perhaps we'd be able to parallelize the span loop above.
+ */
+ gmsym = nil;
+ if(ctxt->linkmode == LinkExternal)
+ gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
+
+ p = cursym->text;
+ ctxt->autosize = p->to.offset + 4;
+ symgrow(ctxt, cursym, cursym->size);
+
+ bp = cursym->p;
+ for(p = p->link; p != nil; p = p->link) {
+ ctxt->pc = p->pc;
+ ctxt->curp = p;
+ o = oplook(ctxt, p);
+ asmout(ctxt, p, o, out, gmsym);
+ for(i=0; i<o->size/4; i++) {
+ v = out[i];
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp++ = v>>24;
+ }
+ }
+}
+
+/*
+ * when the first reference to the literal pool threatens
+ * to go out of range of a 12-bit PC-relative offset,
+ * drop the pool now, and branch round it.
+ * this happens only in extended basic blocks that exceed 4k.
+ */
+static int
+checkpool(Link *ctxt, Prog *p, int sz)
+{
+ if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
+ return flushpool(ctxt, p, 1, 0);
+ else if(p->link == nil)
+ return flushpool(ctxt, p, 2, 0);
+ return 0;
+}
+
+static int
+flushpool(Link *ctxt, Prog *p, int skip, int force)
+{
+ Prog *q;
+
+ if(ctxt->blitrl) {
+ if(skip){
+ if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
+ q = ctxt->arch->prg();
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->pcond = p->link;
+ q->link = ctxt->blitrl;
+ q->lineno = p->lineno;
+ ctxt->blitrl = q;
+ }
+ else if(!force && (p->pc+pool.size-pool.start < 2048))
+ return 0;
+ ctxt->elitrl->link = p->link;
+ p->link = ctxt->blitrl;
+ // BUG(minux): how to correctly handle line number for constant pool entries?
+ // for now, we set line number to the last instruction preceding them at least
+ // this won't bloat the .debug_line tables
+ while(ctxt->blitrl) {
+ ctxt->blitrl->lineno = p->lineno;
+ ctxt->blitrl = ctxt->blitrl->link;
+ }
+ ctxt->blitrl = 0; /* BUG: should refer back to values until out-of-range */
+ ctxt->elitrl = 0;
+ pool.size = 0;
+ pool.start = 0;
+ pool.extra = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static void
+addpool(Link *ctxt, Prog *p, Addr *a)
+{
+ Prog *q, t;
+ int c;
+
+ c = aclass(ctxt, a);
+
+ t = zprg;
+ t.as = AWORD;
+
+ switch(c) {
+ default:
+ t.to = *a;
+ if(ctxt->flag_shared && t.to.sym != nil)
+ t.pcrel = p;
+ break;
+
+ case C_SROREG:
+ case C_LOREG:
+ case C_ROREG:
+ case C_FOREG:
+ case C_SOREG:
+ case C_HOREG:
+ case C_FAUTO:
+ case C_SAUTO:
+ case C_LAUTO:
+ case C_LACON:
+ t.to.type = D_CONST;
+ t.to.offset = ctxt->instoffset;
+ break;
+ }
+
+ if(t.pcrel == nil) {
+ for(q = ctxt->blitrl; q != nil; q = q->link) /* could hash on t.t0.offset */
+ if(q->pcrel == nil && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
+ p->pcond = q;
+ return;
+ }
+ }
+
+ q = ctxt->arch->prg();
+ *q = t;
+ q->pc = pool.size;
+
+ if(ctxt->blitrl == nil) {
+ ctxt->blitrl = q;
+ pool.start = p->pc;
+ } else
+ ctxt->elitrl->link = q;
+ ctxt->elitrl = q;
+ pool.size += 4;
+
+ p->pcond = q;
+}
+
+static int32
+regoff(Link *ctxt, Addr *a)
+{
+
+ ctxt->instoffset = 0;
+ aclass(ctxt, a);
+ return ctxt->instoffset;
+}
+
+static int32
+immrot(uint32 v)
+{
+ int i;
+
+ for(i=0; i<16; i++) {
+ if((v & ~0xff) == 0)
+ return (i<<8) | v | (1<<25);
+ v = (v<<2) | (v>>30);
+ }
+ return 0;
+}
+
+static int32
+immaddr(int32 v)
+{
+ if(v >= 0 && v <= 0xfff)
+ return (v & 0xfff) |
+ (1<<24) | /* pre indexing */
+ (1<<23); /* pre indexing, up */
+ if(v >= -0xfff && v < 0)
+ return (-v & 0xfff) |
+ (1<<24); /* pre indexing */
+ return 0;
+}
+
+static int
+immfloat(int32 v)
+{
+ return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */
+}
+
+static int
+immhalf(int32 v)
+{
+ if(v >= 0 && v <= 0xff)
+ return v|
+ (1<<24)| /* pre indexing */
+ (1<<23); /* pre indexing, up */
+ if(v >= -0xff && v < 0)
+ return (-v & 0xff)|
+ (1<<24); /* pre indexing */
+ return 0;
+}
+
+static int
+aclass(Link *ctxt, Addr *a)
+{
+ LSym *s;
+ int t;
+
+ switch(a->type) {
+ case D_NONE:
+ return C_NONE;
+
+ case D_REG:
+ return C_REG;
+
+ case D_REGREG:
+ return C_REGREG;
+
+ case D_REGREG2:
+ return C_REGREG2;
+
+ case D_SHIFT:
+ return C_SHIFT;
+
+ case D_FREG:
+ return C_FREG;
+
+ case D_FPCR:
+ return C_FCR;
+
+ case D_OREG:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(a->sym == 0 || a->sym->name == 0) {
+ print("null sym external\n");
+ print("%D\n", a);
+ return C_GOK;
+ }
+ ctxt->instoffset = 0; // s.b. unused but just in case
+ return C_ADDR;
+
+ case D_AUTO:
+ ctxt->instoffset = ctxt->autosize + a->offset;
+ t = immaddr(ctxt->instoffset);
+ if(t){
+ if(immhalf(ctxt->instoffset))
+ return immfloat(t) ? C_HFAUTO : C_HAUTO;
+ if(immfloat(t))
+ return C_FAUTO;
+ return C_SAUTO;
+ }
+ return C_LAUTO;
+
+ case D_PARAM:
+ ctxt->instoffset = ctxt->autosize + a->offset + 4L;
+ t = immaddr(ctxt->instoffset);
+ if(t){
+ if(immhalf(ctxt->instoffset))
+ return immfloat(t) ? C_HFAUTO : C_HAUTO;
+ if(immfloat(t))
+ return C_FAUTO;
+ return C_SAUTO;
+ }
+ return C_LAUTO;
+ case D_NONE:
+ ctxt->instoffset = a->offset;
+ t = immaddr(ctxt->instoffset);
+ if(t) {
+ if(immhalf(ctxt->instoffset)) /* n.b. that it will also satisfy immrot */
+ return immfloat(t) ? C_HFOREG : C_HOREG;
+ if(immfloat(t))
+ return C_FOREG; /* n.b. that it will also satisfy immrot */
+ t = immrot(ctxt->instoffset);
+ if(t)
+ return C_SROREG;
+ if(immhalf(ctxt->instoffset))
+ return C_HOREG;
+ return C_SOREG;
+ }
+ t = immrot(ctxt->instoffset);
+ if(t)
+ return C_ROREG;
+ return C_LOREG;
+ }
+ return C_GOK;
+
+ case D_PSR:
+ return C_PSR;
+
+ case D_OCONST:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ ctxt->instoffset = 0; // s.b. unused but just in case
+ return C_ADDR;
+ }
+ return C_GOK;
+
+ case D_FCONST:
+ if(chipzero(ctxt, a->u.dval) >= 0)
+ return C_ZFCON;
+ if(chipfloat(ctxt, a->u.dval) >= 0)
+ return C_SFCON;
+ return C_LFCON;
+
+ case D_CONST:
+ case D_CONST2:
+ switch(a->name) {
+
+ case D_NONE:
+ ctxt->instoffset = a->offset;
+ if(a->reg != NREG)
+ goto aconsize;
+
+ t = immrot(ctxt->instoffset);
+ if(t)
+ return C_RCON;
+ t = immrot(~ctxt->instoffset);
+ if(t)
+ return C_NCON;
+ return C_LCON;
+
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ if(s == nil)
+ break;
+ ctxt->instoffset = 0; // s.b. unused but just in case
+ return C_LCONADDR;
+
+ case D_AUTO:
+ ctxt->instoffset = ctxt->autosize + a->offset;
+ goto aconsize;
+
+ case D_PARAM:
+ ctxt->instoffset = ctxt->autosize + a->offset + 4L;
+ aconsize:
+ t = immrot(ctxt->instoffset);
+ if(t)
+ return C_RACON;
+ return C_LACON;
+ }
+ return C_GOK;
+
+ case D_BRANCH:
+ return C_SBRA;
+ }
+ return C_GOK;
+}
+
+static void
+prasm(Prog *p)
+{
+ print("%P\n", p);
+}
+
+static Optab*
+oplook(Link *ctxt, Prog *p)
+{
+ int a1, a2, a3, r;
+ char *c1, *c3;
+ Optab *o, *e;
+
+ a1 = p->optab;
+ if(a1)
+ return optab+(a1-1);
+ a1 = p->from.class;
+ if(a1 == 0) {
+ a1 = aclass(ctxt, &p->from) + 1;
+ p->from.class = a1;
+ }
+ a1--;
+ a3 = p->to.class;
+ if(a3 == 0) {
+ a3 = aclass(ctxt, &p->to) + 1;
+ p->to.class = a3;
+ }
+ a3--;
+ a2 = C_NONE;
+ if(p->reg != NREG)
+ a2 = C_REG;
+ r = p->as;
+ o = oprange[r].start;
+ if(o == 0) {
+ a1 = opcross[repop[r]][a1][a2][a3];
+ if(a1) {
+ p->optab = a1+1;
+ return optab+a1;
+ }
+ o = oprange[r].stop; /* just generate an error */
+ }
+ if(0 /*debug['O']*/) {
+ print("oplook %A %O %O %O\n",
+ (int)p->as, a1, a2, a3);
+ print(" %d %d\n", p->from.type, p->to.type);
+ }
+ e = oprange[r].stop;
+ c1 = xcmp[a1];
+ c3 = xcmp[a3];
+ for(; o<e; o++)
+ if(o->a2 == a2)
+ if(c1[o->a1])
+ if(c3[o->a3]) {
+ p->optab = (o-optab)+1;
+ return o;
+ }
+ ctxt->diag("illegal combination %A %O %O %O, %d %d",
+ p->as, a1, a2, a3, p->from.type, p->to.type);
+ prasm(p);
+ if(o == 0)
+ o = optab;
+ return o;
+}
+
+static int
+cmp(int a, int b)
+{
+
+ if(a == b)
+ return 1;
+ switch(a) {
+ case C_LCON:
+ if(b == C_RCON || b == C_NCON)
+ return 1;
+ break;
+ case C_LACON:
+ if(b == C_RACON)
+ return 1;
+ break;
+ case C_LFCON:
+ if(b == C_ZFCON || b == C_SFCON)
+ return 1;
+ break;
+
+ case C_HFAUTO:
+ return b == C_HAUTO || b == C_FAUTO;
+ case C_FAUTO:
+ case C_HAUTO:
+ return b == C_HFAUTO;
+ case C_SAUTO:
+ return cmp(C_HFAUTO, b);
+ case C_LAUTO:
+ return cmp(C_SAUTO, b);
+
+ case C_HFOREG:
+ return b == C_HOREG || b == C_FOREG;
+ case C_FOREG:
+ case C_HOREG:
+ return b == C_HFOREG;
+ case C_SROREG:
+ return cmp(C_SOREG, b) || cmp(C_ROREG, b);
+ case C_SOREG:
+ case C_ROREG:
+ return b == C_SROREG || cmp(C_HFOREG, b);
+ case C_LOREG:
+ return cmp(C_SROREG, b);
+
+ case C_LBRA:
+ if(b == C_SBRA)
+ return 1;
+ break;
+
+ case C_HREG:
+ return cmp(C_SP, b) || cmp(C_PC, b);
+
+ }
+ return 0;
+}
+
+static int
+ocmp(const void *a1, const void *a2)
+{
+ Optab *p1, *p2;
+ int n;
+
+ p1 = (Optab*)a1;
+ p2 = (Optab*)a2;
+ n = p1->as - p2->as;
+ if(n)
+ return n;
+ n = p1->a1 - p2->a1;
+ if(n)
+ return n;
+ n = p1->a2 - p2->a2;
+ if(n)
+ return n;
+ n = p1->a3 - p2->a3;
+ if(n)
+ return n;
+ return 0;
+}
+
+static void
+buildop(Link *ctxt)
+{
+ int i, n, r;
+
+ for(i=0; i<C_GOK; i++)
+ for(n=0; n<C_GOK; n++)
+ xcmp[i][n] = cmp(n, i);
+ for(n=0; optab[n].as != AXXX; n++) {
+ if((optab[n].flag & LPCREL) != 0) {
+ if(ctxt->flag_shared)
+ optab[n].size += optab[n].pcrelsiz;
+ else
+ optab[n].flag &= ~LPCREL;
+ }
+ }
+ qsort(optab, n, sizeof(optab[0]), ocmp);
+ for(i=0; i<n; i++) {
+ r = optab[i].as;
+ oprange[r].start = optab+i;
+ while(optab[i].as == r)
+ i++;
+ oprange[r].stop = optab+i;
+ i--;
+
+ switch(r)
+ {
+ default:
+ ctxt->diag("unknown op in build: %A", r);
+ sysfatal("bad code");
+ case AADD:
+ oprange[AAND] = oprange[r];
+ oprange[AEOR] = oprange[r];
+ oprange[ASUB] = oprange[r];
+ oprange[ARSB] = oprange[r];
+ oprange[AADC] = oprange[r];
+ oprange[ASBC] = oprange[r];
+ oprange[ARSC] = oprange[r];
+ oprange[AORR] = oprange[r];
+ oprange[ABIC] = oprange[r];
+ break;
+ case ACMP:
+ oprange[ATEQ] = oprange[r];
+ oprange[ACMN] = oprange[r];
+ break;
+ case AMVN:
+ break;
+ case ABEQ:
+ oprange[ABNE] = oprange[r];
+ oprange[ABCS] = oprange[r];
+ oprange[ABHS] = oprange[r];
+ oprange[ABCC] = oprange[r];
+ oprange[ABLO] = oprange[r];
+ oprange[ABMI] = oprange[r];
+ oprange[ABPL] = oprange[r];
+ oprange[ABVS] = oprange[r];
+ oprange[ABVC] = oprange[r];
+ oprange[ABHI] = oprange[r];
+ oprange[ABLS] = oprange[r];
+ oprange[ABGE] = oprange[r];
+ oprange[ABLT] = oprange[r];
+ oprange[ABGT] = oprange[r];
+ oprange[ABLE] = oprange[r];
+ break;
+ case ASLL:
+ oprange[ASRL] = oprange[r];
+ oprange[ASRA] = oprange[r];
+ break;
+ case AMUL:
+ oprange[AMULU] = oprange[r];
+ break;
+ case ADIV:
+ oprange[AMOD] = oprange[r];
+ oprange[AMODU] = oprange[r];
+ oprange[ADIVU] = oprange[r];
+ break;
+ case AMOVW:
+ case AMOVB:
+ case AMOVBS:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHS:
+ case AMOVHU:
+ break;
+ case ASWPW:
+ oprange[ASWPBU] = oprange[r];
+ break;
+ case AB:
+ case ABL:
+ case ABX:
+ case ABXRET:
+ case ASWI:
+ case AWORD:
+ case AMOVM:
+ case ARFE:
+ case ATEXT:
+ case AUSEFIELD:
+ case ACASE:
+ case ABCASE:
+ case ATYPE:
+ break;
+ case AADDF:
+ oprange[AADDD] = oprange[r];
+ oprange[ASUBF] = oprange[r];
+ oprange[ASUBD] = oprange[r];
+ oprange[AMULF] = oprange[r];
+ oprange[AMULD] = oprange[r];
+ oprange[ADIVF] = oprange[r];
+ oprange[ADIVD] = oprange[r];
+ oprange[ASQRTF] = oprange[r];
+ oprange[ASQRTD] = oprange[r];
+ oprange[AMOVFD] = oprange[r];
+ oprange[AMOVDF] = oprange[r];
+ oprange[AABSF] = oprange[r];
+ oprange[AABSD] = oprange[r];
+ break;
+
+ case ACMPF:
+ oprange[ACMPD] = oprange[r];
+ break;
+
+ case AMOVF:
+ oprange[AMOVD] = oprange[r];
+ break;
+
+ case AMOVFW:
+ oprange[AMOVDW] = oprange[r];
+ break;
+
+ case AMOVWF:
+ oprange[AMOVWD] = oprange[r];
+ break;
+
+ case AMULL:
+ oprange[AMULAL] = oprange[r];
+ oprange[AMULLU] = oprange[r];
+ oprange[AMULALU] = oprange[r];
+ break;
+
+ case AMULWT:
+ oprange[AMULWB] = oprange[r];
+ break;
+
+ case AMULAWT:
+ oprange[AMULAWB] = oprange[r];
+ break;
+
+ case AMULA:
+ case ALDREX:
+ case ASTREX:
+ case ALDREXD:
+ case ASTREXD:
+ case ATST:
+ case APLD:
+ case AUNDEF:
+ case ACLZ:
+ case AFUNCDATA:
+ case APCDATA:
+ break;
+ }
+ }
+}
+
+void
+asmout(Link *ctxt, Prog *p, Optab *o, int32 *out, LSym *gmsym)
+{
+ int32 o1, o2, o3, o4, o5, o6, v;
+ int r, rf, rt, rt2;
+ Reloc *rel;
+
+ctxt->printp = p;
+ o1 = 0;
+ o2 = 0;
+ o3 = 0;
+ o4 = 0;
+ o5 = 0;
+ o6 = 0;
+ ctxt->armsize += o->size;
+if(0 /*debug['P']*/) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type);
+ switch(o->type) {
+ default:
+ ctxt->diag("unknown asm %d", o->type);
+ prasm(p);
+ break;
+
+ case 0: /* pseudo ops */
+if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr);
+ break;
+
+ case 1: /* op R,[R],R */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(p->as == AMOVB || p->as == AMOVH || p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else
+ if(r == NREG)
+ r = rt;
+ o1 |= rf | (r<<16) | (rt<<12);
+ break;
+
+ case 2: /* movbu $I,[R],R */
+ aclass(ctxt, &p->from);
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= immrot(ctxt->instoffset);
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ break;
+
+ case 3: /* add R<<[IR],[R],R */
+ mov:
+ aclass(ctxt, &p->from);
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= p->from.offset;
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ break;
+
+ case 4: /* add $I,[R],R */
+ aclass(ctxt, &p->from);
+ o1 = oprrr(ctxt, AADD, p->scond);
+ o1 |= immrot(ctxt->instoffset);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 |= r << 16;
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 5: /* bra s */
+ o1 = opbra(ctxt, p->as, p->scond);
+ v = -8;
+ if(p->to.sym != nil) {
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 4;
+ rel->sym = p->to.sym;
+ rel->add = o1 | ((v >> 2) & 0xffffff);
+ rel->type = D_CALL;
+ break;
+ }
+ if(p->pcond != nil)
+ v = (p->pcond->pc - ctxt->pc) - 8;
+ o1 |= (v >> 2) & 0xffffff;
+ break;
+
+ case 6: /* b ,O(R) -> add $O,R,PC */
+ aclass(ctxt, &p->to);
+ o1 = oprrr(ctxt, AADD, p->scond);
+ o1 |= immrot(ctxt->instoffset);
+ o1 |= p->to.reg << 16;
+ o1 |= REGPC << 12;
+ break;
+
+ case 7: /* bl (R) -> blx R */
+ aclass(ctxt, &p->to);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("%P: doesn't support BL offset(REG) where offset != 0", p);
+ o1 = oprrr(ctxt, ABL, p->scond);
+ o1 |= p->to.reg;
+ break;
+
+ case 8: /* sll $c,[R],R -> mov (R<<$c),R */
+ aclass(ctxt, &p->from);
+ o1 = oprrr(ctxt, p->as, p->scond);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 |= r;
+ o1 |= (ctxt->instoffset&31) << 7;
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 9: /* sll R,[R],R -> mov (R<<R),R */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 |= r;
+ o1 |= (p->from.reg << 8) | (1<<4);
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 10: /* swi [$con] */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ if(p->to.type != D_NONE) {
+ aclass(ctxt, &p->to);
+ o1 |= ctxt->instoffset & 0xffffff;
+ }
+ break;
+
+ case 11: /* word */
+ aclass(ctxt, &p->to);
+ o1 = ctxt->instoffset;
+ if(p->to.sym != nil) {
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 4;
+ rel->sym = p->to.sym;
+ rel->add = p->to.offset;
+ if(rel->sym == gmsym) {
+ rel->type = D_TLS;
+ if(ctxt->flag_shared)
+ rel->add += ctxt->pc - p->pcrel->pc - 8 - rel->siz;
+ rel->xadd = rel->add;
+ rel->xsym = rel->sym;
+ } else if(ctxt->flag_shared) {
+ rel->type = D_PCREL;
+ rel->add += ctxt->pc - p->pcrel->pc - 8;
+ } else
+ rel->type = D_ADDR;
+ o1 = 0;
+ }
+ break;
+
+ case 12: /* movw $lcon, reg */
+ o1 = omvl(ctxt, p, &p->from, p->to.reg);
+ if(o->flag & LPCREL) {
+ o2 = oprrr(ctxt, AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12;
+ }
+ break;
+
+ case 13: /* op $lcon, [R], R */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = oprrr(ctxt, p->as, p->scond);
+ o2 |= REGTMP;
+ r = p->reg;
+ if(p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else if(r == NREG)
+ r = p->to.reg;
+ o2 |= r << 16;
+ if(p->to.type != D_NONE)
+ o2 |= p->to.reg << 12;
+ break;
+
+ case 14: /* movb/movbu/movh/movhu R,R */
+ o1 = oprrr(ctxt, ASLL, p->scond);
+
+ if(p->as == AMOVBU || p->as == AMOVHU)
+ o2 = oprrr(ctxt, ASRL, p->scond);
+ else
+ o2 = oprrr(ctxt, ASRA, p->scond);
+
+ r = p->to.reg;
+ o1 |= (p->from.reg)|(r<<12);
+ o2 |= (r)|(r<<12);
+ if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) {
+ o1 |= (24<<7);
+ o2 |= (24<<7);
+ } else {
+ o1 |= (16<<7);
+ o2 |= (16<<7);
+ }
+ break;
+
+ case 15: /* mul r,[r,]r */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ if(r == NREG)
+ r = rt;
+ if(rt == r) {
+ r = rf;
+ rf = rt;
+ }
+ if(0)
+ if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) {
+ ctxt->diag("bad registers in MUL");
+ prasm(p);
+ }
+ o1 |= (rf<<8) | r | (rt<<16);
+ break;
+
+
+ case 16: /* div r,[r,]r */
+ o1 = 0xf << 28;
+ o2 = 0;
+ break;
+
+ case 17:
+ o1 = oprrr(ctxt, p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ rt2 = p->to.offset;
+ r = p->reg;
+ o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12);
+ break;
+
+ case 20: /* mov/movb/movbu R,O(R) */
+ aclass(ctxt, &p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = osr(ctxt, p->as, p->from.reg, ctxt->instoffset, r, p->scond);
+ break;
+
+ case 21: /* mov/movbu O(R),R -> lr */
+ aclass(ctxt, &p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = olr(ctxt, ctxt->instoffset, r, p->to.reg, p->scond);
+ if(p->as != AMOVW)
+ o1 |= 1<<22;
+ break;
+
+ case 30: /* mov/movb/movbu R,L(R) */
+ o1 = omvl(ctxt, p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = osrr(ctxt, p->from.reg, REGTMP,r, p->scond);
+ if(p->as != AMOVW)
+ o2 |= 1<<22;
+ break;
+
+ case 31: /* mov/movbu L(R),R -> lr[b] */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = olrr(ctxt, REGTMP,r, p->to.reg, p->scond);
+ if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB)
+ o2 |= 1<<22;
+ break;
+
+ case 34: /* mov $lacon,R */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+
+ o2 = oprrr(ctxt, AADD, p->scond);
+ o2 |= REGTMP;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 |= r << 16;
+ if(p->to.type != D_NONE)
+ o2 |= p->to.reg << 12;
+ break;
+
+ case 35: /* mov PSR,R */
+ o1 = (2<<23) | (0xf<<16) | (0<<0);
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= (p->from.reg & 1) << 22;
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 36: /* mov R,PSR */
+ o1 = (2<<23) | (0x29f<<12) | (0<<4);
+ if(p->scond & C_FBIT)
+ o1 ^= 0x010 << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= (p->to.reg & 1) << 22;
+ o1 |= p->from.reg << 0;
+ break;
+
+ case 37: /* mov $con,PSR */
+ aclass(ctxt, &p->from);
+ o1 = (2<<23) | (0x29f<<12) | (0<<4);
+ if(p->scond & C_FBIT)
+ o1 ^= 0x010 << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= immrot(ctxt->instoffset);
+ o1 |= (p->to.reg & 1) << 22;
+ o1 |= p->from.reg << 0;
+ break;
+
+ case 38: /* movm $con,oreg -> stm */
+ o1 = (0x4 << 25);
+ o1 |= p->from.offset & 0xffff;
+ o1 |= p->to.reg << 16;
+ aclass(ctxt, &p->to);
+ goto movm;
+
+ case 39: /* movm oreg,$con -> ldm */
+ o1 = (0x4 << 25) | (1 << 20);
+ o1 |= p->to.offset & 0xffff;
+ o1 |= p->from.reg << 16;
+ aclass(ctxt, &p->from);
+ movm:
+ if(ctxt->instoffset != 0)
+ ctxt->diag("offset must be zero in MOVM");
+ o1 |= (p->scond & C_SCOND) << 28;
+ if(p->scond & C_PBIT)
+ o1 |= 1 << 24;
+ if(p->scond & C_UBIT)
+ o1 |= 1 << 23;
+ if(p->scond & C_SBIT)
+ o1 |= 1 << 22;
+ if(p->scond & C_WBIT)
+ o1 |= 1 << 21;
+ break;
+
+ case 40: /* swp oreg,reg,reg */
+ aclass(ctxt, &p->from);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("offset must be zero in SWP");
+ o1 = (0x2<<23) | (0x9<<4);
+ if(p->as != ASWPW)
+ o1 |= 1 << 22;
+ o1 |= p->from.reg << 16;
+ o1 |= p->reg << 0;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+
+ case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
+ o1 = 0xe8fd8000;
+ break;
+
+ case 50: /* floating point store */
+ v = regoff(ctxt, &p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = ofsr(ctxt, p->as, p->from.reg, v, r, p->scond, p);
+ break;
+
+ case 51: /* floating point load */
+ v = regoff(ctxt, &p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = ofsr(ctxt, p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
+ break;
+
+ case 52: /* floating point store, int32 offset UGLY */
+ o1 = omvl(ctxt, p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
+ o3 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p);
+ break;
+
+ case 53: /* floating point load, int32 offset UGLY */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
+ o3 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+ break;
+
+ case 54: /* floating point arith */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ if(r == NREG) {
+ r = rt;
+ if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD)
+ r = 0;
+ }
+ o1 |= rf | (r<<16) | (rt<<12);
+ break;
+
+ case 56: /* move to FP[CS]R */
+ o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
+ o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
+ break;
+
+ case 57: /* move from FP[CS]R */
+ o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
+ o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20);
+ break;
+ case 58: /* movbu R,R */
+ o1 = oprrr(ctxt, AAND, p->scond);
+ o1 |= immrot(0xff);
+ rt = p->to.reg;
+ r = p->from.reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ break;
+
+ case 59: /* movw/bu R<<I(R),R -> ldr indexed */
+ if(p->from.reg == NREG) {
+ if(p->as != AMOVW)
+ ctxt->diag("byte MOV from shifter operand");
+ goto mov;
+ }
+ if(p->from.offset&(1<<4))
+ ctxt->diag("bad shift in LDR");
+ o1 = olrr(ctxt, p->from.offset, p->from.reg, p->to.reg, p->scond);
+ if(p->as == AMOVBU)
+ o1 |= 1<<22;
+ break;
+
+ case 60: /* movb R(R),R -> ldrsb indexed */
+ if(p->from.reg == NREG) {
+ ctxt->diag("byte MOV from shifter operand");
+ goto mov;
+ }
+ if(p->from.offset&(~0xf))
+ ctxt->diag("bad shift in LDRSB");
+ o1 = olhrr(ctxt, p->from.offset, p->from.reg, p->to.reg, p->scond);
+ o1 ^= (1<<5)|(1<<6);
+ break;
+
+ case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
+ if(p->to.reg == NREG)
+ ctxt->diag("MOV to shifter operand");
+ o1 = osrr(ctxt, p->from.reg, p->to.offset, p->to.reg, p->scond);
+ if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU)
+ o1 |= 1<<22;
+ break;
+
+ case 62: /* case R -> movw R<<2(PC),PC */
+ if(o->flag & LPCREL) {
+ o1 = oprrr(ctxt, AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12;
+ o2 = olrr(ctxt, REGTMP, REGPC, REGTMP, p->scond);
+ o2 |= 2<<7;
+ o3 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12;
+ } else {
+ o1 = olrr(ctxt, p->from.reg, REGPC, REGPC, p->scond);
+ o1 |= 2<<7;
+ }
+ break;
+
+ case 63: /* bcase */
+ if(p->pcond != nil) {
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 4;
+ if(p->to.sym != nil && p->to.sym->type != 0) {
+ rel->sym = p->to.sym;
+ rel->add = p->to.offset;
+ } else {
+ rel->sym = ctxt->cursym;
+ rel->add = p->pcond->pc;
+ }
+ if(o->flag & LPCREL) {
+ rel->type = D_PCREL;
+ rel->add += ctxt->pc - p->pcrel->pc - 16 + rel->siz;
+ } else
+ rel->type = D_ADDR;
+ o1 = 0;
+ }
+ break;
+
+ /* reloc ops */
+ case 64: /* mov/movb/movbu R,addr */
+ o1 = omvl(ctxt, p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = osr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+
+ case 65: /* mov/movbu addr,R */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = olr(ctxt, 0, REGTMP, p->to.reg, p->scond);
+ if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB)
+ o2 |= 1<<22;
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+
+ case 68: /* floating point store -> ADDR */
+ o1 = omvl(ctxt, p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+
+ case 69: /* floating point load <- ADDR */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+
+ /* ArmV4 ops: */
+ case 70: /* movh/movhu R,O(R) -> strh */
+ aclass(ctxt, &p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = oshr(ctxt, p->from.reg, ctxt->instoffset, r, p->scond);
+ break;
+ case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
+ aclass(ctxt, &p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = olhr(ctxt, ctxt->instoffset, r, p->to.reg, p->scond);
+ if(p->as == AMOVB || p->as == AMOVBS)
+ o1 ^= (1<<5)|(1<<6);
+ else if(p->as == AMOVH || p->as == AMOVHS)
+ o1 ^= (1<<6);
+ break;
+ case 72: /* movh/movhu R,L(R) -> strh */
+ o1 = omvl(ctxt, p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = oshrr(ctxt, p->from.reg, REGTMP,r, p->scond);
+ break;
+ case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = olhrr(ctxt, REGTMP, r, p->to.reg, p->scond);
+ if(p->as == AMOVB || p->as == AMOVBS)
+ o2 ^= (1<<5)|(1<<6);
+ else if(p->as == AMOVH || p->as == AMOVHS)
+ o2 ^= (1<<6);
+ break;
+ case 74: /* bx $I */
+ ctxt->diag("ABX $I");
+ break;
+ case 75: /* bx O(R) */
+ aclass(ctxt, &p->to);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("non-zero offset in ABX");
+/*
+ o1 = oprrr(ctxt, AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
+ o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R
+*/
+ // p->to.reg may be REGLINK
+ o1 = oprrr(ctxt, AADD, p->scond);
+ o1 |= immrot(ctxt->instoffset);
+ o1 |= p->to.reg << 16;
+ o1 |= REGTMP << 12;
+ o2 = oprrr(ctxt, AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
+ o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
+ break;
+ case 76: /* bx O(R) when returning from fn*/
+ ctxt->diag("ABXRET");
+ break;
+ case 77: /* ldrex oreg,reg */
+ aclass(ctxt, &p->from);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("offset must be zero in LDREX");
+ o1 = (0x19<<20) | (0xf9f);
+ o1 |= p->from.reg << 16;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 78: /* strex reg,oreg,reg */
+ aclass(ctxt, &p->from);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("offset must be zero in STREX");
+ o1 = (0x18<<20) | (0xf90);
+ o1 |= p->from.reg << 16;
+ o1 |= p->reg << 0;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 80: /* fmov zfcon,freg */
+ if(p->as == AMOVD) {
+ o1 = 0xeeb00b00; // VMOV imm 64
+ o2 = oprrr(ctxt, ASUBD, p->scond);
+ } else {
+ o1 = 0x0eb00a00; // VMOV imm 32
+ o2 = oprrr(ctxt, ASUBF, p->scond);
+ }
+ v = 0x70; // 1.0
+ r = p->to.reg;
+
+ // movf $1.0, r
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= r << 12;
+ o1 |= (v&0xf) << 0;
+ o1 |= (v&0xf0) << 12;
+
+ // subf r,r,r
+ o2 |= r | (r<<16) | (r<<12);
+ break;
+ case 81: /* fmov sfcon,freg */
+ o1 = 0x0eb00a00; // VMOV imm 32
+ if(p->as == AMOVD)
+ o1 = 0xeeb00b00; // VMOV imm 64
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= p->to.reg << 12;
+ v = chipfloat(ctxt, p->from.u.dval);
+ o1 |= (v&0xf) << 0;
+ o1 |= (v&0xf0) << 12;
+ break;
+ case 82: /* fcmp freg,freg, */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= (p->reg<<12) | (p->from.reg<<0);
+ o2 = 0x0ef1fa10; // VMRS R15
+ o2 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 83: /* fcmp freg,, */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= (p->from.reg<<12) | (1<<16);
+ o2 = 0x0ef1fa10; // VMRS R15
+ o2 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 84: /* movfw freg,freg - truncate float-to-fix */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= (p->from.reg<<0);
+ o1 |= (p->to.reg<<12);
+ break;
+ case 85: /* movwf freg,freg - fix-to-float */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= (p->from.reg<<0);
+ o1 |= (p->to.reg<<12);
+ break;
+ case 86: /* movfw freg,reg - truncate float-to-fix */
+ // macro for movfw freg,FTMP; movw FTMP,reg
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= (p->from.reg<<0);
+ o1 |= (FREGTMP<<12);
+ o2 = oprrr(ctxt, AMOVFW+AEND, p->scond);
+ o2 |= (FREGTMP<<16);
+ o2 |= (p->to.reg<<12);
+ break;
+ case 87: /* movwf reg,freg - fix-to-float */
+ // macro for movw reg,FTMP; movwf FTMP,freg
+ o1 = oprrr(ctxt, AMOVWF+AEND, p->scond);
+ o1 |= (p->from.reg<<12);
+ o1 |= (FREGTMP<<16);
+ o2 = oprrr(ctxt, p->as, p->scond);
+ o2 |= (FREGTMP<<0);
+ o2 |= (p->to.reg<<12);
+ break;
+ case 88: /* movw reg,freg */
+ o1 = oprrr(ctxt, AMOVWF+AEND, p->scond);
+ o1 |= (p->from.reg<<12);
+ o1 |= (p->to.reg<<16);
+ break;
+ case 89: /* movw freg,reg */
+ o1 = oprrr(ctxt, AMOVFW+AEND, p->scond);
+ o1 |= (p->from.reg<<16);
+ o1 |= (p->to.reg<<12);
+ break;
+ case 90: /* tst reg */
+ o1 = oprrr(ctxt, ACMP+AEND, p->scond);
+ o1 |= p->from.reg<<16;
+ break;
+ case 91: /* ldrexd oreg,reg */
+ aclass(ctxt, &p->from);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("offset must be zero in LDREX");
+ o1 = (0x1b<<20) | (0xf9f);
+ o1 |= p->from.reg << 16;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 92: /* strexd reg,oreg,reg */
+ aclass(ctxt, &p->from);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("offset must be zero in STREX");
+ o1 = (0x1a<<20) | (0xf90);
+ o1 |= p->from.reg << 16;
+ o1 |= p->reg << 0;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = olhr(ctxt, 0, REGTMP, p->to.reg, p->scond);
+ if(p->as == AMOVB || p->as == AMOVBS)
+ o2 ^= (1<<5)|(1<<6);
+ else if(p->as == AMOVH || p->as == AMOVHS)
+ o2 ^= (1<<6);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+ case 94: /* movh/movhu R,addr -> strh */
+ o1 = omvl(ctxt, p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = oshr(ctxt, p->from.reg, 0, REGTMP, p->scond);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+ case 95: /* PLD off(reg) */
+ o1 = 0xf5d0f000;
+ o1 |= p->from.reg << 16;
+ if(p->from.offset < 0) {
+ o1 &= ~(1 << 23);
+ o1 |= (-p->from.offset) & 0xfff;
+ } else
+ o1 |= p->from.offset & 0xfff;
+ break;
+ case 96: /* UNDEF */
+ // This is supposed to be something that stops execution.
+ // It's not supposed to be reached, ever, but if it is, we'd
+ // like to be able to tell how we got there. Assemble as
+ // 0xf7fabcfd which is guranteed to raise undefined instruction
+ // exception.
+ o1 = 0xf7fabcfd;
+ break;
+ case 97: /* CLZ Rm, Rd */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= p->to.reg << 12;
+ o1 |= p->from.reg;
+ break;
+ case 98: /* MULW{T,B} Rs, Rm, Rd */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= p->to.reg << 16;
+ o1 |= p->from.reg << 8;
+ o1 |= p->reg;
+ break;
+ case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= p->to.reg << 12;
+ o1 |= p->from.reg << 8;
+ o1 |= p->reg;
+ o1 |= p->to.offset << 16;
+ break;
+ }
+
+ out[0] = o1;
+ out[1] = o2;
+ out[2] = o3;
+ out[3] = o4;
+ out[4] = o5;
+ out[5] = o6;
+ return;
+
+#ifdef NOTDEF
+ v = p->pc;
+ switch(o->size) {
+ default:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
+ break;
+ case 4:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
+ lputl(o1);
+ break;
+ case 8:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p);
+ lputl(o1);
+ lputl(o2);
+ break;
+ case 12:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ break;
+ case 16:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n",
+ v, o1, o2, o3, o4, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ lputl(o4);
+ break;
+ case 20:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
+ v, o1, o2, o3, o4, o5, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ lputl(o4);
+ lputl(o5);
+ break;
+ case 24:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
+ v, o1, o2, o3, o4, o5, o6, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ lputl(o4);
+ lputl(o5);
+ lputl(o6);
+ break;
+ }
+#endif
+}
+
+int32
+oprrr(Link *ctxt, int a, int sc)
+{
+ int32 o;
+
+ o = (sc & C_SCOND) << 28;
+ if(sc & C_SBIT)
+ o |= 1 << 20;
+ if(sc & (C_PBIT|C_WBIT))
+ ctxt->diag(".nil/.W on dp instruction");
+ switch(a) {
+ case AMULU:
+ case AMUL: return o | (0x0<<21) | (0x9<<4);
+ case AMULA: return o | (0x1<<21) | (0x9<<4);
+ case AMULLU: return o | (0x4<<21) | (0x9<<4);
+ case AMULL: return o | (0x6<<21) | (0x9<<4);
+ case AMULALU: return o | (0x5<<21) | (0x9<<4);
+ case AMULAL: return o | (0x7<<21) | (0x9<<4);
+ case AAND: return o | (0x0<<21);
+ case AEOR: return o | (0x1<<21);
+ case ASUB: return o | (0x2<<21);
+ case ARSB: return o | (0x3<<21);
+ case AADD: return o | (0x4<<21);
+ case AADC: return o | (0x5<<21);
+ case ASBC: return o | (0x6<<21);
+ case ARSC: return o | (0x7<<21);
+ case ATST: return o | (0x8<<21) | (1<<20);
+ case ATEQ: return o | (0x9<<21) | (1<<20);
+ case ACMP: return o | (0xa<<21) | (1<<20);
+ case ACMN: return o | (0xb<<21) | (1<<20);
+ case AORR: return o | (0xc<<21);
+ case AMOVB:
+ case AMOVH:
+ case AMOVW: return o | (0xd<<21);
+ case ABIC: return o | (0xe<<21);
+ case AMVN: return o | (0xf<<21);
+ case ASLL: return o | (0xd<<21) | (0<<5);
+ case ASRL: return o | (0xd<<21) | (1<<5);
+ case ASRA: return o | (0xd<<21) | (2<<5);
+ case ASWI: return o | (0xf<<24);
+
+ case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4);
+ case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4);
+ case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4);
+ case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4);
+ case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4);
+ case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4);
+ case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4);
+ case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4);
+ case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4);
+ case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4);
+ case AABSD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (0xc<<4);
+ case AABSF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (0xc<<4);
+ case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4);
+ case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4);
+
+ case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4);
+ case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4);
+
+ case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
+ (1<<8); // dtof
+ case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
+ (0<<8); // dtof
+
+ case AMOVWF:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<7; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (0<<18) | (0<<8); // toint, double
+ case AMOVWD:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<7; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (0<<18) | (1<<8); // toint, double
+
+ case AMOVFW:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<16; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (1<<18) | (0<<8) | (1<<7); // toint, double, trunc
+ case AMOVDW:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<16; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (1<<18) | (1<<8) | (1<<7); // toint, double, trunc
+
+ case AMOVWF+AEND: // copy WtoF
+ return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4);
+ case AMOVFW+AEND: // copy FtoW
+ return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
+ case ACMP+AEND: // cmp imm
+ return o | (0x3<<24) | (0x5<<20);
+
+ case ACLZ:
+ // CLZ doesn't support .nil
+ return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4);
+
+ case AMULWT:
+ return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4);
+ case AMULWB:
+ return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4);
+ case AMULAWT:
+ return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4);
+ case AMULAWB:
+ return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4);
+
+ case ABL: // BLX REG
+ return (o & (0xf<<28)) | (0x12fff3 << 4);
+ }
+ ctxt->diag("bad rrr %d", a);
+ prasm(ctxt->curp);
+ return 0;
+}
+
+int32
+opbra(Link *ctxt, int a, int sc)
+{
+
+ if(sc & (C_SBIT|C_PBIT|C_WBIT))
+ ctxt->diag(".nil/.nil/.W on bra instruction");
+ sc &= C_SCOND;
+ if(a == ABL)
+ return (sc<<28)|(0x5<<25)|(0x1<<24);
+ if(sc != 0xe)
+ ctxt->diag(".COND on bcond instruction");
+ switch(a) {
+ case ABEQ: return (0x0<<28)|(0x5<<25);
+ case ABNE: return (0x1<<28)|(0x5<<25);
+ case ABCS: return (0x2<<28)|(0x5<<25);
+ case ABHS: return (0x2<<28)|(0x5<<25);
+ case ABCC: return (0x3<<28)|(0x5<<25);
+ case ABLO: return (0x3<<28)|(0x5<<25);
+ case ABMI: return (0x4<<28)|(0x5<<25);
+ case ABPL: return (0x5<<28)|(0x5<<25);
+ case ABVS: return (0x6<<28)|(0x5<<25);
+ case ABVC: return (0x7<<28)|(0x5<<25);
+ case ABHI: return (0x8<<28)|(0x5<<25);
+ case ABLS: return (0x9<<28)|(0x5<<25);
+ case ABGE: return (0xa<<28)|(0x5<<25);
+ case ABLT: return (0xb<<28)|(0x5<<25);
+ case ABGT: return (0xc<<28)|(0x5<<25);
+ case ABLE: return (0xd<<28)|(0x5<<25);
+ case AB: return (0xe<<28)|(0x5<<25);
+ }
+ ctxt->diag("bad bra %A", a);
+ prasm(ctxt->curp);
+ return 0;
+}
+
+int32
+olr(Link *ctxt, int32 v, int b, int r, int sc)
+{
+ int32 o;
+
+ if(sc & C_SBIT)
+ ctxt->diag(".nil on LDR/STR instruction");
+ o = (sc & C_SCOND) << 28;
+ if(!(sc & C_PBIT))
+ o |= 1 << 24;
+ if(!(sc & C_UBIT))
+ o |= 1 << 23;
+ if(sc & C_WBIT)
+ o |= 1 << 21;
+ o |= (1<<26) | (1<<20);
+ if(v < 0) {
+ if(sc & C_UBIT)
+ ctxt->diag(".U on neg offset");
+ v = -v;
+ o ^= 1 << 23;
+ }
+ if(v >= (1<<12) || v < 0)
+ ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp);
+ o |= v;
+ o |= b << 16;
+ o |= r << 12;
+ return o;
+}
+
+int32
+olhr(Link *ctxt, int32 v, int b, int r, int sc)
+{
+ int32 o;
+
+ if(sc & C_SBIT)
+ ctxt->diag(".nil on LDRH/STRH instruction");
+ o = (sc & C_SCOND) << 28;
+ if(!(sc & C_PBIT))
+ o |= 1 << 24;
+ if(sc & C_WBIT)
+ o |= 1 << 21;
+ o |= (1<<23) | (1<<20)|(0xb<<4);
+ if(v < 0) {
+ v = -v;
+ o ^= 1 << 23;
+ }
+ if(v >= (1<<8) || v < 0)
+ ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp);
+ o |= (v&0xf)|((v>>4)<<8)|(1<<22);
+ o |= b << 16;
+ o |= r << 12;
+ return o;
+}
+
+int32
+osr(Link *ctxt, int a, int r, int32 v, int b, int sc)
+{
+ int32 o;
+
+ o = olr(ctxt, v, b, r, sc) ^ (1<<20);
+ if(a != AMOVW)
+ o |= 1<<22;
+ return o;
+}
+
+int32
+oshr(Link *ctxt, int r, int32 v, int b, int sc)
+{
+ int32 o;
+
+ o = olhr(ctxt, v, b, r, sc) ^ (1<<20);
+ return o;
+}
+
+
+int32
+osrr(Link *ctxt, int r, int i, int b, int sc)
+{
+
+ return olr(ctxt, i, b, r, sc) ^ ((1<<25) | (1<<20));
+}
+
+int32
+oshrr(Link *ctxt, int r, int i, int b, int sc)
+{
+ return olhr(ctxt, i, b, r, sc) ^ ((1<<22) | (1<<20));
+}
+
+int32
+olrr(Link *ctxt, int i, int b, int r, int sc)
+{
+
+ return olr(ctxt, i, b, r, sc) ^ (1<<25);
+}
+
+int32
+olhrr(Link *ctxt, int i, int b, int r, int sc)
+{
+ return olhr(ctxt, i, b, r, sc) ^ (1<<22);
+}
+
+int32
+ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p)
+{
+ int32 o;
+
+ if(sc & C_SBIT)
+ ctxt->diag(".nil on FLDR/FSTR instruction");
+ o = (sc & C_SCOND) << 28;
+ if(!(sc & C_PBIT))
+ o |= 1 << 24;
+ if(sc & C_WBIT)
+ o |= 1 << 21;
+ o |= (6<<25) | (1<<24) | (1<<23) | (10<<8);
+ if(v < 0) {
+ v = -v;
+ o ^= 1 << 23;
+ }
+ if(v & 3)
+ ctxt->diag("odd offset for floating point op: %d\n%P", v, p);
+ else
+ if(v >= (1<<10) || v < 0)
+ ctxt->diag("literal span too large: %d\n%P", v, p);
+ o |= (v>>2) & 0xFF;
+ o |= b << 16;
+ o |= r << 12;
+
+ switch(a) {
+ default:
+ ctxt->diag("bad fst %A", a);
+ case AMOVD:
+ o |= 1 << 8;
+ case AMOVF:
+ break;
+ }
+ return o;
+}
+
+int32
+omvl(Link *ctxt, Prog *p, Addr *a, int dr)
+{
+ int32 v, o1;
+ if(!p->pcond) {
+ aclass(ctxt, a);
+ v = immrot(~ctxt->instoffset);
+ if(v == 0) {
+ ctxt->diag("missing literal");
+ prasm(p);
+ return 0;
+ }
+ o1 = oprrr(ctxt, AMVN, p->scond&C_SCOND);
+ o1 |= v;
+ o1 |= dr << 12;
+ } else {
+ v = p->pcond->pc - p->pc - 8;
+ o1 = olr(ctxt, v, REGPC, dr, p->scond&C_SCOND);
+ }
+ return o1;
+}
+
+static int
+chipzero(Link *ctxt, float64 e)
+{
+ // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
+ if(ctxt->goarm < 7 || e != 0)
+ return -1;
+ return 0;
+}
+
+static int
+chipfloat(Link *ctxt, float64 e)
+{
+ int n;
+ ulong h1;
+ int32 l, h;
+ uint64 ei;
+
+ // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
+ if(ctxt->goarm < 7)
+ goto no;
+
+ memmove(&ei, &e, 8);
+ l = (int32)ei;
+ h = (int32)(ei>>32);
+
+ if(l != 0 || (h&0xffff) != 0)
+ goto no;
+ h1 = h & 0x7fc00000;
+ if(h1 != 0x40000000 && h1 != 0x3fc00000)
+ goto no;
+ n = 0;
+
+ // sign bit (a)
+ if(h & 0x80000000)
+ n |= 1<<7;
+
+ // exp sign bit (b)
+ if(h1 == 0x3fc00000)
+ n |= 1<<6;
+
+ // rest of exp and mantissa (cd-efgh)
+ n |= (h >> 16) & 0x3f;
+
+//print("match %.8lux %.8lux %d\n", l, h, n);
+ return n;
+
+no:
+ return -1;
+}
diff --git a/src/liblink/asm6.c b/src/liblink/asm6.c
new file mode 100644
index 000000000..019ec0684
--- /dev/null
+++ b/src/liblink/asm6.c
@@ -0,0 +1,3289 @@
+// Inferno utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. ctxt->and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software ctxt->and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, ctxt->and/or sell
+// copies of the Software, ctxt->and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice ctxt->and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Instruction layout.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/6l/6.out.h"
+#include "../pkg/runtime/stack.h"
+
+enum
+{
+ MaxAlign = 32, // max data alignment
+
+ // Loop alignment constants:
+ // want to align loop entry to LoopAlign-byte boundary,
+ // ctxt->and willing to insert at most MaxLoopPad bytes of NOP to do so.
+ // We define a loop entry as the target of a backward jump.
+ //
+ // gcc uses MaxLoopPad = 10 for its 'generic x86-64' config,
+ // ctxt->and it aligns all jump targets, not just backward jump targets.
+ //
+ // As of 6/1/2012, the effect of setting MaxLoopPad = 10 here
+ // is very slight but negative, so the alignment is disabled by
+ // setting MaxLoopPad = 0. The code is here for reference ctxt->and
+ // for future experiments.
+ //
+ LoopAlign = 16,
+ MaxLoopPad = 0,
+
+ FuncAlign = 16
+};
+
+extern char *anames6[];
+
+typedef struct Optab Optab;
+typedef struct Movtab Movtab;
+
+struct Optab
+{
+ short as;
+ uchar* ytab;
+ uchar prefix;
+ uchar op[23];
+};
+struct Movtab
+{
+ short as;
+ uchar ft;
+ uchar tt;
+ uchar code;
+ uchar op[4];
+};
+
+enum
+{
+ Yxxx = 0,
+ Ynone,
+ Yi0,
+ Yi1,
+ Yi8,
+ Ys32,
+ Yi32,
+ Yi64,
+ Yiauto,
+ Yal,
+ Ycl,
+ Yax,
+ Ycx,
+ Yrb,
+ Yrl,
+ Yrf,
+ Yf0,
+ Yrx,
+ Ymb,
+ Yml,
+ Ym,
+ Ybr,
+ Ycol,
+
+ Ycs, Yss, Yds, Yes, Yfs, Ygs,
+ Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
+ Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8,
+ Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
+ Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64,
+ Ymr, Ymm,
+ Yxr, Yxm,
+ Ymax,
+
+ Zxxx = 0,
+
+ Zlit,
+ Zlitm_r,
+ Z_rp,
+ Zbr,
+ Zcall,
+ Zib_,
+ Zib_rp,
+ Zibo_m,
+ Zibo_m_xm,
+ Zil_,
+ Zil_rp,
+ Ziq_rp,
+ Zilo_m,
+ Ziqo_m,
+ Zjmp,
+ Zloop,
+ Zo_iw,
+ Zm_o,
+ Zm_r,
+ Zm2_r,
+ Zm_r_xm,
+ Zm_r_i_xm,
+ Zm_r_3d,
+ Zm_r_xm_nr,
+ Zr_m_xm_nr,
+ Zibm_r, /* mmx1,mmx2/mem64,imm8 */
+ Zmb_r,
+ Zaut_r,
+ Zo_m,
+ Zo_m64,
+ Zpseudo,
+ Zr_m,
+ Zr_m_xm,
+ Zr_m_i_xm,
+ Zrp_,
+ Z_ib,
+ Z_il,
+ Zm_ibo,
+ Zm_ilo,
+ Zib_rr,
+ Zil_rr,
+ Zclr,
+ Zbyte,
+ Zmax,
+
+ Px = 0,
+ P32 = 0x32, /* 32-bit only */
+ Pe = 0x66, /* operand escape */
+ Pm = 0x0f, /* 2byte opcode escape */
+ Pq = 0xff, /* both escapes: 66 0f */
+ Pb = 0xfe, /* byte operands */
+ Pf2 = 0xf2, /* xmm escape 1: f2 0f */
+ Pf3 = 0xf3, /* xmm escape 2: f3 0f */
+ Pq3 = 0x67, /* xmm escape 3: 66 48 0f */
+ Pw = 0x48, /* Rex.w */
+ Py = 0x80, /* defaults to 64-bit mode */
+
+ Rxf = 1<<9, /* internal flag for Rxr on from */
+ Rxt = 1<<8, /* internal flag for Rxr on to */
+ Rxw = 1<<3, /* =1, 64-bit operand size */
+ Rxr = 1<<2, /* extend modrm reg */
+ Rxx = 1<<1, /* extend sib index */
+ Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */
+
+ Maxand = 10, /* in -a output width of the byte codes */
+};
+
+static char ycover[Ymax*Ymax];
+static int reg[D_NONE];
+static int regrex[D_NONE+1];
+static void asmins(Link *ctxt, Prog *p);
+
+static uchar ynone[] =
+{
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+static uchar ytext[] =
+{
+ Ymb, Yi64, Zpseudo,1,
+ 0
+};
+static uchar ynop[] =
+{
+ Ynone, Ynone, Zpseudo,0,
+ Ynone, Yiauto, Zpseudo,0,
+ Ynone, Yml, Zpseudo,0,
+ Ynone, Yrf, Zpseudo,0,
+ Ynone, Yxr, Zpseudo,0,
+ Yiauto, Ynone, Zpseudo,0,
+ Yml, Ynone, Zpseudo,0,
+ Yrf, Ynone, Zpseudo,0,
+ Yxr, Ynone, Zpseudo,1,
+ 0
+};
+static uchar yfuncdata[] =
+{
+ Yi32, Ym, Zpseudo, 0,
+ 0
+};
+static uchar ypcdata[] =
+{
+ Yi32, Yi32, Zpseudo, 0,
+ 0
+};
+static uchar yxorb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+static uchar yxorl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yaddl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yincb[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+static uchar yincw[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ 0
+};
+static uchar yincl[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ 0
+};
+static uchar ycmpb[] =
+{
+ Yal, Yi32, Z_ib, 1,
+ Ymb, Yi32, Zm_ibo, 2,
+ Ymb, Yrb, Zm_r, 1,
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+static uchar ycmpl[] =
+{
+ Yml, Yi8, Zm_ibo, 2,
+ Yax, Yi32, Z_il, 1,
+ Yml, Yi32, Zm_ilo, 2,
+ Yml, Yrl, Zm_r, 1,
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+static uchar yshb[] =
+{
+ Yi1, Ymb, Zo_m, 2,
+ Yi32, Ymb, Zibo_m, 2,
+ Ycx, Ymb, Zo_m, 2,
+ 0
+};
+static uchar yshl[] =
+{
+ Yi1, Yml, Zo_m, 2,
+ Yi32, Yml, Zibo_m, 2,
+ Ycl, Yml, Zo_m, 2,
+ Ycx, Yml, Zo_m, 2,
+ 0
+};
+static uchar ytestb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+static uchar ytestl[] =
+{
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar ymovb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ Yi32, Yrb, Zib_rp, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ 0
+};
+static uchar ymbs[] =
+{
+ Ymb, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ybtl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+static uchar ymovw[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1,
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yiauto, Yrl, Zaut_r, 2,
+ 0
+};
+static uchar ymovl[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1,
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yml, Ymr, Zm_r_xm, 1, // MMX MOVD
+ Ymr, Yml, Zr_m_xm, 1, // MMX MOVD
+ Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit)
+ Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit)
+ Yiauto, Yrl, Zaut_r, 2,
+ 0
+};
+static uchar yret[] =
+{
+ Ynone, Ynone, Zo_iw, 1,
+ Yi32, Ynone, Zo_iw, 1,
+ 0
+};
+static uchar ymovq[] =
+{
+ Yrl, Yml, Zr_m, 1, // 0x89
+ Yml, Yrl, Zm_r, 1, // 0x8b
+ Yi0, Yrl, Zclr, 1, // 0x31
+ Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0)
+ Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate
+ Yi32, Yml, Zilo_m, 2, // 0xc7,(0)
+ Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding)
+ Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ
+ Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD
+ Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD
+ Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q
+ Yxm, Yxr, Zm_r_xm_nr, 2, // MOVQ xmm1/m64 -> xmm2
+ Yxr, Yxm, Zr_m_xm_nr, 2, // MOVQ xmm1 -> xmm2/m64
+ Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load
+ Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store
+ Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ
+ 0
+};
+static uchar ym_rl[] =
+{
+ Ym, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yrl_m[] =
+{
+ Yrl, Ym, Zr_m, 1,
+ 0
+};
+static uchar ymb_rl[] =
+{
+ Ymb, Yrl, Zmb_r, 1,
+ 0
+};
+static uchar yml_rl[] =
+{
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yrl_ml[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+static uchar yml_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+static uchar yrb_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+static uchar yxchg[] =
+{
+ Yax, Yrl, Z_rp, 1,
+ Yrl, Yax, Zrp_, 1,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar ydivl[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ydivb[] =
+{
+ Ymb, Ynone, Zm_o, 2,
+ 0
+};
+static uchar yimul[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ Yi8, Yrl, Zib_rr, 1,
+ Yi32, Yrl, Zil_rr, 1,
+ Yml, Yrl, Zm_r, 2,
+ 0
+};
+static uchar yimul3[] =
+{
+ Yml, Yrl, Zibm_r, 2,
+ 0
+};
+static uchar ybyte[] =
+{
+ Yi64, Ynone, Zbyte, 1,
+ 0
+};
+static uchar yin[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+static uchar yint[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ 0
+};
+static uchar ypushl[] =
+{
+ Yrl, Ynone, Zrp_, 1,
+ Ym, Ynone, Zm_o, 2,
+ Yi8, Ynone, Zib_, 1,
+ Yi32, Ynone, Zil_, 1,
+ 0
+};
+static uchar ypopl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ Ynone, Ym, Zo_m, 2,
+ 0
+};
+static uchar ybswap[] =
+{
+ Ynone, Yrl, Z_rp, 2,
+ 0,
+};
+static uchar yscond[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+static uchar yjcond[] =
+{
+ Ynone, Ybr, Zbr, 0,
+ Yi0, Ybr, Zbr, 0,
+ Yi1, Ybr, Zbr, 1,
+ 0
+};
+static uchar yloop[] =
+{
+ Ynone, Ybr, Zloop, 1,
+ 0
+};
+static uchar ycall[] =
+{
+ Ynone, Yml, Zo_m64, 0,
+ Yrx, Yrx, Zo_m64, 2,
+ Ynone, Ybr, Zcall, 1,
+ 0
+};
+static uchar yjmp[] =
+{
+ Ynone, Yml, Zo_m64, 2,
+ Ynone, Ybr, Zjmp, 1,
+ 0
+};
+
+static uchar yfmvd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfmvdp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfmvf[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+static uchar yfmvx[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ 0
+};
+static uchar yfmvp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+static uchar yfadd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfaddp[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfxch[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ 0
+};
+static uchar ycompp[] =
+{
+ Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
+ 0
+};
+static uchar ystsw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ynone, Yax, Zlit, 1,
+ 0
+};
+static uchar ystcw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ysvrs[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ymm[] =
+{
+ Ymm, Ymr, Zm_r_xm, 1,
+ Yxm, Yxr, Zm_r_xm, 2,
+ 0
+};
+static uchar yxm[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcvm1[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ Yxm, Ymr, Zm_r_xm, 2,
+ 0
+};
+static uchar yxcvm2[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ Ymm, Yxr, Zm_r_xm, 2,
+ 0
+};
+/*
+static uchar yxmq[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ 0
+};
+*/
+static uchar yxr[] =
+{
+ Yxr, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxr_ml[] =
+{
+ Yxr, Yml, Zr_m_xm, 1,
+ 0
+};
+static uchar ymr[] =
+{
+ Ymr, Ymr, Zm_r, 1,
+ 0
+};
+static uchar ymr_ml[] =
+{
+ Ymr, Yml, Zr_m_xm, 1,
+ 0
+};
+static uchar yxcmp[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcmpi[] =
+{
+ Yxm, Yxr, Zm_r_i_xm, 2,
+ 0
+};
+static uchar yxmov[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ Yxr, Yxm, Zr_m_xm, 1,
+ 0
+};
+static uchar yxcvfl[] =
+{
+ Yxm, Yrl, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcvlf[] =
+{
+ Yml, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcvfq[] =
+{
+ Yxm, Yrl, Zm_r_xm, 2,
+ 0
+};
+static uchar yxcvqf[] =
+{
+ Yml, Yxr, Zm_r_xm, 2,
+ 0
+};
+static uchar yps[] =
+{
+ Ymm, Ymr, Zm_r_xm, 1,
+ Yi8, Ymr, Zibo_m_xm, 2,
+ Yxm, Yxr, Zm_r_xm, 2,
+ Yi8, Yxr, Zibo_m_xm, 3,
+ 0
+};
+static uchar yxrrl[] =
+{
+ Yxr, Yrl, Zm_r, 1,
+ 0
+};
+static uchar ymfp[] =
+{
+ Ymm, Ymr, Zm_r_3d, 1,
+ 0,
+};
+static uchar ymrxr[] =
+{
+ Ymr, Yxr, Zm_r, 1,
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar ymshuf[] =
+{
+ Ymm, Ymr, Zibm_r, 2,
+ 0
+};
+static uchar ymshufb[] =
+{
+ Yxm, Yxr, Zm2_r, 2,
+ 0
+};
+static uchar yxshuf[] =
+{
+ Yxm, Yxr, Zibm_r, 2,
+ 0
+};
+static uchar yextrw[] =
+{
+ Yxr, Yrl, Zibm_r, 2,
+ 0
+};
+static uchar yinsrw[] =
+{
+ Yml, Yxr, Zibm_r, 2,
+ 0
+};
+static uchar yinsr[] =
+{
+ Ymm, Yxr, Zibm_r, 3,
+ 0
+};
+static uchar ypsdq[] =
+{
+ Yi8, Yxr, Zibo_m, 2,
+ 0
+};
+static uchar ymskb[] =
+{
+ Yxr, Yrl, Zm_r_xm, 2,
+ Ymr, Yrl, Zm_r_xm, 1,
+ 0
+};
+static uchar ycrc32l[] =
+{
+ Yml, Yrl, Zlitm_r, 0,
+};
+static uchar yprefetch[] =
+{
+ Ym, Ynone, Zm_o, 2,
+ 0,
+};
+static uchar yaes[] =
+{
+ Yxm, Yxr, Zlitm_r, 2,
+ 0
+};
+static uchar yaes2[] =
+{
+ Yxm, Yxr, Zibm_r, 2,
+ 0
+};
+
+/*
+ * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32,
+ * ctxt->and p->from ctxt->and p->to as operands (Addr*). The linker scans optab to find
+ * the entry with the given p->as ctxt->and then looks through the ytable for that
+ * instruction (the second field in the optab struct) for a line whose first
+ * two values match the Ytypes of the p->from ctxt->and p->to operands. The function
+ * oclass in span.c computes the specific Ytype of an operand ctxt->and then the set
+ * of more general Ytypes that it satisfies is implied by the ycover table, set
+ * up in instinit. For example, oclass distinguishes the constants 0 ctxt->and 1
+ * from the more general 8-bit constants, but instinit says
+ *
+ * ycover[Yi0*Ymax + Ys32] = 1;
+ * ycover[Yi1*Ymax + Ys32] = 1;
+ * ycover[Yi8*Ymax + Ys32] = 1;
+ *
+ * which means that Yi0, Yi1, ctxt->and Yi8 all count as Ys32 (signed 32)
+ * if that's what an instruction can handle.
+ *
+ * In parallel with the scan through the ytable for the appropriate line, there
+ * is a z pointer that starts out pointing at the strange magic byte list in
+ * the Optab struct. With each step past a non-matching ytable line, z
+ * advances by the 4th entry in the line. When a matching line is found, that
+ * z pointer has the extra data to use in laying down the instruction bytes.
+ * The actual bytes laid down are a function of the 3rd entry in the line (that
+ * is, the Ztype) ctxt->and the z bytes.
+ *
+ * For example, let's look at AADDL. The optab line says:
+ * { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ *
+ * ctxt->and yaddl says
+ * uchar yaddl[] =
+ * {
+ * Yi8, Yml, Zibo_m, 2,
+ * Yi32, Yax, Zil_, 1,
+ * Yi32, Yml, Zilo_m, 2,
+ * Yrl, Yml, Zr_m, 1,
+ * Yml, Yrl, Zm_r, 1,
+ * 0
+ * };
+ *
+ * so there are 5 possible types of ADDL instruction that can be laid down, ctxt->and
+ * possible states used to lay them down (Ztype ctxt->and z pointer, assuming z
+ * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are:
+ *
+ * Yi8, Yml -> Zibo_m, z (0x83, 00)
+ * Yi32, Yax -> Zil_, z+2 (0x05)
+ * Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00)
+ * Yrl, Yml -> Zr_m, z+2+1+2 (0x01)
+ * Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03)
+ *
+ * The Pconstant in the optab line controls the prefix bytes to emit. That's
+ * relatively straightforward as this program goes.
+ *
+ * The switch on t[2] in doasm implements the various Z cases. Zibo_m, for
+ * example, is an opcode byte (z[0]) then an asmando (which is some kind of
+ * encoded addressing mode for the Yml arg), ctxt->and then a single immediate byte.
+ * Zilo_m is the same but a long (32-bit) immediate.
+ */
+Optab optab[] =
+/* as, ytab, andproto, opcode */
+{
+ { AXXX },
+ { AAAA, ynone, P32, 0x37 },
+ { AAAD, ynone, P32, 0xd5,0x0a },
+ { AAAM, ynone, P32, 0xd4,0x0a },
+ { AAAS, ynone, P32, 0x3f },
+ { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
+ { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 },
+ { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADDPD, yxm, Pq, 0x58 },
+ { AADDPS, yxm, Pm, 0x58 },
+ { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADDSD, yxm, Pf2, 0x58 },
+ { AADDSS, yxm, Pf3, 0x58 },
+ { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADJSP },
+ { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
+ { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AANDNPD, yxm, Pq, 0x55 },
+ { AANDNPS, yxm, Pm, 0x55 },
+ { AANDPD, yxm, Pq, 0x54 },
+ { AANDPS, yxm, Pq, 0x54 },
+ { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AARPL, yrl_ml, P32, 0x63 },
+ { ABOUNDL, yrl_m, P32, 0x62 },
+ { ABOUNDW, yrl_m, Pe, 0x62 },
+ { ABSFL, yml_rl, Pm, 0xbc },
+ { ABSFQ, yml_rl, Pw, 0x0f,0xbc },
+ { ABSFW, yml_rl, Pq, 0xbc },
+ { ABSRL, yml_rl, Pm, 0xbd },
+ { ABSRQ, yml_rl, Pw, 0x0f,0xbd },
+ { ABSRW, yml_rl, Pq, 0xbd },
+ { ABSWAPL, ybswap, Px, 0x0f,0xc8 },
+ { ABSWAPQ, ybswap, Pw, 0x0f,0xc8 },
+ { ABTCL, ybtl, Pm, 0xba,(07),0xbb },
+ { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb },
+ { ABTCW, ybtl, Pq, 0xba,(07),0xbb },
+ { ABTL, ybtl, Pm, 0xba,(04),0xa3 },
+ { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3},
+ { ABTRL, ybtl, Pm, 0xba,(06),0xb3 },
+ { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 },
+ { ABTRW, ybtl, Pq, 0xba,(06),0xb3 },
+ { ABTSL, ybtl, Pm, 0xba,(05),0xab },
+ { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab },
+ { ABTSW, ybtl, Pq, 0xba,(05),0xab },
+ { ABTW, ybtl, Pq, 0xba,(04),0xa3 },
+ { ABYTE, ybyte, Px, 1 },
+ { ACALL, ycall, Px, 0xff,(02),0xe8 },
+ { ACDQ, ynone, Px, 0x99 },
+ { ACLC, ynone, Px, 0xf8 },
+ { ACLD, ynone, Px, 0xfc },
+ { ACLI, ynone, Px, 0xfa },
+ { ACLTS, ynone, Pm, 0x06 },
+ { ACMC, ynone, Px, 0xf5 },
+ { ACMOVLCC, yml_rl, Pm, 0x43 },
+ { ACMOVLCS, yml_rl, Pm, 0x42 },
+ { ACMOVLEQ, yml_rl, Pm, 0x44 },
+ { ACMOVLGE, yml_rl, Pm, 0x4d },
+ { ACMOVLGT, yml_rl, Pm, 0x4f },
+ { ACMOVLHI, yml_rl, Pm, 0x47 },
+ { ACMOVLLE, yml_rl, Pm, 0x4e },
+ { ACMOVLLS, yml_rl, Pm, 0x46 },
+ { ACMOVLLT, yml_rl, Pm, 0x4c },
+ { ACMOVLMI, yml_rl, Pm, 0x48 },
+ { ACMOVLNE, yml_rl, Pm, 0x45 },
+ { ACMOVLOC, yml_rl, Pm, 0x41 },
+ { ACMOVLOS, yml_rl, Pm, 0x40 },
+ { ACMOVLPC, yml_rl, Pm, 0x4b },
+ { ACMOVLPL, yml_rl, Pm, 0x49 },
+ { ACMOVLPS, yml_rl, Pm, 0x4a },
+ { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 },
+ { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 },
+ { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 },
+ { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d },
+ { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f },
+ { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 },
+ { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e },
+ { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 },
+ { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c },
+ { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 },
+ { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 },
+ { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 },
+ { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 },
+ { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b },
+ { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 },
+ { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a },
+ { ACMOVWCC, yml_rl, Pq, 0x43 },
+ { ACMOVWCS, yml_rl, Pq, 0x42 },
+ { ACMOVWEQ, yml_rl, Pq, 0x44 },
+ { ACMOVWGE, yml_rl, Pq, 0x4d },
+ { ACMOVWGT, yml_rl, Pq, 0x4f },
+ { ACMOVWHI, yml_rl, Pq, 0x47 },
+ { ACMOVWLE, yml_rl, Pq, 0x4e },
+ { ACMOVWLS, yml_rl, Pq, 0x46 },
+ { ACMOVWLT, yml_rl, Pq, 0x4c },
+ { ACMOVWMI, yml_rl, Pq, 0x48 },
+ { ACMOVWNE, yml_rl, Pq, 0x45 },
+ { ACMOVWOC, yml_rl, Pq, 0x41 },
+ { ACMOVWOS, yml_rl, Pq, 0x40 },
+ { ACMOVWPC, yml_rl, Pq, 0x4b },
+ { ACMOVWPL, yml_rl, Pq, 0x49 },
+ { ACMOVWPS, yml_rl, Pq, 0x4a },
+ { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
+ { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPPD, yxcmpi, Px, Pe,0xc2 },
+ { ACMPPS, yxcmpi, Pm, 0xc2,0 },
+ { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPSB, ynone, Pb, 0xa6 },
+ { ACMPSD, yxcmpi, Px, Pf2,0xc2 },
+ { ACMPSL, ynone, Px, 0xa7 },
+ { ACMPSQ, ynone, Pw, 0xa7 },
+ { ACMPSS, yxcmpi, Px, Pf3,0xc2 },
+ { ACMPSW, ynone, Pe, 0xa7 },
+ { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACOMISD, yxcmp, Pe, 0x2f },
+ { ACOMISS, yxcmp, Pm, 0x2f },
+ { ACPUID, ynone, Pm, 0xa2 },
+ { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a },
+ { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, },
+ { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d },
+ { ACVTPD2PS, yxm, Pe, 0x5a },
+ { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d },
+ { ACVTPS2PD, yxm, Pm, 0x5a },
+ { API2FW, ymfp, Px, 0x0c },
+ { ACVTSD2SL, yxcvfl, Pf2, 0x2d },
+ { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d },
+ { ACVTSD2SS, yxm, Pf2, 0x5a },
+ { ACVTSL2SD, yxcvlf, Pf2, 0x2a },
+ { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a },
+ { ACVTSL2SS, yxcvlf, Pf3, 0x2a },
+ { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a },
+ { ACVTSS2SD, yxm, Pf3, 0x5a },
+ { ACVTSS2SL, yxcvfl, Pf3, 0x2d },
+ { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d },
+ { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c },
+ { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c },
+ { ACVTTSD2SL, yxcvfl, Pf2, 0x2c },
+ { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c },
+ { ACVTTSS2SL, yxcvfl, Pf3, 0x2c },
+ { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c },
+ { ACWD, ynone, Pe, 0x99 },
+ { ACQO, ynone, Pw, 0x99 },
+ { ADAA, ynone, P32, 0x27 },
+ { ADAS, ynone, P32, 0x2f },
+ { ADATA },
+ { ADECB, yincb, Pb, 0xfe,(01) },
+ { ADECL, yincl, Px, 0xff,(01) },
+ { ADECQ, yincl, Pw, 0xff,(01) },
+ { ADECW, yincw, Pe, 0xff,(01) },
+ { ADIVB, ydivb, Pb, 0xf6,(06) },
+ { ADIVL, ydivl, Px, 0xf7,(06) },
+ { ADIVPD, yxm, Pe, 0x5e },
+ { ADIVPS, yxm, Pm, 0x5e },
+ { ADIVQ, ydivl, Pw, 0xf7,(06) },
+ { ADIVSD, yxm, Pf2, 0x5e },
+ { ADIVSS, yxm, Pf3, 0x5e },
+ { ADIVW, ydivl, Pe, 0xf7,(06) },
+ { AEMMS, ynone, Pm, 0x77 },
+ { AENTER }, /* botch */
+ { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) },
+ { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) },
+ { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) },
+ { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) },
+ { AGLOBL },
+ { AGOK },
+ { AHISTORY },
+ { AHLT, ynone, Px, 0xf4 },
+ { AIDIVB, ydivb, Pb, 0xf6,(07) },
+ { AIDIVL, ydivl, Px, 0xf7,(07) },
+ { AIDIVQ, ydivl, Pw, 0xf7,(07) },
+ { AIDIVW, ydivl, Pe, 0xf7,(07) },
+ { AIMULB, ydivb, Pb, 0xf6,(05) },
+ { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AIMUL3Q, yimul3, Pw, 0x6b,(00) },
+ { AINB, yin, Pb, 0xe4,0xec },
+ { AINCB, yincb, Pb, 0xfe,(00) },
+ { AINCL, yincl, Px, 0xff,(00) },
+ { AINCQ, yincl, Pw, 0xff,(00) },
+ { AINCW, yincw, Pe, 0xff,(00) },
+ { AINL, yin, Px, 0xe5,0xed },
+ { AINSB, ynone, Pb, 0x6c },
+ { AINSL, ynone, Px, 0x6d },
+ { AINSW, ynone, Pe, 0x6d },
+ { AINT, yint, Px, 0xcd },
+ { AINTO, ynone, P32, 0xce },
+ { AINW, yin, Pe, 0xe5,0xed },
+ { AIRETL, ynone, Px, 0xcf },
+ { AIRETQ, ynone, Pw, 0xcf },
+ { AIRETW, ynone, Pe, 0xcf },
+ { AJCC, yjcond, Px, 0x73,0x83,(00) },
+ { AJCS, yjcond, Px, 0x72,0x82 },
+ { AJCXZL, yloop, Px, 0xe3 },
+ { AJCXZQ, yloop, Px, 0xe3 },
+ { AJEQ, yjcond, Px, 0x74,0x84 },
+ { AJGE, yjcond, Px, 0x7d,0x8d },
+ { AJGT, yjcond, Px, 0x7f,0x8f },
+ { AJHI, yjcond, Px, 0x77,0x87 },
+ { AJLE, yjcond, Px, 0x7e,0x8e },
+ { AJLS, yjcond, Px, 0x76,0x86 },
+ { AJLT, yjcond, Px, 0x7c,0x8c },
+ { AJMI, yjcond, Px, 0x78,0x88 },
+ { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
+ { AJNE, yjcond, Px, 0x75,0x85 },
+ { AJOC, yjcond, Px, 0x71,0x81,(00) },
+ { AJOS, yjcond, Px, 0x70,0x80,(00) },
+ { AJPC, yjcond, Px, 0x7b,0x8b },
+ { AJPL, yjcond, Px, 0x79,0x89 },
+ { AJPS, yjcond, Px, 0x7a,0x8a },
+ { ALAHF, ynone, Px, 0x9f },
+ { ALARL, yml_rl, Pm, 0x02 },
+ { ALARW, yml_rl, Pq, 0x02 },
+ { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) },
+ { ALEAL, ym_rl, Px, 0x8d },
+ { ALEAQ, ym_rl, Pw, 0x8d },
+ { ALEAVEL, ynone, P32, 0xc9 },
+ { ALEAVEQ, ynone, Py, 0xc9 },
+ { ALEAVEW, ynone, Pe, 0xc9 },
+ { ALEAW, ym_rl, Pe, 0x8d },
+ { ALOCK, ynone, Px, 0xf0 },
+ { ALODSB, ynone, Pb, 0xac },
+ { ALODSL, ynone, Px, 0xad },
+ { ALODSQ, ynone, Pw, 0xad },
+ { ALODSW, ynone, Pe, 0xad },
+ { ALONG, ybyte, Px, 4 },
+ { ALOOP, yloop, Px, 0xe2 },
+ { ALOOPEQ, yloop, Px, 0xe1 },
+ { ALOOPNE, yloop, Px, 0xe0 },
+ { ALSLL, yml_rl, Pm, 0x03 },
+ { ALSLW, yml_rl, Pq, 0x03 },
+ { AMASKMOVOU, yxr, Pe, 0xf7 },
+ { AMASKMOVQ, ymr, Pm, 0xf7 },
+ { AMAXPD, yxm, Pe, 0x5f },
+ { AMAXPS, yxm, Pm, 0x5f },
+ { AMAXSD, yxm, Pf2, 0x5f },
+ { AMAXSS, yxm, Pf3, 0x5f },
+ { AMINPD, yxm, Pe, 0x5d },
+ { AMINPS, yxm, Pm, 0x5d },
+ { AMINSD, yxm, Pf2, 0x5d },
+ { AMINSS, yxm, Pf3, 0x5d },
+ { AMOVAPD, yxmov, Pe, 0x28,0x29 },
+ { AMOVAPS, yxmov, Pm, 0x28,0x29 },
+ { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
+ { AMOVBLSX, ymb_rl, Pm, 0xbe },
+ { AMOVBLZX, ymb_rl, Pm, 0xb6 },
+ { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe },
+ { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 },
+ { AMOVBWSX, ymb_rl, Pq, 0xbe },
+ { AMOVBWZX, ymb_rl, Pq, 0xb6 },
+ { AMOVO, yxmov, Pe, 0x6f,0x7f },
+ { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
+ { AMOVHLPS, yxr, Pm, 0x12 },
+ { AMOVHPD, yxmov, Pe, 0x16,0x17 },
+ { AMOVHPS, yxmov, Pm, 0x16,0x17 },
+ { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e,0 },
+ { AMOVLHPS, yxr, Pm, 0x16 },
+ { AMOVLPD, yxmov, Pe, 0x12,0x13 },
+ { AMOVLPS, yxmov, Pm, 0x12,0x13 },
+ { AMOVLQSX, yml_rl, Pw, 0x63 },
+ { AMOVLQZX, yml_rl, Px, 0x8b },
+ { AMOVMSKPD, yxrrl, Pq, 0x50 },
+ { AMOVMSKPS, yxrrl, Pm, 0x50 },
+ { AMOVNTO, yxr_ml, Pe, 0xe7 },
+ { AMOVNTPD, yxr_ml, Pe, 0x2b },
+ { AMOVNTPS, yxr_ml, Pm, 0x2b },
+ { AMOVNTQ, ymr_ml, Pm, 0xe7 },
+ { AMOVQ, ymovq, Pw, 0x89, 0x8b, 0x31, 0xc7,(00), 0xb8, 0xc7,(00), 0x6f, 0x7f, 0x6e, 0x7e, Pf2,0xd6, Pf3,0x7e, Pe,0xd6, Pe,0x6e, Pe,0x7e,0 },
+ { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e },
+ { AMOVSB, ynone, Pb, 0xa4 },
+ { AMOVSD, yxmov, Pf2, 0x10,0x11 },
+ { AMOVSL, ynone, Px, 0xa5 },
+ { AMOVSQ, ynone, Pw, 0xa5 },
+ { AMOVSS, yxmov, Pf3, 0x10,0x11 },
+ { AMOVSW, ynone, Pe, 0xa5 },
+ { AMOVUPD, yxmov, Pe, 0x10,0x11 },
+ { AMOVUPS, yxmov, Pm, 0x10,0x11 },
+ { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00),0 },
+ { AMOVWLSX, yml_rl, Pm, 0xbf },
+ { AMOVWLZX, yml_rl, Pm, 0xb7 },
+ { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf },
+ { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 },
+ { AMULB, ydivb, Pb, 0xf6,(04) },
+ { AMULL, ydivl, Px, 0xf7,(04) },
+ { AMULPD, yxm, Pe, 0x59 },
+ { AMULPS, yxm, Ym, 0x59 },
+ { AMULQ, ydivl, Pw, 0xf7,(04) },
+ { AMULSD, yxm, Pf2, 0x59 },
+ { AMULSS, yxm, Pf3, 0x59 },
+ { AMULW, ydivl, Pe, 0xf7,(04) },
+ { ANAME },
+ { ANEGB, yscond, Pb, 0xf6,(03) },
+ { ANEGL, yscond, Px, 0xf7,(03) },
+ { ANEGQ, yscond, Pw, 0xf7,(03) },
+ { ANEGW, yscond, Pe, 0xf7,(03) },
+ { ANOP, ynop, Px, 0,0 },
+ { ANOTB, yscond, Pb, 0xf6,(02) },
+ { ANOTL, yscond, Px, 0xf7,(02) },
+ { ANOTQ, yscond, Pw, 0xf7,(02) },
+ { ANOTW, yscond, Pe, 0xf7,(02) },
+ { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
+ { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AORPD, yxm, Pq, 0x56 },
+ { AORPS, yxm, Pm, 0x56 },
+ { AORQ, yxorl, Pw, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AOUTB, yin, Pb, 0xe6,0xee },
+ { AOUTL, yin, Px, 0xe7,0xef },
+ { AOUTSB, ynone, Pb, 0x6e },
+ { AOUTSL, ynone, Px, 0x6f },
+ { AOUTSW, ynone, Pe, 0x6f },
+ { AOUTW, yin, Pe, 0xe7,0xef },
+ { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b },
+ { APACKSSWB, ymm, Py, 0x63,Pe,0x63 },
+ { APACKUSWB, ymm, Py, 0x67,Pe,0x67 },
+ { APADDB, ymm, Py, 0xfc,Pe,0xfc },
+ { APADDL, ymm, Py, 0xfe,Pe,0xfe },
+ { APADDQ, yxm, Pe, 0xd4 },
+ { APADDSB, ymm, Py, 0xec,Pe,0xec },
+ { APADDSW, ymm, Py, 0xed,Pe,0xed },
+ { APADDUSB, ymm, Py, 0xdc,Pe,0xdc },
+ { APADDUSW, ymm, Py, 0xdd,Pe,0xdd },
+ { APADDW, ymm, Py, 0xfd,Pe,0xfd },
+ { APAND, ymm, Py, 0xdb,Pe,0xdb },
+ { APANDN, ymm, Py, 0xdf,Pe,0xdf },
+ { APAUSE, ynone, Px, 0xf3,0x90 },
+ { APAVGB, ymm, Py, 0xe0,Pe,0xe0 },
+ { APAVGW, ymm, Py, 0xe3,Pe,0xe3 },
+ { APCMPEQB, ymm, Py, 0x74,Pe,0x74 },
+ { APCMPEQL, ymm, Py, 0x76,Pe,0x76 },
+ { APCMPEQW, ymm, Py, 0x75,Pe,0x75 },
+ { APCMPGTB, ymm, Py, 0x64,Pe,0x64 },
+ { APCMPGTL, ymm, Py, 0x66,Pe,0x66 },
+ { APCMPGTW, ymm, Py, 0x65,Pe,0x65 },
+ { APEXTRW, yextrw, Pq, 0xc5,(00) },
+ { APF2IL, ymfp, Px, 0x1d },
+ { APF2IW, ymfp, Px, 0x1c },
+ { API2FL, ymfp, Px, 0x0d },
+ { APFACC, ymfp, Px, 0xae },
+ { APFADD, ymfp, Px, 0x9e },
+ { APFCMPEQ, ymfp, Px, 0xb0 },
+ { APFCMPGE, ymfp, Px, 0x90 },
+ { APFCMPGT, ymfp, Px, 0xa0 },
+ { APFMAX, ymfp, Px, 0xa4 },
+ { APFMIN, ymfp, Px, 0x94 },
+ { APFMUL, ymfp, Px, 0xb4 },
+ { APFNACC, ymfp, Px, 0x8a },
+ { APFPNACC, ymfp, Px, 0x8e },
+ { APFRCP, ymfp, Px, 0x96 },
+ { APFRCPIT1, ymfp, Px, 0xa6 },
+ { APFRCPI2T, ymfp, Px, 0xb6 },
+ { APFRSQIT1, ymfp, Px, 0xa7 },
+ { APFRSQRT, ymfp, Px, 0x97 },
+ { APFSUB, ymfp, Px, 0x9a },
+ { APFSUBR, ymfp, Px, 0xaa },
+ { APINSRW, yinsrw, Pq, 0xc4,(00) },
+ { APINSRD, yinsr, Pq, 0x3a, 0x22, (00) },
+ { APINSRQ, yinsr, Pq3, 0x3a, 0x22, (00) },
+ { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 },
+ { APMAXSW, yxm, Pe, 0xee },
+ { APMAXUB, yxm, Pe, 0xde },
+ { APMINSW, yxm, Pe, 0xea },
+ { APMINUB, yxm, Pe, 0xda },
+ { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 },
+ { APMULHRW, ymfp, Px, 0xb7 },
+ { APMULHUW, ymm, Py, 0xe4,Pe,0xe4 },
+ { APMULHW, ymm, Py, 0xe5,Pe,0xe5 },
+ { APMULLW, ymm, Py, 0xd5,Pe,0xd5 },
+ { APMULULQ, ymm, Py, 0xf4,Pe,0xf4 },
+ { APOPAL, ynone, P32, 0x61 },
+ { APOPAW, ynone, Pe, 0x61 },
+ { APOPFL, ynone, P32, 0x9d },
+ { APOPFQ, ynone, Py, 0x9d },
+ { APOPFW, ynone, Pe, 0x9d },
+ { APOPL, ypopl, P32, 0x58,0x8f,(00) },
+ { APOPQ, ypopl, Py, 0x58,0x8f,(00) },
+ { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
+ { APOR, ymm, Py, 0xeb,Pe,0xeb },
+ { APSADBW, yxm, Pq, 0xf6 },
+ { APSHUFHW, yxshuf, Pf3, 0x70,(00) },
+ { APSHUFL, yxshuf, Pq, 0x70,(00) },
+ { APSHUFLW, yxshuf, Pf2, 0x70,(00) },
+ { APSHUFW, ymshuf, Pm, 0x70,(00) },
+ { APSHUFB, ymshufb,Pq, 0x38, 0x00 },
+ { APSLLO, ypsdq, Pq, 0x73,(07) },
+ { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) },
+ { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06) },
+ { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) },
+ { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) },
+ { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) },
+ { APSRLO, ypsdq, Pq, 0x73,(03) },
+ { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) },
+ { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) },
+ { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) },
+ { APSUBB, yxm, Pe, 0xf8 },
+ { APSUBL, yxm, Pe, 0xfa },
+ { APSUBQ, yxm, Pe, 0xfb },
+ { APSUBSB, yxm, Pe, 0xe8 },
+ { APSUBSW, yxm, Pe, 0xe9 },
+ { APSUBUSB, yxm, Pe, 0xd8 },
+ { APSUBUSW, yxm, Pe, 0xd9 },
+ { APSUBW, yxm, Pe, 0xf9 },
+ { APSWAPL, ymfp, Px, 0xbb },
+ { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 },
+ { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a },
+ { APUNPCKHQDQ, yxm, Pe, 0x6d },
+ { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 },
+ { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 },
+ { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 },
+ { APUNPCKLQDQ, yxm, Pe, 0x6c },
+ { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 },
+ { APUSHAL, ynone, P32, 0x60 },
+ { APUSHAW, ynone, Pe, 0x60 },
+ { APUSHFL, ynone, P32, 0x9c },
+ { APUSHFQ, ynone, Py, 0x9c },
+ { APUSHFW, ynone, Pe, 0x9c },
+ { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
+ { APXOR, ymm, Py, 0xef,Pe,0xef },
+ { AQUAD, ybyte, Px, 8 },
+ { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
+ { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCPPS, yxm, Pm, 0x53 },
+ { ARCPSS, yxm, Pf3, 0x53 },
+ { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
+ { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { ARCRQ, yshl, Pw, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { AREP, ynone, Px, 0xf3 },
+ { AREPN, ynone, Px, 0xf2 },
+ { ARET, ynone, Px, 0xc3 },
+ { ARETFW, yret, Pe, 0xcb,0xca },
+ { ARETFL, yret, Px, 0xcb,0xca },
+ { ARETFQ, yret, Pw, 0xcb,0xca },
+ { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
+ { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { AROLQ, yshl, Pw, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
+ { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARSQRTPS, yxm, Pm, 0x52 },
+ { ARSQRTSS, yxm, Pf3, 0x52 },
+ { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */
+ { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASALQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
+ { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASARQ, yshl, Pw, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
+ { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASBBQ, yxorl, Pw, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASCASB, ynone, Pb, 0xae },
+ { ASCASL, ynone, Px, 0xaf },
+ { ASCASQ, ynone, Pw, 0xaf },
+ { ASCASW, ynone, Pe, 0xaf },
+ { ASETCC, yscond, Pm, 0x93,(00) },
+ { ASETCS, yscond, Pm, 0x92,(00) },
+ { ASETEQ, yscond, Pm, 0x94,(00) },
+ { ASETGE, yscond, Pm, 0x9d,(00) },
+ { ASETGT, yscond, Pm, 0x9f,(00) },
+ { ASETHI, yscond, Pm, 0x97,(00) },
+ { ASETLE, yscond, Pm, 0x9e,(00) },
+ { ASETLS, yscond, Pm, 0x96,(00) },
+ { ASETLT, yscond, Pm, 0x9c,(00) },
+ { ASETMI, yscond, Pm, 0x98,(00) },
+ { ASETNE, yscond, Pm, 0x95,(00) },
+ { ASETOC, yscond, Pm, 0x91,(00) },
+ { ASETOS, yscond, Pm, 0x90,(00) },
+ { ASETPC, yscond, Pm, 0x96,(00) },
+ { ASETPL, yscond, Pm, 0x99,(00) },
+ { ASETPS, yscond, Pm, 0x9a,(00) },
+ { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHLQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
+ { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHUFPD, yxshuf, Pq, 0xc6,(00) },
+ { ASHUFPS, yxshuf, Pm, 0xc6,(00) },
+ { ASQRTPD, yxm, Pe, 0x51 },
+ { ASQRTPS, yxm, Pm, 0x51 },
+ { ASQRTSD, yxm, Pf2, 0x51 },
+ { ASQRTSS, yxm, Pf3, 0x51 },
+ { ASTC, ynone, Px, 0xf9 },
+ { ASTD, ynone, Px, 0xfd },
+ { ASTI, ynone, Px, 0xfb },
+ { ASTMXCSR, ysvrs, Pm, 0xae,(03),0xae,(03) },
+ { ASTOSB, ynone, Pb, 0xaa },
+ { ASTOSL, ynone, Px, 0xab },
+ { ASTOSQ, ynone, Pw, 0xab },
+ { ASTOSW, ynone, Pe, 0xab },
+ { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
+ { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBPD, yxm, Pe, 0x5c },
+ { ASUBPS, yxm, Pm, 0x5c },
+ { ASUBQ, yaddl, Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBSD, yxm, Pf2, 0x5c },
+ { ASUBSS, yxm, Pf3, 0x5c },
+ { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASWAPGS, ynone, Pm, 0x01,0xf8 },
+ { ASYSCALL, ynone, Px, 0x0f,0x05 }, /* fast syscall */
+ { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
+ { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTQ, ytestl, Pw, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATEXT, ytext, Px },
+ { AUCOMISD, yxcmp, Pe, 0x2e },
+ { AUCOMISS, yxcmp, Pm, 0x2e },
+ { AUNPCKHPD, yxm, Pe, 0x15 },
+ { AUNPCKHPS, yxm, Pm, 0x15 },
+ { AUNPCKLPD, yxm, Pe, 0x14 },
+ { AUNPCKLPS, yxm, Pm, 0x14 },
+ { AVERR, ydivl, Pm, 0x00,(04) },
+ { AVERW, ydivl, Pm, 0x00,(05) },
+ { AWAIT, ynone, Px, 0x9b },
+ { AWORD, ybyte, Px, 2 },
+ { AXCHGB, yml_mb, Pb, 0x86,0x86 },
+ { AXCHGL, yxchg, Px, 0x90,0x90,0x87,0x87 },
+ { AXCHGQ, yxchg, Pw, 0x90,0x90,0x87,0x87 },
+ { AXCHGW, yxchg, Pe, 0x90,0x90,0x87,0x87 },
+ { AXLAT, ynone, Px, 0xd7 },
+ { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
+ { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+ { AXORPD, yxm, Pe, 0x57 },
+ { AXORPS, yxm, Pm, 0x57 },
+ { AXORQ, yxorl, Pw, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+ { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+
+ { AFMOVB, yfmvx, Px, 0xdf,(04) },
+ { AFMOVBP, yfmvp, Px, 0xdf,(06) },
+ { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
+ { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
+ { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
+ { AFMOVFP, yfmvp, Px, 0xd9,(03) },
+ { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
+ { AFMOVLP, yfmvp, Px, 0xdb,(03) },
+ { AFMOVV, yfmvx, Px, 0xdf,(05) },
+ { AFMOVVP, yfmvp, Px, 0xdf,(07) },
+ { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
+ { AFMOVWP, yfmvp, Px, 0xdf,(03) },
+ { AFMOVX, yfmvx, Px, 0xdb,(05) },
+ { AFMOVXP, yfmvp, Px, 0xdb,(07) },
+
+ { AFCOMB },
+ { AFCOMBP },
+ { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
+ { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
+ { AFCOMDPP, ycompp, Px, 0xde,(03) },
+ { AFCOMF, yfmvx, Px, 0xd8,(02) },
+ { AFCOMFP, yfmvx, Px, 0xd8,(03) },
+ { AFCOML, yfmvx, Px, 0xda,(02) },
+ { AFCOMLP, yfmvx, Px, 0xda,(03) },
+ { AFCOMW, yfmvx, Px, 0xde,(02) },
+ { AFCOMWP, yfmvx, Px, 0xde,(03) },
+
+ { AFUCOM, ycompp, Px, 0xdd,(04) },
+ { AFUCOMP, ycompp, Px, 0xdd,(05) },
+ { AFUCOMPP, ycompp, Px, 0xda,(13) },
+
+ { AFADDDP, yfaddp, Px, 0xde,(00) },
+ { AFADDW, yfmvx, Px, 0xde,(00) },
+ { AFADDL, yfmvx, Px, 0xda,(00) },
+ { AFADDF, yfmvx, Px, 0xd8,(00) },
+ { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
+
+ { AFMULDP, yfaddp, Px, 0xde,(01) },
+ { AFMULW, yfmvx, Px, 0xde,(01) },
+ { AFMULL, yfmvx, Px, 0xda,(01) },
+ { AFMULF, yfmvx, Px, 0xd8,(01) },
+ { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
+
+ { AFSUBDP, yfaddp, Px, 0xde,(05) },
+ { AFSUBW, yfmvx, Px, 0xde,(04) },
+ { AFSUBL, yfmvx, Px, 0xda,(04) },
+ { AFSUBF, yfmvx, Px, 0xd8,(04) },
+ { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
+
+ { AFSUBRDP, yfaddp, Px, 0xde,(04) },
+ { AFSUBRW, yfmvx, Px, 0xde,(05) },
+ { AFSUBRL, yfmvx, Px, 0xda,(05) },
+ { AFSUBRF, yfmvx, Px, 0xd8,(05) },
+ { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
+
+ { AFDIVDP, yfaddp, Px, 0xde,(07) },
+ { AFDIVW, yfmvx, Px, 0xde,(06) },
+ { AFDIVL, yfmvx, Px, 0xda,(06) },
+ { AFDIVF, yfmvx, Px, 0xd8,(06) },
+ { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
+
+ { AFDIVRDP, yfaddp, Px, 0xde,(06) },
+ { AFDIVRW, yfmvx, Px, 0xde,(07) },
+ { AFDIVRL, yfmvx, Px, 0xda,(07) },
+ { AFDIVRF, yfmvx, Px, 0xd8,(07) },
+ { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
+
+ { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
+ { AFFREE },
+ { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
+ { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
+ { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
+ { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
+ { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
+ { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
+ { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
+ { AF2XM1, ynone, Px, 0xd9, 0xf0 },
+ { AFABS, ynone, Px, 0xd9, 0xe1 },
+ { AFCHS, ynone, Px, 0xd9, 0xe0 },
+ { AFCLEX, ynone, Px, 0xdb, 0xe2 },
+ { AFCOS, ynone, Px, 0xd9, 0xff },
+ { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
+ { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
+ { AFINIT, ynone, Px, 0xdb, 0xe3 },
+ { AFLD1, ynone, Px, 0xd9, 0xe8 },
+ { AFLDL2E, ynone, Px, 0xd9, 0xea },
+ { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
+ { AFLDLG2, ynone, Px, 0xd9, 0xec },
+ { AFLDLN2, ynone, Px, 0xd9, 0xed },
+ { AFLDPI, ynone, Px, 0xd9, 0xeb },
+ { AFLDZ, ynone, Px, 0xd9, 0xee },
+ { AFNOP, ynone, Px, 0xd9, 0xd0 },
+ { AFPATAN, ynone, Px, 0xd9, 0xf3 },
+ { AFPREM, ynone, Px, 0xd9, 0xf8 },
+ { AFPREM1, ynone, Px, 0xd9, 0xf5 },
+ { AFPTAN, ynone, Px, 0xd9, 0xf2 },
+ { AFRNDINT, ynone, Px, 0xd9, 0xfc },
+ { AFSCALE, ynone, Px, 0xd9, 0xfd },
+ { AFSIN, ynone, Px, 0xd9, 0xfe },
+ { AFSINCOS, ynone, Px, 0xd9, 0xfb },
+ { AFSQRT, ynone, Px, 0xd9, 0xfa },
+ { AFTST, ynone, Px, 0xd9, 0xe4 },
+ { AFXAM, ynone, Px, 0xd9, 0xe5 },
+ { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
+ { AFYL2X, ynone, Px, 0xd9, 0xf1 },
+ { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
+
+ { ACMPXCHGB, yrb_mb, Pb, 0x0f,0xb0 },
+ { ACMPXCHGL, yrl_ml, Px, 0x0f,0xb1 },
+ { ACMPXCHGW, yrl_ml, Pe, 0x0f,0xb1 },
+ { ACMPXCHGQ, yrl_ml, Pw, 0x0f,0xb1 },
+ { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
+ { AINVD, ynone, Pm, 0x08 },
+ { AINVLPG, ymbs, Pm, 0x01,(07) },
+ { ALFENCE, ynone, Pm, 0xae,0xe8 },
+ { AMFENCE, ynone, Pm, 0xae,0xf0 },
+ { AMOVNTIL, yrl_ml, Pm, 0xc3 },
+ { AMOVNTIQ, yrl_ml, Pw, 0x0f,0xc3 },
+ { ARDMSR, ynone, Pm, 0x32 },
+ { ARDPMC, ynone, Pm, 0x33 },
+ { ARDTSC, ynone, Pm, 0x31 },
+ { ARSM, ynone, Pm, 0xaa },
+ { ASFENCE, ynone, Pm, 0xae,0xf8 },
+ { ASYSRET, ynone, Pm, 0x07 },
+ { AWBINVD, ynone, Pm, 0x09 },
+ { AWRMSR, ynone, Pm, 0x30 },
+
+ { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
+ { AXADDL, yrl_ml, Px, 0x0f,0xc1 },
+ { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 },
+ { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
+
+ { ACRC32B, ycrc32l,Px, 0xf2,0x0f,0x38,0xf0,0 },
+ { ACRC32Q, ycrc32l,Pw, 0xf2,0x0f,0x38,0xf1,0 },
+
+ { APREFETCHT0, yprefetch, Pm, 0x18,(01) },
+ { APREFETCHT1, yprefetch, Pm, 0x18,(02) },
+ { APREFETCHT2, yprefetch, Pm, 0x18,(03) },
+ { APREFETCHNTA, yprefetch, Pm, 0x18,(00) },
+
+ { AMOVQL, yrl_ml, Px, 0x89 },
+
+ { AUNDEF, ynone, Px, 0x0f, 0x0b },
+
+ { AAESENC, yaes, Pq, 0x38,0xdc,(0) },
+ { AAESENCLAST, yaes, Pq, 0x38,0xdd,(0) },
+ { AAESDEC, yaes, Pq, 0x38,0xde,(0) },
+ { AAESDECLAST, yaes, Pq, 0x38,0xdf,(0) },
+ { AAESIMC, yaes, Pq, 0x38,0xdb,(0) },
+ { AAESKEYGENASSIST, yaes2, Pq, 0x3a,0xdf,(0) },
+
+ { APSHUFD, yaes2, Pq, 0x70,(0) },
+ { APCLMULQDQ, yxshuf, Pq, 0x3a,0x44,0 },
+
+ { AUSEFIELD, ynop, Px, 0,0 },
+ { ATYPE },
+ { AFUNCDATA, yfuncdata, Px, 0,0 },
+ { APCDATA, ypcdata, Px, 0,0 },
+ { ACHECKNIL },
+ { AFATVARDEF },
+
+ { AEND },
+ 0
+};
+
+static Optab* opindex[ALAST+1];
+static vlong vaddr(Link*, Addr*, Reloc*);
+
+// single-instruction no-ops of various lengths.
+// constructed by hand ctxt->and disassembled with gdb to verify.
+// see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion.
+static uchar nop[][16] = {
+ {0x90},
+ {0x66, 0x90},
+ {0x0F, 0x1F, 0x00},
+ {0x0F, 0x1F, 0x40, 0x00},
+ {0x0F, 0x1F, 0x44, 0x00, 0x00},
+ {0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00},
+ {0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00},
+ {0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
+};
+
+static void
+fillnop(uchar *p, int n)
+{
+ int m;
+
+ while(n > 0) {
+ m = n;
+ if(m > nelem(nop))
+ m = nelem(nop);
+ memmove(p, nop[m-1], m);
+ p += m;
+ n -= m;
+ }
+}
+
+static void instinit(void);
+
+void
+span6(Link *ctxt, LSym *s)
+{
+ Prog *p, *q;
+ int32 c, v, loop;
+ uchar *bp;
+ int n, m, i;
+
+ ctxt->cursym = s;
+
+ if(s->p != nil)
+ return;
+
+ if(ycover[0] == 0)
+ instinit();
+
+ for(p = ctxt->cursym->text; p != nil; p = p->link) {
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == nil)
+ p->pcond = p;
+ if((q = p->pcond) != nil)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = p->mode != 64? AADDL: AADDQ;
+ if(v < 0) {
+ p->as = p->mode != 64? ASUBL: ASUBQ;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+
+ for(p = s->text; p != nil; p = p->link) {
+ p->back = 2; // use short branches first time through
+ if((q = p->pcond) != nil && (q->back & 2)) {
+ p->back |= 1; // backward jump
+ q->back |= 4; // loop head
+ }
+
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = p->mode != 64? AADDL: AADDQ;
+ if(v < 0) {
+ p->as = p->mode != 64? ASUBL: ASUBQ;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+
+ n = 0;
+ do {
+ loop = 0;
+ memset(s->r, 0, s->nr*sizeof s->r[0]);
+ s->nr = 0;
+ s->np = 0;
+ c = 0;
+ for(p = s->text; p != nil; p = p->link) {
+ if((p->back & 4) && (c&(LoopAlign-1)) != 0) {
+ // pad with NOPs
+ v = -c&(LoopAlign-1);
+ if(v <= MaxLoopPad) {
+ symgrow(ctxt, s, c+v);
+ fillnop(s->p+c, v);
+ c += v;
+ }
+ }
+
+ p->pc = c;
+
+ // process forward jumps to p
+ for(q = p->comefrom; q != nil; q = q->forwd) {
+ v = p->pc - (q->pc + q->mark);
+ if(q->back & 2) { // short
+ if(v > 127) {
+ loop++;
+ q->back ^= 2;
+ }
+ if(q->as == AJCXZL)
+ s->p[q->pc+2] = v;
+ else
+ s->p[q->pc+1] = v;
+ } else {
+ bp = s->p + q->pc + q->mark - 4;
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp = v>>24;
+ }
+ }
+ p->comefrom = nil;
+
+ asmins(ctxt, p);
+ p->pc = c;
+ m = ctxt->andptr-ctxt->and;
+ symgrow(ctxt, s, p->pc+m);
+ memmove(s->p+p->pc, ctxt->and, m);
+ p->mark = m;
+ c += m;
+ }
+ if(++n > 20) {
+ ctxt->diag("span must be looping");
+ sysfatal("loop");
+ }
+ } while(loop);
+ s->size = c;
+
+ if(0 /* debug['a'] > 1 */) {
+ print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
+ for(i=0; i<s->np; i++) {
+ print(" %.2ux", s->p[i]);
+ if(i%16 == 15)
+ print("\n %.6ux", i+1);
+ }
+ if(i%16)
+ print("\n");
+
+ for(i=0; i<s->nr; i++) {
+ Reloc *r;
+
+ r = &s->r[i];
+ print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
+ }
+ }
+}
+
+static void
+instinit(void)
+{
+ int c, i;
+
+ for(i=1; optab[i].as; i++) {
+ c = optab[i].as;
+ if(opindex[c] != nil)
+ sysfatal("phase error in optab: %d (%A)", i, c);
+ opindex[c] = &optab[i];
+ }
+
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Ys32] = 1;
+ ycover[Yi1*Ymax + Ys32] = 1;
+ ycover[Yi8*Ymax + Ys32] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+ ycover[Ys32*Ymax + Yi32] = 1;
+
+ ycover[Yi0*Ymax + Yi64] = 1;
+ ycover[Yi1*Ymax + Yi64] = 1;
+ ycover[Yi8*Ymax + Yi64] = 1;
+ ycover[Ys32*Ymax + Yi64] = 1;
+ ycover[Yi32*Ymax + Yi64] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+ ycover[Yrl*Ymax + Yrb] = 1;
+
+ ycover[Ycl*Ymax + Ycx] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Yrl*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ ycover[Yax*Ymax + Ymm] = 1;
+ ycover[Ycx*Ymax + Ymm] = 1;
+ ycover[Yrx*Ymax + Ymm] = 1;
+ ycover[Yrl*Ymax + Ymm] = 1;
+ ycover[Ym*Ymax + Ymm] = 1;
+ ycover[Ymr*Ymax + Ymm] = 1;
+
+ ycover[Ym*Ymax + Yxm] = 1;
+ ycover[Yxr*Ymax + Yxm] = 1;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_R15B) {
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_SPB && i <= D_DIB)
+ regrex[i] = 0x40;
+ if(i >= D_R8B && i <= D_R15B)
+ regrex[i] = Rxr | Rxx | Rxb;
+ }
+ if(i >= D_AH && i<= D_BH)
+ reg[i] = 4 + ((i-D_AH) & 7);
+ if(i >= D_AX && i <= D_R15) {
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_R8)
+ regrex[i] = Rxr | Rxx | Rxb;
+ }
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
+ if(i >= D_M0 && i <= D_M0+7)
+ reg[i] = (i-D_M0) & 7;
+ if(i >= D_X0 && i <= D_X0+15) {
+ reg[i] = (i-D_X0) & 7;
+ if(i >= D_X0+8)
+ regrex[i] = Rxr | Rxx | Rxb;
+ }
+ if(i >= D_CR+8 && i <= D_CR+15)
+ regrex[i] = Rxr;
+ }
+}
+
+static int
+prefixof(Addr *a)
+{
+ switch(a->type) {
+ case D_INDIR+D_CS:
+ return 0x2e;
+ case D_INDIR+D_DS:
+ return 0x3e;
+ case D_INDIR+D_ES:
+ return 0x26;
+ case D_INDIR+D_FS:
+ return 0x64;
+ case D_INDIR+D_GS:
+ return 0x65;
+ }
+ switch(a->index) {
+ case D_CS:
+ return 0x2e;
+ case D_DS:
+ return 0x3e;
+ case D_ES:
+ return 0x26;
+ case D_FS:
+ return 0x64;
+ case D_GS:
+ return 0x65;
+ }
+ return 0;
+}
+
+static int
+oclass(Link *ctxt, Addr *a)
+{
+ vlong v;
+ int32 l;
+
+ if(a->type >= D_INDIR || a->index != D_NONE) {
+ if(a->index != D_NONE && a->scale == 0) {
+ if(a->type == D_ADDR) {
+ switch(a->index) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(ctxt->flag_shared)
+ return Yiauto;
+ else
+ return Yi32; /* TO DO: Yi64 */
+ case D_AUTO:
+ case D_PARAM:
+ return Yiauto;
+ }
+ return Yxxx;
+ }
+ return Ycol;
+ }
+ return Ym;
+ }
+ switch(a->type)
+ {
+ case D_AL:
+ return Yal;
+
+ case D_AX:
+ return Yax;
+
+/*
+ case D_SPB:
+*/
+ case D_BPB:
+ case D_SIB:
+ case D_DIB:
+ case D_R8B:
+ case D_R9B:
+ case D_R10B:
+ case D_R11B:
+ case D_R12B:
+ case D_R13B:
+ case D_R14B:
+ case D_R15B:
+ if(ctxt->asmode != 64)
+ return Yxxx;
+ case D_DL:
+ case D_BL:
+ case D_AH:
+ case D_CH:
+ case D_DH:
+ case D_BH:
+ return Yrb;
+
+ case D_CL:
+ return Ycl;
+
+ case D_CX:
+ return Ycx;
+
+ case D_DX:
+ case D_BX:
+ return Yrx;
+
+ case D_R8: /* not really Yrl */
+ case D_R9:
+ case D_R10:
+ case D_R11:
+ case D_R12:
+ case D_R13:
+ case D_R14:
+ case D_R15:
+ if(ctxt->asmode != 64)
+ return Yxxx;
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ return Yrl;
+
+ case D_F0+0:
+ return Yf0;
+
+ case D_F0+1:
+ case D_F0+2:
+ case D_F0+3:
+ case D_F0+4:
+ case D_F0+5:
+ case D_F0+6:
+ case D_F0+7:
+ return Yrf;
+
+ case D_M0+0:
+ case D_M0+1:
+ case D_M0+2:
+ case D_M0+3:
+ case D_M0+4:
+ case D_M0+5:
+ case D_M0+6:
+ case D_M0+7:
+ return Ymr;
+
+ case D_X0+0:
+ case D_X0+1:
+ case D_X0+2:
+ case D_X0+3:
+ case D_X0+4:
+ case D_X0+5:
+ case D_X0+6:
+ case D_X0+7:
+ case D_X0+8:
+ case D_X0+9:
+ case D_X0+10:
+ case D_X0+11:
+ case D_X0+12:
+ case D_X0+13:
+ case D_X0+14:
+ case D_X0+15:
+ return Yxr;
+
+ case D_NONE:
+ return Ynone;
+
+ case D_CS: return Ycs;
+ case D_SS: return Yss;
+ case D_DS: return Yds;
+ case D_ES: return Yes;
+ case D_FS: return Yfs;
+ case D_GS: return Ygs;
+
+ case D_GDTR: return Ygdtr;
+ case D_IDTR: return Yidtr;
+ case D_LDTR: return Yldtr;
+ case D_MSW: return Ymsw;
+ case D_TASK: return Ytask;
+
+ case D_CR+0: return Ycr0;
+ case D_CR+1: return Ycr1;
+ case D_CR+2: return Ycr2;
+ case D_CR+3: return Ycr3;
+ case D_CR+4: return Ycr4;
+ case D_CR+5: return Ycr5;
+ case D_CR+6: return Ycr6;
+ case D_CR+7: return Ycr7;
+ case D_CR+8: return Ycr8;
+
+ case D_DR+0: return Ydr0;
+ case D_DR+1: return Ydr1;
+ case D_DR+2: return Ydr2;
+ case D_DR+3: return Ydr3;
+ case D_DR+4: return Ydr4;
+ case D_DR+5: return Ydr5;
+ case D_DR+6: return Ydr6;
+ case D_DR+7: return Ydr7;
+
+ case D_TR+0: return Ytr0;
+ case D_TR+1: return Ytr1;
+ case D_TR+2: return Ytr2;
+ case D_TR+3: return Ytr3;
+ case D_TR+4: return Ytr4;
+ case D_TR+5: return Ytr5;
+ case D_TR+6: return Ytr6;
+ case D_TR+7: return Ytr7;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ return Ym;
+
+ case D_CONST:
+ case D_ADDR:
+ if(a->sym == nil) {
+ v = a->offset;
+ if(v == 0)
+ return Yi0;
+ if(v == 1)
+ return Yi1;
+ if(v >= -128 && v <= 127)
+ return Yi8;
+ l = v;
+ if((vlong)l == v)
+ return Ys32; /* can sign extend */
+ if((v>>32) == 0)
+ return Yi32; /* unsigned */
+ return Yi64;
+ }
+ return Yi32; /* TO DO: D_ADDR as Yi64 */
+
+ case D_BRANCH:
+ return Ybr;
+ }
+ return Yxxx;
+}
+
+static void
+asmidx(Link *ctxt, int scale, int index, int base)
+{
+ int i;
+
+ switch(index) {
+ default:
+ goto bad;
+
+ case D_NONE:
+ i = 4 << 3;
+ goto bas;
+
+ case D_R8:
+ case D_R9:
+ case D_R10:
+ case D_R11:
+ case D_R12:
+ case D_R13:
+ case D_R14:
+ case D_R15:
+ if(ctxt->asmode != 64)
+ goto bad;
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i = reg[index] << 3;
+ break;
+ }
+ switch(scale) {
+ default:
+ goto bad;
+ case 1:
+ break;
+ case 2:
+ i |= (1<<6);
+ break;
+ case 4:
+ i |= (2<<6);
+ break;
+ case 8:
+ i |= (3<<6);
+ break;
+ }
+bas:
+ switch(base) {
+ default:
+ goto bad;
+ case D_NONE: /* must be mod=00 */
+ i |= 5;
+ break;
+ case D_R8:
+ case D_R9:
+ case D_R10:
+ case D_R11:
+ case D_R12:
+ case D_R13:
+ case D_R14:
+ case D_R15:
+ if(ctxt->asmode != 64)
+ goto bad;
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i |= reg[base];
+ break;
+ }
+ *ctxt->andptr++ = i;
+ return;
+bad:
+ ctxt->diag("asmidx: bad address %d/%d/%d", scale, index, base);
+ *ctxt->andptr++ = 0;
+ return;
+}
+
+static void
+put4(Link *ctxt, int32 v)
+{
+ ctxt->andptr[0] = v;
+ ctxt->andptr[1] = v>>8;
+ ctxt->andptr[2] = v>>16;
+ ctxt->andptr[3] = v>>24;
+ ctxt->andptr += 4;
+}
+
+static void
+relput4(Link *ctxt, Prog *p, Addr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(ctxt, a, &rel);
+ if(rel.siz != 0) {
+ if(rel.siz != 4)
+ ctxt->diag("bad reloc");
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ put4(ctxt, v);
+}
+
+static void
+put8(Link *ctxt, vlong v)
+{
+ ctxt->andptr[0] = v;
+ ctxt->andptr[1] = v>>8;
+ ctxt->andptr[2] = v>>16;
+ ctxt->andptr[3] = v>>24;
+ ctxt->andptr[4] = v>>32;
+ ctxt->andptr[5] = v>>40;
+ ctxt->andptr[6] = v>>48;
+ ctxt->andptr[7] = v>>56;
+ ctxt->andptr += 8;
+}
+
+/*
+static void
+relput8(Prog *p, Addr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(ctxt, a, &rel);
+ if(rel.siz != 0) {
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->siz = 8;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ put8(ctxt, v);
+}
+*/
+
+static vlong
+vaddr(Link *ctxt, Addr *a, Reloc *r)
+{
+ int t;
+ vlong v;
+ LSym *s;
+
+ if(r != nil)
+ memset(r, 0, sizeof *r);
+
+ t = a->type;
+ v = a->offset;
+ if(t == D_ADDR)
+ t = a->index;
+ switch(t) {
+ case D_STATIC:
+ case D_EXTERN:
+ s = a->sym;
+ if(r == nil) {
+ ctxt->diag("need reloc for %D", a);
+ sysfatal("reloc");
+ }
+ r->siz = 4; // TODO: 8 for external symbols
+ r->off = -1; // caller must fill in
+ r->sym = s;
+ r->add = v;
+ v = 0;
+ if(ctxt->flag_shared) {
+ if(s->type == STLSBSS) {
+ r->xadd = r->add - r->siz;
+ r->type = D_TLS;
+ r->xsym = s;
+ } else
+ r->type = D_PCREL;
+ } else
+ r->type = D_ADDR;
+ }
+ return v;
+}
+
+static void
+asmandsz(Link *ctxt, Addr *a, int r, int rex, int m64)
+{
+ int32 v;
+ int t, scale;
+ Reloc rel;
+
+ USED(m64);
+ rex &= (0x40 | Rxr);
+ v = a->offset;
+ t = a->type;
+ rel.siz = 0;
+ if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) {
+ if(t < D_INDIR) {
+ switch(t) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ if(ctxt->flag_shared)
+ goto bad;
+ t = D_NONE;
+ v = vaddr(ctxt, a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ } else
+ t -= D_INDIR;
+ ctxt->rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
+ if(t == D_NONE) {
+ *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
+ *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ return;
+ }
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ *ctxt->andptr++ = v;
+ return;
+ }
+ *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(t >= D_AL && t <= D_X0+15) {
+ if(v)
+ goto bad;
+ *ctxt->andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+ ctxt->rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
+ return;
+ }
+
+ scale = a->scale;
+ if(t < D_INDIR) {
+ switch(a->type) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(ctxt, a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ scale = 1;
+ } else
+ t -= D_INDIR;
+
+ ctxt->rexflag |= (regrex[t] & Rxb) | rex;
+ if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
+ if(ctxt->flag_shared && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || ctxt->asmode != 64) {
+ *ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ goto putrelv;
+ }
+ /* temporary */
+ *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
+ *ctxt->andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
+ goto putrelv;
+ }
+ if(t == D_SP || t == D_R12) {
+ if(v == 0) {
+ *ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(ctxt, scale, D_NONE, t);
+ return;
+ }
+ if(v >= -128 && v < 128) {
+ *ctxt->andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(ctxt, scale, D_NONE, t);
+ *ctxt->andptr++ = v;
+ return;
+ }
+ *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(ctxt, scale, D_NONE, t);
+ goto putrelv;
+ }
+ if(t >= D_AX && t <= D_R15) {
+ if(v == 0 && t != D_BP && t != D_R13) {
+ *ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+ if(v >= -128 && v < 128) {
+ ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ ctxt->andptr[1] = v;
+ ctxt->andptr += 2;
+ return;
+ }
+ *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ goto putrelv;
+ }
+ goto bad;
+
+putrelv:
+ if(rel.siz != 0) {
+ Reloc *r;
+
+ if(rel.siz != 4) {
+ ctxt->diag("bad rel");
+ goto bad;
+ }
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and;
+ } else if(ctxt->iself && ctxt->linkmode == LinkExternal && a->type == D_INDIR+D_FS
+ && ctxt->headtype != Hopenbsd) {
+ Reloc *r;
+ LSym *s;
+
+ r = addrel(ctxt->cursym);
+ r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and;
+ r->add = a->offset - ctxt->tlsoffset;
+ r->xadd = r->add;
+ r->siz = 4;
+ r->type = D_TLS;
+ s = linklookup(ctxt, "runtime.tlsgm", 0);
+ r->sym = s;
+ r->xsym = s;
+ v = 0;
+ }
+
+ put4(ctxt, v);
+ return;
+
+bad:
+ ctxt->diag("asmand: bad address %D", a);
+ return;
+}
+
+static void
+asmand(Link *ctxt, Addr *a, Addr *ra)
+{
+ asmandsz(ctxt, a, reg[ra->type], regrex[ra->type], 0);
+}
+
+static void
+asmando(Link *ctxt, Addr *a, int o)
+{
+ asmandsz(ctxt, a, o, 0, 0);
+}
+
+static void
+bytereg(Addr *a, char *t)
+{
+ if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) {
+ a->type = D_AL + (a->type-D_AX);
+ *t = 0;
+ }
+}
+
+#define E 0xff
+static Movtab ymovtab[] =
+{
+/* push */
+ {APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0},
+ {APUSHL, Yss, Ynone, 0, 0x16,E,0,0},
+ {APUSHL, Yds, Ynone, 0, 0x1e,E,0,0},
+ {APUSHL, Yes, Ynone, 0, 0x06,E,0,0},
+ {APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
+ {APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
+ {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
+ {APUSHQ, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
+
+ {APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0},
+ {APUSHW, Yss, Ynone, 0, Pe,0x16,E,0},
+ {APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0},
+ {APUSHW, Yes, Ynone, 0, Pe,0x06,E,0},
+ {APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E},
+ {APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E},
+
+/* pop */
+ {APOPL, Ynone, Yds, 0, 0x1f,E,0,0},
+ {APOPL, Ynone, Yes, 0, 0x07,E,0,0},
+ {APOPL, Ynone, Yss, 0, 0x17,E,0,0},
+ {APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
+ {APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
+ {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
+ {APOPQ, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
+
+ {APOPW, Ynone, Yds, 0, Pe,0x1f,E,0},
+ {APOPW, Ynone, Yes, 0, Pe,0x07,E,0},
+ {APOPW, Ynone, Yss, 0, Pe,0x17,E,0},
+ {APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E},
+ {APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E},
+
+/* mov seg */
+ {AMOVW, Yes, Yml, 1, 0x8c,0,0,0},
+ {AMOVW, Ycs, Yml, 1, 0x8c,1,0,0},
+ {AMOVW, Yss, Yml, 1, 0x8c,2,0,0},
+ {AMOVW, Yds, Yml, 1, 0x8c,3,0,0},
+ {AMOVW, Yfs, Yml, 1, 0x8c,4,0,0},
+ {AMOVW, Ygs, Yml, 1, 0x8c,5,0,0},
+
+ {AMOVW, Yml, Yes, 2, 0x8e,0,0,0},
+ {AMOVW, Yml, Ycs, 2, 0x8e,1,0,0},
+ {AMOVW, Yml, Yss, 2, 0x8e,2,0,0},
+ {AMOVW, Yml, Yds, 2, 0x8e,3,0,0},
+ {AMOVW, Yml, Yfs, 2, 0x8e,4,0,0},
+ {AMOVW, Yml, Ygs, 2, 0x8e,5,0,0},
+
+/* mov cr */
+ {AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0},
+ {AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0},
+ {AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0},
+ {AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0},
+ {AMOVL, Ycr8, Yml, 3, 0x0f,0x20,8,0},
+ {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0},
+ {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0},
+ {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0},
+ {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0},
+ {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,0},
+
+ {AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0},
+ {AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0},
+ {AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0},
+ {AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0},
+ {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0},
+ {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0},
+ {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0},
+ {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0},
+ {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0},
+ {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,0},
+
+/* mov dr */
+ {AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0},
+ {AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0},
+ {AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0},
+ {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0},
+ {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0},
+ {AMOVQ, Ydr7, Yml, 3, 0x0f,0x21,7,0},
+
+ {AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0},
+ {AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0},
+ {AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0},
+ {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0},
+ {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0},
+ {AMOVQ, Yml, Ydr7, 4, 0x0f,0x23,7,0},
+
+/* mov tr */
+ {AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0},
+ {AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0},
+
+ {AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E},
+ {AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E},
+
+/* lgdt, sgdt, lidt, sidt */
+ {AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
+ {AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
+ {AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0},
+ {AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0},
+ {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
+ {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
+ {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0},
+ {AMOVQ, Yidtr, Ym, 3, 0x0f,0x01,1,0},
+
+/* lldt, sldt */
+ {AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0},
+ {AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0},
+
+/* lmsw, smsw */
+ {AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0},
+ {AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0},
+
+/* ltr, str */
+ {AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0},
+ {AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0},
+
+/* load full pointer */
+ {AMOVL, Yml, Ycol, 5, 0,0,0,0},
+ {AMOVW, Yml, Ycol, 5, Pe,0,0,0},
+
+/* double shift */
+ {ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0},
+ {ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0},
+ {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0},
+ {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0},
+ {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0},
+ {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,0},
+ 0
+};
+
+static int
+isax(Addr *a)
+{
+
+ switch(a->type) {
+ case D_AX:
+ case D_AL:
+ case D_AH:
+ case D_INDIR+D_AX:
+ return 1;
+ }
+ if(a->index == D_AX)
+ return 1;
+ return 0;
+}
+
+static void
+subreg(Prog *p, int from, int to)
+{
+
+ if(0 /*debug['Q']*/)
+ print("\n%P s/%R/%R/\n", p, from, to);
+
+ if(p->from.type == from)
+ p->from.type = to;
+ if(p->to.type == from)
+ p->to.type = to;
+
+ if(p->from.index == from)
+ p->from.index = to;
+ if(p->to.index == from)
+ p->to.index = to;
+
+ from += D_INDIR;
+ if(p->from.type == from)
+ p->from.type = to+D_INDIR;
+ if(p->to.type == from)
+ p->to.type = to+D_INDIR;
+
+ if(0 /*debug['Q']*/)
+ print("%P\n", p);
+}
+
+static int
+mediaop(Link *ctxt, Optab *o, int op, int osize, int z)
+{
+ switch(op){
+ case Pm:
+ case Pe:
+ case Pf2:
+ case Pf3:
+ if(osize != 1){
+ if(op != Pm)
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = Pm;
+ op = o->op[++z];
+ break;
+ }
+ default:
+ if(ctxt->andptr == ctxt->and || ctxt->andptr[-1] != Pm)
+ *ctxt->andptr++ = Pm;
+ break;
+ }
+ *ctxt->andptr++ = op;
+ return z;
+}
+
+static void
+doasm(Link *ctxt, Prog *p)
+{
+ Optab *o;
+ Prog *q, pp;
+ uchar *t;
+ Movtab *mo;
+ int z, op, ft, tt, xo, l, pre;
+ vlong v;
+ Reloc rel, *r;
+ Addr *a;
+
+ ctxt->curp = p; // TODO
+
+ o = opindex[p->as];
+ if(o == nil) {
+ ctxt->diag("asmins: missing op %P", p);
+ return;
+ }
+
+ pre = prefixof(&p->from);
+ if(pre)
+ *ctxt->andptr++ = pre;
+ pre = prefixof(&p->to);
+ if(pre)
+ *ctxt->andptr++ = pre;
+
+ if(p->ft == 0)
+ p->ft = oclass(ctxt, &p->from);
+ if(p->tt == 0)
+ p->tt = oclass(ctxt, &p->to);
+
+ ft = p->ft * Ymax;
+ tt = p->tt * Ymax;
+
+ t = o->ytab;
+ if(t == 0) {
+ ctxt->diag("asmins: noproto %P", p);
+ return;
+ }
+ xo = o->op[0] == 0x0f;
+ for(z=0; *t; z+=t[3]+xo,t+=4)
+ if(ycover[ft+t[0]])
+ if(ycover[tt+t[1]])
+ goto found;
+ goto domov;
+
+found:
+ switch(o->prefix) {
+ case Pq: /* 16 bit escape ctxt->and opcode escape */
+ *ctxt->andptr++ = Pe;
+ *ctxt->andptr++ = Pm;
+ break;
+ case Pq3: /* 16 bit escape, Rex.w, ctxt->and opcode escape */
+ *ctxt->andptr++ = Pe;
+ *ctxt->andptr++ = Pw;
+ *ctxt->andptr++ = Pm;
+ break;
+
+ case Pf2: /* xmm opcode escape */
+ case Pf3:
+ *ctxt->andptr++ = o->prefix;
+ *ctxt->andptr++ = Pm;
+ break;
+
+ case Pm: /* opcode escape */
+ *ctxt->andptr++ = Pm;
+ break;
+
+ case Pe: /* 16 bit escape */
+ *ctxt->andptr++ = Pe;
+ break;
+
+ case Pw: /* 64-bit escape */
+ if(p->mode != 64)
+ ctxt->diag("asmins: illegal 64: %P", p);
+ ctxt->rexflag |= Pw;
+ break;
+
+ case Pb: /* botch */
+ bytereg(&p->from, &p->ft);
+ bytereg(&p->to, &p->tt);
+ break;
+
+ case P32: /* 32 bit but illegal if 64-bit mode */
+ if(p->mode == 64)
+ ctxt->diag("asmins: illegal in 64-bit mode: %P", p);
+ break;
+
+ case Py: /* 64-bit only, no prefix */
+ if(p->mode != 64)
+ ctxt->diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
+ break;
+ }
+
+ if(z >= nelem(o->op))
+ sysfatal("asmins bad table %P", p);
+ op = o->op[z];
+ if(op == 0x0f) {
+ *ctxt->andptr++ = op;
+ op = o->op[++z];
+ }
+ switch(t[2]) {
+ default:
+ ctxt->diag("asmins: unknown z %d %P", t[2], p);
+ return;
+
+ case Zpseudo:
+ break;
+
+ case Zlit:
+ for(; op = o->op[z]; z++)
+ *ctxt->andptr++ = op;
+ break;
+
+ case Zlitm_r:
+ for(; op = o->op[z]; z++)
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, &p->to);
+ break;
+
+ case Zmb_r:
+ bytereg(&p->from, &p->ft);
+ /* fall through */
+ case Zm_r:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, &p->to);
+ break;
+ case Zm2_r:
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = o->op[z+1];
+ asmand(ctxt, &p->from, &p->to);
+ break;
+
+ case Zm_r_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->from, &p->to);
+ break;
+
+ case Zm_r_xm_nr:
+ ctxt->rexflag = 0;
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->from, &p->to);
+ break;
+
+ case Zm_r_i_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->from, &p->to);
+ *ctxt->andptr++ = p->to.offset;
+ break;
+
+ case Zm_r_3d:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0x0f;
+ asmand(ctxt, &p->from, &p->to);
+ *ctxt->andptr++ = op;
+ break;
+
+ case Zibm_r:
+ while ((op = o->op[z++]) != 0)
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, &p->to);
+ *ctxt->andptr++ = p->to.offset;
+ break;
+
+ case Zaut_r:
+ *ctxt->andptr++ = 0x8d; /* leal */
+ if(p->from.type != D_ADDR)
+ ctxt->diag("asmins: Zaut sb type ADDR");
+ p->from.type = p->from.index;
+ p->from.index = D_NONE;
+ asmand(ctxt, &p->from, &p->to);
+ p->from.index = p->from.type;
+ p->from.type = D_ADDR;
+ break;
+
+ case Zm_o:
+ *ctxt->andptr++ = op;
+ asmando(ctxt, &p->from, o->op[z+1]);
+ break;
+
+ case Zr_m:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, &p->from);
+ break;
+
+ case Zr_m_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->to, &p->from);
+ break;
+
+ case Zr_m_xm_nr:
+ ctxt->rexflag = 0;
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->to, &p->from);
+ break;
+
+ case Zr_m_i_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->to, &p->from);
+ *ctxt->andptr++ = p->from.offset;
+ break;
+
+ case Zo_m:
+ *ctxt->andptr++ = op;
+ asmando(ctxt, &p->to, o->op[z+1]);
+ break;
+
+ case Zo_m64:
+ *ctxt->andptr++ = op;
+ asmandsz(ctxt, &p->to, o->op[z+1], 0, 1);
+ break;
+
+ case Zm_ibo:
+ *ctxt->andptr++ = op;
+ asmando(ctxt, &p->from, o->op[z+1]);
+ *ctxt->andptr++ = vaddr(ctxt, &p->to, nil);
+ break;
+
+ case Zibo_m:
+ *ctxt->andptr++ = op;
+ asmando(ctxt, &p->to, o->op[z+1]);
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Zibo_m_xm:
+ z = mediaop(ctxt, o, op, t[3], z);
+ asmando(ctxt, &p->to, o->op[z+1]);
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Z_ib:
+ case Zib_:
+ if(t[2] == Zib_)
+ a = &p->from;
+ else
+ a = &p->to;
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = vaddr(ctxt, a, nil);
+ break;
+
+ case Zib_rp:
+ ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40);
+ *ctxt->andptr++ = op + reg[p->to.type];
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Zil_rp:
+ ctxt->rexflag |= regrex[p->to.type] & Rxb;
+ *ctxt->andptr++ = op + reg[p->to.type];
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, &p->from, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, &p->from);
+ break;
+
+ case Zo_iw:
+ *ctxt->andptr++ = op;
+ if(p->from.type != D_NONE){
+ v = vaddr(ctxt, &p->from, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ break;
+
+ case Ziq_rp:
+ v = vaddr(ctxt, &p->from, &rel);
+ l = v>>32;
+ if(l == 0 && rel.siz != 8){
+ //p->mark |= 0100;
+ //print("zero: %llux %P\n", v, p);
+ ctxt->rexflag &= ~(0x40|Rxw);
+ ctxt->rexflag |= regrex[p->to.type] & Rxb;
+ *ctxt->andptr++ = 0xb8 + reg[p->to.type];
+ if(rel.type != 0) {
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ put4(ctxt, v);
+ }else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */
+ //p->mark |= 0100;
+ //print("sign: %llux %P\n", v, p);
+ *ctxt->andptr ++ = 0xc7;
+ asmando(ctxt, &p->to, 0);
+ put4(ctxt, v);
+ }else{ /* need all 8 */
+ //print("all: %llux %P\n", v, p);
+ ctxt->rexflag |= regrex[p->to.type] & Rxb;
+ *ctxt->andptr++ = op + reg[p->to.type];
+ if(rel.type != 0) {
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ put8(ctxt, v);
+ }
+ break;
+
+ case Zib_rr:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, &p->to);
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Z_il:
+ case Zil_:
+ if(t[2] == Zil_)
+ a = &p->from;
+ else
+ a = &p->to;
+ *ctxt->andptr++ = op;
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, a, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, a);
+ break;
+
+ case Zm_ilo:
+ case Zilo_m:
+ *ctxt->andptr++ = op;
+ if(t[2] == Zilo_m) {
+ a = &p->from;
+ asmando(ctxt, &p->to, o->op[z+1]);
+ } else {
+ a = &p->to;
+ asmando(ctxt, &p->from, o->op[z+1]);
+ }
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, a, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, a);
+ break;
+
+ case Zil_rr:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, &p->to);
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, &p->from, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, &p->from);
+ break;
+
+ case Z_rp:
+ ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40);
+ *ctxt->andptr++ = op + reg[p->to.type];
+ break;
+
+ case Zrp_:
+ ctxt->rexflag |= regrex[p->from.type] & (Rxb|0x40);
+ *ctxt->andptr++ = op + reg[p->from.type];
+ break;
+
+ case Zclr:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, &p->to);
+ break;
+
+ case Zcall:
+ if(p->to.sym == nil) {
+ ctxt->diag("call without target");
+ sysfatal("bad code");
+ }
+ *ctxt->andptr++ = op;
+ r = addrel(ctxt->cursym);
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ r->sym = p->to.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(ctxt, 0);
+ break;
+
+ case Zbr:
+ case Zjmp:
+ case Zloop:
+ // TODO: jump across functions needs reloc
+ if(p->to.sym != nil) {
+ if(t[2] != Zjmp) {
+ ctxt->diag("branch to ATEXT");
+ sysfatal("bad code");
+ }
+ *ctxt->andptr++ = o->op[z+1];
+ r = addrel(ctxt->cursym);
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ r->sym = p->to.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(ctxt, 0);
+ break;
+ }
+ // Assumes q is in this function.
+ // TODO: Check in input, preserve in brchain.
+
+ // Fill in backward jump now.
+ q = p->pcond;
+ if(q == nil) {
+ ctxt->diag("jmp/branch/loop without target");
+ sysfatal("bad code");
+ }
+ if(p->back & 1) {
+ v = q->pc - (p->pc + 2);
+ if(v >= -128) {
+ if(p->as == AJCXZL)
+ *ctxt->andptr++ = 0x67;
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = v;
+ } else if(t[2] == Zloop) {
+ ctxt->diag("loop too far: %P", p);
+ } else {
+ v -= 5-2;
+ if(t[2] == Zbr) {
+ *ctxt->andptr++ = 0x0f;
+ v--;
+ }
+ *ctxt->andptr++ = o->op[z+1];
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ *ctxt->andptr++ = v>>16;
+ *ctxt->andptr++ = v>>24;
+ }
+ break;
+ }
+
+ // Annotate target; will fill in later.
+ p->forwd = q->comefrom;
+ q->comefrom = p;
+ if(p->back & 2) { // short
+ if(p->as == AJCXZL)
+ *ctxt->andptr++ = 0x67;
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = 0;
+ } else if(t[2] == Zloop) {
+ ctxt->diag("loop too far: %P", p);
+ } else {
+ if(t[2] == Zbr)
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = o->op[z+1];
+ *ctxt->andptr++ = 0;
+ *ctxt->andptr++ = 0;
+ *ctxt->andptr++ = 0;
+ *ctxt->andptr++ = 0;
+ }
+ break;
+
+/*
+ v = q->pc - p->pc - 2;
+ if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = v;
+ } else {
+ v -= 5-2;
+ if(t[2] == Zbr) {
+ *ctxt->andptr++ = 0x0f;
+ v--;
+ }
+ *ctxt->andptr++ = o->op[z+1];
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ *ctxt->andptr++ = v>>16;
+ *ctxt->andptr++ = v>>24;
+ }
+*/
+ break;
+
+ case Zbyte:
+ v = vaddr(ctxt, &p->from, &rel);
+ if(rel.siz != 0) {
+ rel.siz = op;
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ *ctxt->andptr++ = v;
+ if(op > 1) {
+ *ctxt->andptr++ = v>>8;
+ if(op > 2) {
+ *ctxt->andptr++ = v>>16;
+ *ctxt->andptr++ = v>>24;
+ if(op > 4) {
+ *ctxt->andptr++ = v>>32;
+ *ctxt->andptr++ = v>>40;
+ *ctxt->andptr++ = v>>48;
+ *ctxt->andptr++ = v>>56;
+ }
+ }
+ }
+ break;
+ }
+ return;
+
+domov:
+ for(mo=ymovtab; mo->as; mo++)
+ if(p->as == mo->as)
+ if(ycover[ft+mo->ft])
+ if(ycover[tt+mo->tt]){
+ t = mo->op;
+ goto mfound;
+ }
+bad:
+ if(p->mode != 64){
+ /*
+ * here, the assembly has failed.
+ * if its a byte instruction that has
+ * unaddressable registers, try to
+ * exchange registers ctxt->and reissue the
+ * instruction with the operands renamed.
+ */
+ pp = *p;
+ z = p->from.type;
+ if(z >= D_BP && z <= D_DI) {
+ if(isax(&p->to) || p->to.type == D_NONE) {
+ // We certainly don't want to exchange
+ // with AX if the op is MUL or DIV.
+ *ctxt->andptr++ = 0x87; /* xchg lhs,bx */
+ asmando(ctxt, &p->from, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x87; /* xchg lhs,bx */
+ asmando(ctxt, &p->from, reg[D_BX]);
+ } else {
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ }
+ return;
+ }
+ z = p->to.type;
+ if(z >= D_BP && z <= D_DI) {
+ if(isax(&p->from)) {
+ *ctxt->andptr++ = 0x87; /* xchg rhs,bx */
+ asmando(ctxt, &p->to, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x87; /* xchg rhs,bx */
+ asmando(ctxt, &p->to, reg[D_BX]);
+ } else {
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ }
+ return;
+ }
+ }
+ ctxt->diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p);
+ return;
+
+mfound:
+ switch(mo->code) {
+ default:
+ ctxt->diag("asmins: unknown mov %d %P", mo->code, p);
+ break;
+
+ case 0: /* lit */
+ for(z=0; t[z]!=E; z++)
+ *ctxt->andptr++ = t[z];
+ break;
+
+ case 1: /* r,m */
+ *ctxt->andptr++ = t[0];
+ asmando(ctxt, &p->to, t[1]);
+ break;
+
+ case 2: /* m,r */
+ *ctxt->andptr++ = t[0];
+ asmando(ctxt, &p->from, t[1]);
+ break;
+
+ case 3: /* r,m - 2op */
+ *ctxt->andptr++ = t[0];
+ *ctxt->andptr++ = t[1];
+ asmando(ctxt, &p->to, t[2]);
+ ctxt->rexflag |= regrex[p->from.type] & (Rxr|0x40);
+ break;
+
+ case 4: /* m,r - 2op */
+ *ctxt->andptr++ = t[0];
+ *ctxt->andptr++ = t[1];
+ asmando(ctxt, &p->from, t[2]);
+ ctxt->rexflag |= regrex[p->to.type] & (Rxr|0x40);
+ break;
+
+ case 5: /* load full pointer, trash heap */
+ if(t[0])
+ *ctxt->andptr++ = t[0];
+ switch(p->to.index) {
+ default:
+ goto bad;
+ case D_DS:
+ *ctxt->andptr++ = 0xc5;
+ break;
+ case D_SS:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0xb2;
+ break;
+ case D_ES:
+ *ctxt->andptr++ = 0xc4;
+ break;
+ case D_FS:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0xb4;
+ break;
+ case D_GS:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0xb5;
+ break;
+ }
+ asmand(ctxt, &p->from, &p->to);
+ break;
+
+ case 6: /* double shift */
+ if(t[0] == Pw){
+ if(p->mode != 64)
+ ctxt->diag("asmins: illegal 64: %P", p);
+ ctxt->rexflag |= Pw;
+ t++;
+ }else if(t[0] == Pe){
+ *ctxt->andptr++ = Pe;
+ t++;
+ }
+ z = p->from.type;
+ switch(z) {
+ default:
+ goto bad;
+ case D_CONST:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = t[0];
+ asmandsz(ctxt, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+ *ctxt->andptr++ = p->from.offset;
+ break;
+ case D_CL:
+ case D_CX:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = t[1];
+ asmandsz(ctxt, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+ break;
+ }
+ break;
+ }
+}
+
+static void
+asmins(Link *ctxt, Prog *p)
+{
+ int n, np, c;
+ Reloc *r;
+
+ ctxt->rexflag = 0;
+ ctxt->andptr = ctxt->and;
+ ctxt->asmode = p->mode;
+ doasm(ctxt, p);
+ if(ctxt->rexflag){
+ /*
+ * as befits the whole approach of the architecture,
+ * the rex prefix must appear before the first opcode byte
+ * (ctxt->and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but
+ * before the 0f opcode escape!), or it might be ignored.
+ * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
+ */
+ if(p->mode != 64)
+ ctxt->diag("asmins: illegal in mode %d: %P", p->mode, p);
+ n = ctxt->andptr - ctxt->and;
+ for(np = 0; np < n; np++) {
+ c = ctxt->and[np];
+ if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
+ break;
+ }
+ memmove(ctxt->and+np+1, ctxt->and+np, n-np);
+ ctxt->and[np] = 0x40 | ctxt->rexflag;
+ ctxt->andptr++;
+ }
+ n = ctxt->andptr - ctxt->and;
+ for(r=ctxt->cursym->r+ctxt->cursym->nr; r-- > ctxt->cursym->r; ) {
+ if(r->off < p->pc)
+ break;
+ if(ctxt->rexflag)
+ r->off++;
+ if(r->type == D_PCREL)
+ r->add -= p->pc + n - (r->off + r->siz);
+ }
+}
diff --git a/src/liblink/asm8.c b/src/liblink/asm8.c
new file mode 100644
index 000000000..624627656
--- /dev/null
+++ b/src/liblink/asm8.c
@@ -0,0 +1,2571 @@
+// Inferno utils/8l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Instruction layout.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/8l/8.out.h"
+#include "../pkg/runtime/stack.h"
+
+enum
+{
+ MaxAlign = 32, // max data alignment
+ FuncAlign = 16
+};
+
+extern char *anames6[];
+
+typedef struct Optab Optab;
+
+struct Optab
+{
+ short as;
+ uchar* ytab;
+ uchar prefix;
+ uchar op[13];
+};
+
+enum
+{
+ Yxxx = 0,
+ Ynone,
+ Yi0,
+ Yi1,
+ Yi8,
+ Yi32,
+ Yiauto,
+ Yal,
+ Ycl,
+ Yax,
+ Ycx,
+ Yrb,
+ Yrl,
+ Yrf,
+ Yf0,
+ Yrx,
+ Ymb,
+ Yml,
+ Ym,
+ Ybr,
+ Ycol,
+
+ Ycs, Yss, Yds, Yes, Yfs, Ygs,
+ Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
+ Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7,
+ Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
+ Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7,
+ Ymr, Ymm,
+ Yxr, Yxm,
+ Ymax,
+
+ Zxxx = 0,
+
+ Zlit,
+ Zlitm_r,
+ Z_rp,
+ Zbr,
+ Zcall,
+ Zcallcon,
+ Zcallind,
+ Zib_,
+ Zib_rp,
+ Zibo_m,
+ Zil_,
+ Zil_rp,
+ Zilo_m,
+ Zjmp,
+ Zjmpcon,
+ Zloop,
+ Zm_o,
+ Zm_r,
+ Zm2_r,
+ Zm_r_xm,
+ Zm_r_i_xm,
+ Zaut_r,
+ Zo_m,
+ Zpseudo,
+ Zr_m,
+ Zr_m_xm,
+ Zr_m_i_xm,
+ Zrp_,
+ Z_ib,
+ Z_il,
+ Zm_ibo,
+ Zm_ilo,
+ Zib_rr,
+ Zil_rr,
+ Zclr,
+ Zibm_r, /* mmx1,mmx2/mem64,imm8 */
+ Zbyte,
+ Zmov,
+ Zmax,
+
+ Px = 0,
+ Pe = 0x66, /* operand escape */
+ Pm = 0x0f, /* 2byte opcode escape */
+ Pq = 0xff, /* both escape */
+ Pb = 0xfe, /* byte operands */
+ Pf2 = 0xf2, /* xmm escape 1 */
+ Pf3 = 0xf3, /* xmm escape 2 */
+};
+
+static uchar ycover[Ymax*Ymax];
+static char reg[D_NONE];
+static void asmins(Link *ctxt, Prog *p);
+
+static uchar ynone[] =
+{
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+static uchar ytext[] =
+{
+ Ymb, Yi32, Zpseudo,1,
+ 0
+};
+static uchar ynop[] =
+{
+ Ynone, Ynone, Zpseudo,1,
+ Ynone, Yml, Zpseudo,1,
+ Ynone, Yrf, Zpseudo,1,
+ Yml, Ynone, Zpseudo,1,
+ Yrf, Ynone, Zpseudo,1,
+ 0
+};
+static uchar yfuncdata[] =
+{
+ Yi32, Ym, Zpseudo, 0,
+ 0
+};
+static uchar ypcdata[] =
+{
+ Yi32, Yi32, Zpseudo, 0,
+ 0,
+};
+static uchar yxorb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+static uchar yxorl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yaddl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yincb[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+static uchar yincl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ Ynone, Yml, Zo_m, 2,
+ 0
+};
+static uchar ycmpb[] =
+{
+ Yal, Yi32, Z_ib, 1,
+ Ymb, Yi32, Zm_ibo, 2,
+ Ymb, Yrb, Zm_r, 1,
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+static uchar ycmpl[] =
+{
+ Yml, Yi8, Zm_ibo, 2,
+ Yax, Yi32, Z_il, 1,
+ Yml, Yi32, Zm_ilo, 2,
+ Yml, Yrl, Zm_r, 1,
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+static uchar yshb[] =
+{
+ Yi1, Ymb, Zo_m, 2,
+ Yi32, Ymb, Zibo_m, 2,
+ Ycx, Ymb, Zo_m, 2,
+ 0
+};
+static uchar yshl[] =
+{
+ Yi1, Yml, Zo_m, 2,
+ Yi32, Yml, Zibo_m, 2,
+ Ycl, Yml, Zo_m, 2,
+ Ycx, Yml, Zo_m, 2,
+ 0
+};
+static uchar ytestb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+static uchar ytestl[] =
+{
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar ymovb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ Yi32, Yrb, Zib_rp, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ 0
+};
+static uchar ymovw[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1+2,
+// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yiauto, Yrl, Zaut_r, 1,
+ 0
+};
+static uchar ymovl[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1+2,
+// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit)
+ Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit)
+ Yiauto, Yrl, Zaut_r, 1,
+ 0
+};
+static uchar ymovq[] =
+{
+ Yml, Yxr, Zm_r_xm, 2,
+ 0
+};
+static uchar ym_rl[] =
+{
+ Ym, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yrl_m[] =
+{
+ Yrl, Ym, Zr_m, 1,
+ 0
+};
+static uchar ymb_rl[] =
+{
+ Ymb, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yml_rl[] =
+{
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yrb_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+static uchar yrl_ml[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+static uchar yml_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+static uchar yxchg[] =
+{
+ Yax, Yrl, Z_rp, 1,
+ Yrl, Yax, Zrp_, 1,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar ydivl[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ydivb[] =
+{
+ Ymb, Ynone, Zm_o, 2,
+ 0
+};
+static uchar yimul[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ Yi8, Yrl, Zib_rr, 1,
+ Yi32, Yrl, Zil_rr, 1,
+ 0
+};
+static uchar ybyte[] =
+{
+ Yi32, Ynone, Zbyte, 1,
+ 0
+};
+static uchar yin[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+static uchar yint[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ 0
+};
+static uchar ypushl[] =
+{
+ Yrl, Ynone, Zrp_, 1,
+ Ym, Ynone, Zm_o, 2,
+ Yi8, Ynone, Zib_, 1,
+ Yi32, Ynone, Zil_, 1,
+ 0
+};
+static uchar ypopl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ Ynone, Ym, Zo_m, 2,
+ 0
+};
+static uchar ybswap[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ 0,
+};
+static uchar yscond[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+static uchar yjcond[] =
+{
+ Ynone, Ybr, Zbr, 0,
+ Yi0, Ybr, Zbr, 0,
+ Yi1, Ybr, Zbr, 1,
+ 0
+};
+static uchar yloop[] =
+{
+ Ynone, Ybr, Zloop, 1,
+ 0
+};
+static uchar ycall[] =
+{
+ Ynone, Yml, Zo_m, 0,
+ Yrx, Yrx, Zo_m, 2,
+ Ynone, Ycol, Zcallind, 2,
+ Ynone, Ybr, Zcall, 0,
+ Ynone, Yi32, Zcallcon, 1,
+ 0
+};
+static uchar yjmp[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ Ynone, Ybr, Zjmp, 0,
+ Ynone, Yi32, Zjmpcon, 1,
+ 0
+};
+
+static uchar yfmvd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfmvdp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfmvf[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+static uchar yfmvx[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ 0
+};
+static uchar yfmvp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+static uchar yfcmv[] =
+{
+ Yrf, Yf0, Zm_o, 2,
+ 0
+};
+static uchar yfadd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfaddp[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfxch[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ 0
+};
+static uchar ycompp[] =
+{
+ Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
+ 0
+};
+static uchar ystsw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ynone, Yax, Zlit, 1,
+ 0
+};
+static uchar ystcw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ysvrs[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ymskb[] =
+{
+ Yxr, Yrl, Zm_r_xm, 2,
+ Ymr, Yrl, Zm_r_xm, 1,
+ 0
+};
+static uchar yxm[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcvm1[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ Yxm, Ymr, Zm_r_xm, 2,
+ 0
+};
+static uchar yxcvm2[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ Ymm, Yxr, Zm_r_xm, 2,
+ 0
+};
+static uchar yxmq[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ 0
+};
+static uchar yxr[] =
+{
+ Yxr, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxr_ml[] =
+{
+ Yxr, Yml, Zr_m_xm, 1,
+ 0
+};
+static uchar yxcmp[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcmpi[] =
+{
+ Yxm, Yxr, Zm_r_i_xm, 2,
+ 0
+};
+static uchar yxmov[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ Yxr, Yxm, Zr_m_xm, 1,
+ 0
+};
+static uchar yxcvfl[] =
+{
+ Yxm, Yrl, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcvlf[] =
+{
+ Yml, Yxr, Zm_r_xm, 1,
+ 0
+};
+/*
+static uchar yxcvfq[] =
+{
+ Yxm, Yrl, Zm_r_xm, 2,
+ 0
+};
+static uchar yxcvqf[] =
+{
+ Yml, Yxr, Zm_r_xm, 2,
+ 0
+};
+*/
+static uchar yxrrl[] =
+{
+ Yxr, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yprefetch[] =
+{
+ Ym, Ynone, Zm_o, 2,
+ 0,
+};
+static uchar yaes[] =
+{
+ Yxm, Yxr, Zlitm_r, 2,
+ 0
+};
+static uchar yinsrd[] =
+{
+ Yml, Yxr, Zibm_r, 2,
+ 0
+};
+static uchar ymshufb[] =
+{
+ Yxm, Yxr, Zm2_r, 2,
+ 0
+};
+
+static Optab optab[] =
+/* as, ytab, andproto, opcode */
+{
+ { AXXX },
+ { AAAA, ynone, Px, 0x37 },
+ { AAAD, ynone, Px, 0xd5,0x0a },
+ { AAAM, ynone, Px, 0xd4,0x0a },
+ { AAAS, ynone, Px, 0x3f },
+ { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
+ { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADDB, yxorb, Px, 0x04,0x80,(00),0x00,0x02 },
+ { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADJSP },
+ { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
+ { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AARPL, yrl_ml, Px, 0x63 },
+ { ABOUNDL, yrl_m, Px, 0x62 },
+ { ABOUNDW, yrl_m, Pe, 0x62 },
+ { ABSFL, yml_rl, Pm, 0xbc },
+ { ABSFW, yml_rl, Pq, 0xbc },
+ { ABSRL, yml_rl, Pm, 0xbd },
+ { ABSRW, yml_rl, Pq, 0xbd },
+ { ABTL, yml_rl, Pm, 0xa3 },
+ { ABTW, yml_rl, Pq, 0xa3 },
+ { ABTCL, yml_rl, Pm, 0xbb },
+ { ABTCW, yml_rl, Pq, 0xbb },
+ { ABTRL, yml_rl, Pm, 0xb3 },
+ { ABTRW, yml_rl, Pq, 0xb3 },
+ { ABTSL, yml_rl, Pm, 0xab },
+ { ABTSW, yml_rl, Pq, 0xab },
+ { ABYTE, ybyte, Px, 1 },
+ { ACALL, ycall, Px, 0xff,(02),0xff,(0x15),0xe8 },
+ { ACLC, ynone, Px, 0xf8 },
+ { ACLD, ynone, Px, 0xfc },
+ { ACLI, ynone, Px, 0xfa },
+ { ACLTS, ynone, Pm, 0x06 },
+ { ACMC, ynone, Px, 0xf5 },
+ { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
+ { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPSB, ynone, Pb, 0xa6 },
+ { ACMPSL, ynone, Px, 0xa7 },
+ { ACMPSW, ynone, Pe, 0xa7 },
+ { ADAA, ynone, Px, 0x27 },
+ { ADAS, ynone, Px, 0x2f },
+ { ADATA },
+ { ADECB, yincb, Pb, 0xfe,(01) },
+ { ADECL, yincl, Px, 0x48,0xff,(01) },
+ { ADECW, yincl, Pe, 0x48,0xff,(01) },
+ { ADIVB, ydivb, Pb, 0xf6,(06) },
+ { ADIVL, ydivl, Px, 0xf7,(06) },
+ { ADIVW, ydivl, Pe, 0xf7,(06) },
+ { AENTER }, /* botch */
+ { AGLOBL },
+ { AGOK },
+ { AHISTORY },
+ { AHLT, ynone, Px, 0xf4 },
+ { AIDIVB, ydivb, Pb, 0xf6,(07) },
+ { AIDIVL, ydivl, Px, 0xf7,(07) },
+ { AIDIVW, ydivl, Pe, 0xf7,(07) },
+ { AIMULB, ydivb, Pb, 0xf6,(05) },
+ { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69 },
+ { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69 },
+ { AINB, yin, Pb, 0xe4,0xec },
+ { AINL, yin, Px, 0xe5,0xed },
+ { AINW, yin, Pe, 0xe5,0xed },
+ { AINCB, yincb, Pb, 0xfe,(00) },
+ { AINCL, yincl, Px, 0x40,0xff,(00) },
+ { AINCW, yincl, Pe, 0x40,0xff,(00) },
+ { AINSB, ynone, Pb, 0x6c },
+ { AINSL, ynone, Px, 0x6d },
+ { AINSW, ynone, Pe, 0x6d },
+ { AINT, yint, Px, 0xcd },
+ { AINTO, ynone, Px, 0xce },
+ { AIRETL, ynone, Px, 0xcf },
+ { AIRETW, ynone, Pe, 0xcf },
+ { AJCC, yjcond, Px, 0x73,0x83,(00) },
+ { AJCS, yjcond, Px, 0x72,0x82 },
+ { AJCXZL, yloop, Px, 0xe3 },
+ { AJCXZW, yloop, Px, 0xe3 },
+ { AJEQ, yjcond, Px, 0x74,0x84 },
+ { AJGE, yjcond, Px, 0x7d,0x8d },
+ { AJGT, yjcond, Px, 0x7f,0x8f },
+ { AJHI, yjcond, Px, 0x77,0x87 },
+ { AJLE, yjcond, Px, 0x7e,0x8e },
+ { AJLS, yjcond, Px, 0x76,0x86 },
+ { AJLT, yjcond, Px, 0x7c,0x8c },
+ { AJMI, yjcond, Px, 0x78,0x88 },
+ { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
+ { AJNE, yjcond, Px, 0x75,0x85 },
+ { AJOC, yjcond, Px, 0x71,0x81,(00) },
+ { AJOS, yjcond, Px, 0x70,0x80,(00) },
+ { AJPC, yjcond, Px, 0x7b,0x8b },
+ { AJPL, yjcond, Px, 0x79,0x89 },
+ { AJPS, yjcond, Px, 0x7a,0x8a },
+ { ALAHF, ynone, Px, 0x9f },
+ { ALARL, yml_rl, Pm, 0x02 },
+ { ALARW, yml_rl, Pq, 0x02 },
+ { ALEAL, ym_rl, Px, 0x8d },
+ { ALEAW, ym_rl, Pe, 0x8d },
+ { ALEAVEL, ynone, Px, 0xc9 },
+ { ALEAVEW, ynone, Pe, 0xc9 },
+ { ALOCK, ynone, Px, 0xf0 },
+ { ALODSB, ynone, Pb, 0xac },
+ { ALODSL, ynone, Px, 0xad },
+ { ALODSW, ynone, Pe, 0xad },
+ { ALONG, ybyte, Px, 4 },
+ { ALOOP, yloop, Px, 0xe2 },
+ { ALOOPEQ, yloop, Px, 0xe1 },
+ { ALOOPNE, yloop, Px, 0xe0 },
+ { ALSLL, yml_rl, Pm, 0x03 },
+ { ALSLW, yml_rl, Pq, 0x03 },
+ { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
+ { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),Pe,0x6e,Pe,0x7e,0 },
+ { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),0 },
+ { AMOVQ, ymovq, Pf3, 0x7e },
+ { AMOVBLSX, ymb_rl, Pm, 0xbe },
+ { AMOVBLZX, ymb_rl, Pm, 0xb6 },
+ { AMOVBWSX, ymb_rl, Pq, 0xbe },
+ { AMOVBWZX, ymb_rl, Pq, 0xb6 },
+ { AMOVWLSX, yml_rl, Pm, 0xbf },
+ { AMOVWLZX, yml_rl, Pm, 0xb7 },
+ { AMOVSB, ynone, Pb, 0xa4 },
+ { AMOVSL, ynone, Px, 0xa5 },
+ { AMOVSW, ynone, Pe, 0xa5 },
+ { AMULB, ydivb, Pb, 0xf6,(04) },
+ { AMULL, ydivl, Px, 0xf7,(04) },
+ { AMULW, ydivl, Pe, 0xf7,(04) },
+ { ANAME },
+ { ANEGB, yscond, Px, 0xf6,(03) },
+ { ANEGL, yscond, Px, 0xf7,(03) },
+ { ANEGW, yscond, Pe, 0xf7,(03) },
+ { ANOP, ynop, Px,0,0 },
+ { ANOTB, yscond, Px, 0xf6,(02) },
+ { ANOTL, yscond, Px, 0xf7,(02) },
+ { ANOTW, yscond, Pe, 0xf7,(02) },
+ { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
+ { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AOUTB, yin, Pb, 0xe6,0xee },
+ { AOUTL, yin, Px, 0xe7,0xef },
+ { AOUTW, yin, Pe, 0xe7,0xef },
+ { AOUTSB, ynone, Pb, 0x6e },
+ { AOUTSL, ynone, Px, 0x6f },
+ { AOUTSW, ynone, Pe, 0x6f },
+ { APAUSE, ynone, Px, 0xf3,0x90 },
+ { APOPAL, ynone, Px, 0x61 },
+ { APOPAW, ynone, Pe, 0x61 },
+ { APOPFL, ynone, Px, 0x9d },
+ { APOPFW, ynone, Pe, 0x9d },
+ { APOPL, ypopl, Px, 0x58,0x8f,(00) },
+ { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
+ { APUSHAL, ynone, Px, 0x60 },
+ { APUSHAW, ynone, Pe, 0x60 },
+ { APUSHFL, ynone, Px, 0x9c },
+ { APUSHFW, ynone, Pe, 0x9c },
+ { APUSHL, ypushl, Px, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
+ { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
+ { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
+ { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { AREP, ynone, Px, 0xf3 },
+ { AREPN, ynone, Px, 0xf2 },
+ { ARET, ynone, Px, 0xc3 },
+ { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
+ { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
+ { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ASAHF, ynone, Px, 0x9e },
+ { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
+ { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
+ { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASCASB, ynone, Pb, 0xae },
+ { ASCASL, ynone, Px, 0xaf },
+ { ASCASW, ynone, Pe, 0xaf },
+ { ASETCC, yscond, Pm, 0x93,(00) },
+ { ASETCS, yscond, Pm, 0x92,(00) },
+ { ASETEQ, yscond, Pm, 0x94,(00) },
+ { ASETGE, yscond, Pm, 0x9d,(00) },
+ { ASETGT, yscond, Pm, 0x9f,(00) },
+ { ASETHI, yscond, Pm, 0x97,(00) },
+ { ASETLE, yscond, Pm, 0x9e,(00) },
+ { ASETLS, yscond, Pm, 0x96,(00) },
+ { ASETLT, yscond, Pm, 0x9c,(00) },
+ { ASETMI, yscond, Pm, 0x98,(00) },
+ { ASETNE, yscond, Pm, 0x95,(00) },
+ { ASETOC, yscond, Pm, 0x91,(00) },
+ { ASETOS, yscond, Pm, 0x90,(00) },
+ { ASETPC, yscond, Pm, 0x96,(00) },
+ { ASETPL, yscond, Pm, 0x99,(00) },
+ { ASETPS, yscond, Pm, 0x9a,(00) },
+ { ACDQ, ynone, Px, 0x99 },
+ { ACWD, ynone, Pe, 0x99 },
+ { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
+ { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASTC, ynone, Px, 0xf9 },
+ { ASTD, ynone, Px, 0xfd },
+ { ASTI, ynone, Px, 0xfb },
+ { ASTOSB, ynone, Pb, 0xaa },
+ { ASTOSL, ynone, Px, 0xab },
+ { ASTOSW, ynone, Pe, 0xab },
+ { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
+ { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASYSCALL, ynone, Px, 0xcd,100 },
+ { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
+ { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATEXT, ytext, Px },
+ { AVERR, ydivl, Pm, 0x00,(04) },
+ { AVERW, ydivl, Pm, 0x00,(05) },
+ { AWAIT, ynone, Px, 0x9b },
+ { AWORD, ybyte, Px, 2 },
+ { AXCHGB, yml_mb, Pb, 0x86,0x86 },
+ { AXCHGL, yxchg, Px, 0x90,0x90,0x87,0x87 },
+ { AXCHGW, yxchg, Pe, 0x90,0x90,0x87,0x87 },
+ { AXLAT, ynone, Px, 0xd7 },
+ { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
+ { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+ { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+
+ { AFMOVB, yfmvx, Px, 0xdf,(04) },
+ { AFMOVBP, yfmvp, Px, 0xdf,(06) },
+ { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
+ { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
+ { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
+ { AFMOVFP, yfmvp, Px, 0xd9,(03) },
+ { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
+ { AFMOVLP, yfmvp, Px, 0xdb,(03) },
+ { AFMOVV, yfmvx, Px, 0xdf,(05) },
+ { AFMOVVP, yfmvp, Px, 0xdf,(07) },
+ { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
+ { AFMOVWP, yfmvp, Px, 0xdf,(03) },
+ { AFMOVX, yfmvx, Px, 0xdb,(05) },
+ { AFMOVXP, yfmvp, Px, 0xdb,(07) },
+
+ { AFCOMB },
+ { AFCOMBP },
+ { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
+ { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
+ { AFCOMDPP, ycompp, Px, 0xde,(03) },
+ { AFCOMF, yfmvx, Px, 0xd8,(02) },
+ { AFCOMFP, yfmvx, Px, 0xd8,(03) },
+ { AFCOMI, yfmvx, Px, 0xdb,(06) },
+ { AFCOMIP, yfmvx, Px, 0xdf,(06) },
+ { AFCOML, yfmvx, Px, 0xda,(02) },
+ { AFCOMLP, yfmvx, Px, 0xda,(03) },
+ { AFCOMW, yfmvx, Px, 0xde,(02) },
+ { AFCOMWP, yfmvx, Px, 0xde,(03) },
+
+ { AFUCOM, ycompp, Px, 0xdd,(04) },
+ { AFUCOMI, ycompp, Px, 0xdb,(05) },
+ { AFUCOMIP, ycompp, Px, 0xdf,(05) },
+ { AFUCOMP, ycompp, Px, 0xdd,(05) },
+ { AFUCOMPP, ycompp, Px, 0xda,(13) },
+
+ { AFADDDP, yfaddp, Px, 0xde,(00) },
+ { AFADDW, yfmvx, Px, 0xde,(00) },
+ { AFADDL, yfmvx, Px, 0xda,(00) },
+ { AFADDF, yfmvx, Px, 0xd8,(00) },
+ { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
+
+ { AFMULDP, yfaddp, Px, 0xde,(01) },
+ { AFMULW, yfmvx, Px, 0xde,(01) },
+ { AFMULL, yfmvx, Px, 0xda,(01) },
+ { AFMULF, yfmvx, Px, 0xd8,(01) },
+ { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
+
+ { AFSUBDP, yfaddp, Px, 0xde,(05) },
+ { AFSUBW, yfmvx, Px, 0xde,(04) },
+ { AFSUBL, yfmvx, Px, 0xda,(04) },
+ { AFSUBF, yfmvx, Px, 0xd8,(04) },
+ { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
+
+ { AFSUBRDP, yfaddp, Px, 0xde,(04) },
+ { AFSUBRW, yfmvx, Px, 0xde,(05) },
+ { AFSUBRL, yfmvx, Px, 0xda,(05) },
+ { AFSUBRF, yfmvx, Px, 0xd8,(05) },
+ { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
+
+ { AFDIVDP, yfaddp, Px, 0xde,(07) },
+ { AFDIVW, yfmvx, Px, 0xde,(06) },
+ { AFDIVL, yfmvx, Px, 0xda,(06) },
+ { AFDIVF, yfmvx, Px, 0xd8,(06) },
+ { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
+
+ { AFDIVRDP, yfaddp, Px, 0xde,(06) },
+ { AFDIVRW, yfmvx, Px, 0xde,(07) },
+ { AFDIVRL, yfmvx, Px, 0xda,(07) },
+ { AFDIVRF, yfmvx, Px, 0xd8,(07) },
+ { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
+
+ { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
+ { AFFREE },
+ { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
+ { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
+ { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
+ { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
+ { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
+ { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
+ { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
+ { AF2XM1, ynone, Px, 0xd9, 0xf0 },
+ { AFABS, ynone, Px, 0xd9, 0xe1 },
+ { AFCHS, ynone, Px, 0xd9, 0xe0 },
+ { AFCLEX, ynone, Px, 0xdb, 0xe2 },
+ { AFCOS, ynone, Px, 0xd9, 0xff },
+ { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
+ { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
+ { AFINIT, ynone, Px, 0xdb, 0xe3 },
+ { AFLD1, ynone, Px, 0xd9, 0xe8 },
+ { AFLDL2E, ynone, Px, 0xd9, 0xea },
+ { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
+ { AFLDLG2, ynone, Px, 0xd9, 0xec },
+ { AFLDLN2, ynone, Px, 0xd9, 0xed },
+ { AFLDPI, ynone, Px, 0xd9, 0xeb },
+ { AFLDZ, ynone, Px, 0xd9, 0xee },
+ { AFNOP, ynone, Px, 0xd9, 0xd0 },
+ { AFPATAN, ynone, Px, 0xd9, 0xf3 },
+ { AFPREM, ynone, Px, 0xd9, 0xf8 },
+ { AFPREM1, ynone, Px, 0xd9, 0xf5 },
+ { AFPTAN, ynone, Px, 0xd9, 0xf2 },
+ { AFRNDINT, ynone, Px, 0xd9, 0xfc },
+ { AFSCALE, ynone, Px, 0xd9, 0xfd },
+ { AFSIN, ynone, Px, 0xd9, 0xfe },
+ { AFSINCOS, ynone, Px, 0xd9, 0xfb },
+ { AFSQRT, ynone, Px, 0xd9, 0xfa },
+ { AFTST, ynone, Px, 0xd9, 0xe4 },
+ { AFXAM, ynone, Px, 0xd9, 0xe5 },
+ { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
+ { AFYL2X, ynone, Px, 0xd9, 0xf1 },
+ { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
+ { AEND },
+ { ADYNT_ },
+ { AINIT_ },
+ { ASIGNAME },
+ { ACMPXCHGB, yrb_mb, Pm, 0xb0 },
+ { ACMPXCHGL, yrl_ml, Pm, 0xb1 },
+ { ACMPXCHGW, yrl_ml, Pm, 0xb1 },
+ { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
+
+ { ACPUID, ynone, Pm, 0xa2 },
+ { ARDTSC, ynone, Pm, 0x31 },
+
+ { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
+ { AXADDL, yrl_ml, Pm, 0xc1 },
+ { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
+
+ { ACMOVLCC, yml_rl, Pm, 0x43 },
+ { ACMOVLCS, yml_rl, Pm, 0x42 },
+ { ACMOVLEQ, yml_rl, Pm, 0x44 },
+ { ACMOVLGE, yml_rl, Pm, 0x4d },
+ { ACMOVLGT, yml_rl, Pm, 0x4f },
+ { ACMOVLHI, yml_rl, Pm, 0x47 },
+ { ACMOVLLE, yml_rl, Pm, 0x4e },
+ { ACMOVLLS, yml_rl, Pm, 0x46 },
+ { ACMOVLLT, yml_rl, Pm, 0x4c },
+ { ACMOVLMI, yml_rl, Pm, 0x48 },
+ { ACMOVLNE, yml_rl, Pm, 0x45 },
+ { ACMOVLOC, yml_rl, Pm, 0x41 },
+ { ACMOVLOS, yml_rl, Pm, 0x40 },
+ { ACMOVLPC, yml_rl, Pm, 0x4b },
+ { ACMOVLPL, yml_rl, Pm, 0x49 },
+ { ACMOVLPS, yml_rl, Pm, 0x4a },
+ { ACMOVWCC, yml_rl, Pq, 0x43 },
+ { ACMOVWCS, yml_rl, Pq, 0x42 },
+ { ACMOVWEQ, yml_rl, Pq, 0x44 },
+ { ACMOVWGE, yml_rl, Pq, 0x4d },
+ { ACMOVWGT, yml_rl, Pq, 0x4f },
+ { ACMOVWHI, yml_rl, Pq, 0x47 },
+ { ACMOVWLE, yml_rl, Pq, 0x4e },
+ { ACMOVWLS, yml_rl, Pq, 0x46 },
+ { ACMOVWLT, yml_rl, Pq, 0x4c },
+ { ACMOVWMI, yml_rl, Pq, 0x48 },
+ { ACMOVWNE, yml_rl, Pq, 0x45 },
+ { ACMOVWOC, yml_rl, Pq, 0x41 },
+ { ACMOVWOS, yml_rl, Pq, 0x40 },
+ { ACMOVWPC, yml_rl, Pq, 0x4b },
+ { ACMOVWPL, yml_rl, Pq, 0x49 },
+ { ACMOVWPS, yml_rl, Pq, 0x4a },
+
+ { AFCMOVCC, yfcmv, Px, 0xdb,(00) },
+ { AFCMOVCS, yfcmv, Px, 0xda,(00) },
+ { AFCMOVEQ, yfcmv, Px, 0xda,(01) },
+ { AFCMOVHI, yfcmv, Px, 0xdb,(02) },
+ { AFCMOVLS, yfcmv, Px, 0xda,(02) },
+ { AFCMOVNE, yfcmv, Px, 0xdb,(01) },
+ { AFCMOVNU, yfcmv, Px, 0xdb,(03) },
+ { AFCMOVUN, yfcmv, Px, 0xda,(03) },
+
+ { ALFENCE, ynone, Pm, 0xae,0xe8 },
+ { AMFENCE, ynone, Pm, 0xae,0xf0 },
+ { ASFENCE, ynone, Pm, 0xae,0xf8 },
+
+ { AEMMS, ynone, Pm, 0x77 },
+
+ { APREFETCHT0, yprefetch, Pm, 0x18,(01) },
+ { APREFETCHT1, yprefetch, Pm, 0x18,(02) },
+ { APREFETCHT2, yprefetch, Pm, 0x18,(03) },
+ { APREFETCHNTA, yprefetch, Pm, 0x18,(00) },
+
+ { ABSWAPL, ybswap, Pm, 0xc8 },
+
+ { AUNDEF, ynone, Px, 0x0f, 0x0b },
+
+ { AADDPD, yxm, Pq, 0x58 },
+ { AADDPS, yxm, Pm, 0x58 },
+ { AADDSD, yxm, Pf2, 0x58 },
+ { AADDSS, yxm, Pf3, 0x58 },
+ { AANDNPD, yxm, Pq, 0x55 },
+ { AANDNPS, yxm, Pm, 0x55 },
+ { AANDPD, yxm, Pq, 0x54 },
+ { AANDPS, yxm, Pq, 0x54 },
+ { ACMPPD, yxcmpi, Px, Pe,0xc2 },
+ { ACMPPS, yxcmpi, Pm, 0xc2,0 },
+ { ACMPSD, yxcmpi, Px, Pf2,0xc2 },
+ { ACMPSS, yxcmpi, Px, Pf3,0xc2 },
+ { ACOMISD, yxcmp, Pe, 0x2f },
+ { ACOMISS, yxcmp, Pm, 0x2f },
+ { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a },
+ { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, },
+ { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d },
+ { ACVTPD2PS, yxm, Pe, 0x5a },
+ { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d },
+ { ACVTPS2PD, yxm, Pm, 0x5a },
+ { ACVTSD2SL, yxcvfl, Pf2, 0x2d },
+ { ACVTSD2SS, yxm, Pf2, 0x5a },
+ { ACVTSL2SD, yxcvlf, Pf2, 0x2a },
+ { ACVTSL2SS, yxcvlf, Pf3, 0x2a },
+ { ACVTSS2SD, yxm, Pf3, 0x5a },
+ { ACVTSS2SL, yxcvfl, Pf3, 0x2d },
+ { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c },
+ { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c },
+ { ACVTTSD2SL, yxcvfl, Pf2, 0x2c },
+ { ACVTTSS2SL, yxcvfl, Pf3, 0x2c },
+ { ADIVPD, yxm, Pe, 0x5e },
+ { ADIVPS, yxm, Pm, 0x5e },
+ { ADIVSD, yxm, Pf2, 0x5e },
+ { ADIVSS, yxm, Pf3, 0x5e },
+ { AMASKMOVOU, yxr, Pe, 0xf7 },
+ { AMAXPD, yxm, Pe, 0x5f },
+ { AMAXPS, yxm, Pm, 0x5f },
+ { AMAXSD, yxm, Pf2, 0x5f },
+ { AMAXSS, yxm, Pf3, 0x5f },
+ { AMINPD, yxm, Pe, 0x5d },
+ { AMINPS, yxm, Pm, 0x5d },
+ { AMINSD, yxm, Pf2, 0x5d },
+ { AMINSS, yxm, Pf3, 0x5d },
+ { AMOVAPD, yxmov, Pe, 0x28,0x29 },
+ { AMOVAPS, yxmov, Pm, 0x28,0x29 },
+ { AMOVO, yxmov, Pe, 0x6f,0x7f },
+ { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
+ { AMOVHLPS, yxr, Pm, 0x12 },
+ { AMOVHPD, yxmov, Pe, 0x16,0x17 },
+ { AMOVHPS, yxmov, Pm, 0x16,0x17 },
+ { AMOVLHPS, yxr, Pm, 0x16 },
+ { AMOVLPD, yxmov, Pe, 0x12,0x13 },
+ { AMOVLPS, yxmov, Pm, 0x12,0x13 },
+ { AMOVMSKPD, yxrrl, Pq, 0x50 },
+ { AMOVMSKPS, yxrrl, Pm, 0x50 },
+ { AMOVNTO, yxr_ml, Pe, 0xe7 },
+ { AMOVNTPD, yxr_ml, Pe, 0x2b },
+ { AMOVNTPS, yxr_ml, Pm, 0x2b },
+ { AMOVSD, yxmov, Pf2, 0x10,0x11 },
+ { AMOVSS, yxmov, Pf3, 0x10,0x11 },
+ { AMOVUPD, yxmov, Pe, 0x10,0x11 },
+ { AMOVUPS, yxmov, Pm, 0x10,0x11 },
+ { AMULPD, yxm, Pe, 0x59 },
+ { AMULPS, yxm, Ym, 0x59 },
+ { AMULSD, yxm, Pf2, 0x59 },
+ { AMULSS, yxm, Pf3, 0x59 },
+ { AORPD, yxm, Pq, 0x56 },
+ { AORPS, yxm, Pm, 0x56 },
+ { APADDQ, yxm, Pe, 0xd4 },
+ { APAND, yxm, Pe, 0xdb },
+ { APCMPEQB, yxmq, Pe ,0x74 },
+ { APMAXSW, yxm, Pe, 0xee },
+ { APMAXUB, yxm, Pe, 0xde },
+ { APMINSW, yxm, Pe, 0xea },
+ { APMINUB, yxm, Pe, 0xda },
+ { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 },
+ { APSADBW, yxm, Pq, 0xf6 },
+ { APSUBB, yxm, Pe, 0xf8 },
+ { APSUBL, yxm, Pe, 0xfa },
+ { APSUBQ, yxm, Pe, 0xfb },
+ { APSUBSB, yxm, Pe, 0xe8 },
+ { APSUBSW, yxm, Pe, 0xe9 },
+ { APSUBUSB, yxm, Pe, 0xd8 },
+ { APSUBUSW, yxm, Pe, 0xd9 },
+ { APSUBW, yxm, Pe, 0xf9 },
+ { APUNPCKHQDQ, yxm, Pe, 0x6d },
+ { APUNPCKLQDQ, yxm, Pe, 0x6c },
+ { ARCPPS, yxm, Pm, 0x53 },
+ { ARCPSS, yxm, Pf3, 0x53 },
+ { ARSQRTPS, yxm, Pm, 0x52 },
+ { ARSQRTSS, yxm, Pf3, 0x52 },
+ { ASQRTPD, yxm, Pe, 0x51 },
+ { ASQRTPS, yxm, Pm, 0x51 },
+ { ASQRTSD, yxm, Pf2, 0x51 },
+ { ASQRTSS, yxm, Pf3, 0x51 },
+ { ASUBPD, yxm, Pe, 0x5c },
+ { ASUBPS, yxm, Pm, 0x5c },
+ { ASUBSD, yxm, Pf2, 0x5c },
+ { ASUBSS, yxm, Pf3, 0x5c },
+ { AUCOMISD, yxcmp, Pe, 0x2e },
+ { AUCOMISS, yxcmp, Pm, 0x2e },
+ { AUNPCKHPD, yxm, Pe, 0x15 },
+ { AUNPCKHPS, yxm, Pm, 0x15 },
+ { AUNPCKLPD, yxm, Pe, 0x14 },
+ { AUNPCKLPS, yxm, Pm, 0x14 },
+ { AXORPD, yxm, Pe, 0x57 },
+ { AXORPS, yxm, Pm, 0x57 },
+
+ { AAESENC, yaes, Pq, 0x38,0xdc,(0) },
+ { APINSRD, yinsrd, Pq, 0x3a, 0x22, (00) },
+ { APSHUFB, ymshufb,Pq, 0x38, 0x00 },
+
+ { AUSEFIELD, ynop, Px, 0,0 },
+ { ATYPE },
+ { AFUNCDATA, yfuncdata, Px, 0,0 },
+ { APCDATA, ypcdata, Px, 0,0 },
+ { ACHECKNIL },
+ { AFATVARDEF },
+
+ 0
+};
+
+static int32 vaddr(Link*, Addr*, Reloc*);
+
+static void instinit(void);
+
+void
+span8(Link *ctxt, LSym *s)
+{
+ Prog *p, *q;
+ int32 c, v, loop;
+ uchar *bp;
+ int n, m, i;
+
+ ctxt->cursym = s;
+
+ if(s->text == nil || s->text->link == nil)
+ return;
+
+ if(ycover[0] == 0)
+ instinit();
+
+ for(p = s->text; p != nil; p = p->link) {
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == nil)
+ p->pcond = p;
+ if((q = p->pcond) != nil)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = AADDL;
+ if(v < 0) {
+ p->as = ASUBL;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+
+ for(p = s->text; p != nil; p = p->link) {
+ p->back = 2; // use short branches first time through
+ if((q = p->pcond) != nil && (q->back & 2))
+ p->back |= 1; // backward jump
+
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = AADDL;
+ if(v < 0) {
+ p->as = ASUBL;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+
+ n = 0;
+ do {
+ loop = 0;
+ memset(s->r, 0, s->nr*sizeof s->r[0]);
+ s->nr = 0;
+ s->np = 0;
+ c = 0;
+ for(p = s->text; p != nil; p = p->link) {
+ p->pc = c;
+
+ // process forward jumps to p
+ for(q = p->comefrom; q != nil; q = q->forwd) {
+ v = p->pc - (q->pc + q->mark);
+ if(q->back & 2) { // short
+ if(v > 127) {
+ loop++;
+ q->back ^= 2;
+ }
+ if(q->as == AJCXZW)
+ s->p[q->pc+2] = v;
+ else
+ s->p[q->pc+1] = v;
+ } else {
+ bp = s->p + q->pc + q->mark - 4;
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp = v>>24;
+ }
+ }
+ p->comefrom = nil;
+
+ asmins(ctxt, p);
+ p->pc = c;
+ m = ctxt->andptr-ctxt->and;
+ symgrow(ctxt, s, p->pc+m);
+ memmove(s->p+p->pc, ctxt->and, m);
+ p->mark = m;
+ c += m;
+ }
+ if(++n > 20) {
+ ctxt->diag("span must be looping");
+ sysfatal("bad code");
+ }
+ } while(loop);
+ s->size = c;
+
+ if(0 /* debug['a'] > 1 */) {
+ print("span1 %s %d (%d tries)\n %.6ux", s->name, s->size, n, 0);
+ for(i=0; i<s->np; i++) {
+ print(" %.2ux", s->p[i]);
+ if(i%16 == 15)
+ print("\n %.6ux", i+1);
+ }
+ if(i%16)
+ print("\n");
+
+ for(i=0; i<s->nr; i++) {
+ Reloc *r;
+
+ r = &s->r[i];
+ print(" rel %#.4ux/%d %s%+d\n", r->off, r->siz, r->sym->name, r->add);
+ }
+ }
+}
+
+static void
+instinit(void)
+{
+ int i;
+
+ for(i=1; optab[i].as; i++)
+ if(i != optab[i].as)
+ sysfatal("phase error in optab: at %A found %A", i, optab[i].as);
+
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ ycover[Yax*Ymax + Ymm] = 1;
+ ycover[Ycx*Ymax + Ymm] = 1;
+ ycover[Yrx*Ymax + Ymm] = 1;
+ ycover[Yrl*Ymax + Ymm] = 1;
+ ycover[Ym*Ymax + Ymm] = 1;
+ ycover[Ymr*Ymax + Ymm] = 1;
+
+ ycover[Ym*Ymax + Yxm] = 1;
+ ycover[Yxr*Ymax + Yxm] = 1;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_BH)
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_AX && i <= D_DI)
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
+ if(i >= D_X0 && i <= D_X0+7)
+ reg[i] = (i-D_X0) & 7;
+ }
+}
+
+static int
+prefixof(Addr *a)
+{
+ switch(a->type) {
+ case D_INDIR+D_CS:
+ return 0x2e;
+ case D_INDIR+D_DS:
+ return 0x3e;
+ case D_INDIR+D_ES:
+ return 0x26;
+ case D_INDIR+D_FS:
+ return 0x64;
+ case D_INDIR+D_GS:
+ return 0x65;
+ }
+ return 0;
+}
+
+static int
+oclass(Addr *a)
+{
+ int32 v;
+
+ if((a->type >= D_INDIR && a->type < 2*D_INDIR) || a->index != D_NONE) {
+ if(a->index != D_NONE && a->scale == 0) {
+ if(a->type == D_ADDR) {
+ switch(a->index) {
+ case D_EXTERN:
+ case D_STATIC:
+ return Yi32;
+ case D_AUTO:
+ case D_PARAM:
+ return Yiauto;
+ }
+ return Yxxx;
+ }
+ //if(a->type == D_INDIR+D_ADDR)
+ // print("*Ycol\n");
+ return Ycol;
+ }
+ return Ym;
+ }
+ switch(a->type)
+ {
+ case D_AL:
+ return Yal;
+
+ case D_AX:
+ return Yax;
+
+ case D_CL:
+ case D_DL:
+ case D_BL:
+ case D_AH:
+ case D_CH:
+ case D_DH:
+ case D_BH:
+ return Yrb;
+
+ case D_CX:
+ return Ycx;
+
+ case D_DX:
+ case D_BX:
+ return Yrx;
+
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ return Yrl;
+
+ case D_F0+0:
+ return Yf0;
+
+ case D_F0+1:
+ case D_F0+2:
+ case D_F0+3:
+ case D_F0+4:
+ case D_F0+5:
+ case D_F0+6:
+ case D_F0+7:
+ return Yrf;
+
+ case D_X0+0:
+ case D_X0+1:
+ case D_X0+2:
+ case D_X0+3:
+ case D_X0+4:
+ case D_X0+5:
+ case D_X0+6:
+ case D_X0+7:
+ return Yxr;
+
+ case D_NONE:
+ return Ynone;
+
+ case D_CS: return Ycs;
+ case D_SS: return Yss;
+ case D_DS: return Yds;
+ case D_ES: return Yes;
+ case D_FS: return Yfs;
+ case D_GS: return Ygs;
+
+ case D_GDTR: return Ygdtr;
+ case D_IDTR: return Yidtr;
+ case D_LDTR: return Yldtr;
+ case D_MSW: return Ymsw;
+ case D_TASK: return Ytask;
+
+ case D_CR+0: return Ycr0;
+ case D_CR+1: return Ycr1;
+ case D_CR+2: return Ycr2;
+ case D_CR+3: return Ycr3;
+ case D_CR+4: return Ycr4;
+ case D_CR+5: return Ycr5;
+ case D_CR+6: return Ycr6;
+ case D_CR+7: return Ycr7;
+
+ case D_DR+0: return Ydr0;
+ case D_DR+1: return Ydr1;
+ case D_DR+2: return Ydr2;
+ case D_DR+3: return Ydr3;
+ case D_DR+4: return Ydr4;
+ case D_DR+5: return Ydr5;
+ case D_DR+6: return Ydr6;
+ case D_DR+7: return Ydr7;
+
+ case D_TR+0: return Ytr0;
+ case D_TR+1: return Ytr1;
+ case D_TR+2: return Ytr2;
+ case D_TR+3: return Ytr3;
+ case D_TR+4: return Ytr4;
+ case D_TR+5: return Ytr5;
+ case D_TR+6: return Ytr6;
+ case D_TR+7: return Ytr7;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ return Ym;
+
+ case D_CONST:
+ case D_CONST2:
+ case D_ADDR:
+ if(a->sym == nil) {
+ v = a->offset;
+ if(v == 0)
+ return Yi0;
+ if(v == 1)
+ return Yi1;
+ if(v >= -128 && v <= 127)
+ return Yi8;
+ }
+ return Yi32;
+
+ case D_BRANCH:
+ return Ybr;
+ }
+ return Yxxx;
+}
+
+static void
+asmidx(Link *ctxt, int scale, int index, int base)
+{
+ int i;
+
+ switch(index) {
+ default:
+ goto bad;
+
+ case D_NONE:
+ i = 4 << 3;
+ goto bas;
+
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i = reg[index] << 3;
+ break;
+ }
+ switch(scale) {
+ default:
+ goto bad;
+ case 1:
+ break;
+ case 2:
+ i |= (1<<6);
+ break;
+ case 4:
+ i |= (2<<6);
+ break;
+ case 8:
+ i |= (3<<6);
+ break;
+ }
+bas:
+ switch(base) {
+ default:
+ goto bad;
+ case D_NONE: /* must be mod=00 */
+ i |= 5;
+ break;
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i |= reg[base];
+ break;
+ }
+ *ctxt->andptr++ = i;
+ return;
+bad:
+ ctxt->diag("asmidx: bad address %d,%d,%d", scale, index, base);
+ *ctxt->andptr++ = 0;
+ return;
+}
+
+static void
+put4(Link *ctxt, int32 v)
+{
+ ctxt->andptr[0] = v;
+ ctxt->andptr[1] = v>>8;
+ ctxt->andptr[2] = v>>16;
+ ctxt->andptr[3] = v>>24;
+ ctxt->andptr += 4;
+}
+
+static void
+relput4(Link *ctxt, Prog *p, Addr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(ctxt, a, &rel);
+ if(rel.siz != 0) {
+ if(rel.siz != 4)
+ ctxt->diag("bad reloc");
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ put4(ctxt, v);
+}
+
+static int32
+vaddr(Link *ctxt, Addr *a, Reloc *r)
+{
+ int t;
+ int32 v;
+ LSym *s;
+
+ if(r != nil)
+ memset(r, 0, sizeof *r);
+
+ t = a->type;
+ v = a->offset;
+ if(t == D_ADDR)
+ t = a->index;
+ switch(t) {
+ case D_STATIC:
+ case D_EXTERN:
+ s = a->sym;
+ if(s != nil) {
+ if(r == nil) {
+ ctxt->diag("need reloc for %D", a);
+ sysfatal("bad code");
+ }
+ r->type = D_ADDR;
+ r->siz = 4;
+ r->off = -1;
+ r->sym = s;
+ r->add = v;
+ v = 0;
+ }
+ }
+ return v;
+}
+
+static int
+istls(Link *ctxt, Addr *a)
+{
+ if(ctxt->headtype == Hlinux)
+ return a->index == D_GS;
+ return a->type == D_INDIR+D_GS;
+}
+
+static void
+asmand(Link *ctxt, Addr *a, int r)
+{
+ int32 v;
+ int t, scale;
+ Reloc rel;
+
+ v = a->offset;
+ t = a->type;
+ rel.siz = 0;
+ if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) {
+ if(t < D_INDIR || t >= 2*D_INDIR) {
+ switch(t) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(ctxt, a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ } else
+ t -= D_INDIR;
+
+ if(t == D_NONE) {
+ *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(v == 0 && rel.siz == 0 && t != D_BP) {
+ *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ return;
+ }
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ *ctxt->andptr++ = v;
+ return;
+ }
+ *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(t >= D_AL && t <= D_F7 || t >= D_X0 && t <= D_X7) {
+ if(v)
+ goto bad;
+ *ctxt->andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+
+ scale = a->scale;
+ if(t < D_INDIR || t >= 2*D_INDIR) {
+ switch(a->type) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(ctxt, a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ scale = 1;
+ } else
+ t -= D_INDIR;
+
+ if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
+ *ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ goto putrelv;
+ }
+ if(t == D_SP) {
+ if(v == 0 && rel.siz == 0) {
+ *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, scale, D_NONE, t);
+ return;
+ }
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, scale, D_NONE, t);
+ *ctxt->andptr++ = v;
+ return;
+ }
+ *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, scale, D_NONE, t);
+ goto putrelv;
+ }
+ if(t >= D_AX && t <= D_DI) {
+ if(v == 0 && rel.siz == 0 && t != D_BP) {
+ *ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+ if(v >= -128 && v < 128 && rel.siz == 0 && a->index != D_FS && a->index != D_GS) {
+ ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ ctxt->andptr[1] = v;
+ ctxt->andptr += 2;
+ return;
+ }
+ *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ goto putrelv;
+ }
+ goto bad;
+
+putrelv:
+ if(rel.siz != 0) {
+ Reloc *r;
+
+ if(rel.siz != 4) {
+ ctxt->diag("bad rel");
+ goto bad;
+ }
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and;
+ } else if(ctxt->iself && ctxt->linkmode == LinkExternal && istls(ctxt, a) && ctxt->headtype != Hopenbsd) {
+ Reloc *r;
+ LSym *s;
+
+ r = addrel(ctxt->cursym);
+ r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and;
+ r->add = a->offset - ctxt->tlsoffset;
+ r->xadd = r->add;
+ r->siz = 4;
+ r->type = D_TLS;
+ s = linklookup(ctxt, "runtime.tlsgm", 0);
+ r->sym = s;
+ r->xsym = s;
+ v = 0;
+ }
+
+ put4(ctxt, v);
+ return;
+
+bad:
+ ctxt->diag("asmand: bad address %D", a);
+ return;
+}
+
+#define E 0xff
+static uchar ymovtab[] =
+{
+/* push */
+ APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0,
+ APUSHL, Yss, Ynone, 0, 0x16,E,0,0,
+ APUSHL, Yds, Ynone, 0, 0x1e,E,0,0,
+ APUSHL, Yes, Ynone, 0, 0x06,E,0,0,
+ APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0,
+ APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0,
+
+ APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0,
+ APUSHW, Yss, Ynone, 0, Pe,0x16,E,0,
+ APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0,
+ APUSHW, Yes, Ynone, 0, Pe,0x06,E,0,
+ APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E,
+ APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E,
+
+/* pop */
+ APOPL, Ynone, Yds, 0, 0x1f,E,0,0,
+ APOPL, Ynone, Yes, 0, 0x07,E,0,0,
+ APOPL, Ynone, Yss, 0, 0x17,E,0,0,
+ APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0,
+ APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0,
+
+ APOPW, Ynone, Yds, 0, Pe,0x1f,E,0,
+ APOPW, Ynone, Yes, 0, Pe,0x07,E,0,
+ APOPW, Ynone, Yss, 0, Pe,0x17,E,0,
+ APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E,
+ APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E,
+
+/* mov seg */
+ AMOVW, Yes, Yml, 1, 0x8c,0,0,0,
+ AMOVW, Ycs, Yml, 1, 0x8c,1,0,0,
+ AMOVW, Yss, Yml, 1, 0x8c,2,0,0,
+ AMOVW, Yds, Yml, 1, 0x8c,3,0,0,
+ AMOVW, Yfs, Yml, 1, 0x8c,4,0,0,
+ AMOVW, Ygs, Yml, 1, 0x8c,5,0,0,
+
+ AMOVW, Yml, Yes, 2, 0x8e,0,0,0,
+ AMOVW, Yml, Ycs, 2, 0x8e,1,0,0,
+ AMOVW, Yml, Yss, 2, 0x8e,2,0,0,
+ AMOVW, Yml, Yds, 2, 0x8e,3,0,0,
+ AMOVW, Yml, Yfs, 2, 0x8e,4,0,0,
+ AMOVW, Yml, Ygs, 2, 0x8e,5,0,0,
+
+/* mov cr */
+ AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0,
+ AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0,
+ AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0,
+ AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0,
+
+ AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0,
+ AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0,
+ AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0,
+ AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0,
+
+/* mov dr */
+ AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0,
+ AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0,
+ AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0,
+
+ AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0,
+ AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0,
+ AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0,
+
+/* mov tr */
+ AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0,
+ AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0,
+
+ AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E,
+ AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E,
+
+/* lgdt, sgdt, lidt, sidt */
+ AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0,
+ AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0,
+ AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0,
+ AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0,
+
+/* lldt, sldt */
+ AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0,
+ AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0,
+
+/* lmsw, smsw */
+ AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0,
+ AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0,
+
+/* ltr, str */
+ AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0,
+ AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0,
+
+/* load full pointer */
+ AMOVL, Yml, Ycol, 5, 0,0,0,0,
+ AMOVW, Yml, Ycol, 5, Pe,0,0,0,
+
+/* double shift */
+ ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0,
+ ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0,
+
+/* extra imul */
+ AIMULW, Yml, Yrl, 7, Pq,0xaf,0,0,
+ AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0,
+ 0
+};
+
+// byteswapreg returns a byte-addressable register (AX, BX, CX, DX)
+// which is not referenced in a->type.
+// If a is empty, it returns BX to account for MULB-like instructions
+// that might use DX and AX.
+static int
+byteswapreg(Link *ctxt, Addr *a)
+{
+ int cana, canb, canc, cand;
+
+ cana = canb = canc = cand = 1;
+
+ switch(a->type) {
+ case D_NONE:
+ cana = cand = 0;
+ break;
+ case D_AX:
+ case D_AL:
+ case D_AH:
+ case D_INDIR+D_AX:
+ cana = 0;
+ break;
+ case D_BX:
+ case D_BL:
+ case D_BH:
+ case D_INDIR+D_BX:
+ canb = 0;
+ break;
+ case D_CX:
+ case D_CL:
+ case D_CH:
+ case D_INDIR+D_CX:
+ canc = 0;
+ break;
+ case D_DX:
+ case D_DL:
+ case D_DH:
+ case D_INDIR+D_DX:
+ cand = 0;
+ break;
+ }
+ switch(a->index) {
+ case D_AX:
+ cana = 0;
+ break;
+ case D_BX:
+ canb = 0;
+ break;
+ case D_CX:
+ canc = 0;
+ break;
+ case D_DX:
+ cand = 0;
+ break;
+ }
+ if(cana)
+ return D_AX;
+ if(canb)
+ return D_BX;
+ if(canc)
+ return D_CX;
+ if(cand)
+ return D_DX;
+
+ ctxt->diag("impossible byte register");
+ sysfatal("bad code");
+ return 0;
+}
+
+static void
+subreg(Prog *p, int from, int to)
+{
+
+ if(0 /* debug['Q'] */)
+ print("\n%P s/%R/%R/\n", p, from, to);
+
+ if(p->from.type == from) {
+ p->from.type = to;
+ p->ft = 0;
+ }
+ if(p->to.type == from) {
+ p->to.type = to;
+ p->tt = 0;
+ }
+
+ if(p->from.index == from) {
+ p->from.index = to;
+ p->ft = 0;
+ }
+ if(p->to.index == from) {
+ p->to.index = to;
+ p->tt = 0;
+ }
+
+ from += D_INDIR;
+ if(p->from.type == from) {
+ p->from.type = to+D_INDIR;
+ p->ft = 0;
+ }
+ if(p->to.type == from) {
+ p->to.type = to+D_INDIR;
+ p->tt = 0;
+ }
+
+ if(0 /* debug['Q'] */)
+ print("%P\n", p);
+}
+
+static int
+mediaop(Link *ctxt, Optab *o, int op, int osize, int z)
+{
+ switch(op){
+ case Pm:
+ case Pe:
+ case Pf2:
+ case Pf3:
+ if(osize != 1){
+ if(op != Pm)
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = Pm;
+ op = o->op[++z];
+ break;
+ }
+ default:
+ if(ctxt->andptr == ctxt->and || ctxt->andptr[-1] != Pm)
+ *ctxt->andptr++ = Pm;
+ break;
+ }
+ *ctxt->andptr++ = op;
+ return z;
+}
+
+static void
+doasm(Link *ctxt, Prog *p)
+{
+ Optab *o;
+ Prog *q, pp;
+ uchar *t;
+ int z, op, ft, tt, breg;
+ int32 v, pre;
+ Reloc rel, *r;
+ Addr *a;
+
+ ctxt->curp = p; // TODO
+
+ pre = prefixof(&p->from);
+ if(pre)
+ *ctxt->andptr++ = pre;
+ pre = prefixof(&p->to);
+ if(pre)
+ *ctxt->andptr++ = pre;
+
+ if(p->ft == 0)
+ p->ft = oclass(&p->from);
+ if(p->tt == 0)
+ p->tt = oclass(&p->to);
+
+ ft = p->ft * Ymax;
+ tt = p->tt * Ymax;
+ o = &optab[p->as];
+ t = o->ytab;
+ if(t == 0) {
+ ctxt->diag("asmins: noproto %P", p);
+ return;
+ }
+ for(z=0; *t; z+=t[3],t+=4)
+ if(ycover[ft+t[0]])
+ if(ycover[tt+t[1]])
+ goto found;
+ goto domov;
+
+found:
+ switch(o->prefix) {
+ case Pq: /* 16 bit escape and opcode escape */
+ *ctxt->andptr++ = Pe;
+ *ctxt->andptr++ = Pm;
+ break;
+
+ case Pf2: /* xmm opcode escape */
+ case Pf3:
+ *ctxt->andptr++ = o->prefix;
+ *ctxt->andptr++ = Pm;
+ break;
+
+ case Pm: /* opcode escape */
+ *ctxt->andptr++ = Pm;
+ break;
+
+ case Pe: /* 16 bit escape */
+ *ctxt->andptr++ = Pe;
+ break;
+
+ case Pb: /* botch */
+ break;
+ }
+
+ op = o->op[z];
+ switch(t[2]) {
+ default:
+ ctxt->diag("asmins: unknown z %d %P", t[2], p);
+ return;
+
+ case Zpseudo:
+ break;
+
+ case Zlit:
+ for(; op = o->op[z]; z++)
+ *ctxt->andptr++ = op;
+ break;
+
+ case Zlitm_r:
+ for(; op = o->op[z]; z++)
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ break;
+
+ case Zm_r:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ break;
+
+ case Zm2_r:
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = o->op[z+1];
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ break;
+
+ case Zm_r_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ break;
+
+ case Zm_r_i_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ *ctxt->andptr++ = p->to.offset;
+ break;
+
+ case Zibm_r:
+ while ((op = o->op[z++]) != 0)
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ *ctxt->andptr++ = p->to.offset;
+ break;
+
+ case Zaut_r:
+ *ctxt->andptr++ = 0x8d; /* leal */
+ if(p->from.type != D_ADDR)
+ ctxt->diag("asmins: Zaut sb type ADDR");
+ p->from.type = p->from.index;
+ p->from.index = D_NONE;
+ p->ft = 0;
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ p->from.index = p->from.type;
+ p->from.type = D_ADDR;
+ p->ft = 0;
+ break;
+
+ case Zm_o:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, o->op[z+1]);
+ break;
+
+ case Zr_m:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, reg[p->from.type]);
+ break;
+
+ case Zr_m_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->to, reg[p->from.type]);
+ break;
+
+ case Zr_m_i_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->to, reg[p->from.type]);
+ *ctxt->andptr++ = p->from.offset;
+ break;
+
+ case Zo_m:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, o->op[z+1]);
+ break;
+
+ case Zm_ibo:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, o->op[z+1]);
+ *ctxt->andptr++ = vaddr(ctxt, &p->to, nil);
+ break;
+
+ case Zibo_m:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, o->op[z+1]);
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Z_ib:
+ case Zib_:
+ if(t[2] == Zib_)
+ a = &p->from;
+ else
+ a = &p->to;
+ v = vaddr(ctxt, a, nil);
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = v;
+ break;
+
+ case Zib_rp:
+ *ctxt->andptr++ = op + reg[p->to.type];
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Zil_rp:
+ *ctxt->andptr++ = op + reg[p->to.type];
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, &p->from, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, &p->from);
+ break;
+
+ case Zib_rr:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, reg[p->to.type]);
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Z_il:
+ case Zil_:
+ if(t[2] == Zil_)
+ a = &p->from;
+ else
+ a = &p->to;
+ *ctxt->andptr++ = op;
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, a, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, a);
+ break;
+
+ case Zm_ilo:
+ case Zilo_m:
+ *ctxt->andptr++ = op;
+ if(t[2] == Zilo_m) {
+ a = &p->from;
+ asmand(ctxt, &p->to, o->op[z+1]);
+ } else {
+ a = &p->to;
+ asmand(ctxt, &p->from, o->op[z+1]);
+ }
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, a, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, a);
+ break;
+
+ case Zil_rr:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, reg[p->to.type]);
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, &p->from, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, &p->from);
+ break;
+
+ case Z_rp:
+ *ctxt->andptr++ = op + reg[p->to.type];
+ break;
+
+ case Zrp_:
+ *ctxt->andptr++ = op + reg[p->from.type];
+ break;
+
+ case Zclr:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, reg[p->to.type]);
+ break;
+
+ case Zcall:
+ if(p->to.sym == nil) {
+ ctxt->diag("call without target");
+ sysfatal("bad code");
+ }
+ *ctxt->andptr++ = op;
+ r = addrel(ctxt->cursym);
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ r->type = D_PCREL;
+ r->siz = 4;
+ r->sym = p->to.sym;
+ put4(ctxt, 0);
+ break;
+
+ case Zbr:
+ case Zjmp:
+ case Zloop:
+ if(p->to.sym != nil) {
+ if(t[2] != Zjmp) {
+ ctxt->diag("branch to ATEXT");
+ sysfatal("bad code");
+ }
+ *ctxt->andptr++ = o->op[z+1];
+ r = addrel(ctxt->cursym);
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ r->sym = p->to.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(ctxt, 0);
+ break;
+ }
+
+ // Assumes q is in this function.
+ // Fill in backward jump now.
+ q = p->pcond;
+ if(q == nil) {
+ ctxt->diag("jmp/branch/loop without target");
+ sysfatal("bad code");
+ }
+ if(p->back & 1) {
+ v = q->pc - (p->pc + 2);
+ if(v >= -128) {
+ if(p->as == AJCXZW)
+ *ctxt->andptr++ = 0x67;
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = v;
+ } else if(t[2] == Zloop) {
+ ctxt->diag("loop too far: %P", p);
+ } else {
+ v -= 5-2;
+ if(t[2] == Zbr) {
+ *ctxt->andptr++ = 0x0f;
+ v--;
+ }
+ *ctxt->andptr++ = o->op[z+1];
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ *ctxt->andptr++ = v>>16;
+ *ctxt->andptr++ = v>>24;
+ }
+ break;
+ }
+
+ // Annotate target; will fill in later.
+ p->forwd = q->comefrom;
+ q->comefrom = p;
+ if(p->back & 2) { // short
+ if(p->as == AJCXZW)
+ *ctxt->andptr++ = 0x67;
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = 0;
+ } else if(t[2] == Zloop) {
+ ctxt->diag("loop too far: %P", p);
+ } else {
+ if(t[2] == Zbr)
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = o->op[z+1];
+ *ctxt->andptr++ = 0;
+ *ctxt->andptr++ = 0;
+ *ctxt->andptr++ = 0;
+ *ctxt->andptr++ = 0;
+ }
+ break;
+
+ case Zcallcon:
+ case Zjmpcon:
+ if(t[2] == Zcallcon)
+ *ctxt->andptr++ = op;
+ else
+ *ctxt->andptr++ = o->op[z+1];
+ r = addrel(ctxt->cursym);
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ r->type = D_PCREL;
+ r->siz = 4;
+ r->add = p->to.offset;
+ put4(ctxt, 0);
+ break;
+
+ case Zcallind:
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = o->op[z+1];
+ r = addrel(ctxt->cursym);
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ r->type = D_ADDR;
+ r->siz = 4;
+ r->add = p->to.offset;
+ r->sym = p->to.sym;
+ put4(ctxt, 0);
+ break;
+
+ case Zbyte:
+ v = vaddr(ctxt, &p->from, &rel);
+ if(rel.siz != 0) {
+ rel.siz = op;
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ *ctxt->andptr++ = v;
+ if(op > 1) {
+ *ctxt->andptr++ = v>>8;
+ if(op > 2) {
+ *ctxt->andptr++ = v>>16;
+ *ctxt->andptr++ = v>>24;
+ }
+ }
+ break;
+
+ case Zmov:
+ goto domov;
+ }
+ return;
+
+domov:
+ for(t=ymovtab; *t; t+=8)
+ if(p->as == t[0])
+ if(ycover[ft+t[1]])
+ if(ycover[tt+t[2]])
+ goto mfound;
+bad:
+ /*
+ * here, the assembly has failed.
+ * if its a byte instruction that has
+ * unaddressable registers, try to
+ * exchange registers and reissue the
+ * instruction with the operands renamed.
+ */
+ pp = *p;
+ z = p->from.type;
+ if(z >= D_BP && z <= D_DI) {
+ if((breg = byteswapreg(ctxt, &p->to)) != D_AX) {
+ *ctxt->andptr++ = 0x87; /* xchg lhs,bx */
+ asmand(ctxt, &p->from, reg[breg]);
+ subreg(&pp, z, breg);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x87; /* xchg lhs,bx */
+ asmand(ctxt, &p->from, reg[breg]);
+ } else {
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ }
+ return;
+ }
+ z = p->to.type;
+ if(z >= D_BP && z <= D_DI) {
+ if((breg = byteswapreg(ctxt, &p->from)) != D_AX) {
+ *ctxt->andptr++ = 0x87; /* xchg rhs,bx */
+ asmand(ctxt, &p->to, reg[breg]);
+ subreg(&pp, z, breg);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x87; /* xchg rhs,bx */
+ asmand(ctxt, &p->to, reg[breg]);
+ } else {
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ }
+ return;
+ }
+ ctxt->diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
+ return;
+
+mfound:
+ switch(t[3]) {
+ default:
+ ctxt->diag("asmins: unknown mov %d %P", t[3], p);
+ break;
+
+ case 0: /* lit */
+ for(z=4; t[z]!=E; z++)
+ *ctxt->andptr++ = t[z];
+ break;
+
+ case 1: /* r,m */
+ *ctxt->andptr++ = t[4];
+ asmand(ctxt, &p->to, t[5]);
+ break;
+
+ case 2: /* m,r */
+ *ctxt->andptr++ = t[4];
+ asmand(ctxt, &p->from, t[5]);
+ break;
+
+ case 3: /* r,m - 2op */
+ *ctxt->andptr++ = t[4];
+ *ctxt->andptr++ = t[5];
+ asmand(ctxt, &p->to, t[6]);
+ break;
+
+ case 4: /* m,r - 2op */
+ *ctxt->andptr++ = t[4];
+ *ctxt->andptr++ = t[5];
+ asmand(ctxt, &p->from, t[6]);
+ break;
+
+ case 5: /* load full pointer, trash heap */
+ if(t[4])
+ *ctxt->andptr++ = t[4];
+ switch(p->to.index) {
+ default:
+ goto bad;
+ case D_DS:
+ *ctxt->andptr++ = 0xc5;
+ break;
+ case D_SS:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0xb2;
+ break;
+ case D_ES:
+ *ctxt->andptr++ = 0xc4;
+ break;
+ case D_FS:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0xb4;
+ break;
+ case D_GS:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0xb5;
+ break;
+ }
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ break;
+
+ case 6: /* double shift */
+ z = p->from.type;
+ switch(z) {
+ default:
+ goto bad;
+ case D_CONST:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = t[4];
+ asmand(ctxt, &p->to, reg[p->from.index]);
+ *ctxt->andptr++ = p->from.offset;
+ break;
+ case D_CL:
+ case D_CX:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = t[5];
+ asmand(ctxt, &p->to, reg[p->from.index]);
+ break;
+ }
+ break;
+
+ case 7: /* imul rm,r */
+ if(t[4] == Pq) {
+ *ctxt->andptr++ = Pe;
+ *ctxt->andptr++ = Pm;
+ } else
+ *ctxt->andptr++ = t[4];
+ *ctxt->andptr++ = t[5];
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ break;
+ }
+}
+
+static void
+asmins(Link *ctxt, Prog *p)
+{
+ ctxt->andptr = ctxt->and;
+ doasm(ctxt, p);
+ if(ctxt->andptr > ctxt->and+sizeof ctxt->and) {
+ print("and[] is too short - %ld byte instruction\n", ctxt->andptr - ctxt->and);
+ sysfatal("bad code");
+ }
+}
diff --git a/src/liblink/data.c b/src/liblink/data.c
new file mode 100644
index 000000000..97d226041
--- /dev/null
+++ b/src/liblink/data.c
@@ -0,0 +1,366 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+void
+mangle(char *file)
+{
+ sysfatal("%s: mangled input file", file);
+}
+
+void
+symgrow(Link *ctxt, LSym *s, int32 siz)
+{
+ USED(ctxt);
+
+ if(s->np >= siz)
+ return;
+
+ if(s->np > s->maxp) {
+ ctxt->cursym = s;
+ sysfatal("corrupt symbol data: np=%lld > maxp=%lld", (vlong)s->np, (vlong)s->maxp);
+ }
+
+ if(s->maxp < siz) {
+ if(s->maxp == 0)
+ s->maxp = 8;
+ while(s->maxp < siz)
+ s->maxp <<= 1;
+ s->p = erealloc(s->p, s->maxp);
+ memset(s->p+s->np, 0, s->maxp-s->np);
+ }
+ s->np = siz;
+}
+
+void
+savedata(Link *ctxt, LSym *s, Prog *p, char *pn)
+{
+ int32 off, siz, i, fl;
+ float32 flt;
+ uchar *cast;
+ vlong o;
+ Reloc *r;
+
+ off = p->from.offset;
+ siz = ctxt->arch->datasize(p);
+ if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
+ mangle(pn);
+ symgrow(ctxt, s, off+siz);
+
+ if(p->to.type == ctxt->arch->D_FCONST) {
+ switch(siz) {
+ default:
+ case 4:
+ flt = p->to.u.dval;
+ cast = (uchar*)&flt;
+ for(i=0; i<4; i++)
+ s->p[off+i] = cast[fnuxi4[i]];
+ break;
+ case 8:
+ cast = (uchar*)&p->to.u.dval;
+ for(i=0; i<8; i++)
+ s->p[off+i] = cast[fnuxi8[i]];
+ break;
+ }
+ } else if(p->to.type == ctxt->arch->D_SCONST) {
+ for(i=0; i<siz; i++)
+ s->p[off+i] = p->to.u.sval[i];
+ } else if(p->to.type == ctxt->arch->D_CONST) {
+ if(p->to.sym)
+ goto Addr;
+ o = p->to.offset;
+ fl = o;
+ cast = (uchar*)&fl;
+ switch(siz) {
+ default:
+ ctxt->diag("bad nuxi %d\n%P", siz, p);
+ break;
+ case 1:
+ s->p[off] = cast[inuxi1[0]];
+ break;
+ case 2:
+ for(i=0; i<2; i++)
+ s->p[off+i] = cast[inuxi2[i]];
+ break;
+ case 4:
+ for(i=0; i<4; i++)
+ s->p[off+i] = cast[inuxi4[i]];
+ break;
+ case 8:
+ cast = (uchar*)&o;
+ for(i=0; i<8; i++)
+ s->p[off+i] = cast[inuxi8[i]];
+ break;
+ }
+ } else if(p->to.type == ctxt->arch->D_ADDR || p->to.type == ctxt->arch->D_SIZE) {
+ Addr:
+ r = addrel(s);
+ r->off = off;
+ r->siz = siz;
+ r->sym = p->to.sym;
+ r->type = p->to.type;
+ if(r->type != ctxt->arch->D_SIZE)
+ r->type = ctxt->arch->D_ADDR;
+ r->add = p->to.offset;
+ } else {
+ ctxt->diag("bad data: %P", p);
+ }
+}
+
+Reloc*
+addrel(LSym *s)
+{
+ if(s->nr >= s->maxr) {
+ if(s->maxr == 0)
+ s->maxr = 4;
+ else
+ s->maxr <<= 1;
+ s->r = erealloc(s->r, s->maxr*sizeof s->r[0]);
+ memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
+ }
+ return &s->r[s->nr++];
+}
+
+vlong
+setuintxx(Link *ctxt, LSym *s, vlong off, uint64 v, vlong wid)
+{
+ int32 i, fl;
+ vlong o;
+ uchar *cast;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ if(s->size < off+wid) {
+ s->size = off+wid;
+ symgrow(ctxt, s, s->size);
+ }
+ fl = v;
+ cast = (uchar*)&fl;
+ switch(wid) {
+ case 1:
+ s->p[off] = cast[inuxi1[0]];
+ break;
+ case 2:
+ for(i=0; i<2; i++)
+ s->p[off+i] = cast[inuxi2[i]];
+ break;
+ case 4:
+ for(i=0; i<4; i++)
+ s->p[off+i] = cast[inuxi4[i]];
+ break;
+ case 8:
+ o = v;
+ cast = (uchar*)&o;
+ for(i=0; i<8; i++)
+ s->p[off+i] = cast[inuxi8[i]];
+ break;
+ }
+ return off+wid;
+}
+
+vlong
+adduintxx(Link *ctxt, LSym *s, uint64 v, int wid)
+{
+ vlong off;
+
+ off = s->size;
+ setuintxx(ctxt, s, off, v, wid);
+ return off;
+}
+
+vlong
+adduint8(Link *ctxt, LSym *s, uint8 v)
+{
+ return adduintxx(ctxt, s, v, 1);
+}
+
+vlong
+adduint16(Link *ctxt, LSym *s, uint16 v)
+{
+ return adduintxx(ctxt, s, v, 2);
+}
+
+vlong
+adduint32(Link *ctxt, LSym *s, uint32 v)
+{
+ return adduintxx(ctxt, s, v, 4);
+}
+
+vlong
+adduint64(Link *ctxt, LSym *s, uint64 v)
+{
+ return adduintxx(ctxt, s, v, 8);
+}
+
+vlong
+setuint8(Link *ctxt, LSym *s, vlong r, uint8 v)
+{
+ return setuintxx(ctxt, s, r, v, 1);
+}
+
+vlong
+setuint16(Link *ctxt, LSym *s, vlong r, uint16 v)
+{
+ return setuintxx(ctxt, s, r, v, 2);
+}
+
+vlong
+setuint32(Link *ctxt, LSym *s, vlong r, uint32 v)
+{
+ return setuintxx(ctxt, s, r, v, 4);
+}
+
+vlong
+setuint64(Link *ctxt, LSym *s, vlong r, uint64 v)
+{
+ return setuintxx(ctxt, s, r, v, 8);
+}
+
+vlong
+addaddrplus(Link *ctxt, LSym *s, LSym *t, vlong add)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += ctxt->arch->ptrsize;
+ symgrow(ctxt, s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->siz = ctxt->arch->ptrsize;
+ r->type = ctxt->arch->D_ADDR;
+ r->add = add;
+ return i + r->siz;
+}
+
+vlong
+addpcrelplus(Link *ctxt, LSym *s, LSym *t, vlong add)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += 4;
+ symgrow(ctxt, s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->add = add;
+ r->type = ctxt->arch->D_PCREL;
+ r->siz = 4;
+ return i + r->siz;
+}
+
+vlong
+addaddr(Link *ctxt, LSym *s, LSym *t)
+{
+ return addaddrplus(ctxt, s, t, 0);
+}
+
+vlong
+setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add)
+{
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ if(off+ctxt->arch->ptrsize > s->size) {
+ s->size = off + ctxt->arch->ptrsize;
+ symgrow(ctxt, s, s->size);
+ }
+ r = addrel(s);
+ r->sym = t;
+ r->off = off;
+ r->siz = ctxt->arch->ptrsize;
+ r->type = ctxt->arch->D_ADDR;
+ r->add = add;
+ return off + r->siz;
+}
+
+vlong
+setaddr(Link *ctxt, LSym *s, vlong off, LSym *t)
+{
+ return setaddrplus(ctxt, s, off, t, 0);
+}
+
+vlong
+addsize(Link *ctxt, LSym *s, LSym *t)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += ctxt->arch->ptrsize;
+ symgrow(ctxt, s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->siz = ctxt->arch->ptrsize;
+ r->type = ctxt->arch->D_SIZE;
+ return i + r->siz;
+}
+
+vlong
+addaddrplus4(Link *ctxt, LSym *s, LSym *t, vlong add)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += 4;
+ symgrow(ctxt, s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->siz = 4;
+ r->type = ctxt->arch->D_ADDR;
+ r->add = add;
+ return i + r->siz;
+}
diff --git a/src/liblink/go.c b/src/liblink/go.c
new file mode 100644
index 000000000..9f5a423d3
--- /dev/null
+++ b/src/liblink/go.c
@@ -0,0 +1,74 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// go-specific code shared across loaders (5l, 6l, 8l).
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+// replace all "". with pkg.
+char*
+expandpkg(char *t0, char *pkg)
+{
+ int n;
+ char *p;
+ char *w, *w0, *t;
+
+ n = 0;
+ for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3)
+ n++;
+
+ if(n == 0)
+ return estrdup(t0);
+
+ w0 = emallocz(strlen(t0) + strlen(pkg)*n);
+ w = w0;
+ for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) {
+ memmove(w, t, p - t);
+ w += p-t;
+ strcpy(w, pkg);
+ w += strlen(pkg);
+ t = p+2;
+ }
+ strcpy(w, t);
+ return w0;
+}
+
+void*
+emallocz(long n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(p == nil)
+ sysfatal("out of memory");
+ memset(p, 0, n);
+ return p;
+}
+
+char*
+estrdup(char *p)
+{
+ p = strdup(p);
+ if(p == nil)
+ sysfatal("out of memory");
+ return p;
+}
+
+void*
+erealloc(void *p, long n)
+{
+ p = realloc(p, n);
+ if(p == nil)
+ sysfatal("out of memory");
+ return p;
+}
+
+void
+double2ieee(uint64 *ieee, float64 f)
+{
+ memmove(ieee, &f, 8);
+}
diff --git a/src/liblink/ld.c b/src/liblink/ld.c
new file mode 100644
index 000000000..f6632877b
--- /dev/null
+++ b/src/liblink/ld.c
@@ -0,0 +1,572 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+void
+copyhistfrog(Link *ctxt, char *buf, int nbuf)
+{
+ char *p, *ep;
+ int i;
+
+ p = buf;
+ ep = buf + nbuf;
+ for(i=0; i<ctxt->histfrogp; i++) {
+ p = seprint(p, ep, "%s", ctxt->histfrog[i]->name+1);
+ if(i+1<ctxt->histfrogp && (p == buf || p[-1] != '/'))
+ p = seprint(p, ep, "/");
+ }
+}
+
+void
+addhist(Link *ctxt, int32 line, int type)
+{
+ Auto *u;
+ LSym *s;
+ int i, j, k;
+
+ u = emallocz(sizeof(Auto));
+ s = emallocz(sizeof(LSym));
+ s->name = emallocz(2*(ctxt->histfrogp+1) + 1);
+
+ u->asym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = ctxt->curhist;
+ ctxt->curhist = u;
+
+ s->name[0] = 0;
+ j = 1;
+ for(i=0; i<ctxt->histfrogp; i++) {
+ k = ctxt->histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+ s->name[j] = 0;
+ s->name[j+1] = 0;
+}
+
+void
+histtoauto(Link *ctxt)
+{
+ Auto *l;
+
+ while(l = ctxt->curhist) {
+ ctxt->curhist = l->link;
+ l->link = ctxt->curauto;
+ ctxt->curauto = l;
+ }
+}
+
+void
+collapsefrog(Link *ctxt, LSym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<ctxt->histfrogp; i++)
+ if(strcmp(ctxt->histfrog[i]->name+1, "..") == 0) {
+ memmove(ctxt->histfrog+i-1, ctxt->histfrog+i+1,
+ (ctxt->histfrogp-i-1)*sizeof(ctxt->histfrog[0]));
+ ctxt->histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<ctxt->histfrogp; i++)
+ if(strcmp(ctxt->histfrog[i]->name+1, ".") == 0) {
+ memmove(ctxt->histfrog+i, ctxt->histfrog+i+1,
+ (ctxt->histfrogp-i-1)*sizeof(ctxt->histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(ctxt->histfrog+0, ctxt->histfrog+1,
+ (ctxt->histfrogp-1)*sizeof(ctxt->histfrog[0]));
+
+out:
+ ctxt->histfrog[ctxt->histfrogp-1] = s;
+}
+
+// Saved history stacks encountered while reading archives.
+// Keeping them allows us to answer virtual lineno -> file:line
+// queries.
+//
+// The history stack is a complex data structure, described best at the
+// bottom of http://plan9.bell-labs.com/magic/man2html/6/a.out.
+// One of the key benefits of interpreting it here is that the runtime
+// does not have to. Perhaps some day the compilers could generate
+// a simpler linker input too.
+
+// savehist processes a single line, off history directive
+// found in the input object file.
+void
+savehist(Link *ctxt, int32 line, int32 off)
+{
+ char tmp[1024];
+ LSym *file;
+ Hist2 *h;
+
+ // NOTE(rsc): We used to do the copyctxt->histfrog first and this
+ // condition was if(tmp[0] != '\0') to check for an empty string,
+ // implying that ctxt->histfrogp == 0, implying that this is a history pop.
+ // However, on Windows in the misc/cgo test, the linker is
+ // presented with an ANAME corresponding to an empty string,
+ // that ANAME ends up being the only ctxt->histfrog, and thus we have
+ // a situation where ctxt->histfrogp > 0 (not a pop) but the path we find
+ // is the empty string. Really that shouldn't happen, but it doesn't
+ // seem to be bothering anyone yet, and it's easier to fix the condition
+ // to test ctxt->histfrogp than to track down where that empty string is
+ // coming from. Probably it is coming from go tool pack's P command.
+ if(ctxt->histfrogp > 0) {
+ tmp[0] = '\0';
+ copyhistfrog(ctxt, tmp, sizeof tmp);
+ file = linklookup(ctxt, tmp, HistVersion);
+ } else
+ file = nil;
+
+ if(file != nil && line == 1 && off == 0) {
+ // start of new stack
+ if(ctxt->histdepth != 0)
+ sysfatal("history stack phase error: unexpected start of new stack depth=%d file=%s", ctxt->histdepth, tmp);
+ ctxt->nhist2 = 0;
+ ctxt->histcopy = nil;
+ }
+
+ if(ctxt->nhist2 >= ctxt->maxhist2) {
+ if(ctxt->maxhist2 == 0)
+ ctxt->maxhist2 = 1;
+ ctxt->maxhist2 *= 2;
+ ctxt->hist2 = erealloc(ctxt->hist2, ctxt->maxhist2*sizeof ctxt->hist2[0]);
+ }
+ h = &ctxt->hist2[ctxt->nhist2++];
+ h->line = line;
+ h->off = off;
+ h->file = file;
+
+ if(file != nil) {
+ if(off == 0)
+ ctxt->histdepth++;
+ } else {
+ if(off != 0)
+ sysfatal("history stack phase error: bad offset in pop");
+ ctxt->histdepth--;
+ }
+}
+
+// gethist returns the history stack currently in effect.
+// The result is valid indefinitely.
+Hist2*
+gethist(Link *ctxt)
+{
+ if(ctxt->histcopy == nil) {
+ if(ctxt->nhist2 == 0)
+ return nil;
+ ctxt->histcopy = emallocz((ctxt->nhist2+1)*sizeof ctxt->hist2[0]);
+ memmove(ctxt->histcopy, ctxt->hist2, ctxt->nhist2*sizeof ctxt->hist2[0]);
+ ctxt->histcopy[ctxt->nhist2].line = -1;
+ }
+ return ctxt->histcopy;
+}
+
+typedef struct Hstack Hstack;
+struct Hstack
+{
+ Hist2 *h;
+ int delta;
+};
+
+// getline sets *f to the file number and *l to the line number
+// of the virtual line number line according to the history stack h.
+void
+linkgetline(Link *ctxt, Hist2 *h, int32 line, LSym **f, int32 *l)
+{
+ Hstack stk[100];
+ int nstk, start;
+ Hist2 *top, *h0;
+ static Hist2 *lasth;
+ static int32 laststart, lastend, lastdelta;
+ static LSym *lastfile;
+
+ h0 = h;
+ *f = 0;
+ *l = 0;
+ start = 0;
+ if(h == nil || line == 0) {
+ print("%s: getline: h=%p line=%d\n", ctxt->cursym->name, h, line);
+ return;
+ }
+
+ // Cache span used during last lookup, so that sequential
+ // translation of line numbers in compiled code is efficient.
+ if(!ctxt->debughist && lasth == h && laststart <= line && line < lastend) {
+ *f = lastfile;
+ *l = line - lastdelta;
+ return;
+ }
+
+ if(ctxt->debughist)
+ print("getline %d laststart=%d lastend=%d\n", line, laststart, lastend);
+
+ nstk = 0;
+ for(; h->line != -1; h++) {
+ if(ctxt->debughist)
+ print("\t%s %d %d\n", h->file ? h->file->name : "?", h->line, h->off);
+
+ if(h->line > line) {
+ if(nstk == 0)
+ sysfatal("history stack phase error: empty stack at line %d", (int)line);
+ top = stk[nstk-1].h;
+ lasth = h;
+ lastfile = top->file;
+ laststart = start;
+ lastend = h->line;
+ lastdelta = stk[nstk-1].delta;
+ *f = lastfile;
+ *l = line - lastdelta;
+ if(ctxt->debughist)
+ print("\tgot %d %d [%d %d %d]\n", *f, *l, laststart, lastend, lastdelta);
+ return;
+ }
+ if(h->file == nil) {
+ // pop included file
+ if(nstk == 0)
+ sysfatal("history stack phase error: stack underflow");
+ nstk--;
+ if(nstk > 0)
+ stk[nstk-1].delta += h->line - stk[nstk].h->line;
+ start = h->line;
+ } else if(h->off == 0) {
+ // push included file
+ if(nstk >= nelem(stk))
+ sysfatal("history stack phase error: stack overflow");
+ start = h->line;
+ stk[nstk].h = h;
+ stk[nstk].delta = h->line - 1;
+ nstk++;
+ } else {
+ // #line directive
+ if(nstk == 0)
+ sysfatal("history stack phase error: stack underflow");
+ stk[nstk-1].h = h;
+ stk[nstk-1].delta = h->line - h->off;
+ start = h->line;
+ }
+ if(ctxt->debughist)
+ print("\t\tnstk=%d delta=%d\n", nstk, stk[nstk].delta);
+ }
+
+ sysfatal("history stack phase error: cannot find line for %d", line);
+ nstk = 0;
+ for(h = h0; h->line != -1; h++) {
+ print("\t%d %d %s\n", h->line, h->off, h->file ? h->file->name : "");
+ if(h->file == nil)
+ nstk--;
+ else if(h->off == 0)
+ nstk++;
+ }
+}
+
+void
+addlib(Link *ctxt, char *src, char *obj)
+{
+ char name[1024], pname[1024], comp[256], *p;
+ int i, search;
+
+ if(ctxt->histfrogp <= 0)
+ return;
+
+ search = 0;
+ if(ctxt->histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else
+ if(isalpha((uchar)ctxt->histfrog[0]->name[1]) && ctxt->histfrog[0]->name[2] == ':') {
+ strcpy(name, ctxt->histfrog[0]->name+1);
+ i = 1;
+ } else
+ if(ctxt->histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ sprint(name, "");
+ i = 0;
+ search = 1;
+ }
+
+ for(; i<ctxt->histfrogp; i++) {
+ snprint(comp, sizeof comp, "%s", ctxt->histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = ctxt->thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(ctxt->thestring)-2+1 >= sizeof comp)
+ sysfatal("library component too long");
+ memmove(p+strlen(ctxt->thestring), p+2, strlen(p+2)+1);
+ memmove(p, ctxt->thestring, strlen(ctxt->thestring));
+ }
+ if(strlen(name) + strlen(comp) + 3 >= sizeof(name))
+ sysfatal("library component too long");
+ if(i > 0 || !search)
+ strcat(name, "/");
+ strcat(name, comp);
+ }
+ cleanname(name);
+
+ // runtime.a -> runtime
+ p = nil;
+ if(strlen(name) > 2 && name[strlen(name)-2] == '.') {
+ p = name+strlen(name)-2;
+ *p = '\0';
+ }
+
+ // already loaded?
+ for(i=0; i<ctxt->libraryp; i++)
+ if(strcmp(ctxt->library[i].pkg, name) == 0)
+ return;
+
+ // runtime -> runtime.a for search
+ if(p != nil)
+ *p = '.';
+
+ if(search) {
+ // try dot, -L "libdir", and then goroot.
+ for(i=0; i<ctxt->nlibdir; i++) {
+ snprint(pname, sizeof pname, "%s/%s", ctxt->libdir[i], name);
+ if(access(pname, AEXIST) >= 0)
+ break;
+ }
+ }else
+ strcpy(pname, name);
+ cleanname(pname);
+
+ /* runtime.a -> runtime */
+ if(p != nil)
+ *p = '\0';
+
+ if(ctxt->debugvlog > 1 && ctxt->bso)
+ Bprint(ctxt->bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
+
+ addlibpath(ctxt, src, obj, pname, name);
+}
+
+/*
+ * add library to library list.
+ * srcref: src file referring to package
+ * objref: object file referring to package
+ * file: object file, e.g., /home/rsc/go/pkg/container/vector.a
+ * pkg: package import path, e.g. container/vector
+ */
+void
+addlibpath(Link *ctxt, char *srcref, char *objref, char *file, char *pkg)
+{
+ int i;
+ Library *l;
+
+ for(i=0; i<ctxt->libraryp; i++)
+ if(strcmp(file, ctxt->library[i].file) == 0)
+ return;
+
+ if(ctxt->debugvlog > 1 && ctxt->bso)
+ Bprint(ctxt->bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
+ cputime(), srcref, objref, file, pkg);
+
+ if(ctxt->libraryp == ctxt->nlibrary){
+ ctxt->nlibrary = 50 + 2*ctxt->libraryp;
+ ctxt->library = erealloc(ctxt->library, sizeof ctxt->library[0] * ctxt->nlibrary);
+ }
+
+ l = &ctxt->library[ctxt->libraryp++];
+ l->objref = estrdup(objref);
+ l->srcref = estrdup(srcref);
+ l->file = estrdup(file);
+ l->pkg = estrdup(pkg);
+}
+
+int
+find1(int32 l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x04030201L, i+1);
+ if(i < 2)
+ inuxi2[i] = c;
+ if(i < 1)
+ inuxi1[i] = c;
+ inuxi4[i] = c;
+ if(c == i) {
+ inuxi8[i] = c;
+ inuxi8[i+4] = c+4;
+ } else {
+ inuxi8[i] = c+4;
+ inuxi8[i+4] = c;
+ }
+ fnuxi4[i] = c;
+ fnuxi8[i] = c;
+ fnuxi8[i+4] = c+4;
+ }
+}
+
+uchar fnuxi8[8];
+uchar fnuxi4[4];
+uchar inuxi1[1];
+uchar inuxi2[2];
+uchar inuxi4[4];
+uchar inuxi8[8];
+
+#define LOG 5
+void
+mkfwd(LSym *sym)
+{
+ Prog *p;
+ int i;
+ int32 dwn[LOG], cnt[LOG];
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1;
+ else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = nil;
+ }
+ i = 0;
+ for(p = sym->text; p != nil && p->link != nil; p = p->link) {
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = nil;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != nil)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+copyp(Link *ctxt, Prog *q)
+{
+ Prog *p;
+
+ p = ctxt->arch->prg();
+ *p = *q;
+ return p;
+}
+
+Prog*
+appendp(Link *ctxt, Prog *q)
+{
+ Prog *p;
+
+ p = ctxt->arch->prg();
+ p->link = q->link;
+ q->link = p;
+ p->lineno = q->lineno;
+ p->mode = q->mode;
+ return p;
+}
+
+vlong
+atolwhex(char *s)
+{
+ vlong n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
diff --git a/src/liblink/obj.c b/src/liblink/obj.c
new file mode 100644
index 000000000..eacbc4011
--- /dev/null
+++ b/src/liblink/obj.c
@@ -0,0 +1,403 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+enum
+{
+ HISTSZ = 10,
+ NSYM = 50,
+};
+
+int
+linklinefmt(Link *ctxt, Fmt *fp)
+{
+ struct
+ {
+ Hist* incl; /* start of this include file */
+ int32 idel; /* delta line number to apply to include */
+ Hist* line; /* start of this #line directive */
+ int32 ldel; /* delta line number to apply to #line */
+ } a[HISTSZ];
+ int32 lno, d;
+ int i, n;
+ Hist *h;
+
+ lno = va_arg(fp->args, int32);
+
+ n = 0;
+ for(h=ctxt->hist; h!=nil; h=h->link) {
+ if(h->offset < 0)
+ continue;
+ if(lno < h->line)
+ break;
+ if(h->name) {
+ if(h->offset > 0) {
+ // #line directive
+ if(n > 0 && n < HISTSZ) {
+ a[n-1].line = h;
+ a[n-1].ldel = h->line - h->offset + 1;
+ }
+ } else {
+ // beginning of file
+ if(n < HISTSZ) {
+ a[n].incl = h;
+ a[n].idel = h->line;
+ a[n].line = 0;
+ }
+ n++;
+ }
+ continue;
+ }
+ n--;
+ if(n > 0 && n < HISTSZ) {
+ d = h->line - a[n].incl->line;
+ a[n-1].ldel += d;
+ a[n-1].idel += d;
+ }
+ }
+
+ if(n > HISTSZ)
+ n = HISTSZ;
+
+ for(i=n-1; i>=0; i--) {
+ if(i != n-1) {
+ if(fp->flags & ~(FmtWidth|FmtPrec))
+ break;
+ fmtprint(fp, " ");
+ }
+ if(ctxt->debugline || (fp->flags&FmtLong))
+ fmtprint(fp, "%s/", ctxt->pathname);
+ if(a[i].line)
+ fmtprint(fp, "%s:%d[%s:%d]",
+ a[i].line->name, lno-a[i].ldel+1,
+ a[i].incl->name, lno-a[i].idel+1);
+ else
+ fmtprint(fp, "%s:%d",
+ a[i].incl->name, lno-a[i].idel+1);
+ lno = a[i].incl->line - 1; // now print out start of this file
+ }
+ if(n == 0)
+ fmtprint(fp, "<unknown line number>");
+
+ return 0;
+}
+
+static void
+outzfile(Link *ctxt, Biobuf *b, char *p)
+{
+ char *q, *q2;
+
+ while(p) {
+ q = utfrune(p, '/');
+ if(ctxt->windows) {
+ q2 = utfrune(p, '\\');
+ if(q2 && (!q || q2 < q))
+ q = q2;
+ }
+ if(!q) {
+ ctxt->arch->zfile(b, p, strlen(p));
+ return;
+ }
+ if(q > p)
+ ctxt->arch->zfile(b, p, q-p);
+ p = q + 1;
+ }
+}
+
+#define isdelim(c) (c == '/' || c == '\\')
+
+static void
+outwinname(Link *ctxt, Biobuf *b, Hist *h, char *ds, char *p)
+{
+ if(isdelim(p[0])) {
+ // full rooted name
+ ctxt->arch->zfile(b, ds, 3); // leading "c:/"
+ outzfile(ctxt, b, p+1);
+ } else {
+ // relative name
+ if(h->offset >= 0 && ctxt->pathname && ctxt->pathname[1] == ':') {
+ if(tolowerrune(ds[0]) == tolowerrune(ctxt->pathname[0])) {
+ // using current drive
+ ctxt->arch->zfile(b, ctxt->pathname, 3); // leading "c:/"
+ outzfile(ctxt, b, ctxt->pathname+3);
+ } else {
+ // using drive other then current,
+ // we don't have any simple way to
+ // determine current working directory
+ // there, therefore will output name as is
+ ctxt->arch->zfile(b, ds, 2); // leading "c:"
+ }
+ }
+ outzfile(ctxt, b, p);
+ }
+}
+
+void
+linkouthist(Link *ctxt, Biobuf *b)
+{
+ Hist *h;
+ char *p, ds[] = {'c', ':', '/', 0};
+ char *tofree;
+ int n;
+ static int first = 1;
+ static char *goroot, *goroot_final;
+
+ if(first) {
+ // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
+ first = 0;
+ goroot = getenv("GOROOT");
+ goroot_final = getenv("GOROOT_FINAL");
+ if(goroot == nil)
+ goroot = "";
+ if(goroot_final == nil)
+ goroot_final = goroot;
+ if(strcmp(goroot, goroot_final) == 0) {
+ goroot = nil;
+ goroot_final = nil;
+ }
+ }
+
+ tofree = nil;
+ for(h = ctxt->hist; h != nil; h = h->link) {
+ p = h->name;
+ if(p) {
+ if(goroot != nil) {
+ n = strlen(goroot);
+ if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
+ tofree = smprint("%s%s", goroot_final, p+n);
+ p = tofree;
+ }
+ }
+ if(ctxt->windows) {
+ // if windows variable is set, then, we know already,
+ // pathname is started with windows drive specifier
+ // and all '\' were replaced with '/' (see lex.c)
+ if(isdelim(p[0]) && isdelim(p[1])) {
+ // file name has network name in it,
+ // like \\server\share\dir\file.go
+ ctxt->arch->zfile(b, "//", 2); // leading "//"
+ outzfile(ctxt, b, p+2);
+ } else if(p[1] == ':') {
+ // file name has drive letter in it
+ ds[0] = p[0];
+ outwinname(ctxt, b, h, ds, p+2);
+ } else {
+ // no drive letter in file name
+ outwinname(ctxt, b, h, ctxt->pathname, p);
+ }
+ } else {
+ if(p[0] == '/') {
+ // full rooted name, like /home/rsc/dir/file.go
+ ctxt->arch->zfile(b, "/", 1); // leading "/"
+ outzfile(ctxt, b, p+1);
+ } else {
+ // relative name, like dir/file.go
+ if(h->offset >= 0 && ctxt->pathname && ctxt->pathname[0] == '/') {
+ ctxt->arch->zfile(b, "/", 1); // leading "/"
+ outzfile(ctxt, b, ctxt->pathname+1);
+ }
+ outzfile(ctxt, b, p);
+ }
+ }
+ }
+ ctxt->arch->zhist(b, h->line, h->offset);
+ if(tofree) {
+ free(tofree);
+ tofree = nil;
+ }
+ }
+}
+
+void
+linklinehist(Link *ctxt, int lineno, char *f, int offset)
+{
+ Hist *h;
+
+ if(0) // debug['f']
+ if(f) {
+ if(offset)
+ print("%4d: %s (#line %d)\n", lineno, f, offset);
+ else
+ print("%4d: %s\n", lineno, f);
+ } else
+ print("%4d: <pop>\n", lineno);
+
+ h = malloc(sizeof(Hist));
+ memset(h, 0, sizeof *h);
+ h->name = f;
+ h->line = lineno;
+ h->offset = offset;
+ h->link = nil;
+ if(ctxt->ehist == nil) {
+ ctxt->hist = h;
+ ctxt->ehist = h;
+ return;
+ }
+ ctxt->ehist->link = h;
+ ctxt->ehist = h;
+}
+
+void
+linkprfile(Link *ctxt, int32 l)
+{
+ int i, n;
+ Hist a[HISTSZ], *h;
+ int32 d;
+
+ n = 0;
+ for(h = ctxt->hist; h != nil; h = h->link) {
+ if(l < h->line)
+ break;
+ if(h->name) {
+ if(h->offset == 0) {
+ if(n >= 0 && n < HISTSZ)
+ a[n] = *h;
+ n++;
+ continue;
+ }
+ if(n > 0 && n < HISTSZ)
+ if(a[n-1].offset == 0) {
+ a[n] = *h;
+ n++;
+ } else
+ a[n-1] = *h;
+ continue;
+ }
+ n--;
+ if(n >= 0 && n < HISTSZ) {
+ d = h->line - a[n].line;
+ for(i=0; i<n; i++)
+ a[i].line += d;
+ }
+ }
+ if(n > HISTSZ)
+ n = HISTSZ;
+ for(i=0; i<n; i++)
+ print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+linknewplist(Link *ctxt)
+{
+ Plist *pl;
+
+ pl = malloc(sizeof(*pl));
+ memset(pl, 0, sizeof *pl);
+ if(ctxt->plist == nil)
+ ctxt->plist = pl;
+ else
+ ctxt->plast->link = pl;
+ ctxt->plast = pl;
+
+ return pl;
+}
+
+static struct {
+ struct { LSym *sym; short type; } h[NSYM];
+ int sym;
+} z;
+
+static void
+zsymreset(void)
+{
+ for(z.sym=0; z.sym<NSYM; z.sym++) {
+ z.h[z.sym].sym = nil;
+ z.h[z.sym].type = 0;
+ }
+ z.sym = 1;
+}
+
+
+static int
+zsym(Link *ctxt, Biobuf *b, LSym *s, int t, int *new)
+{
+ int i;
+
+ *new = 0;
+ if(s == nil)
+ return 0;
+
+ i = s->symid;
+ if(i < 0 || i >= NSYM)
+ i = 0;
+ if(z.h[i].type == t && z.h[i].sym == s)
+ return i;
+ i = z.sym;
+ s->symid = i;
+ ctxt->arch->zname(b, s, t);
+ z.h[i].sym = s;
+ z.h[i].type = t;
+ if(++z.sym >= NSYM)
+ z.sym = 1;
+ *new = 1;
+ return i;
+}
+
+static int
+zsymaddr(Link *ctxt, Biobuf *b, Addr *a, int *new)
+{
+ return zsym(ctxt, b, a->sym, ctxt->arch->symtype(a), new);
+}
+
+void
+linkwritefuncs(Link *ctxt, Biobuf *b)
+{
+ int32 pcloc;
+ Plist *pl;
+ LSym *s;
+ Prog *p;
+ int sf, st, gf, gt, new;
+
+ zsymreset();
+
+ // fix up pc
+ pcloc = 0;
+ for(pl=ctxt->plist; pl!=nil; pl=pl->link) {
+ if(pl->name != nil && strcmp(pl->name->name, "_") == 0)
+ continue;
+ for(p=pl->firstpc; p!=nil; p=p->link) {
+ p->loc = pcloc;
+ if(!ctxt->arch->isdata(p))
+ pcloc++;
+ }
+ }
+
+ // put out functions
+ for(pl=ctxt->plist; pl!=nil; pl=pl->link) {
+ if(pl->name != nil && strcmp(pl->name->name, "_") == 0)
+ continue;
+
+ // -S prints code; -S -S prints code and data
+ if(ctxt->debugasm && (pl->name || ctxt->debugasm>1)) {
+ s = pl->name;
+ print("\n--- prog list \"%lS\" ---\n", s);
+ for(p=pl->firstpc; p!=nil; p=p->link)
+ print("%P\n", p);
+ }
+
+ for(p=pl->firstpc; p!=nil; p=p->link) {
+ for(;;) {
+ sf = zsymaddr(ctxt, b, &p->from, &new);
+ gf = zsym(ctxt, b, p->from.gotype, ctxt->arch->D_EXTERN, &new);
+ if(new && sf == gf)
+ continue;
+ st = zsymaddr(ctxt, b, &p->to, &new);
+ if(new && (st == sf || st == gf))
+ continue;
+ gt = zsym(ctxt, b, p->to.gotype, ctxt->arch->D_EXTERN, &new);
+ if(new && (gt == sf || gt == gf || gt == st))
+ continue;
+ break;
+ }
+ ctxt->arch->zprog(ctxt, b, p, sf, gf, st, gt);
+ }
+ }
+}
diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c
new file mode 100644
index 000000000..e9c0b5731
--- /dev/null
+++ b/src/liblink/obj5.c
@@ -0,0 +1,1187 @@
+// Derived from Inferno utils/5c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/5l/5.out.h"
+#include "../pkg/runtime/stack.h"
+
+static Addr noaddr = {
+ .type = D_NONE,
+ .name = D_NONE,
+ .reg = NREG,
+};
+
+static Prog zprg = {
+ .as = AGOK,
+ .scond = 14,
+ .reg = NREG,
+ .from = {
+ .name = D_NONE,
+ .type = D_NONE,
+ .reg = NREG,
+ },
+ .to = {
+ .name = D_NONE,
+ .type = D_NONE,
+ .reg = NREG,
+ },
+};
+
+static void
+zname(Biobuf *b, LSym *s, int t)
+{
+ BPUTC(b, ANAME); /* as */
+ BPUTC(b, t); /* type */
+ BPUTC(b, s->symid); /* sym */
+ Bwrite(b, s->name, strlen(s->name)+1);
+}
+
+static void
+zfile(Biobuf *b, char *p, int n)
+{
+ BPUTC(b, ANAME);
+ BPUTC(b, D_FILE);
+ BPUTC(b, 1);
+ BPUTC(b, '<');
+ Bwrite(b, p, n);
+ BPUTC(b, 0);
+}
+
+static void
+zaddr(Biobuf *b, Addr *a, int s, int gotype)
+{
+ int32 l;
+ uint64 e;
+ int i;
+ char *n;
+
+ switch(a->type) {
+ case D_STATIC:
+ case D_AUTO:
+ case D_EXTERN:
+ case D_PARAM:
+ // TODO(kaib): remove once everything seems to work
+ sysfatal("We should no longer generate these as types");
+
+ default:
+ BPUTC(b, a->type);
+ BPUTC(b, a->reg);
+ BPUTC(b, s);
+ BPUTC(b, a->name);
+ BPUTC(b, gotype);
+ }
+
+ switch(a->type) {
+ default:
+ print("unknown type %d in zaddr\n", a->type);
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ break;
+
+ case D_CONST2:
+ l = a->offset2;
+ BPUTLE4(b, l); // fall through
+ case D_OREG:
+ case D_CONST:
+ case D_SHIFT:
+ case D_STATIC:
+ case D_AUTO:
+ case D_EXTERN:
+ case D_PARAM:
+ l = a->offset;
+ BPUTLE4(b, l);
+ break;
+
+ case D_BRANCH:
+ if(a->offset == 0 || a->u.branch != nil) {
+ if(a->u.branch == nil)
+ sysfatal("unpatched branch %D", a);
+ a->offset = a->u.branch->loc;
+ }
+ l = a->offset;
+ BPUTLE4(b, l);
+ break;
+
+ case D_SCONST:
+ n = a->u.sval;
+ for(i=0; i<NSNAME; i++) {
+ BPUTC(b, *n);
+ n++;
+ }
+ break;
+
+ case D_REGREG:
+ case D_REGREG2:
+ BPUTC(b, a->offset);
+ break;
+
+ case D_FCONST:
+ double2ieee(&e, a->u.dval);
+ BPUTLE4(b, e);
+ BPUTLE4(b, e >> 32);
+ break;
+ }
+}
+
+static void
+zhist(Biobuf *b, int line, vlong offset)
+{
+ Addr a;
+
+ BPUTC(b, AHISTORY);
+ BPUTC(b, C_SCOND_NONE);
+ BPUTC(b, NREG);
+ BPUTLE4(b, line);
+ zaddr(b, &noaddr, 0, 0);
+ a = noaddr;
+ if(offset != 0) {
+ a.offset = offset;
+ a.type = D_CONST;
+ }
+ zaddr(b, &a, 0, 0);
+}
+
+static int
+symtype(Addr *a)
+{
+ return a->name;
+}
+
+static void
+zprog(Link *ctxt, Biobuf *b, Prog *p, int sf, int gf, int st, int gt)
+{
+ USED(ctxt);
+
+ BPUTC(b, p->as);
+ BPUTC(b, p->scond);
+ BPUTC(b, p->reg);
+ BPUTLE4(b, p->lineno);
+ zaddr(b, &p->from, sf, gf);
+ zaddr(b, &p->to, st, gt);
+}
+
+static int
+isdata(Prog *p)
+{
+ return p->as == ADATA || p->as == AGLOBL;
+}
+
+static int
+iscall(Prog *p)
+{
+ return p->as == ABL;
+}
+
+static int
+datasize(Prog *p)
+{
+ return p->reg;
+}
+
+static int
+textflag(Prog *p)
+{
+ return p->reg;
+}
+
+static void
+settextflag(Prog *p, int f)
+{
+ p->reg = f;
+}
+
+static Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = emallocz(sizeof(*p));
+ *p = zprg;
+ return p;
+}
+
+static Prog* stacksplit(Link*, Prog*, int32);
+static void initdiv(Link*);
+static void softfloat(Link*, LSym*);
+
+// Prog.mark
+enum
+{
+ FOLL = 1<<0,
+ LABEL = 1<<1,
+ LEAF = 1<<2,
+};
+
+static void
+linkcase(Prog *casep)
+{
+ Prog *p;
+
+ for(p = casep; p != nil; p = p->link){
+ if(p->as == ABCASE) {
+ for(; p != nil && p->as == ABCASE; p = p->link)
+ p->pcrel = casep;
+ break;
+ }
+ }
+}
+
+static void
+nocache(Prog *p)
+{
+ p->optab = 0;
+ p->from.class = 0;
+ p->to.class = 0;
+}
+
+static void
+addstacksplit(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *pl, *q, *q1, *q2;
+ int o;
+ LSym *tlsfallback;
+ int32 autosize, autoffset;
+
+ autosize = 0;
+
+ if(ctxt->symmorestack[0] == nil)
+ ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
+
+ tlsfallback = linklookup(ctxt, "runtime.read_tls_fallback", 0);
+ ctxt->gmsym = nil;
+ if(ctxt->linkmode == LinkExternal)
+ ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
+ q = nil;
+
+ ctxt->cursym = cursym;
+
+ if(cursym->text == nil || cursym->text->link == nil)
+ return;
+
+ softfloat(ctxt, cursym);
+
+ if(ctxt->debugzerostack) {
+ p = cursym->text;
+ autoffset = p->to.offset;
+ if(autoffset < 0)
+ autoffset = 0;
+ if(autoffset && !(p->reg&NOSPLIT)) {
+ // MOVW $4(R13), R1
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = 13;
+ p->from.offset = 4;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ // MOVW $n(R13), R2
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = 13;
+ p->from.offset = 4 + autoffset;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ // MOVW $0, R3
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ // L:
+ // MOVW.nil R3, 0(R1) +4
+ // CMP R1, R2
+ // BNE L
+ p = pl = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_OREG;
+ p->to.reg = 1;
+ p->to.offset = 4;
+ p->scond |= C_PBIT;
+
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->reg = 2;
+
+ p = appendp(ctxt, p);
+ p->as = ABNE;
+ p->to.type = D_BRANCH;
+ p->pcond = pl;
+ }
+ }
+
+ /*
+ * find leaf subroutines
+ * strip NOPs
+ * expand RET
+ * expand BECOME pseudo
+ * fixup TLS
+ */
+
+ for(p = cursym->text; p != nil; p = p->link) {
+ switch(p->as) {
+ case ACASE:
+ if(ctxt->flag_shared)
+ linkcase(p);
+ break;
+
+ case ATEXT:
+ p->mark |= LEAF;
+ break;
+
+ case ARET:
+ break;
+
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+ q = p;
+ if(ctxt->sym_div == nil)
+ initdiv(ctxt);
+ cursym->text->mark &= ~LEAF;
+ continue;
+
+ case ANOP:
+ q1 = p->link;
+ q->link = q1; /* q is non-nop */
+ if(q1 != nil)
+ q1->mark |= p->mark;
+ continue;
+
+ case ABL:
+ case ABX:
+ cursym->text->mark &= ~LEAF;
+
+ case ABCASE:
+ case AB:
+
+ case ABEQ:
+ case ABNE:
+ case ABCS:
+ case ABHS:
+ case ABCC:
+ case ABLO:
+ case ABMI:
+ case ABPL:
+ case ABVS:
+ case ABVC:
+ case ABHI:
+ case ABLS:
+ case ABGE:
+ case ABLT:
+ case ABGT:
+ case ABLE:
+ q1 = p->pcond;
+ if(q1 != nil) {
+ while(q1->as == ANOP) {
+ q1 = q1->link;
+ p->pcond = q1;
+ }
+ }
+ break;
+ case AWORD:
+ // Rewrite TLS register fetch: MRC 15, 0, <reg>, C13, C0, 3
+ if((p->to.offset & 0xffff0fff) == 0xee1d0f70) {
+ if(ctxt->headtype == Hopenbsd) {
+ p->as = ARET;
+ } else if(ctxt->goarm < 7) {
+ if(tlsfallback->type != STEXT) {
+ ctxt->diag("runtime·read_tls_fallback not defined");
+ sysfatal("tlsfallback");
+ }
+ // BL runtime.read_tls_fallback(SB)
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->to.sym = tlsfallback;
+ p->pcond = tlsfallback->text;
+ p->to.offset = 0;
+ cursym->text->mark &= ~LEAF;
+ }
+ if(ctxt->linkmode == LinkExternal) {
+ // runtime.tlsgm is relocated with R_ARM_TLS_LE32
+ // and $runtime.tlsgm will contain the TLS offset.
+ //
+ // MOV $runtime.tlsgm+ctxt->tlsoffset(SB), REGTMP
+ // ADD REGTMP, <reg>
+ //
+ // In shared mode, runtime.tlsgm is relocated with
+ // R_ARM_TLS_IE32 and runtime.tlsgm(SB) will point
+ // to the GOT entry containing the TLS offset.
+ //
+ // MOV runtime.tlsgm(SB), REGTMP
+ // ADD REGTMP, <reg>
+ // SUB -ctxt->tlsoffset, <reg>
+ //
+ // The SUB compensates for ctxt->tlsoffset
+ // used in runtime.save_gm and runtime.load_gm.
+ q = p;
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->scond = 14;
+ p->reg = NREG;
+ if(ctxt->flag_shared) {
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ } else {
+ p->from.type = D_CONST;
+ p->from.offset = ctxt->tlsoffset;
+ }
+ p->from.sym = ctxt->gmsym;
+ p->from.name = D_EXTERN;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+ p->to.offset = 0;
+
+ p = appendp(ctxt, p);
+ p->as = AADD;
+ p->scond = 14;
+ p->reg = NREG;
+ p->from.type = D_REG;
+ p->from.reg = REGTMP;
+ p->to.type = D_REG;
+ p->to.reg = (q->to.offset & 0xf000) >> 12;
+ p->to.offset = 0;
+
+ if(ctxt->flag_shared) {
+ p = appendp(ctxt, p);
+ p->as = ASUB;
+ p->scond = 14;
+ p->reg = NREG;
+ p->from.type = D_CONST;
+ p->from.offset = -ctxt->tlsoffset;
+ p->to.type = D_REG;
+ p->to.reg = (q->to.offset & 0xf000) >> 12;
+ p->to.offset = 0;
+ }
+ }
+ }
+ }
+ q = p;
+ }
+
+ for(p = cursym->text; p != nil; p = p->link) {
+ o = p->as;
+ switch(o) {
+ case ATEXT:
+ autosize = p->to.offset + 4;
+ if(autosize <= 4)
+ if(cursym->text->mark & LEAF) {
+ p->to.offset = -4;
+ autosize = 0;
+ }
+
+ if(!autosize && !(cursym->text->mark & LEAF)) {
+ if(ctxt->debugvlog) {
+ Bprint(ctxt->bso, "save suppressed in: %s\n",
+ cursym->name);
+ Bflush(ctxt->bso);
+ }
+ cursym->text->mark |= LEAF;
+ }
+ if(cursym->text->mark & LEAF) {
+ cursym->leaf = 1;
+ if(!autosize)
+ break;
+ }
+
+ if(!(p->reg & NOSPLIT))
+ p = stacksplit(ctxt, p, autosize); // emit split check
+
+ // MOVW.W R14,$-autosize(SP)
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->scond |= C_WBIT;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_OREG;
+ p->to.offset = -autosize;
+ p->to.reg = REGSP;
+ p->spadj = autosize;
+
+ if(cursym->text->reg & WRAPPER) {
+ // g->panicwrap += autosize;
+ // MOVW panicwrap_offset(g), R3
+ // ADD $autosize, R3
+ // MOVW R3 panicwrap_offset(g)
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->from.offset = 2*ctxt->arch->ptrsize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ p = appendp(ctxt, p);
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_OREG;
+ p->to.reg = REGG;
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ }
+ break;
+
+ case ARET:
+ nocache(p);
+ if(cursym->text->mark & LEAF) {
+ if(!autosize) {
+ p->as = AB;
+ p->from = zprg.from;
+ if(p->to.sym) { // retjmp
+ p->to.type = D_BRANCH;
+ p->pcond = p->to.sym->text;
+ } else {
+ p->to.type = D_OREG;
+ p->to.offset = 0;
+ p->to.reg = REGLINK;
+ }
+ break;
+ }
+ }
+
+ if(cursym->text->reg & WRAPPER) {
+ int scond;
+
+ // Preserve original RET's cond, to allow RET.EQ
+ // in the implementation of reflect.call.
+ scond = p->scond;
+ p->scond = C_SCOND_NONE;
+
+ // g->panicwrap -= autosize;
+ // MOVW panicwrap_offset(g), R3
+ // SUB $autosize, R3
+ // MOVW R3 panicwrap_offset(g)
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->from.offset = 2*ctxt->arch->ptrsize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+ p = appendp(ctxt, p);
+
+ p->as = ASUB;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+ p = appendp(ctxt, p);
+
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_OREG;
+ p->to.reg = REGG;
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+
+ p->scond = scond;
+ }
+
+ p->as = AMOVW;
+ p->scond |= C_PBIT;
+ p->from.type = D_OREG;
+ p->from.offset = autosize;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = REGPC;
+ // If there are instructions following
+ // this ARET, they come from a branch
+ // with the same stackframe, so no spadj.
+
+ if(p->to.sym) { // retjmp
+ p->to.reg = REGLINK;
+ q2 = appendp(ctxt, p);
+ q2->as = AB;
+ q2->to.type = D_BRANCH;
+ q2->to.sym = p->to.sym;
+ q2->pcond = p->to.sym->text;
+ p->to.sym = nil;
+ p = q2;
+ }
+ break;
+
+ case AADD:
+ if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
+ p->spadj = -p->from.offset;
+ break;
+
+ case ASUB:
+ if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
+ p->spadj = p->from.offset;
+ break;
+
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+ if(ctxt->debugdivmod)
+ break;
+ if(p->from.type != D_REG)
+ break;
+ if(p->to.type != D_REG)
+ break;
+ q1 = p;
+
+ /* MOV a,4(SP) */
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->lineno = q1->lineno;
+ p->from.type = D_REG;
+ p->from.reg = q1->from.reg;
+ p->to.type = D_OREG;
+ p->to.reg = REGSP;
+ p->to.offset = 4;
+
+ /* MOV b,REGTMP */
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->lineno = q1->lineno;
+ p->from.type = D_REG;
+ p->from.reg = q1->reg;
+ if(q1->reg == NREG)
+ p->from.reg = q1->to.reg;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+ p->to.offset = 0;
+
+ /* CALL appropriate */
+ p = appendp(ctxt, p);
+ p->as = ABL;
+ p->lineno = q1->lineno;
+ p->to.type = D_BRANCH;
+ p->pcond = p;
+ switch(o) {
+ case ADIV:
+ p->to.sym = ctxt->sym_div;
+ break;
+ case ADIVU:
+ p->to.sym = ctxt->sym_divu;
+ break;
+ case AMOD:
+ p->to.sym = ctxt->sym_mod;
+ break;
+ case AMODU:
+ p->to.sym = ctxt->sym_modu;
+ break;
+ }
+
+ /* MOV REGTMP, b */
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->lineno = q1->lineno;
+ p->from.type = D_REG;
+ p->from.reg = REGTMP;
+ p->from.offset = 0;
+ p->to.type = D_REG;
+ p->to.reg = q1->to.reg;
+
+ /* ADD $8,SP */
+ p = appendp(ctxt, p);
+ p->as = AADD;
+ p->lineno = q1->lineno;
+ p->from.type = D_CONST;
+ p->from.reg = NREG;
+ p->from.offset = 8;
+ p->reg = NREG;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+ p->spadj = -8;
+
+ /* Keep saved LR at 0(SP) after SP change. */
+ /* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */
+ /* TODO: Remove SP adjustments; see issue 6699. */
+ q1->as = AMOVW;
+ q1->from.type = D_OREG;
+ q1->from.reg = REGSP;
+ q1->from.offset = 0;
+ q1->reg = NREG;
+ q1->to.type = D_REG;
+ q1->to.reg = REGTMP;
+
+ /* SUB $8,SP */
+ q1 = appendp(ctxt, q1);
+ q1->as = AMOVW;
+ q1->from.type = D_REG;
+ q1->from.reg = REGTMP;
+ q1->reg = NREG;
+ q1->to.type = D_OREG;
+ q1->to.reg = REGSP;
+ q1->to.offset = -8;
+ q1->scond |= C_WBIT;
+ q1->spadj = 8;
+
+ break;
+ case AMOVW:
+ if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
+ p->spadj = -p->to.offset;
+ if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
+ p->spadj = -p->from.offset;
+ if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
+ p->spadj = -p->from.offset;
+ break;
+ }
+ }
+}
+
+static void
+softfloat(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *next, *psfloat;
+ LSym *symsfloat;
+ int wasfloat;
+
+ if(!ctxt->debugfloat)
+ return;
+
+ symsfloat = linklookup(ctxt, "_sfloat", 0);
+ psfloat = nil;
+ if(symsfloat->type == STEXT)
+ psfloat = symsfloat->text;
+
+ wasfloat = 0;
+ for(p = cursym->text; p != nil; p = p->link)
+ if(p->pcond != nil)
+ p->pcond->mark |= LABEL;
+ for(p = cursym->text; p != nil; p = p->link) {
+ switch(p->as) {
+ case AMOVW:
+ if(p->to.type == D_FREG || p->from.type == D_FREG)
+ goto soft;
+ goto notsoft;
+
+ case AMOVWD:
+ case AMOVWF:
+ case AMOVDW:
+ case AMOVFW:
+ case AMOVFD:
+ case AMOVDF:
+ case AMOVF:
+ case AMOVD:
+
+ case ACMPF:
+ case ACMPD:
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ case ASQRTF:
+ case ASQRTD:
+ case AABSF:
+ case AABSD:
+ goto soft;
+
+ default:
+ goto notsoft;
+
+ soft:
+ if (psfloat == nil)
+ ctxt->diag("floats used with _sfloat not defined");
+ if (!wasfloat || (p->mark&LABEL)) {
+ next = ctxt->arch->prg();
+ *next = *p;
+
+ // BL _sfloat(SB)
+ *p = zprg;
+ p->link = next;
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->to.sym = symsfloat;
+ p->pcond = psfloat;
+ p->lineno = next->lineno;
+
+ p = next;
+ wasfloat = 1;
+ }
+ break;
+
+ notsoft:
+ wasfloat = 0;
+ }
+ }
+}
+
+static Prog*
+stacksplit(Link *ctxt, Prog *p, int32 framesize)
+{
+ int32 arg;
+
+ // MOVW g_stackguard(g), R1
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ if(framesize <= StackSmall) {
+ // small stack: SP < stackguard
+ // CMP stackguard, SP
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->reg = REGSP;
+ } else if(framesize <= StackBig) {
+ // large stack: SP-framesize < stackguard-StackSmall
+ // MOVW $-framesize(SP), R2
+ // CMP stackguard, R2
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = REGSP;
+ p->from.offset = -framesize;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->reg = 2;
+ } else {
+ // Such a large stack we need to protect against wraparound
+ // if SP is close to zero.
+ // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
+ // The +StackGuard on both sides is required to keep the left side positive:
+ // SP is allowed to be slightly below stackguard. See stack.h.
+ // CMP $StackPreempt, R1
+ // MOVW.NE $StackGuard(SP), R2
+ // SUB.NE R1, R2
+ // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
+ // CMP.NE R3, R2
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_CONST;
+ p->from.offset = (uint32)StackPreempt;
+ p->reg = 1;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = REGSP;
+ p->from.offset = StackGuard;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+ p->scond = C_SCOND_NE;
+
+ p = appendp(ctxt, p);
+ p->as = ASUB;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+ p->scond = C_SCOND_NE;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.offset = framesize + (StackGuard - StackSmall);
+ p->to.type = D_REG;
+ p->to.reg = 3;
+ p->scond = C_SCOND_NE;
+
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->reg = 2;
+ p->scond = C_SCOND_NE;
+ }
+
+ // MOVW.LS $framesize, R1
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LS;
+ p->from.type = D_CONST;
+ p->from.offset = framesize;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ // MOVW.LS $args, R2
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LS;
+ p->from.type = D_CONST;
+ arg = ctxt->cursym->text->to.offset2;
+ if(arg == 1) // special marker for known 0
+ arg = 0;
+ if(arg&3)
+ ctxt->diag("misaligned argument size in stack split");
+ p->from.offset = arg;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ // MOVW.LS R14, R3
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LS;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted
+ p = appendp(ctxt, p);
+ p->as = ABL;
+ p->scond = C_SCOND_LS;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[0];
+
+ // BLS start
+ p = appendp(ctxt, p);
+ p->as = ABLS;
+ p->to.type = D_BRANCH;
+ p->pcond = ctxt->cursym->text->link;
+
+ return p;
+}
+
+static void
+initdiv(Link *ctxt)
+{
+ if(ctxt->sym_div != nil)
+ return;
+ ctxt->sym_div = linklookup(ctxt, "_div", 0);
+ ctxt->sym_divu = linklookup(ctxt, "_divu", 0);
+ ctxt->sym_mod = linklookup(ctxt, "_mod", 0);
+ ctxt->sym_modu = linklookup(ctxt, "_modu", 0);
+}
+
+static void xfol(Link*, Prog*, Prog**);
+
+static void
+follow(Link *ctxt, LSym *s)
+{
+ Prog *firstp, *lastp;
+
+ ctxt->cursym = s;
+
+ firstp = ctxt->arch->prg();
+ lastp = firstp;
+ xfol(ctxt, s->text, &lastp);
+ lastp->link = nil;
+ s->text = firstp->link;
+}
+
+static int
+relinv(int a)
+{
+ switch(a) {
+ case ABEQ: return ABNE;
+ case ABNE: return ABEQ;
+ case ABCS: return ABCC;
+ case ABHS: return ABLO;
+ case ABCC: return ABCS;
+ case ABLO: return ABHS;
+ case ABMI: return ABPL;
+ case ABPL: return ABMI;
+ case ABVS: return ABVC;
+ case ABVC: return ABVS;
+ case ABHI: return ABLS;
+ case ABLS: return ABHI;
+ case ABGE: return ABLT;
+ case ABLT: return ABGE;
+ case ABGT: return ABLE;
+ case ABLE: return ABGT;
+ }
+ sysfatal("unknown relation: %s", anames5[a]);
+ return 0;
+}
+
+static void
+xfol(Link *ctxt, Prog *p, Prog **last)
+{
+ Prog *q, *r;
+ int a, i;
+
+loop:
+ if(p == nil)
+ return;
+ a = p->as;
+ if(a == AB) {
+ q = p->pcond;
+ if(q != nil && q->as != ATEXT) {
+ p->mark |= FOLL;
+ p = q;
+ if(!(p->mark & FOLL))
+ goto loop;
+ }
+ }
+ if(p->mark & FOLL) {
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == *last || q == nil)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF)
+ goto copy;
+ if(q->pcond == nil || (q->pcond->mark&FOLL))
+ continue;
+ if(a != ABEQ && a != ABNE)
+ continue;
+ copy:
+ for(;;) {
+ r = ctxt->arch->prg();
+ *r = *p;
+ if(!(r->mark&FOLL))
+ print("can't happen 1\n");
+ r->mark |= FOLL;
+ if(p != q) {
+ p = p->link;
+ (*last)->link = r;
+ *last = r;
+ continue;
+ }
+ (*last)->link = r;
+ *last = r;
+ if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF)
+ return;
+ r->as = ABNE;
+ if(a == ABNE)
+ r->as = ABEQ;
+ r->pcond = p->link;
+ r->link = p->pcond;
+ if(!(r->link->mark&FOLL))
+ xfol(ctxt, r->link, last);
+ if(!(r->pcond->mark&FOLL))
+ print("can't happen 2\n");
+ return;
+ }
+ }
+ a = AB;
+ q = ctxt->arch->prg();
+ q->as = a;
+ q->lineno = p->lineno;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+ p->mark |= FOLL;
+ (*last)->link = p;
+ *last = p;
+ if(a == AB || (a == ARET && p->scond == 14) || a == ARFE || a == AUNDEF){
+ return;
+ }
+ if(p->pcond != nil)
+ if(a != ABL && a != ABX && p->link != nil) {
+ q = brchain(ctxt, p->link);
+ if(a != ATEXT && a != ABCASE)
+ if(q != nil && (q->mark&FOLL)) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ xfol(ctxt, p->link, last);
+ q = brchain(ctxt, p->pcond);
+ if(q == nil)
+ q = p->pcond;
+ if(q->mark&FOLL) {
+ p->pcond = q;
+ return;
+ }
+ p = q;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+LinkArch linkarm = {
+ .name = "arm",
+
+ .addstacksplit = addstacksplit,
+ .assemble = span5,
+ .datasize = datasize,
+ .follow = follow,
+ .iscall = iscall,
+ .isdata = isdata,
+ .ldobj = ldobj5,
+ .nopout = nopout5,
+ .prg = prg,
+ .settextflag = settextflag,
+ .symtype = symtype,
+ .textflag = textflag,
+ .zfile = zfile,
+ .zhist = zhist,
+ .zname = zname,
+ .zprog = zprog,
+
+ .minlc = 4,
+ .ptrsize = 4,
+
+ .D_ADDR = D_ADDR,
+ .D_BRANCH = D_BRANCH,
+ .D_CONST = D_CONST,
+ .D_EXTERN = D_EXTERN,
+ .D_FCONST = D_FCONST,
+ .D_NONE = D_NONE,
+ .D_PCREL = D_PCREL,
+ .D_SCONST = D_SCONST,
+ .D_SIZE = D_SIZE,
+
+ .ACALL = ABL,
+ .AFUNCDATA = AFUNCDATA,
+ .AJMP = AB,
+ .ANOP = ANOP,
+ .APCDATA = APCDATA,
+ .ARET = ARET,
+ .ATEXT = ATEXT,
+ .AUSEFIELD = AUSEFIELD,
+};
diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c
new file mode 100644
index 000000000..bd24d1d9e
--- /dev/null
+++ b/src/liblink/obj6.c
@@ -0,0 +1,1078 @@
+// Inferno utils/6l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/6l/6.out.h"
+#include "../pkg/runtime/stack.h"
+
+static Addr noaddr = {
+ .type = D_NONE,
+ .index = D_NONE,
+ .scale = 0,
+};
+
+static Prog zprg = {
+ .back = 2,
+ .as = AGOK,
+ .from = {
+ .type = D_NONE,
+ .index = D_NONE,
+ },
+ .to = {
+ .type = D_NONE,
+ .index = D_NONE,
+ },
+};
+
+static void
+zname(Biobuf *b, LSym *s, int t)
+{
+ BPUTLE2(b, ANAME); /* as */
+ BPUTC(b, t); /* type */
+ BPUTC(b, s->symid); /* sym */
+ Bwrite(b, s->name, strlen(s->name)+1);
+}
+
+static void
+zfile(Biobuf *b, char *p, int n)
+{
+ BPUTLE2(b, ANAME);
+ BPUTC(b, D_FILE);
+ BPUTC(b, 1);
+ BPUTC(b, '<');
+ Bwrite(b, p, n);
+ BPUTC(b, 0);
+}
+
+static void
+zaddr(Biobuf *b, Addr *a, int s, int gotype)
+{
+ int32 l;
+ uint64 e;
+ int i, t;
+ char *n;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(s != 0)
+ t |= T_SYM;
+ if(gotype != 0)
+ t |= T_GOTYPE;
+
+ switch(a->type) {
+
+ case D_BRANCH:
+ if(a->offset == 0 || a->u.branch != nil) {
+ if(a->u.branch == nil)
+ sysfatal("unpatched branch %D", a);
+ a->offset = a->u.branch->loc;
+ }
+
+ default:
+ t |= T_TYPE;
+
+ case D_NONE:
+ if(a->offset != 0) {
+ t |= T_OFFSET;
+ l = a->offset;
+ if((vlong)l != a->offset)
+ t |= T_64;
+ }
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ }
+ BPUTC(b, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ BPUTC(b, a->index);
+ BPUTC(b, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ BPUTLE4(b, l);
+ if(t & T_64) {
+ l = a->offset>>32;
+ BPUTLE4(b, l);
+ }
+ }
+ if(t & T_SYM) /* implies sym */
+ BPUTC(b, s);
+ if(t & T_FCONST) {
+ double2ieee(&e, a->u.dval);
+ BPUTLE4(b, e);
+ BPUTLE4(b, e >> 32);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->u.sval;
+ for(i=0; i<NSNAME; i++) {
+ BPUTC(b, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ BPUTC(b, a->type);
+ if(t & T_GOTYPE)
+ BPUTC(b, gotype);
+}
+
+static void
+zhist(Biobuf *b, int line, vlong offset)
+{
+ Addr a;
+
+ BPUTLE2(b, AHISTORY);
+ BPUTLE4(b, line);
+ zaddr(b, &noaddr, 0, 0);
+ a = noaddr;
+ if(offset != 0) {
+ a.offset = offset;
+ a.type = D_CONST;
+ }
+ zaddr(b, &a, 0, 0);
+}
+
+static int
+symtype(Addr *a)
+{
+ int t;
+
+ t = a->type;
+ if(t == D_ADDR)
+ t = a->index;
+ return t;
+}
+
+static void
+zprog(Link *ctxt, Biobuf *b, Prog *p, int sf, int gf, int st, int gt)
+{
+ USED(ctxt);
+
+ BPUTLE2(b, p->as);
+ BPUTLE4(b, p->lineno);
+ zaddr(b, &p->from, sf, gf);
+ zaddr(b, &p->to, st, gt);
+}
+
+static int
+isdata(Prog *p)
+{
+ return p->as == ADATA || p->as == AGLOBL;
+}
+
+static int
+iscall(Prog *p)
+{
+ return p->as == ACALL;
+}
+
+static int
+datasize(Prog *p)
+{
+ return p->from.scale;
+}
+
+static int
+textflag(Prog *p)
+{
+ return p->from.scale;
+}
+
+static void
+settextflag(Prog *p, int f)
+{
+ p->from.scale = f;
+}
+
+static void
+progedit(Link *ctxt, Prog *p)
+{
+ Prog *q;
+ LSym *gmsym;
+
+ gmsym = nil; // TODO
+
+ if(ctxt->headtype == Hwindows) {
+ // Windows
+ // Convert
+ // op n(GS), reg
+ // to
+ // MOVL 0x28(GS), reg
+ // op n(reg), reg
+ // The purpose of this patch is to fix some accesses
+ // to extern register variables (TLS) on Windows, as
+ // a different method is used to access them.
+ if(p->from.type == D_INDIR+D_GS
+ && p->to.type >= D_AX && p->to.type <= D_DI
+ && p->from.offset <= 8) {
+ q = appendp(ctxt, p);
+ q->from = p->from;
+ q->from.type = D_INDIR + p->to.type;
+ q->to = p->to;
+ q->as = p->as;
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0x28;
+ }
+ }
+ if(ctxt->headtype == Hlinux || ctxt->headtype == Hfreebsd
+ || ctxt->headtype == Hopenbsd || ctxt->headtype == Hnetbsd
+ || ctxt->headtype == Hplan9 || ctxt->headtype == Hdragonfly) {
+ // ELF uses FS instead of GS.
+ if(p->from.type == D_INDIR+D_GS)
+ p->from.type = D_INDIR+D_FS;
+ if(p->to.type == D_INDIR+D_GS)
+ p->to.type = D_INDIR+D_FS;
+ if(p->from.index == D_GS)
+ p->from.index = D_FS;
+ if(p->to.index == D_GS)
+ p->to.index = D_FS;
+ }
+ if(!ctxt->flag_shared) {
+ // Convert g() or m() accesses of the form
+ // op n(reg)(GS*1), reg
+ // to
+ // op n(GS*1), reg
+ if(p->from.index == D_FS || p->from.index == D_GS) {
+ p->from.type = D_INDIR + p->from.index;
+ p->from.index = D_NONE;
+ }
+ // Convert g() or m() accesses of the form
+ // op reg, n(reg)(GS*1)
+ // to
+ // op reg, n(GS*1)
+ if(p->to.index == D_FS || p->to.index == D_GS) {
+ p->to.type = D_INDIR + p->to.index;
+ p->to.index = D_NONE;
+ }
+ // Convert get_tls access of the form
+ // op runtime.tlsgm(SB), reg
+ // to
+ // NOP
+ if(gmsym != nil && p->from.sym == gmsym) {
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+ p->from.sym = nil;
+ p->to.sym = nil;
+ return;
+ }
+ } else {
+ /*
+ // Convert TLS reads of the form
+ // op n(GS), reg
+ // to
+ // MOVQ $runtime.tlsgm(SB), reg
+ // op n(reg)(GS*1), reg
+ if((p->from.type == D_INDIR+D_FS || p->from.type == D_INDIR + D_GS) && p->to.type >= D_AX && p->to.type <= D_DI) {
+ q = appendp(ctxt, p);
+ q->to = p->to;
+ q->as = p->as;
+ q->from.type = D_INDIR+p->to.type;
+ q->from.index = p->from.type - D_INDIR;
+ q->from.scale = 1;
+ q->from.offset = p->from.offset;
+ p->as = AMOVQ;
+ p->from.type = D_EXTERN;
+ p->from.sym = gmsym;
+ p->from.offset = 0;
+ }
+ */
+ }
+}
+
+static char*
+morename[] =
+{
+ "runtime.morestack00",
+ "runtime.morestack10",
+ "runtime.morestack01",
+ "runtime.morestack11",
+
+ "runtime.morestack8",
+ "runtime.morestack16",
+ "runtime.morestack24",
+ "runtime.morestack32",
+ "runtime.morestack40",
+ "runtime.morestack48",
+};
+
+static Prog* load_g_cx(Link*, Prog*);
+static Prog* stacksplit(Link*, Prog*, int32, int32, Prog**);
+
+static void
+parsetextconst(vlong arg, vlong *textstksiz, vlong *textarg)
+{
+ *textstksiz = arg & 0xffffffffLL;
+ if(*textstksiz & 0x80000000LL)
+ *textstksiz = -(-*textstksiz & 0xffffffffLL);
+
+ *textarg = (arg >> 32) & 0xffffffffLL;
+ if(*textarg & 0x80000000LL)
+ *textarg = 0;
+ *textarg = (*textarg+7) & ~7LL;
+}
+
+static void
+addstacksplit(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *q, *q1;
+ int32 autoffset, deltasp;
+ int a, pcsize;
+ uint32 i;
+ vlong textstksiz, textarg;
+
+ if(ctxt->gmsym == nil) {
+ ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
+ if(nelem(morename) > nelem(ctxt->symmorestack))
+ sysfatal("Link.symmorestack needs at least %d elements", nelem(morename));
+ for(i=0; i<nelem(morename); i++)
+ ctxt->symmorestack[i] = linklookup(ctxt, morename[i], 0);
+ }
+ ctxt->cursym = cursym;
+
+ if(cursym->text == nil || cursym->text->link == nil)
+ return;
+
+ p = cursym->text;
+ parsetextconst(p->to.offset, &textstksiz, &textarg);
+ autoffset = textstksiz;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) {
+ for(q = p; q != nil; q = q->link)
+ if(q->as == ACALL)
+ goto noleaf;
+ p->from.scale |= NOSPLIT;
+ noleaf:;
+ }
+
+ if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
+ ctxt->diag("nosplit func likely to overflow stack");
+
+ q = nil;
+ if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
+ p = appendp(ctxt, p);
+ p = load_g_cx(ctxt, p); // load g into CX
+ }
+ if(!(cursym->text->from.scale & NOSPLIT))
+ p = stacksplit(ctxt, p, autoffset, textarg, &q); // emit split check
+
+ if(autoffset) {
+ p = appendp(ctxt, p);
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset;
+ p->spadj = autoffset;
+ } else {
+ // zero-byte stack adjustment.
+ // Insert a fake non-zero adjustment so that stkcheck can
+ // recognize the end of the stack-splitting prolog.
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ p->spadj = -ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ p->spadj = ctxt->arch->ptrsize;
+ }
+ if(q != nil)
+ q->pcond = p;
+ deltasp = autoffset;
+
+ if(cursym->text->from.scale & WRAPPER) {
+ // g->panicwrap += autoffset + ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+ p->as = AADDL;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset + ctxt->arch->ptrsize;
+ p->to.type = D_INDIR+D_CX;
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ }
+
+ if(ctxt->debugstack > 1 && autoffset) {
+ // 6l -K -K means double-check for stack overflow
+ // even after calling morestack and even if the
+ // function is marked as nosplit.
+ p = appendp(ctxt, p);
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_BX;
+
+ p = appendp(ctxt, p);
+ p->as = ASUBQ;
+ p->from.type = D_CONST;
+ p->from.offset = StackSmall+32;
+ p->to.type = D_BX;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPQ;
+ p->from.type = D_SP;
+ p->to.type = D_BX;
+
+ p = appendp(ctxt, p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ q1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ q1->pcond = p;
+ }
+
+ if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
+ // 6l -Z means zero the stack frame on entry.
+ // This slows down function calls but can help avoid
+ // false positives in garbage collection.
+ p = appendp(ctxt, p);
+ p->as = AMOVQ;
+ p->from.type = D_SP;
+ p->to.type = D_DI;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVQ;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset/8;
+ p->to.type = D_CX;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVQ;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = AREP;
+
+ p = appendp(ctxt, p);
+ p->as = ASTOSQ;
+ }
+
+ for(; p != nil; p = p->link) {
+ pcsize = p->mode/8;
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + pcsize;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + pcsize;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ p->spadj = 4;
+ continue;
+ case APUSHQ:
+ case APUSHFQ:
+ deltasp += 8;
+ p->spadj = 8;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ p->spadj = 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ p->spadj = -4;
+ continue;
+ case APOPQ:
+ case APOPFQ:
+ deltasp -= 8;
+ p->spadj = -8;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ p->spadj = -2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ ctxt->diag("unbalanced PUSH/POP");
+
+ if(cursym->text->from.scale & WRAPPER) {
+ p = load_g_cx(ctxt, p);
+ p = appendp(ctxt, p);
+ // g->panicwrap -= autoffset + ctxt->arch->ptrsize;
+ p->as = ASUBL;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset + ctxt->arch->ptrsize;
+ p->to.type = D_INDIR+D_CX;
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+ p->as = ARET;
+ }
+
+ if(autoffset) {
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = -autoffset;
+ p->spadj = -autoffset;
+ p = appendp(ctxt, p);
+ p->as = ARET;
+ // If there are instructions following
+ // this ARET, they come from a branch
+ // with the same stackframe, so undo
+ // the cleanup.
+ p->spadj = +autoffset;
+ }
+ if(p->to.sym) // retjmp
+ p->as = AJMP;
+ }
+}
+
+// Append code to p to load g into cx.
+// Overwrites p with the first instruction (no first appendp).
+// Overwriting p is unusual but it lets use this in both the
+// prologue (caller must call appendp first) and in the epilogue.
+// Returns last new instruction.
+static Prog*
+load_g_cx(Link *ctxt, Prog *p)
+{
+ if(ctxt->flag_shared) {
+ // Load TLS offset with MOVQ $runtime.tlsgm(SB), CX
+ p->as = AMOVQ;
+ p->from.type = D_EXTERN;
+ p->from.sym = ctxt->gmsym;
+ p->to.type = D_CX;
+ p = appendp(ctxt, p);
+ }
+ p->as = AMOVQ;
+ if(ctxt->headtype == Hlinux || ctxt->headtype == Hfreebsd
+ || ctxt->headtype == Hopenbsd || ctxt->headtype == Hnetbsd
+ || ctxt->headtype == Hplan9 || ctxt->headtype == Hdragonfly)
+ // ELF uses FS
+ p->from.type = D_INDIR+D_FS;
+ else
+ p->from.type = D_INDIR+D_GS;
+ if(ctxt->flag_shared) {
+ // Add TLS offset stored in CX
+ p->from.index = p->from.type - D_INDIR;
+ p->from.type = D_INDIR + D_CX;
+ }
+ p->from.offset = ctxt->tlsoffset+0;
+ p->to.type = D_CX;
+ if(ctxt->headtype == Hwindows) {
+ // movq %gs:0x28, %rcx
+ // movq (%rcx), %rcx
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0x28;
+ p->to.type = D_CX;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_CX;
+ }
+ return p;
+}
+
+// Append code to p to check for stack split.
+// Appends to (does not overwrite) p.
+// Assumes g is in CX.
+// Returns last new instruction.
+// On return, *jmpok is the instruction that should jump
+// to the stack frame allocation if no split is needed.
+static Prog*
+stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, Prog **jmpok)
+{
+ Prog *q, *q1;
+ uint32 moreconst1, moreconst2, i;
+
+ if(ctxt->debugstack) {
+ // 6l -K means check not only for stack
+ // overflow but stack underflow.
+ // On underflow, INT 3 (breakpoint).
+ // Underflow itself is rare but this also
+ // catches out-of-sync stack guard info
+
+ p = appendp(ctxt, p);
+ p->as = ACMPQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 8;
+ p->to.type = D_SP;
+
+ p = appendp(ctxt, p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ q1->pcond = p;
+ }
+
+ q = nil;
+ q1 = nil;
+ if(framesize <= StackSmall) {
+ // small stack: SP <= stackguard
+ // CMPQ SP, stackguard
+ p = appendp(ctxt, p);
+ p->as = ACMPQ;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_CX;
+ } else if(framesize <= StackBig) {
+ // large stack: SP-framesize <= stackguard-StackSmall
+ // LEAQ -xxx(SP), AX
+ // CMPQ AX, stackguard
+ p = appendp(ctxt, p);
+ p->as = ALEAQ;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = -(framesize-StackSmall);
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPQ;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_CX;
+ } else {
+ // Such a large stack we need to protect against wraparound.
+ // If SP is close to zero:
+ // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
+ // The +StackGuard on both sides is required to keep the left side positive:
+ // SP is allowed to be slightly below stackguard. See stack.h.
+ //
+ // Preemption sets stackguard to StackPreempt, a very large value.
+ // That breaks the math above, so we have to check for that explicitly.
+ // MOVQ stackguard, CX
+ // CMPQ CX, $StackPreempt
+ // JEQ label-of-call-to-morestack
+ // LEAQ StackGuard(SP), AX
+ // SUBQ CX, AX
+ // CMPQ AX, $(framesize+(StackGuard-StackSmall))
+
+ p = appendp(ctxt, p);
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_SI;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPQ;
+ p->from.type = D_SI;
+ p->to.type = D_CONST;
+ p->to.offset = StackPreempt;
+
+ p = appendp(ctxt, p);
+ p->as = AJEQ;
+ p->to.type = D_BRANCH;
+ q1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = ALEAQ;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = StackGuard;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ASUBQ;
+ p->from.type = D_SI;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPQ;
+ p->from.type = D_AX;
+ p->to.type = D_CONST;
+ p->to.offset = framesize+(StackGuard-StackSmall);
+ }
+
+ // common
+ p = appendp(ctxt, p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ q = p;
+
+ // If we ask for more stack, we'll get a minimum of StackMin bytes.
+ // We need a stack frame large enough to hold the top-of-stack data,
+ // the function arguments+results, our caller's PC, our frame,
+ // a word for the return PC of the next call, and then the StackLimit bytes
+ // that must be available on entry to any function called from a function
+ // that did a stack check. If StackMin is enough, don't ask for a specific
+ // amount: then we can use the custom functions and save a few
+ // instructions.
+ moreconst1 = 0;
+ if(StackTop + textarg + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin)
+ moreconst1 = framesize;
+ moreconst2 = textarg;
+ if(moreconst2 == 1) // special marker
+ moreconst2 = 0;
+ if((moreconst2&7) != 0)
+ ctxt->diag("misaligned argument size in stack split");
+ // 4 varieties varieties (const1==0 cross const2==0)
+ // and 6 subvarieties of (const1==0 and const2!=0)
+ p = appendp(ctxt, p);
+ if(moreconst1 == 0 && moreconst2 == 0) {
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[0];
+ } else
+ if(moreconst1 != 0 && moreconst2 == 0) {
+ p->as = AMOVL;
+ p->from.type = D_CONST;
+ p->from.offset = moreconst1;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[1];
+ } else
+ if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
+ i = moreconst2/8 + 3;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[i];
+ } else
+ if(moreconst1 == 0 && moreconst2 != 0) {
+ p->as = AMOVL;
+ p->from.type = D_CONST;
+ p->from.offset = moreconst2;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[2];
+ } else {
+ p->as = AMOVQ;
+ p->from.type = D_CONST;
+ p->from.offset = (uint64)moreconst2 << 32;
+ p->from.offset |= moreconst1;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[3];
+ }
+
+ p = appendp(ctxt, p);
+ p->as = AJMP;
+ p->to.type = D_BRANCH;
+ p->pcond = ctxt->cursym->text->link;
+
+ if(q != nil)
+ q->pcond = p->link;
+ if(q1 != nil)
+ q1->pcond = q->link;
+
+ *jmpok = q;
+ return p;
+}
+
+static void xfol(Link*, Prog*, Prog**);
+
+static void
+follow(Link *ctxt, LSym *s)
+{
+ Prog *firstp, *lastp;
+
+ ctxt->cursym = s;
+
+ firstp = ctxt->arch->prg();
+ lastp = firstp;
+ xfol(ctxt, s->text, &lastp);
+ lastp->link = nil;
+ s->text = firstp->link;
+}
+
+static int
+nofollow(int a)
+{
+ switch(a) {
+ case AJMP:
+ case ARET:
+ case AIRETL:
+ case AIRETQ:
+ case AIRETW:
+ case ARETFL:
+ case ARETFQ:
+ case ARETFW:
+ case AUNDEF:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+pushpop(int a)
+{
+ switch(a) {
+ case APUSHL:
+ case APUSHFL:
+ case APUSHQ:
+ case APUSHFQ:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPQ:
+ case APOPFQ:
+ case APOPW:
+ case APOPFW:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+relinv(int a)
+{
+ switch(a) {
+ case AJEQ: return AJNE;
+ case AJNE: return AJEQ;
+ case AJLE: return AJGT;
+ case AJLS: return AJHI;
+ case AJLT: return AJGE;
+ case AJMI: return AJPL;
+ case AJGE: return AJLT;
+ case AJPL: return AJMI;
+ case AJGT: return AJLE;
+ case AJHI: return AJLS;
+ case AJCS: return AJCC;
+ case AJCC: return AJCS;
+ case AJPS: return AJPC;
+ case AJPC: return AJPS;
+ case AJOS: return AJOC;
+ case AJOC: return AJOS;
+ }
+ sysfatal("unknown relation: %s", anames6[a]);
+ return 0;
+}
+
+static void
+xfol(Link *ctxt, Prog *p, Prog **last)
+{
+ Prog *q;
+ int i;
+ enum as a;
+
+loop:
+ if(p == nil)
+ return;
+ if(p->as == AJMP)
+ if((q = p->pcond) != nil && q->as != ATEXT) {
+ /* mark instruction as done and continue layout at target of jump */
+ p->mark = 1;
+ p = q;
+ if(p->mark == 0)
+ goto loop;
+ }
+ if(p->mark) {
+ /*
+ * p goes here, but already used it elsewhere.
+ * copy up to 4 instructions or else branch to other copy.
+ */
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == nil)
+ break;
+ if(q == *last)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(nofollow(a) || pushpop(a))
+ break; // NOTE(rsc): arm does goto copy
+ if(q->pcond == nil || q->pcond->mark)
+ continue;
+ if(a == ACALL || a == ALOOP)
+ continue;
+ for(;;) {
+ if(p->as == ANOP) {
+ p = p->link;
+ continue;
+ }
+ q = copyp(ctxt, p);
+ p = p->link;
+ q->mark = 1;
+ (*last)->link = q;
+ *last = q;
+ if(q->as != a || q->pcond == nil || q->pcond->mark)
+ continue;
+
+ q->as = relinv(q->as);
+ p = q->pcond;
+ q->pcond = q->link;
+ q->link = p;
+ xfol(ctxt, q->link, last);
+ p = q->link;
+ if(p->mark)
+ return;
+ goto loop;
+ }
+ } /* */
+ q = ctxt->arch->prg();
+ q->as = AJMP;
+ q->lineno = p->lineno;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+
+ /* emit p */
+ p->mark = 1;
+ (*last)->link = p;
+ *last = p;
+ a = p->as;
+
+ /* continue loop with what comes after p */
+ if(nofollow(a))
+ return;
+ if(p->pcond != nil && a != ACALL) {
+ /*
+ * some kind of conditional branch.
+ * recurse to follow one path.
+ * continue loop on the other.
+ */
+ if((q = brchain(ctxt, p->pcond)) != nil)
+ p->pcond = q;
+ if((q = brchain(ctxt, p->link)) != nil)
+ p->link = q;
+ if(p->from.type == D_CONST) {
+ if(p->from.offset == 1) {
+ /*
+ * expect conditional jump to be taken.
+ * rewrite so that's the fall-through case.
+ */
+ p->as = relinv(a);
+ q = p->link;
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ } else {
+ q = p->link;
+ if(q->mark)
+ if(a != ALOOP) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ }
+ xfol(ctxt, p->link, last);
+ if(p->pcond->mark)
+ return;
+ p = p->pcond;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+static Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = emallocz(sizeof(*p));
+ *p = zprg;
+ return p;
+}
+
+LinkArch linkamd64 = {
+ .name = "amd64",
+
+ .zprog = zprog,
+ .zhist = zhist,
+ .zfile = zfile,
+ .zname = zname,
+ .isdata = isdata,
+ .ldobj = ldobj6,
+ .nopout = nopout6,
+ .symtype = symtype,
+ .iscall = iscall,
+ .datasize = datasize,
+ .textflag = textflag,
+ .settextflag = settextflag,
+ .progedit = progedit,
+ .prg = prg,
+ .addstacksplit = addstacksplit,
+ .assemble = span6,
+ .follow = follow,
+
+ .minlc = 1,
+ .ptrsize = 8,
+
+ .D_ADDR = D_ADDR,
+ .D_BRANCH = D_BRANCH,
+ .D_CONST = D_CONST,
+ .D_EXTERN = D_EXTERN,
+ .D_FCONST = D_FCONST,
+ .D_NONE = D_NONE,
+ .D_PCREL = D_PCREL,
+ .D_SCONST = D_SCONST,
+ .D_SIZE = D_SIZE,
+
+ .ACALL = ACALL,
+ .AFUNCDATA = AFUNCDATA,
+ .AJMP = AJMP,
+ .ANOP = ANOP,
+ .APCDATA = APCDATA,
+ .ARET = ARET,
+ .ATEXT = ATEXT,
+ .AUSEFIELD = AUSEFIELD,
+};
diff --git a/src/liblink/obj8.c b/src/liblink/obj8.c
new file mode 100644
index 000000000..e744abe55
--- /dev/null
+++ b/src/liblink/obj8.c
@@ -0,0 +1,937 @@
+// Inferno utils/8l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/8l/8.out.h"
+#include "../pkg/runtime/stack.h"
+
+static Addr noaddr = {
+ .type = D_NONE,
+ .index = D_NONE,
+ .scale = 1,
+};
+
+static Prog zprg = {
+ .back = 2,
+ .as = AGOK,
+ .from = {
+ .type = D_NONE,
+ .index = D_NONE,
+ .scale = 1,
+ },
+ .to = {
+ .type = D_NONE,
+ .index = D_NONE,
+ .scale = 1,
+ },
+};
+
+static void
+zname(Biobuf *b, LSym *s, int t)
+{
+ BPUTLE2(b, ANAME); /* as */
+ BPUTC(b, t); /* type */
+ BPUTC(b, s->symid); /* sym */
+ Bwrite(b, s->name, strlen(s->name)+1);
+}
+
+static void
+zfile(Biobuf *b, char *p, int n)
+{
+ BPUTLE2(b, ANAME);
+ BPUTC(b, D_FILE);
+ BPUTC(b, 1);
+ BPUTC(b, '<');
+ Bwrite(b, p, n);
+ BPUTC(b, 0);
+}
+
+static void
+zaddr(Biobuf *b, Addr *a, int s, int gotype)
+{
+ int32 l;
+ uint64 e;
+ int i, t;
+ char *n;
+
+ t = 0;
+ if(a->index != D_NONE || a->scale != 0)
+ t |= T_INDEX;
+ if(s != 0)
+ t |= T_SYM;
+ if(gotype != 0)
+ t |= T_GOTYPE;
+
+ switch(a->type) {
+
+ case D_BRANCH:
+ if(a->offset == 0 || a->u.branch != nil) {
+ if(a->u.branch == nil)
+ sysfatal("unpatched branch %D", a);
+ a->offset = a->u.branch->loc;
+ }
+
+ default:
+ t |= T_TYPE;
+
+ case D_NONE:
+ if(a->offset != 0)
+ t |= T_OFFSET;
+ if(a->offset2 != 0)
+ t |= T_OFFSET2;
+ break;
+ case D_FCONST:
+ t |= T_FCONST;
+ break;
+ case D_SCONST:
+ t |= T_SCONST;
+ break;
+ }
+ BPUTC(b, t);
+
+ if(t & T_INDEX) { /* implies index, scale */
+ BPUTC(b, a->index);
+ BPUTC(b, a->scale);
+ }
+ if(t & T_OFFSET) { /* implies offset */
+ l = a->offset;
+ BPUTLE4(b, l);
+ }
+ if(t & T_OFFSET2) { /* implies offset */
+ l = a->offset2;
+ BPUTLE4(b, l);
+ }
+ if(t & T_SYM) /* implies sym */
+ BPUTC(b, s);
+ if(t & T_FCONST) {
+ double2ieee(&e, a->u.dval);
+ BPUTLE4(b, e);
+ BPUTLE4(b, e >> 32);
+ return;
+ }
+ if(t & T_SCONST) {
+ n = a->u.sval;
+ for(i=0; i<NSNAME; i++) {
+ BPUTC(b, *n);
+ n++;
+ }
+ return;
+ }
+ if(t & T_TYPE)
+ BPUTC(b, a->type);
+ if(t & T_GOTYPE)
+ BPUTC(b, gotype);
+}
+
+static void
+zhist(Biobuf *b, int line, vlong offset)
+{
+ Addr a;
+
+ BPUTLE2(b, AHISTORY);
+ BPUTLE4(b, line);
+ zaddr(b, &noaddr, 0, 0);
+ a = noaddr;
+ if(offset != 0) {
+ a.offset = offset;
+ a.type = D_CONST;
+ }
+ zaddr(b, &a, 0, 0);
+}
+
+static int
+symtype(Addr *a)
+{
+ int t;
+
+ t = a->type;
+ if(t == D_ADDR)
+ t = a->index;
+ return t;
+}
+
+static void
+zprog(Link *ctxt, Biobuf *b, Prog *p, int sf, int gf, int st, int gt)
+{
+ USED(ctxt);
+
+ BPUTLE2(b, p->as);
+ BPUTLE4(b, p->lineno);
+ zaddr(b, &p->from, sf, gf);
+ zaddr(b, &p->to, st, gt);
+}
+
+static int
+isdata(Prog *p)
+{
+ return p->as == ADATA || p->as == AGLOBL;
+}
+
+static int
+iscall(Prog *p)
+{
+ return p->as == ACALL;
+}
+
+static int
+datasize(Prog *p)
+{
+ return p->from.scale;
+}
+
+static int
+textflag(Prog *p)
+{
+ return p->from.scale;
+}
+
+static void
+settextflag(Prog *p, int f)
+{
+ p->from.scale = f;
+}
+
+static void
+progedit(Link *ctxt, Prog *p)
+{
+ Prog *q;
+
+ if(ctxt->headtype == Hwindows) {
+ // Convert
+ // op n(GS), reg
+ // to
+ // MOVL 0x14(FS), reg
+ // op n(reg), reg
+ // The purpose of this patch is to fix some accesses
+ // to extern register variables (TLS) on Windows, as
+ // a different method is used to access them.
+ if(p->from.type == D_INDIR+D_GS
+ && p->to.type >= D_AX && p->to.type <= D_DI) {
+ q = appendp(ctxt, p);
+ q->from = p->from;
+ q->from.type = D_INDIR + p->to.type;
+ q->to = p->to;
+ q->as = p->as;
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_FS;
+ p->from.offset = 0x14;
+ }
+ }
+ if(ctxt->headtype == Hlinux) {
+ // Running binaries under Xen requires using
+ // MOVL 0(GS), reg
+ // and then off(reg) instead of saying off(GS) directly
+ // when the offset is negative.
+ // In external mode we just produce a reloc.
+ if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
+ && p->to.type >= D_AX && p->to.type <= D_DI) {
+ if(ctxt->linkmode != LinkExternal) {
+ q = appendp(ctxt, p);
+ q->from = p->from;
+ q->from.type = D_INDIR + p->to.type;
+ q->to = p->to;
+ q->as = p->as;
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0;
+ } else {
+ // Add signals to relocate.
+ p->from.index = D_GS;
+ p->from.scale = 1;
+ }
+ }
+ }
+ /* TODO
+ if(ctxt->headtype == Hplan9) {
+ if(p->from.type == D_INDIR+D_GS
+ && p->to.type >= D_AX && p->to.type <= D_DI) {
+ q = appendp(ctxt, p);
+ q->from = p->from;
+ q->from.type = D_INDIR + p->to.type;
+ q->to = p->to;
+ q->as = p->as;
+ p->as = AMOVL;
+ p->from.type = D_EXTERN;
+ p->from.sym = plan9_tos;
+ p->from.offset = 0;
+ }
+ }
+ */
+}
+
+static Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = emallocz(sizeof(*p));
+ *p = zprg;
+ return p;
+}
+
+static Prog* load_g_cx(Link*, Prog*);
+static Prog* stacksplit(Link*, Prog*, int32, Prog**);
+
+static void
+addstacksplit(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *q;
+ int32 autoffset, deltasp;
+ int a;
+
+ if(ctxt->symmorestack[0] == nil)
+ ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
+
+ if(ctxt->headtype == Hplan9 && ctxt->plan9tos == nil)
+ ctxt->plan9tos = linklookup(ctxt, "_tos", 0);
+
+ ctxt->cursym = cursym;
+
+ if(cursym->text == nil || cursym->text->link == nil)
+ return;
+
+ p = cursym->text;
+ autoffset = p->to.offset;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ q = nil;
+
+ if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
+ p = appendp(ctxt, p);
+ p = load_g_cx(ctxt, p); // load g into CX
+ }
+ if(!(cursym->text->from.scale & NOSPLIT))
+ p = stacksplit(ctxt, p, autoffset, &q); // emit split check
+
+ if(autoffset) {
+ p = appendp(ctxt, p);
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset;
+ p->spadj = autoffset;
+ } else {
+ // zero-byte stack adjustment.
+ // Insert a fake non-zero adjustment so that stkcheck can
+ // recognize the end of the stack-splitting prolog.
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ p->spadj = -ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ p->spadj = ctxt->arch->ptrsize;
+ }
+ if(q != nil)
+ q->pcond = p;
+ deltasp = autoffset;
+
+ if(cursym->text->from.scale & WRAPPER) {
+ // g->panicwrap += autoffset + ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+ p->as = AADDL;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset + ctxt->arch->ptrsize;
+ p->to.type = D_INDIR+D_CX;
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ }
+
+ if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
+ // 8l -Z means zero the stack frame on entry.
+ // This slows down function calls but can help avoid
+ // false positives in garbage collection.
+ p = appendp(ctxt, p);
+ p->as = AMOVL;
+ p->from.type = D_SP;
+ p->to.type = D_DI;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVL;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset/4;
+ p->to.type = D_CX;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVL;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = AREP;
+
+ p = appendp(ctxt, p);
+ p->as = ASTOSL;
+ }
+
+ for(; p != nil; p = p->link) {
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + 4;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + 4;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ p->spadj = 4;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ p->spadj = 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ p->spadj = -4;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ p->spadj = -2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ ctxt->diag("unbalanced PUSH/POP");
+
+ if(cursym->text->from.scale & WRAPPER) {
+ p = load_g_cx(ctxt, p);
+ p = appendp(ctxt, p);
+ // g->panicwrap -= autoffset + ctxt->arch->ptrsize;
+ p->as = ASUBL;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset + ctxt->arch->ptrsize;
+ p->to.type = D_INDIR+D_CX;
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+ p->as = ARET;
+ }
+
+ if(autoffset) {
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = -autoffset;
+ p->spadj = -autoffset;
+ p = appendp(ctxt, p);
+ p->as = ARET;
+ // If there are instructions following
+ // this ARET, they come from a branch
+ // with the same stackframe, so undo
+ // the cleanup.
+ p->spadj = +autoffset;
+ }
+ if(p->to.sym) // retjmp
+ p->as = AJMP;
+ }
+}
+
+// Append code to p to load g into cx.
+// Overwrites p with the first instruction (no first appendp).
+// Overwriting p is unusual but it lets use this in both the
+// prologue (caller must call appendp first) and in the epilogue.
+// Returns last new instruction.
+static Prog*
+load_g_cx(Link *ctxt, Prog *p)
+{
+ switch(ctxt->headtype) {
+ case Hwindows:
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_FS;
+ p->from.offset = 0x14;
+ p->to.type = D_CX;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_CX;
+ break;
+
+ case Hlinux:
+ if(ctxt->linkmode != LinkExternal) {
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0;
+ p->to.type = D_CX;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = ctxt->tlsoffset + 0;
+ p->to.type = D_CX;
+ } else {
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = ctxt->tlsoffset + 0;
+ p->to.type = D_CX;
+ p->from.index = D_GS;
+ p->from.scale = 1;
+ }
+ break;
+
+ case Hplan9:
+ p->as = AMOVL;
+ p->from.type = D_EXTERN;
+ p->from.sym = ctxt->plan9tos;
+ p->to.type = D_CX;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = ctxt->tlsoffset + 0;
+ p->to.type = D_CX;
+ break;
+
+ default:
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = ctxt->tlsoffset + 0;
+ p->to.type = D_CX;
+ }
+ return p;
+}
+
+// Append code to p to check for stack split.
+// Appends to (does not overwrite) p.
+// Assumes g is in CX.
+// Returns last new instruction.
+// On return, *jmpok is the instruction that should jump
+// to the stack frame allocation if no split is needed.
+static Prog*
+stacksplit(Link *ctxt, Prog *p, int32 framesize, Prog **jmpok)
+{
+ Prog *q, *q1;
+ int arg;
+
+ if(ctxt->debugstack) {
+ // 8l -K means check not only for stack
+ // overflow but stack underflow.
+ // On underflow, INT 3 (breakpoint).
+ // Underflow itself is rare but this also
+ // catches out-of-sync stack guard info.
+ p = appendp(ctxt, p);
+ p->as = ACMPL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 4;
+ p->to.type = D_SP;
+
+ p = appendp(ctxt, p);
+ p->as = AJCC;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ q1->pcond = p;
+ }
+ q1 = nil;
+
+ if(framesize <= StackSmall) {
+ // small stack: SP <= stackguard
+ // CMPL SP, stackguard
+ p = appendp(ctxt, p);
+ p->as = ACMPL;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_CX;
+ } else if(framesize <= StackBig) {
+ // large stack: SP-framesize <= stackguard-StackSmall
+ // LEAL -(framesize-StackSmall)(SP), AX
+ // CMPL AX, stackguard
+ p = appendp(ctxt, p);
+ p->as = ALEAL;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = -(framesize-StackSmall);
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPL;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_CX;
+ } else {
+ // Such a large stack we need to protect against wraparound
+ // if SP is close to zero.
+ // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
+ // The +StackGuard on both sides is required to keep the left side positive:
+ // SP is allowed to be slightly below stackguard. See stack.h.
+ //
+ // Preemption sets stackguard to StackPreempt, a very large value.
+ // That breaks the math above, so we have to check for that explicitly.
+ // MOVL stackguard, CX
+ // CMPL CX, $StackPreempt
+ // JEQ label-of-call-to-morestack
+ // LEAL StackGuard(SP), AX
+ // SUBL stackguard, AX
+ // CMPL AX, $(framesize+(StackGuard-StackSmall))
+ p = appendp(ctxt, p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_SI;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPL;
+ p->from.type = D_SI;
+ p->to.type = D_CONST;
+ p->to.offset = (uint32)StackPreempt;
+
+ p = appendp(ctxt, p);
+ p->as = AJEQ;
+ p->to.type = D_BRANCH;
+ q1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = ALEAL;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = StackGuard;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ASUBL;
+ p->from.type = D_SI;
+ p->from.offset = 0;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPL;
+ p->from.type = D_AX;
+ p->to.type = D_CONST;
+ p->to.offset = framesize+(StackGuard-StackSmall);
+ }
+
+ // common
+ p = appendp(ctxt, p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q = p;
+
+ p = appendp(ctxt, p); // save frame size in DI
+ p->as = AMOVL;
+ p->to.type = D_DI;
+ p->from.type = D_CONST;
+
+ // If we ask for more stack, we'll get a minimum of StackMin bytes.
+ // We need a stack frame large enough to hold the top-of-stack data,
+ // the function arguments+results, our caller's PC, our frame,
+ // a word for the return PC of the next call, and then the StackLimit bytes
+ // that must be available on entry to any function called from a function
+ // that did a stack check. If StackMin is enough, don't ask for a specific
+ // amount: then we can use the custom functions and save a few
+ // instructions.
+ if(StackTop + ctxt->cursym->text->to.offset2 + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin)
+ p->from.offset = (framesize+7) & ~7LL;
+
+ arg = ctxt->cursym->text->to.offset2;
+ if(arg == 1) // special marker for known 0
+ arg = 0;
+ if(arg&3)
+ ctxt->diag("misaligned argument size in stack split");
+ p = appendp(ctxt, p); // save arg size in AX
+ p->as = AMOVL;
+ p->to.type = D_AX;
+ p->from.type = D_CONST;
+ p->from.offset = arg;
+
+ p = appendp(ctxt, p);
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[0];
+
+ p = appendp(ctxt, p);
+ p->as = AJMP;
+ p->to.type = D_BRANCH;
+ p->pcond = ctxt->cursym->text->link;
+
+ if(q != nil)
+ q->pcond = p->link;
+ if(q1 != nil)
+ q1->pcond = q->link;
+
+ *jmpok = q;
+ return p;
+}
+
+static void xfol(Link*, Prog*, Prog**);
+
+static void
+follow(Link *ctxt, LSym *s)
+{
+ Prog *firstp, *lastp;
+
+ ctxt->cursym = s;
+
+ firstp = ctxt->arch->prg();
+ lastp = firstp;
+ xfol(ctxt, s->text, &lastp);
+ lastp->link = nil;
+ s->text = firstp->link;
+}
+
+static int
+nofollow(int a)
+{
+ switch(a) {
+ case AJMP:
+ case ARET:
+ case AIRETL:
+ case AIRETW:
+ case AUNDEF:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+pushpop(int a)
+{
+ switch(a) {
+ case APUSHL:
+ case APUSHFL:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPW:
+ case APOPFW:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+relinv(int a)
+{
+
+ switch(a) {
+ case AJEQ: return AJNE;
+ case AJNE: return AJEQ;
+ case AJLE: return AJGT;
+ case AJLS: return AJHI;
+ case AJLT: return AJGE;
+ case AJMI: return AJPL;
+ case AJGE: return AJLT;
+ case AJPL: return AJMI;
+ case AJGT: return AJLE;
+ case AJHI: return AJLS;
+ case AJCS: return AJCC;
+ case AJCC: return AJCS;
+ case AJPS: return AJPC;
+ case AJPC: return AJPS;
+ case AJOS: return AJOC;
+ case AJOC: return AJOS;
+ }
+ sysfatal("unknown relation: %s", anames8[a]);
+ return 0;
+}
+
+static void
+xfol(Link *ctxt, Prog *p, Prog **last)
+{
+ Prog *q;
+ int i;
+ enum as a;
+
+loop:
+ if(p == nil)
+ return;
+ if(p->as == AJMP)
+ if((q = p->pcond) != nil && q->as != ATEXT) {
+ /* mark instruction as done and continue layout at target of jump */
+ p->mark = 1;
+ p = q;
+ if(p->mark == 0)
+ goto loop;
+ }
+ if(p->mark) {
+ /*
+ * p goes here, but already used it elsewhere.
+ * copy up to 4 instructions or else branch to other copy.
+ */
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == nil)
+ break;
+ if(q == *last)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(nofollow(a) || pushpop(a))
+ break; // NOTE(rsc): arm does goto copy
+ if(q->pcond == nil || q->pcond->mark)
+ continue;
+ if(a == ACALL || a == ALOOP)
+ continue;
+ for(;;) {
+ if(p->as == ANOP) {
+ p = p->link;
+ continue;
+ }
+ q = copyp(ctxt, p);
+ p = p->link;
+ q->mark = 1;
+ (*last)->link = q;
+ *last = q;
+ if(q->as != a || q->pcond == nil || q->pcond->mark)
+ continue;
+
+ q->as = relinv(q->as);
+ p = q->pcond;
+ q->pcond = q->link;
+ q->link = p;
+ xfol(ctxt, q->link, last);
+ p = q->link;
+ if(p->mark)
+ return;
+ goto loop;
+ }
+ } /* */
+ q = ctxt->arch->prg();
+ q->as = AJMP;
+ q->lineno = p->lineno;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+
+ /* emit p */
+ p->mark = 1;
+ (*last)->link = p;
+ *last = p;
+ a = p->as;
+
+ /* continue loop with what comes after p */
+ if(nofollow(a))
+ return;
+ if(p->pcond != nil && a != ACALL) {
+ /*
+ * some kind of conditional branch.
+ * recurse to follow one path.
+ * continue loop on the other.
+ */
+ if((q = brchain(ctxt, p->pcond)) != nil)
+ p->pcond = q;
+ if((q = brchain(ctxt, p->link)) != nil)
+ p->link = q;
+ if(p->from.type == D_CONST) {
+ if(p->from.offset == 1) {
+ /*
+ * expect conditional jump to be taken.
+ * rewrite so that's the fall-through case.
+ */
+ p->as = relinv(a);
+ q = p->link;
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ } else {
+ q = p->link;
+ if(q->mark)
+ if(a != ALOOP) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ }
+ xfol(ctxt, p->link, last);
+ if(p->pcond->mark)
+ return;
+ p = p->pcond;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+LinkArch link386 = {
+ .name = "386",
+
+ .addstacksplit = addstacksplit,
+ .assemble = span8,
+ .datasize = datasize,
+ .follow = follow,
+ .iscall = iscall,
+ .isdata = isdata,
+ .ldobj = ldobj8,
+ .nopout = nopout8,
+ .prg = prg,
+ .progedit = progedit,
+ .settextflag = settextflag,
+ .symtype = symtype,
+ .textflag = textflag,
+ .zfile = zfile,
+ .zhist = zhist,
+ .zname = zname,
+ .zprog = zprog,
+
+ .minlc = 1,
+ .ptrsize = 4,
+
+ .D_ADDR = D_ADDR,
+ .D_BRANCH = D_BRANCH,
+ .D_CONST = D_CONST,
+ .D_EXTERN = D_EXTERN,
+ .D_FCONST = D_FCONST,
+ .D_NONE = D_NONE,
+ .D_PCREL = D_PCREL,
+ .D_SCONST = D_SCONST,
+ .D_SIZE = D_SIZE,
+
+ .ACALL = ACALL,
+ .AFUNCDATA = AFUNCDATA,
+ .AJMP = AJMP,
+ .ANOP = ANOP,
+ .APCDATA = APCDATA,
+ .ARET = ARET,
+ .ATEXT = ATEXT,
+ .AUSEFIELD = AUSEFIELD,
+};
diff --git a/src/liblink/pass.c b/src/liblink/pass.c
new file mode 100644
index 000000000..3fe77d61b
--- /dev/null
+++ b/src/liblink/pass.c
@@ -0,0 +1,115 @@
+// Inferno utils/6l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Code and data passes.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+Prog*
+brchain(Link *ctxt, Prog *p)
+{
+ int i;
+
+ for(i=0; i<20; i++) {
+ if(p == nil || p->as != ctxt->arch->AJMP)
+ return p;
+ p = p->pcond;
+ }
+ return nil;
+}
+
+Prog*
+brloop(Link *ctxt, Prog *p)
+{
+ int c;
+ Prog *q;
+
+ c = 0;
+ for(q = p; q != nil; q = q->pcond) {
+ if(q->as != ctxt->arch->AJMP)
+ break;
+ c++;
+ if(c >= 5000)
+ return nil;
+ }
+ return q;
+}
+
+void
+linkpatch(Link *ctxt, LSym *sym)
+{
+ int32 c;
+ Prog *p, *q;
+ LSym *s;
+
+ ctxt->cursym = sym;
+
+ for(p = sym->text; p != nil; p = p->link) {
+ if(ctxt->arch->progedit)
+ ctxt->arch->progedit(ctxt, p);
+ if(p->as == ctxt->arch->ACALL || (p->as == ctxt->arch->AJMP && p->to.type != ctxt->arch->D_BRANCH) || (p->as == ctxt->arch->ARET && p->to.sym != nil)) {
+ s = p->to.sym;
+ if(s) {
+ p->to.type = ctxt->arch->D_BRANCH;
+ continue;
+ }
+ }
+ if(p->to.type != ctxt->arch->D_BRANCH)
+ continue;
+ c = p->to.offset;
+ for(q = sym->text; q != nil;) {
+ if(c == q->pc)
+ break;
+ if(q->forwd != nil && c >= q->forwd->pc)
+ q = q->forwd;
+ else
+ q = q->link;
+ }
+ if(q == nil) {
+ ctxt->diag("branch out of range (%#ux)\n%P [%s]",
+ c, p, p->to.sym ? p->to.sym->name : "<nil>");
+ p->to.type = ctxt->arch->D_NONE;
+ }
+ p->pcond = q;
+ }
+
+ for(p = sym->text; p != nil; p = p->link) {
+ p->mark = 0; /* initialization for follow */
+ if(p->pcond != nil) {
+ p->pcond = brloop(ctxt, p->pcond);
+ if(p->pcond != nil)
+ if(p->to.type == ctxt->arch->D_BRANCH)
+ p->to.offset = p->pcond->pc;
+ }
+ }
+}
diff --git a/src/liblink/pcln.c b/src/liblink/pcln.c
new file mode 100644
index 000000000..21eb94414
--- /dev/null
+++ b/src/liblink/pcln.c
@@ -0,0 +1,298 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+static void
+addvarint(Link *ctxt, Pcdata *d, uint32 val)
+{
+ int32 n;
+ uint32 v;
+ uchar *p;
+
+ USED(ctxt);
+
+ n = 0;
+ for(v = val; v >= 0x80; v >>= 7)
+ n++;
+ n++;
+
+ if(d->n + n > d->m) {
+ d->m = (d->n + n)*2;
+ d->p = erealloc(d->p, d->m);
+ }
+
+ p = d->p + d->n;
+ for(v = val; v >= 0x80; v >>= 7)
+ *p++ = v | 0x80;
+ *p++ = v;
+ d->n += n;
+}
+
+// funcpctab writes to dst a pc-value table mapping the code in func to the values
+// returned by valfunc parameterized by arg. The invocation of valfunc to update the
+// current value is, for each p,
+//
+// val = valfunc(func, val, p, 0, arg);
+// record val as value at p->pc;
+// val = valfunc(func, val, p, 1, arg);
+//
+// where func is the function, val is the current value, p is the instruction being
+// considered, and arg can be used to further parameterize valfunc.
+static void
+funcpctab(Link *ctxt, Pcdata *dst, LSym *func, char *desc, int32 (*valfunc)(Link*, LSym*, int32, Prog*, int32, void*), void* arg)
+{
+ int dbg, i;
+ int32 oldval, val, started;
+ uint32 delta;
+ vlong pc;
+ Prog *p;
+
+ // To debug a specific function, uncomment second line and change name.
+ dbg = 0;
+ //dbg = strcmp(func->name, "main.main") == 0;
+ //dbg = strcmp(desc, "pctofile") == 0;
+
+ ctxt->debugpcln += dbg;
+
+ dst->n = 0;
+
+ if(ctxt->debugpcln)
+ Bprint(ctxt->bso, "funcpctab %s [valfunc=%s]\n", func->name, desc);
+
+ val = -1;
+ oldval = val;
+ if(func->text == nil)
+ return;
+
+ pc = func->text->pc;
+
+ if(ctxt->debugpcln)
+ Bprint(ctxt->bso, "%6llux %6d %P\n", pc, val, func->text);
+
+ started = 0;
+ for(p=func->text; p != nil; p = p->link) {
+ // Update val. If it's not changing, keep going.
+ val = valfunc(ctxt, func, val, p, 0, arg);
+ if(val == oldval && started) {
+ val = valfunc(ctxt, func, val, p, 1, arg);
+ if(ctxt->debugpcln)
+ Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
+ continue;
+ }
+
+ // If the pc of the next instruction is the same as the
+ // pc of this instruction, this instruction is not a real
+ // instruction. Keep going, so that we only emit a delta
+ // for a true instruction boundary in the program.
+ if(p->link && p->link->pc == p->pc) {
+ val = valfunc(ctxt, func, val, p, 1, arg);
+ if(ctxt->debugpcln)
+ Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
+ continue;
+ }
+
+ // The table is a sequence of (value, pc) pairs, where each
+ // pair states that the given value is in effect from the current position
+ // up to the given pc, which becomes the new current position.
+ // To generate the table as we scan over the program instructions,
+ // we emit a "(value" when pc == func->value, and then
+ // each time we observe a change in value we emit ", pc) (value".
+ // When the scan is over, we emit the closing ", pc)".
+ //
+ // The table is delta-encoded. The value deltas are signed and
+ // transmitted in zig-zag form, where a complement bit is placed in bit 0,
+ // and the pc deltas are unsigned. Both kinds of deltas are sent
+ // as variable-length little-endian base-128 integers,
+ // where the 0x80 bit indicates that the integer continues.
+
+ if(ctxt->debugpcln)
+ Bprint(ctxt->bso, "%6llux %6d %P\n", (vlong)p->pc, val, p);
+
+ if(started) {
+ addvarint(ctxt, dst, (p->pc - pc) / ctxt->arch->minlc);
+ pc = p->pc;
+ }
+ delta = val - oldval;
+ if(delta>>31)
+ delta = 1 | ~(delta<<1);
+ else
+ delta <<= 1;
+ addvarint(ctxt, dst, delta);
+ oldval = val;
+ started = 1;
+ val = valfunc(ctxt, func, val, p, 1, arg);
+ }
+
+ if(started) {
+ if(ctxt->debugpcln)
+ Bprint(ctxt->bso, "%6llux done\n", (vlong)func->text->pc+func->size);
+ addvarint(ctxt, dst, (func->value+func->size - pc) / ctxt->arch->minlc);
+ addvarint(ctxt, dst, 0); // terminator
+ }
+
+ if(ctxt->debugpcln) {
+ Bprint(ctxt->bso, "wrote %d bytes to %p\n", dst->n, dst);
+ for(i=0; i<dst->n; i++)
+ Bprint(ctxt->bso, " %02ux", dst->p[i]);
+ Bprint(ctxt->bso, "\n");
+ }
+
+ ctxt->debugpcln -= dbg;
+}
+
+// pctofileline computes either the file number (arg == 0)
+// or the line number (arg == 1) to use at p.
+// Because p->lineno applies to p, phase == 0 (before p)
+// takes care of the update.
+static int32
+pctofileline(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
+{
+ int32 i, l;
+ LSym *f;
+ Pcln *pcln;
+
+ if(p->as == ctxt->arch->ATEXT || p->as == ctxt->arch->ANOP || p->as == ctxt->arch->AUSEFIELD || p->lineno == 0 || phase == 1)
+ return oldval;
+ linkgetline(ctxt, sym->hist, p->lineno, &f, &l);
+ if(f == nil) {
+ // print("getline failed for %s %P\n", ctxt->cursym->name, p);
+ return oldval;
+ }
+ if(arg == nil)
+ return l;
+ pcln = arg;
+
+ if(f == pcln->lastfile)
+ return pcln->lastindex;
+
+ for(i=0; i<pcln->nfile; i++) {
+ if(pcln->file[i] == f) {
+ pcln->lastfile = f;
+ pcln->lastindex = i;
+ return i;
+ }
+ }
+
+ if(pcln->nfile >= pcln->mfile) {
+ pcln->mfile = (pcln->nfile+1)*2;
+ pcln->file = erealloc(pcln->file, pcln->mfile*sizeof pcln->file[0]);
+ }
+ pcln->file[pcln->nfile++] = f;
+ pcln->lastfile = f;
+ pcln->lastindex = i;
+ return i;
+}
+
+// pctospadj computes the sp adjustment in effect.
+// It is oldval plus any adjustment made by p itself.
+// The adjustment by p takes effect only after p, so we
+// apply the change during phase == 1.
+static int32
+pctospadj(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
+{
+ USED(arg);
+ USED(sym);
+
+ if(oldval == -1) // starting
+ oldval = 0;
+ if(phase == 0)
+ return oldval;
+ if(oldval + p->spadj < -10000 || oldval + p->spadj > 1100000000) {
+ ctxt->diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj);
+ sysfatal("bad code");
+ }
+ return oldval + p->spadj;
+}
+
+// pctopcdata computes the pcdata value in effect at p.
+// A PCDATA instruction sets the value in effect at future
+// non-PCDATA instructions.
+// Since PCDATA instructions have no width in the final code,
+// it does not matter which phase we use for the update.
+static int32
+pctopcdata(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
+{
+ USED(sym);
+
+ if(phase == 0 || p->as != ctxt->arch->APCDATA || p->from.offset != (uintptr)arg)
+ return oldval;
+ if((int32)p->to.offset != p->to.offset) {
+ ctxt->diag("overflow in PCDATA instruction: %P", p);
+ sysfatal("bad code");
+ }
+ return p->to.offset;
+}
+
+void
+linkpcln(Link *ctxt, LSym *cursym)
+{
+ Prog *p;
+ Pcln *pcln;
+ int i, npcdata, nfuncdata, n;
+ uint32 *havepc, *havefunc;
+
+ ctxt->cursym = cursym;
+
+ pcln = emallocz(sizeof *pcln);
+ cursym->pcln = pcln;
+
+ npcdata = 0;
+ nfuncdata = 0;
+ for(p = cursym->text; p != nil; p = p->link) {
+ if(p->as == ctxt->arch->APCDATA && p->from.offset >= npcdata)
+ npcdata = p->from.offset+1;
+ if(p->as == ctxt->arch->AFUNCDATA && p->from.offset >= nfuncdata)
+ nfuncdata = p->from.offset+1;
+ }
+
+ pcln->pcdata = emallocz(npcdata*sizeof pcln->pcdata[0]);
+ pcln->npcdata = npcdata;
+ pcln->funcdata = emallocz(nfuncdata*sizeof pcln->funcdata[0]);
+ pcln->funcdataoff = emallocz(nfuncdata*sizeof pcln->funcdataoff[0]);
+ pcln->nfuncdata = nfuncdata;
+
+ funcpctab(ctxt, &pcln->pcsp, cursym, "pctospadj", pctospadj, nil);
+ funcpctab(ctxt, &pcln->pcfile, cursym, "pctofile", pctofileline, pcln);
+ funcpctab(ctxt, &pcln->pcline, cursym, "pctoline", pctofileline, nil);
+
+ // tabulate which pc and func data we have.
+ n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4;
+ havepc = emallocz(n);
+ havefunc = havepc + (npcdata+31)/32;
+ for(p = cursym->text; p != nil; p = p->link) {
+ if(p->as == ctxt->arch->AFUNCDATA) {
+ if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1)
+ ctxt->diag("multiple definitions for FUNCDATA $%d", p->from.offset);
+ havefunc[p->from.offset/32] |= 1<<(p->from.offset%32);
+ }
+ if(p->as == ctxt->arch->APCDATA)
+ havepc[p->from.offset/32] |= 1<<(p->from.offset%32);
+ }
+ // pcdata.
+ for(i=0; i<npcdata; i++) {
+ if(!(havepc[i/32]>>(i%32))&1)
+ continue;
+ funcpctab(ctxt, &pcln->pcdata[i], cursym, "pctopcdata", pctopcdata, (void*)(uintptr)i);
+ }
+ free(havepc);
+
+ // funcdata
+ if(nfuncdata > 0) {
+ for(p = cursym->text; p != nil; p = p->link) {
+ if(p->as == ctxt->arch->AFUNCDATA) {
+ i = p->from.offset;
+ pcln->funcdataoff[i] = p->to.offset;
+ if(p->to.type != ctxt->arch->D_CONST) {
+ // TODO: Dedup.
+ //funcdata_bytes += p->to.sym->size;
+ pcln->funcdata[i] = p->to.sym;
+ }
+ }
+ }
+ }
+}
diff --git a/src/liblink/rdobj5.c b/src/liblink/rdobj5.c
new file mode 100644
index 000000000..f2a8b8223
--- /dev/null
+++ b/src/liblink/rdobj5.c
@@ -0,0 +1,585 @@
+// Inferno utils/5l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/5l/5.out.h"
+
+// TODO: remove duplicate chipzero, chipfloat
+
+static void finish(Link*);
+
+static int
+chipzero(Link *ctxt, float64 e)
+{
+ // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
+ if(ctxt->goarm < 7 || e != 0)
+ return -1;
+ return 0;
+}
+
+static int
+chipfloat(Link *ctxt, float64 e)
+{
+ int n;
+ ulong h1;
+ int32 l, h;
+ uint64 ei;
+
+ // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
+ if(ctxt->goarm < 7)
+ goto no;
+
+ memmove(&ei, &e, 8);
+ l = (int32)ei;
+ h = (int32)(ei>>32);
+
+ if(l != 0 || (h&0xffff) != 0)
+ goto no;
+ h1 = h & 0x7fc00000;
+ if(h1 != 0x40000000 && h1 != 0x3fc00000)
+ goto no;
+ n = 0;
+
+ // sign bit (a)
+ if(h & 0x80000000)
+ n |= 1<<7;
+
+ // exp sign bit (b)
+ if(h1 == 0x3fc00000)
+ n |= 1<<6;
+
+ // rest of exp and mantissa (cd-efgh)
+ n |= (h >> 16) & 0x3f;
+
+//print("match %.8lux %.8lux %d\n", l, h, n);
+ return n;
+
+no:
+ return -1;
+}
+
+static LSym*
+zsym(char *pn, Biobuf *f, LSym *h[])
+{
+ int o;
+
+ o = BGETC(f);
+ if(o == 0)
+ return nil;
+ if(o < 0 || o >= NSYM || h[o] == nil)
+ mangle(pn);
+ return h[o];
+}
+
+static void
+zaddr(Link *ctxt, char *pn, Biobuf *f, Addr *a, LSym *h[], LSym **pgotype)
+{
+ int i, c;
+ int32 l;
+ LSym *s, *gotype;
+ Auto *u;
+ uint64 v;
+
+ a->type = BGETC(f);
+ a->reg = BGETC(f);
+ c = BGETC(f);
+ if(c < 0 || c > NSYM){
+ print("sym out of range: %d\n", c);
+ BPUTC(f, ALAST+1);
+ return;
+ }
+ a->sym = h[c];
+ a->name = BGETC(f);
+ gotype = zsym(pn, f, h);
+ if(pgotype)
+ *pgotype = gotype;
+
+ if((schar)a->reg < 0 || a->reg > NREG) {
+ print("register out of range %d\n", a->reg);
+ BPUTC(f, ALAST+1);
+ return; /* force real diagnostic */
+ }
+
+ if(a->type == D_CONST || a->type == D_OCONST) {
+ if(a->name == D_EXTERN || a->name == D_STATIC) {
+ s = a->sym;
+ if(s != nil && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) {
+ if(0 && !s->fnptr && s->name[0] != '.')
+ print("%s used as function pointer\n", s->name);
+ s->fnptr = 1; // over the top cos of SXREF
+ }
+ }
+ }
+
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ BPUTC(f, ALAST+1);
+ return; /* force real diagnostic */
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_PSR:
+ case D_FPCR:
+ break;
+
+ case D_REGREG:
+ case D_REGREG2:
+ a->offset = BGETC(f);
+ break;
+
+ case D_CONST2:
+ a->offset2 = BGETLE4(f); // fall through
+ case D_BRANCH:
+ case D_OREG:
+ case D_CONST:
+ case D_OCONST:
+ case D_SHIFT:
+ a->offset = BGETLE4(f);
+ break;
+
+ case D_SCONST:
+ Bread(f, a->u.sval, NSNAME);
+ break;
+
+ case D_FCONST:
+ v = (uint32)BGETLE4(f);
+ v |= (uint64)BGETLE4(f)<<32;
+ memmove(&a->u.dval, &v, 8);
+ break;
+ }
+ s = a->sym;
+ if(s == nil)
+ return;
+ i = a->name;
+ if(i != D_AUTO && i != D_PARAM) {
+ if(s && gotype)
+ s->gotype = gotype;
+ return;
+ }
+
+ l = a->offset;
+ for(u=ctxt->curauto; u; u=u->link)
+ if(u->asym == s)
+ if(u->type == i) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ if(gotype)
+ u->gotype = gotype;
+ return;
+ }
+
+ u = emallocz(sizeof(Auto));
+ u->link = ctxt->curauto;
+ ctxt->curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = i;
+ u->gotype = gotype;
+}
+
+void
+nopout5(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+void
+ldobj5(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ int32 ipc;
+ Prog *p;
+ LSym *h[NSYM], *s;
+ int v, o, r, skip;
+ uint32 sig;
+ char *name;
+ int ntext;
+ int32 eof, autosize;
+ char src[1024], *x, literal[64];
+ Prog *lastp;
+ LSym *fromgotype;
+
+ lastp = nil;
+ ntext = 0;
+ eof = Boffset(f) + len;
+ src[0] = 0;
+ pn = estrdup(pn); // we keep it in LSym* references
+
+newloop:
+ memset(h, 0, sizeof(h));
+ ctxt->version++;
+ ctxt->histfrogp = 0;
+ ipc = ctxt->pc;
+ skip = 0;
+
+loop:
+ if(f->state == Bracteof || Boffset(f) >= eof)
+ goto eof;
+ o = BGETC(f);
+ if(o == Beof)
+ goto eof;
+
+ if(o <= AXXX || o >= ALAST) {
+ ctxt->diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
+ sysfatal("probably not a .5 file");
+ }
+ if(o == ANAME || o == ASIGNAME) {
+ sig = 0;
+ if(o == ASIGNAME)
+ sig = BGETLE4(f);
+ v = BGETC(f); /* type */
+ o = BGETC(f); /* sym */
+ r = 0;
+ if(v == D_STATIC)
+ r = ctxt->version;
+ name = Brdline(f, '\0');
+ if(name == nil) {
+ if(Blinelen(f) > 0) {
+ fprint(2, "%s: name too long\n", pn);
+ sysfatal("invalid object file");
+ }
+ goto eof;
+ }
+ x = expandpkg(name, pkg);
+ s = linklookup(ctxt, x, r);
+ if(x != name)
+ free(x);
+
+ if(sig != 0){
+ if(s->sig != 0 && s->sig != sig)
+ ctxt->diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name);
+ s->sig = sig;
+ s->file = pn;
+ }
+
+ if(ctxt->debugread)
+ print(" ANAME %s\n", s->name);
+ if(o < 0 || o >= nelem(h)) {
+ fprint(2, "%s: mangled input file\n", pn);
+ sysfatal("invalid object");
+ }
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ ctxt->histgen++;
+ s->type = SFILE;
+ s->value = ctxt->histgen;
+ }
+ if(ctxt->histfrogp < LinkMaxHist) {
+ ctxt->histfrog[ctxt->histfrogp] = s;
+ ctxt->histfrogp++;
+ } else
+ collapsefrog(ctxt, s);
+ ctxt->dwarfaddfrag(s->value, s->name);
+ }
+ goto loop;
+ }
+
+ p = emallocz(sizeof(Prog));
+ p->as = o;
+ p->scond = BGETC(f);
+ p->reg = BGETC(f);
+ p->lineno = BGETLE4(f);
+
+ zaddr(ctxt, pn, f, &p->from, h, &fromgotype);
+ zaddr(ctxt, pn, f, &p->to, h, nil);
+
+ if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG)
+ ctxt->diag("register out of range %A %d", p->as, p->reg);
+
+ p->link = nil;
+ p->pcond = nil;
+
+ if(ctxt->debugread)
+ print("%P\n", p);
+
+ switch(o) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(ctxt, src, pn);
+ ctxt->histfrogp = 0;
+ goto loop;
+ }
+ if(src[0] == '\0')
+ copyhistfrog(ctxt, src, sizeof src);
+ addhist(ctxt, p->lineno, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(ctxt, p->to.offset, D_FILE1); /* 'Z' */
+ savehist(ctxt, p->lineno, p->to.offset);
+ ctxt->histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ finish(ctxt);
+ if(Boffset(f) == eof)
+ return;
+ goto newloop;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s == nil) {
+ ctxt->diag("GLOBL must have a name\n%P", p);
+ sysfatal("mangled input");
+ }
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
+ ctxt->diag("redefinition: %s\n%P", s->name, p);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset > s->size)
+ s->size = p->to.offset;
+ if(p->reg & DUPOK)
+ s->dupok = 1;
+ if(p->reg & RODATA)
+ s->type = SRODATA;
+ else if(p->reg & NOPTR)
+ s->type = SNOPTRBSS;
+ break;
+
+ case ADATA:
+ // Assume that AGLOBL comes after ADATA.
+ // If we've seen an AGLOBL that said this sym was DUPOK,
+ // ignore any more ADATA we see, which must be
+ // redefinitions.
+ s = p->from.sym;
+ if(s->dupok) {
+// if(debug['v'])
+// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
+ goto loop;
+ }
+ if(s->file == nil)
+ s->file = pn;
+ else if(s->file != pn) {
+ ctxt->diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
+ sysfatal("mangled input");
+ }
+ savedata(ctxt, s, p, pn);
+ free(p);
+ break;
+
+ case AGOK:
+ ctxt->diag("unknown opcode\n%P", p);
+ p->pc = ctxt->pc;
+ ctxt->pc++;
+ break;
+
+ case ATYPE:
+ if(skip)
+ goto casedef;
+ ctxt->pc++;
+ goto loop;
+
+ case ATEXT:
+ if(ctxt->cursym != nil && ctxt->cursym->text)
+ finish(ctxt);
+ s = p->from.sym;
+ if(s == nil) {
+ ctxt->diag("TEXT must have a name\n%P", p);
+ sysfatal("mangled input");
+ }
+ ctxt->cursym = s;
+ if(s->type != 0 && s->type != SXREF && (p->reg & DUPOK)) {
+ skip = 1;
+ goto casedef;
+ }
+ if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
+ /* redefinition, so file has probably been seen before */
+ if(ctxt->debugvlog)
+ Bprint(ctxt->bso, "skipping: %s: redefinition: %s", pn, s->name);
+ return;
+ }
+ skip = 0;
+ if(s->type != 0 && s->type != SXREF)
+ ctxt->diag("redefinition: %s\n%P", s->name, p);
+ if(ctxt->etextp)
+ ctxt->etextp->next = s;
+ else
+ ctxt->textp = s;
+ if(fromgotype) {
+ if(s->gotype && s->gotype != fromgotype)
+ ctxt->diag("%s: type mismatch for %s", pn, s->name);
+ s->gotype = fromgotype;
+ }
+ ctxt->etextp = s;
+ autosize = (p->to.offset+3L) & ~3L;
+ p->to.offset = autosize;
+ autosize += 4;
+ s->type = STEXT;
+ s->hist = gethist(ctxt);
+ s->text = p;
+ s->value = ctxt->pc;
+ s->args = p->to.offset2;
+ lastp = p;
+ p->pc = ctxt->pc;
+ ctxt->pc++;
+ break;
+
+ case ASUB:
+ if(p->from.type == D_CONST)
+ if(p->from.name == D_NONE)
+ if(p->from.offset < 0) {
+ p->from.offset = -p->from.offset;
+ p->as = AADD;
+ }
+ goto casedef;
+
+ case AADD:
+ if(p->from.type == D_CONST)
+ if(p->from.name == D_NONE)
+ if(p->from.offset < 0) {
+ p->from.offset = -p->from.offset;
+ p->as = ASUB;
+ }
+ goto casedef;
+
+ case AMOVWD:
+ case AMOVWF:
+ case AMOVDW:
+ case AMOVFW:
+ case AMOVFD:
+ case AMOVDF:
+ // case AMOVF:
+ // case AMOVD:
+ case ACMPF:
+ case ACMPD:
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ goto casedef;
+
+ case AMOVF:
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_FCONST && chipfloat(ctxt, p->from.u.dval) < 0 &&
+ (chipzero(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
+ /* size sb 9 max */
+ sprint(literal, "$%.17gf", (float32)p->from.u.dval);
+ s = linklookup(ctxt, literal, 0);
+ if(s->type == 0) {
+ float32 f32;
+ int32 i32;
+ s->type = SRODATA;
+ f32 = p->from.u.dval;
+ memmove(&i32, &f32, 4);
+ adduint32(ctxt, s, i32);
+ s->reachable = 0;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ case AMOVD:
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_FCONST && chipfloat(ctxt, p->from.u.dval) < 0 &&
+ (chipzero(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
+ /* size sb 18 max */
+ sprint(literal, "$%.17g", p->from.u.dval);
+ s = linklookup(ctxt, literal, 0);
+ if(s->type == 0) {
+ int64 i64;
+ s->type = SRODATA;
+ memmove(&i64, &p->from.u.dval, 8);
+ adduint64(ctxt, s, i64);
+ s->reachable = 0;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ default:
+ casedef:
+ if(skip)
+ nopout5(p);
+ p->pc = ctxt->pc;
+ ctxt->pc++;
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ if(lastp == nil) {
+ if(p->as != ANOP)
+ ctxt->diag("unexpected instruction: %P", p);
+ break;
+ }
+ lastp->link = p;
+ lastp = p;
+ break;
+ }
+ goto loop;
+
+eof:
+ ctxt->diag("truncated object file: %s", pn);
+}
+
+static void
+finish(Link *ctxt)
+{
+ LSym *s;
+
+ histtoauto(ctxt);
+ if(ctxt->cursym != nil && ctxt->cursym->text) {
+ s = ctxt->cursym;
+ s->autom = ctxt->curauto;
+ // mkfwd(s);
+ // linkpatch(ctxt, s);
+ // ctxt->arch->follow(ctxt, s);
+ // ctxt->arch->addstacksplit(ctxt, s);
+ // ctxt->arch->assemble(ctxt, s);
+ // linkpcln(ctxt, s);
+ }
+
+ ctxt->curauto = 0;
+ ctxt->cursym = nil;
+}
+
diff --git a/src/liblink/rdobj6.c b/src/liblink/rdobj6.c
new file mode 100644
index 000000000..52ed18b93
--- /dev/null
+++ b/src/liblink/rdobj6.c
@@ -0,0 +1,495 @@
+// Inferno utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/6l/6.out.h"
+
+static LSym*
+zsym(char *pn, Biobuf *f, LSym *h[])
+{
+ int o;
+
+ o = BGETC(f);
+ if(o < 0 || o >= NSYM || h[o] == nil)
+ mangle(pn);
+ return h[o];
+}
+
+static void finish(Link*);
+
+static void
+zaddr(Link *ctxt, char *pn, Biobuf *f, Addr *a, LSym *h[], LSym **pgotype)
+{
+ int t;
+ int32 l;
+ LSym *s, *gotype;
+ Auto *u;
+ uint64 v;
+
+ t = BGETC(f);
+ a->index = D_NONE;
+ a->scale = 0;
+ if(t & T_INDEX) {
+ a->index = BGETC(f);
+ a->scale = BGETC(f);
+ }
+ a->offset = 0;
+ if(t & T_OFFSET) {
+ a->offset = BGETLE4(f);
+ if(t & T_64) {
+ a->offset &= 0xFFFFFFFFULL;
+ a->offset |= (uvlong)BGETLE4(f) << 32;
+ }
+ }
+ a->sym = nil;
+ if(t & T_SYM)
+ a->sym = zsym(pn, f, h);
+ a->type = D_NONE;
+ if(t & T_FCONST) {
+ v = (uint32)BGETLE4(f);
+ v |= (uint64)BGETLE4(f)<<32;
+ memmove(&a->u.dval, &v, 8);
+ a->type = D_FCONST;
+ } else
+ if(t & T_SCONST) {
+ Bread(f, a->u.sval, NSNAME);
+ a->type = D_SCONST;
+ }
+ if(t & T_TYPE)
+ a->type = BGETC(f);
+ if(a->type < 0 || a->type >= D_SIZE)
+ mangle(pn);
+ gotype = nil;
+ if(t & T_GOTYPE)
+ gotype = zsym(pn, f, h);
+ if(pgotype)
+ *pgotype = gotype;
+ s = a->sym;
+ t = a->type;
+ if(t == D_INDIR+D_GS || a->index == D_GS)
+ a->offset += ctxt->tlsoffset;
+ if(t != D_AUTO && t != D_PARAM) {
+ if(s && gotype)
+ s->gotype = gotype;
+ return;
+ }
+ l = a->offset;
+ for(u=ctxt->curauto; u; u=u->link) {
+ if(u->asym == s)
+ if(u->type == t) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ if(gotype)
+ u->gotype = gotype;
+ return;
+ }
+ }
+
+ switch(t) {
+ case D_FILE:
+ case D_FILE1:
+ case D_AUTO:
+ case D_PARAM:
+ if(s == nil)
+ mangle(pn);
+ }
+
+ u = emallocz(sizeof(*u));
+ u->link = ctxt->curauto;
+ ctxt->curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = t;
+ u->gotype = gotype;
+}
+
+void
+nopout6(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+void
+ldobj6(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ vlong ipc;
+ Prog *p;
+ int v, o, r, skip, mode;
+ LSym *h[NSYM], *s;
+ uint32 sig;
+ char *name, *x;
+ int ntext;
+ vlong eof;
+ char src[1024], literal[64];
+ Prog *lastp;
+ LSym *fromgotype;
+
+ lastp = nil;
+ ntext = 0;
+ eof = Boffset(f) + len;
+ src[0] = 0;
+ pn = estrdup(pn); // we keep it in LSym* references
+
+newloop:
+ memset(h, 0, sizeof(h));
+ ctxt->version++;
+ ctxt->histfrogp = 0;
+ ipc = ctxt->pc;
+ skip = 0;
+ mode = 64;
+
+loop:
+ if(f->state == Bracteof || Boffset(f) >= eof)
+ goto eof;
+ o = BGETC(f);
+ if(o == Beof)
+ goto eof;
+ o |= BGETC(f) << 8;
+ if(o <= AXXX || o >= ALAST) {
+ if(o < 0)
+ goto eof;
+ sysfatal("%s:#%lld: opcode out of range: %#ux\n\tprobably not a .6 file", pn, Boffset(f), o);
+ }
+
+ if(o == ANAME || o == ASIGNAME) {
+ sig = 0;
+ if(o == ASIGNAME)
+ sig = BGETLE4(f);
+ USED(sig);
+ v = BGETC(f); /* type */
+ o = BGETC(f); /* sym */
+ r = 0;
+ if(v == D_STATIC)
+ r = ctxt->version;
+ name = Brdline(f, '\0');
+ if(name == nil) {
+ if(Blinelen(f) > 0)
+ sysfatal("%s: name too long", pn);
+ goto eof;
+ }
+ x = expandpkg(name, pkg);
+ s = linklookup(ctxt, x, r);
+ if(x != name)
+ free(x);
+
+ if(ctxt->debugread)
+ print(" ANAME %s\n", s->name);
+ if(o < 0 || o >= nelem(h))
+ mangle(pn);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ ctxt->histgen++;
+ s->type = SFILE;
+ s->value = ctxt->histgen;
+ }
+ if(ctxt->histfrogp < LinkMaxHist) {
+ ctxt->histfrog[ctxt->histfrogp] = s;
+ ctxt->histfrogp++;
+ } else
+ collapsefrog(ctxt, s);
+ if(ctxt->dwarfaddfrag)
+ ctxt->dwarfaddfrag(s->value, s->name);
+ }
+ goto loop;
+ }
+
+ p = emallocz(sizeof(*p));
+ p->as = o;
+ p->lineno = BGETLE4(f);
+ p->back = 2;
+ p->mode = mode;
+ zaddr(ctxt, pn, f, &p->from, h, &fromgotype);
+ zaddr(ctxt, pn, f, &p->to, h, nil);
+
+ switch(p->as) {
+ case ATEXT:
+ case ADATA:
+ case AGLOBL:
+ if(p->from.sym == nil)
+ mangle(pn);
+ break;
+ }
+
+ if(ctxt->debugread)
+ print("%P\n", p);
+
+ switch(p->as) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(ctxt, src, pn);
+ ctxt->histfrogp = 0;
+ goto loop;
+ }
+ if(src[0] == '\0')
+ copyhistfrog(ctxt, src, sizeof src);
+ addhist(ctxt, p->lineno, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(ctxt, p->to.offset, D_FILE1); /* 'Z' */
+ savehist(ctxt, p->lineno, p->to.offset);
+ ctxt->histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ finish(ctxt);
+ if(Boffset(f) == eof)
+ return;
+ goto newloop;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->size = 0;
+ }
+ if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
+ ctxt->diag("%s: redefinition: %s in %s",
+ pn, s->name, ctxt->cursym ? ctxt->cursym->name : "<none>");
+ s->type = SBSS;
+ s->size = 0;
+ }
+ if(p->to.offset > s->size)
+ s->size = p->to.offset;
+ if(p->from.scale & DUPOK)
+ s->dupok = 1;
+ if(p->from.scale & RODATA)
+ s->type = SRODATA;
+ else if(p->from.scale & NOPTR)
+ s->type = SNOPTRBSS;
+ goto loop;
+
+ case ADATA:
+ // Assume that AGLOBL comes after ADATA.
+ // If we've seen an AGLOBL that said this sym was DUPOK,
+ // ignore any more ADATA we see, which must be
+ // redefinitions.
+ s = p->from.sym;
+ if(s->dupok) {
+// if(ctxt->debugvlog)
+// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
+ goto loop;
+ }
+ if(s->file == nil)
+ s->file = pn;
+ else if(s->file != pn)
+ sysfatal("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
+ savedata(ctxt, s, p, pn);
+ free(p);
+ goto loop;
+
+ case AGOK:
+ ctxt->diag("%s: GOK opcode in %s", pn, ctxt->cursym ? ctxt->cursym->name : "<none>");
+ ctxt->pc++;
+ goto loop;
+
+ case ATYPE:
+ if(skip)
+ goto casdef;
+ ctxt->pc++;
+ goto loop;
+
+ case ATEXT:
+ s = p->from.sym;
+ if(s->text != nil) {
+ if(p->from.scale & DUPOK) {
+ skip = 1;
+ goto casdef;
+ }
+ ctxt->diag("%s: %s: redefinition", pn, s->name);
+ return;
+ }
+ if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
+ /* redefinition, so file has probably been seen before */
+ if(ctxt->debugvlog && ctxt->bso)
+ Bprint(ctxt->bso, "skipping: %s: redefinition: %s", pn, s->name);
+ return;
+ }
+ if(ctxt->cursym != nil && ctxt->cursym->text)
+ finish(ctxt);
+ skip = 0;
+ if(ctxt->etextp)
+ ctxt->etextp->next = s;
+ else
+ ctxt->textp = s;
+ ctxt->etextp = s;
+ s->text = p;
+ ctxt->cursym = s;
+ if(s->type != 0 && s->type != SXREF) {
+ if(p->from.scale & DUPOK) {
+ skip = 1;
+ goto casdef;
+ }
+ ctxt->diag("%s: redefinition: %s\n%P", pn, s->name, p);
+ }
+ if(fromgotype) {
+ if(s->gotype && s->gotype != fromgotype)
+ ctxt->diag("%s: type mismatch for %s", pn, s->name);
+ s->gotype = fromgotype;
+ }
+ s->type = STEXT;
+ s->hist = gethist(ctxt);
+ s->value = ctxt->pc;
+ s->args = p->to.offset >> 32;
+ lastp = p;
+ p->pc = ctxt->pc++;
+ goto loop;
+
+ case AMODE:
+ if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){
+ switch((int)p->from.offset){
+ case 16: case 32: case 64:
+ mode = p->from.offset;
+ break;
+ }
+ }
+ goto loop;
+
+ case AFMOVF:
+ case AFADDF:
+ case AFSUBF:
+ case AFSUBRF:
+ case AFMULF:
+ case AFDIVF:
+ case AFDIVRF:
+ case AFCOMF:
+ case AFCOMFP:
+ case AMOVSS:
+ case AADDSS:
+ case ASUBSS:
+ case AMULSS:
+ case ADIVSS:
+ case ACOMISS:
+ case AUCOMISS:
+ if(skip)
+ goto casdef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 9 max */
+ sprint(literal, "$%.17gf", (float32)p->from.u.dval);
+ s = linklookup(ctxt, literal, 0);
+ if(s->type == 0) {
+ int32 i32;
+ float32 f32;
+ s->type = SRODATA;
+ f32 = p->from.u.dval;
+ memmove(&i32, &f32, 4);
+ adduint32(ctxt, s, i32);
+ s->reachable = 0;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ case AFMOVD:
+ case AFADDD:
+ case AFSUBD:
+ case AFSUBRD:
+ case AFMULD:
+ case AFDIVD:
+ case AFDIVRD:
+ case AFCOMD:
+ case AFCOMDP:
+ case AMOVSD:
+ case AADDSD:
+ case ASUBSD:
+ case AMULSD:
+ case ADIVSD:
+ case ACOMISD:
+ case AUCOMISD:
+ if(skip)
+ goto casdef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 18 max */
+ sprint(literal, "$%.17g", p->from.u.dval);
+ s = linklookup(ctxt, literal, 0);
+ if(s->type == 0) {
+ int64 i64;
+ s->type = SRODATA;
+ memmove(&i64, &p->from.u.dval, 8);
+ adduint64(ctxt, s, i64);
+ s->reachable = 0;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ casdef:
+ default:
+ if(skip)
+ nopout6(p);
+ p->pc = ctxt->pc;
+ ctxt->pc++;
+
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ if(lastp == nil) {
+ if(p->as != ANOP)
+ ctxt->diag("unexpected instruction: %P", p);
+ goto loop;
+ }
+ lastp->link = p;
+ lastp = p;
+ goto loop;
+ }
+
+eof:
+ ctxt->diag("truncated object file: %s", pn);
+}
+
+static void
+finish(Link *ctxt)
+{
+ LSym *s;
+
+ histtoauto(ctxt);
+ if(ctxt->cursym != nil && ctxt->cursym->text) {
+ s = ctxt->cursym;
+ s->autom = ctxt->curauto;
+ // mkfwd(s);
+ // linkpatch(ctxt, s);
+ // ctxt->arch->follow(ctxt, s);
+ // ctxt->arch->addstacksplit(ctxt, s);
+ // ctxt->arch->assemble(ctxt, s);
+ // linkpcln(ctxt, s);
+ }
+
+ ctxt->curauto = 0;
+ ctxt->cursym = nil;
+}
diff --git a/src/liblink/rdobj8.c b/src/liblink/rdobj8.c
new file mode 100644
index 000000000..d84e42889
--- /dev/null
+++ b/src/liblink/rdobj8.c
@@ -0,0 +1,466 @@
+// Inferno utils/8l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/8l/8.out.h"
+
+static LSym*
+zsym(char *pn, Biobuf *f, LSym *h[])
+{
+ int o;
+
+ o = BGETC(f);
+ if(o < 0 || o >= NSYM || h[o] == nil)
+ mangle(pn);
+ return h[o];
+}
+
+static void finish(Link*);
+
+static void
+zaddr(Link *ctxt, char *pn, Biobuf *f, Addr *a, LSym *h[], LSym **pgotype)
+{
+ int t;
+ int32 l;
+ LSym *s, *gotype;
+ Auto *u;
+ uint64 v;
+
+ t = BGETC(f);
+ a->index = D_NONE;
+ a->scale = 0;
+ if(t & T_INDEX) {
+ a->index = BGETC(f);
+ a->scale = BGETC(f);
+ }
+ a->type = D_NONE;
+ a->offset = 0;
+ if(t & T_OFFSET)
+ a->offset = BGETLE4(f);
+ a->offset2 = 0;
+ if(t & T_OFFSET2) {
+ a->offset2 = BGETLE4(f);
+ a->type = D_CONST2;
+ }
+ a->sym = nil;
+ if(t & T_SYM)
+ a->sym = zsym(pn, f, h);
+ if(t & T_FCONST) {
+ v = (uint32)BGETLE4(f);
+ v |= (uint64)BGETLE4(f)<<32;
+ memmove(&a->u.dval, &v, 8);
+ a->type = D_FCONST;
+ } else
+ if(t & T_SCONST) {
+ Bread(f, a->u.sval, NSNAME);
+ a->type = D_SCONST;
+ }
+ if(t & T_TYPE)
+ a->type = BGETC(f);
+ gotype = nil;
+ if(t & T_GOTYPE)
+ gotype = zsym(pn, f, h);
+ if(pgotype)
+ *pgotype = gotype;
+ t = a->type;
+ if(t == D_INDIR+D_GS)
+ a->offset += ctxt->tlsoffset;
+
+ s = a->sym;
+ if(s == nil)
+ return;
+ if(t != D_AUTO && t != D_PARAM) {
+ if(gotype)
+ s->gotype = gotype;
+ return;
+ }
+ l = a->offset;
+ for(u=ctxt->curauto; u; u=u->link) {
+ if(u->asym == s)
+ if(u->type == t) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ if(gotype)
+ u->gotype = gotype;
+ return;
+ }
+ }
+
+ u = emallocz(sizeof(*u));
+ u->link = ctxt->curauto;
+ ctxt->curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = t;
+ u->gotype = gotype;
+}
+
+void
+nopout8(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+void
+ldobj8(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ int32 ipc;
+ Prog *p;
+ int v, o, r, skip;
+ LSym *h[NSYM], *s;
+ uint32 sig;
+ int ntext;
+ int32 eof;
+ char *name, *x;
+ char src[1024], literal[64];
+ Prog *lastp;
+ LSym *fromgotype;
+
+ lastp = nil;
+ ntext = 0;
+ eof = Boffset(f) + len;
+ src[0] = 0;
+ pn = estrdup(pn); // we keep it in LSym* references
+
+newloop:
+ memset(h, 0, sizeof(h));
+ ctxt->version++;
+ ctxt->histfrogp = 0;
+ ipc = ctxt->pc;
+ skip = 0;
+
+loop:
+ if(f->state == Bracteof || Boffset(f) >= eof)
+ goto eof;
+ o = BGETC(f);
+ if(o == Beof)
+ goto eof;
+ o |= BGETC(f) << 8;
+ if(o <= AXXX || o >= ALAST) {
+ if(o < 0)
+ goto eof;
+ ctxt->diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
+ print(" probably not a .%c file\n", ctxt->thechar);
+ sysfatal("invalid file");
+ }
+
+ if(o == ANAME || o == ASIGNAME) {
+ sig = 0;
+ if(o == ASIGNAME)
+ sig = BGETLE4(f);
+ USED(sig);
+
+ v = BGETC(f); /* type */
+ o = BGETC(f); /* sym */
+ r = 0;
+ if(v == D_STATIC)
+ r = ctxt->version;
+ name = Brdline(f, '\0');
+ if(name == nil) {
+ if(Blinelen(f) > 0)
+ sysfatal("%s: name too long", pn);
+ goto eof;
+ }
+ x = expandpkg(name, pkg);
+ s = linklookup(ctxt, x, r);
+ if(x != name)
+ free(x);
+
+ if(ctxt->debugread)
+ print(" ANAME %s\n", s->name);
+ if(o < 0 || o >= nelem(h))
+ mangle(pn);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ ctxt->histgen++;
+ s->type = SFILE;
+ s->value = ctxt->histgen;
+ }
+ if(ctxt->histfrogp < LinkMaxHist) {
+ ctxt->histfrog[ctxt->histfrogp] = s;
+ ctxt->histfrogp++;
+ } else
+ collapsefrog(ctxt, s);
+ ctxt->dwarfaddfrag(s->value, s->name);
+ }
+ goto loop;
+ }
+
+ p = emallocz(sizeof(*p));
+ p->as = o;
+ p->lineno = BGETLE4(f);
+ p->back = 2;
+ zaddr(ctxt, pn, f, &p->from, h, &fromgotype);
+ zaddr(ctxt, pn, f, &p->to, h, nil);
+
+ if(ctxt->debugread)
+ print("%P\n", p);
+
+ switch(p->as) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(ctxt, src, pn);
+ ctxt->histfrogp = 0;
+ goto loop;
+ }
+ if(src[0] == '\0')
+ copyhistfrog(ctxt, src, sizeof src);
+ addhist(ctxt, p->lineno, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(ctxt, p->to.offset, D_FILE1); /* 'Z' */
+ savehist(ctxt, p->lineno, p->to.offset);
+ ctxt->histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ finish(ctxt);
+ if(Boffset(f) == eof)
+ return;
+ goto newloop;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->size = 0;
+ }
+ if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
+ ctxt->diag("%s: redefinition: %s in %s",
+ pn, s->name, ctxt->cursym ? ctxt->cursym->name : "<none>");
+ s->type = SBSS;
+ s->size = 0;
+ }
+ if(p->to.offset > s->size)
+ s->size = p->to.offset;
+ if(p->from.scale & DUPOK)
+ s->dupok = 1;
+ if(p->from.scale & RODATA)
+ s->type = SRODATA;
+ else if(p->from.scale & NOPTR)
+ s->type = SNOPTRBSS;
+ goto loop;
+
+ case ADATA:
+ // Assume that AGLOBL comes after ADATA.
+ // If we've seen an AGLOBL that said this sym was DUPOK,
+ // ignore any more ADATA we see, which must be
+ // redefinitions.
+ s = p->from.sym;
+ if(s->dupok) {
+// if(ctxt->debugvlog)
+// Bprint(ctxt->bso, "skipping %s in %s: dupok\n", s->name, pn);
+ goto loop;
+ }
+ if(s->file == nil)
+ s->file = pn;
+ else if(s->file != pn) {
+ ctxt->diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
+ sysfatal("multiple init");
+ }
+ savedata(ctxt, s, p, pn);
+ free(p);
+ goto loop;
+
+ case AGOK:
+ ctxt->diag("%s: GOK opcode in %s", pn, ctxt->cursym ? ctxt->cursym->name : "<none>");
+ ctxt->pc++;
+ goto loop;
+
+ case ATYPE:
+ if(skip)
+ goto casdef;
+ ctxt->pc++;
+ goto loop;
+
+ case ATEXT:
+ s = p->from.sym;
+ if(s->text != nil) {
+ if(p->from.scale & DUPOK) {
+ skip = 1;
+ goto casdef;
+ }
+ ctxt->diag("%s: %s: redefinition", pn, s->name);
+ return;
+ }
+ if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
+ /* redefinition, so file has probably been seen before */
+ if(ctxt->debugvlog)
+ ctxt->diag("skipping: %s: redefinition: %s", pn, s->name);
+ return;
+ }
+ if(ctxt->cursym != nil && ctxt->cursym->text)
+ finish(ctxt);
+ skip = 0;
+ if(ctxt->etextp)
+ ctxt->etextp->next = s;
+ else
+ ctxt->textp = s;
+ ctxt->etextp = s;
+ s->text = p;
+ ctxt->cursym = s;
+ if(s->type != 0 && s->type != SXREF) {
+ if(p->from.scale & DUPOK) {
+ skip = 1;
+ goto casdef;
+ }
+ ctxt->diag("%s: redefinition: %s\n%P", pn, s->name, p);
+ }
+ s->type = STEXT;
+ s->hist = gethist(ctxt);
+ s->value = ctxt->pc;
+ s->args = p->to.offset2;
+ lastp = p;
+ p->pc = ctxt->pc++;
+ goto loop;
+
+ case AFMOVF:
+ case AFADDF:
+ case AFSUBF:
+ case AFSUBRF:
+ case AFMULF:
+ case AFDIVF:
+ case AFDIVRF:
+ case AFCOMF:
+ case AFCOMFP:
+ case AMOVSS:
+ case AADDSS:
+ case ASUBSS:
+ case AMULSS:
+ case ADIVSS:
+ case ACOMISS:
+ case AUCOMISS:
+ if(skip)
+ goto casdef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 9 max */
+ sprint(literal, "$(%.17gf)", (float32)p->from.u.dval);
+ s = linklookup(ctxt, literal, 0);
+ if(s->type == 0) {
+ float32 f32;
+ int32 i32;
+ s->type = SRODATA;
+ f32 = p->from.u.dval;
+ memmove(&i32, &f32, 4);
+ adduint32(ctxt, s, i32);
+ s->reachable = 0;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ case AFMOVD:
+ case AFADDD:
+ case AFSUBD:
+ case AFSUBRD:
+ case AFMULD:
+ case AFDIVD:
+ case AFDIVRD:
+ case AFCOMD:
+ case AFCOMDP:
+ case AMOVSD:
+ case AADDSD:
+ case ASUBSD:
+ case AMULSD:
+ case ADIVSD:
+ case ACOMISD:
+ case AUCOMISD:
+ if(skip)
+ goto casdef;
+ if(p->from.type == D_FCONST) {
+ /* size sb 18 max */
+ sprint(literal, "$%.17g",
+ p->from.u.dval);
+ s = linklookup(ctxt, literal, 0);
+ if(s->type == 0) {
+ int64 i64;
+ s->type = SRODATA;
+ memmove(&i64, &p->from.u.dval, 8);
+ adduint64(ctxt, s, i64);
+ s->reachable = 0;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ goto casdef;
+
+ casdef:
+ default:
+ if(skip)
+ nopout8(p);
+ p->pc = ctxt->pc;
+ ctxt->pc++;
+
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ if(lastp == nil) {
+ if(p->as != ANOP)
+ ctxt->diag("unexpected instruction: %P", p);
+ goto loop;
+ }
+ lastp->link = p;
+ lastp = p;
+ goto loop;
+ }
+
+eof:
+ ctxt->diag("truncated object file: %s", pn);
+}
+
+static void
+finish(Link *ctxt)
+{
+ LSym *s;
+
+ histtoauto(ctxt);
+ if(ctxt->cursym != nil && ctxt->cursym->text) {
+ s = ctxt->cursym;
+ s->autom = ctxt->curauto;
+ // mkfwd(s);
+ // linkpatch(ctxt, s);
+ // ctxt->arch->follow(ctxt, s);
+ // ctxt->arch->addstacksplit(ctxt, s);
+ // ctxt->arch->assemble(ctxt, s);
+ // linkpcln(ctxt, s);
+ }
+
+ ctxt->curauto = 0;
+ ctxt->cursym = nil;
+}
diff --git a/src/liblink/sym.c b/src/liblink/sym.c
new file mode 100644
index 000000000..e876a5ca0
--- /dev/null
+++ b/src/liblink/sym.c
@@ -0,0 +1,158 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+static int
+yy_isalpha(int c)
+{
+ return c >= 0 && c <= 0xFF && isalpha(c);
+}
+
+Link*
+linknew(LinkArch *arch)
+{
+ Link *ctxt;
+ char *p;
+ char buf[1024];
+
+ nuxiinit();
+
+ ctxt = emallocz(sizeof *ctxt);
+ ctxt->arch = arch;
+ ctxt->version = HistVersion;
+
+ // TODO: Make caller pass in ctxt->arch,
+ // so that for example 6g only has the linkamd64 code.
+ p = getgoarch();
+ if(strncmp(p, arch->name, strlen(arch->name)) != 0)
+ sysfatal("invalid goarch %s (want %s or derivative)", p, arch->name);
+
+ if(getwd(buf, sizeof buf) == 0)
+ strcpy(buf, "/???");
+ if(yy_isalpha(buf[0]) && buf[1] == ':') {
+ // On Windows.
+ ctxt->windows = 1;
+
+ // Canonicalize path by converting \ to / (Windows accepts both).
+ for(p=buf; *p; p++)
+ if(*p == '\\')
+ *p = '/';
+ }
+ ctxt->pathname = strdup(buf);
+
+ return ctxt;
+}
+
+LSym*
+linknewsym(Link *ctxt, char *symb, int v)
+{
+ LSym *s;
+ int l;
+
+ l = strlen(symb) + 1;
+ s = malloc(sizeof(*s));
+ memset(s, 0, sizeof(*s));
+
+ s->dynid = -1;
+ s->plt = -1;
+ s->got = -1;
+ s->name = malloc(l + 1);
+ memmove(s->name, symb, l);
+ s->name[l] = '\0';
+
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ s->sig = 0;
+ s->size = 0;
+ ctxt->nsymbol++;
+
+ s->allsym = ctxt->allsym;
+ ctxt->allsym = s;
+
+ return s;
+}
+
+static LSym*
+_lookup(Link *ctxt, char *symb, int v, int creat)
+{
+ LSym *s;
+ char *p;
+ uint32 h;
+ int c;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ h &= 0xffffff;
+ h %= LINKHASH;
+ for(s = ctxt->hash[h]; s != nil; s = s->hash)
+ if(strcmp(s->name, symb) == 0)
+ return s;
+ if(!creat)
+ return nil;
+
+ s = linknewsym(ctxt, symb, v);
+ s->extname = s->name;
+ s->hash = ctxt->hash[h];
+ ctxt->hash[h] = s;
+
+ return s;
+}
+
+LSym*
+linklookup(Link *ctxt, char *name, int v)
+{
+ return _lookup(ctxt, name, v, 1);
+}
+
+// read-only lookup
+LSym*
+linkrlookup(Link *ctxt, char *name, int v)
+{
+ return _lookup(ctxt, name, v, 0);
+}
+
+int
+linksymfmt(Fmt *f)
+{
+ LSym *s;
+
+ s = va_arg(f->args, LSym*);
+ if(s == nil)
+ return fmtstrcpy(f, "<nil>");
+
+ return fmtstrcpy(f, s->name);
+}