summaryrefslogtreecommitdiff
path: root/src/cmd/5l
diff options
context:
space:
mode:
authorMichael Stapelberg <stapelberg@debian.org>2013-03-04 21:27:36 +0100
committerMichael Stapelberg <michael@stapelberg.de>2013-03-04 21:27:36 +0100
commit04b08da9af0c450d645ab7389d1467308cfc2db8 (patch)
treedb247935fa4f2f94408edc3acd5d0d4f997aa0d8 /src/cmd/5l
parent917c5fb8ec48e22459d77e3849e6d388f93d3260 (diff)
downloadgolang-upstream/1.1_hg20130304.tar.gz
Imported Upstream version 1.1~hg20130304upstream/1.1_hg20130304
Diffstat (limited to 'src/cmd/5l')
-rw-r--r--src/cmd/5l/5.out.h31
-rw-r--r--src/cmd/5l/asm.c1055
-rw-r--r--src/cmd/5l/doc.go4
-rw-r--r--src/cmd/5l/l.h57
-rw-r--r--src/cmd/5l/list.c8
-rw-r--r--src/cmd/5l/noop.c50
-rw-r--r--src/cmd/5l/obj.c223
-rw-r--r--src/cmd/5l/optab.c41
-rw-r--r--src/cmd/5l/pass.c77
-rw-r--r--src/cmd/5l/softfloat.c3
-rw-r--r--src/cmd/5l/span.c107
11 files changed, 962 insertions, 694 deletions
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index 569536ebd..4aef8a27f 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -49,12 +49,11 @@
#define REGM (REGEXT-1)
/* compiler allocates external registers R10 down */
#define REGTMP 11
-#define REGSB 12
#define REGSP 13
#define REGLINK 14
#define REGPC 15
-#define NFREG 8
+#define NFREG 16
#define FREGRET 0
#define FREGEXT 7
#define FREGTMP 15
@@ -127,6 +126,8 @@ enum as
ADIVD,
ASQRTF,
ASQRTD,
+ AABSF,
+ AABSD,
ASRL,
ASRA,
@@ -184,6 +185,21 @@ enum as
ALDREXD,
ASTREXD,
+ APLD,
+
+ AUNDEF,
+
+ ACLZ,
+
+ AMULWT,
+ AMULWB,
+ AMULAWT,
+ AMULAWB,
+
+ AUSEFIELD,
+ ALOCALS,
+ ATYPE,
+
ALAST,
};
@@ -237,12 +253,14 @@ enum as
#define D_SHIFT (D_NONE+19)
#define D_FPCR (D_NONE+20)
-#define D_REGREG (D_NONE+21)
+#define D_REGREG (D_NONE+21) // (reg, reg)
#define D_ADDR (D_NONE+22)
#define D_SBIG (D_NONE+23)
#define D_CONST2 (D_NONE+24)
+#define D_REGREG2 (D_NONE+25) // reg, reg
+
/* name */
#define D_EXTERN (D_NONE+3)
#define D_STATIC (D_NONE+4)
@@ -252,11 +270,16 @@ enum as
/* internal only */
#define D_SIZE (D_NONE+40)
#define D_PCREL (D_NONE+41)
+#define D_GOTOFF (D_NONE+42) // R_ARM_GOTOFF
+#define D_PLT0 (D_NONE+43) // R_ARM_PLT32, 1st inst: add ip, pc, #0xNN00000
+#define D_PLT1 (D_NONE+44) // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000
+#define D_PLT2 (D_NONE+45) // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]!
+#define D_CALL (D_NONE+46) // R_ARM_PLT32/R_ARM_CALL/R_ARM_JUMP24, bl xxxxx or b yyyyy
/*
* this is the ranlib header
*/
-#define SYMDEF "__.SYMDEF"
+#define SYMDEF "__.GOSYMDEF"
/*
* this is the simulated IEEE floating point
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index b36a982d1..04f2a9c6c 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -33,10 +33,14 @@
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
+#include "../ld/dwarf.h"
static Prog *PP;
-char linuxdynld[] = "/lib/ld-linux.so.2";
+char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI
+char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
+char openbsddynld[] = "XXX";
+char netbsddynld[] = "/libexec/ld.elf_so";
int32
entryvalue(void)
@@ -55,32 +59,6 @@ entryvalue(void)
return s->value;
}
-enum {
- ElfStrEmpty,
- ElfStrInterp,
- ElfStrHash,
- ElfStrGot,
- ElfStrGotPlt,
- ElfStrDynamic,
- ElfStrDynsym,
- ElfStrDynstr,
- ElfStrRel,
- ElfStrText,
- ElfStrData,
- ElfStrBss,
- ElfStrSymtab,
- ElfStrStrtab,
- ElfStrShstrtab,
- ElfStrRelPlt,
- ElfStrPlt,
- ElfStrNoteNetbsdIdent,
- ElfStrNoPtrData,
- ElfStrNoPtrBss,
- NElfStr
-};
-
-vlong elfstr[NElfStr];
-
static int
needlib(char *name)
{
@@ -103,164 +81,437 @@ needlib(char *name)
int nelfsym = 1;
+static void addpltsym(Sym*);
+static void addgotsym(Sym*);
+static void addgotsyminternal(Sym*);
+
+// Preserve highest 8 bits of a, and do addition to lower 24-bit
+// of a and b; used to adjust ARM branch intruction's target
+static int32
+braddoff(int32 a, int32 b)
+{
+ return (((uint32)a) & 0xff000000U) | (0x00ffffffU & (uint32)(a + b));
+}
+
+Sym *
+lookuprel(void)
+{
+ return lookup(".rel", 0);
+}
+
void
-adddynrel(Sym *s, Reloc *r)
+adddynrela(Sym *rel, Sym *s, Reloc *r)
{
- USED(s);
- USED(r);
- diag("adddynrel: unsupported binary format");
+ addaddrplus(rel, s, r->off);
+ adduint32(rel, R_ARM_RELATIVE);
}
void
-adddynsym(Sym *s)
+adddynrel(Sym *s, Reloc *r)
{
- USED(s);
- diag("adddynsym: not implemented");
+ Sym *targ, *rel;
+
+ 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_ARM_PLT32:
+ r->type = D_CALL;
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = braddoff(r->add, targ->plt / 4);
+ }
+ return;
+
+ case 256 + R_ARM_THM_PC22: // R_ARM_THM_CALL
+ diag("R_ARM_THM_CALL, are you using -marm?");
+ errorexit();
+ return;
+
+ case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL
+ if(targ->dynimpname == nil || targ->dynexport) {
+ addgotsyminternal(targ);
+ } else {
+ addgotsym(targ);
+ }
+ r->type = D_CONST; // write r->add during relocsym
+ r->sym = S;
+ r->add += targ->got;
+ return;
+
+ case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P
+ if(targ->dynimpname == nil || targ->dynexport) {
+ addgotsyminternal(targ);
+ } else {
+ addgotsym(targ);
+ }
+ r->type = D_PCREL;
+ r->sym = lookup(".got", 0);
+ r->add += targ->got + 4;
+ return;
+
+ case 256 + R_ARM_GOTOFF: // R_ARM_GOTOFF32
+ r->type = D_GOTOFF;
+ return;
+
+ case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL
+ r->type = D_PCREL;
+ r->sym = lookup(".got", 0);
+ r->add += 4;
+ return;
+
+ case 256 + R_ARM_CALL:
+ r->type = D_CALL;
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = braddoff(r->add, targ->plt / 4);
+ }
+ return;
+
+ case 256 + R_ARM_REL32: // R_ARM_REL32
+ r->type = D_PCREL;
+ r->add += 4;
+ return;
+
+ case 256 + R_ARM_ABS32:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name);
+ r->type = D_ADDR;
+ return;
+
+ case 256 + R_ARM_V4BX:
+ // we can just ignore this, because we are targeting ARM V5+ anyway
+ if(r->sym) {
+ // R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
+ r->sym->type = 0;
+ }
+ r->sym = S;
+ return;
+
+ case 256 + R_ARM_PC24:
+ case 256 + R_ARM_JUMP24:
+ r->type = D_CALL;
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = braddoff(r->add, targ->plt / 4);
+ }
+ return;
+ }
+
+ // Handle references to ELF symbols from our own object files.
+ if(targ->dynimpname == nil || targ->dynexport)
+ return;
+
+ switch(r->type) {
+ case D_PCREL:
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ return;
+
+ case D_ADDR:
+ if(s->type != SDATA)
+ break;
+ if(iself) {
+ adddynsym(targ);
+ rel = lookup(".rel", 0);
+ addaddrplus(rel, s, r->off);
+ adduint32(rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc
+ r->type = D_CONST; // write r->add during relocsym
+ r->sym = S;
+ return;
+ }
+ break;
+ }
+
+ cursym = s;
+ diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}
-static void
+int
+elfreloc1(Reloc *r, vlong off, int32 elfsym, vlong add)
+{
+ USED(add); // written to obj file by ../ld/data.c's reloc
+
+ LPUT(off);
+
+ switch(r->type) {
+ default:
+ return -1;
+
+ case D_ADDR:
+ if(r->siz == 4)
+ LPUT(R_ARM_ABS32 | elfsym<<8);
+ else
+ return -1;
+ break;
+
+ case D_PCREL:
+ if(r->siz == 4)
+ LPUT(R_ARM_REL32 | elfsym<<8);
+ else
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
+void
elfsetupplt(void)
{
- // TODO
+ Sym *plt, *got;
+
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ if(plt->size == 0) {
+ // str lr, [sp, #-4]!
+ adduint32(plt, 0xe52de004);
+ // ldr lr, [pc, #4]
+ adduint32(plt, 0xe59fe004);
+ // add lr, pc, lr
+ adduint32(plt, 0xe08fe00e);
+ // ldr pc, [lr, #8]!
+ adduint32(plt, 0xe5bef008);
+ // .word &GLOBAL_OFFSET_TABLE[0] - .
+ addpcrelplus(plt, got, 4);
+
+ // the first .plt entry requires 3 .plt.got entries
+ adduint32(got, 0);
+ adduint32(got, 0);
+ adduint32(got, 0);
+ }
}
int
archreloc(Reloc *r, Sym *s, vlong *val)
{
- USED(r);
- USED(s);
- USED(val);
- return -1;
+ switch(r->type) {
+ case D_CONST:
+ *val = r->add;
+ return 0;
+ case D_GOTOFF:
+ *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
+ return 0;
+ // The following three arch specific relocations are only for generation of
+ // Linux/ARM ELF's PLT entry (3 assembler instruction)
+ case D_PLT0: // add ip, pc, #0xXX00000
+ if (symaddr(lookup(".got.plt", 0)) < symaddr(lookup(".plt", 0)))
+ diag(".got.plt should be placed after .plt section.");
+ *val = 0xe28fc600U +
+ (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add) >> 20));
+ return 0;
+ case D_PLT1: // add ip, ip, #0xYY000
+ *val = 0xe28cca00U +
+ (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 4) >> 12));
+ return 0;
+ case D_PLT2: // ldr pc, [ip, #0xZZZ]!
+ *val = 0xe5bcf000U +
+ (0xfff & (uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 8));
+ return 0;
+ case D_CALL: // bl XXXXXX or b YYYYYY
+ *val = braddoff((0xff000000U & (uint32)r->add),
+ (0xffffff & (uint32)
+ ((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4)));
+ return 0;
+}
+return -1;
}
-void
-adddynlib(char *lib)
+static Reloc *
+addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ)
{
- Sym *s;
+Reloc *r;
+ r = addrel(plt);
+ r->sym = got;
+ r->off = plt->size;
+ r->siz = 4;
+ r->type = typ;
+ r->add = sym->got - 8;
+
+ plt->reachable = 1;
+ plt->size += 4;
+ symgrow(plt, plt->size);
+
+ return r;
+}
+
+static void
+addpltsym(Sym *s)
+{
+ Sym *plt, *got, *rel;
- if(!needlib(lib))
+ if(s->plt >= 0)
return;
+
+ adddynsym(s);
if(iself) {
- s = lookup(".dynstr", 0);
- if(s->size == 0)
- addstring(s, "");
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ rel = lookup(".rel.plt", 0);
+ if(plt->size == 0)
+ elfsetupplt();
+
+ // .got entry
+ s->got = got->size;
+ // In theory, all GOT should point to the first PLT entry,
+ // Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
+ // dynamic linker won't, so we'd better do it ourselves.
+ addaddrplus(got, plt, 0);
+
+ // .plt entry, this depends on the .got entry
+ s->plt = plt->size;
+ addpltreloc(plt, got, s, D_PLT0); // add lr, pc, #0xXX00000
+ addpltreloc(plt, got, s, D_PLT1); // add lr, lr, #0xYY000
+ addpltreloc(plt, got, s, D_PLT2); // ldr pc, [lr, #0xZZZ]!
+
+ // rel
+ addaddrplus(rel, got, s->got);
+ adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT));
} else {
- diag("adddynlib: unsupported binary format");
+ diag("addpltsym: unsupported binary format");
+ }
+}
+
+static void
+addgotsyminternal(Sym *s)
+{
+ Sym *got;
+
+ if(s->got >= 0)
+ return;
+
+ got = lookup(".got", 0);
+ s->got = got->size;
+
+ addaddrplus(got, s, 0);
+
+ if(iself) {
+ ;
+ } else {
+ diag("addgotsyminternal: unsupported binary format");
+ }
+}
+
+static void
+addgotsym(Sym *s)
+{
+ Sym *got, *rel;
+
+ if(s->got >= 0)
+ return;
+
+ adddynsym(s);
+ got = lookup(".got", 0);
+ s->got = got->size;
+ adduint32(got, 0);
+
+ if(iself) {
+ rel = lookup(".rel", 0);
+ addaddrplus(rel, got, s->got);
+ adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT));
+ } else {
+ diag("addgotsym: unsupported binary format");
}
}
void
-doelf(void)
+adddynsym(Sym *s)
{
- Sym *s, *shstrtab, *dynstr;
+ Sym *d;
+ int t;
+ char *name;
- if(!iself)
+ if(s->dynid >= 0)
return;
- /* predefine strings we need for section headers */
- shstrtab = lookup(".shstrtab", 0);
- shstrtab->type = SELFROSECT;
- shstrtab->reachable = 1;
-
- elfstr[ElfStrEmpty] = addstring(shstrtab, "");
- elfstr[ElfStrText] = addstring(shstrtab, ".text");
- elfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
- elfstr[ElfStrData] = addstring(shstrtab, ".data");
- elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
- elfstr[ElfStrNoPtrBss] = addstring(shstrtab, ".noptrbss");
- if(HEADTYPE == Hnetbsd)
- elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
- addstring(shstrtab, ".rodata");
- addstring(shstrtab, ".gosymtab");
- addstring(shstrtab, ".gopclntab");
- if(!debug['s']) {
- elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
- elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
+ if(s->dynimpname == nil) {
+ s->dynimpname = s->name;
+ //diag("adddynsym: no dynamic name for %s", s->name);
}
- elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
-
- if(!debug['d']) { /* -d suppresses dynamic loader format */
- elfstr[ElfStrInterp] = addstring(shstrtab, ".interp");
- elfstr[ElfStrHash] = addstring(shstrtab, ".hash");
- elfstr[ElfStrGot] = addstring(shstrtab, ".got");
- elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt");
- elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic");
- elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
- elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
- elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
- elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
- elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
-
- /* dynamic symbol table - first entry all zeros */
- s = lookup(".dynsym", 0);
- s->type = SELFROSECT;
- s->reachable = 1;
- s->value += ELF32SYMSIZE;
-
- /* dynamic string table */
- s = lookup(".dynstr", 0);
- s->type = SELFROSECT;
- s->reachable = 1;
- if(s->size == 0)
- addstring(s, "");
- dynstr = s;
- /* relocation table */
- s = lookup(".rel", 0);
- s->reachable = 1;
- s->type = SELFROSECT;
+ if(iself) {
+ s->dynid = nelfsym++;
- /* global offset table */
- s = lookup(".got", 0);
- s->reachable = 1;
- s->type = SELFSECT; // writable
-
- /* hash */
- s = lookup(".hash", 0);
- s->reachable = 1;
- s->type = SELFROSECT;
-
- /* got.plt */
- s = lookup(".got.plt", 0);
- s->reachable = 1;
- s->type = SELFSECT; // writable
-
- s = lookup(".plt", 0);
- s->reachable = 1;
- s->type = SELFROSECT;
+ d = lookup(".dynsym", 0);
- s = lookup(".rel.plt", 0);
- s->reachable = 1;
- s->type = SELFROSECT;
-
- elfsetupplt();
-
- /* define dynamic elf table */
- s = lookup(".dynamic", 0);
- s->reachable = 1;
- s->type = SELFSECT; // writable
-
- /*
- * .dynamic table
- */
- elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
- elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
- elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
- elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
- elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
- elfwritedynentsym(s, DT_REL, lookup(".rel", 0));
- elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0));
- elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
- if(rpath)
- elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
- elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
- elfwritedynent(s, DT_PLTREL, DT_REL);
- elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
- elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
- elfwritedynent(s, DT_DEBUG, 0);
- elfwritedynent(s, DT_NULL, 0);
+ /* name */
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ adduint32(d, addstring(lookup(".dynstr", 0), name));
+
+ /* value */
+ if(s->type == SDYNIMPORT)
+ adduint32(d, 0);
+ else
+ addaddr(d, s);
+
+ /* size */
+ adduint32(d, 0);
+
+ /* type */
+ t = STB_GLOBAL << 4;
+ if(s->dynexport && (s->type&SMASK) == STEXT)
+ t |= STT_FUNC;
+ else
+ t |= STT_OBJECT;
+ adduint8(d, t);
+ adduint8(d, 0);
+
+ /* shndx */
+ if(!s->dynexport && s->dynimpname != nil)
+ adduint16(d, SHN_UNDEF);
+ else {
+ switch(s->type) {
+ default:
+ case STEXT:
+ t = 11;
+ break;
+ case SRODATA:
+ t = 12;
+ break;
+ case SDATA:
+ t = 13;
+ break;
+ case SBSS:
+ t = 14;
+ break;
+ }
+ adduint16(d, t);
+ }
+ } else {
+ 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 {
+ diag("adddynlib: unsupported binary format");
}
}
@@ -276,48 +527,26 @@ datoff(vlong addr)
}
void
-shsym(Elf64_Shdr *sh, Sym *s)
-{
- vlong addr;
- addr = symaddr(s);
- if(sh->flags&SHF_ALLOC)
- sh->addr = addr;
- sh->off = datoff(addr);
- sh->size = s->size;
-}
-
-void
-phsh(Elf64_Phdr *ph, Elf64_Shdr *sh)
-{
- ph->vaddr = sh->addr;
- ph->paddr = ph->vaddr;
- ph->off = sh->off;
- ph->filesz = sh->size;
- ph->memsz = sh->size;
- ph->align = sh->addralign;
-}
-
-void
asmb(void)
{
int32 t;
- int a, dynsym;
- uint32 fo, symo, startva, resoff;
- ElfEhdr *eh;
- ElfPhdr *ph, *pph;
- ElfShdr *sh;
+ uint32 symo;
Section *sect;
- int o;
+ Sym *sym;
+ int i;
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
Bflush(&bso);
+ if(iself)
+ asmbelfsetup();
+
sect = segtext.sect;
cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
codeblk(sect->vaddr, sect->len);
- /* output read-only data in text segment (rodata, gosymtab and pclntab) */
+ /* output read-only data in text segment (rodata, gosymtab, pclntab, ...) */
for(sect = sect->next; sect != nil; sect = sect->next) {
cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
datblk(sect->vaddr, sect->len);
@@ -330,19 +559,6 @@ asmb(void)
cseek(segdata.fileoff);
datblk(segdata.vaddr, segdata.filelen);
- if(iself) {
- /* index of elf text section; needed by asmelfsym, double-checked below */
- /* !debug['d'] causes extra sections before the .text section */
- elftextsh = 2;
- if(!debug['d']) {
- elftextsh += 10;
- if(elfverneed)
- elftextsh += 2;
- }
- if(HEADTYPE == Hnetbsd)
- elftextsh += 1;
- }
-
/* output symbol table */
symsize = 0;
lcsize = 0;
@@ -365,28 +581,43 @@ asmb(void)
case Hplan9x32:
symo = HEADR+segtext.len+segdata.filelen;
break;
- case Hnetbsd:
- symo = rnd(segdata.filelen, 4096);
- break;
ElfSym:
symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
symo = rnd(symo, INITRND);
break;
}
cseek(symo);
- if(iself) {
- if(debug['v'])
- Bprint(&bso, "%5.2f elfsym\n", cputime());
- asmelfsym();
+ switch(HEADTYPE) {
+ default:
+ if(iself) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f elfsym\n", cputime());
+ asmelfsym();
+ cflush();
+ cwrite(elfstrdat, elfstrsize);
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+ dwarfemitdebugsections();
+
+ if(isobj)
+ elfemitreloc();
+ }
+ break;
+ case Hplan9x32:
+ asmplan9sym();
cflush();
- cwrite(elfstrdat, elfstrsize);
- // if(debug['v'])
- // Bprint(&bso, "%5.2f dwarf\n", cputime());
- // dwarfemitdebugsections();
+ sym = lookup("pclntab", 0);
+ if(sym != nil) {
+ lcsize = sym->np;
+ for(i=0; i < lcsize; i++)
+ cput(sym->p[i]);
+
+ cflush();
+ }
+ break;
}
- cflush();
-
}
cursym = nil;
@@ -395,6 +626,7 @@ asmb(void)
Bflush(&bso);
cseek(0L);
switch(HEADTYPE) {
+ default:
case Hnoheader: /* no header */
break;
case Hrisc: /* aif for risc os */
@@ -409,7 +641,7 @@ asmb(void)
- 8) / 4); /* BL - entry code */
lputl(0xef000011); /* SWI - exit code */
- lputl(textsize+HEADR); /* text size */
+ lputl(segtext.filelen+HEADR); /* text size */
lputl(segdata.filelen); /* data size */
lputl(0); /* sym size */
@@ -429,7 +661,7 @@ asmb(void)
break;
case Hplan9x32: /* plan 9 */
lput(0x647); /* magic */
- lput(textsize); /* sizes */
+ lput(segtext.filelen); /* sizes */
lput(segdata.filelen);
lput(segdata.len - segdata.filelen);
lput(symsize); /* nsyms */
@@ -437,16 +669,6 @@ asmb(void)
lput(0L);
lput(lcsize);
break;
- case Hnetbsd: /* boot for NetBSD */
- lput((143<<16)|0413); /* magic */
- lputl(rnd(HEADR+textsize, 4096));
- lputl(rnd(segdata.filelen, 4096));
- lputl(segdata.len - segdata.filelen);
- lputl(symsize); /* nsyms */
- lputl(entryvalue()); /* va of entry */
- lputl(0L);
- lputl(0L);
- break;
case Hixp1200: /* boot for IXP1200 */
break;
case Hipaq: /* boot for ipaq */
@@ -456,216 +678,20 @@ asmb(void)
lputl(0xe3300000); /* nop */
break;
case Hlinux:
- /* elf arm */
- eh = getElfEhdr();
- fo = HEADR;
- startva = INITTEXT - fo; /* va of byte 0 of file */
- resoff = ELFRESERVE;
-
- /* This null SHdr must appear before all others */
- newElfShdr(elfstr[ElfStrEmpty]);
-
- /* program header info */
- pph = newElfPhdr();
- pph->type = PT_PHDR;
- pph->flags = PF_R + PF_X;
- pph->off = eh->ehsize;
- pph->vaddr = INITTEXT - HEADR + pph->off;
- pph->paddr = INITTEXT - HEADR + pph->off;
- pph->align = INITRND;
-
- /*
- * PHDR must be in a loaded segment. Adjust the text
- * segment boundaries downwards to include it.
- */
- o = segtext.vaddr - pph->vaddr;
- segtext.vaddr -= o;
- segtext.len += o;
- o = segtext.fileoff - pph->off;
- segtext.fileoff -= o;
- segtext.filelen += o;
-
- if(!debug['d']) {
- /* interpreter for dynamic linking */
- sh = newElfShdr(elfstr[ElfStrInterp]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC;
- sh->addralign = 1;
- if(interpreter == nil)
- interpreter = linuxdynld;
- resoff -= elfinterp(sh, startva, resoff, interpreter);
-
- ph = newElfPhdr();
- ph->type = PT_INTERP;
- ph->flags = PF_R;
- phsh(ph, sh);
- }
-
- if(HEADTYPE == Hnetbsd) {
- sh = newElfShdr(elfstr[ElfStrNoteNetbsdIdent]);
- sh->type = SHT_NOTE;
- sh->flags = SHF_ALLOC;
- sh->addralign = 4;
- resoff -= elfnetbsdsig(sh, startva, resoff);
-
- ph = newElfPhdr();
- ph->type = PT_NOTE;
- ph->flags = PF_R;
- phsh(ph, sh);
- }
-
- elfphload(&segtext);
- elfphload(&segdata);
-
- /* Dynamic linking sections */
- if(!debug['d']) { /* -d suppresses dynamic loader format */
- /* S headers for dynamic linking */
- sh = newElfShdr(elfstr[ElfStrGot]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 4;
- sh->addralign = 4;
- shsym(sh, lookup(".got", 0));
-
- sh = newElfShdr(elfstr[ElfStrGotPlt]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 4;
- sh->addralign = 4;
- shsym(sh, lookup(".got.plt", 0));
-
- dynsym = eh->shnum;
- sh = newElfShdr(elfstr[ElfStrDynsym]);
- sh->type = SHT_DYNSYM;
- sh->flags = SHF_ALLOC;
- sh->entsize = ELF32SYMSIZE;
- sh->addralign = 4;
- sh->link = dynsym+1; // dynstr
- // sh->info = index of first non-local symbol (number of local symbols)
- shsym(sh, lookup(".dynsym", 0));
-
- sh = newElfShdr(elfstr[ElfStrDynstr]);
- sh->type = SHT_STRTAB;
- sh->flags = SHF_ALLOC;
- sh->addralign = 1;
- shsym(sh, lookup(".dynstr", 0));
-
- sh = newElfShdr(elfstr[ElfStrHash]);
- sh->type = SHT_HASH;
- sh->flags = SHF_ALLOC;
- sh->entsize = 4;
- sh->addralign = 4;
- sh->link = dynsym;
- shsym(sh, lookup(".hash", 0));
-
- sh = newElfShdr(elfstr[ElfStrRel]);
- sh->type = SHT_REL;
- sh->flags = SHF_ALLOC;
- sh->entsize = ELF32RELSIZE;
- sh->addralign = 4;
- sh->link = dynsym;
- shsym(sh, lookup(".rel", 0));
-
- /* sh and PT_DYNAMIC for .dynamic section */
- sh = newElfShdr(elfstr[ElfStrDynamic]);
- sh->type = SHT_DYNAMIC;
- sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 8;
- sh->addralign = 4;
- sh->link = dynsym+1; // dynstr
- shsym(sh, lookup(".dynamic", 0));
-
- ph = newElfPhdr();
- ph->type = PT_DYNAMIC;
- ph->flags = PF_R + PF_W;
- phsh(ph, sh);
-
- /*
- * Thread-local storage segment (really just size).
- if(tlsoffset != 0) {
- ph = newElfPhdr();
- ph->type = PT_TLS;
- ph->flags = PF_R;
- ph->memsz = -tlsoffset;
- ph->align = 4;
- }
- */
- }
-
- ph = newElfPhdr();
- ph->type = PT_GNU_STACK;
- ph->flags = PF_W+PF_R;
- ph->align = 4;
-
- sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
- sh->type = SHT_STRTAB;
- sh->addralign = 1;
- shsym(sh, lookup(".shstrtab", 0));
-
- if(elftextsh != eh->shnum)
- diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
- for(sect=segtext.sect; sect!=nil; sect=sect->next)
- elfshbits(sect);
- for(sect=segdata.sect; sect!=nil; sect=sect->next)
- elfshbits(sect);
-
- if(!debug['s']) {
- sh = newElfShdr(elfstr[ElfStrSymtab]);
- sh->type = SHT_SYMTAB;
- sh->off = symo;
- sh->size = symsize;
- sh->addralign = 4;
- sh->entsize = 16;
- sh->link = eh->shnum; // link to strtab
-
- sh = newElfShdr(elfstr[ElfStrStrtab]);
- sh->type = SHT_STRTAB;
- sh->off = symo+symsize;
- sh->size = elfstrsize;
- sh->addralign = 1;
-
- // dwarfaddelfheaders();
- }
-
- /* Main header */
- eh->ident[EI_MAG0] = '\177';
- eh->ident[EI_MAG1] = 'E';
- eh->ident[EI_MAG2] = 'L';
- eh->ident[EI_MAG3] = 'F';
- eh->ident[EI_CLASS] = ELFCLASS32;
- eh->ident[EI_DATA] = ELFDATA2LSB;
- eh->ident[EI_VERSION] = EV_CURRENT;
-
- eh->type = ET_EXEC;
- eh->machine = EM_ARM;
- eh->version = EV_CURRENT;
- eh->entry = entryvalue();
-
- if(pph != nil) {
- pph->filesz = eh->phnum * eh->phentsize;
- pph->memsz = pph->filesz;
- }
-
- cseek(0);
- a = 0;
- a += elfwritehdr();
- a += elfwritephdrs();
- a += elfwriteshdrs();
- a += elfwriteinterp(elfstr[ElfStrInterp]);
- if(HEADTYPE == Hnetbsd)
- a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
- if(a > ELFRESERVE)
- diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
+ case Hfreebsd:
+ case Hnetbsd:
+ case Hopenbsd:
+ asmbelf(symo);
break;
}
cflush();
if(debug['c']){
- print("textsize=%d\n", textsize);
+ print("textsize=%ulld\n", segtext.filelen);
print("datsize=%ulld\n", segdata.filelen);
print("bsssize=%ulld\n", segdata.len - segdata.filelen);
print("symsize=%d\n", symsize);
print("lcsize=%d\n", lcsize);
- print("total=%lld\n", textsize+segdata.len+symsize+lcsize);
+ print("total=%lld\n", segtext.filelen+segdata.len+symsize+lcsize);
}
}
@@ -812,6 +838,7 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
case 5: /* bra s */
v = -8;
+ // TODO: Use addrel.
if(p->cond != P)
v = (p->cond->pc - pc) - 8;
o1 = opbra(p->as, p->scond);
@@ -875,15 +902,22 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
rel = addrel(cursym);
rel->off = pc - cursym->value;
rel->siz = 4;
- rel->type = D_ADDR;
rel->sym = p->to.sym;
rel->add = p->to.offset;
+ if(flag_shared) {
+ rel->type = D_PCREL;
+ rel->add += pc - p->pcrel->pc - 8;
+ } else
+ rel->type = D_ADDR;
o1 = 0;
}
break;
case 12: /* movw $lcon, reg */
o1 = omvl(p, &p->from, p->to.reg);
+ if(o->flag & LPCREL) {
+ o2 = oprrr(AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12;
+ }
break;
case 13: /* op $lcon, [R], R */
@@ -1128,7 +1162,7 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
r = p->reg;
if(r == NREG) {
r = rt;
- if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD)
+ if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD)
r = 0;
}
o1 |= rf | (r<<16) | (rt<<12);
@@ -1188,13 +1222,23 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
break;
case 62: /* case R -> movw R<<2(PC),PC */
- o1 = olrr(p->from.reg, REGPC, REGPC, p->scond);
- o1 |= 2<<7;
+ if(o->flag & LPCREL) {
+ o1 = oprrr(AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12;
+ o2 = olrr(REGTMP, REGPC, REGTMP, p->scond);
+ o2 |= 2<<7;
+ o3 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12;
+ } else {
+ o1 = olrr(p->from.reg, REGPC, REGPC, p->scond);
+ o1 |= 2<<7;
+ }
break;
case 63: /* bcase */
- if(p->cond != P)
+ if(p->cond != P) {
o1 = p->cond->pc;
+ if(flag_shared)
+ o1 = o1 - p->pcrel->pc - 16;
+ }
break;
/* reloc ops */
@@ -1203,6 +1247,10 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
if(!o1)
break;
o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
break;
case 65: /* mov/movbu addr,R */
@@ -1212,6 +1260,10 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
o2 = olr(0, REGTMP, p->to.reg, p->scond);
if(p->as == AMOVBU || p->as == AMOVB)
o2 |= 1<<22;
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
break;
case 68: /* floating point store -> ADDR */
@@ -1219,6 +1271,10 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
if(!o1)
break;
o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
break;
case 69: /* floating point load <- ADDR */
@@ -1226,6 +1282,10 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
if(!o1)
break;
o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
break;
/* ArmV4 ops: */
@@ -1422,12 +1482,57 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
o2 ^= (1<<5)|(1<<6);
else if(p->as == AMOVH)
o2 ^= (1<<6);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
break;
case 94: /* movh/movhu R,addr -> strh */
o1 = omvl(p, &p->to, REGTMP);
if(!o1)
break;
o2 = oshr(p->from.reg, 0, REGTMP, p->scond);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+ case 95: /* PLD off(reg) */
+ o1 = 0xf5d0f000;
+ o1 |= p->from.reg << 16;
+ if(p->from.offset < 0) {
+ o1 &= ~(1 << 23);
+ o1 |= (-p->from.offset) & 0xfff;
+ } else
+ o1 |= p->from.offset & 0xfff;
+ break;
+ case 96: /* UNDEF */
+ // This is supposed to be something that stops execution.
+ // It's not supposed to be reached, ever, but if it is, we'd
+ // like to be able to tell how we got there. Assemble as
+ // BL $0
+ // TODO: Use addrel.
+ v = (0 - pc) - 8;
+ o1 = opbra(ABL, C_SCOND_NONE);
+ o1 |= (v >> 2) & 0xffffff;
+ break;
+ case 97: /* CLZ Rm, Rd */
+ o1 = oprrr(p->as, p->scond);
+ o1 |= p->to.reg << 12;
+ o1 |= p->from.reg;
+ break;
+ case 98: /* MULW{T,B} Rs, Rm, Rd */
+ o1 = oprrr(p->as, p->scond);
+ o1 |= p->to.reg << 16;
+ o1 |= p->from.reg << 8;
+ o1 |= p->reg;
+ break;
+ case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
+ o1 = oprrr(p->as, p->scond);
+ o1 |= p->to.reg << 12;
+ o1 |= p->from.reg << 8;
+ o1 |= p->reg;
+ o1 |= p->to.offset << 16;
break;
}
@@ -1547,6 +1652,8 @@ oprrr(int a, int sc)
case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4);
case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4);
case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4);
+ case AABSD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (0xc<<4);
+ case AABSF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (0xc<<4);
case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4);
case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4);
@@ -1586,6 +1693,19 @@ oprrr(int a, int sc)
return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
case ACMP+AEND: // cmp imm
return o | (0x3<<24) | (0x5<<20);
+
+ case ACLZ:
+ // CLZ doesn't support .S
+ return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4);
+
+ case AMULWT:
+ return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4);
+ case AMULWB:
+ return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4);
+ case AMULAWT:
+ return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4);
+ case AMULAWB:
+ return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4);
}
diag("bad rrr %d", a);
prasm(curp);
@@ -1789,7 +1909,8 @@ omvl(Prog *p, Adr *a, int dr)
int
chipzero(Ieee *e)
{
- if(e->l != 0 || e->h != 0)
+ // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
+ if(goarm < 7 || e->l != 0 || e->h != 0)
return -1;
return 0;
}
@@ -1800,6 +1921,10 @@ chipfloat(Ieee *e)
int n;
ulong h;
+ // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
+ if(goarm < 7)
+ goto no;
+
if(e->l != 0 || (e->h&0xffff) != 0)
goto no;
h = e->h & 0x7fc00000;
@@ -1824,83 +1949,3 @@ chipfloat(Ieee *e)
no:
return -1;
}
-
-
-void
-genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
-{
- Auto *a;
- Sym *s;
- int h;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- put(s, s->name, 'T', s->value, s->size, s->version, 0);
-
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->hash) {
- if(s->hide)
- continue;
- switch(s->type) {
- case SCONST:
- case SRODATA:
- case SDATA:
- case SELFROSECT:
- case STYPE:
- case SSTRING:
- case SGOSTRING:
- case SNOPTRDATA:
- case SSYMTAB:
- case SPCLNTAB:
- if(!s->reachable)
- continue;
- put(s, s->name, 'D', s->value, s->size, s->version, s->gotype);
- continue;
-
- case SBSS:
- case SNOPTRBSS:
- if(!s->reachable)
- continue;
- if(s->np > 0)
- diag("%s should not be bss (size=%d type=%d special=%d)", s->name, (int)s->np, s->type, s->special);
- put(s, s->name, 'B', s->value, s->size, s->version, s->gotype);
- continue;
-
- case SFILE:
- put(nil, s->name, 'f', s->value, 0, s->version, 0);
- continue;
- }
- }
- }
-
- for(s = textp; s != nil; s = s->next) {
- /* filenames first */
- for(a=s->autom; a; a=a->link)
- if(a->type == D_FILE)
- put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
- else
- if(a->type == D_FILE1)
- put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
-
- put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
-
- /* frame, auto and param after */
- put(nil, ".frame", 'm', s->text->to.offset+4, 0, 0, 0);
-
- for(a=s->autom; a; a=a->link)
- if(a->type == D_AUTO)
- put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
- else
- if(a->type == D_PARAM)
- put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
- }
- if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %ud\n", symsize);
- Bflush(&bso);
-}
-
-void
-setpersrc(Sym *s)
-{
- USED(s);
-}
diff --git a/src/cmd/5l/doc.go b/src/cmd/5l/doc.go
index 969f502a7..a054a228b 100644
--- a/src/cmd/5l/doc.go
+++ b/src/cmd/5l/doc.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build ignore
+
/*
5l is the linker for the ARM.
@@ -10,4 +12,4 @@ The $GOARCH for these tools is arm.
The flags are documented in ../ld/doc.go.
*/
-package documentation
+package main
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index b1a48ded8..62dd8947f 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -36,7 +36,9 @@
enum
{
thechar = '5',
- PtrSize = 4
+ PtrSize = 4,
+ IntSize = 4,
+ FuncAlign = 4 // single-instruction alignment
};
#ifndef EXTERN
@@ -66,22 +68,24 @@ struct Adr
{
union
{
- int32 u0offset;
+ struct {
+ int32 u0offset;
+ int32 u0offset2; // argsize
+ } u0off;
char* u0sval;
Ieee u0ieee;
char* u0sbig;
} u0;
Sym* sym;
+ Sym* gotype;
char type;
- uchar index; // not used on arm, required by ld/go.c
char reg;
char name;
- int32 offset2; // argsize
char class;
- Sym* gotype;
};
-#define offset u0.u0offset
+#define offset u0.u0off.u0offset
+#define offset2 u0.u0off.u0offset2
#define sval u0.u0sval
#define scon sval
#define ieee u0.u0ieee
@@ -107,7 +111,7 @@ struct Prog
} u0;
Prog* cond;
Prog* link;
- Prog* dlink;
+ Prog* pcrel;
int32 pc;
int32 line;
int32 spadj;
@@ -116,7 +120,7 @@ struct Prog
uchar as;
uchar scond;
uchar reg;
- uchar align;
+ uchar align; // unused
};
#define regused u0.u0regused
@@ -135,8 +139,6 @@ struct Sym
uchar reachable;
uchar dynexport;
uchar leaf;
- uchar stkcheck;
- uchar hide;
int32 dynid;
int32 plt;
int32 got;
@@ -144,18 +146,26 @@ struct Sym
int32 sig;
int32 size;
int32 align; // if non-zero, required alignment in bytes
+ int32 elfsym;
+ int32 locals; // size of stack frame locals area
+ int32 args; // size of stack frame incoming arguments area
uchar special;
uchar fnptr; // used as fn ptr
+ uchar stkcheck;
+ uchar hide;
Sym* hash; // in hash table
Sym* allsym; // in all symbol list
Sym* next; // in text or data list
Sym* sub; // in SSUB list
Sym* outer; // container of sub
Sym* gotype;
+ Sym* reachparent;
+ Sym* queue;
char* file;
char* dynimpname;
char* dynimplib;
char* dynimpvers;
+ struct Section* sect;
// STEXT
Auto* autom;
@@ -168,6 +178,7 @@ struct Sym
Reloc* r;
int32 nr;
int32 maxr;
+ int rel_ro;
};
#define SIGNINTERN (1729*325*1729)
@@ -190,6 +201,7 @@ struct Optab
char size;
char param;
char flag;
+ uchar pcrelsiz;
};
struct Oprang
{
@@ -207,10 +219,12 @@ enum
LFROM = 1<<0,
LTO = 1<<1,
LPOOL = 1<<2,
+ LPCREL = 1<<3,
C_NONE = 0,
C_REG,
C_REGREG,
+ C_REGREG2,
C_SHIFT,
C_FREG,
C_PSR,
@@ -220,6 +234,7 @@ enum
C_NCON, /* ~RCON */
C_SCON, /* 0xffff */
C_LCON,
+ C_LCONADDR,
C_ZFCON,
C_SFCON,
C_LFCON,
@@ -273,6 +288,7 @@ EXTERN int32 INITDAT; /* data location */
EXTERN int32 INITRND; /* data round above text location */
EXTERN int32 INITTEXT; /* text location */
EXTERN char* INITENTRY; /* entry point */
+EXTERN char* LIBINITENTRY; /* shared library entry point */
EXTERN int32 autosize;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
@@ -280,7 +296,7 @@ EXTERN Prog* curp;
EXTERN Sym* cursym;
EXTERN Sym* datap;
EXTERN int32 elfdatsize;
-EXTERN char debug[128];
+EXTERN int debug[128];
EXTERN Sym* etextp;
EXTERN char* noname;
EXTERN Prog* lastp;
@@ -298,12 +314,15 @@ EXTERN char* rpath;
EXTERN uint32 stroffset;
EXTERN int32 symsize;
EXTERN Sym* textp;
-EXTERN int32 textsize;
EXTERN int version;
EXTERN char xcmp[C_GOK+1][C_GOK+1];
EXTERN Prog zprg;
EXTERN int dtype;
+EXTERN int tlsoffset;
EXTERN int armsize;
+EXTERN int goarm;
+EXTERN Sym* adrgotype; // type symbol on last Adr read
+EXTERN Sym* fromgotype; // type symbol on last p->from read
extern char* anames[];
extern Optab optab[];
@@ -312,6 +331,8 @@ void addpool(Prog*, Adr*);
EXTERN Prog* blitrl;
EXTERN Prog* elitrl;
+EXTERN int goarm;
+
void initdiv(void);
EXTERN Prog* prog_div;
EXTERN Prog* prog_divu;
@@ -398,6 +419,9 @@ void span(void);
void strnput(char*, int);
int32 symaddr(Sym*);
void undef(void);
+void vputb(uint64);
+void vputl(uint64);
+void wputb(uint16);
void wput(int32);
void wputl(ushort w);
void xdefine(char*, int, int32);
@@ -407,8 +431,9 @@ int32 immaddr(int32);
int32 opbra(int, int);
int brextra(Prog*);
int isbranch(Prog*);
-void fnptrs(void);
+void fnptrs(void);
void doelf(void);
+void dozerostk(void); // used by -Z
vlong addaddr(Sym *s, Sym *t);
vlong addsize(Sym *s, Sym *t);
@@ -425,3 +450,9 @@ vlong adduintxx(Sym *s, uint64 v, int wid);
#define VPUT(a) abort()
#endif
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+ DWARFREGSP = 13
+};
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
index 293fee3c6..a051774b4 100644
--- a/src/cmd/5l/list.c
+++ b/src/cmd/5l/list.c
@@ -225,6 +225,12 @@ Dconv(Fmt *fp)
snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
break;
+ case D_REGREG2:
+ snprint(str, sizeof str, "R%d,R%d", a->reg, (int)a->offset);
+ if(a->name != D_NONE || a->sym != S)
+ snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
case D_FREG:
snprint(str, sizeof str, "F%d", a->reg);
if(a->name != D_NONE || a->sym != S)
@@ -429,6 +435,7 @@ cnames[] =
[C_LAUTO] = "C_LAUTO",
[C_LBRA] = "C_LBRA",
[C_LCON] = "C_LCON",
+ [C_LCONADDR] = "C_LCONADDR",
[C_LOREG] = "C_LOREG",
[C_NCON] = "C_NCON",
[C_NONE] = "C_NONE",
@@ -438,6 +445,7 @@ cnames[] =
[C_RCON] = "C_RCON",
[C_REG] = "C_REG",
[C_REGREG] = "C_REGREG",
+ [C_REGREG2] = "C_REGREG2",
[C_ROREG] = "C_ROREG",
[C_SAUTO] = "C_SAUTO",
[C_SBRA] = "C_SBRA",
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
index 004f9f2fa..99a096a31 100644
--- a/src/cmd/5l/noop.c
+++ b/src/cmd/5l/noop.c
@@ -45,6 +45,20 @@ static Sym* sym_divu;
static Sym* sym_mod;
static Sym* sym_modu;
+static void
+linkcase(Prog *casep)
+{
+ Prog *p;
+
+ for(p = casep; p != P; p = p->link){
+ if(p->as == ABCASE) {
+ for(; p != P && p->as == ABCASE; p = p->link)
+ p->pcrel = casep;
+ break;
+ }
+ }
+}
+
void
noops(void)
{
@@ -76,6 +90,11 @@ noops(void)
for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) {
switch(p->as) {
+ case ACASE:
+ if(flag_shared)
+ linkcase(p);
+ break;
+
case ATEXT:
p->mark |= LEAF;
break;
@@ -365,11 +384,7 @@ noops(void)
q1 = p;
/* MOV a,4(SP) */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
+ p = appendp(p);
p->as = AMOVW;
p->line = q1->line;
p->from.type = D_REG;
@@ -379,11 +394,7 @@ noops(void)
p->to.offset = 4;
/* MOV b,REGTMP */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
+ p = appendp(p);
p->as = AMOVW;
p->line = q1->line;
p->from.type = D_REG;
@@ -395,11 +406,7 @@ noops(void)
p->to.offset = 0;
/* CALL appropriate */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
+ p = appendp(p);
p->as = ABL;
p->line = q1->line;
p->to.type = D_BRANCH;
@@ -424,11 +431,7 @@ noops(void)
}
/* MOV REGTMP, b */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
+ p = appendp(p);
p->as = AMOVW;
p->line = q1->line;
p->from.type = D_REG;
@@ -438,12 +441,9 @@ noops(void)
p->to.reg = q1->to.reg;
/* ADD $8,SP */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
+ p = appendp(p);
p->as = AADD;
+ p->line = q1->line;
p->from.type = D_CONST;
p->from.reg = NREG;
p->from.offset = 8;
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index a3f816160..6aa7fdd69 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -34,6 +34,7 @@
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
+#include "../ld/dwarf.h"
#include <ar.h>
#ifndef DEFAULT
@@ -47,41 +48,29 @@ Header headers[] = {
"noheader", Hnoheader,
"risc", Hrisc,
"plan9", Hplan9x32,
- "netbsd", Hnetbsd,
"ixp1200", Hixp1200,
"ipaq", Hipaq,
"linux", Hlinux,
+ "freebsd", Hfreebsd,
+ "netbsd", Hnetbsd,
0, 0
};
/*
* -Hrisc -T0x10005000 -R4 is aif for risc os
* -Hplan9 -T4128 -R4096 is plan9 format
- * -Hnetbsd -T0xF0000020 -R4 is NetBSD format
* -Hixp1200 is IXP1200 (raw)
* -Hipaq -T0xC0008010 -R1024 is ipaq
* -Hlinux -Tx -Rx is linux elf
+ * -Hfreebsd is freebsd elf
+ * -Hnetbsd is netbsd elf
*/
-static char*
-linkername[] =
-{
- "runtime.softfloat",
- "math.sqrtGoC",
-};
-
-void
-usage(void)
-{
- fprint(2, "usage: 5l [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-D data] [-R rnd] [-r path] [-o out] main.5\n");
- errorexit();
-}
-
void
main(int argc, char *argv[])
{
- int c, i;
- char *p, *name, *val;
+ char *p;
+ Sym *s;
Binit(&bso, 1, OWRITE);
listinit();
@@ -92,59 +81,53 @@ main(int argc, char *argv[])
INITDAT = -1;
INITRND = -1;
INITENTRY = 0;
+ LIBINITENTRY = 0;
nuxiinit();
- p = getenv("GOARM");
- if(p != nil && strcmp(p, "5") == 0)
+ p = getgoarm();
+ if(p != nil)
+ goarm = atoi(p);
+ else
+ goarm = 6;
+ if(goarm == 5)
debug['F'] = 1;
- ARGBEGIN {
- default:
- c = ARGC();
- if(c == 'l')
- usage();
- if(c >= 0 && c < sizeof(debug))
- debug[c]++;
- break;
- case 'o':
- outfile = EARGF(usage());
- break;
- case 'E':
- INITENTRY = EARGF(usage());
- break;
- case 'I':
- interpreter = EARGF(usage());
- break;
- case 'L':
- Lflag(EARGF(usage()));
- break;
- case 'T':
- INITTEXT = atolwhex(EARGF(usage()));
- break;
- case 'D':
- INITDAT = atolwhex(EARGF(usage()));
- break;
- case 'R':
- INITRND = atolwhex(EARGF(usage()));
- break;
- case 'r':
- rpath = EARGF(usage());
- break;
- case 'H':
- HEADTYPE = headtype(EARGF(usage()));
- /* do something about setting INITTEXT */
- break;
- case 'V':
- print("%cl version %s\n", thechar, getgoversion());
- errorexit();
- case 'X':
- name = EARGF(usage());
- val = EARGF(usage());
- addstrdata(name, val);
- break;
- } ARGEND
-
- USED(argc);
+ flagcount("1", "use alternate profiling code", &debug['1']);
+ flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
+ flagstr("E", "sym: entry symbol", &INITENTRY);
+ flagint32("D", "addr: data address", &INITDAT);
+ flagcount("G", "debug pseudo-ops", &debug['G']);
+ flagfn1("I", "interp: set ELF interp", setinterp);
+ flagfn1("L", "dir: add dir to library path", Lflag);
+ flagfn1("H", "head: header type", setheadtype);
+ flagcount("K", "add stack underflow checks", &debug['K']);
+ flagcount("M", "disable software div/mod", &debug['M']);
+ flagcount("O", "print pc-line tables", &debug['O']);
+ flagcount("P", "debug code generation", &debug['P']);
+ flagint32("R", "rnd: address rounding", &INITRND);
+ flagint32("T", "addr: text address", &INITTEXT);
+ flagfn0("V", "print version and exit", doversion);
+ flagcount("W", "disassemble input", &debug['W']);
+ flagfn2("X", "name value: define string data", addstrdata);
+ flagcount("Z", "clear stack frame on entry", &debug['Z']);
+ flagcount("a", "disassemble output", &debug['a']);
+ flagcount("c", "dump call graph", &debug['c']);
+ flagcount("d", "disable dynamic executable", &debug['d']);
+ flagcount("f", "ignore version mismatch", &debug['f']);
+ flagcount("g", "disable go package data checks", &debug['g']);
+ flagstr("k", "sym: set field tracking symbol", &tracksym);
+ flagcount("n", "dump symbol table", &debug['n']);
+ flagstr("o", "outfile: set output file", &outfile);
+ flagcount("p", "insert profiling code", &debug['p']);
+ flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
+ flagcount("race", "enable race detector", &flag_race);
+ flagcount("s", "disable symbol table", &debug['s']);
+ flagcount("u", "reject unsafe packages", &debug['u']);
+ flagcount("v", "print link trace", &debug['v']);
+ flagcount("w", "disable DWARF generation", &debug['w']);
+ flagcount("shared", "generate shared object", &flag_shared);
+
+ flagparse(&argc, &argv, usage);
if(argc != 1)
usage();
@@ -152,7 +135,7 @@ main(int argc, char *argv[])
libinit();
if(HEADTYPE == -1)
- HEADTYPE = Hlinux;
+ HEADTYPE = headtype(goos);
switch(HEADTYPE) {
default:
diag("unknown -H option");
@@ -184,15 +167,6 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
- case Hnetbsd: /* boot for NetBSD */
- HEADR = 32L;
- if(INITTEXT == -1)
- INITTEXT = 0xF0000020L;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
case Hixp1200: /* boot for IXP1200 */
HEADR = 0L;
if(INITTEXT == -1)
@@ -212,7 +186,11 @@ main(int argc, char *argv[])
INITRND = 1024;
break;
case Hlinux: /* arm elf */
- debug['d'] = 1; // no dynamic linking
+ case Hfreebsd:
+ case Hnetbsd:
+ debug['d'] = 0; // with dynamic linking
+ tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m
+ // this number is known to ../../pkg/runtime/cgo/gcc_linux_arm.c
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
@@ -246,13 +224,17 @@ main(int argc, char *argv[])
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
+ // embed goarm to runtime.goarm
+ s = lookup("runtime.goarm", 0);
+ s->dupok = 1;
+ adduint8(s, goarm);
+
addlibpath("command line", "command line", argv[0], "main");
loadlib();
// mark some functions that are only referenced after linker code editing
- // TODO(kaib): this doesn't work, the prog can't be found in runtime
- for(i=0; i<nelem(linkername); i++)
- mark(lookup(linkername[i], 0));
+ if(debug['F'])
+ mark(rlookup("_sfloat", 0));
deadcode();
if(textp == nil) {
diag("no code");
@@ -268,9 +250,16 @@ main(int argc, char *argv[])
doelf();
follow();
softfloat();
- noops();
+ // 5l -Z means zero the stack frame on entry.
+ // This slows down function calls but can help avoid
+ // false positives in garbage collection.
+ if(debug['Z'])
+ dozerostk();
+ noops(); // generate stack split prolog, handle div/mod, etc.
dostkcheck();
span();
+ addexport();
+ // textaddress() functionality is handled in span()
pclntab();
symtab();
dodata();
@@ -291,24 +280,38 @@ main(int argc, char *argv[])
errorexit();
}
+static Sym*
+zsym(char *pn, Biobuf *f, Sym *h[])
+{
+ int o;
+
+ o = BGETC(f);
+ if(o == 0)
+ return S;
+ if(o < 0 || o >= NSYM || h[o] == nil)
+ mangle(pn);
+ return h[o];
+}
+
static void
-zaddr(Biobuf *f, Adr *a, Sym *h[])
+zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
{
int i, c;
int32 l;
Sym *s;
Auto *u;
- a->type = Bgetc(f);
- a->reg = Bgetc(f);
- c = Bgetc(f);
+ a->type = BGETC(f);
+ a->reg = BGETC(f);
+ c = BGETC(f);
if(c < 0 || c > NSYM){
print("sym out of range: %d\n", c);
Bputc(f, ALAST+1);
return;
}
a->sym = h[c];
- a->name = Bgetc(f);
+ a->name = BGETC(f);
+ adrgotype = zsym(pn, f, h);
if((schar)a->reg < 0 || a->reg > NREG) {
print("register out of range %d\n", a->reg);
@@ -341,7 +344,8 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
break;
case D_REGREG:
- a->offset = Bgetc(f);
+ case D_REGREG2:
+ a->offset = BGETC(f);
break;
case D_CONST2:
@@ -368,8 +372,11 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
if(s == S)
return;
i = a->name;
- if(i != D_AUTO && i != D_PARAM)
+ if(i != D_AUTO && i != D_PARAM) {
+ if(s && adrgotype)
+ s->gotype = adrgotype;
return;
+ }
l = a->offset;
for(u=curauto; u; u=u->link)
@@ -377,6 +384,8 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
if(u->type == i) {
if(u->aoffset > l)
u->aoffset = l;
+ if(adrgotype)
+ u->gotype = adrgotype;
return;
}
@@ -386,6 +395,7 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
u->asym = s;
u->aoffset = l;
u->type = i;
+ u->gotype = adrgotype;
}
void
@@ -425,7 +435,7 @@ newloop:
loop:
if(f->state == Bracteof || Boffset(f) >= eof)
goto eof;
- o = Bgetc(f);
+ o = BGETC(f);
if(o == Beof)
goto eof;
@@ -438,8 +448,8 @@ loop:
sig = 0;
if(o == ASIGNAME)
sig = Bget4(f);
- v = Bgetc(f); /* type */
- o = Bgetc(f); /* sym */
+ v = BGETC(f); /* type */
+ o = BGETC(f); /* sym */
r = 0;
if(v == D_STATIC)
r = version;
@@ -483,18 +493,20 @@ loop:
histfrogp++;
} else
collapsefrog(s);
+ dwarfaddfrag(s->value, s->name);
}
goto loop;
}
p = mal(sizeof(Prog));
p->as = o;
- p->scond = Bgetc(f);
- p->reg = Bgetc(f);
+ p->scond = BGETC(f);
+ p->reg = BGETC(f);
p->line = Bget4(f);
- zaddr(f, &p->from, h);
- zaddr(f, &p->to, h);
+ zaddr(pn, f, &p->from, h);
+ fromgotype = adrgotype;
+ zaddr(pn, f, &p->to, h);
if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG)
diag("register out of range %A %d", p->as, p->reg);
@@ -582,6 +594,15 @@ loop:
pc++;
break;
+ case ALOCALS:
+ cursym->locals = p->to.offset;
+ pc++;
+ break;
+
+ case ATYPE:
+ pc++;
+ goto loop;
+
case ATEXT:
if(cursym != nil && cursym->text) {
histtoauto();
@@ -611,6 +632,11 @@ loop:
etextp->next = s;
else
textp = s;
+ if(fromgotype) {
+ if(s->gotype && s->gotype != fromgotype)
+ diag("%s: type mismatch for %s", pn, s->name);
+ s->gotype = fromgotype;
+ }
etextp = s;
p->align = 4;
autosize = (p->to.offset+3L) & ~3L;
@@ -619,6 +645,7 @@ loop:
s->type = STEXT;
s->text = p;
s->value = pc;
+ s->args = p->to.offset2;
lastp = p;
p->pc = pc;
pc++;
@@ -672,7 +699,7 @@ loop:
sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
s = lookup(literal, 0);
if(s->type == 0) {
- s->type = SBSS;
+ s->type = SRODATA;
adduint32(s, ieeedtof(&p->from.ieee));
s->reachable = 0;
}
@@ -694,7 +721,7 @@ loop:
p->from.ieee.l, p->from.ieee.h);
s = lookup(literal, 0);
if(s->type == 0) {
- s->type = SBSS;
+ s->type = SRODATA;
adduint32(s, p->from.ieee.l);
adduint32(s, p->from.ieee.h);
s->reachable = 0;
diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c
index 514786f85..231071f20 100644
--- a/src/cmd/5l/optab.c
+++ b/src/cmd/5l/optab.c
@@ -63,6 +63,7 @@ Optab optab[] =
{ AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL },
{ ABL, C_NONE, C_NONE, C_ROREG, 7, 8, 0 },
+ { ABL, C_REG, C_NONE, C_ROREG, 7, 8, 0 },
{ ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 },
{ ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 },
@@ -77,10 +78,12 @@ Optab optab[] =
{ ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 },
{ AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 },
{ AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM },
+ { AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4},
{ AADD, C_NCON, C_REG, C_REG, 13, 8, 0 },
{ AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 },
@@ -103,6 +106,7 @@ Optab optab[] =
{ ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 },
{ AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 },
+ { AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0 },
{ AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
{ AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
@@ -118,20 +122,20 @@ Optab optab[] =
{ AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
{ AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
+ { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
{ AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
{ AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
+ { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
{ AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
{ AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
+ { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
{ AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
{ AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
- { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
+ { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 },
{ AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
{ AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
- { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
+ { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 },
{ AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM },
@@ -158,8 +162,8 @@ Optab optab[] =
{ AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM },
{ AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM },
- { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO },
- { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM },
+ { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4 },
+ { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4},
{ AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
{ AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 },
@@ -177,7 +181,7 @@ Optab optab[] =
{ AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
{ AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
- { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0 },
+ { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8 },
{ ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0 },
{ AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
@@ -194,20 +198,20 @@ Optab optab[] =
{ AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
{ AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
- { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO },
+ { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
{ AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
{ AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
{ AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
{ AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
+ { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
{ AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
{ AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
+ { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
{ AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
{ AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
+ { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
{ ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 },
{ ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 },
@@ -232,5 +236,16 @@ Optab optab[] =
{ ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 },
{ ASTREXD, C_SOREG,C_REG, C_REG, 92, 4, 0 },
+ { APLD, C_SOREG,C_NONE, C_NONE, 95, 4, 0 },
+
+ { AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0 },
+
+ { ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0 },
+
+ { AMULWT, C_REG, C_REG, C_REG, 98, 4, 0 },
+ { AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0 },
+
+ { AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0 },
+
{ AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
};
diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c
index 0f2afbd85..c22b86085 100644
--- a/src/cmd/5l/pass.c
+++ b/src/cmd/5l/pass.c
@@ -119,7 +119,7 @@ loop:
i--;
continue;
}
- if(a == AB || (a == ARET && q->scond == 14) || a == ARFE)
+ if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF)
goto copy;
if(q->cond == P || (q->cond->mark&FOLL))
continue;
@@ -140,7 +140,7 @@ loop:
}
(*last)->link = r;
*last = r;
- if(a == AB || (a == ARET && q->scond == 14) || a == ARFE)
+ if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF)
return;
r->as = ABNE;
if(a == ABNE)
@@ -166,7 +166,7 @@ loop:
p->mark |= FOLL;
(*last)->link = p;
*last = p;
- if(a == AB || (a == ARET && p->scond == 14) || a == ARFE){
+ if(a == AB || (a == ARET && p->scond == 14) || a == ARFE || a == AUNDEF){
return;
}
if(p->cond != P)
@@ -215,7 +215,7 @@ patch(void)
s = p->to.sym;
if(s->text == nil)
continue;
- switch(s->type) {
+ switch(s->type&SMASK) {
default:
diag("undefined: %s", s->name);
s->type = STEXT;
@@ -231,7 +231,7 @@ patch(void)
if(p->to.type != D_BRANCH)
continue;
c = p->to.offset;
- for(q = textp->text; q != P;) {
+ for(q = cursym->text; q != P;) {
if(c == q->pc)
break;
if(q->forwd != P && c >= q->forwd->pc)
@@ -333,3 +333,70 @@ rnd(int32 v, int32 r)
v -= c;
return v;
}
+
+void
+dozerostk(void)
+{
+ Prog *p, *pl;
+ int32 autoffset;
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
+ p = cursym->text;
+ autoffset = p->to.offset;
+ if(autoffset < 0)
+ autoffset = 0;
+ if(autoffset && !(p->reg&NOSPLIT)) {
+ // MOVW $4(R13), R1
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = 13;
+ p->from.offset = 4;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ // MOVW $n(R13), R2
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = 13;
+ p->from.offset = 4 + autoffset;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ // MOVW $0, R3
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ // L:
+ // MOVW.P R3, 0(R1) +4
+ // CMP R1, R2
+ // BNE L
+ p = pl = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_OREG;
+ p->to.reg = 1;
+ p->to.offset = 4;
+ p->scond |= C_PBIT;
+
+ p = appendp(p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->reg = 2;
+
+ p = appendp(p);
+ p->as = ABNE;
+ p->to.type = D_BRANCH;
+ p->cond = pl;
+ }
+ }
+}
diff --git a/src/cmd/5l/softfloat.c b/src/cmd/5l/softfloat.c
index 401107178..de6481c71 100644
--- a/src/cmd/5l/softfloat.c
+++ b/src/cmd/5l/softfloat.c
@@ -55,6 +55,8 @@ softfloat(void)
case ADIVD:
case ASQRTF:
case ASQRTD:
+ case AABSF:
+ case AABSD:
goto soft;
default:
@@ -74,6 +76,7 @@ softfloat(void)
p->to.type = D_BRANCH;
p->to.sym = symsfloat;
p->cond = psfloat;
+ p->line = next->line;
p = next;
wasfloat = 1;
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
index 13e1848e1..a5afa02e7 100644
--- a/src/cmd/5l/span.c
+++ b/src/cmd/5l/span.c
@@ -90,16 +90,36 @@ span(void)
int32 c, otxt, out[6];
Section *sect;
uchar *bp;
+ Sym *sub;
if(debug['v'])
Bprint(&bso, "%5.2f span\n", cputime());
Bflush(&bso);
+ sect = addsection(&segtext, ".text", 05);
+ lookup("text", 0)->sect = sect;
+ lookup("etext", 0)->sect = sect;
+
bflag = 0;
c = INITTEXT;
otxt = c;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ cursym->sect = sect;
p = cursym->text;
+ if(p == P || p->link == P) { // handle external functions and ELF section symbols
+ if(cursym->type & SSUB)
+ continue;
+ if(cursym->align != 0)
+ c = rnd(c, cursym->align);
+ cursym->value = 0;
+ for(sub = cursym; sub != S; sub = sub->sub) {
+ sub->value += c;
+ for(p = sub->text; p != P; p = p->link)
+ p->pc += sub->value;
+ }
+ c += cursym->size;
+ continue;
+ }
p->pc = c;
cursym->value = c;
@@ -160,6 +180,8 @@ span(void)
bflag = 0;
c = INITTEXT;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(!cursym->text || !cursym->text->link)
+ continue;
cursym->value = c;
for(p = cursym->text; p != P; p = p->link) {
curp = p;
@@ -217,6 +239,8 @@ span(void)
*/
for(cursym = textp; cursym != nil; cursym = cursym->next) {
p = cursym->text;
+ if(p == P || p->link == P)
+ continue;
autosize = p->to.offset + 4;
symgrow(cursym, cursym->size);
@@ -235,7 +259,6 @@ span(void)
}
}
}
- sect = addsection(&segtext, ".text", 05);
sect->vaddr = INITTEXT;
sect->len = c - INITTEXT;
}
@@ -269,12 +292,20 @@ flushpool(Prog *p, int skip, int force)
q->to.type = D_BRANCH;
q->cond = p->link;
q->link = blitrl;
+ q->line = p->line;
blitrl = q;
}
else if(!force && (p->pc+pool.size-pool.start < 2048))
return 0;
elitrl->link = p->link;
p->link = blitrl;
+ // BUG(minux): how to correctly handle line number for constant pool entries?
+ // for now, we set line number to the last instruction preceding them at least
+ // this won't bloat the .debug_line tables
+ while(blitrl) {
+ blitrl->line = p->line;
+ blitrl = blitrl->link;
+ }
blitrl = 0; /* BUG: should refer back to values until out-of-range */
elitrl = 0;
pool.size = 0;
@@ -299,9 +330,11 @@ addpool(Prog *p, Adr *a)
switch(c) {
default:
t.to = *a;
+ if(flag_shared && t.to.sym != S)
+ t.pcrel = p;
break;
- case C_SROREG:
+ case C_SROREG:
case C_LOREG:
case C_ROREG:
case C_FOREG:
@@ -316,11 +349,13 @@ addpool(Prog *p, Adr *a)
break;
}
- for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */
- if(memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
- p->cond = q;
- return;
- }
+ if(t.pcrel == P) {
+ for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */
+ if(q->pcrel == P && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
+ p->cond = q;
+ return;
+ }
+ }
q = prg();
*q = t;
@@ -407,25 +442,9 @@ immhalf(int32 v)
int32
symaddr(Sym *s)
{
- int32 v;
-
- v = s->value;
- switch(s->type) {
- default:
- diag("unexpected type %d in symaddr(%s)", s->type, s->name);
- return 0;
-
- case STEXT:
- case SELFROSECT:
- case SRODATA:
- case SDATA:
- case SBSS:
- case SCONST:
- case SNOPTRDATA:
- case SNOPTRBSS:
- break;
- }
- return v;
+ if(!s->reachable)
+ diag("unreachable symbol in symaddr - %s", s->name);
+ return s->value;
}
int
@@ -444,6 +463,9 @@ aclass(Adr *a)
case D_REGREG:
return C_REGREG;
+ case D_REGREG2:
+ return C_REGREG2;
+
case D_SHIFT:
return C_SHIFT;
@@ -552,7 +574,10 @@ aclass(Adr *a)
if(s == S)
break;
instoffset = 0; // s.b. unused but just in case
- return C_LCON;
+ if(flag_shared)
+ return C_LCONADDR;
+ else
+ return C_LCON;
case D_AUTO:
instoffset = autosize + a->offset;
@@ -718,8 +743,14 @@ buildop(void)
for(i=0; i<C_GOK; i++)
for(n=0; n<C_GOK; n++)
xcmp[i][n] = cmp(n, i);
- for(n=0; optab[n].as != AXXX; n++)
- ;
+ for(n=0; optab[n].as != AXXX; n++) {
+ if((optab[n].flag & LPCREL) != 0) {
+ if(flag_shared)
+ optab[n].size += optab[n].pcrelsiz;
+ else
+ optab[n].flag &= ~LPCREL;
+ }
+ }
qsort(optab, n, sizeof(optab[0]), ocmp);
for(i=0; i<n; i++) {
r = optab[i].as;
@@ -798,8 +829,11 @@ buildop(void)
case AMOVM:
case ARFE:
case ATEXT:
+ case AUSEFIELD:
+ case ALOCALS:
case ACASE:
case ABCASE:
+ case ATYPE:
break;
case AADDF:
oprange[AADDD] = oprange[r];
@@ -813,6 +847,8 @@ buildop(void)
oprange[ASQRTD] = oprange[r];
oprange[AMOVFD] = oprange[r];
oprange[AMOVDF] = oprange[r];
+ oprange[AABSF] = oprange[r];
+ oprange[AABSD] = oprange[r];
break;
case ACMPF:
@@ -832,17 +868,28 @@ buildop(void)
break;
case AMULL:
- oprange[AMULA] = oprange[r];
oprange[AMULAL] = oprange[r];
oprange[AMULLU] = oprange[r];
oprange[AMULALU] = oprange[r];
break;
+ case AMULWT:
+ oprange[AMULWB] = oprange[r];
+ break;
+
+ case AMULAWT:
+ oprange[AMULAWB] = oprange[r];
+ break;
+
+ case AMULA:
case ALDREX:
case ASTREX:
case ALDREXD:
case ASTREXD:
case ATST:
+ case APLD:
+ case AUNDEF:
+ case ACLZ:
break;
}
}