summaryrefslogtreecommitdiff
path: root/src/cmd/6l
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/6l')
-rw-r--r--src/cmd/6l/6.out.h6
-rw-r--r--src/cmd/6l/Makefile26
-rw-r--r--src/cmd/6l/asm.c1389
-rw-r--r--src/cmd/6l/doc.go4
-rw-r--r--src/cmd/6l/l.h140
-rw-r--r--src/cmd/6l/list.c73
-rw-r--r--src/cmd/6l/obj.c549
-rw-r--r--src/cmd/6l/optab.c6
-rw-r--r--src/cmd/6l/pass.c1112
-rw-r--r--src/cmd/6l/prof.c171
-rw-r--r--src/cmd/6l/span.c1282
11 files changed, 1942 insertions, 2816 deletions
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
index ca5e485c0..709f82ccc 100644
--- a/src/cmd/6l/6.out.h
+++ b/src/cmd/6l/6.out.h
@@ -33,6 +33,7 @@
#define NOPROF (1<<0)
#define DUPOK (1<<1)
#define NOSPLIT (1<<2)
+#define RODATA (1<<3)
/*
* amd64
@@ -389,8 +390,8 @@ enum as
AEND,
- ADYNT,
- AINIT,
+ ADYNT_,
+ AINIT_,
ASIGNAME,
@@ -823,6 +824,7 @@ enum
D_INDIR, /* additive */
D_SIZE = D_INDIR + D_INDIR, /* 6l internal */
+ D_PCREL,
T_TYPE = 1<<0,
T_INDEX = 1<<1,
diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile
index 72bde4465..fba1b42ae 100644
--- a/src/cmd/6l/Makefile
+++ b/src/cmd/6l/Makefile
@@ -2,23 +2,29 @@
# 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=\
- 6l\
+TARG=6l
OFILES=\
asm.$O\
+ data.$O\
+ dwarf.$O\
elf.$O\
enam.$O\
go.$O\
+ ldelf.$O\
+ ldmacho.$O\
lib.$O\
list.$O\
macho.$O\
obj.$O\
optab.$O\
pass.$O\
+ prof.$O\
span.$O\
+ symtab.$O\
HFILES=\
l.h\
@@ -26,20 +32,14 @@ HFILES=\
../ld/lib.h\
../ld/elf.h\
../ld/macho.h\
+ ../ld/dwarf.h\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
enam.c: 6.out.h
sh mkenam
-clean:
- rm -f *.$O $(TARG) *.6 enam.c 6.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+CLEANFILES+=enam.c
%.$O: ../ld/%.c
- $(CC) $(CFLAGS) -c -I. ../ld/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index b45557ebe..9726d227c 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/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"
#define Dbufslop 100
@@ -41,7 +44,6 @@ char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
char freebsddynld[] = "/libexec/ld-elf.so.1";
char zeroes[32];
-Prog* datsort(Prog *l);
vlong
entryvalue(void)
@@ -55,15 +57,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;
}
@@ -113,130 +108,13 @@ vputl(uint64 v)
lputl(v>>32);
}
-void
-strnput(char *s, int n)
-{
- int i;
-
- for(i=0; i<n; i++) {
- cput(*s);
- if(*s != 0)
- s++;
- }
-}
-
-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 = 8 };
-
- 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 = 8 };
-
- 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)
- 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;
}
@@ -260,6 +138,8 @@ enum {
ElfStrShstrtab,
ElfStrSymtab,
ElfStrStrtab,
+ ElfStrRelaPlt,
+ ElfStrPlt,
NElfStr
};
@@ -281,29 +161,461 @@ needlib(char *name)
return 0;
}
+int nelfsym = 1;
+
+static void addpltsym(Sym*);
+static void addgotsym(Sym*);
+
+void
+adddynrel(Sym *s, Reloc *r)
+{
+ Sym *targ, *rela, *got;
+
+ targ = r->sym;
+ cursym = s;
+
+ switch(r->type) {
+ default:
+ if(r->type >= 256) {
+ diag("unexpected relocation type %d", r->type);
+ return;
+ }
+ break;
+
+ // Handle relocations found in ELF object files.
+ case 256 + R_X86_64_PC32:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
+ if(targ->type == 0 || targ->type == SXREF)
+ diag("unknown symbol %s in pcrel", targ->name);
+ r->type = D_PCREL;
+ r->add += 4;
+ return;
+
+ case 256 + R_X86_64_PLT32:
+ r->type = D_PCREL;
+ r->add += 4;
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add += targ->plt;
+ }
+ return;
+
+ case 256 + R_X86_64_GOTPCREL:
+ if(targ->dynimpname == nil || targ->dynexport) {
+ // have symbol
+ // turn MOVQ of GOT entry into LEAQ of symbol itself
+ if(r->off < 2 || s->p[r->off-2] != 0x8b) {
+ diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name);
+ return;
+ }
+ s->p[r->off-2] = 0x8d;
+ r->type = D_PCREL;
+ r->add += 4;
+ return;
+ }
+ addgotsym(targ);
+ r->type = D_PCREL;
+ r->sym = lookup(".got", 0);
+ r->add += 4;
+ r->add += targ->got;
+ return;
+
+ case 256 + R_X86_64_64:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
+ r->type = D_ADDR;
+ return;
+
+ // Handle relocations found in Mach-O object files.
+ case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0:
+ case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0:
+ case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
+ // TODO: What is the difference between all these?
+ r->type = D_ADDR;
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected reloc for dynamic symbol %s", targ->name);
+ return;
+
+ case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ r->type = D_PCREL;
+ return;
+ }
+ // fall through
+ case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1:
+ case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1:
+ case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1:
+ case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
+ case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
+ r->type = D_PCREL;
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
+ return;
+
+ case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
+ if(targ->dynimpname == nil || targ->dynexport) {
+ // have symbol
+ // turn MOVQ of GOT entry into LEAQ of symbol itself
+ if(r->off < 2 || s->p[r->off-2] != 0x8b) {
+ diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name);
+ return;
+ }
+ s->p[r->off-2] = 0x8d;
+ r->type = D_PCREL;
+ return;
+ }
+ // fall through
+ case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
+ if(targ->dynimpname == nil || targ->dynexport)
+ diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
+ addgotsym(targ);
+ r->type = D_PCREL;
+ r->sym = lookup(".got", 0);
+ r->add += targ->got;
+ return;
+ }
+
+ // Handle references to ELF symbols from our own object files.
+ if(targ->dynimpname == nil || targ->dynexport)
+ return;
+
+ switch(r->type) {
+ case D_PCREL:
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ return;
+
+ case D_ADDR:
+ if(s->type != SDATA)
+ break;
+ if(iself) {
+ adddynsym(targ);
+ rela = lookup(".rela", 0);
+ addaddrplus(rela, s, r->off);
+ if(r->siz == 8)
+ adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
+ else
+ adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
+ adduint64(rela, r->add);
+ r->type = 256; // ignore during relocsym
+ return;
+ }
+ if(HEADTYPE == 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;
+ adduint64(got, 0);
+ adduint32(lookup(".linkedit.got", 0), targ->dynid);
+ r->type = 256; // ignore during relocsym
+ return;
+ }
+ break;
+ }
+
+ cursym = s;
+ diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
+}
+
+int
+archreloc(Reloc *r, Sym *s, vlong *val)
+{
+ return -1;
+}
+
+static void
+elfsetupplt(void)
+{
+ Sym *plt, *got;
+
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ if(plt->size == 0) {
+ // pushq got+8(IP)
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x35);
+ addpcrelplus(plt, got, 8);
+
+ // jmpq got+16(IP)
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addpcrelplus(plt, got, 16);
+
+ // nopl 0(AX)
+ adduint32(plt, 0x00401f0f);
+
+ // assume got->size == 0 too
+ addaddrplus(got, lookup(".dynamic", 0), 0);
+ adduint64(got, 0);
+ adduint64(got, 0);
+ }
+}
+
+static void
+addpltsym(Sym *s)
+{
+ if(s->plt >= 0)
+ return;
+
+ adddynsym(s);
+
+ if(iself) {
+ Sym *plt, *got, *rela;
+
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ rela = lookup(".rela.plt", 0);
+ if(plt->size == 0)
+ elfsetupplt();
+
+ // jmpq *got+size(IP)
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addpcrelplus(plt, got, got->size);
+
+ // add to got: pointer to current pos in plt
+ addaddrplus(got, plt, plt->size);
+
+ // pushq $x
+ adduint8(plt, 0x68);
+ adduint32(plt, (got->size-24-8)/8);
+
+ // jmpq .plt
+ adduint8(plt, 0xe9);
+ adduint32(plt, -(plt->size+4));
+
+ // rela
+ addaddrplus(rela, got, got->size-8);
+ adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
+ adduint64(rela, 0);
+
+ s->plt = plt->size - 16;
+ } else if(HEADTYPE == 6) { // Mach-O
+ // To do lazy symbol lookup right, we're supposed
+ // to tell the dynamic loader which library each
+ // symbol comes from and format the link info
+ // section just so. I'm too lazy (ha!) to do that
+ // so for now we'll just use non-lazy pointers,
+ // which don't need to be told which library to use.
+ //
+ // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
+ // has details about what we're avoiding.
+
+ Sym *plt;
+
+ addgotsym(s);
+ plt = lookup(".plt", 0);
+
+ adduint32(lookup(".linkedit.plt", 0), s->dynid);
+
+ // jmpq *got+size(IP)
+ s->plt = plt->size;
+
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addpcrelplus(plt, lookup(".got", 0), s->got);
+ } else {
+ diag("addpltsym: unsupported binary format");
+ }
+}
+
+static void
+addgotsym(Sym *s)
+{
+ Sym *got, *rela;
+
+ if(s->got >= 0)
+ return;
+
+ adddynsym(s);
+ got = lookup(".got", 0);
+ s->got = got->size;
+ adduint64(got, 0);
+
+ if(iself) {
+ rela = lookup(".rela", 0);
+ addaddrplus(rela, got, s->got);
+ adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
+ adduint64(rela, 0);
+ } else if(HEADTYPE == 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);
+
+ if(iself) {
+ s->dynid = nelfsym++;
+
+ d = lookup(".dynsym", 0);
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ adduint32(d, addstring(lookup(".dynstr", 0), name));
+ /* type */
+ t = STB_GLOBAL << 4;
+ if(s->dynexport && s->type == STEXT)
+ t |= STT_FUNC;
+ else
+ t |= STT_OBJECT;
+ adduint8(d, t);
+
+ /* reserved */
+ adduint8(d, 0);
+
+ /* section where symbol is defined */
+ if(!s->dynexport && s->dynimpname != nil)
+ adduint16(d, SHN_UNDEF);
+ else {
+ switch(s->type) {
+ default:
+ case STEXT:
+ t = 11;
+ break;
+ case SRODATA:
+ t = 12;
+ break;
+ case SDATA:
+ t = 13;
+ break;
+ case SBSS:
+ t = 14;
+ break;
+ }
+ adduint16(d, t);
+ }
+
+ /* value */
+ if(s->type == SDYNIMPORT)
+ adduint64(d, 0);
+ else
+ addaddr(d, s);
+
+ /* size of object */
+ adduint64(d, 0);
+
+ if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) {
+ elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
+ addstring(lookup(".dynstr", 0), s->dynimplib));
+ }
+ } else if(HEADTYPE == 6) {
+ // Mach-o symbol nlist64
+ d = lookup(".dynsym", 0);
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ s->dynid = d->size/16;
+ // darwin still puts _ prefixes on all C symbols
+ str = lookup(".dynstr", 0);
+ adduint32(d, str->size);
+ adduint8(str, '_');
+ addstring(str, name);
+ if(s->type == SDYNIMPORT) {
+ adduint8(d, 0x01); // type - N_EXT - external symbol
+ adduint8(d, 0); // section
+ } else {
+ adduint8(d, 0x0f);
+ switch(s->type) {
+ default:
+ case STEXT:
+ adduint8(d, 1);
+ break;
+ case SDATA:
+ adduint8(d, 2);
+ break;
+ case SBSS:
+ adduint8(d, 4);
+ break;
+ }
+ }
+ adduint16(d, 0); // desc
+ if(s->type == SDYNIMPORT)
+ adduint64(d, 0); // value
+ else
+ addaddr(d, s);
+ } else {
+ 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(HEADTYPE != 7 && HEADTYPE != 9)
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");
- if(debug['e']) {
- elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
- elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
- }
+ elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
+ elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
+ dwarfaddshstrings(shstrtab);
}
elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
@@ -316,19 +628,21 @@ doelf(void)
elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
elfstr[ElfStrRela] = addstring(shstrtab, ".rela");
+ elfstr[ElfStrRelaPlt] = addstring(shstrtab, ".rela.plt");
+ elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
/* dynamic symbol table - first entry all zeros */
s = lookup(".dynsym", 0);
s->type = SELFDATA;
s->reachable = 1;
- s->value += ELF64SYMSIZE;
+ s->size += ELF64SYMSIZE;
/* dynamic string table */
s = lookup(".dynstr", 0);
s->type = SELFDATA;
s->reachable = 1;
- s->value += ELF64SYMSIZE;
- addstring(s, "");
+ if(s->size == 0)
+ addstring(s, "");
dynstr = s;
/* relocation table */
@@ -339,15 +653,24 @@ 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 - ??? */
s = lookup(".got.plt", 0);
s->reachable = 1;
+ s->type = SDATA; // writable, not SELFDATA
+
+ s = lookup(".plt", 0);
+ s->reachable = 1;
s->type = SELFDATA;
- /* hash */
- s = lookup(".hash", 0);
+ elfsetupplt();
+
+ s = lookup(".rela.plt", 0);
s->reachable = 1;
s->type = SELFDATA;
@@ -355,78 +678,10 @@ doelf(void)
s = lookup(".dynamic", 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(".rela", 0);
- addaddr(d, s);
- adduint64(d, ELF64_R_INFO(nsym, R_X86_64_64));
- adduint64(d, 0);
- }
-
- nsym++;
-
- d = lookup(".dynsym", 0);
- adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname));
- /* 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);
- }
-
- /* value */
- if(!s->dynexport)
- adduint64(d, 0);
- else
- addaddr(d, s);
-
- /* size of object */
- adduint64(d, 0);
-
- if(!s->dynexport && needlib(s->dynimplib))
- elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib));
- }
- }
-
- elfdynhash(nsym);
/*
* .dynamic table
*/
- s = dynamic;
elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
@@ -437,6 +692,11 @@ doelf(void)
elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
+
+ elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
+ elfwritedynent(s, DT_PLTREL, DT_RELA);
+ elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
+ elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
elfwritedynent(s, DT_NULL, 0);
}
}
@@ -463,15 +723,13 @@ phsh(ElfPhdr *ph, ElfShdr *sh)
void
asmb(void)
{
- Prog *p;
- int32 v, magic;
+ int32 magic;
int a, dynsym;
- uchar *op1;
vlong vl, va, startva, fo, w, symo, elfsymo, elfstro, elfsymsize, machlink;
- vlong symdatva = SYMDATVA;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
+ Section *sect;
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
@@ -481,101 +739,51 @@ asmb(void)
elfsymsize = 0;
elfstro = 0;
elfsymo = 0;
- seek(cout, HEADR, 0);
- pc = INITTEXT;
- curp = firstp;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- if(p->pc != pc) {
- if(!debug['a'])
- print("%P\n", curp);
- diag("phase error %llux sb %llux in %s", p->pc, pc, TNAME);
- pc = p->pc;
- }
- curp = p;
- asmins(p);
- a = (andptr - and);
- if(cbc < a)
- cflush();
- if(debug['a']) {
- Bprint(&bso, pcstr, pc);
- for(op1 = and; op1 < andptr; op1++)
- Bprint(&bso, "%.2ux", *op1);
- for(; op1 < and+Maxand; op1++)
- Bprint(&bso, " ");
- Bprint(&bso, "%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;
- }
- cflush();
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f codeblk\n", cputime());
+ Bflush(&bso);
+
+ sect = segtext.sect;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ codeblk(sect->vaddr, sect->len);
+
+ /* 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);
+ seek(cout, segdata.fileoff, 0);
+ datblk(segdata.vaddr, segdata.filelen);
+
+ machlink = 0;
+ if(HEADTYPE == 6)
+ machlink = domacholink();
switch(HEADTYPE) {
default:
- diag("unknown header type %ld", HEADTYPE);
+ diag("unknown header type %d", HEADTYPE);
case 2:
case 5:
- seek(cout, HEADR+textsize, 0);
break;
case 6:
debug['8'] = 1; /* 64-bit addresses */
- v = HEADR+textsize;
- seek(cout, v, 0);
- v = rnd(v, 4096) - v;
- while(v > 0) {
- cput(0);
- v--;
- }
- cflush();
break;
-
case 7:
case 9:
debug['8'] = 1; /* 64-bit addresses */
- v = rnd(HEADR+textsize, INITRND);
- seek(cout, v, 0);
-
/* index of elf text section; needed by asmelfsym, double-checked below */
- /* debug['d'] causes 8 extra sections before the .text section */
+ /* !debug['d'] causes extra sections before the .text section */
elftextsh = 1;
if(!debug['d'])
- elftextsh += 8;
+ elftextsh += 10;
break;
}
- if(debug['v'])
- Bprint(&bso, "%5.2f datblk\n", cputime());
- Bflush(&bso);
-
- if(dlm){
- char buf[8];
-
- write(cout, buf, INITDAT-textsize);
- textsize = INITDAT;
- }
-
- datap = datsort(datap);
- 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);
- }
-
- machlink = 0;
- if(HEADTYPE == 6)
- machlink = domacholink();
-
symsize = 0;
spsize = 0;
lcsize = 0;
@@ -589,14 +797,14 @@ asmb(void)
case 2:
case 5:
debug['s'] = 1;
- symo = HEADR+textsize+datsize;
+ symo = HEADR+segtext.len+segdata.filelen;
break;
case 6:
- symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND)+machlink;
+ symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
break;
case 7:
case 9:
- symo = rnd(HEADR+textsize, INITRND)+datsize;
+ symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen;
symo = rnd(symo, INITRND);
break;
}
@@ -608,8 +816,6 @@ asmb(void)
* line number table
*/
seek(cout, symo+8, 0);
- if(!debug['s'])
- asmsym();
if(debug['v'])
Bprint(&bso, "%5.2f sp\n", cputime());
Bflush(&bso);
@@ -617,30 +823,26 @@ asmb(void)
Bprint(&bso, "%5.2f pc\n", cputime());
Bflush(&bso);
if(!debug['s'])
- asmlc();
- if(dlm)
- asmdyn();
- if(!debug['s'])
strnput("", INITRND-(8+symsize+lcsize)%INITRND);
cflush();
seek(cout, symo, 0);
lputl(symsize);
lputl(lcsize);
cflush();
- if(!debug['s'] && debug['e']) {
+ if(!debug['s']) {
elfsymo = symo+8+symsize+lcsize;
seek(cout, elfsymo, 0);
- asmelfsym();
+ asmelfsym64();
cflush();
elfstro = seek(cout, 0, 1);
elfsymsize = elfstro - elfsymo;
- write(cout, elfstrdat, elfstrsize);
- }
- } else
- if(dlm){
- seek(cout, HEADR+textsize+datsize, 0);
- asmdyn();
- cflush();
+ ewrite(cout, elfstrdat, elfstrsize);
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+ dwarfemitdebugsections();
+ }
}
if(debug['v'])
@@ -652,12 +854,10 @@ asmb(void)
case 2: /* plan9 */
magic = 4*26*26+7;
magic |= 0x00008000; /* fat header */
- if(dlm)
- magic |= 0x80000000; /* dlm */
lputb(magic); /* magic */
- lputb(textsize); /* sizes */
- lputb(datsize);
- lputb(bsssize);
+ lputb(segtext.filelen); /* sizes */
+ lputb(segdata.filelen);
+ lputb(segdata.len - segdata.filelen);
lputb(symsize); /* nsyms */
vl = entryvalue();
lputb(PADDR(vl)); /* va of entry */
@@ -667,19 +867,17 @@ asmb(void)
break;
case 3: /* plan9 */
magic = 4*26*26+7;
- if(dlm)
- magic |= 0x80000000;
lputb(magic); /* magic */
- lputb(textsize); /* sizes */
- lputb(datsize);
- lputb(bsssize);
+ lputb(segtext.filelen); /* sizes */
+ lputb(segdata.filelen);
+ lputb(segdata.len - segdata.filelen);
lputb(symsize); /* nsyms */
lputb(entryvalue()); /* va of entry */
lputb(spsize); /* sp offsets */
lputb(lcsize); /* line offsets */
break;
case 6:
- asmbmacho(symdatva, symo);
+ asmbmacho();
break;
case 7:
case 9:
@@ -689,7 +887,7 @@ asmb(void)
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]);
@@ -724,41 +922,8 @@ asmb(void)
phsh(ph, sh);
}
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_X+PF_R;
- ph->vaddr = va - fo;
- ph->paddr = va - fo;
- ph->off = 0;
- ph->filesz = w + fo;
- ph->memsz = w + fo;
- ph->align = INITRND;
-
- fo = rnd(fo+w, INITRND);
- va = rnd(va+w, INITRND);
- 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']) {
- 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 */
@@ -776,7 +941,7 @@ asmb(void)
sh->entsize = 8;
sh->addralign = 8;
shsym(sh, lookup(".got.plt", 0));
-
+
dynsym = eh->shnum;
sh = newElfShdr(elfstr[ElfStrDynsym]);
sh->type = SHT_DYNSYM;
@@ -793,6 +958,22 @@ asmb(void)
sh->addralign = 1;
shsym(sh, lookup(".dynstr", 0));
+ sh = newElfShdr(elfstr[ElfStrRelaPlt]);
+ sh->type = SHT_RELA;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = ELF64RELASIZE;
+ sh->addralign = 8;
+ sh->link = dynsym;
+ sh->info = eh->shnum; // .plt
+ shsym(sh, lookup(".rela.plt", 0));
+
+ sh = newElfShdr(elfstr[ElfStrPlt]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC+SHF_EXECINSTR;
+ sh->entsize = 16;
+ sh->addralign = 4;
+ shsym(sh, lookup(".plt", 0));
+
sh = newElfShdr(elfstr[ElfStrHash]);
sh->type = SHT_HASH;
sh->flags = SHF_ALLOC;
@@ -821,6 +1002,17 @@ asmb(void)
ph->type = PT_DYNAMIC;
ph->flags = PF_R + PF_W;
phsh(ph, sh);
+
+ /*
+ * Thread-local storage segment (really just size).
+ */
+ if(tlsoffset != 0) {
+ ph = newElfPhdr();
+ ph->type = PT_TLS;
+ ph->flags = PF_R;
+ ph->memsz = -tlsoffset;
+ ph->align = 8;
+ }
}
ph = newElfPhdr();
@@ -828,93 +1020,41 @@ asmb(void)
ph->flags = PF_W+PF_R;
ph->align = 8;
- fo = ELFRESERVE;
- va = startva + fo;
- w = textsize;
-
if(elftextsh != eh->shnum)
diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
- 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 = 8;
-
- 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 = 8;
-
- 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 = 8;
+ 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 = newElfShdr(elfstr[ElfStrGosymtab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva;
-
- fo += w;
- w = symsize;
+ shsym(sh, lookup("symtab", 0));
- sh = newElfShdr(elfstr[ElfStrGosymtab]);
+ 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;
+ shsym(sh, lookup("pclntab", 0));
- fo += w;
- w = lcsize;
+ sh = newElfShdr(elfstr[ElfStrSymtab]);
+ sh->type = SHT_SYMTAB;
+ sh->off = elfsymo;
+ sh->size = elfsymsize;
+ sh->addralign = 8;
+ sh->entsize = 24;
+ sh->link = eh->shnum; // link to strtab
- sh = newElfShdr(elfstr[ElfStrGopclntab]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
+ sh = newElfShdr(elfstr[ElfStrStrtab]);
+ sh->type = SHT_STRTAB;
+ sh->off = elfstro;
+ sh->size = elfstrsize;
sh->addralign = 1;
- sh->addr = symdatva + 8 + symsize;
-
- if(debug['e']) {
- sh = newElfShdr(elfstr[ElfStrSymtab]);
- sh->type = SHT_SYMTAB;
- sh->off = elfsymo;
- sh->size = elfsymsize;
- sh->addralign = 8;
- sh->entsize = 24;
- sh->link = eh->shnum; // link to strtab
-
- sh = newElfShdr(elfstr[ElfStrStrtab]);
- sh->type = SHT_STRTAB;
- sh->off = elfstro;
- sh->size = elfstrsize;
- sh->addralign = 1;
- }
+
+ dwarfaddelfheaders();
}
sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
@@ -961,354 +1101,91 @@ 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
-outa(int n, uchar *cast, uchar *map, vlong l)
-{
- int i, j;
-
- Bprint(&bso, pcstr, l);
- for(i=0; i<n; i++) {
- j = i;
- if(map != nil)
- j = map[j];
- Bprint(&bso, "%.2ux", cast[j]);
- }
- for(; i<Maxand; i++)
- Bprint(&bso, " ");
- Bprint(&bso, "%P\n", curp);
-}
-
-/*
- * divide-and-conquer list-link
- * sort of Prog* structures.
- * Used for the data block.
- */
-int
-datcmp(Prog *p1, Prog *p2)
+/* Current position in file */
+vlong
+cpos(void)
{
- vlong v1, v2;
-
- v1 = p1->from.offset;
- v2 = p2->from.offset;
- if(v1 > v2)
- return +1;
- if(v1 < v2)
- return -1;
- return 0;
+ return seek(cout, 0, 1) + sizeof(buf.cbuf) - cbc;
}
-Prog*
-dsort(Prog *l)
-{
- Prog *l1, *l2, *le;
-
- if(l == 0 || l->link == 0)
- return l;
-
- l1 = l;
- l2 = l;
- for(;;) {
- l2 = l2->link;
- if(l2 == 0)
- break;
- l2 = l2->link;
- if(l2 == 0)
- break;
- l1 = l1->link;
- }
-
- l2 = l1->link;
- l1->link = 0;
- l1 = dsort(l);
- l2 = dsort(l2);
-
- /* set up lead element */
- if(datcmp(l1, l2) < 0) {
- l = l1;
- l1 = l1->link;
- } else {
- l = l2;
- l2 = l2->link;
- }
- le = l;
-
- for(;;) {
- if(l1 == 0) {
- while(l2) {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- le->link = 0;
- break;
- }
- if(l2 == 0) {
- while(l1) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- }
- break;
- }
- if(datcmp(l1, l2) < 0) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- } else {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- }
- le->link = 0;
- return l;
-}
-
-static Prog *datp;
-
-Prog*
-datsort(Prog *l)
+vlong
+rnd(vlong v, vlong r)
{
- Prog *p;
- Adr *a;
+ vlong c;
- for(p = l; p != P; p = p->link) {
- a = &p->from;
- a->offset += a->sym->value;
- }
- datp = dsort(l);
- return datp;
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
}
void
-datblk(int32 s, int32 n)
+genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
{
- Prog *p;
- uchar *cast;
- int32 l, fl, j;
- vlong o;
- int i, c;
- Adr *a;
-
- for(p = datp; p != P; p = p->link) {
- a = &p->from;
- l = a->offset - s;
- if(l+a->scale < 0)
- continue;
- datp = p;
- break;
- }
-
- memset(buf.dbuf, 0, n+Dbufslop);
- for(p = datp; p != P; p = p->link) {
- a = &p->from;
-
- l = a->offset - s;
- if(l >= n)
- break;
-
- c = a->scale;
- i = 0;
- if(l < 0) {
- if(l+c <= 0)
+ Auto *a;
+ Sym *s;
+ int h;
+
+ 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 SMACHOGOT:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
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 for %d %d", s, j);
- break;
- }
- }
-
- switch(p->to.type) {
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (uchar*)&fl;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi4[i]];
- l++;
- }
- break;
- case 8:
- cast = (uchar*)&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;
+ case SBSS:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
+ continue;
- default:
- o = p->to.offset;
- if(p->to.type == D_SIZE)
- o += 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, o);
- if(p->to.sym->type == Sxxx) {
- curtext = p; // show useful name in diag's output
- diag("missing symbol %s", p->to.sym->name);
- }
- o += p->to.sym->value;
- if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
- o += INITDAT;
- if(dlm)
- dynreloc(p->to.sym, l+s+INITDAT, 1);
- }
- }
- fl = o;
- cast = (uchar*)&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;
- case 8:
- cast = (uchar*)&o;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi8[i]];
- l++;
- }
- break;
+ case SFILE:
+ put(nil, s->name, 'f', s->value, 0, s->version, 0);
+ continue;
}
- 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->offset - s;
- if(l >= n)
- continue;
-
- c = a->scale;
- i = 0;
- if(l < 0)
- continue;
-
- if(a->sym->type == SMACHO)
+ for(s = textp; s != nil; s = s->next) {
+ if(s->text == nil)
continue;
- switch(p->to.type) {
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (uchar*)&fl;
- outa(c, cast, fnuxi4, l+s+INITDAT);
- break;
- case 8:
- cast = (uchar*)&p->to.ieee;
- outa(c, cast, fnuxi8, l+s+INITDAT);
- break;
- }
- break;
-
- case D_SCONST:
- outa(c, (uchar*)p->to.scon, nil, l+s+INITDAT);
- break;
-
- default:
- o = p->to.offset;
- if(p->to.type == D_SIZE)
- o += p->to.sym->size;
- if(p->to.type == D_ADDR) {
- if(p->to.sym) {
- o += p->to.sym->value;
- if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
- o += INITDAT;
- }
- }
- fl = o;
- cast = (uchar*)&fl;
- switch(c) {
- case 1:
- outa(c, cast, inuxi1, l+s+INITDAT);
- break;
- case 2:
- outa(c, cast, inuxi2, l+s+INITDAT);
- break;
- case 4:
- outa(c, cast, inuxi4, l+s+INITDAT);
- break;
- case 8:
- cast = (uchar*)&o;
- outa(c, cast, inuxi8, l+s+INITDAT);
- break;
- }
- break;
- }
+ /* filenames first */
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_FILE)
+ put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
+ else
+ if(a->type == D_FILE1)
+ put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
+
+ put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
+
+ /* frame, auto and param after */
+ put(nil, ".frame", 'm', s->text->to.offset+8, 0, 0, 0);
+
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
+ else
+ if(a->type == D_PARAM)
+ put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
}
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %ud\n", symsize);
+ Bflush(&bso);
}
-
-vlong
-rnd(vlong v, vlong r)
-{
- vlong c;
-
- if(r <= 0)
- return v;
- v += r - 1;
- c = v % r;
- if(c < 0)
- c += r;
- v -= c;
- return v;
-}
-
diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go
index a74e9b5c0..501317f36 100644
--- a/src/cmd/6l/doc.go
+++ b/src/cmd/6l/doc.go
@@ -32,8 +32,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_amd64.
-r dir1:dir2:...
Set the dynamic linker search path when using ELF.
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index 3db0b450a..1c52ea89d 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/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)\
@@ -56,6 +56,7 @@ typedef struct Sym Sym;
typedef struct Auto Auto;
typedef struct Optab Optab;
typedef struct Movtab Movtab;
+typedef struct Reloc Reloc;
struct Adr
{
@@ -67,11 +68,7 @@ struct Adr
Ieee u0ieee;
char *u0sbig;
} u0;
- union
- {
- Auto* u1autom;
- Sym* u1sym;
- } u1;
+ Sym* sym;
short type;
char 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;
+ int64 add;
+ Sym* sym;
+};
struct Prog
{
Adr from;
Adr to;
- Prog *forwd;
+ Prog* forwd;
+ Prog* comefrom;
Prog* link;
- Prog* dlink;
Prog* pcond; /* work on this */
vlong pc;
+ int32 spadj;
int32 line;
short as;
char ft; /* oclass cache */
@@ -102,9 +106,12 @@ struct Prog
uchar mark; /* work on these */
uchar back;
- char width; /* fake for DATA */
+ char width; /* fake for DATA */
char mode; /* 16, 32, or 64 */
};
+#define datasize from.scale
+#define textflag from.scale
+
struct Auto
{
Sym* asym;
@@ -115,25 +122,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 dynid;
+ int32 sig;
+ int32 plt;
+ int32 got;
+ Sym* hash; // in hash table
+ Sym* next; // in text or data list
+ Sym* sub; // in SSUB list
+ Sym* outer; // container of sub
vlong value;
vlong size;
- int32 sig;
- Sym* link;
- Prog* text;
- Prog* data;
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
{
@@ -154,21 +175,25 @@ struct Movtab
enum
{
Sxxx,
+
+ /* order here is order in output file */
STEXT = 1,
+ SELFDATA,
+ SMACHOPLT,
+ SRODATA,
SDATA,
+ SMACHOGOT,
SBSS,
- SDATA1,
+
SXREF,
+ SMACHODYNSTR,
+ SMACHODYNSYM,
+ SMACHOINDIRECTPLT,
+ SMACHOINDIRECTGOT,
SFILE,
SCONST,
- SUNDEF,
-
- SIMPORT,
- SEXPORT,
-
- SMACHO,
- SFIXED,
- SELFDATA,
+ SDYNIMPORT,
+ SSUB = 1<<8,
NHASH = 10007,
NHUNK = 100000,
@@ -274,8 +299,6 @@ enum
Rxx = 1<<1, /* extend sib index */
Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */
- Roffset = 22, /* no. bits for offset in relocation address */
- Rindex = 10, /* no. bits for index in relocation address */
Maxand = 10, /* in -a output width of the byte codes */
};
@@ -300,35 +323,30 @@ EXTERN union
EXTERN int32 HEADR;
EXTERN int32 HEADTYPE;
-EXTERN vlong INITDAT;
EXTERN int32 INITRND;
EXTERN vlong INITTEXT;
+EXTERN vlong INITDAT;
EXTERN char* INITENTRY; /* entry point */
EXTERN Biobuf bso;
-EXTERN int32 bsssize;
EXTERN int cbc;
EXTERN char* cbp;
EXTERN char* pcstr;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
-EXTERN Prog* curtext;
-EXTERN Prog* datap;
-EXTERN Prog* edatap;
-EXTERN vlong datsize;
+EXTERN Sym* cursym;
+EXTERN Sym* datap;
EXTERN vlong elfdatsize;
EXTERN char debug[128];
EXTERN char literal[32];
-EXTERN Prog* etextp;
-EXTERN Prog* firstp;
-EXTERN int xrefresolv;
+EXTERN Sym* textp;
+EXTERN Sym* etextp;
EXTERN char ycover[Ymax*Ymax];
EXTERN uchar* andptr;
EXTERN uchar* rexptr;
EXTERN uchar and[30];
EXTERN int reg[D_NONE];
EXTERN int regrex[D_NONE+1];
-EXTERN Prog* lastp;
EXTERN int32 lcsize;
EXTERN int nerrors;
EXTERN char* noname;
@@ -338,8 +356,7 @@ EXTERN char* rpath;
EXTERN int32 spsize;
EXTERN Sym* symlist;
EXTERN int32 symsize;
-EXTERN Prog* textp;
-EXTERN vlong textsize;
+EXTERN int tlsoffset;
EXTERN int version;
EXTERN Prog zprg;
EXTERN int dtype;
@@ -347,45 +364,29 @@ EXTERN char* paramspace;
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; // export table
-EXTERN int dlm; // dynamically loadable module
-EXTERN int imports, nimports;
-EXTERN int exports, nexports;
-EXTERN char* EXPTAB;
-EXTERN Prog undefp;
EXTERN vlong textstksiz;
EXTERN vlong textarg;
extern char thechar;
-EXTERN int dynptrsize;
EXTERN int elfstrsize;
EXTERN char* elfstrdat;
EXTERN int elftextsh;
-#define UP (&undefp)
-
extern Optab optab[];
extern Optab* opindex[];
extern char* anames[];
int Aconv(Fmt*);
int Dconv(Fmt*);
+int Iconv(Fmt*);
int Pconv(Fmt*);
int Rconv(Fmt*);
int Sconv(Fmt*);
void addhist(int32, int);
void addstackmark(void);
Prog* appendp(Prog*);
-vlong addstring(Sym*, char*);
-vlong adduint32(Sym*, uint32);
-vlong adduint64(Sym*, uint64);
-vlong addaddr(Sym*, Sym*);
-vlong addsize(Sym*, Sym*);
void asmb(void);
void asmdyn(void);
void asmins(Prog*);
-void asmlc(void);
-void asmsp(void);
void asmsym(void);
void asmelfsym(void);
vlong atolwhex(char*);
@@ -393,35 +394,29 @@ Prog* brchain(Prog*);
Prog* brloop(Prog*);
void buildop(void);
void cflush(void);
-void ckoff(Sym*, int32);
Prog* copyp(Prog*);
+vlong cpos(void);
double cputime(void);
void datblk(int32, int32);
void deadcode(void);
void diag(char*, ...);
-void dobss(void);
void dodata(void);
void doelf(void);
-void doinit(void);
void domacho(void);
void doprof1(void);
void doprof2(void);
void dostkoff(void);
-void dynreloc(Sym*, uint32, int);
vlong entryvalue(void);
-void export(void);
void follow(void);
void gethunk(void);
void gotypestrings(void);
-void import(void);
void listinit(void);
Sym* lookup(char*, int);
void lputb(int32);
void lputl(int32);
+void instinit(void);
void main(int, char*[]);
-void mkfwd(void);
void* mysbrk(uint32);
-Prog* newdata(Sym*, int, int, int);
Prog* newtext(Prog*, Sym*);
void nopout(Prog*);
int opsize(Prog*);
@@ -429,19 +424,14 @@ void patch(void);
Prog* prg(void);
void parsetextconst(vlong);
int relinv(int);
-int32 reuse(Prog*, Sym*);
vlong rnd(vlong, vlong);
void span(void);
-void strnput(char*, int);
void undef(void);
-vlong vaddr(Adr*);
vlong symaddr(Sym*);
void vputl(uint64);
void wputb(uint16);
void wputl(uint16);
void xdefine(char*, int, vlong);
-void xfol(Prog*);
-void zaddr(Biobuf*, Adr*, Sym*[]);
void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32);
void machsymseg(uint32, uint32);
@@ -460,3 +450,9 @@ uint32 machheadr(void);
#pragma varargck type "R" int
#pragma varargck type "A" int
#pragma varargck argpos diag 1
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+ DWARFREGSP = 7
+};
diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c
index 195e11d1d..f39efa2e8 100644
--- a/src/cmd/6l/list.c
+++ b/src/cmd/6l/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"
@@ -42,46 +44,36 @@ listinit(void)
fmtinstall('D', Dconv);
fmtinstall('S', Sconv);
fmtinstall('P', Pconv);
+ fmtinstall('I', Iconv);
}
int
Pconv(Fmt *fp)
{
- char str[STRINGSZ], str1[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
- if(p == P)
- return fmtstrcpy(fp, "<P>");
-
bigP = p;
-
- snprint(str1, sizeof(str1), "(%ld)", p->line);
switch(p->as) {
case ATEXT:
if(p->from.scale) {
- snprint(str, sizeof(str), "%-7s %-7A %D,%d,%lD",
- str1, p->as, &p->from, p->from.scale, &p->to);
+ fmtprint(fp, "(%d) %A %D,%d,%D",
+ p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
- snprint(str, sizeof(str), "%-7s %-7A %D,%lD",
- str1, p->as, &p->from, &p->to);
- break;
-
default:
- snprint(str, sizeof(str), "%-7s %-7A %D,%D",
- str1, p->as, &p->from, &p->to);
+ fmtprint(fp, "(%d) %A %D,%D",
+ p->line, p->as, &p->from, &p->to);
break;
-
case ADATA:
- case AINIT:
- case ADYNT:
- snprint(str, sizeof(str), "%-7s %-7A %D/%d,%D",
- str1, p->as, &p->from, p->from.scale, &p->to);
+ 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
@@ -187,7 +179,7 @@ Dconv(Fmt *fp)
break;
case D_FCONST:
- snprint(str, sizeof(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:
@@ -402,19 +394,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/6l/obj.c b/src/cmd/6l/obj.c
index 5a4b6a3fc..96d78c3b9 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/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 <ar.h>
char *noname = "<none>";
@@ -51,28 +54,6 @@ char* paramspace = "FP";
* options used: 189BLQSWabcjlnpsvz
*/
-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)
{
@@ -83,7 +64,7 @@ usage(void)
void
main(int argc, char *argv[])
{
- int i, c;
+ int c;
Binit(&bso, 1, OWRITE);
cout = -1;
@@ -187,6 +168,11 @@ main(int argc, char *argv[])
INITRND = 4096;
break;
case 6: /* apple MACH */
+ /*
+ * OS X system constant - offset from 0(GS) to our TLS.
+ * Explained in ../../libcgo/darwin_amd64.c.
+ */
+ tlsoffset = 0x8a0;
machoinit();
HEADR = MACHORESERVE;
if(INITRND == -1)
@@ -198,6 +184,13 @@ main(int argc, char *argv[])
break;
case 7: /* elf64 executable */
case 9: /* freebsd */
+ /*
+ * ELF uses TLS offset negative from FS.
+ * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
+ * Also known to ../../pkg/runtime/linux/amd64/sys.s
+ * and ../../libcgo/linux_amd64.s.
+ */
+ tlsoffset = -16;
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
@@ -209,117 +202,13 @@ main(int argc, char *argv[])
break;
}
if(INITDAT != 0 && INITRND != 0)
- print("warning: -D0x%llux is ignored because of -R0x%lux\n",
+ print("warning: -D0x%llux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
if(debug['v'])
- Bprint(&bso, "HEADER = -H%ld -T0x%llux -D0x%llux -R0x%lux\n",
+ Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
HEADTYPE, INITTEXT, INITDAT, INITRND);
Bflush(&bso);
- for(i=1; optab[i].as; i++) {
- c = optab[i].as;
- if(opindex[c] != nil) {
- diag("phase error in optab: %d (%A)", i, c);
- errorexit();
- }
- opindex[c] = &optab[i];
- }
-
- for(i=0; i<Ymax; i++)
- ycover[i*Ymax + i] = 1;
-
- ycover[Yi0*Ymax + Yi8] = 1;
- ycover[Yi1*Ymax + Yi8] = 1;
-
- ycover[Yi0*Ymax + Ys32] = 1;
- ycover[Yi1*Ymax + Ys32] = 1;
- ycover[Yi8*Ymax + Ys32] = 1;
-
- ycover[Yi0*Ymax + Yi32] = 1;
- ycover[Yi1*Ymax + Yi32] = 1;
- ycover[Yi8*Ymax + Yi32] = 1;
- ycover[Ys32*Ymax + Yi32] = 1;
-
- ycover[Yi0*Ymax + Yi64] = 1;
- ycover[Yi1*Ymax + Yi64] = 1;
- ycover[Yi8*Ymax + Yi64] = 1;
- ycover[Ys32*Ymax + Yi64] = 1;
- ycover[Yi32*Ymax + Yi64] = 1;
-
- ycover[Yal*Ymax + Yrb] = 1;
- ycover[Ycl*Ymax + Yrb] = 1;
- ycover[Yax*Ymax + Yrb] = 1;
- ycover[Ycx*Ymax + Yrb] = 1;
- ycover[Yrx*Ymax + Yrb] = 1;
- ycover[Yrl*Ymax + Yrb] = 1;
-
- ycover[Ycl*Ymax + Ycx] = 1;
-
- ycover[Yax*Ymax + Yrx] = 1;
- ycover[Ycx*Ymax + Yrx] = 1;
-
- ycover[Yax*Ymax + Yrl] = 1;
- ycover[Ycx*Ymax + Yrl] = 1;
- ycover[Yrx*Ymax + Yrl] = 1;
-
- ycover[Yf0*Ymax + Yrf] = 1;
-
- ycover[Yal*Ymax + Ymb] = 1;
- ycover[Ycl*Ymax + Ymb] = 1;
- ycover[Yax*Ymax + Ymb] = 1;
- ycover[Ycx*Ymax + Ymb] = 1;
- ycover[Yrx*Ymax + Ymb] = 1;
- ycover[Yrb*Ymax + Ymb] = 1;
- ycover[Yrl*Ymax + Ymb] = 1;
- ycover[Ym*Ymax + Ymb] = 1;
-
- ycover[Yax*Ymax + Yml] = 1;
- ycover[Ycx*Ymax + Yml] = 1;
- ycover[Yrx*Ymax + Yml] = 1;
- ycover[Yrl*Ymax + Yml] = 1;
- ycover[Ym*Ymax + Yml] = 1;
-
- ycover[Yax*Ymax + Ymm] = 1;
- ycover[Ycx*Ymax + Ymm] = 1;
- ycover[Yrx*Ymax + Ymm] = 1;
- ycover[Yrl*Ymax + Ymm] = 1;
- ycover[Ym*Ymax + Ymm] = 1;
- ycover[Ymr*Ymax + Ymm] = 1;
-
- ycover[Yax*Ymax + Yxm] = 1;
- ycover[Ycx*Ymax + Yxm] = 1;
- ycover[Yrx*Ymax + Yxm] = 1;
- ycover[Yrl*Ymax + Yxm] = 1;
- ycover[Ym*Ymax + Yxm] = 1;
- ycover[Yxr*Ymax + Yxm] = 1;
-
- for(i=0; i<D_NONE; i++) {
- reg[i] = -1;
- if(i >= D_AL && i <= D_R15B) {
- reg[i] = (i-D_AL) & 7;
- if(i >= D_SPB && i <= D_DIB)
- regrex[i] = 0x40;
- if(i >= D_R8B && i <= D_R15B)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_AH && i<= D_BH)
- reg[i] = 4 + ((i-D_AH) & 7);
- if(i >= D_AX && i <= D_R15) {
- reg[i] = (i-D_AX) & 7;
- if(i >= D_R8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_F0 && i <= D_F0+7)
- reg[i] = (i-D_F0) & 7;
- if(i >= D_M0 && i <= D_M0+7)
- reg[i] = (i-D_M0) & 7;
- if(i >= D_X0 && i <= D_X0+15) {
- reg[i] = (i-D_X0) & 7;
- if(i >= D_X0+8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_CR+8 && i <= D_CR+15)
- regrex[i] = Rxr;
- }
+ instinit();
zprg.link = P;
zprg.pcond = P;
@@ -334,50 +223,20 @@ main(int argc, char *argv[])
pcstr = "%.6llux ";
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 = 0;
- INITDAT = 0;
- INITRND = 8;
- INITENTRY = EXPTAB;
- }
- export();
- }
-
patch();
follow();
doelf();
if(HEADTYPE == 6)
domacho();
- dodata();
- dobss();
dostkoff();
paramspace = "SP"; /* (FP) now (SP) on output */
if(debug['p'])
@@ -386,12 +245,18 @@ main(int argc, char *argv[])
else
doprof2();
span();
- doinit();
+ 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));
}
@@ -400,8 +265,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;
@@ -425,7 +301,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);
a->type = D_NONE;
if(t & T_FCONST) {
a->ieee.l = Bget4(f);
@@ -438,16 +314,17 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
}
if(t & T_TYPE)
a->type = Bgetc(f);
+ if(a->type < 0 || a->type >= D_SIZE)
+ mangle(pn);
adrgotype = S;
if(t & T_GOTYPE)
- adrgotype = h[Bgetc(f)];
+ adrgotype = zsym(pn, f, h);
s = a->sym;
- if(s == S)
- return;
-
t = a->type;
+ if(t == D_INDIR+D_GS)
+ a->offset += tlsoffset;
if(t != D_AUTO && t != D_PARAM) {
- if(adrgotype)
+ if(s && adrgotype)
s->gotype = adrgotype;
return;
}
@@ -484,7 +361,7 @@ void
ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
{
vlong ipc;
- Prog *p, *t;
+ Prog *p;
int v, o, r, skip, mode;
Sym *h[NSYM], *s, *di;
uint32 sig;
@@ -492,7 +369,9 @@ ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
int ntext;
vlong eof;
char src[1024];
+ Prog *lastp;
+ lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
di = S;
@@ -549,7 +428,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;
@@ -557,6 +436,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;
@@ -571,6 +452,7 @@ loop:
histfrogp++;
} else
collapsefrog(s);
+ dwarfaddfrag(s->value, s->name);
}
goto loop;
}
@@ -582,9 +464,18 @@ loop:
p->mode = mode;
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);
+
+ switch(p->as) {
+ case ATEXT:
+ case ADATA:
+ case AGLOBL:
+ if(p->from.sym == S)
+ mangle(pn);
+ break;
+ }
if(debug['W'])
print("%P\n", p);
@@ -606,10 +497,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;
@@ -618,89 +509,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:
@@ -710,23 +553,29 @@ loop:
case ATEXT:
s = p->from.sym;
+ if(s->text != nil) {
+ diag("%s: %s: redefinition", pn, s->name);
+ return;
+ }
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
if(debug['v'])
Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
return;
}
- if(curtext != P) {
+ if(cursym != nil && cursym->text) {
histtoauto();
- curtext->to.autom = curauto;
+ cursym->autom = curauto;
curauto = 0;
}
skip = 0;
- curtext = p;
- if(s == S) {
- diag("%s: no TEXT symbol: %P", pn, p);
- errorexit();
- }
+ 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;
@@ -739,7 +588,10 @@ loop:
diag("%s: type mismatch for %s", pn, s->name);
s->gotype = fromgotype;
}
- newtext(p, s);
+ s->type = STEXT;
+ s->value = pc;
+ lastp = p;
+ p->pc = pc++;
goto loop;
case AMODE:
@@ -772,24 +624,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;
@@ -817,25 +657,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;
@@ -847,13 +676,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;
@@ -895,154 +729,3 @@ appendp(Prog *q)
p->mode = q->mode;
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/6l/optab.c b/src/cmd/6l/optab.c
index c729f0e23..6cc50313e 100644
--- a/src/cmd/6l/optab.c
+++ b/src/cmd/6l/optab.c
@@ -783,7 +783,7 @@ Optab optab[] =
{ AMOVBWSX, ymb_rl, Pq, 0xbe },
{ AMOVBWZX, ymb_rl, Pq, 0xb6 },
{ AMOVO, yxmov, Pe, 0x6f,0x7f },
- { AMOVOU, yxmov, Pf2, 0x6f,0x7f },
+ { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
{ AMOVHLPS, yxr, Pm, 0x12 },
{ AMOVHPD, yxmov, Pe, 0x16,0x17 },
{ AMOVHPS, yxmov, Pm, 0x16,0x17 },
@@ -907,9 +907,9 @@ Optab optab[] =
{ APOPQ, ypopl, Py, 0x58,0x8f,(00) },
{ APOPW, ypopl, Pe, 0x58,0x8f,(00) },
{ APOR, ymm, Py, 0xeb,Pe,0xeb },
- { APSADBW, yxm, Pw, Pe,0xf6 },
+ { APSADBW, yxm, Pq, 0xf6 },
{ APSHUFHW, yxshuf, Pf3, 0x70 },
- { APSHUFL, yxm, Pw, Pe,0x70 },
+ { APSHUFL, yxshuf, Pq, 0x70 },
{ APSHUFLW, yxshuf, Pf2, 0x70 },
{ APSHUFW, ymshuf, Pm, 0x70 },
{ APSLLO, ypsdq, Pq, 0x73,(07) },
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
index f86942926..5c4ed00a6 100644
--- a/src/cmd/6l/pass.c
+++ b/src/cmd/6l/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 ../../runtime/proc.c:/StackGuard
enum
{
@@ -38,157 +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) {
- curtext = p; // for diag messages
- 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 (%lld): %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, 8);
- 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->value = t;
- if(t > MINSIZ)
- continue;
- if(t >= 8)
- datsize = rnd(datsize, 8);
- s->size = t;
- 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->reachable)
- continue;
- if(s->type != SDATA) {
- if(s->type == SDATA1)
- s->type = SDATA;
- continue;
- }
- t = s->value;
- if(t >= 8)
- datsize = rnd(datsize, 8);
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
- if(datsize)
- datsize = rnd(datsize, 8);
-
- 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;
- }
-}
-
-void
-dobss(void)
-{
- int i;
- Sym *s;
- int32 t;
-
- if(dynptrsize > 0) {
- /* dynamic pointer section between data and bss */
- datsize = rnd(datsize, 8);
- }
-
- /* 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;
- if(t >= 8)
- bsssize = rnd(bsssize, 8);
- s->value = bsssize + dynptrsize + datsize;
- bsssize += t;
- }
-
- xdefine("data", SBSS, 0);
- xdefine("edata", SBSS, datsize);
- xdefine("end", SBSS, dynptrsize + bsssize + datsize);
-
- if(debug['s'])
- xdefine("symdat", SFIXED, 0);
- else
- xdefine("symdat", SFIXED, SYMDATVA);
-}
-
Prog*
brchain(Prog *p)
{
@@ -205,19 +58,61 @@ 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 AIRETQ:
+ case AIRETW:
+ case ARETFL:
+ case ARETFQ:
+ case ARETFW:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+pushpop(int a)
+{
+ switch(a) {
+ case APUSHL:
+ case APUSHFL:
+ case APUSHQ:
+ case APUSHFQ:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPQ:
+ case APOPFQ:
+ case APOPW:
+ case APOPFW:
+ return 1;
+ }
+ return 0;
+}
+
+static void
+xfol(Prog *p, Prog **last)
{
Prog *q;
int i;
@@ -226,55 +121,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 AIRETQ:
- case AIRETW:
- case ARETFL:
- case ARETFQ:
- case ARETFW:
-
- case APUSHL:
- case APUSHFL:
- case APUSHQ:
- case APUSHFQ:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPQ:
- case APOPFQ:
- 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)
@@ -287,8 +158,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;
@@ -296,14 +167,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;
@@ -312,15 +182,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 || a == AIRETQ || a == AIRETW ||
- a == ARETFL || a == ARETFQ || a == ARETFW)
+
+ /* 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) {
@@ -328,7 +205,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;
@@ -376,32 +253,11 @@ relinv(int a)
case AJOC: return AJOS;
}
diag("unknown relation: %s in %s", anames[a], TNAME);
+ errorexit();
return 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;
@@ -419,58 +275,58 @@ patch(void)
s = lookup("exit", 0);
vexit = s->value;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
+ for(cursym = textp; cursym != nil; cursym = cursym->next)
+ for(p = cursym->text; p != P; p = p->link) {
+ if(HEADTYPE == 7 || HEADTYPE == 9) {
+ // ELF uses FS instead of GS.
+ if(p->from.type == D_INDIR+D_GS)
+ p->from.type = D_INDIR+D_FS;
+ if(p->to.type == D_INDIR+D_GS)
+ p->to.type = D_INDIR+D_FS;
+ }
if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
s = p->to.sym;
if(s) {
if(debug['c'])
Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- switch(s->type) {
- default:
+ 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
- case STEXT:
- p->to.offset = s->value;
- break;
- case SUNDEF:
- p->pcond = UP;
- p->to.offset = 0;
- break;
}
+ 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 || p->pcond == UP)
+ if(p->to.type != D_BRANCH)
continue;
c = p->to.offset;
- for(q = firstp; q != P;) {
- if(q->forwd != P)
- if(c >= q->forwd->pc) {
- q = q->forwd;
- continue;
- }
+ for(q = cursym->text; q != P;) {
if(c == q->pc)
break;
- q = q->link;
+ if(q->forwd != P && c >= q->forwd->pc)
+ q = q->forwd;
+ else
+ q = q->link;
}
if(q == P) {
- diag("branch out of range in %s\n%P [%s]",
- TNAME, p, p->to.sym ? p->to.sym->name : "<nil>");
+ diag("branch out of range in %s (%#ux)\n%P [%s]",
+ TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
p->to.type = D_NONE;
}
p->pcond = q;
}
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
+ for(cursym = textp; cursym != nil; cursym = cursym->next)
+ for(p = cursym->text; p != P; p = p->link) {
p->mark = 0; /* initialization for follow */
- if(p->pcond != P && p->pcond != UP) {
+ if(p->pcond != P) {
p->pcond = brloop(p->pcond);
if(p->pcond != P)
if(p->to.type == D_BRANCH)
@@ -479,40 +335,6 @@ patch(void)
}
}
-#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;
- }
- }
-}
-
Prog*
brloop(Prog *p)
{
@@ -553,378 +375,275 @@ dostkoff(void)
{
Prog *p, *q, *q1;
int32 autoffset, deltasp;
- int a, f, curframe, curbecome, maxbecome, pcsize;
+ int a, pcsize;
uint32 moreconst1, moreconst2, i;
for(i=0; i<nelem(morename); i++) {
symmorestack[i] = lookup(morename[i], 0);
- pmorestack[i] = P;
- }
-
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- for(i=0; i<nelem(morename); i++) {
- if(p->from.sym == symmorestack[i]) {
- pmorestack[i] = p;
- break;
- }
- }
- }
- }
-
- for(i=0; i<nelem(morename); i++) {
- if(pmorestack[i] == P)
- diag("morestack trampoline not defined");
- }
-
- 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;
-
- 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;
- }
-
- if(debug['b'])
- print("max become = %d\n", maxbecome);
- xdefine("ALEFbecome", STEXT, maxbecome);
-
- 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);
- }
- }
- }
- break;
- }
+ if(symmorestack[i]->type != STEXT)
+ diag("morestack trampoline not defined - %s", morename[i]);
+ pmorestack[i] = symmorestack[i]->text;
}
autoffset = 0;
deltasp = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
- parsetextconst(p->to.offset);
- autoffset = textstksiz;
- if(autoffset < 0)
- autoffset = 0;
-
- q = P;
- q1 = P;
- if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
- diag("nosplit func likely to overflow stack");
-
- if(!(p->from.scale & NOSPLIT)) {
- if(debug['K']) {
- // 6l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_INDIR+D_R15;
- p->from.offset = 8;
- p->to.type = D_SP;
-
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
- }
-
- if(autoffset < StackBig) { // do we need to call morestack?
- if(autoffset <= StackSmall) {
- // small stack
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_R15;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else {
- // large stack
- p = appendp(p);
- p->as = ALEAQ;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(autoffset-StackSmall);
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_R15;
- }
+ p = cursym->text;
+ parsetextconst(p->to.offset);
+ autoffset = textstksiz;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ q = P;
+ q1 = P;
+ if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
+ diag("nosplit func likely to overflow stack");
+
+ if(!(p->from.scale & NOSPLIT)) {
+ p = appendp(p); // load g into CX
+ p->as = AMOVQ;
+ if(HEADTYPE == 7 || HEADTYPE == 9) // ELF uses FS
+ p->from.type = D_INDIR+D_FS;
+ else
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = tlsoffset+0;
+ p->to.type = D_CX;
+
+ if(debug['K']) {
+ // 6l -K means check not only for stack
+ // overflow but stack underflow.
+ // On underflow, INT 3 (breakpoint).
+ // Underflow itself is rare but this also
+ // catches out-of-sync stack guard info
- // common
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q = p;
- }
+ p = appendp(p);
+ p->as = ACMPQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 8;
+ p->to.type = D_SP;
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
- moreconst1 = 0;
- if(autoffset+160 > 4096)
- moreconst1 = (autoffset+160) & ~7LL;
- moreconst2 = textarg;
+ p = appendp(p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q1 = p;
- // 4 varieties varieties (const1==0 cross const2==0)
- // and 6 subvarieties of (const1==0 and const2!=0)
p = appendp(p);
- if(moreconst1 == 0 && moreconst2 == 0) {
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[0];
- p->to.sym = symmorestack[0];
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else
- if(moreconst1 != 0 && moreconst2 == 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst1;
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[1];
- p->to.sym = symmorestack[1];
- } else
- if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
- i = moreconst2/8 + 3;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[i];
- p->to.sym = symmorestack[i];
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else
- if(moreconst1 == 0 && moreconst2 != 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst2;
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
+ p = appendp(p);
+ p->as = ANOP;
+ q1->pcond = p;
+ q1 = P;
+ }
+ if(autoffset < StackBig) { // do we need to call morestack?
+ if(autoffset <= StackSmall) {
+ // small stack
p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[2];
- p->to.sym = symmorestack[2];
+ p->as = ACMPQ;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_CX;
} else {
- p->as = AMOVQ;
- p->from.type = D_CONST;
- p->from.offset = (uint64)moreconst2 << 32;
- p->from.offset |= moreconst1;
+ // large stack
+ p = appendp(p);
+ p->as = ALEAQ;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = -(autoffset-StackSmall);
p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[3];
- p->to.sym = symmorestack[3];
+ p->as = ACMPQ;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_CX;
}
- }
-
- if(q != P)
- q->pcond = p->link;
- if(autoffset) {
+ // common
p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- if(q != P)
- q->pcond = p;
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q = p;
}
- deltasp = autoffset;
- if(debug['K'] > 1 && autoffset) {
- // 6l -KK means double-check for stack overflow
- // even after calling morestack and even if the
- // function is marked as nosplit.
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_R15;
- p->from.offset = 0;
- p->to.type = D_BX;
+ /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
+ moreconst1 = 0;
+ if(autoffset+160+textarg > 4096)
+ moreconst1 = (autoffset+160) & ~7LL;
+ moreconst2 = textarg;
- p = appendp(p);
- p->as = ASUBQ;
+ // 4 varieties varieties (const1==0 cross const2==0)
+ // and 6 subvarieties of (const1==0 and const2!=0)
+ p = appendp(p);
+ if(moreconst1 == 0 && moreconst2 == 0) {
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[0];
+ p->to.sym = symmorestack[0];
+ } else
+ if(moreconst1 != 0 && moreconst2 == 0) {
+ p->as = AMOVL;
p->from.type = D_CONST;
- p->from.offset = StackSmall+32;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_BX;
+ p->from.offset = moreconst1;
+ p->to.type = D_AX;
p = appendp(p);
- p->as = AJHI;
+ p->as = ACALL;
p->to.type = D_BRANCH;
- q1 = p;
+ p->pcond = pmorestack[1];
+ p->to.sym = symmorestack[1];
+ } else
+ if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
+ i = moreconst2/8 + 3;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[i];
+ p->to.sym = symmorestack[i];
+ } else
+ if(moreconst1 == 0 && moreconst2 != 0) {
+ p->as = AMOVL;
+ p->from.type = D_CONST;
+ p->from.offset = moreconst2;
+ p->to.type = D_AX;
p = appendp(p);
- p->as = AINT;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[2];
+ p->to.sym = symmorestack[2];
+ } else {
+ p->as = AMOVQ;
p->from.type = D_CONST;
- p->from.offset = 3;
+ p->from.offset = (uint64)moreconst2 << 32;
+ p->from.offset |= moreconst1;
+ p->to.type = D_AX;
p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- q1 = P;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[3];
+ p->to.sym = symmorestack[3];
}
}
- pcsize = p->mode/8;
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + pcsize;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + pcsize;
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- continue;
- case APUSHQ:
- case APUSHFQ:
- deltasp += 8;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- continue;
- case APOPQ:
- case APOPFQ:
- deltasp -= 8;
- 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) {
+ p = appendp(p);
p->as = AADJSP;
p->from.type = D_CONST;
- p->from.offset = -autoffset;
+ p->from.offset = autoffset;
+ p->spadj = autoffset;
+ if(q != P)
+ q->pcond = p;
+ }
+ deltasp = autoffset;
+ if(debug['K'] > 1 && autoffset) {
+ // 6l -KK means double-check for stack overflow
+ // even after calling morestack and even if the
+ // function is marked as nosplit.
p = appendp(p);
- p->as = ARET;
- }
- continue;
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_BX;
- become:
- q = p;
- p = appendp(p);
- p->as = AJMP;
- p->to = q->to;
- p->pcond = q->pcond;
+ p = appendp(p);
+ p->as = ASUBQ;
+ p->from.type = D_CONST;
+ p->from.offset = StackSmall+32;
+ p->to.type = D_BX;
- q->as = AADJSP;
- q->from = zprg.from;
- q->from.type = D_CONST;
- q->from.offset = -autoffset;
- q->to = zprg.to;
- continue;
+ p = appendp(p);
+ p->as = ACMPQ;
+ p->from.type = D_SP;
+ p->to.type = D_BX;
+
+ p = appendp(p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ q1 = p;
+
+ p = appendp(p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(p);
+ p->as = ANOP;
+ q1->pcond = p;
+ q1 = P;
+ }
+
+ for(; p != P; p = p->link) {
+ pcsize = p->mode/8;
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + pcsize;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + pcsize;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ p->spadj = 4;
+ continue;
+ case APUSHQ:
+ case APUSHFQ:
+ deltasp += 8;
+ p->spadj = 8;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ p->spadj = 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ p->spadj = -4;
+ continue;
+ case APOPQ:
+ case APOPFQ:
+ deltasp -= 8;
+ p->spadj = -8;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ p->spadj = -2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ diag("unbalanced PUSH/POP");
+
+ if(autoffset) {
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = -autoffset;
+ p->spadj = -autoffset;
+ p = appendp(p);
+ p->as = ARET;
+ }
+ }
}
}
@@ -975,180 +694,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=%lld\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);
-}
diff --git a/src/cmd/6l/prof.c b/src/cmd/6l/prof.c
new file mode 100644
index 000000000..25992a40b
--- /dev/null
+++ b/src/cmd/6l/prof.c
@@ -0,0 +1,171 @@
+// Inferno utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Profiling.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+void
+doprof1(void)
+{
+#if 0
+ Sym *s;
+ int32 n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADDL;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->size = n*4;
+#endif
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ if(p->from.sym == s2) {
+ p->from.scale = 1;
+ ps2 = p;
+ }
+ if(p->from.sym == s4) {
+ p->from.scale = 1;
+ ps4 = p;
+ }
+ }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+
+ if(p->from.scale & NOPROF) /* dont profile */
+ continue;
+
+ /*
+ * JMPL profin
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = ps2;
+ p->to.sym = s2;
+
+ for(; p; p=p->link) {
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * JAL profout
+ */
+ p->as = ACALL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->pcond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+ }
+ }
+ }
+}
diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c
index 15f931bcb..5251f19bb 100644
--- a/src/cmd/6l/span.c
+++ b/src/cmd/6l/span.c
@@ -28,34 +28,33 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Instruction layout.
+
#include "l.h"
#include "../ld/lib.h"
-#include "../ld/elf.h"
static int rexflag;
static int asmode;
+static vlong vaddr(Adr*, Reloc*);
void
-span(void)
+span1(Sym *s)
{
Prog *p, *q;
- int32 v;
- vlong 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;
+
+ if(s->p != nil)
+ return;
+
+ for(p = s->text; p != P; p = p->link) {
+ p->back = 2; // use short branches first time through
+ if((q = p->pcond) != P && (q->back & 2))
+ p->back |= 1; // backward jump
+
if(p->as == AADJSP) {
p->to.type = D_SP;
v = -p->from.offset;
@@ -70,378 +69,253 @@ span(void)
p->as = ANOP;
}
}
+
n = 0;
+ do {
+ loop = 0;
+ memset(s->r, 0, s->nr*sizeof s->r[0]);
+ s->nr = 0;
+ s->np = 0;
+ c = 0;
+ for(p = s->text; p != P; p = p->link) {
+ p->pc = c;
+
+ // process forward jumps to p
+ for(q = p->comefrom; q != P; q = q->forwd) {
+ v = p->pc - (q->pc + q->mark);
+ if(q->back & 2) { // short
+ if(v > 127) {
+ loop++;
+ q->back ^= 2;
+ }
+ s->p[q->pc+1] = v;
+ } else {
+ bp = s->p + q->pc + q->mark - 4;
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp++ = v>>24;
+ }
+ }
+ p->comefrom = P;
-start:
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
- Bflush(&bso);
- c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- if(p->to.type == D_BRANCH)
- if(p->back)
- p->pc = c;
- asmins(p);
- p->pc = c;
- m = andptr-and;
- p->mark = m;
- c += m;
- }
-
-loop:
- n++;
- if(debug['v'])
- Bprint(&bso, "%5.2f span %d\n", cputime(), n);
- Bflush(&bso);
- if(n > 50) {
- print("span must be looping\n");
- errorexit();
- }
- again = 0;
- c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- if(p->to.type == D_BRANCH || p->back & 0100) {
- if(p->back)
- p->pc = c;
asmins(p);
+ p->pc = c;
m = andptr-and;
- if(m != p->mark) {
- p->mark = m;
- again++;
- }
+ symgrow(s, p->pc+m);
+ memmove(s->p+p->pc, and, m);
+ p->mark = m;
+ c += m;
}
- p->pc = c;
- c += p->mark;
- }
- if(again) {
- textsize = c;
- goto loop;
- }
- if(INITRND) {
- INITDAT = rnd(c, INITRND);
- if(INITDAT != idat) {
- idat = INITDAT;
- goto start;
+ if(++n > 20) {
+ diag("span must be looping");
+ errorexit();
+ }
+ } while(loop);
+ s->size = c;
+
+ if(debug['a'] > 1) {
+ print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
+ for(i=0; i<s->np; i++) {
+ print(" %.2ux", s->p[i]);
+ if(i%16 == 15)
+ print("\n %.6ux", i+1);
+ }
+ if(i%16)
+ print("\n");
+
+ for(i=0; i<s->nr; i++) {
+ Reloc *r;
+
+ r = &s->r[i];
+ print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
}
}
- xdefine("etext", STEXT, c);
- if(debug['v'])
- Bprint(&bso, "etext = %llux\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, vlong v)
+span(void)
{
- Sym *s;
+ Prog *p, *q;
+ int32 v;
+ int n;
- 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;
-}
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
-void
-putsymb(char *s, int t, vlong v, vlong size, int ver, Sym *go)
-{
- int i, f, l;
- vlong gv;
-
- if(t == 'f')
- s++;
- l = 4;
- if(!debug['8']){
- lputb(v>>32);
- l = 8;
- }
- lputb(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)
- diag("unreachable type %s", go->name);
- gv = go->value+INITDAT;
- }
- if(l == 8)
- lputb(gv>>32);
- lputb(gv);
- symsize += l + 1 + i+1 + l;
-
- if(debug['n']) {
- if(t == 'z' || t == 'Z') {
- Bprint(&bso, "%c %.8llux ", 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);
+ // NOTE(rsc): If we get rid of the globals we should
+ // be able to parallelize these iterations.
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->p != nil)
+ continue;
+ // TODO: move into span1
+ for(p = cursym->text; p != P; p = p->link) {
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == P)
+ p->pcond = p;
+ if((q = p->pcond) != P)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = p->mode != 64? AADDL: AADDQ;
+ if(v < 0) {
+ p->as = p->mode != 64? ASUBL: ASUBQ;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
}
- Bprint(&bso, "\n");
- return;
}
- if(ver)
- Bprint(&bso, "%c %.8llux %s<%d> %s (%.8llux)\n", t, v, s, ver, go ? go->name : "", gv);
- else
- Bprint(&bso, "%c %.8llux %s %s (%.8llux)\n", t, v, s, go ? go->name : "", gv);
+ span1(cursym);
}
}
void
-genasmsym(void (*put)(char*, int, vlong, vlong, int, Sym*))
+xdefine(char *p, int t, vlong v)
{
- Prog *p;
- Auto *a;
Sym *s;
- int h;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- put(s->name, 'T', s->value, s->size, 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;
- put(s->name, 'D', s->value, s->size, s->version, s->gotype);
- continue;
-
- case SDATA:
- case SELFDATA:
- if(!s->reachable)
- continue;
- put(s->name, 'D', s->value+INITDAT, s->size, s->version, s->gotype);
- continue;
-
- case SMACHO:
- if(!s->reachable)
- continue;
- put(s->name, 'D', s->value+INITDAT+datsize+bsssize, s->size, s->version, s->gotype);
- continue;
-
- case SBSS:
- if(!s->reachable)
- continue;
- put(s->name, 'B', s->value+INITDAT, s->size, s->version, s->gotype);
- continue;
-
- case SFIXED:
- put(s->name, 'B', s->value, s->size, s->version, s->gotype);
- continue;
-
- case SFILE:
- put(s->name, 'f', s->value, 0, 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)
- put(a->asym->name, 'z', a->aoffset, 0, 0, 0);
- else
- if(a->type == D_FILE1)
- put(a->asym->name, 'Z', a->aoffset, 0, 0, 0);
-
- if(!s->reachable)
- continue;
- put(s->name, 'T', s->value, s->size, s->version, s->gotype);
-
- /* frame, auto and param after */
- put(".frame", 'm', p->to.offset+8, 0, 0, 0);
-
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_AUTO)
- put(a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
- else
- if(a->type == D_PARAM)
- put(a->asym->name, 'p', a->aoffset, 0, 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
-asmsym(void)
+instinit(void)
{
- genasmsym(putsymb);
-}
+ int c, i;
-char *elfstrdat;
-int elfstrsize;
-int maxelfstr;
-
-int
-putelfstr(char *s)
-{
- int off, n;
-
- if(elfstrsize == 0 && s[0] != 0) {
- // first entry must be empty string
- putelfstr("");
- }
-
- n = strlen(s)+1;
- if(elfstrsize+n > maxelfstr) {
- maxelfstr = 2*(elfstrsize+n+(1<<20));
- elfstrdat = realloc(elfstrdat, maxelfstr);
- }
- off = elfstrsize;
- elfstrsize += n;
- memmove(elfstrdat+off, s, n);
- return off;
-}
-
-void
-putelfsymb(char *s, int t, vlong addr, vlong size, int ver, Sym *go)
-{
- int bind, type, shndx, stroff;
-
- bind = STB_GLOBAL;
- switch(t) {
- default:
- return;
- case 'T':
- type = STT_FUNC;
- shndx = elftextsh + 0;
- break;
- case 'D':
- type = STT_OBJECT;
- shndx = elftextsh + 1;
- break;
- case 'B':
- type = STT_OBJECT;
- shndx = elftextsh + 2;
- break;
+ for(i=1; optab[i].as; i++) {
+ c = optab[i].as;
+ if(opindex[c] != nil) {
+ diag("phase error in optab: %d (%A)", i, c);
+ errorexit();
+ }
+ opindex[c] = &optab[i];
}
-
- stroff = putelfstr(s);
- lputl(stroff); // string
- cput((bind<<4)|(type&0xF));
- cput(0);
- wputl(shndx);
- vputl(addr);
- vputl(size);
-}
-void
-asmelfsym(void)
-{
- genasmsym(putelfsymb);
-}
-
-void
-asmlc(void)
-{
- vlong oldpc;
- Prog *p;
- int32 oldlc, 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['O'])
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- continue;
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Ys32] = 1;
+ ycover[Yi1*Ymax + Ys32] = 1;
+ ycover[Yi8*Ymax + Ys32] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+ ycover[Ys32*Ymax + Yi32] = 1;
+
+ ycover[Yi0*Ymax + Yi64] = 1;
+ ycover[Yi1*Ymax + Yi64] = 1;
+ ycover[Yi8*Ymax + Yi64] = 1;
+ ycover[Ys32*Ymax + Yi64] = 1;
+ ycover[Yi32*Ymax + Yi64] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+ ycover[Yrl*Ymax + Yrb] = 1;
+
+ ycover[Ycl*Ymax + Ycx] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Yrl*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ ycover[Yax*Ymax + Ymm] = 1;
+ ycover[Ycx*Ymax + Ymm] = 1;
+ ycover[Yrx*Ymax + Ymm] = 1;
+ ycover[Yrl*Ymax + Ymm] = 1;
+ ycover[Ym*Ymax + Ymm] = 1;
+ ycover[Ymr*Ymax + Ymm] = 1;
+
+ ycover[Yax*Ymax + Yxm] = 1;
+ ycover[Ycx*Ymax + Yxm] = 1;
+ ycover[Yrx*Ymax + Yxm] = 1;
+ ycover[Yrl*Ymax + Yxm] = 1;
+ ycover[Ym*Ymax + Yxm] = 1;
+ ycover[Yxr*Ymax + Yxm] = 1;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_R15B) {
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_SPB && i <= D_DIB)
+ regrex[i] = 0x40;
+ if(i >= D_R8B && i <= D_R15B)
+ regrex[i] = Rxr | Rxx | Rxb;
}
- if(debug['O'])
- 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['O'])
- Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
- v -= s;
- lcsize++;
+ if(i >= D_AH && i<= D_BH)
+ reg[i] = 4 + ((i-D_AH) & 7);
+ if(i >= D_AX && i <= D_R15) {
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_R8)
+ regrex[i] = Rxr | Rxx | Rxb;
}
- 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['O']) {
- 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, "%6llux %P\n",
- p->pc, p);
- }
- lcsize += 5;
- continue;
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
+ if(i >= D_M0 && i <= D_M0+7)
+ reg[i] = (i-D_M0) & 7;
+ if(i >= D_X0 && i <= D_X0+15) {
+ reg[i] = (i-D_X0) & 7;
+ if(i >= D_X0+8)
+ regrex[i] = Rxr | Rxx | Rxb;
}
- if(s > 0) {
- cput(0+s); /* 1-64 +lc */
- if(debug['O']) {
- Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- }
- } else {
- cput(64-s); /* 65-128 -lc */
- if(debug['O']) {
- Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- }
- }
- lcsize++;
+ if(i >= D_CR+8 && i <= D_CR+15)
+ regrex[i] = Rxr;
}
- while(lcsize & 1) {
- s = 129;
- cput(s);
- lcsize++;
+}
+
+int
+prefixof(Adr *a)
+{
+ switch(a->type) {
+ case D_INDIR+D_CS:
+ return 0x2e;
+ case D_INDIR+D_DS:
+ return 0x3e;
+ case D_INDIR+D_ES:
+ return 0x26;
+ case D_INDIR+D_FS:
+ return 0x64;
+ case D_INDIR+D_GS:
+ return 0x65;
}
- if(debug['v'] || debug['O'])
- Bprint(&bso, "lcsize = %ld\n", lcsize);
- Bflush(&bso);
+ return 0;
}
int
@@ -641,11 +515,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;
@@ -670,10 +544,10 @@ asmidx(Adr *a, int base)
case D_BP:
case D_SI:
case D_DI:
- i = reg[(int)a->index] << 3;
+ i = reg[index] << 3;
break;
}
- switch(a->scale) {
+ switch(scale) {
default:
goto bad;
case 1:
@@ -719,7 +593,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;
}
@@ -727,10 +601,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;
@@ -739,12 +609,25 @@ put4(int32 v)
}
static void
-put8(vlong v)
+relput4(Prog *p, Adr *a)
{
- if(dlm && curp != P && reloca != nil){
- dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); /* TO DO */
- reloca = nil;
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(a, &rel);
+ if(rel.siz != 0) {
+ if(rel.siz != 4)
+ diag("bad reloc");
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
}
+ put4(v);
+}
+
+static void
+put8(vlong v)
+{
andptr[0] = v;
andptr[1] = v>>8;
andptr[2] = v>>16;
@@ -756,24 +639,41 @@ put8(vlong v)
andptr += 8;
}
+/*
+static void
+relput8(Prog *p, Adr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(a, &rel);
+ if(rel.siz != 0) {
+ r = addrel(cursym);
+ *r = rel;
+ r->siz = 8;
+ r->off = p->pc + andptr - and;
+ }
+ put8(v);
+}
+*/
+
vlong
symaddr(Sym *s)
{
- 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;
}
-vlong
-vaddr(Adr *a)
+static vlong
+vaddr(Adr *a, Reloc *r)
{
int t;
vlong v;
Sym *s;
+
+ if(r != nil)
+ memset(r, 0, sizeof *r);
t = a->type;
v = a->offset;
@@ -783,34 +683,18 @@ vaddr(Adr *a)
case D_STATIC:
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)
- diag("unreachable symbol in vaddr - %s", s->name);
- if((uvlong)s->value < (uvlong)INITTEXT)
- v += INITTEXT; /* TO DO */
- v += s->value;
- break;
- case SFIXED:
- v += s->value;
- break;
- case SMACHO:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + datsize + s->value;
- break;
- default:
- if(!s->reachable)
- diag("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + s->value;
- }
+ if(!s->reachable)
+ diag("unreachable symbol in vaddr - %s", s->name);
+ if(r == nil) {
+ diag("need reloc for %D", a);
+ errorexit();
}
+ r->type = D_ADDR;
+ r->siz = 4; // TODO: 8 for external symbols
+ r->off = -1; // caller must fill in
+ r->sym = s;
+ r->add = v;
+ v = 0;
}
return v;
}
@@ -819,55 +703,51 @@ static void
asmandsz(Adr *a, int r, int rex, int m64)
{
int32 v;
- int t;
- Adr aa;
+ int t, scale;
+ Reloc rel;
rex &= (0x40 | Rxr);
v = a->offset;
t = a->type;
+ rel.siz = 0;
if(a->index != D_NONE) {
- if(t >= D_INDIR) {
- t -= D_INDIR;
- rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
- return;
- }
- if(v == 0 && t != D_BP && t != D_R13) {
- *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) {
+ 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;
+ rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
+ if(t == D_NONE) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
return;
}
- switch(t) {
- 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;
+ if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ return;
}
- aa.offset = vaddr(a);
- aa.index = a->index;
- aa.scale = a->scale;
- asmandsz(&aa, r, rex, m64);
- return;
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ *andptr++ = v;
+ return;
+ }
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
}
if(t >= D_AL && t <= D_X0+15) {
if(v)
@@ -876,72 +756,84 @@ asmandsz(Adr *a, int r, int rex, int m64)
rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
return;
}
- if(t >= D_INDIR) {
+
+ scale = a->scale;
+ if(t < D_INDIR) {
+ switch(a->type) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ scale = 1;
+ } else
t -= D_INDIR;
- rexflag |= (regrex[t] & Rxb) | rex;
- if(t == D_NONE) {
- if(asmode != 64){
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- put4(v);
- return;
- }
- /* temporary */
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
- *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
- put4(v);
+
+ rexflag |= (regrex[t] & Rxb) | rex;
+ if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
+ if(asmode != 64){
+ *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ goto putrelv;
+ }
+ /* temporary */
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
+ *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
+ goto putrelv;
+ }
+ if(t == D_SP || t == D_R12) {
+ if(v == 0) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
return;
}
- if(t == D_SP || t == D_R12) {
- if(v == 0) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(a, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(a, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
+ if(v >= -128 && v < 128) {
+ *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ *andptr++ = v;
return;
}
- if(t >= D_AX && t <= D_R15) {
- if(v == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- put4(v);
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ goto putrelv;
+ }
+ if(t >= D_AX && t <= D_R15) {
+ if(v == 0 && t != D_BP && t != D_R13) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
- goto bad;
+ if(v >= -128 && v < 128) {
+ andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ andptr[1] = v;
+ andptr += 2;
+ return;
+ }
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ goto putrelv;
}
- 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);
- asmandsz(&aa, r, rex, m64);
+ put4(v);
return;
+
bad:
diag("asmand: bad address %D", a);
return;
@@ -1173,14 +1065,25 @@ doasm(Prog *p)
Prog *q, pp;
uchar *t;
Movtab *mo;
- int z, op, ft, tt, xo, l;
+ int z, op, ft, tt, xo, l, pre;
vlong v;
+ Reloc rel, *r;
+ Adr *a;
+
+ curp = p; // TODO
o = opindex[p->as];
if(o == nil) {
diag("asmins: missing op %P", p);
return;
}
+
+ pre = prefixof(&p->from);
+ if(pre)
+ *andptr++ = pre;
+ pre = prefixof(&p->to);
+ if(pre)
+ *andptr++ = pre;
if(p->ft == 0)
p->ft = oclass(&p->from);
@@ -1244,7 +1147,7 @@ found:
diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
break;
}
- v = vaddr(&p->from);
+
op = o->op[z];
if(op == 0x0f) {
*andptr++ = op;
@@ -1350,64 +1253,74 @@ found:
break;
case Zm_ibo:
- v = vaddr(&p->to);
*andptr++ = op;
asmando(&p->from, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->to, nil);
break;
case Zibo_m:
*andptr++ = op;
asmando(&p->to, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Zibo_m_xm:
z = mediaop(o, op, t[3], z);
asmando(&p->to, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_ib:
- v = vaddr(&p->to);
case Zib_:
+ if(t[2] == Zib_)
+ a = &p->from;
+ else
+ a = &p->to;
*andptr++ = op;
- *andptr++ = v;
+ *andptr++ = vaddr(a, nil);
break;
case Zib_rp:
rexflag |= regrex[p->to.type] & (Rxb|0x40);
*andptr++ = op + reg[p->to.type];
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Zil_rp:
rexflag |= regrex[p->to.type] & Rxb;
*andptr++ = op + reg[p->to.type];
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Zo_iw:
*andptr++ = op;
if(p->from.type != D_NONE){
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
break;
case Ziq_rp:
+ v = vaddr(&p->from, &rel);
l = v>>32;
- if(l == 0){
+ if(l == 0 && rel.siz != 8){
//p->mark |= 0100;
//print("zero: %llux %P\n", v, p);
rexflag &= ~(0x40|Rxw);
rexflag |= regrex[p->to.type] & Rxb;
*andptr++ = 0xb8 + reg[p->to.type];
+ if(rel.type != 0) {
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
put4(v);
}else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */
//p->mark |= 0100;
@@ -1419,6 +1332,11 @@ found:
//print("all: %llux %P\n", v, p);
rexflag |= regrex[p->to.type] & Rxb;
*andptr++ = op + reg[p->to.type];
+ if(rel.type != 0) {
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
put8(v);
}
break;
@@ -1426,53 +1344,54 @@ found:
case Zib_rr:
*andptr++ = op;
asmand(&p->to, &p->to);
- *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;
- asmando(&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;
- asmando(&p->to, o->op[z+1]);
+ if(t[2] == Zilo_m) {
+ a = &p->from;
+ asmando(&p->to, o->op[z+1]);
+ } else {
+ a = &p->to;
+ asmando(&p->from, o->op[z+1]);
+ }
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
case Zil_rr:
*andptr++ = op;
asmand(&p->to, &p->to);
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Z_rp:
@@ -1490,74 +1409,132 @@ found:
asmand(&p->to, &p->to);
break;
- case Zbr:
+ case Zcall:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v >= -128 && v <= 127) {
- *andptr++ = op;
- *andptr++ = v;
- } else {
- v -= 6-2;
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *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();
}
+ *andptr++ = op;
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->sym = q->from.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(0);
break;
- case Zcall:
+ case Zbr:
+ case Zjmp:
+ // TODO: jump across functions needs reloc
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);
+ if(q == nil) {
+ diag("jmp/branch without target");
+ errorexit();
+ }
+ if(q->as == ATEXT) {
+ if(t[2] == Zbr) {
+ diag("branch to ATEXT");
+ errorexit();
}
- *andptr++ = op;
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ *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;
}
- break;
+ // Assumes q is in this function.
+ // TODO: Check in input, preserve in brchain.
- case Zjmp:
- q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v >= -128 && v <= 127) {
+ // Fill in backward jump now.
+ if(p->back & 1) {
+ v = q->pc - (p->pc + 2);
+ if(v >= -128) {
*andptr++ = op;
*andptr++ = v;
} else {
v -= 5-2;
+ if(t[2] == Zbr) {
+ *andptr++ = 0x0f;
+ v--;
+ }
*andptr++ = o->op[z+1];
*andptr++ = v;
*andptr++ = v>>8;
*andptr++ = v>>16;
*andptr++ = v>>24;
}
+ break;
+ }
+
+ // Annotate target; will fill in later.
+ p->forwd = q->comefrom;
+ q->comefrom = p;
+ if(p->back & 2) { // short
+ *andptr++ = op;
+ *andptr++ = 0;
+ } else {
+ if(t[2] == Zbr)
+ *andptr++ = 0x0f;
+ *andptr++ = o->op[z+1];
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
}
break;
+
+/*
+ v = q->pc - p->pc - 2;
+ if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
+ *andptr++ = op;
+ *andptr++ = v;
+ } else {
+ v -= 5-2;
+ if(t[2] == Zbr) {
+ *andptr++ = 0x0f;
+ v--;
+ }
+ *andptr++ = o->op[z+1];
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ }
+*/
+ break;
case Zloop:
q = p->pcond;
- if(q) {
- 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;
@@ -1730,6 +1707,7 @@ void
asmins(Prog *p)
{
int n, np, c;
+ Reloc *r;
rexflag = 0;
andptr = and;
@@ -1739,7 +1717,7 @@ asmins(Prog *p)
/*
* as befits the whole approach of the architecture,
* the rex prefix must appear before the first opcode byte
- * (and thus after any 66/67/f2/f3 prefix bytes, but
+ * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but
* before the 0f opcode escape!), or it might be ignored.
* note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
*/
@@ -1748,164 +1726,16 @@ asmins(Prog *p)
n = andptr - and;
for(np = 0; np < n; np++) {
c = and[np];
- if(c != 0x66 && c != 0xf2 && c != 0xf3 && c != 0x67)
+ if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
break;
}
+ for(r=cursym->r+cursym->nr; r-- > cursym->r; ) {
+ if(r->off < p->pc)
+ break;
+ r->off++;
+ }
memmove(and+np+1, and+np, n-np);
and[np] = 0x40 | rexflag;
andptr++;
}
}
-
-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);
- lputb(0);
- t = 0;
- lputb(imports);
- t += 4;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->type == SUNDEF){
- lputb(s->sig);
- t += 4;
- t += sput(s->name);
- }
-
- la = 0;
- r = &rels;
- n = r->n;
- m = r->m;
- a = r->a;
- lputb(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){
- wputb(ra);
- t += 2;
- }
- else{
- lputb(ra);
- t += 4;
- }
- la = *a++;
- }
-
- cflush();
- seek(cout, off, 0);
- lputb(t);
-
- if(debug['v']){
- Bprint(&bso, "import table entries = %d\n", imports);
- Bprint(&bso, "export table entries = %d\n", exports);
- }
-}