diff options
author | Michael Stapelberg <stapelberg@debian.org> | 2013-03-04 21:27:36 +0100 |
---|---|---|
committer | Michael Stapelberg <michael@stapelberg.de> | 2013-03-04 21:27:36 +0100 |
commit | 04b08da9af0c450d645ab7389d1467308cfc2db8 (patch) | |
tree | db247935fa4f2f94408edc3acd5d0d4f997aa0d8 /src/cmd/5l | |
parent | 917c5fb8ec48e22459d77e3849e6d388f93d3260 (diff) | |
download | golang-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.h | 31 | ||||
-rw-r--r-- | src/cmd/5l/asm.c | 1055 | ||||
-rw-r--r-- | src/cmd/5l/doc.go | 4 | ||||
-rw-r--r-- | src/cmd/5l/l.h | 57 | ||||
-rw-r--r-- | src/cmd/5l/list.c | 8 | ||||
-rw-r--r-- | src/cmd/5l/noop.c | 50 | ||||
-rw-r--r-- | src/cmd/5l/obj.c | 223 | ||||
-rw-r--r-- | src/cmd/5l/optab.c | 41 | ||||
-rw-r--r-- | src/cmd/5l/pass.c | 77 | ||||
-rw-r--r-- | src/cmd/5l/softfloat.c | 3 | ||||
-rw-r--r-- | src/cmd/5l/span.c | 107 |
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; } } |