summaryrefslogtreecommitdiff
path: root/src/cmd/8l
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/8l')
-rw-r--r--src/cmd/8l/8.out.h8
-rw-r--r--src/cmd/8l/Makefile29
-rw-r--r--src/cmd/8l/asm.c1328
-rw-r--r--src/cmd/8l/doc.go4
-rw-r--r--src/cmd/8l/l.h136
-rw-r--r--src/cmd/8l/list.c87
-rw-r--r--src/cmd/8l/obj.c505
-rw-r--r--src/cmd/8l/optab.c4
-rw-r--r--src/cmd/8l/pass.c1058
-rw-r--r--src/cmd/8l/prof.c173
-rw-r--r--src/cmd/8l/span.c1183
11 files changed, 1817 insertions, 2698 deletions
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
index c17f606e2..0866f05f0 100644
--- a/src/cmd/8l/8.out.h
+++ b/src/cmd/8l/8.out.h
@@ -33,6 +33,7 @@
#define NOPROF (1<<0)
#define DUPOK (1<<1)
#define NOSPLIT (1<<2)
+#define RODATA (1<<3)
enum as
{
@@ -383,8 +384,8 @@ enum as
AEND,
- ADYNT,
- AINIT,
+ ADYNT_,
+ AINIT_,
ASIGNAME,
@@ -498,6 +499,9 @@ enum
D_CONST2 = D_INDIR+D_INDIR,
D_SIZE, /* 8l internal */
+ D_PCREL,
+ D_GOTOFF,
+ D_GOTREL,
T_TYPE = 1<<0,
T_INDEX = 1<<1,
diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile
index 88c7c512b..84976ba18 100644
--- a/src/cmd/8l/Makefile
+++ b/src/cmd/8l/Makefile
@@ -2,15 +2,20 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 8l\
+TARG=8l
OFILES=\
asm.$O\
+ data.$O\
+ dwarf.$O\
elf.$O\
enam.$O\
+ go.$O\
+ ldelf.$O\
+ ldmacho.$O\
lib.$O\
list.$O\
macho.$O\
@@ -18,30 +23,26 @@ OFILES=\
optab.$O\
pass.$O\
pe.$O\
+ prof.$O\
span.$O\
- go.$O\
+ symtab.$O\
+
HFILES=\
l.h\
../8l/8.out.h\
+ ../ld/dwarf.h\
../ld/elf.h\
../ld/macho.h\
../ld/pe.h\
-
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
enam.c: 8.out.h
sh mkenam
-clean:
- rm -f *.$O $(TARG) *.8 enam.c 8.out a.out
+CLEANFILES+=enam.c
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
%.$O: ../ld/%.c
- $(CC) $(CFLAGS) -c -I. ../ld/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index a7f894aa2..cdb5a33e6 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -28,9 +28,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Writing object files.
+
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
+#include "../ld/dwarf.h"
#include "../ld/macho.h"
#include "../ld/pe.h"
@@ -38,7 +41,6 @@
char linuxdynld[] = "/lib/ld-linux.so.2";
char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
-uint32 symdatva = SYMDATVA;
int32
entryvalue(void)
@@ -52,15 +54,8 @@ entryvalue(void)
s = lookup(a, 0);
if(s->type == 0)
return INITTEXT;
- switch(s->type) {
- case STEXT:
- break;
- case SDATA:
- if(dlm)
- return s->value+INITDAT;
- default:
+ if(s->type != STEXT)
diag("entry not text: %s", s->name);
- }
return s->value;
}
@@ -103,134 +98,13 @@ vputl(uvlong l)
lputl(l);
}
-void
-strnput(char *s, int n)
-{
- for(; *s && n > 0; s++) {
- cput(*s);
- n--;
- }
- while(n > 0) {
- cput(0);
- n--;
- }
-}
-
-vlong
-addstring(Sym *s, char *str)
-{
- int n, m;
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- n = strlen(str)+1;
- while(n > 0) {
- m = n;
- if(m > sizeof(p->to.scon))
- m = sizeof(p->to.scon);
- p = newdata(s, s->value, m, D_EXTERN);
- p->to.type = D_SCONST;
- memmove(p->to.scon, str, m);
- s->value += m;
- str += m;
- n -= m;
- }
- return r;
-}
-
-vlong
-adduintxx(Sym *s, uint64 v, int wid)
-{
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, wid, D_EXTERN);
- s->value += wid;
- p->to.type = D_CONST;
- p->to.offset = v;
- return r;
-}
-
-vlong
-adduint8(Sym *s, uint8 v)
-{
- return adduintxx(s, v, 1);
-}
-
-vlong
-adduint16(Sym *s, uint16 v)
-{
- return adduintxx(s, v, 2);
-}
-
-vlong
-adduint32(Sym *s, uint32 v)
-{
- return adduintxx(s, v, 4);
-}
-
-vlong
-adduint64(Sym *s, uint64 v)
-{
- return adduintxx(s, v, 8);
-}
-
-vlong
-addaddr(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 4 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
-vlong
-addsize(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 4 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_SIZE;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
vlong
datoff(vlong addr)
{
- if(addr >= INITDAT) {
- if(HEADTYPE == 8)
- return addr - INITDAT + rnd(HEADR+textsize, 4096);
- return addr - INITDAT + rnd(HEADR+textsize, INITRND);
- }
+ if(addr >= segdata.vaddr)
+ return addr - segdata.vaddr + segdata.fileoff;
+ if(addr >= segtext.vaddr)
+ return addr - segtext.vaddr + segtext.fileoff;
diag("datoff %#llx", addr);
return 0;
}
@@ -252,6 +126,10 @@ enum {
ElfStrGosymtab,
ElfStrGopclntab,
ElfStrShstrtab,
+ ElfStrSymtab,
+ ElfStrStrtab,
+ ElfStrRelPlt,
+ ElfStrPlt,
NElfStr
};
@@ -273,26 +151,424 @@ needlib(char *name)
return 0;
}
+int nelfsym = 1;
+
+static void addpltsym(Sym*);
+static void addgotsym(Sym*);
+
+void
+adddynrel(Sym *s, Reloc *r)
+{
+ Sym *targ, *rel, *got;
+
+ targ = r->sym;
+ cursym = s;
+
+ switch(r->type) {
+ default:
+ if(r->type >= 256) {
+ diag("unexpected relocation type %d", r->type);
+ return;
+ }
+ break;
+
+ // Handle relocations found in ELF object files.
+ case 256 + R_386_PC32:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name);
+ if(targ->type == 0 || targ->type == SXREF)
+ diag("unknown symbol %s in pcrel", targ->name);
+ r->type = D_PCREL;
+ r->add += 4;
+ return;
+
+ case 256 + R_386_PLT32:
+ r->type = D_PCREL;
+ r->add += 4;
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add += targ->plt;
+ }
+ return;
+
+ case 256 + R_386_GOT32:
+ if(targ->dynimpname == nil || targ->dynexport) {
+ // have symbol
+ // turn MOVL of GOT entry into LEAL of symbol itself
+ if(r->off < 2 || s->p[r->off-2] != 0x8b) {
+ diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
+ return;
+ }
+ s->p[r->off-2] = 0x8d;
+ r->type = D_GOTOFF;
+ return;
+ }
+ addgotsym(targ);
+ r->type = D_CONST; // write r->add during relocsym
+ r->sym = S;
+ r->add += targ->got;
+ return;
+
+ case 256 + R_386_GOTOFF:
+ r->type = D_GOTOFF;
+ return;
+
+ case 256 + R_386_GOTPC:
+ r->type = D_PCREL;
+ r->sym = lookup(".got", 0);
+ r->add += 4;
+ return;
+
+ case 256 + R_386_32:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
+ r->type = D_ADDR;
+ return;
+
+ case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
+ r->type = D_ADDR;
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected reloc for dynamic symbol %s", targ->name);
+ return;
+
+ case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ r->type = D_PCREL;
+ return;
+ }
+ r->type = D_PCREL;
+ return;
+
+ case 512 + MACHO_FAKE_GOTPCREL:
+ if(targ->dynimpname == nil || targ->dynexport) {
+ // have symbol
+ // turn MOVL of GOT entry into LEAL of symbol itself
+ if(r->off < 2 || s->p[r->off-2] != 0x8b) {
+ diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
+ return;
+ }
+ s->p[r->off-2] = 0x8d;
+ r->type = D_PCREL;
+ return;
+ }
+ addgotsym(targ);
+ r->sym = lookup(".got", 0);
+ r->add += targ->got;
+ r->type = D_PCREL;
+ return;
+ }
+
+ // Handle references to ELF symbols from our own object files.
+ if(targ->dynimpname == nil || targ->dynexport)
+ return;
+
+ switch(r->type) {
+ case D_PCREL:
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ return;
+
+ case D_ADDR:
+ if(s->type != SDATA)
+ break;
+ if(iself) {
+ adddynsym(targ);
+ rel = lookup(".rel", 0);
+ addaddrplus(rel, s, r->off);
+ adduint32(rel, ELF32_R_INFO(targ->dynid, R_386_32));
+ r->type = D_CONST; // write r->add during relocsym
+ r->sym = S;
+ return;
+ }
+ if(HEADTYPE == 6 && s->size == PtrSize && r->off == 0) {
+ // Mach-O relocations are a royal pain to lay out.
+ // They use a compact stateful bytecode representation
+ // that is too much bother to deal with.
+ // Instead, interpret the C declaration
+ // void *_Cvar_stderr = &stderr;
+ // as making _Cvar_stderr the name of a GOT entry
+ // for stderr. This is separate from the usual GOT entry,
+ // just in case the C code assigns to the variable,
+ // and of course it only works for single pointers,
+ // but we only need to support cgo and that's all it needs.
+ adddynsym(targ);
+ got = lookup(".got", 0);
+ s->type = got->type | SSUB;
+ s->outer = got;
+ s->sub = got->sub;
+ got->sub = s;
+ s->value = got->size;
+ adduint32(got, 0);
+ adduint32(lookup(".linkedit.got", 0), targ->dynid);
+ r->type = 256; // ignore during relocsym
+ return;
+ }
+ break;
+ }
+
+ cursym = s;
+ diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
+}
+
+static void
+elfsetupplt(void)
+{
+ Sym *plt, *got;
+
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ if(plt->size == 0) {
+ // pushl got+4
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x35);
+ addaddrplus(plt, got, 4);
+
+ // jmp *got+8
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addaddrplus(plt, got, 8);
+
+ // zero pad
+ adduint32(plt, 0);
+
+ // assume got->size == 0 too
+ addaddrplus(got, lookup(".dynamic", 0), 0);
+ adduint32(got, 0);
+ adduint32(got, 0);
+ }
+}
+
+int
+archreloc(Reloc *r, Sym *s, vlong *val)
+{
+ switch(r->type) {
+ case D_CONST:
+ *val = r->add;
+ return 0;
+ case D_GOTOFF:
+ *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
+ return 0;
+ }
+ return -1;
+}
+
+static void
+addpltsym(Sym *s)
+{
+ Sym *plt, *got, *rel;
+
+ if(s->plt >= 0)
+ return;
+
+ adddynsym(s);
+
+ if(iself) {
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ rel = lookup(".rel.plt", 0);
+ if(plt->size == 0)
+ elfsetupplt();
+
+ // jmpq *got+size
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addaddrplus(plt, got, got->size);
+
+ // add to got: pointer to current pos in plt
+ addaddrplus(got, plt, plt->size);
+
+ // pushl $x
+ adduint8(plt, 0x68);
+ adduint32(plt, rel->size);
+
+ // jmp .plt
+ adduint8(plt, 0xe9);
+ adduint32(plt, -(plt->size+4));
+
+ // rel
+ addaddrplus(rel, got, got->size-4);
+ adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
+
+ s->plt = plt->size - 16;
+ } else if(HEADTYPE == 6) { // Mach-O
+ // Same laziness as in 6l.
+
+ Sym *plt;
+
+ plt = lookup(".plt", 0);
+
+ addgotsym(s);
+
+ adduint32(lookup(".linkedit.plt", 0), s->dynid);
+
+ // jmpq *got+size(IP)
+ s->plt = plt->size;
+
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addaddrplus(plt, lookup(".got", 0), s->got);
+ } else {
+ diag("addpltsym: unsupported binary format");
+ }
+}
+
+static void
+addgotsym(Sym *s)
+{
+ Sym *got, *rel;
+
+ if(s->got >= 0)
+ return;
+
+ adddynsym(s);
+ got = lookup(".got", 0);
+ s->got = got->size;
+ adduint32(got, 0);
+
+ if(iself) {
+ rel = lookup(".rel", 0);
+ addaddrplus(rel, got, s->got);
+ adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
+ } else if(HEADTYPE == 6) { // Mach-O
+ adduint32(lookup(".linkedit.got", 0), s->dynid);
+ } else {
+ diag("addgotsym: unsupported binary format");
+ }
+}
+
+void
+adddynsym(Sym *s)
+{
+ Sym *d, *str;
+ int t;
+ char *name;
+
+ if(s->dynid >= 0)
+ return;
+
+ if(s->dynimpname == nil)
+ diag("adddynsym: no dynamic name for %s", s->name, *(int32*)0);
+
+ if(iself) {
+ s->dynid = nelfsym++;
+
+ d = lookup(".dynsym", 0);
+
+ /* name */
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ adduint32(d, addstring(lookup(".dynstr", 0), name));
+
+ /* value */
+ if(s->type == SDYNIMPORT)
+ adduint32(d, 0);
+ else
+ addaddr(d, s);
+
+ /* size */
+ adduint32(d, 0);
+
+ /* type */
+ t = STB_GLOBAL << 4;
+ if(s->dynexport && s->type == STEXT)
+ t |= STT_FUNC;
+ else
+ t |= STT_OBJECT;
+ adduint8(d, t);
+ adduint8(d, 0);
+
+ /* shndx */
+ if(!s->dynexport && s->dynimpname != nil)
+ adduint16(d, SHN_UNDEF);
+ else {
+ switch(s->type) {
+ default:
+ case STEXT:
+ t = 11;
+ break;
+ case SRODATA:
+ t = 12;
+ break;
+ case SDATA:
+ t = 13;
+ break;
+ case SBSS:
+ t = 14;
+ break;
+ }
+ adduint16(d, t);
+ }
+ } else if(HEADTYPE == 6) {
+ // Mach-O symbol nlist32
+ d = lookup(".dynsym", 0);
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ s->dynid = d->size/12;
+ // darwin still puts _ prefixes on all C symbols
+ str = lookup(".dynstr", 0);
+ adduint32(d, str->size);
+ adduint8(str, '_');
+ addstring(str, name);
+ adduint8(d, 0x01); // type - N_EXT - external symbol
+ adduint8(d, 0); // section
+ adduint16(d, 0); // desc
+ adduint32(d, 0); // value
+ } else {
+ diag("adddynsym: unsupported binary format");
+ }
+}
+
+void
+adddynlib(char *lib)
+{
+ Sym *s;
+
+ if(!needlib(lib))
+ return;
+
+ if(iself) {
+ s = lookup(".dynstr", 0);
+ if(s->size == 0)
+ addstring(s, "");
+ elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ } else if(HEADTYPE == 6) { // Mach-O
+ machoadddynlib(lib);
+ } else {
+ diag("adddynlib: unsupported binary format");
+ }
+}
+
void
doelf(void)
{
- Sym *s, *shstrtab, *dynamic, *dynstr, *d;
- int h, nsym, t;
+ Sym *s, *shstrtab, *dynstr;
if(!iself)
return;
/* predefine strings we need for section headers */
shstrtab = lookup(".shstrtab", 0);
+ shstrtab->type = SELFDATA;
shstrtab->reachable = 1;
+
elfstr[ElfStrEmpty] = addstring(shstrtab, "");
elfstr[ElfStrText] = addstring(shstrtab, ".text");
elfstr[ElfStrData] = addstring(shstrtab, ".data");
elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+ addstring(shstrtab, ".elfdata");
+ addstring(shstrtab, ".rodata");
if(!debug['s']) {
elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab");
elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab");
+ dwarfaddshstrings(shstrtab);
}
elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
@@ -305,6 +581,8 @@ doelf(void)
elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
+ elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
+ elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
/* interpreter string */
s = lookup(".interp", 0);
@@ -315,13 +593,14 @@ doelf(void)
s = lookup(".dynsym", 0);
s->type = SELFDATA;
s->reachable = 1;
- s->value += ELF32SYMSIZE;
+ s->size += ELF32SYMSIZE;
/* dynamic string table */
s = lookup(".dynstr", 0);
s->reachable = 1;
s->type = SELFDATA;
- addstring(s, "");
+ if(s->size == 0)
+ addstring(s, "");
dynstr = s;
/* relocation table */
@@ -332,88 +611,36 @@ doelf(void)
/* global offset table */
s = lookup(".got", 0);
s->reachable = 1;
+ s->type = SDATA; // writable, so not SELFDATA
+
+ /* hash */
+ s = lookup(".hash", 0);
+ s->reachable = 1;
s->type = SELFDATA;
- /* got.plt - ??? */
+ /* got.plt */
s = lookup(".got.plt", 0);
s->reachable = 1;
+ s->type = SDATA; // writable, so not SELFDATA
+
+ s = lookup(".plt", 0);
+ s->reachable = 1;
s->type = SELFDATA;
- /* define dynamic elf table */
- s = lookup(".dynamic", 0);
+ s = lookup(".rel.plt", 0);
s->reachable = 1;
s->type = SELFDATA;
- dynamic = s;
- /*
- * relocation entries for dynimport symbols
- */
- nsym = 1; // sym 0 is reserved
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->link) {
- if(!s->reachable || (s->type != STEXT && s->type != SDATA && s->type != SBSS) || s->dynimpname == nil)
- continue;
-
- if(!s->dynexport) {
- d = lookup(".rel", 0);
- addaddr(d, s);
- adduint32(d, ELF32_R_INFO(nsym, R_386_32));
- }
-
- nsym++;
-
- d = lookup(".dynsym", 0);
- adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname));
- /* value */
- if(!s->dynexport)
- adduint32(d, 0);
- else
- addaddr(d, s);
-
- /* size of object */
- adduint32(d, 0);
-
- /* type */
- t = STB_GLOBAL << 4;
- if(s->dynexport && s->type == STEXT)
- t |= STT_FUNC;
- else
- t |= STT_OBJECT;
- adduint8(d, t);
-
- /* reserved */
- adduint8(d, 0);
-
- /* section where symbol is defined */
- if(!s->dynexport)
- adduint16(d, SHN_UNDEF);
- else {
- switch(s->type) {
- default:
- case STEXT:
- t = 9;
- break;
- case SDATA:
- t = 10;
- break;
- case SBSS:
- t = 11;
- break;
- }
- adduint16(d, t);
- }
-
- if(!s->dynexport && needlib(s->dynimplib))
- elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib));
- }
- }
+ elfsetupplt();
- elfdynhash(nsym);
+ /* define dynamic elf table */
+ s = lookup(".dynamic", 0);
+ s->reachable = 1;
+ s->type = SELFDATA;
/*
* .dynamic table
*/
- s = dynamic;
elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
@@ -424,6 +651,10 @@ doelf(void)
elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
+ elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
+ elfwritedynent(s, DT_PLTREL, DT_REL);
+ elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
+ elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
elfwritedynent(s, DT_NULL, 0);
}
}
@@ -450,155 +681,52 @@ phsh(Elf64_Phdr *ph, Elf64_Shdr *sh)
void
asmb(void)
{
- Prog *p;
int32 v, magic;
int a, dynsym;
uint32 va, fo, w, symo, startva, machlink;
- uchar *op1;
- ulong expectpc;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
+ Section *sect;
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
Bflush(&bso);
- seek(cout, HEADR, 0);
- pc = INITTEXT;
- curp = firstp;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- curp = p;
- if(HEADTYPE == 8) {
- // native client
- expectpc = p->pc;
- p->pc = pc;
- asmins(p);
- if(p->pc != expectpc) {
- Bflush(&bso);
- diag("phase error %lux sb %lux in %s", p->pc, expectpc, TNAME);
- }
- while(pc < p->pc) {
- cput(0x90); // nop
- pc++;
- }
- }
- if(p->pc != pc) {
- Bflush(&bso);
- if(!debug['a'])
- print("%P\n", curp);
- diag("phase error %lux sb %lux in %s", p->pc, pc, TNAME);
- pc = p->pc;
- }
- if(HEADTYPE != 8) {
- asmins(p);
- if(pc != p->pc) {
- Bflush(&bso);
- diag("asmins changed pc %lux sb %lux in %s", p->pc, pc, TNAME);
- }
- }
- if(cbc < sizeof(and))
- cflush();
- a = (andptr - and);
-
- if(debug['a']) {
- Bprint(&bso, pcstr, pc);
- for(op1 = and; op1 < andptr; op1++)
- Bprint(&bso, "%.2ux", *op1 & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- }
- if(dlm) {
- if(p->as == ATEXT)
- reloca = nil;
- else if(reloca != nil)
- diag("reloc failure: %P", curp);
- }
- memmove(cbp, and, a);
- cbp += a;
- pc += a;
- cbc -= a;
- }
- if(HEADTYPE == 8) {
- while(pc < INITDAT) {
- cput(0xf4); // hlt
- pc++;
- }
- }
- cflush();
+ sect = segtext.sect;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ codeblk(sect->vaddr, sect->len);
- switch(HEADTYPE) {
- default:
- if(iself)
- goto Elfseek;
- diag("unknown header type %d", HEADTYPE);
- case 0:
- seek(cout, rnd(HEADR+textsize, 8192), 0);
- break;
- case 1:
- textsize = rnd(HEADR+textsize, 4096)-HEADR;
- seek(cout, textsize+HEADR, 0);
- break;
- case 2:
- seek(cout, HEADR+textsize, 0);
- break;
- case 3:
- case 4:
- seek(cout, HEADR+rnd(textsize, INITRND), 0);
- break;
- case 6:
- v = HEADR+textsize;
- seek(cout, v, 0);
- v = rnd(v, 4096) - v;
- while(v > 0) {
- cput(0);
- v--;
- }
- cflush();
- break;
- case 8:
- // Native Client only needs to round
- // text segment file address to 4096 bytes,
- // but text segment memory address rounds
- // to INITRND (65536).
- v = rnd(HEADR+textsize, 4096);
- seek(cout, v, 0);
- break;
- Elfseek:
- case 10:
- v = rnd(HEADR+textsize, INITRND);
- seek(cout, v, 0);
- break;
- }
+ /* output read-only data in text segment */
+ sect = segtext.sect->next;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ datblk(sect->vaddr, sect->len);
if(debug['v'])
Bprint(&bso, "%5.2f datblk\n", cputime());
Bflush(&bso);
- if(dlm){
- char buf[8];
-
- write(cout, buf, INITDAT-textsize);
- textsize = INITDAT;
- }
-
- for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) {
- if(datsize-v > sizeof(buf)-Dbufslop)
- datblk(v, sizeof(buf)-Dbufslop);
- else
- datblk(v, datsize-v);
- }
+ seek(cout, segdata.fileoff, 0);
+ datblk(segdata.vaddr, segdata.filelen);
machlink = 0;
if(HEADTYPE == 6)
machlink = domacholink();
+ if(iself) {
+ /* index of elf text section; needed by asmelfsym, double-checked below */
+ /* !debug['d'] causes extra sections before the .text section */
+ elftextsh = 1;
+ if(!debug['d'])
+ elftextsh += 10;
+ }
+
symsize = 0;
spsize = 0;
lcsize = 0;
symo = 0;
if(!debug['s']) {
+ // TODO: rationalize
if(debug['v'])
Bprint(&bso, "%5.2f sym\n", cputime());
Bflush(&bso);
@@ -607,53 +735,38 @@ asmb(void)
if(iself)
goto Elfsym;
case 0:
- seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0);
+ seek(cout, rnd(HEADR+segtext.filelen, 8192)+segdata.filelen, 0);
break;
case 1:
- seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
+ seek(cout, rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen, 0);
break;
case 2:
- seek(cout, HEADR+textsize+datsize, 0);
+ seek(cout, HEADR+segtext.filelen+segdata.filelen, 0);
break;
case 3:
case 4:
debug['s'] = 1;
- symo = HEADR+textsize+datsize;
+ symo = HEADR+segtext.filelen+segdata.filelen;
break;
case 6:
- symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND)+machlink;
+ symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
break;
Elfsym:
- case 10:
- symo = rnd(HEADR+textsize, INITRND)+datsize;
+ symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
symo = rnd(symo, INITRND);
break;
+ case 10:
+ // TODO(brainman): not sure what symo meant to be, but it is not used for Windows PE for now anyway
+ symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
+ symo = rnd(symo, PEFILEALIGN);
+ break;
+ }
+ if(HEADTYPE != 10 && !debug['s']) {
+ seek(cout, symo, 0);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+ dwarfemitdebugsections();
}
- seek(cout, symo+8, 0);
- if(!debug['s'])
- asmsym();
- if(debug['v'])
- Bprint(&bso, "%5.2f sp\n", cputime());
- Bflush(&bso);
- if(debug['v'])
- Bprint(&bso, "%5.2f pc\n", cputime());
- Bflush(&bso);
- if(!debug['s'])
- asmlc();
- if(dlm)
- asmdyn();
- if(HEADTYPE == 10 || (iself && !debug['s']))
- strnput("", INITRND-(8+symsize+lcsize)%INITRND);
- cflush();
- seek(cout, symo, 0);
- lputl(symsize);
- lputl(lcsize);
- cflush();
- }
- else if(dlm){
- seek(cout, HEADR+textsize+datsize, 0);
- asmdyn();
- cflush();
}
if(debug['v'])
Bprint(&bso, "%5.2f headr\n", cputime());
@@ -666,17 +779,17 @@ asmb(void)
case 0: /* garbage */
lput(0x160L<<16); /* magic and sections */
lput(0L); /* time and date */
- lput(rnd(HEADR+textsize, 4096)+datsize);
+ lput(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen);
lput(symsize); /* nsyms */
lput((0x38L<<16)|7L); /* size of optional hdr and flags */
lput((0413<<16)|0437L); /* magic and version */
- lput(rnd(HEADR+textsize, 4096)); /* sizes */
- lput(datsize);
- lput(bsssize);
+ lput(rnd(HEADR+segtext.filelen, 4096)); /* sizes */
+ lput(segdata.filelen);
+ lput(segdata.len - segdata.filelen);
lput(entryvalue()); /* va of entry */
lput(INITTEXT-HEADR); /* va of base of text */
- lput(INITDAT); /* va of base of data */
- lput(INITDAT+datsize); /* va of base of bss */
+ lput(segdata.vaddr); /* va of base of data */
+ lput(segdata.vaddr+segdata.filelen); /* va of base of bss */
lput(~0L); /* gp reg mask */
lput(0L);
lput(0L);
@@ -698,19 +811,19 @@ asmb(void)
* a.out header
*/
lputl(0x10b); /* magic, version stamp */
- lputl(rnd(textsize, INITRND)); /* text sizes */
- lputl(datsize); /* data sizes */
- lputl(bsssize); /* bss sizes */
+ lputl(rnd(segtext.filelen, INITRND)); /* text sizes */
+ lputl(segdata.filelen); /* data sizes */
+ lputl(segdata.len - segdata.filelen); /* bss sizes */
lput(entryvalue()); /* va of entry */
lputl(INITTEXT); /* text start */
- lputl(INITDAT); /* data start */
+ lputl(segdata.vaddr); /* data start */
/*
* text section header
*/
s8put(".text");
lputl(HEADR); /* pa */
lputl(HEADR); /* va */
- lputl(textsize); /* text size */
+ lputl(segtext.filelen); /* text size */
lputl(HEADR); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
@@ -720,10 +833,10 @@ asmb(void)
* data section header
*/
s8put(".data");
- lputl(INITDAT); /* pa */
- lputl(INITDAT); /* va */
- lputl(datsize); /* data size */
- lputl(HEADR+textsize); /* file offset */
+ lputl(segdata.vaddr); /* pa */
+ lputl(segdata.vaddr); /* va */
+ lputl(segdata.filelen); /* data size */
+ lputl(HEADR+segtext.filelen); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
lputl(0); /* relocation, line numbers */
@@ -732,9 +845,9 @@ asmb(void)
* bss section header
*/
s8put(".bss");
- lputl(INITDAT+datsize); /* pa */
- lputl(INITDAT+datsize); /* va */
- lputl(bsssize); /* bss size */
+ lputl(segdata.vaddr+segdata.filelen); /* pa */
+ lputl(segdata.vaddr+segdata.filelen); /* va */
+ lputl(segdata.len - segdata.filelen); /* bss size */
lputl(0); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
@@ -747,20 +860,18 @@ asmb(void)
lputl(0); /* pa */
lputl(0); /* va */
lputl(symsize+lcsize); /* comment size */
- lputl(HEADR+textsize+datsize); /* file offset */
- lputl(HEADR+textsize+datsize); /* offset of syms */
- lputl(HEADR+textsize+datsize+symsize);/* offset of line numbers */
+ lputl(HEADR+segtext.filelen+segdata.filelen); /* file offset */
+ lputl(HEADR+segtext.filelen+segdata.filelen); /* offset of syms */
+ lputl(HEADR+segtext.filelen+segdata.filelen+symsize);/* offset of line numbers */
lputl(0); /* relocation, line numbers */
lputl(0x200); /* flags comment only */
break;
case 2: /* plan9 */
magic = 4*11*11+7;
- if(dlm)
- magic |= 0x80000000;
lput(magic); /* magic */
- lput(textsize); /* sizes */
- lput(datsize);
- lput(bsssize);
+ lput(segtext.filelen); /* sizes */
+ lput(segdata.filelen);
+ lput(segdata.len - segdata.filelen);
lput(symsize); /* nsyms */
lput(entryvalue()); /* va of entry */
lput(spsize); /* sp offsets */
@@ -771,7 +882,7 @@ asmb(void)
break;
case 4:
/* fake MS-DOS .EXE */
- v = rnd(HEADR+textsize, INITRND)+datsize;
+ v = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
wputl(0x5A4D); /* 'MZ' */
wputl(v % 512); /* bytes in last page */
wputl(rnd(v, 512)/512); /* total number of pages */
@@ -793,34 +904,31 @@ asmb(void)
break;
case 6:
- asmbmacho(symdatva, symo);
+ asmbmacho();
break;
Elfput:
/* elf 386 */
- if(HEADTYPE == 8 || HEADTYPE == 11)
+ if(HEADTYPE == 11)
debug['d'] = 1;
eh = getElfEhdr();
fo = HEADR;
startva = INITTEXT - HEADR;
va = startva + fo;
- w = textsize;
+ w = segtext.filelen;
/* This null SHdr must appear before all others */
sh = newElfShdr(elfstr[ElfStrEmpty]);
- /* program header info - but not on native client */
- pph = nil;
- if(HEADTYPE != 8) {
- pph = newElfPhdr();
- pph->type = PT_PHDR;
- pph->flags = PF_R + PF_X;
- pph->off = eh->ehsize;
- pph->vaddr = INITTEXT - HEADR + pph->off;
- pph->paddr = INITTEXT - HEADR + pph->off;
- pph->align = INITRND;
- }
+ /* program header info */
+ pph = newElfPhdr();
+ pph->type = PT_PHDR;
+ pph->flags = PF_R + PF_X;
+ pph->off = eh->ehsize;
+ pph->vaddr = INITTEXT - HEADR + pph->off;
+ pph->paddr = INITTEXT - HEADR + pph->off;
+ pph->align = INITRND;
if(!debug['d']) {
/* interpreter */
@@ -843,51 +951,8 @@ asmb(void)
phsh(ph, sh);
}
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_X+PF_R;
- if(HEADTYPE != 8) { // Include header, but not on Native Client.
- va -= fo;
- w += fo;
- fo = 0;
- }
- ph->vaddr = va;
- ph->paddr = va;
- ph->off = fo;
- ph->filesz = w;
- ph->memsz = INITDAT - va;
- ph->align = INITRND;
-
- // NaCl text segment file address rounds to 4096;
- // only memory address rounds to INITRND.
- if(HEADTYPE == 8)
- fo = rnd(fo+w, 4096);
- else
- fo = rnd(fo+w, INITRND);
- va = INITDAT;
- w = datsize;
-
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_W+PF_R;
- ph->off = fo;
- ph->vaddr = va;
- ph->paddr = va;
- ph->filesz = w;
- ph->memsz = w+bsssize;
- ph->align = INITRND;
-
- if(!debug['s'] && HEADTYPE != 8 && HEADTYPE != 11) {
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_R;
- ph->off = symo;
- ph->vaddr = symdatva;
- ph->paddr = symdatva;
- ph->filesz = rnd(8+symsize+lcsize, INITRND);
- ph->memsz = rnd(8+symsize+lcsize, INITRND);
- ph->align = INITRND;
- }
+ elfphload(&segtext);
+ elfphload(&segdata);
/* Dynamic linking sections */
if (!debug['d']) { /* -d suppresses dynamic loader format */
@@ -921,6 +986,22 @@ asmb(void)
sh->flags = SHF_ALLOC;
sh->addralign = 1;
shsym(sh, lookup(".dynstr", 0));
+
+ sh = newElfShdr(elfstr[ElfStrRelPlt]);
+ sh->type = SHT_REL;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = ELF32RELSIZE;
+ sh->addralign = 4;
+ sh->link = dynsym;
+ sh->info = eh->shnum; // .plt
+ shsym(sh, lookup(".rel.plt", 0));
+
+ sh = newElfShdr(elfstr[ElfStrPlt]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC+SHF_EXECINSTR;
+ sh->entsize = 4;
+ sh->addralign = 4;
+ shsym(sh, lookup(".plt", 0));
sh = newElfShdr(elfstr[ElfStrHash]);
sh->type = SHT_HASH;
@@ -968,80 +1049,27 @@ asmb(void)
ph->flags = PF_W+PF_R;
ph->align = 4;
- fo = HEADR;
- va = startva + fo;
- w = textsize;
-
- sh = newElfShdr(elfstr[ElfStrText]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_EXECINSTR;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 4;
-
- // NaCl text segment file address rounds to 4096;
- // only memory address rounds to INITRND.
- if(HEADTYPE == 8)
- fo = rnd(fo+w, 4096);
- else
- fo = rnd(fo+w, INITRND);
- va = rnd(va+w, INITRND);
- w = datsize;
-
- sh = newElfShdr(elfstr[ElfStrData]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va + elfdatsize;
- sh->off = fo + elfdatsize;
- sh->size = w - elfdatsize;
- sh->addralign = 4;
-
- fo += w;
- va += w;
- w = bsssize;
-
- sh = newElfShdr(elfstr[ElfStrBss]);
- sh->type = SHT_NOBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 4;
+ if(elftextsh != eh->shnum)
+ diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
+ for(sect=segtext.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
+ for(sect=segdata.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
if (!debug['s']) {
- fo = symo;
- w = 8;
-
- sh = newElfShdr(elfstr[ElfStrGosymcounts]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 1;
- sh->addr = symdatva;
-
- fo += w;
- w = symsize;
-
sh = newElfShdr(elfstr[ElfStrGosymtab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva + 8;
-
- fo += w;
- w = lcsize;
+ shsym(sh, lookup("symtab", 0));
sh = newElfShdr(elfstr[ElfStrGopclntab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva + 8 + symsize;
+ shsym(sh, lookup("pclntab", 0));
+
+ dwarfaddelfheaders();
}
sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
@@ -1058,11 +1086,6 @@ asmb(void)
eh->ident[EI_DATA] = ELFDATA2LSB;
eh->ident[EI_VERSION] = EV_CURRENT;
switch(HEADTYPE) {
- case 8:
- eh->ident[EI_OSABI] = ELFOSABI_NACL;
- eh->ident[EI_ABIVERSION] = 7;
- eh->flags = 0x200000; // aligned mod 32
- break;
case 9:
eh->ident[EI_OSABI] = 9;
break;
@@ -1113,215 +1136,16 @@ cflush(void)
n = sizeof(buf.cbuf) - cbc;
if(n)
- write(cout, buf.cbuf, n);
+ ewrite(cout, buf.cbuf, n);
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
}
-void
-datblk(int32 s, int32 n)
+/* Current position in file */
+vlong
+cpos(void)
{
- Prog *p;
- char *cast;
- int32 l, fl, j;
- int i, c;
- Adr *a;
-
- memset(buf.dbuf, 0, n+Dbufslop);
- for(p = datap; p != P; p = p->link) {
- a = &p->from;
-
- l = a->sym->value + a->offset - s;
- if(l >= n)
- continue;
-
- c = a->scale;
- i = 0;
- if(l < 0) {
- if(l+c <= 0)
- continue;
- i = -l;
- l = 0;
- }
-
- curp = p;
- if(!a->sym->reachable)
- diag("unreachable symbol in datblk - %s", a->sym->name);
- if(a->sym->type == SMACHO)
- continue;
-
- if(p->as != AINIT && p->as != ADYNT) {
- for(j=l+(c-i)-1; j>=l; j--)
- if(buf.dbuf[j]) {
- print("%P\n", p);
- diag("multiple initialization");
- break;
- }
- }
- switch(p->to.type) {
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (char*)&fl;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi4[i]];
- l++;
- }
- break;
- case 8:
- cast = (char*)&p->to.ieee;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi8[i]];
- l++;
- }
- break;
- }
- break;
-
- case D_SCONST:
- for(; i<c; i++) {
- buf.dbuf[l] = p->to.scon[i];
- l++;
- }
- break;
-
- default:
- fl = p->to.offset;
- if(p->to.type == D_SIZE)
- fl += p->to.sym->size;
- if(p->to.type == D_ADDR) {
- if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
- diag("DADDR type%P", p);
- if(p->to.sym) {
- if(p->to.sym->type == SUNDEF)
- ckoff(p->to.sym, fl);
- fl += p->to.sym->value;
- if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
- fl += INITDAT;
- if(dlm)
- dynreloc(p->to.sym, l+s+INITDAT, 1);
- }
- }
- cast = (char*)&fl;
- switch(c) {
- default:
- diag("bad nuxi %d %d\n%P", c, i, curp);
- break;
- case 1:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi1[i]];
- l++;
- }
- break;
- case 2:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi2[i]];
- l++;
- }
- break;
- case 4:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi4[i]];
- l++;
- }
- break;
- }
- break;
- }
- }
-
- write(cout, buf.dbuf, n);
- if(!debug['a'])
- return;
-
- /*
- * a second pass just to print the asm
- */
- for(p = datap; p != P; p = p->link) {
- a = &p->from;
-
- l = a->sym->value + a->offset - s;
- if(l < 0 || l >= n)
- continue;
-
- c = a->scale;
- i = 0;
-
- switch(p->to.type) {
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (char*)&fl;
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[fnuxi4[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- case 8:
- cast = (char*)&p->to.ieee;
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- }
- break;
-
- case D_SCONST:
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
-
- default:
- fl = p->to.offset;
- if(p->to.type == D_SIZE)
- fl += p->to.sym->size;
- if(p->to.type == D_ADDR) {
- if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
- diag("DADDR type%P", p);
- if(p->to.sym) {
- if(p->to.sym->type == SUNDEF)
- ckoff(p->to.sym, fl);
- fl += p->to.sym->value;
- if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
- fl += INITDAT;
- if(dlm)
- dynreloc(p->to.sym, l+s+INITDAT, 1);
- }
- }
- cast = (char*)&fl;
- switch(c) {
- default:
- diag("bad nuxi %d %d\n%P", c, i, curp);
- break;
- case 1:
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[inuxi1[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- case 2:
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[inuxi2[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- case 4:
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[inuxi4[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- }
- break;
- }
- }
+ return seek(cout, 0, 1) + sizeof(buf.cbuf) - cbc;
}
int32
@@ -1338,3 +1162,71 @@ rnd(int32 v, int32 r)
v -= c;
return v;
}
+
+void
+genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+{
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ put(s, s->name, 'T', s->value, s->size, s->version, 0);
+
+ for(h=0; h<NHASH; h++) {
+ for(s=hash[h]; s!=S; s=s->hash) {
+ switch(s->type&~SSUB) {
+ case SCONST:
+ case SRODATA:
+ case SDATA:
+ case SELFDATA:
+ case SMACHO:
+ case SMACHOGOT:
+ case SWINDOWS:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
+ continue;
+
+ case SBSS:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
+ continue;
+
+ case SFILE:
+ put(nil, s->name, 'f', s->value, 0, s->version, 0);
+ continue;
+ }
+ }
+ }
+
+ for(s = textp; s != nil; s = s->next) {
+ if(s->text == nil)
+ continue;
+
+ /* filenames first */
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_FILE)
+ put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
+ else
+ if(a->type == D_FILE1)
+ put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
+
+ put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
+
+ /* frame, auto and param after */
+ put(nil, ".frame", 'm', s->text->to.offset+4, 0, 0, 0);
+
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
+ else
+ if(a->type == D_PARAM)
+ put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %ud\n", symsize);
+ Bflush(&bso);
+}
diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go
index c8c058684..0bf6f151f 100644
--- a/src/cmd/8l/doc.go
+++ b/src/cmd/8l/doc.go
@@ -29,8 +29,8 @@ Options new in this version:
Write Apple Mach-O binaries (default when $GOOS is darwin)
-H7
Write Linux ELF binaries (default when $GOOS is linux)
--L dir1,dir2,..
- Search for libraries (package files) in the comma-separated list of directories.
+-L dir1 -L dir2
+ Search for libraries (package files) in dir1, dir2, etc.
The default is the single location $GOROOT/pkg/$GOOS_386.
-r dir1:dir2:...
Set the dynamic linker search path when using ELF.
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index 495c40d64..daede8879 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -44,7 +44,7 @@ enum
#define P ((Prog*)0)
#define S ((Sym*)0)
-#define TNAME (curtext?curtext->from.sym->name:noname)
+#define TNAME (cursym?cursym->name:noname)
#define cput(c)\
{ *cbp++ = c;\
if(--cbc <= 0)\
@@ -55,6 +55,7 @@ typedef struct Prog Prog;
typedef struct Sym Sym;
typedef struct Auto Auto;
typedef struct Optab Optab;
+typedef struct Reloc Reloc;
struct Adr
{
@@ -66,11 +67,7 @@ struct Adr
Ieee u0ieee;
char *u0sbig;
} u0;
- union
- {
- Auto* u1autom;
- Sym* u1sym;
- } u1;
+ Sym* sym;
short type;
uchar index;
char scale;
@@ -83,18 +80,25 @@ struct Adr
#define ieee u0.u0ieee
#define sbig u0.u0sbig
-#define autom u1.u1autom
-#define sym u1.u1sym
+struct Reloc
+{
+ int32 off;
+ uchar siz;
+ int32 type;
+ int32 add;
+ Sym* sym;
+};
struct Prog
{
Adr from;
Adr to;
- Prog *forwd;
+ Prog* forwd;
+ Prog* comefrom;
Prog* link;
- Prog* dlink;
Prog* pcond; /* work on this */
int32 pc;
+ int32 spadj;
int32 line;
short as;
char width; /* fake for DATA */
@@ -103,8 +107,10 @@ struct Prog
uchar mark; /* work on these */
uchar back;
uchar bigjmp;
-
};
+#define datasize from.scale
+#define textflag from.scale
+
struct Auto
{
Sym* asym;
@@ -115,25 +121,39 @@ struct Auto
};
struct Sym
{
- char *name;
+ char* name;
short type;
short version;
- short become;
- short frame;
- uchar subtype;
uchar dupok;
uchar reachable;
uchar dynexport;
+ uchar special;
int32 value;
int32 size;
int32 sig;
- Sym* link;
- Prog* text;
- Prog* data;
+ int32 dynid;
+ int32 plt;
+ int32 got;
+ Sym* hash; // in hash table
+ Sym* next; // in text or data list
+ Sym* sub; // in sub list
+ Sym* outer; // container of sub
Sym* gotype;
char* file;
char* dynimpname;
char* dynimplib;
+
+ // STEXT
+ Auto* autom;
+ Prog* text;
+
+ // SDATA, SBSS
+ uchar* p;
+ int32 np;
+ int32 maxp;
+ Reloc* r;
+ int32 nr;
+ int32 maxr;
};
struct Optab
{
@@ -146,23 +166,28 @@ struct Optab
enum
{
Sxxx,
-
+
+ /* order here is order in output file */
STEXT,
+ SELFDATA,
+ SMACHOPLT,
+ SRODATA,
SDATA,
+ SMACHO, /* Mach-O __nl_symbol_ptr */
+ SMACHOGOT,
+ SWINDOWS,
SBSS,
- SDATA1,
+
SXREF,
+ SMACHODYNSTR,
+ SMACHODYNSYM,
+ SMACHOINDIRECTPLT,
+ SMACHOINDIRECTGOT,
SFILE,
SCONST,
- SUNDEF,
-
- SIMPORT,
- SEXPORT,
+ SDYNIMPORT,
- SMACHO, /* pointer to mach-o imported symbol */
-
- SFIXED,
- SELFDATA,
+ SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */
NHASH = 10007,
NHUNK = 100000,
@@ -240,9 +265,6 @@ enum
Pm = 0x0f, /* 2byte opcode escape */
Pq = 0xff, /* both escape */
Pb = 0xfe, /* byte operands */
-
- Roffset = 22, /* no. bits for offset in relocation address */
- Rindex = 10, /* no. bits for index in relocation address */
};
EXTERN union
@@ -266,12 +288,11 @@ EXTERN union
EXTERN int32 HEADR;
EXTERN int32 HEADTYPE;
-EXTERN int32 INITDAT;
EXTERN int32 INITRND;
EXTERN int32 INITTEXT;
+EXTERN int32 INITDAT;
EXTERN char* INITENTRY; /* entry point */
EXTERN Biobuf bso;
-EXTERN int32 bsssize;
EXTERN int32 casepc;
EXTERN int cbc;
EXTERN char* cbp;
@@ -279,22 +300,17 @@ EXTERN char* pcstr;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
-EXTERN Prog* curtext;
-EXTERN Prog* datap;
-EXTERN Prog* edatap;
-EXTERN int32 datsize;
+EXTERN Sym* cursym;
+EXTERN Sym* datap;
EXTERN int32 elfdatsize;
-EXTERN int32 dynptrsize;
EXTERN char debug[128];
EXTERN char literal[32];
-EXTERN Prog* etextp;
+EXTERN Sym* etextp;
EXTERN Prog* firstp;
-EXTERN int xrefresolv;
EXTERN uchar ycover[Ymax*Ymax];
EXTERN uchar* andptr;
EXTERN uchar and[100];
EXTERN char reg[D_NONE];
-EXTERN Prog* lastp;
EXTERN int32 lcsize;
EXTERN int maxop;
EXTERN int nerrors;
@@ -304,30 +320,22 @@ EXTERN char* rpath;
EXTERN int32 spsize;
EXTERN Sym* symlist;
EXTERN int32 symsize;
-EXTERN Prog* textp;
+EXTERN Sym* textp;
EXTERN int32 textsize;
-EXTERN int32 textpad;
EXTERN int version;
EXTERN Prog zprg;
EXTERN int dtype;
EXTERN int tlsoffset;
EXTERN Sym* adrgotype; // type symbol on last Adr read
EXTERN Sym* fromgotype; // type symbol on last p->from read
-
-EXTERN Adr* reloca;
-EXTERN int doexp, dlm;
-EXTERN int imports, nimports;
-EXTERN int exports, nexports;
-EXTERN char* EXPTAB;
-EXTERN Prog undefp;
-
-#define UP (&undefp)
+EXTERN int elftextsh;
extern Optab optab[];
extern char* anames[];
int Aconv(Fmt*);
int Dconv(Fmt*);
+int Iconv(Fmt*);
int Pconv(Fmt*);
int Rconv(Fmt*);
int Sconv(Fmt*);
@@ -336,29 +344,23 @@ Prog* appendp(Prog*);
void asmb(void);
void asmdyn(void);
void asmins(Prog*);
-void asmlc(void);
-void asmsp(void);
void asmsym(void);
int32 atolwhex(char*);
Prog* brchain(Prog*);
Prog* brloop(Prog*);
void cflush(void);
-void ckoff(Sym*, int32);
Prog* copyp(Prog*);
+vlong cpos(void);
double cputime(void);
-void datblk(int32, int32);
void diag(char*, ...);
void dodata(void);
void doelf(void);
-void doinit(void);
void doprof1(void);
void doprof2(void);
void dostkoff(void);
-void dynreloc(Sym*, uint32, int);
int32 entryvalue(void);
-void export(void);
void follow(void);
-void import(void);
+void instinit(void);
void listinit(void);
Sym* lookup(char*, int);
void lput(int32);
@@ -366,26 +368,20 @@ void lputl(int32);
void vputl(uvlong);
void strnput(char*, int);
void main(int, char*[]);
-void mkfwd(void);
void* mal(uint32);
-Prog* newdata(Sym*, int, int, int);
-Prog* newtext(Prog*, Sym*);
int opsize(Prog*);
void patch(void);
Prog* prg(void);
int relinv(int);
-int32 reuse(Prog*, Sym*);
int32 rnd(int32, int32);
void s8put(char*);
void span(void);
void undef(void);
-int32 vaddr(Adr*);
int32 symaddr(Sym*);
void wput(ushort);
void wputl(ushort);
void xdefine(char*, int, int32);
-void xfol(Prog*);
-void zaddr(Biobuf*, Adr*, Sym*[]);
+
uint32 machheadr(void);
vlong addaddr(Sym *s, Sym *t);
vlong addsize(Sym *s, Sym *t);
@@ -410,3 +406,9 @@ void deadcode(void);
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "A" int
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+ DWARFREGSP = 4
+};
diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c
index a5dbba7f8..4e199d767 100644
--- a/src/cmd/8l/list.c
+++ b/src/cmd/8l/list.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Printing.
+
#include "l.h"
#include "../ld/lib.h"
@@ -40,6 +42,7 @@ listinit(void)
fmtinstall('D', Dconv);
fmtinstall('S', Sconv);
fmtinstall('P', Pconv);
+ fmtinstall('I', Iconv);
}
static Prog *bigP;
@@ -47,7 +50,6 @@ static Prog *bigP;
int
Pconv(Fmt *fp)
{
- char str[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
@@ -55,23 +57,23 @@ Pconv(Fmt *fp)
switch(p->as) {
case ATEXT:
if(p->from.scale) {
- sprint(str, "(%d) %A %D,%d,%D",
+ fmtprint(fp, "(%d) %A %D,%d,%D",
p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
default:
- sprint(str, "(%d) %A %D,%D",
+ fmtprint(fp, "(%d) %A %D,%D",
p->line, p->as, &p->from, &p->to);
break;
case ADATA:
- case AINIT:
- case ADYNT:
- sprint(str, "(%d) %A %D/%d,%D",
+ case AINIT_:
+ case ADYNT_:
+ fmtprint(fp, "(%d) %A %D/%d,%D",
p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
bigP = P;
- return fmtstrcpy(fp, str);
+ return 0;
}
int
@@ -102,15 +104,15 @@ Dconv(Fmt *fp)
i = a->type;
if(i >= D_INDIR && i < 2*D_INDIR) {
if(a->offset)
- sprint(str, "%ld(%R)", a->offset, i-D_INDIR);
+ snprint(str, sizeof str, "%d(%R)", a->offset, i-D_INDIR);
else
- sprint(str, "(%R)", i-D_INDIR);
+ snprint(str, sizeof str, "(%R)", i-D_INDIR);
goto brk;
}
switch(i) {
default:
- sprint(str, "%R", i);
+ snprint(str, sizeof str, "%R", i);
break;
case D_NONE:
@@ -120,54 +122,54 @@ Dconv(Fmt *fp)
case D_BRANCH:
if(bigP != P && bigP->pcond != P)
if(a->sym != S)
- sprint(str, "%lux+%s", bigP->pcond->pc,
+ snprint(str, sizeof str, "%ux+%s", bigP->pcond->pc,
a->sym->name);
else
- sprint(str, "%lux", bigP->pcond->pc);
+ snprint(str, sizeof str, "%ux", bigP->pcond->pc);
else
- sprint(str, "%ld(PC)", a->offset);
+ snprint(str, sizeof str, "%d(PC)", a->offset);
break;
case D_EXTERN:
- sprint(str, "%s+%ld(SB)", xsymname(a->sym), a->offset);
+ snprint(str, sizeof str, "%s+%d(SB)", xsymname(a->sym), a->offset);
break;
case D_STATIC:
- sprint(str, "%s<%d>+%ld(SB)", xsymname(a->sym),
+ snprint(str, sizeof str, "%s<%d>+%d(SB)", xsymname(a->sym),
a->sym->version, a->offset);
break;
case D_AUTO:
- sprint(str, "%s+%ld(SP)", xsymname(a->sym), a->offset);
+ snprint(str, sizeof str, "%s+%d(SP)", xsymname(a->sym), a->offset);
break;
case D_PARAM:
if(a->sym)
- sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ snprint(str, sizeof str, "%s+%d(FP)", a->sym->name, a->offset);
else
- sprint(str, "%ld(FP)", a->offset);
+ snprint(str, sizeof str, "%d(FP)", a->offset);
break;
case D_CONST:
- sprint(str, "$%ld", a->offset);
+ snprint(str, sizeof str, "$%d", a->offset);
break;
case D_CONST2:
- sprint(str, "$%ld-%ld", a->offset, a->offset2);
+ snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2);
break;
case D_FCONST:
- sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
+ snprint(str, sizeof str, "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
break;
case D_SCONST:
- sprint(str, "$\"%S\"", a->scon);
+ snprint(str, sizeof str, "$\"%S\"", a->scon);
break;
case D_ADDR:
a->type = a->index;
a->index = D_NONE;
- sprint(str, "$%D", a);
+ snprint(str, sizeof str, "$%D", a);
a->index = a->type;
a->type = D_ADDR;
goto conv;
@@ -316,19 +318,48 @@ Sconv(Fmt *fp)
return fmtstrcpy(fp, str);
}
+int
+Iconv(Fmt *fp)
+{
+ int i, n;
+ uchar *p;
+ char *s;
+ Fmt fmt;
+
+ n = fp->prec;
+ fp->prec = 0;
+ if(!(fp->flags&FmtPrec) || n < 0)
+ return fmtstrcpy(fp, "%I");
+ fp->flags &= ~FmtPrec;
+ p = va_arg(fp->args, uchar*);
+
+ // format into temporary buffer and
+ // call fmtstrcpy to handle padding.
+ fmtstrinit(&fmt);
+ for(i=0; i<n; i++)
+ fmtprint(&fmt, "%.2ux", *p++);
+ s = fmtstrflush(&fmt);
+ fmtstrcpy(fp, s);
+ free(s);
+ return 0;
+}
+
void
diag(char *fmt, ...)
{
- char buf[STRINGSZ], *tn;
+ char buf[STRINGSZ], *tn, *sep;
va_list arg;
- tn = "??none??";
- if(curtext != P && curtext->from.sym != S)
- tn = curtext->from.sym->name;
+ tn = "";
+ sep = "";
+ if(cursym != S) {
+ tn = cursym->name;
+ sep = ": ";
+ }
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
- print("%s: %s\n", tn, buf);
+ print("%s%s%s\n", tn, sep, buf);
nerrors++;
if(nerrors > 20) {
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index 1a3ecec1d..18b2112fe 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -28,11 +28,14 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Reading object files.
+
#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
#include "../ld/macho.h"
+#include "../ld/dwarf.h"
#include "../ld/pe.h"
#include <ar.h>
@@ -52,32 +55,12 @@ char *thestring = "386";
* -H4 -Tx -Rx is fake MS-DOS .EXE
* -H6 -Tx -Rx is Apple Mach-O
* -H7 -Tx -Rx is Linux ELF32
- * -H8 -Tx -Rx is Google Native Client
+ * -H8 -Tx -Rx was Google Native Client
* -H9 -Tx -Rx is FreeBSD ELF32
+ * -H10 -Tx -Rx is MS Windows PE
+ * -H11 -Tx -Rx is tiny (os image)
*/
-static int
-isobjfile(char *f)
-{
- int n, v;
- Biobuf *b;
- char buf1[5], buf2[SARMAG];
-
- b = Bopen(f, OREAD);
- if(b == nil)
- return 0;
- n = Bread(b, buf1, 5);
- if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
- v = 1; /* good enough for our purposes */
- else{
- Bseek(b, 0, 0);
- n = Bread(b, buf2, SARMAG);
- v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
- }
- Bterm(b);
- return v;
-}
-
void
usage(void)
{
@@ -88,7 +71,7 @@ usage(void)
void
main(int argc, char *argv[])
{
- int i, c;
+ int c;
Binit(&bso, 1, OWRITE);
cout = -1;
@@ -152,9 +135,6 @@ main(int argc, char *argv[])
if(strcmp(goos, "darwin") == 0)
HEADTYPE = 6;
else
- if(strcmp(goos, "nacl") == 0)
- HEADTYPE = 8;
- else
if(strcmp(goos, "freebsd") == 0)
HEADTYPE = 9;
else
@@ -164,6 +144,9 @@ main(int argc, char *argv[])
if(strcmp(goos, "tiny") == 0)
HEADTYPE = 11;
else
+ if(strcmp(goos, "plan9") == 0)
+ HEADTYPE = 2;
+ else
print("goos is not known: %s\n", goos);
}
@@ -208,7 +191,7 @@ main(int argc, char *argv[])
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
- INITRND = 4096;
+ INITRND = 1;
break;
case 3: /* MS-DOS .COM */
HEADR = 0;
@@ -229,7 +212,7 @@ main(int argc, char *argv[])
INITRND = 4;
HEADR += (INITTEXT & 0xFFFF);
if(debug['v'])
- Bprint(&bso, "HEADR = 0x%ld\n", HEADR);
+ Bprint(&bso, "HEADR = 0x%d\n", HEADR);
break;
case 6: /* apple MACH */
/*
@@ -249,7 +232,7 @@ main(int argc, char *argv[])
case 7: /* elf32 executable */
case 9:
/*
- * Linux ELF uses TLS offsets negative from %gs.
+ * ELF uses TLS offsets negative from %gs.
* Translate 0(GS) and 4(GS) into -8(GS) and -4(GS).
* Also known to ../../pkg/runtime/linux/386/sys.s
* and ../../libcgo/linux_386.c.
@@ -264,30 +247,15 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
- case 8: /* native client elf32 executable */
- elfinit();
- HEADR = 4096;
- if(INITTEXT == -1)
- INITTEXT = 0x20000;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 65536;
-
- // 512 kB of address space for closures.
- // (Doesn't take any space in the binary file.)
- // Closures are 64 bytes each, so this is 8,192 closures.
- textpad = 512*1024;
- break;
case 10: /* PE executable */
peinit();
- HEADR = PERESERVE;
+ HEADR = PEFILEHEADR;
if(INITTEXT == -1)
- INITTEXT = PEBASE+0x1000;
+ INITTEXT = PEBASE+PESECTHEADR;
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
- INITRND = PEALIGN;
+ INITRND = PESECTALIGN;
break;
case 11:
tlsoffset = 0;
@@ -302,68 +270,14 @@ main(int argc, char *argv[])
break;
}
if(INITDAT != 0 && INITRND != 0)
- print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ print("warning: -D0x%ux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
if(debug['v'])
- Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n",
+ Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
HEADTYPE, INITTEXT, INITDAT, INITRND);
Bflush(&bso);
- for(i=1; optab[i].as; i++)
- if(i != optab[i].as) {
- diag("phase error in optab: %d", i);
- errorexit();
- }
- maxop = i;
-
- for(i=0; i<Ymax; i++)
- ycover[i*Ymax + i] = 1;
-
- ycover[Yi0*Ymax + Yi8] = 1;
- ycover[Yi1*Ymax + Yi8] = 1;
-
- ycover[Yi0*Ymax + Yi32] = 1;
- ycover[Yi1*Ymax + Yi32] = 1;
- ycover[Yi8*Ymax + Yi32] = 1;
-
- ycover[Yal*Ymax + Yrb] = 1;
- ycover[Ycl*Ymax + Yrb] = 1;
- ycover[Yax*Ymax + Yrb] = 1;
- ycover[Ycx*Ymax + Yrb] = 1;
- ycover[Yrx*Ymax + Yrb] = 1;
-
- ycover[Yax*Ymax + Yrx] = 1;
- ycover[Ycx*Ymax + Yrx] = 1;
-
- ycover[Yax*Ymax + Yrl] = 1;
- ycover[Ycx*Ymax + Yrl] = 1;
- ycover[Yrx*Ymax + Yrl] = 1;
-
- ycover[Yf0*Ymax + Yrf] = 1;
-
- ycover[Yal*Ymax + Ymb] = 1;
- ycover[Ycl*Ymax + Ymb] = 1;
- ycover[Yax*Ymax + Ymb] = 1;
- ycover[Ycx*Ymax + Ymb] = 1;
- ycover[Yrx*Ymax + Ymb] = 1;
- ycover[Yrb*Ymax + Ymb] = 1;
- ycover[Ym*Ymax + Ymb] = 1;
-
- ycover[Yax*Ymax + Yml] = 1;
- ycover[Ycx*Ymax + Yml] = 1;
- ycover[Yrx*Ymax + Yml] = 1;
- ycover[Yrl*Ymax + Yml] = 1;
- ycover[Ym*Ymax + Yml] = 1;
-
- for(i=0; i<D_NONE; i++) {
- reg[i] = -1;
- if(i >= D_AL && i <= D_BH)
- reg[i] = (i-D_AL) & 7;
- if(i >= D_AX && i <= D_DI)
- reg[i] = (i-D_AX) & 7;
- if(i >= D_F0 && i <= D_F0+7)
- reg[i] = (i-D_F0) & 7;
- }
+ instinit();
zprg.link = P;
zprg.pcond = P;
zprg.back = 2;
@@ -373,49 +287,25 @@ main(int argc, char *argv[])
zprg.from.scale = 1;
zprg.to = zprg.from;
- pcstr = "%.6lux ";
+ pcstr = "%.6ux ";
nuxiinit();
histgen = 0;
- textp = P;
- datap = P;
- edatap = P;
pc = 0;
dtype = 4;
version = 0;
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
- firstp = prg();
- lastp = firstp;
addlibpath("command line", "command line", argv[0], "main");
loadlib();
-
deadcode();
-
- firstp = firstp->link;
- if(firstp == P)
- errorexit();
- if(doexp || dlm){
- EXPTAB = "_exporttab";
- zerosig(EXPTAB);
- zerosig("etext");
- zerosig("edata");
- zerosig("end");
- if(dlm){
- import();
- HEADTYPE = 2;
- INITTEXT = INITDAT = 0;
- INITRND = 8;
- INITENTRY = EXPTAB;
- }
- export();
- }
patch();
follow();
doelf();
if(HEADTYPE == 6)
domacho();
- dodata();
+ if(HEADTYPE == 10)
+ dope();
dostkoff();
if(debug['p'])
if(debug['1'])
@@ -423,14 +313,18 @@ main(int argc, char *argv[])
else
doprof2();
span();
- doinit();
- if(HEADTYPE == 10)
- dope();
+ addexport();
+ textaddress();
+ pclntab();
+ symtab();
+ dodata();
+ address();
+ reloc();
asmb();
undef();
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%ld symbols\n", nsymbol);
+ Bprint(&bso, "%d symbols\n", nsymbol);
Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
}
@@ -439,8 +333,19 @@ main(int argc, char *argv[])
errorexit();
}
-void
-zaddr(Biobuf *f, Adr *a, Sym *h[])
+static Sym*
+zsym(char *pn, Biobuf *f, Sym *h[])
+{
+ int o;
+
+ o = Bgetc(f);
+ if(o < 0 || o >= NSYM || h[o] == nil)
+ mangle(pn);
+ return h[o];
+}
+
+static void
+zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
{
int t;
int32 l;
@@ -465,7 +370,7 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
}
a->sym = S;
if(t & T_SYM)
- a->sym = h[Bgetc(f)];
+ a->sym = zsym(pn, f, h);
if(t & T_FCONST) {
a->ieee.l = Bget4(f);
a->ieee.h = Bget4(f);
@@ -479,7 +384,7 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
a->type = Bgetc(f);
adrgotype = S;
if(t & T_GOTYPE)
- adrgotype = h[Bgetc(f)];
+ adrgotype = zsym(pn, f, h);
t = a->type;
if(t == D_INDIR+D_GS)
@@ -526,7 +431,7 @@ void
ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
{
int32 ipc;
- Prog *p, *t;
+ Prog *p;
int v, o, r, skip;
Sym *h[NSYM], *s, *di;
uint32 sig;
@@ -534,7 +439,9 @@ ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
int32 eof;
char *name, *x;
char src[1024];
+ Prog *lastp;
+ lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
di = S;
@@ -591,7 +498,7 @@ loop:
if(sig != 0){
if(s->sig != 0 && s->sig != sig)
diag("incompatible type signatures"
- "%lux(%s) and %lux(%s) for %s",
+ "%ux(%s) and %ux(%s) for %s",
s->sig, s->file, sig, pn, s->name);
s->sig = sig;
s->file = pn;
@@ -599,6 +506,8 @@ loop:
if(debug['W'])
print(" ANAME %s\n", s->name);
+ if(o < 0 || o >= nelem(h))
+ mangle(pn);
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
@@ -613,6 +522,7 @@ loop:
histfrogp++;
} else
collapsefrog(s);
+ dwarfaddfrag(s->value, s->name);
}
goto loop;
}
@@ -623,9 +533,9 @@ loop:
p->back = 2;
p->ft = 0;
p->tt = 0;
- zaddr(f, &p->from, h);
+ zaddr(pn, f, &p->from, h);
fromgotype = adrgotype;
- zaddr(f, &p->to, h);
+ zaddr(pn, f, &p->to, h);
if(debug['W'])
print("%P\n", p);
@@ -647,10 +557,10 @@ loop:
case AEND:
histtoauto();
- if(curtext != P)
- curtext->to.autom = curauto;
+ if(cursym != nil && cursym->text)
+ cursym->autom = curauto;
curauto = 0;
- curtext = P;
+ cursym = nil;
if(Boffset(f) == eof)
return;
goto newloop;
@@ -659,89 +569,41 @@ loop:
s = p->from.sym;
if(s->type == 0 || s->type == SXREF) {
s->type = SBSS;
- s->value = 0;
+ s->size = 0;
}
- if(s->type != SBSS) {
+ if(s->type != SBSS && !s->dupok) {
diag("%s: redefinition: %s in %s",
pn, s->name, TNAME);
s->type = SBSS;
- s->value = 0;
+ s->size = 0;
}
- if(p->to.offset > s->value)
- s->value = p->to.offset;
+ if(p->to.offset > s->size)
+ s->size = p->to.offset;
if(p->from.scale & DUPOK)
s->dupok = 1;
+ if(p->from.scale & RODATA)
+ s->type = SRODATA;
goto loop;
- case ADYNT:
- if(p->to.sym == S) {
- diag("DYNT without a sym\n%P", p);
- break;
- }
- di = p->to.sym;
- p->from.scale = 4;
- if(di->type == SXREF) {
- if(debug['z'])
- Bprint(&bso, "%P set to %d\n", p, dtype);
- di->type = SCONST;
- di->value = dtype;
- dtype += 4;
- }
- if(p->from.sym == S)
- break;
-
- p->from.offset = di->value;
- p->from.sym->type = SDATA;
- if(curtext == P) {
- diag("DYNT not in text: %P", p);
- break;
- }
- p->to.sym = curtext->from.sym;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- goto data;
-
- case AINIT:
- if(p->from.sym == S) {
- diag("INIT without a sym\n%P", p);
- break;
- }
- if(di == S) {
- diag("INIT without previous DYNT\n%P", p);
- break;
- }
- p->from.offset = di->value;
- p->from.sym->type = SDATA;
- goto data;
-
case ADATA:
- data:
// 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 != S && s->dupok) {
+ if(s->dupok) {
// if(debug['v'])
// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
- if(s != S) {
- p->dlink = s->data;
- s->data = p;
- 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();
- }
+ 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();
}
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- p->link = P;
+ savedata(s, p);
+ unmal(p, sizeof *p);
goto loop;
case AGOK:
@@ -751,9 +613,9 @@ loop:
case ATEXT:
s = p->from.sym;
- if(s == S) {
- diag("%s: no TEXT symbol: %P", pn, p);
- errorexit();
+ if(s->text != nil) {
+ diag("%s: %s: redefinition", pn, s->name);
+ return;
}
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
@@ -761,13 +623,19 @@ loop:
diag("skipping: %s: redefinition: %s", pn, s->name);
return;
}
- if(curtext != P) {
+ if(cursym != nil && cursym->text) {
histtoauto();
- curtext->to.autom = curauto;
+ cursym->autom = curauto;
curauto = 0;
}
skip = 0;
- curtext = p;
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ s->text = p;
+ cursym = s;
if(s->type != 0 && s->type != SXREF) {
if(p->from.scale & DUPOK) {
skip = 1;
@@ -775,7 +643,10 @@ loop:
}
diag("%s: redefinition: %s\n%P", pn, s->name, p);
}
- newtext(p, s);
+ s->type = STEXT;
+ s->value = pc;
+ lastp = p;
+ p->pc = pc++;
goto loop;
case AFMOVF:
@@ -791,24 +662,12 @@ loop:
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 9 max */
- sprint(literal, "$%lux", ieeedtof(&p->from.ieee));
+ sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
s = lookup(literal, 0);
if(s->type == 0) {
- s->type = SBSS;
- s->value = 4;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_EXTERN;
- t->from.sym = s;
- t->from.scale = 4;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ s->type = SDATA;
+ adduint32(s, ieeedtof(&p->from.ieee));
+ s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
@@ -829,25 +688,14 @@ loop:
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 18 max */
- sprint(literal, "$%lux.%lux",
+ sprint(literal, "$%ux.%ux",
p->from.ieee.l, p->from.ieee.h);
s = lookup(literal, 0);
if(s->type == 0) {
- s->type = SBSS;
- s->value = 8;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_EXTERN;
- t->from.sym = s;
- t->from.scale = 8;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ s->type = SDATA;
+ adduint32(s, p->from.ieee.l);
+ adduint32(s, p->from.ieee.h);
+ s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
@@ -859,13 +707,18 @@ loop:
default:
if(skip)
nopout(p);
+ p->pc = pc;
+ pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
+ if(lastp == nil) {
+ if(p->as != ANOP)
+ diag("unexpected instruction: %P", p);
+ goto loop;
+ }
lastp->link = p;
lastp = p;
- p->pc = pc;
- pc++;
goto loop;
}
goto loop;
@@ -905,153 +758,3 @@ appendp(Prog *q)
p->line = q->line;
return p;
}
-
-void
-doprof1(void)
-{
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->from.scale = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.sym = s;
- q->from.scale = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->value = n*4;
-}
-
-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(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->from.sym == s2) {
- p->from.scale = 1;
- ps2 = p;
- }
- if(p->from.sym == s4) {
- p->from.scale = 1;
- ps4 = p;
- }
- }
- }
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
-
- if(p->from.scale & NOPROF) { /* dont profile */
- for(;;) {
- q = p->link;
- if(q == P)
- break;
- if(q->as == ATEXT)
- break;
- p = q;
- }
- continue;
- }
-
- /*
- * JMPL profin
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = ps2;
- p->to.sym = s2;
-
- 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;
-
- /*
- * JAL profout
- */
- p->as = ACALL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->pcond = ps4;
- p->to.sym = s4;
-
- p = q;
-
- continue;
- }
- }
-}
diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c
index 5b7be692e..fceab785d 100644
--- a/src/cmd/8l/optab.c
+++ b/src/cmd/8l/optab.c
@@ -696,8 +696,8 @@ Optab optab[] =
{ AFYL2X, ynone, Px, 0xd9, 0xf1 },
{ AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
{ AEND },
- { ADYNT },
- { AINIT },
+ { ADYNT_ },
+ { AINIT_ },
{ ASIGNAME },
{ ACMPXCHGB, yrb_mb, Pm, 0xb0 },
{ ACMPXCHGL, yrl_ml, Pm, 0xb1 },
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
index ace640d22..6e387b0b5 100644
--- a/src/cmd/8l/pass.c
+++ b/src/cmd/8l/pass.c
@@ -28,9 +28,13 @@
// 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**);
+
// see ../../pkg/runtime/proc.c:/StackGuard
enum
{
@@ -38,138 +42,6 @@ enum
StackBig = 4096,
};
-void
-dodata(void)
-{
- int i;
- Sym *s;
- Prog *p;
- int32 t, u;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f dodata\n", cputime());
- Bflush(&bso);
- for(p = datap; p != P; p = p->link) {
- s = p->from.sym;
- if(p->as == ADYNT || p->as == AINIT)
- s->value = dtype;
- if(s->type == SBSS)
- s->type = SDATA;
- if(s->type != SDATA && s->type != SELFDATA)
- diag("initialize non-data (%d): %s\n%P",
- s->type, s->name, p);
- t = p->from.offset + p->width;
- if(t > s->value)
- diag("initialize bounds (%ld): %s\n%P",
- s->value, s->name, p);
- }
-
- /* allocate elf guys - must be segregated from real data */
- datsize = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SELFDATA)
- continue;
- t = rnd(s->value, 4);
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
- elfdatsize = datsize;
-
- /* allocate small guys */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SDATA)
- if(s->type != SBSS)
- continue;
- t = s->value;
- if(t == 0 && s->name[0] != '.') {
- diag("%s: no size", s->name);
- t = 1;
- }
- t = rnd(t, 4);
- s->size = t;
- s->value = t;
- if(t > MINSIZ)
- continue;
- s->value = datsize;
- datsize += t;
- s->type = SDATA1;
- }
-
- /* allocate the rest of the data */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type != SDATA) {
- if(s->type == SDATA1)
- s->type = SDATA;
- continue;
- }
- t = s->value;
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
-
- if(debug['j']) {
- /*
- * pad data with bss that fits up to next
- * 8k boundary, then push data to 8k
- */
- u = rnd(datsize, 8192);
- u -= datsize;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SBSS)
- continue;
- t = s->value;
- if(t > u)
- continue;
- u -= t;
- s->size = t;
- s->value = datsize;
- s->type = SDATA;
- datsize += t;
- }
- datsize += u;
- }
-
- if(dynptrsize > 0) {
- /* dynamic pointer section between data and bss */
- datsize = rnd(datsize, 4);
- }
-
- /* now the bss */
- bsssize = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SBSS)
- continue;
- t = s->value;
- s->size = t;
- s->value = bsssize + dynptrsize + datsize;
- bsssize += t;
- }
-
- xdefine("data", SBSS, 0);
- xdefine("edata", SBSS, datsize);
- xdefine("end", SBSS, dynptrsize + bsssize + datsize);
-
- if(debug['s'] || HEADTYPE == 8)
- xdefine("symdat", SFIXED, 0);
- else
- xdefine("symdat", SFIXED, SYMDATVA);
-}
-
Prog*
brchain(Prog *p)
{
@@ -186,19 +58,53 @@ brchain(Prog *p)
void
follow(void)
{
+ Prog *firstp, *lastp;
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
- firstp = prg();
- lastp = firstp;
- xfol(textp);
- lastp->link = P;
- firstp = firstp->link;
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ firstp = prg();
+ lastp = firstp;
+ xfol(cursym->text, &lastp);
+ lastp->link = nil;
+ cursym->text = firstp->link;
+ }
}
-void
-xfol(Prog *p)
+static int
+nofollow(int a)
+{
+ switch(a) {
+ case AJMP:
+ case ARET:
+ case AIRETL:
+ case AIRETW:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+pushpop(int a)
+{
+ switch(a) {
+ case APUSHL:
+ case APUSHFL:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPW:
+ case APOPFW:
+ return 1;
+ }
+ return 0;
+}
+
+static void
+xfol(Prog *p, Prog **last)
{
Prog *q;
int i;
@@ -207,46 +113,31 @@ xfol(Prog *p)
loop:
if(p == P)
return;
- if(p->as == ATEXT)
- curtext = p;
- if(!curtext->from.sym->reachable) {
- p = p->pcond;
- goto loop;
- }
if(p->as == AJMP)
if((q = p->pcond) != P && q->as != ATEXT) {
+ /* mark instruction as done and continue layout at target of jump */
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
- /* copy up to 4 instructions to avoid branch */
+ /*
+ * p goes here, but already used it elsewhere.
+ * copy up to 4 instructions or else branch to other copy.
+ */
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == P)
break;
- if(q == lastp)
+ if(q == *last)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
- switch(a) {
- case AJMP:
- case ARET:
- case AIRETL:
-
- case APUSHL:
- case APUSHFL:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPW:
- case APOPFW:
- goto brk;
- }
+ if(nofollow(a) || pushpop(a))
+ break; // NOTE(rsc): arm does goto copy
if(q->pcond == P || q->pcond->mark)
continue;
if(a == ACALL || a == ALOOP)
@@ -259,8 +150,8 @@ loop:
q = copyp(p);
p = p->link;
q->mark = 1;
- lastp->link = q;
- lastp = q;
+ (*last)->link = q;
+ *last = q;
if(q->as != a || q->pcond == P || q->pcond->mark)
continue;
@@ -268,14 +159,13 @@ loop:
p = q->pcond;
q->pcond = q->link;
q->link = p;
- xfol(q->link);
+ xfol(q->link, last);
p = q->link;
if(p->mark)
return;
goto loop;
}
} /* */
- brk:;
q = prg();
q->as = AJMP;
q->line = p->line;
@@ -284,14 +174,22 @@ loop:
q->pcond = p;
p = q;
}
+
+ /* emit p */
p->mark = 1;
- lastp->link = p;
- lastp = p;
+ (*last)->link = p;
+ *last = p;
a = p->as;
- if(a == AJMP || a == ARET || a == AIRETL)
+
+ /* continue loop with what comes after p */
+ if(nofollow(a))
return;
- if(p->pcond != P)
- if(a != ACALL) {
+ if(p->pcond != P && a != ACALL) {
+ /*
+ * some kind of conditional branch.
+ * recurse to follow one path.
+ * continue loop on the other.
+ */
q = brchain(p->link);
if(q != P && q->mark)
if(a != ALOOP) {
@@ -299,7 +197,7 @@ loop:
p->link = p->pcond;
p->pcond = q;
}
- xfol(p->link);
+ xfol(p->link, last);
q = brchain(p->pcond);
if(q->mark) {
p->pcond = q;
@@ -339,28 +237,6 @@ relinv(int a)
}
void
-doinit(void)
-{
- Sym *s;
- Prog *p;
- int x;
-
- for(p = datap; p != P; p = p->link) {
- x = p->to.type;
- if(x != D_EXTERN && x != D_STATIC)
- continue;
- s = p->to.sym;
- if(s->type == 0 || s->type == SXREF)
- diag("undefined %s initializer of %s",
- s->name, p->from.sym->name);
- p->to.offset += s->value;
- p->to.type = D_CONST;
- if(s->type == SDATA || s->type == SBSS)
- p->to.offset += INITDAT;
- }
-}
-
-void
patch(void)
{
int32 c;
@@ -377,116 +253,106 @@ patch(void)
Bflush(&bso);
s = lookup("exit", 0);
vexit = s->value;
- for(p = firstp; p != P; p = p->link) {
- if(HEADTYPE == 10) {
- // Convert
- // op n(GS), reg
- // to
- // MOVL 0x2C(FS), reg
- // op n(reg), reg
- // The purpose of this patch is to fix some accesses
- // to extern register variables (TLS) on Windows, as
- // a different method is used to access them.
- if(p->from.type == D_INDIR+D_GS
- && p->to.type >= D_AX && p->to.type <= D_DI) {
- q = appendp(p);
- q->from = p->from;
- q->from.type += p->to.type-D_GS;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x2C;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ if(HEADTYPE == 10) { // Windows
+ // Convert
+ // op n(GS), reg
+ // to
+ // MOVL 0x2C(FS), reg
+ // op n(reg), reg
+ // The purpose of this patch is to fix some accesses
+ // to extern register variables (TLS) on Windows, as
+ // a different method is used to access them.
+ if(p->from.type == D_INDIR+D_GS
+ && p->to.type >= D_AX && p->to.type <= D_DI) {
+ q = appendp(p);
+ q->from = p->from;
+ q->from.type = D_INDIR + p->to.type;
+ q->to = p->to;
+ q->as = p->as;
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_FS;
+ p->from.offset = 0x2C;
+ }
}
- }
- if(p->as == ATEXT)
- curtext = p;
- if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
- s = p->to.sym;
- if(s) {
- if(debug['c'])
- Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- switch(s->type) {
- default:
- /* diag prints TNAME first */
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- case STEXT:
- p->to.offset = s->value;
- break;
- case SUNDEF:
- p->pcond = UP;
- p->to.offset = 0;
- break;
+ if(HEADTYPE == 7) { // Linux
+ // Running binaries under Xen requires using
+ // MOVL 0(GS), reg
+ // and then off(reg) instead of saying off(GS) directly
+ // when the offset is negative.
+ if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
+ && p->to.type >= D_AX && p->to.type <= D_DI) {
+ q = appendp(p);
+ q->from = p->from;
+ q->from.type = D_INDIR + p->to.type;
+ q->to = p->to;
+ q->as = p->as;
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0;
}
- p->to.type = D_BRANCH;
}
- }
- if(p->to.type != D_BRANCH || p->pcond == UP)
- continue;
- c = p->to.offset;
- for(q = firstp; q != P;) {
- if(q->forwd != P)
- if(c >= q->forwd->pc) {
- q = q->forwd;
+ if(HEADTYPE == 2) { // Plan 9
+ if(p->from.type == D_INDIR+D_GS
+ && p->to.type >= D_AX && p->to.type <= D_DI) {
+ p->as = AMOVL;
+ p->from.type = D_ADDR+D_STATIC;
+ p->from.offset += 0xdfffefc0;
+ }
+ }
+ if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
+ s = p->to.sym;
+ if(s) {
+ if(debug['c'])
+ Bprint(&bso, "%s calls %s\n", TNAME, s->name);
+ if((s->type&~SSUB) != STEXT) {
+ /* diag prints TNAME first */
+ diag("undefined: %s", s->name);
+ s->type = STEXT;
+ s->value = vexit;
+ continue; // avoid more error messages
+ }
+ if(s->text == nil)
+ continue;
+ p->to.type = D_BRANCH;
+ p->to.offset = s->text->pc;
+ p->pcond = s->text;
+ continue;
+ }
+ }
+ if(p->to.type != D_BRANCH)
continue;
+ c = p->to.offset;
+ for(q = cursym->text; q != P;) {
+ if(c == q->pc)
+ break;
+ if(q->forwd != P && c >= q->forwd->pc)
+ q = q->forwd;
+ else
+ q = q->link;
}
- if(c == q->pc)
- break;
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range in %s\n%P", TNAME, p);
- p->to.type = D_NONE;
+ if(q == P) {
+ diag("branch out of range in %s (%#ux)\n%P [%s]",
+ TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
+ p->to.type = D_NONE;
+ }
+ p->pcond = q;
}
- p->pcond = q;
}
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- p->mark = 0; /* initialization for follow */
- if(p->pcond != P && p->pcond != UP) {
- p->pcond = brloop(p->pcond);
- if(p->pcond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->pcond->pc;
- }
- }
-}
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->p != nil)
+ continue;
-#define LOG 5
-void
-mkfwd(void)
-{
- Prog *p;
- int i;
- int32 dwn[LOG], cnt[LOG];
- Prog *lst[LOG];
-
- for(i=0; i<LOG; i++) {
- if(i == 0)
- cnt[i] = 1; else
- cnt[i] = LOG * cnt[i-1];
- dwn[i] = 1;
- lst[i] = P;
- }
- i = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- i--;
- if(i < 0)
- i = LOG-1;
- p->forwd = P;
- dwn[i]--;
- if(dwn[i] <= 0) {
- dwn[i] = cnt[i];
- if(lst[i] != P)
- lst[i]->forwd = p;
- lst[i] = p;
+ for(p = cursym->text; p != P; p = p->link) {
+ p->mark = 0; /* initialization for follow */
+ if(p->pcond != P) {
+ p->pcond = brloop(p->pcond);
+ if(p->pcond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->pcond->pc;
+ }
}
}
}
@@ -513,286 +379,221 @@ dostkoff(void)
{
Prog *p, *q, *q1;
int32 autoffset, deltasp;
- int a, f, curframe, curbecome, maxbecome;
+ int a;
Prog *pmorestack;
Sym *symmorestack;
pmorestack = P;
symmorestack = lookup("runtime.morestack", 0);
- if(symmorestack->type == STEXT)
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->from.sym == symmorestack) {
- pmorestack = p;
- p->from.scale |= NOSPLIT;
- break;
- }
- }
- }
- if(pmorestack == P)
+ if(symmorestack->type != STEXT)
diag("runtime.morestack not defined");
+ else {
+ pmorestack = symmorestack->text;
+ symmorestack->text->from.scale |= NOSPLIT;
+ }
- curframe = 0;
- curbecome = 0;
- maxbecome = 0;
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
-
- /* find out how much arg space is used in this TEXT */
- if(p->to.type == (D_INDIR+D_SP))
- if(p->to.offset > curframe)
- curframe = p->to.offset;
-
- switch(p->as) {
- case ATEXT:
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
- curframe = 0;
- curbecome = 0;
-
- curtext = p;
- break;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
- case ARET:
- /* special form of RET is BECOME */
- if(p->from.type == D_CONST)
- if(p->from.offset > curbecome)
- curbecome = p->from.offset;
- break;
- }
- }
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
+ p = cursym->text;
+ autoffset = p->to.offset;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ q = P;
+ q1 = P;
+ if(pmorestack != P)
+ if(!(p->from.scale & NOSPLIT)) {
+ p = appendp(p); // load g into CX
+ switch(HEADTYPE) {
+ case 10: // Windows
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_FS;
+ p->from.offset = 0x2c;
+ p->to.type = D_CX;
- if(debug['b'])
- print("max become = %d\n", maxbecome);
- xdefine("ALEFbecome", STEXT, maxbecome);
+ p = appendp(p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_CX;
+ break;
+
+ case 7: // Linux
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0;
+ p->to.type = D_CX;
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
- switch(p->as) {
- case ATEXT:
- curtext = p;
- break;
- case ACALL:
- if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
- f = maxbecome - curtext->from.sym->frame;
- if(f <= 0)
- break;
- /* calling a become or calling a variable */
- if(p->to.sym == S || p->to.sym->become) {
- curtext->to.offset += f;
- if(debug['b']) {
- curp = p;
- print("%D calling %D increase %d\n",
- &curtext->from, &p->to, f);
- }
- }
+ p = appendp(p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = tlsoffset + 0;
+ p->to.type = D_CX;
+ break;
+
+ case 2: // Plan 9
+ p->as = AMOVL;
+ p->from.type = D_ADDR+D_STATIC;
+ p->from.offset = 0xdfffefc0;
+ p->to.type = D_CX;
+ break;
+
+ default:
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = tlsoffset + 0;
+ p->to.type = D_CX;
}
- break;
- }
- }
- autoffset = 0;
- deltasp = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
- autoffset = p->to.offset;
- if(autoffset < 0)
- autoffset = 0;
-
- q = P;
- q1 = P;
- if(pmorestack != P)
- if(!(p->from.scale & NOSPLIT)) {
- p = appendp(p); // load g into CX
- if(HEADTYPE == 10) {
- p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x2c;
- p->to.type = D_CX;
+ if(debug['K']) {
+ // 8l -K means check not only for stack
+ // overflow but stack underflow.
+ // On underflow, INT 3 (breakpoint).
+ // Underflow itself is rare but this also
+ // catches out-of-sync stack guard info.
+ p = appendp(p);
+ p->as = ACMPL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 4;
+ p->to.type = D_SP;
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_CX;
- } else {
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- }
+ p = appendp(p);
+ p->as = AJCC;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q1 = p;
- if(debug['K']) {
- // 8l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info.
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 4;
- p->to.type = D_SP;
+ p = appendp(p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(p);
+ p->as = ANOP;
+ q1->pcond = p;
+ }
+ if(autoffset < StackBig) { // do we need to call morestack
+ if(autoffset <= StackSmall) {
+ // small stack
p = appendp(p);
- p->as = AJCC;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
+ p->as = ACMPL;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_CX;
+ } else {
+ // large stack
p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
- }
-
- if(autoffset < StackBig) { // do we need to call morestack
- if(autoffset <= StackSmall) {
- // small stack
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_CX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else {
- // large stack
- p = appendp(p);
- p->as = ALEAL;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(autoffset-StackSmall);
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
-
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_CX;
- }
+ p->as = ALEAL;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = -(autoffset-StackSmall);
+ p->to.type = D_AX;
- // common
p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q = p;
+ p->as = ACMPL;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_CX;
}
- p = appendp(p); // save frame size in DX
- p->as = AMOVL;
- p->to.type = D_DX;
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
- p->from.type = D_CONST;
- if(autoffset+160 > 4096)
- p->from.offset = (autoffset+160) & ~7LL;
-
- p = appendp(p); // save arg size in AX
- p->as = AMOVL;
- p->to.type = D_AX;
- p->from.type = D_CONST;
- p->from.offset = curtext->to.offset2;
-
+ // common
p = appendp(p);
- p->as = ACALL;
+ p->as = AJHI;
p->to.type = D_BRANCH;
- p->pcond = pmorestack;
- p->to.sym = symmorestack;
-
+ p->to.offset = 4;
+ q = p;
}
- if(q != P)
- q->pcond = p->link;
+ p = appendp(p); // save frame size in DX
+ p->as = AMOVL;
+ p->to.type = D_DX;
+ /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
+ p->from.type = D_CONST;
+ if(autoffset+160 > 4096)
+ p->from.offset = (autoffset+160) & ~7LL;
+
+ p = appendp(p); // save arg size in AX
+ p->as = AMOVL;
+ p->to.type = D_AX;
+ p->from.type = D_CONST;
+ p->from.offset = cursym->text->to.offset2;
+
+ p = appendp(p);
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack;
+ p->to.sym = symmorestack;
- if(autoffset) {
- p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- if(q != P)
- q->pcond = p;
- }
- deltasp = autoffset;
- }
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + 4;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + 4;
-
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- continue;
- case APOPW:
- case APOPFW:
- deltasp -= 2;
- continue;
- case ARET:
- break;
}
- if(autoffset != deltasp)
- diag("unbalanced PUSH/POP");
- if(p->from.type == D_CONST)
- goto become;
+ if(q != P)
+ q->pcond = p->link;
if(autoffset) {
- q = p;
p = appendp(p);
- p->as = ARET;
-
- q->as = AADJSP;
- q->from.type = D_CONST;
- q->from.offset = -autoffset;
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset;
+ p->spadj = autoffset;
+ if(q != P)
+ q->pcond = p;
+ }
+ deltasp = autoffset;
+
+ for(; p != P; p = p->link) {
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + 4;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + 4;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ p->spadj = 4;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ p->spadj = 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ p->spadj = -4;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ p->spadj = -2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ diag("unbalanced PUSH/POP");
+
+ if(autoffset) {
+ q = p;
+ p = appendp(p);
+ p->as = ARET;
+
+ q->as = AADJSP;
+ q->from.type = D_CONST;
+ q->from.offset = -autoffset;
+ p->spadj = -autoffset;
+ }
}
- continue;
-
- become:
- q = p;
- p = appendp(p);
- p->as = AJMP;
- p->to = q->to;
- p->pcond = q->pcond;
-
- q->as = AADJSP;
- q->from = zprg.from;
- q->from.type = D_CONST;
- q->from.offset = -autoffset;
- q->to = zprg.to;
- continue;
}
}
@@ -843,176 +644,7 @@ undef(void)
Sym *s;
for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
+ for(s = hash[i]; s != S; s = s->hash)
if(s->type == SXREF)
- diag("%s: not defined", s->name);
-}
-
-void
-import(void)
-{
- int i;
- Sym *s;
-
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
- if(s->value != 0)
- diag("value != 0 on SXREF");
- undefsym(s);
- Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value);
- if(debug['S'])
- s->sig = 0;
- }
-}
-
-void
-ckoff(Sym *s, int32 v)
-{
- if(v < 0 || v >= 1<<Roffset)
- diag("relocation offset %ld for %s out of range", v, s->name);
-}
-
-Prog*
-newdata(Sym *s, int o, int w, int t)
-{
- Prog *p;
-
- p = prg();
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- p->as = ADATA;
- p->width = w;
- p->from.scale = w;
- p->from.type = t;
- p->from.sym = s;
- p->from.offset = o;
- p->to.type = D_CONST;
- p->dlink = s->data;
- s->data = p;
- return p;
-}
-
-Prog*
-newtext(Prog *p, Sym *s)
-{
- if(p == P) {
- p = prg();
- p->as = ATEXT;
- p->from.sym = s;
- }
- s->type = STEXT;
- s->text = p;
- s->value = pc;
- lastp->link = p;
- lastp = p;
- p->pc = pc++;
- if(textp == P)
- textp = p;
- else
- etextp->pcond = p;
- etextp = p;
- return p;
-}
-
-void
-export(void)
-{
- int i, j, n, off, nb, sv, ne;
- Sym *s, *et, *str, **esyms;
- Prog *p;
- char buf[NSNAME], *t;
-
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
- n++;
- esyms = mal(n*sizeof(Sym*));
- ne = n;
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
- esyms[n++] = s;
- for(i = 0; i < ne-1; i++)
- for(j = i+1; j < ne; j++)
- if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
- s = esyms[i];
- esyms[i] = esyms[j];
- esyms[j] = s;
- }
-
- nb = 0;
- off = 0;
- et = lookup(EXPTAB, 0);
- if(et->type != 0 && et->type != SXREF)
- diag("%s already defined", EXPTAB);
- et->type = SDATA;
- str = lookup(".string", 0);
- if(str->type == 0)
- str->type = SDATA;
- sv = str->value;
- for(i = 0; i < ne; i++){
- s = esyms[i];
- if(debug['S'])
- s->sig = 0;
- /* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
-
- /* signature */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.offset = s->sig;
-
- /* address */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.sym = s;
-
- /* string */
- t = s->name;
- n = strlen(t)+1;
- for(;;){
- buf[nb++] = *t;
- sv++;
- if(nb >= NSNAME){
- p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
- p->to.type = D_SCONST;
- memmove(p->to.scon, buf, NSNAME);
- nb = 0;
- }
- if(*t++ == 0)
- break;
- }
-
- /* name */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.type = D_ADDR;
- p->to.index = D_STATIC;
- p->to.sym = str;
- p->to.offset = sv-n;
- }
-
- if(nb > 0){
- p = newdata(str, sv-nb, nb, D_STATIC);
- p->to.type = D_SCONST;
- memmove(p->to.scon, buf, nb);
- }
-
- for(i = 0; i < 3; i++){
- newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- }
- et->value = off;
- if(sv == 0)
- sv = 1;
- str->value = sv;
- exports = ne;
- free(esyms);
+ diag("%s(%d): not defined", s->name, s->version);
}
diff --git a/src/cmd/8l/prof.c b/src/cmd/8l/prof.c
new file mode 100644
index 000000000..4e95fad79
--- /dev/null
+++ b/src/cmd/8l/prof.c
@@ -0,0 +1,173 @@
+// Inferno utils/8l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Profiling.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+void
+doprof1(void)
+{
+#if 0 // TODO(rsc)
+ Sym *s;
+ int32 n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADDL;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->size = n*4;
+#endif
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ if(p->from.sym == s2) {
+ p->from.scale = 1;
+ ps2 = p;
+ }
+ if(p->from.sym == s4) {
+ p->from.scale = 1;
+ ps4 = p;
+ }
+ }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+
+ if(p->from.scale & NOPROF) /* dont profile */
+ continue;
+
+ /*
+ * JMPL profin
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = ps2;
+ p->to.sym = s2;
+
+ for(; p; p=p->link) {
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * JAL profout
+ */
+ p->as = ACALL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->pcond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+ }
+ }
+ }
+}
diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c
index 99ba279da..66a843b23 100644
--- a/src/cmd/8l/span.c
+++ b/src/cmd/8l/span.c
@@ -28,29 +28,28 @@
// 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 int32 vaddr(Adr*, Reloc*);
+
void
-span(void)
+span1(Sym *s)
{
Prog *p, *q;
- int32 v, c, idat;
- int m, n, again;
-
- xdefine("etext", STEXT, 0L);
- idat = INITDAT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- n = 0;
- if(p->to.type == D_BRANCH)
- if(p->pcond == P)
- p->pcond = p;
- if((q = p->pcond) != P)
- if(q->back != 2)
- n = 1;
- p->back = n;
+ int32 c, v, loop;
+ uchar *bp;
+ int n, m, i;
+
+ cursym = s;
+
+ for(p = s->text; p != P; p = p->link) {
+ p->back = 2; // use short branches first time through
+ if((q = p->pcond) != P && (q->back & 2))
+ p->back |= 1; // backward jump
+
if(p->as == AADJSP) {
p->to.type = D_SP;
v = -p->from.offset;
@@ -65,293 +64,186 @@ span(void)
p->as = ANOP;
}
}
-
+
n = 0;
-start:
- do{
- again = 0;
- if(debug['v'])
- Bprint(&bso, "%5.2f span %d\n", cputime(), n);
- Bflush(&bso);
- if(n > 50) {
- print("span must be looping - %d\n", textsize);
+ do {
+ loop = 0;
+ memset(s->r, 0, s->nr*sizeof s->r[0]);
+ s->nr = 0;
+ s->np = 0;
+ c = 0;
+ for(p = s->text; p != P; p = p->link) {
+ p->pc = c;
+
+ // process forward jumps to p
+ for(q = p->comefrom; q != P; q = q->forwd) {
+ v = p->pc - (q->pc + q->mark);
+ if(q->back & 2) { // short
+ if(v > 127) {
+ loop++;
+ q->back ^= 2;
+ }
+ s->p[q->pc+1] = v;
+ } else {
+ bp = s->p + q->pc + q->mark - 4;
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp++ = v>>24;
+ }
+ }
+ p->comefrom = P;
+
+ asmins(p);
+ p->pc = c;
+ m = andptr-and;
+ symgrow(s, p->pc+m);
+ memmove(s->p+p->pc, and, m);
+ p->mark = m;
+ c += m;
+ }
+ if(++n > 20) {
+ diag("span must be looping");
errorexit();
}
- c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
- if(HEADTYPE == 8)
- c = (c+31)&~31;
- }
- if(p->to.type == D_BRANCH)
- if(p->back)
- p->pc = c;
- if(n == 0 || HEADTYPE == 8 || p->to.type == D_BRANCH) {
- if(HEADTYPE == 8)
- p->pc = c;
- asmins(p);
- m = andptr-and;
- if(p->mark != m)
- again = 1;
- p->mark = m;
- }
- if(HEADTYPE == 8) {
- c = p->pc + p->mark;
- } else {
- p->pc = c;
- c += p->mark;
- }
+ } while(loop);
+ s->size = c;
+
+ if(debug['a'] > 1) {
+ print("span1 %s %d (%d tries)\n %.6ux", s->name, s->size, n, 0);
+ for(i=0; i<s->np; i++) {
+ print(" %.2ux", s->p[i]);
+ if(i%16 == 15)
+ print("\n %.6ux", i+1);
}
- textsize = c;
- n++;
- }while(again);
-
- if(INITRND) {
- INITDAT = rnd(c+textpad, INITRND);
- if(INITDAT != idat) {
- idat = INITDAT;
- goto start;
+ if(i%16)
+ print("\n");
+
+ for(i=0; i<s->nr; i++) {
+ Reloc *r;
+
+ r = &s->r[i];
+ print(" rel %#.4ux/%d %s%+d\n", r->off, r->siz, r->sym->name, r->add);
}
}
- xdefine("etext", STEXT, c);
- if(debug['v'])
- Bprint(&bso, "etext = %lux\n", c);
- Bflush(&bso);
- for(p = textp; p != P; p = p->pcond)
- p->from.sym->value = p->pc;
- textsize = c - INITTEXT;
}
void
-xdefine(char *p, int t, int32 v)
+span(void)
{
- Sym *s;
-
- s = lookup(p, 0);
- if(s->type == 0 || s->type == SXREF) {
- s->type = t;
- s->value = v;
- }
- if(s->type == STEXT && s->value == 0)
- s->value = v;
-}
+ Prog *p, *q;
+ int32 v;
+ int n;
-void
-putsymb(char *s, int t, int32 v, int ver, Sym *go)
-{
- int i, f;
- vlong gv;
-
- if(t == 'f')
- s++;
- lput(v);
- if(ver)
- t += 'a' - 'A';
- cput(t+0x80); /* 0x80 is variable length */
-
- if(t == 'Z' || t == 'z') {
- cput(s[0]);
- for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
- cput(s[i]);
- cput(s[i+1]);
- }
- cput(0);
- cput(0);
- i++;
- }
- else {
- for(i=0; s[i]; i++)
- cput(s[i]);
- cput(0);
- }
- gv = 0;
- if(go) {
- if(!go->reachable)
- sysfatal("unreachable type %s", go->name);
- gv = go->value+INITDAT;
- }
- lput(gv);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
- symsize += 4 + 1 + i+1 + 4;
+ // NOTE(rsc): If we get rid of the globals we should
+ // be able to parallelize these iterations.
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
- if(debug['n']) {
- if(t == 'z' || t == 'Z') {
- Bprint(&bso, "%c %.8lux ", t, v);
- for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
- f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
- Bprint(&bso, "/%x", f);
+ // TODO: move into span1
+ for(p = cursym->text; p != P; p = p->link) {
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == P)
+ p->pcond = p;
+ if((q = p->pcond) != P)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = AADDL;
+ if(v < 0) {
+ p->as = ASUBL;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
}
- Bprint(&bso, "\n");
- return;
}
- if(ver)
- Bprint(&bso, "%c %.8lux %s<%d> %s (%.8llux)\n", t, v, s, ver, go ? go->name : "", gv);
- else
- Bprint(&bso, "%c %.8lux %s\n", t, v, s, go ? go->name : "", gv);
+ span1(cursym);
}
}
void
-asmsym(void)
+xdefine(char *p, int t, int32 v)
{
- Prog *p;
- Auto *a;
Sym *s;
- int h;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- putsymb(s->name, 'T', s->value, s->version, 0);
-
- for(h=0; h<NHASH; h++)
- for(s=hash[h]; s!=S; s=s->link)
- switch(s->type) {
- case SCONST:
- if(!s->reachable)
- continue;
- putsymb(s->name, 'D', s->value, s->version, s->gotype);
- continue;
-
- case SDATA:
- case SELFDATA:
- if(!s->reachable)
- continue;
- putsymb(s->name, 'D', s->value+INITDAT, s->version, s->gotype);
- continue;
-
- case SMACHO:
- if(!s->reachable)
- continue;
- putsymb(s->name, 'D', s->value+INITDAT+datsize+bsssize, s->version, s->gotype);
- continue;
-
- case SBSS:
- if(!s->reachable)
- continue;
- putsymb(s->name, 'B', s->value+INITDAT, s->version, s->gotype);
- continue;
-
- case SFIXED:
- putsymb(s->name, 'B', s->value, s->version, s->gotype);
- continue;
-
- case SFILE:
- putsymb(s->name, 'f', s->value, s->version, 0);
- continue;
- }
- for(p=textp; p!=P; p=p->pcond) {
- s = p->from.sym;
- if(s->type != STEXT)
- continue;
-
- /* filenames first */
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_FILE)
- putsymb(a->asym->name, 'z', a->aoffset, 0, 0);
- else
- if(a->type == D_FILE1)
- putsymb(a->asym->name, 'Z', a->aoffset, 0, 0);
-
- if(!s->reachable)
- continue;
-
- putsymb(s->name, 'T', s->value, s->version, s->gotype);
-
- /* frame, auto and param after */
- putsymb(".frame", 'm', p->to.offset+4, 0, 0);
-
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_AUTO)
- putsymb(a->asym->name, 'a', -a->aoffset, 0, a->gotype);
- else
- if(a->type == D_PARAM)
- putsymb(a->asym->name, 'p', a->aoffset, 0, a->gotype);
- }
- if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %lud\n", symsize);
- Bflush(&bso);
+ s = lookup(p, 0);
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
}
void
-asmlc(void)
+instinit(void)
{
- int32 oldpc, oldlc;
- Prog *p;
- int32 v, s;
-
- oldpc = INITTEXT;
- oldlc = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
- if(p->as == ATEXT)
- curtext = p;
- if(debug['L'])
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- continue;
- }
- if(debug['L'])
- Bprint(&bso, "\t\t%6ld", lcsize);
- v = (p->pc - oldpc) / MINLC;
- while(v) {
- s = 127;
- if(v < 127)
- s = v;
- cput(s+128); /* 129-255 +pc */
- if(debug['L'])
- Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
- v -= s;
- lcsize++;
- }
- s = p->line - oldlc;
- oldlc = p->line;
- oldpc = p->pc + MINLC;
- if(s > 64 || s < -64) {
- cput(0); /* 0 vv +lc */
- cput(s>>24);
- cput(s>>16);
- cput(s>>8);
- cput(s);
- if(debug['L']) {
- if(s > 0)
- Bprint(&bso, " lc+%ld(%d,%ld)\n",
- s, 0, s);
- else
- Bprint(&bso, " lc%ld(%d,%ld)\n",
- s, 0, s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
- lcsize += 5;
- continue;
- }
- if(s > 0) {
- cput(0+s); /* 1-64 +lc */
- if(debug['L']) {
- Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
- } else {
- cput(64-s); /* 65-128 -lc */
- if(debug['L']) {
- Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
+ int i;
+
+ for(i=1; optab[i].as; i++)
+ if(i != optab[i].as) {
+ diag("phase error in optab: %d", i);
+ errorexit();
}
- lcsize++;
- }
- while(lcsize & 1) {
- s = 129;
- cput(s);
- lcsize++;
+ maxop = i;
+
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_BH)
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_AX && i <= D_DI)
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
}
- if(debug['v'] || debug['L'])
- Bprint(&bso, "lcsize = %ld\n", lcsize);
- Bflush(&bso);
}
int
@@ -506,11 +398,11 @@ oclass(Adr *a)
}
void
-asmidx(Adr *a, int base)
+asmidx(int scale, int index, int base)
{
int i;
- switch(a->index) {
+ switch(index) {
default:
goto bad;
@@ -525,10 +417,10 @@ asmidx(Adr *a, int base)
case D_BP:
case D_SI:
case D_DI:
- i = reg[a->index] << 3;
+ i = reg[index] << 3;
break;
}
- switch(a->scale) {
+ switch(scale) {
default:
goto bad;
case 1:
@@ -564,7 +456,7 @@ bas:
*andptr++ = i;
return;
bad:
- diag("asmidx: bad address %D", a);
+ diag("asmidx: bad address %d,%d,%d", scale, index, base);
*andptr++ = 0;
return;
}
@@ -572,10 +464,6 @@ bad:
static void
put4(int32 v)
{
- if(dlm && curp != P && reloca != nil){
- dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);
- reloca = nil;
- }
andptr[0] = v;
andptr[1] = v>>8;
andptr[2] = v>>16;
@@ -583,24 +471,40 @@ put4(int32 v)
andptr += 4;
}
+static void
+relput4(Prog *p, Adr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(a, &rel);
+ if(rel.siz != 0) {
+ if(rel.siz != 4)
+ diag("bad reloc");
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
+ put4(v);
+}
+
int32
symaddr(Sym *s)
{
- Adr a;
-
- a.type = D_ADDR;
- a.index = D_EXTERN;
- a.offset = 0;
- a.sym = s;
- return vaddr(&a);
+ if(!s->reachable)
+ diag("unreachable symbol in symaddr - %s", s->name);
+ return s->value;
}
-int32
-vaddr(Adr *a)
+static int32
+vaddr(Adr *a, Reloc *r)
{
int t;
int32 v;
Sym *s;
+
+ if(r != nil)
+ memset(r, 0, sizeof *r);
t = a->type;
v = a->offset;
@@ -611,30 +515,18 @@ vaddr(Adr *a)
case D_EXTERN:
s = a->sym;
if(s != nil) {
- if(dlm && curp != P)
- reloca = a;
- switch(s->type) {
- case SUNDEF:
- ckoff(s, v);
- case STEXT:
- case SCONST:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += s->value;
- break;
- case SMACHO:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + datsize + s->value;
- break;
- case SFIXED:
- v += s->value;
- break;
- default:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + s->value;
+ if(!s->reachable)
+ sysfatal("unreachable symbol in vaddr - %s", s->name);
+ if(r == nil) {
+ diag("need reloc for %D", a);
+ errorexit();
}
+ r->type = D_ADDR;
+ r->siz = 4;
+ r->off = -1;
+ r->sym = s;
+ r->add = v;
+ v = 0;
}
}
return v;
@@ -644,118 +536,127 @@ void
asmand(Adr *a, int r)
{
int32 v;
- int t;
- Adr aa;
+ int t, scale;
+ Reloc rel;
v = a->offset;
t = a->type;
+ rel.siz = 0;
if(a->index != D_NONE) {
- if(t >= D_INDIR && t < 2*D_INDIR) {
- t -= D_INDIR;
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
- return;
- }
- if(v == 0 && t != D_BP) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- *andptr++ = v;
- return;
+ if(t < D_INDIR || t >= 2*D_INDIR) {
+ switch(t) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
}
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
+ } else
+ t -= D_INDIR;
+
+ if(t == D_NONE) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(v == 0 && rel.siz == 0 && t != D_BP) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ return;
+ }
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ *andptr++ = v;
return;
}
- switch(t) {
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(t >= D_AL && t <= D_F0+7) {
+ if(v)
+ goto bad;
+ *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+
+ scale = a->scale;
+ if(t < D_INDIR || t >= 2*D_INDIR) {
+ switch(a->type) {
default:
goto bad;
case D_STATIC:
case D_EXTERN:
- aa.type = D_NONE+D_INDIR;
+ t = D_NONE;
+ v = vaddr(a, &rel);
break;
case D_AUTO:
case D_PARAM:
- aa.type = D_SP+D_INDIR;
+ t = D_SP;
break;
}
- aa.offset = vaddr(a);
- aa.index = a->index;
- aa.scale = a->scale;
- asmand(&aa, r);
- return;
- }
- if(t >= D_AL && t <= D_F0+7) {
- if(v)
- goto bad;
- *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(t >= D_INDIR && t < 2*D_INDIR) {
+ scale = 1;
+ } else
t -= D_INDIR;
- if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- put4(v);
+
+ if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
+ *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ goto putrelv;
+ }
+ if(t == D_SP) {
+ if(v == 0 && rel.siz == 0) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
return;
}
- if(t == D_SP) {
- if(v == 0) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, D_SP);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a, D_SP);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a, D_SP);
- put4(v);
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ *andptr++ = v;
return;
}
- if(t >= D_AX && t <= D_DI) {
- if(v == 0 && t != D_BP) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- put4(v);
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ goto putrelv;
+ }
+ if(t >= D_AX && t <= D_DI) {
+ if(v == 0 && rel.siz == 0 && t != D_BP) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
- goto bad;
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ andptr[1] = v;
+ andptr += 2;
+ return;
+ }
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ goto putrelv;
}
- switch(a->type) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- aa.type = D_NONE+D_INDIR;
- break;
- case D_AUTO:
- case D_PARAM:
- aa.type = D_SP+D_INDIR;
- break;
+ goto bad;
+
+putrelv:
+ if(rel.siz != 0) {
+ Reloc *r;
+
+ if(rel.siz != 4) {
+ diag("bad rel");
+ goto bad;
+ }
+ r = addrel(cursym);
+ *r = rel;
+ r->off = curp->pc + andptr - and;
}
- aa.index = D_NONE;
- aa.scale = 1;
- aa.offset = vaddr(a);
- asmand(&aa, r);
+ put4(v);
return;
+
bad:
diag("asmand: bad address %D", a);
return;
@@ -921,22 +822,6 @@ subreg(Prog *p, int from, int to)
print("%P\n", p);
}
-// nacl RET:
-// POPL BX
-// ANDL BX, $~31
-// JMP BX
-uchar naclret[] = { 0x5b, 0x83, 0xe3, ~31, 0xff, 0xe3 };
-
-// nacl JMP BX:
-// ANDL BX, $~31
-// JMP BX
-uchar nacljmpbx[] = { 0x83, 0xe3, ~31, 0xff, 0xe3 };
-
-// nacl CALL BX:
-// ANDL BX, $~31
-// CALL BX
-uchar naclcallbx[] = { 0x83, 0xe3, ~31, 0xff, 0xd3 };
-
void
doasm(Prog *p)
{
@@ -945,6 +830,10 @@ doasm(Prog *p)
uchar *t;
int z, op, ft, tt;
int32 v, pre;
+ Reloc rel, *r;
+ Adr *a;
+
+ curp = p; // TODO
pre = prefixof(&p->from);
if(pre)
@@ -990,7 +879,7 @@ found:
case Pb: /* botch */
break;
}
- v = vaddr(&p->from);
+
op = o->op[z];
switch(t[2]) {
default:
@@ -1001,12 +890,6 @@ found:
break;
case Zlit:
- if(HEADTYPE == 8 && p->as == ARET) {
- // native client return.
- for(z=0; z<sizeof(naclret); z++)
- *andptr++ = naclret[z];
- break;
- }
for(; op = o->op[z]; z++)
*andptr++ = op;
break;
@@ -1040,137 +923,100 @@ found:
break;
case Zo_m:
- if(HEADTYPE == 8) {
- Adr a;
-
- switch(p->as) {
- case AJMP:
- if(p->to.type < D_AX || p->to.type > D_DI)
- diag("indirect jmp must use register in native client");
- // ANDL $~31, REG
- *andptr++ = 0x83;
- asmand(&p->to, 04);
- *andptr++ = ~31;
- // JMP REG
- *andptr++ = 0xFF;
- asmand(&p->to, 04);
- return;
-
- case ACALL:
- a = p->to;
- // native client indirect call
- if(a.type < D_AX || a.type > D_DI) {
- // MOVL target into BX
- *andptr++ = 0x8b;
- asmand(&p->to, reg[D_BX]);
- memset(&a, 0, sizeof a);
- a.type = D_BX;
- }
- // ANDL $~31, REG
- *andptr++ = 0x83;
- asmand(&a, 04);
- *andptr++ = ~31;
- // CALL REG
- *andptr++ = 0xFF;
- asmand(&a, 02);
- return;
- }
- }
*andptr++ = op;
asmand(&p->to, o->op[z+1]);
break;
case Zm_ibo:
- v = vaddr(&p->to);
*andptr++ = op;
asmand(&p->from, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->to, nil);
break;
case Zibo_m:
*andptr++ = op;
asmand(&p->to, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_ib:
- v = vaddr(&p->to);
case Zib_:
- if(HEADTYPE == 8 && p->as == AINT && v == 3) {
- // native client disallows all INT instructions.
- // translate INT $3 to HLT.
- *andptr++ = 0xf4;
- break;
- }
+ if(t[2] == Zib_)
+ a = &p->from;
+ else
+ a = &p->to;
+ v = vaddr(a, nil);
*andptr++ = op;
*andptr++ = v;
break;
case Zib_rp:
*andptr++ = op + reg[p->to.type];
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Zil_rp:
*andptr++ = op + reg[p->to.type];
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Zib_rr:
*andptr++ = op;
asmand(&p->to, reg[p->to.type]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_il:
- v = vaddr(&p->to);
case Zil_:
- *andptr++ = op;
- if(o->prefix == Pe) {
- *andptr++ = v;
- *andptr++ = v>>8;
- }
+ if(t[2] == Zil_)
+ a = &p->from;
else
- put4(v);
- break;
-
- case Zm_ilo:
- v = vaddr(&p->to);
+ a = &p->to;
*andptr++ = op;
- asmand(&p->from, o->op[z+1]);
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
+ case Zm_ilo:
case Zilo_m:
*andptr++ = op;
- asmand(&p->to, o->op[z+1]);
+ if(t[2] == Zilo_m) {
+ a = &p->from;
+ asmand(&p->to, o->op[z+1]);
+ } else {
+ a = &p->to;
+ asmand(&p->from, o->op[z+1]);
+ }
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
case Zil_rr:
*andptr++ = op;
asmand(&p->to, reg[p->to.type]);
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Z_rp:
@@ -1185,99 +1031,128 @@ found:
*andptr++ = op;
asmand(&p->to, reg[p->to.type]);
break;
-
- case Zbr:
- q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(q->pc == 0)
- v = 0;
- if(v >= -128 && v <= 127 && !p->bigjmp) {
- *andptr++ = op;
- *andptr++ = v;
- } else {
- p->bigjmp = 1;
- v -= 6-2;
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
- }
- break;
-
+
case Zcall:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 5;
- if(dlm && curp != P && p->to.sym->type == SUNDEF){
- /* v = 0 - p->pc - 5; */
- v = 0;
- ckoff(p->to.sym, v);
- v += p->to.sym->value;
- dynreloc(p->to.sym, p->pc+1, 0);
- }
- *andptr++ = op;
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ if(q == nil) {
+ diag("call without target");
+ errorexit();
+ }
+ if(q->as != ATEXT) {
+ // Could handle this case by making D_PCREL
+ // record the Prog* instead of the Sym*, but let's
+ // wait until the need arises.
+ diag("call of non-TEXT %P", q);
+ errorexit();
}
- break;
-
- case Zcallcon:
- v = p->to.offset - p->pc - 5;
*andptr++ = op;
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->type = D_PCREL;
+ r->siz = 4;
+ r->sym = q->from.sym;
+ put4(0);
break;
+ case Zbr:
case Zjmp:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(q->pc == 0)
- v = 0;
- if(v >= -128 && v <= 127 && !p->bigjmp) {
+ if(q == nil) {
+ diag("jmp/branch without target");
+ errorexit();
+ }
+ if(q->as == ATEXT) {
+ // jump out of function
+ if(t[2] == Zbr) {
+ diag("branch to ATEXT");
+ errorexit();
+ }
+ *andptr++ = o->op[z+1];
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->sym = q->from.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(0);
+ break;
+ }
+
+ // Assumes q is in this function.
+ // TODO: Check in input, preserve in brchain.
+
+ // Fill in backward jump now.
+ if(p->back & 1) {
+ v = q->pc - (p->pc + 2);
+ if(v >= -128) {
*andptr++ = op;
*andptr++ = v;
} else {
- p->bigjmp = 1;
v -= 5-2;
+ if(t[2] == Zbr) {
+ *andptr++ = 0x0f;
+ v--;
+ }
*andptr++ = o->op[z+1];
*andptr++ = v;
*andptr++ = v>>8;
*andptr++ = v>>16;
*andptr++ = v>>24;
}
+ break;
+ }
+
+ // Annotate target; will fill in later.
+ p->forwd = q->comefrom;
+ q->comefrom = p;
+ if(p->back & 2) { // short
+ *andptr++ = op;
+ *andptr++ = 0;
+ } else {
+ if(t[2] == Zbr)
+ *andptr++ = 0x0f;
+ *andptr++ = o->op[z+1];
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
}
break;
+ case Zcallcon:
case Zjmpcon:
- v = p->to.offset - p->pc - 5;
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ if(t[2] == Zcallcon)
+ *andptr++ = op;
+ else
+ *andptr++ = o->op[z+1];
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->type = D_PCREL;
+ r->siz = 4;
+ r->add = p->to.offset;
+ put4(0);
break;
case Zloop:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v < -128 && v > 127)
- diag("loop too far: %P", p);
- *andptr++ = op;
- *andptr++ = v;
+ if(q == nil) {
+ diag("loop without target");
+ errorexit();
}
+ v = q->pc - p->pc - 2;
+ if(v < -128 && v > 127)
+ diag("loop too far: %P", p);
+ *andptr++ = op;
+ *andptr++ = v;
break;
case Zbyte:
+ v = vaddr(&p->from, &rel);
+ if(rel.siz != 0) {
+ rel.siz = op;
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
*andptr++ = v;
if(op > 1) {
*andptr++ = v>>8;
@@ -1342,7 +1217,7 @@ bad:
}
return;
}
- diag("doasm: notfound t2=%lux from=%lux to=%lux %P", t[2], p->from.type, p->to.type, p);
+ diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
return;
mfound:
@@ -1441,204 +1316,10 @@ mfound:
void
asmins(Prog *p)
{
- if(HEADTYPE == 8) {
- ulong npc;
- static Prog *prefix;
-
- // native client
- // - pad indirect jump targets (aka ATEXT) to 32-byte boundary
- // - instructions cannot cross 32-byte boundary
- // - end of call (return address) must be on 32-byte boundary
- if(p->as == ATEXT)
- p->pc += 31 & -p->pc;
- if(p->as == ACALL) {
- // must end on 32-byte boundary.
- // doasm to find out how long the CALL encoding is.
- andptr = and;
- doasm(p);
- npc = p->pc + (andptr - and);
- p->pc += 31 & -npc;
- }
- if(p->as == AREP || p->as == AREPN) {
- // save prefix for next instruction,
- // so that inserted NOPs do not split (e.g.) REP / MOVSL sequence.
- prefix = p;
- andptr = and;
- return;
- }
- andptr = and;
- if(prefix)
- doasm(prefix);
- doasm(p);
- npc = p->pc + (andptr - and);
- if(andptr > and && (p->pc&~31) != ((npc-1)&~31)) {
- // crossed 32-byte boundary; pad to boundary and try again
- p->pc += 31 & -p->pc;
- andptr = and;
- if(prefix)
- doasm(prefix);
- doasm(p);
- }
- prefix = nil;
- } else {
- andptr = and;
- doasm(p);
- }
+ andptr = and;
+ doasm(p);
if(andptr > and+sizeof and) {
print("and[] is too short - %d byte instruction\n", andptr - and);
errorexit();
}
}
-
-enum{
- ABSD = 0,
- ABSU = 1,
- RELD = 2,
- RELU = 3,
-};
-
-int modemap[4] = { 0, 1, -1, 2, };
-
-typedef struct Reloc Reloc;
-
-struct Reloc
-{
- int n;
- int t;
- uchar *m;
- uint32 *a;
-};
-
-Reloc rels;
-
-static void
-grow(Reloc *r)
-{
- int t;
- uchar *m, *nm;
- uint32 *a, *na;
-
- t = r->t;
- r->t += 64;
- m = r->m;
- a = r->a;
- r->m = nm = mal(r->t*sizeof(uchar));
- r->a = na = mal(r->t*sizeof(uint32));
- memmove(nm, m, t*sizeof(uchar));
- memmove(na, a, t*sizeof(uint32));
- free(m);
- free(a);
-}
-
-void
-dynreloc(Sym *s, uint32 v, int abs)
-{
- int i, k, n;
- uchar *m;
- uint32 *a;
- Reloc *r;
-
- if(s->type == SUNDEF)
- k = abs ? ABSU : RELU;
- else
- k = abs ? ABSD : RELD;
- /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */
- k = modemap[k];
- r = &rels;
- n = r->n;
- if(n >= r->t)
- grow(r);
- m = r->m;
- a = r->a;
- for(i = n; i > 0; i--){
- if(v < a[i-1]){ /* happens occasionally for data */
- m[i] = m[i-1];
- a[i] = a[i-1];
- }
- else
- break;
- }
- m[i] = k;
- a[i] = v;
- r->n++;
-}
-
-static int
-sput(char *s)
-{
- char *p;
-
- p = s;
- while(*s)
- cput(*s++);
- cput(0);
- return s-p+1;
-}
-
-void
-asmdyn()
-{
- int i, n, t, c;
- Sym *s;
- uint32 la, ra, *a;
- vlong off;
- uchar *m;
- Reloc *r;
-
- cflush();
- off = seek(cout, 0, 1);
- lput(0);
- t = 0;
- lput(imports);
- t += 4;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->type == SUNDEF){
- lput(s->sig);
- t += 4;
- t += sput(s->name);
- }
-
- la = 0;
- r = &rels;
- n = r->n;
- m = r->m;
- a = r->a;
- lput(n);
- t += 4;
- for(i = 0; i < n; i++){
- ra = *a-la;
- if(*a < la)
- diag("bad relocation order");
- if(ra < 256)
- c = 0;
- else if(ra < 65536)
- c = 1;
- else
- c = 2;
- cput((c<<6)|*m++);
- t++;
- if(c == 0){
- cput(ra);
- t++;
- }
- else if(c == 1){
- wput(ra);
- t += 2;
- }
- else{
- lput(ra);
- t += 4;
- }
- la = *a++;
- }
-
- cflush();
- seek(cout, off, 0);
- lput(t);
-
- if(debug['v']){
- Bprint(&bso, "import table entries = %d\n", imports);
- Bprint(&bso, "export table entries = %d\n", exports);
- }
-}