summaryrefslogtreecommitdiff
path: root/src/cmd/5l
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/cmd/5l
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/cmd/5l')
-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
11 files changed, 216 insertions, 5074 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;
-}
-*/