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/8l | |
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/8l')
-rw-r--r-- | src/cmd/8l/8.out.h | 152 | ||||
-rw-r--r-- | src/cmd/8l/asm.c | 648 | ||||
-rw-r--r-- | src/cmd/8l/doc.go | 4 | ||||
-rw-r--r-- | src/cmd/8l/l.h | 23 | ||||
-rw-r--r-- | src/cmd/8l/list.c | 9 | ||||
-rw-r--r-- | src/cmd/8l/obj.c | 148 | ||||
-rw-r--r-- | src/cmd/8l/optab.c | 208 | ||||
-rw-r--r-- | src/cmd/8l/pass.c | 79 | ||||
-rw-r--r-- | src/cmd/8l/span.c | 156 |
9 files changed, 767 insertions, 660 deletions
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h index 9d2751cf0..386889956 100644 --- a/src/cmd/8l/8.out.h +++ b/src/cmd/8l/8.out.h @@ -451,6 +451,125 @@ enum as ASFENCE, AEMMS, + + APREFETCHT0, + APREFETCHT1, + APREFETCHT2, + APREFETCHNTA, + + ABSWAPL, + + AUNDEF, + + // SSE2 + AADDPD, + AADDPS, + AADDSD, + AADDSS, + AANDNPD, + AANDNPS, + AANDPD, + AANDPS, + ACMPPD, + ACMPPS, + ACMPSD, + ACMPSS, + ACOMISD, + ACOMISS, + ACVTPL2PD, + ACVTPL2PS, + ACVTPD2PL, + ACVTPD2PS, + ACVTPS2PL, + ACVTPS2PD, + ACVTSD2SL, + ACVTSD2SS, + ACVTSL2SD, + ACVTSL2SS, + ACVTSS2SD, + ACVTSS2SL, + ACVTTPD2PL, + ACVTTPS2PL, + ACVTTSD2SL, + ACVTTSS2SL, + ADIVPD, + ADIVPS, + ADIVSD, + ADIVSS, + AMASKMOVOU, + AMAXPD, + AMAXPS, + AMAXSD, + AMAXSS, + AMINPD, + AMINPS, + AMINSD, + AMINSS, + AMOVAPD, + AMOVAPS, + AMOVO, + AMOVOU, + AMOVHLPS, + AMOVHPD, + AMOVHPS, + AMOVLHPS, + AMOVLPD, + AMOVLPS, + AMOVMSKPD, + AMOVMSKPS, + AMOVNTO, + AMOVNTPD, + AMOVNTPS, + AMOVSD, + AMOVSS, + AMOVUPD, + AMOVUPS, + AMULPD, + AMULPS, + AMULSD, + AMULSS, + AORPD, + AORPS, + APADDQ, + APMAXSW, + APMAXUB, + APMINSW, + APMINUB, + APSADBW, + APSUBB, + APSUBL, + APSUBQ, + APSUBSB, + APSUBSW, + APSUBUSB, + APSUBUSW, + APSUBW, + APUNPCKHQDQ, + APUNPCKLQDQ, + ARCPPS, + ARCPSS, + ARSQRTPS, + ARSQRTSS, + ASQRTPD, + ASQRTPS, + ASQRTSD, + ASQRTSS, + ASUBPD, + ASUBPS, + ASUBSD, + ASUBSS, + AUCOMISD, + AUCOMISS, + AUNPCKHPD, + AUNPCKHPS, + AUNPCKLPD, + AUNPCKLPS, + AXORPD, + AXORPS, + + AUSEFIELD, + ALOCALS, + ATYPE, ALAST }; @@ -496,17 +615,26 @@ enum D_DR = 43, D_TR = 51, - D_NONE = 59, - - D_BRANCH = 60, - D_EXTERN = 61, - D_STATIC = 62, - D_AUTO = 63, - D_PARAM = 64, - D_CONST = 65, - D_FCONST = 66, - D_SCONST = 67, - D_ADDR = 68, + D_X0 = 59, + D_X1, + D_X2, + D_X3, + D_X4, + D_X5, + D_X6, + D_X7, + + D_NONE = 67, + + D_BRANCH = 68, + D_EXTERN = 69, + D_STATIC = 70, + D_AUTO = 71, + D_PARAM = 72, + D_CONST = 73, + D_FCONST = 74, + D_SCONST = 75, + D_ADDR = 76, D_FILE, D_FILE1, @@ -538,7 +666,7 @@ enum /* * this is the ranlib header */ -#define SYMDEF "__.SYMDEF" +#define SYMDEF "__.GOSYMDEF" /* * this is the simulated IEEE floating point diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index 25ffc786f..a00174c36 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -70,34 +70,6 @@ datoff(vlong addr) return 0; } -enum { - ElfStrEmpty, - ElfStrInterp, - ElfStrHash, - ElfStrGot, - ElfStrGotPlt, - ElfStrDynamic, - ElfStrDynsym, - ElfStrDynstr, - ElfStrRel, - ElfStrText, - ElfStrData, - ElfStrBss, - ElfStrShstrtab, - ElfStrSymtab, - ElfStrStrtab, - ElfStrRelPlt, - ElfStrPlt, - ElfStrGnuVersion, - ElfStrGnuVersionR, - ElfStrNoteNetbsdIdent, - ElfStrNoPtrData, - ElfStrNoPtrBss, - NElfStr -}; - -vlong elfstr[NElfStr]; - static int needlib(char *name) { @@ -123,6 +95,21 @@ int nelfsym = 1; static void addpltsym(Sym*); static void addgotsym(Sym*); +Sym * +lookuprel(void) +{ + return lookup(".rel", 0); +} + +void +adddynrela(Sym *rela, Sym *s, Reloc *r) +{ + USED(rela); + USED(s); + USED(r); + sysfatal("adddynrela not implemented"); +} + void adddynrel(Sym *s, Reloc *r) { @@ -282,7 +269,36 @@ adddynrel(Sym *s, Reloc *r) 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_386_32 | elfsym<<8); + else + return -1; + break; + + case D_PCREL: + if(r->siz == 4) + LPUT(R_386_PC32 | elfsym<<8); + else + return -1; + break; + } + + return 0; +} + +void elfsetupplt(void) { Sym *plt, *got; @@ -415,6 +431,7 @@ adddynsym(Sym *s) Sym *d, *str; int t; char *name; + vlong off; if(s->dynid >= 0) return; @@ -444,7 +461,7 @@ adddynsym(Sym *s) /* type */ t = STB_GLOBAL << 4; - if(s->dynexport && s->type == STEXT) + if(s->dynexport && (s->type&SMASK) == STEXT) t |= STT_FUNC; else t |= STT_OBJECT; @@ -478,16 +495,51 @@ adddynsym(Sym *s) name = s->dynimpname; if(name == nil) name = s->name; - s->dynid = d->size/12; + if(d->size == 0 && ndynexp > 0) { // pre-allocate for dynexps + symgrow(d, ndynexp*12); + } + if(s->dynid <= -100) { // pre-allocated, see cmd/ld/go.c:^sortdynexp() + s->dynid = -s->dynid-100; + off = s->dynid*12; + } else { + off = d->size; + s->dynid = off/12; + } // darwin still puts _ prefixes on all C symbols str = lookup(".dynstr", 0); - adduint32(d, str->size); + setuint32(d, off, str->size); + off += 4; adduint8(str, '_'); addstring(str, name); - adduint8(d, 0x01); // type - N_EXT - external symbol - adduint8(d, 0); // section - adduint16(d, 0); // desc - adduint32(d, 0); // value + if(s->type == SDYNIMPORT) { + setuint8(d, off, 0x01); // type - N_EXT - external symbol + off++; + setuint8(d, off, 0); // section + off++; + } else { + setuint8(d, off, 0x0f); + off++; + switch(s->type) { + default: + case STEXT: + setuint8(d, off, 1); + break; + case SDATA: + setuint8(d, off, 2); + break; + case SBSS: + setuint8(d, off, 4); + break; + } + off++; + } + setuint16(d, off, 0); // desc + off += 2; + if(s->type == SDYNIMPORT) + setuint32(d, off, 0); // value + else + setaddr(d, off, s); + off += 4; } else if(HEADTYPE != Hwindows) { diag("adddynsym: unsupported binary format"); } @@ -514,177 +566,26 @@ adddynlib(char *lib) } void -doelf(void) -{ - Sym *s, *shstrtab, *dynstr; - - if(!iself) - 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, ".elfdata"); - addstring(shstrtab, ".rodata"); - addstring(shstrtab, ".gosymtab"); - addstring(shstrtab, ".gopclntab"); - if(!debug['s']) { - elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab"); - elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab"); - dwarfaddshstrings(shstrtab); - } - 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"); - elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version"); - elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r"); - - /* dynamic symbol table - first entry all zeros */ - s = lookup(".dynsym", 0); - s->type = SELFROSECT; - s->reachable = 1; - s->size += ELF32SYMSIZE; - - /* dynamic string table */ - s = lookup(".dynstr", 0); - s->reachable = 1; - s->type = SELFROSECT; - if(s->size == 0) - addstring(s, ""); - dynstr = s; - - /* relocation table */ - s = lookup(".rel", 0); - s->reachable = 1; - s->type = SELFROSECT; - - /* 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; - - s = lookup(".rel.plt", 0); - s->reachable = 1; - s->type = SELFROSECT; - - s = lookup(".gnu.version", 0); - s->reachable = 1; - s->type = SELFROSECT; - - s = lookup(".gnu.version_r", 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); - - // Do not write DT_NULL. elfdynhash will finish it. - } -} - -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 v, magic; - int a, dynsym; - uint32 symo, startva, dwarfoff, machlink, resoff; - ElfEhdr *eh; - ElfPhdr *ph, *pph; - ElfShdr *sh; + uint32 symo, dwarfoff, machlink; Section *sect; Sym *sym; - int o; 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); @@ -712,19 +613,6 @@ asmb(void) machlink = domacholink(); } - if(iself) { - /* index of elf text section; needed by asmelfsym, double-checked below */ - /* !debug['d'] causes extra sections before the .text section */ - elftextsh = 2; - if(!debug['d']) { - elftextsh += 10; - if(elfverneed) - elftextsh += 2; - } - if(HEADTYPE == Hnetbsd) - elftextsh += 1; - } - symsize = 0; spsize = 0; lcsize = 0; @@ -777,6 +665,9 @@ asmb(void) if(debug['v']) Bprint(&bso, "%5.2f dwarf\n", cputime()); dwarfemitdebugsections(); + + if(isobj) + elfemitreloc(); } break; case Hplan9x32: @@ -805,8 +696,6 @@ asmb(void) cseek(0L); switch(HEADTYPE) { default: - if(iself) - goto Elfput; case Hgarbunix: /* garbage */ lputb(0x160L<<16); /* magic and sections */ lputb(0L); /* time and date */ @@ -932,273 +821,15 @@ asmb(void) wputl(0x003E); /* reloc table offset */ wputl(0x0000); /* overlay number */ break; - case Hdarwin: asmbmacho(); break; - - Elfput: - eh = getElfEhdr(); - startva = INITTEXT - HEADR; - 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 */ - sh = newElfShdr(elfstr[ElfStrInterp]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC; - sh->addralign = 1; - if(interpreter == nil) { - switch(HEADTYPE) { - case Hlinux: - interpreter = linuxdynld; - break; - case Hfreebsd: - interpreter = freebsddynld; - break; - case Hnetbsd: - interpreter = netbsddynld; - break; - case Hopenbsd: - interpreter = openbsddynld; - break; - } - } - 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); - } - - // Additions to the reserved area must be above this line. - USED(resoff); - - 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)); - - if(elfverneed) { - sh = newElfShdr(elfstr[ElfStrGnuVersion]); - sh->type = SHT_GNU_VERSYM; - sh->flags = SHF_ALLOC; - sh->addralign = 2; - sh->link = dynsym; - sh->entsize = 2; - shsym(sh, lookup(".gnu.version", 0)); - - sh = newElfShdr(elfstr[ElfStrGnuVersionR]); - sh->type = SHT_GNU_VERNEED; - sh->flags = SHF_ALLOC; - sh->addralign = 4; - sh->info = elfverneed; - sh->link = dynsym+1; // dynstr - shsym(sh, lookup(".gnu.version_r", 0)); - } - - sh = newElfShdr(elfstr[ElfStrRelPlt]); - sh->type = SHT_REL; - sh->flags = SHF_ALLOC; - sh->entsize = ELF32RELSIZE; - sh->addralign = 4; - sh->link = dynsym; - sh->info = eh->shnum; // .plt - shsym(sh, lookup(".rel.plt", 0)); - - sh = newElfShdr(elfstr[ElfStrPlt]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC+SHF_EXECINSTR; - sh->entsize = 4; - sh->addralign = 4; - shsym(sh, lookup(".plt", 0)); - - sh = newElfShdr(elfstr[ElfStrHash]); - sh->type = SHT_HASH; - 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; - switch(HEADTYPE) { - case Hfreebsd: - eh->ident[EI_OSABI] = ELFOSABI_FREEBSD; - break; - case Hnetbsd: - eh->ident[EI_OSABI] = ELFOSABI_NETBSD; - break; - case Hopenbsd: - eh->ident[EI_OSABI] = ELFOSABI_OPENBSD; - break; - } - - eh->type = ET_EXEC; - eh->machine = EM_386; - 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 Hlinux: + case Hfreebsd: + case Hnetbsd: + case Hopenbsd: + asmbelf(symo); break; - case Hwindows: asmbpe(); break; @@ -1231,80 +862,3 @@ rnd(int32 v, int32 r) v -= c; return v; } - -void -genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) -{ - Auto *a; - Sym *s; - int h; - - s = lookup("etext", 0); - if(s->type == STEXT) - put(s, s->name, 'T', s->value, s->size, s->version, 0); - - for(h=0; h<NHASH; h++) { - for(s=hash[h]; s!=S; s=s->hash) { - if(s->hide) - continue; - switch(s->type&~SSUB) { - case SCONST: - case SRODATA: - case SDATA: - case SELFROSECT: - case SMACHO: - case SMACHOGOT: - case STYPE: - case SSTRING: - case SGOSTRING: - case SWINDOWS: - case SNOPTRDATA: - case SSYMTAB: - case SPCLNTAB: - if(!s->reachable) - continue; - put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype); - continue; - - case SBSS: - case SNOPTRBSS: - if(!s->reachable) - continue; - put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype); - continue; - - case SFILE: - put(nil, s->name, 'f', s->value, 0, s->version, 0); - continue; - } - } - } - - for(s = textp; s != nil; s = s->next) { - if(s->text == nil) - continue; - - /* filenames first */ - for(a=s->autom; a; a=a->link) - if(a->type == D_FILE) - put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0); - else - if(a->type == D_FILE1) - put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0); - - put(s, s->name, 'T', s->value, s->size, s->version, s->gotype); - - /* frame, auto and param after */ - put(nil, ".frame", 'm', s->text->to.offset+4, 0, 0, 0); - - for(a=s->autom; a; a=a->link) - if(a->type == D_AUTO) - put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype); - else - if(a->type == D_PARAM) - put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype); - } - if(debug['v'] || debug['n']) - Bprint(&bso, "symsize = %d\n", symsize); - Bflush(&bso); -} diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go index 12301d4f2..ff06bc376 100644 --- a/src/cmd/8l/doc.go +++ b/src/cmd/8l/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 + /* 8l is the linker for the 32-bit x86. @@ -10,4 +12,4 @@ The $GOARCH for these tools is 386. The flags are documented in ../ld/doc.go. */ -package documentation +package main diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h index b974f464b..f88f058e3 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -40,7 +40,9 @@ enum { thechar = '8', - PtrSize = 4 + PtrSize = 4, + IntSize = 4, + FuncAlign = 16 }; #define P ((Prog*)0) @@ -135,16 +137,22 @@ struct Sym int32 plt; int32 got; 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 Sym* hash; // in hash table Sym* allsym; // in all symbol list Sym* next; // in text or data list Sym* sub; // in sub 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; @@ -157,6 +165,7 @@ struct Sym Reloc* r; int32 nr; int32 maxr; + int rel_ro; }; struct Optab { @@ -201,6 +210,8 @@ enum Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7, Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, + Ymr, Ymm, + Yxr, Yxm, Ymax, Zxxx = 0, @@ -222,10 +233,14 @@ enum Zloop, Zm_o, Zm_r, + Zm_r_xm, + Zm_r_i_xm, Zaut_r, Zo_m, Zpseudo, Zr_m, + Zr_m_xm, + Zr_m_i_xm, Zrp_, Z_ib, Z_il, @@ -243,6 +258,8 @@ enum Pm = 0x0f, /* 2byte opcode escape */ Pq = 0xff, /* both escape */ Pb = 0xfe, /* byte operands */ + Pf2 = 0xf2, /* xmm escape 1 */ + Pf3 = 0xf3, /* xmm escape 2 */ }; #pragma varargck type "A" int @@ -261,6 +278,7 @@ EXTERN int32 INITRND; EXTERN int32 INITTEXT; EXTERN int32 INITDAT; EXTERN char* INITENTRY; /* entry point */ +EXTERN char* LIBINITENTRY; /* shared library entry point */ EXTERN int32 casepc; EXTERN char* pcstr; EXTERN Auto* curauto; @@ -269,7 +287,7 @@ EXTERN Prog* curp; EXTERN Sym* cursym; EXTERN Sym* datap; EXTERN int32 elfdatsize; -EXTERN char debug[128]; +EXTERN int debug[128]; EXTERN char literal[32]; EXTERN Sym* etextp; EXTERN Prog* firstp; @@ -282,7 +300,6 @@ EXTERN int maxop; EXTERN int nerrors; EXTERN char* noname; EXTERN int32 pc; -EXTERN char* interpreter; EXTERN char* rpath; EXTERN int32 spsize; EXTERN Sym* symlist; diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c index 31ae02346..0b544fbce 100644 --- a/src/cmd/8l/list.c +++ b/src/cmd/8l/list.c @@ -254,6 +254,15 @@ char* regstr[] = "TR5", "TR6", "TR7", + + "X0", + "X1", + "X2", + "X3", + "X4", + "X5", + "X6", + "X7", "NONE", /* [D_NONE] */ }; diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c index af4bc844f..dcb8390b9 100644 --- a/src/cmd/8l/obj.c +++ b/src/cmd/8l/obj.c @@ -77,18 +77,8 @@ Header headers[] = { */ void -usage(void) -{ - fprint(2, "usage: 8l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.8\n"); - exits("usage"); -} - -void main(int argc, char *argv[]) { - int c; - char *name, *val; - Binit(&bso, 1, OWRITE); listinit(); memset(debug, 0, sizeof(debug)); @@ -99,52 +89,44 @@ main(int argc, char *argv[]) INITDAT = -1; INITRND = -1; INITENTRY = 0; + LIBINITENTRY = 0; nuxiinit(); - ARGBEGIN { - default: - c = ARGC(); - if(c == 'l') - usage(); - if(c >= 0 && c < sizeof(debug)) - debug[c]++; - break; - case 'o': /* output to (next arg) */ - outfile = EARGF(usage()); - break; - case 'E': - INITENTRY = EARGF(usage()); - break; - case 'H': - HEADTYPE = headtype(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 'V': - print("%cl version %s\n", thechar, getgoversion()); - errorexit(); - case 'X': - name = EARGF(usage()); - val = EARGF(usage()); - addstrdata(name, val); - break; - } ARGEND + 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); + 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("O", "print pc-line tables", &debug['O']); + flagcount("Q", "debug byte-register code gen", &debug['Q']); + flagint32("R", "rnd: address rounding", &INITRND); + flagcount("S", "check type signatures", &debug['S']); + 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']); + flagcount("hostobj", "generate host object file", &isobj); + flagstr("k", "sym: set field tracking symbol", &tracksym); + 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("n", "dump symbol table", &debug['n']); + flagcount("u", "reject unsafe packages", &debug['u']); + flagcount("v", "print link trace", &debug['v']); + flagcount("w", "disable DWARF generation", &debug['w']); + + flagparse(&argc, &argv, usage); if(argc != 1) usage(); @@ -154,6 +136,15 @@ main(int argc, char *argv[]) if(HEADTYPE == -1) HEADTYPE = headtype(goos); + if(isobj) { + switch(HEADTYPE) { + default: + sysfatal("cannot use -hostobj with -H %s", headstr(HEADTYPE)); + case Hlinux: + break; + } + } + if(outfile == nil) { if(HEADTYPE == Hwindows) outfile = "8.out.exe"; @@ -300,6 +291,7 @@ main(int argc, char *argv[]) if(HEADTYPE == Hwindows) dope(); dostkoff(); + dostkcheck(); if(debug['p']) if(debug['1']) doprof1(); @@ -332,7 +324,7 @@ zsym(char *pn, Biobuf *f, Sym *h[]) { int o; - o = Bgetc(f); + o = BGETC(f); if(o < 0 || o >= NSYM || h[o] == nil) mangle(pn); return h[o]; @@ -346,12 +338,12 @@ zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[]) Sym *s; Auto *u; - t = Bgetc(f); + t = BGETC(f); a->index = D_NONE; a->scale = 0; if(t & T_INDEX) { - a->index = Bgetc(f); - a->scale = Bgetc(f); + a->index = BGETC(f); + a->scale = BGETC(f); } a->type = D_NONE; a->offset = 0; @@ -375,7 +367,7 @@ zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[]) a->type = D_SCONST; } if(t & T_TYPE) - a->type = Bgetc(f); + a->type = BGETC(f); adrgotype = S; if(t & T_GOTYPE) adrgotype = zsym(pn, f, h); @@ -451,10 +443,10 @@ newloop: loop: if(f->state == Bracteof || Boffset(f) >= eof) goto eof; - o = Bgetc(f); + o = BGETC(f); if(o == Beof) goto eof; - o |= Bgetc(f) << 8; + o |= BGETC(f) << 8; if(o <= AXXX || o >= ALAST) { if(o < 0) goto eof; @@ -467,8 +459,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; @@ -523,8 +515,6 @@ loop: p->as = o; p->line = Bget4(f); p->back = 2; - p->ft = 0; - p->tt = 0; zaddr(pn, f, &p->from, h); fromgotype = adrgotype; zaddr(pn, f, &p->to, h); @@ -605,6 +595,15 @@ loop: pc++; goto loop; + case ALOCALS: + cursym->locals = p->to.offset; + pc++; + goto loop; + + case ATYPE: + pc++; + goto loop; + case ATEXT: s = p->from.sym; if(s->text != nil) { @@ -643,6 +642,7 @@ loop: } s->type = STEXT; s->value = pc; + s->args = p->to.offset2; lastp = p; p->pc = pc++; goto loop; @@ -656,6 +656,13 @@ loop: case AFDIVRF: case AFCOMF: case AFCOMFP: + case AMOVSS: + case AADDSS: + case ASUBSS: + case AMULSS: + case ADIVSS: + case ACOMISS: + case AUCOMISS: if(skip) goto casdef; if(p->from.type == D_FCONST) { @@ -663,7 +670,7 @@ loop: sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); s = lookup(literal, 0); if(s->type == 0) { - s->type = SDATA; + s->type = SRODATA; adduint32(s, ieeedtof(&p->from.ieee)); s->reachable = 0; } @@ -682,6 +689,13 @@ loop: case AFDIVRD: case AFCOMD: case AFCOMDP: + case AMOVSD: + case AADDSD: + case ASUBSD: + case AMULSD: + case ADIVSD: + case ACOMISD: + case AUCOMISD: if(skip) goto casdef; if(p->from.type == D_FCONST) { @@ -690,7 +704,7 @@ loop: p->from.ieee.l, p->from.ieee.h); s = lookup(literal, 0); if(s->type == 0) { - s->type = SDATA; + s->type = SRODATA; adduint32(s, p->from.ieee.l); adduint32(s, p->from.ieee.h); s->reachable = 0; diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c index 856482290..79d7b39f0 100644 --- a/src/cmd/8l/optab.c +++ b/src/cmd/8l/optab.c @@ -242,6 +242,11 @@ uchar ypopl[] = Ynone, Ym, Zo_m, 2, 0 }; +uchar ybswap[] = +{ + Ynone, Yrl, Z_rp, 1, + 0, +}; uchar yscond[] = { Ynone, Ymb, Zo_m, 2, @@ -249,7 +254,9 @@ uchar yscond[] = }; uchar yjcond[] = { - Ynone, Ybr, Zbr, 1, + Ynone, Ybr, Zbr, 0, + Yi0, Ybr, Zbr, 0, + Yi1, Ybr, Zbr, 1, 0 }; uchar yloop[] = @@ -259,7 +266,8 @@ uchar yloop[] = }; uchar ycall[] = { - Ynone, Yml, Zo_m, 2, + Ynone, Yml, Zo_m, 0, + Yrx, Yrx, Zo_m, 2, Ynone, Ycol, Zcallind, 2, Ynone, Ybr, Zcall, 0, Ynone, Yi32, Zcallcon, 1, @@ -349,6 +357,84 @@ uchar ysvrs[] = Ym, Ynone, Zm_o, 2, 0 }; +uchar yxm[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxcvm1[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + Yxm, Ymr, Zm_r_xm, 2, + 0 +}; +uchar yxcvm2[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + Ymm, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yxmq[] = +{ + Yxm, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yxr[] = +{ + Yxr, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxr_ml[] = +{ + Yxr, Yml, Zr_m_xm, 1, + 0 +}; +uchar yxcmp[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxcmpi[] = +{ + Yxm, Yxr, Zm_r_i_xm, 2, + 0 +}; +uchar yxmov[] = +{ + Yxm, Yxr, Zm_r_xm, 1, + Yxr, Yxm, Zr_m_xm, 1, + 0 +}; +uchar yxcvfl[] = +{ + Yxm, Yrl, Zm_r_xm, 1, + 0 +}; +uchar yxcvlf[] = +{ + Yml, Yxr, Zm_r_xm, 1, + 0 +}; +uchar yxcvfq[] = +{ + Yxm, Yrl, Zm_r_xm, 2, + 0 +}; +uchar yxcvqf[] = +{ + Yml, Yxr, Zm_r_xm, 2, + 0 +}; +uchar yxrrl[] = +{ + Yxr, Yrl, Zm_r, 1, + 0 +}; +uchar yprefetch[] = +{ + Ym, Ynone, Zm_o, 2, + 0, +}; Optab optab[] = /* as, ytab, andproto, opcode */ @@ -761,5 +847,123 @@ Optab optab[] = { AEMMS, ynone, Pm, 0x77 }, + { APREFETCHT0, yprefetch, Pm, 0x18,(01) }, + { APREFETCHT1, yprefetch, Pm, 0x18,(02) }, + { APREFETCHT2, yprefetch, Pm, 0x18,(03) }, + { APREFETCHNTA, yprefetch, Pm, 0x18,(00) }, + + { ABSWAPL, ybswap, Pm, 0xc8 }, + + { AUNDEF, ynone, Px, 0x0f, 0x0b }, + + { AADDPD, yxm, Pq, 0x58 }, + { AADDPS, yxm, Pm, 0x58 }, + { AADDSD, yxm, Pf2, 0x58 }, + { AADDSS, yxm, Pf3, 0x58 }, + { AANDNPD, yxm, Pq, 0x55 }, + { AANDNPS, yxm, Pm, 0x55 }, + { AANDPD, yxm, Pq, 0x54 }, + { AANDPS, yxm, Pq, 0x54 }, + { ACMPPD, yxcmpi, Px, Pe,0xc2 }, + { ACMPPS, yxcmpi, Pm, 0xc2,0 }, + { ACMPSD, yxcmpi, Px, Pf2,0xc2 }, + { ACMPSS, yxcmpi, Px, Pf3,0xc2 }, + { ACOMISD, yxcmp, Pe, 0x2f }, + { ACOMISS, yxcmp, Pm, 0x2f }, + { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a }, + { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, }, + { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d }, + { ACVTPD2PS, yxm, Pe, 0x5a }, + { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d }, + { ACVTPS2PD, yxm, Pm, 0x5a }, + { ACVTSD2SL, yxcvfl, Pf2, 0x2d }, + { ACVTSD2SS, yxm, Pf2, 0x5a }, + { ACVTSL2SD, yxcvlf, Pf2, 0x2a }, + { ACVTSL2SS, yxcvlf, Pf3, 0x2a }, + { ACVTSS2SD, yxm, Pf3, 0x5a }, + { ACVTSS2SL, yxcvfl, Pf3, 0x2d }, + { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c }, + { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c }, + { ACVTTSD2SL, yxcvfl, Pf2, 0x2c }, + { ACVTTSS2SL, yxcvfl, Pf3, 0x2c }, + { ADIVPD, yxm, Pe, 0x5e }, + { ADIVPS, yxm, Pm, 0x5e }, + { ADIVSD, yxm, Pf2, 0x5e }, + { ADIVSS, yxm, Pf3, 0x5e }, + { AMASKMOVOU, yxr, Pe, 0xf7 }, + { AMAXPD, yxm, Pe, 0x5f }, + { AMAXPS, yxm, Pm, 0x5f }, + { AMAXSD, yxm, Pf2, 0x5f }, + { AMAXSS, yxm, Pf3, 0x5f }, + { AMINPD, yxm, Pe, 0x5d }, + { AMINPS, yxm, Pm, 0x5d }, + { AMINSD, yxm, Pf2, 0x5d }, + { AMINSS, yxm, Pf3, 0x5d }, + { AMOVAPD, yxmov, Pe, 0x28,0x29 }, + { AMOVAPS, yxmov, Pm, 0x28,0x29 }, + { AMOVO, yxmov, Pe, 0x6f,0x7f }, + { AMOVOU, yxmov, Pf3, 0x6f,0x7f }, + { AMOVHLPS, yxr, Pm, 0x12 }, + { AMOVHPD, yxmov, Pe, 0x16,0x17 }, + { AMOVHPS, yxmov, Pm, 0x16,0x17 }, + { AMOVLHPS, yxr, Pm, 0x16 }, + { AMOVLPD, yxmov, Pe, 0x12,0x13 }, + { AMOVLPS, yxmov, Pm, 0x12,0x13 }, + { AMOVMSKPD, yxrrl, Pq, 0x50 }, + { AMOVMSKPS, yxrrl, Pm, 0x50 }, + { AMOVNTO, yxr_ml, Pe, 0xe7 }, + { AMOVNTPD, yxr_ml, Pe, 0x2b }, + { AMOVNTPS, yxr_ml, Pm, 0x2b }, + { AMOVSD, yxmov, Pf2, 0x10,0x11 }, + { AMOVSS, yxmov, Pf3, 0x10,0x11 }, + { AMOVUPD, yxmov, Pe, 0x10,0x11 }, + { AMOVUPS, yxmov, Pm, 0x10,0x11 }, + { AMULPD, yxm, Pe, 0x59 }, + { AMULPS, yxm, Ym, 0x59 }, + { AMULSD, yxm, Pf2, 0x59 }, + { AMULSS, yxm, Pf3, 0x59 }, + { AORPD, yxm, Pq, 0x56 }, + { AORPS, yxm, Pm, 0x56 }, + { APADDQ, yxm, Pe, 0xd4 }, + { APMAXSW, yxm, Pe, 0xee }, + { APMAXUB, yxm, Pe, 0xde }, + { APMINSW, yxm, Pe, 0xea }, + { APMINUB, yxm, Pe, 0xda }, + { APSADBW, yxm, Pq, 0xf6 }, + { APSUBB, yxm, Pe, 0xf8 }, + { APSUBL, yxm, Pe, 0xfa }, + { APSUBQ, yxm, Pe, 0xfb }, + { APSUBSB, yxm, Pe, 0xe8 }, + { APSUBSW, yxm, Pe, 0xe9 }, + { APSUBUSB, yxm, Pe, 0xd8 }, + { APSUBUSW, yxm, Pe, 0xd9 }, + { APSUBW, yxm, Pe, 0xf9 }, + { APUNPCKHQDQ, yxm, Pe, 0x6d }, + { APUNPCKLQDQ, yxm, Pe, 0x6c }, + { ARCPPS, yxm, Pm, 0x53 }, + { ARCPSS, yxm, Pf3, 0x53 }, + { ARSQRTPS, yxm, Pm, 0x52 }, + { ARSQRTSS, yxm, Pf3, 0x52 }, + { ASQRTPD, yxm, Pe, 0x51 }, + { ASQRTPS, yxm, Pm, 0x51 }, + { ASQRTSD, yxm, Pf2, 0x51 }, + { ASQRTSS, yxm, Pf3, 0x51 }, + { ASUBPD, yxm, Pe, 0x5c }, + { ASUBPS, yxm, Pm, 0x5c }, + { ASUBSD, yxm, Pf2, 0x5c }, + { ASUBSS, yxm, Pf3, 0x5c }, + { AUCOMISD, yxcmp, Pe, 0x2e }, + { AUCOMISS, yxcmp, Pm, 0x2e }, + { AUNPCKHPD, yxm, Pe, 0x15 }, + { AUNPCKHPS, yxm, Pm, 0x15 }, + { AUNPCKLPD, yxm, Pe, 0x14 }, + { AUNPCKLPS, yxm, Pm, 0x14 }, + { AXORPD, yxm, Pe, 0x57 }, + { AXORPS, yxm, Pm, 0x57 }, + + { AUSEFIELD, ynop, Px, 0,0 }, + { ALOCALS }, + { ATYPE }, + 0 }; diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c index 9034fdf3a..14dd3e0dc 100644 --- a/src/cmd/8l/pass.c +++ b/src/cmd/8l/pass.c @@ -75,6 +75,7 @@ nofollow(int a) case ARET: case AIRETL: case AIRETW: + case AUNDEF: return 1; } return 0; @@ -184,20 +185,34 @@ loop: * recurse to follow one path. * continue loop on the other. */ - q = brchain(p->link); - if(q != P && q->mark) - if(a != ALOOP) { - p->as = relinv(a); - p->link = p->pcond; + if((q = brchain(p->pcond)) != P) p->pcond = q; + if((q = brchain(p->link)) != P) + p->link = q; + if(p->from.type == D_CONST) { + if(p->from.offset == 1) { + /* + * expect conditional jump to be taken. + * rewrite so that's the fall-through case. + */ + p->as = relinv(a); + q = p->link; + p->link = p->pcond; + p->pcond = q; + } + } else { + q = p->link; + if(q->mark) + if(a != ALOOP) { + p->as = relinv(a); + p->link = p->pcond; + p->pcond = q; + } } xfol(p->link, last); - q = brchain(p->pcond); - if(q->mark) { - p->pcond = q; + if(p->pcond->mark) return; - } - p = q; + p = p->pcond; goto loop; } p = p->link; @@ -315,7 +330,7 @@ patch(void) } else if(s) { if(debug['c']) Bprint(&bso, "%s calls %s\n", TNAME, s->name); - if((s->type&~SSUB) != STEXT) { + if((s->type&SMASK) != STEXT) { /* diag prints TNAME first */ diag("undefined: %s", s->name); s->type = STEXT; @@ -524,9 +539,9 @@ dostkoff(void) q = p; } - p = appendp(p); // save frame size in DX + p = appendp(p); // save frame size in DI p->as = AMOVL; - p->to.type = D_DX; + p->to.type = D_DI; p->from.type = D_CONST; // If we ask for more stack, we'll get a minimum of StackMin bytes. @@ -565,9 +580,47 @@ dostkoff(void) p->spadj = autoffset; if(q != P) q->pcond = p; + } else { + // zero-byte stack adjustment. + // Insert a fake non-zero adjustment so that stkcheck can + // recognize the end of the stack-splitting prolog. + p = appendp(p); + p->as = ANOP; + p->spadj = -PtrSize; + p = appendp(p); + p->as = ANOP; + p->spadj = PtrSize; } deltasp = autoffset; + if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) { + // 8l -Z means zero the stack frame on entry. + // This slows down function calls but can help avoid + // false positives in garbage collection. + p = appendp(p); + p->as = AMOVL; + p->from.type = D_SP; + p->to.type = D_DI; + + p = appendp(p); + p->as = AMOVL; + p->from.type = D_CONST; + p->from.offset = autoffset/4; + p->to.type = D_CX; + + p = appendp(p); + p->as = AMOVL; + p->from.type = D_CONST; + p->from.offset = 0; + p->to.type = D_AX; + + p = appendp(p); + p->as = AREP; + + p = appendp(p); + p->as = ASTOSL; + } + for(; p != P; p = p->link) { a = p->from.type; if(a == D_AUTO) diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c index 81c1d37eb..b828d8645 100644 --- a/src/cmd/8l/span.c +++ b/src/cmd/8l/span.c @@ -194,7 +194,7 @@ instinit(void) for(i=1; optab[i].as; i++) if(i != optab[i].as) { - diag("phase error in optab: %d", i); + diag("phase error in optab: at %A found %A", i, optab[i].as); errorexit(); } maxop = i; @@ -238,6 +238,16 @@ instinit(void) ycover[Yrl*Ymax + Yml] = 1; ycover[Ym*Ymax + Yml] = 1; + ycover[Yax*Ymax + Ymm] = 1; + ycover[Ycx*Ymax + Ymm] = 1; + ycover[Yrx*Ymax + Ymm] = 1; + ycover[Yrl*Ymax + Ymm] = 1; + ycover[Ym*Ymax + Ymm] = 1; + ycover[Ymr*Ymax + Ymm] = 1; + + ycover[Ym*Ymax + Yxm] = 1; + ycover[Yxr*Ymax + Yxm] = 1; + for(i=0; i<D_NONE; i++) { reg[i] = -1; if(i >= D_AL && i <= D_BH) @@ -246,6 +256,8 @@ instinit(void) reg[i] = (i-D_AX) & 7; if(i >= D_F0 && i <= D_F0+7) reg[i] = (i-D_F0) & 7; + if(i >= D_X0 && i <= D_X0+7) + reg[i] = (i-D_X0) & 7; } } @@ -333,6 +345,16 @@ oclass(Adr *a) case D_F0+7: return Yrf; + case D_X0+0: + case D_X0+1: + case D_X0+2: + case D_X0+3: + case D_X0+4: + case D_X0+5: + case D_X0+6: + case D_X0+7: + return Yxr; + case D_NONE: return Ynone; @@ -585,7 +607,7 @@ asmand(Adr *a, int r) asmidx(a->scale, a->index, t); goto putrelv; } - if(t >= D_AL && t <= D_F0+7) { + if(t >= D_AL && t <= D_F7 || t >= D_X0 && t <= D_X7) { if(v) goto bad; *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); @@ -772,19 +794,71 @@ uchar ymovtab[] = 0 }; +// byteswapreg returns a byte-addressable register (AX, BX, CX, DX) +// which is not referenced in a->type. +// If a is empty, it returns BX to account for MULB-like instructions +// that might use DX and AX. int -isax(Adr *a) +byteswapreg(Adr *a) { + int cana, canb, canc, cand; + + cana = canb = canc = cand = 1; switch(a->type) { + case D_NONE: + cana = cand = 0; + break; case D_AX: case D_AL: case D_AH: case D_INDIR+D_AX: - return 1; + cana = 0; + break; + case D_BX: + case D_BL: + case D_BH: + case D_INDIR+D_BX: + canb = 0; + break; + case D_CX: + case D_CL: + case D_CH: + case D_INDIR+D_CX: + canc = 0; + break; + case D_DX: + case D_DL: + case D_DH: + case D_INDIR+D_DX: + cand = 0; + break; + } + switch(a->index) { + case D_AX: + cana = 0; + break; + case D_BX: + canb = 0; + break; + case D_CX: + canc = 0; + break; + case D_DX: + cand = 0; + break; } - if(a->index == D_AX) - return 1; + if(cana) + return D_AX; + if(canb) + return D_BX; + if(canc) + return D_CX; + if(cand) + return D_DX; + + diag("impossible byte register"); + errorexit(); return 0; } @@ -827,13 +901,37 @@ subreg(Prog *p, int from, int to) print("%P\n", p); } +static int +mediaop(Optab *o, int op, int osize, int z) +{ + switch(op){ + case Pm: + case Pe: + case Pf2: + case Pf3: + if(osize != 1){ + if(op != Pm) + *andptr++ = op; + *andptr++ = Pm; + op = o->op[++z]; + break; + } + default: + if(andptr == and || andptr[-1] != Pm) + *andptr++ = Pm; + break; + } + *andptr++ = op; + return z; +} + void doasm(Prog *p) { Optab *o; Prog *q, pp; uchar *t; - int z, op, ft, tt; + int z, op, ft, tt, breg; int32 v, pre; Reloc rel, *r; Adr *a; @@ -873,6 +971,12 @@ found: *andptr++ = Pm; break; + case Pf2: /* xmm opcode escape */ + case Pf3: + *andptr++ = o->prefix; + *andptr++ = Pm; + break; + case Pm: /* opcode escape */ *andptr++ = Pm; break; @@ -904,6 +1008,17 @@ found: asmand(&p->from, reg[p->to.type]); break; + case Zm_r_xm: + mediaop(o, op, t[3], z); + asmand(&p->from, reg[p->to.type]); + break; + + case Zm_r_i_xm: + mediaop(o, op, t[3], z); + asmand(&p->from, reg[p->to.type]); + *andptr++ = p->to.offset; + break; + case Zaut_r: *andptr++ = 0x8d; /* leal */ if(p->from.type != D_ADDR) @@ -927,6 +1042,17 @@ found: asmand(&p->to, reg[p->from.type]); break; + case Zr_m_xm: + mediaop(o, op, t[3], z); + asmand(&p->to, reg[p->from.type]); + break; + + case Zr_m_i_xm: + mediaop(o, op, t[3], z); + asmand(&p->to, reg[p->from.type]); + *andptr++ = p->from.offset; + break; + case Zo_m: *andptr++ = op; asmand(&p->to, o->op[z+1]); @@ -1198,13 +1324,13 @@ bad: pp = *p; z = p->from.type; if(z >= D_BP && z <= D_DI) { - if(isax(&p->to)) { + if((breg = byteswapreg(&p->to)) != D_AX) { *andptr++ = 0x87; /* xchg lhs,bx */ - asmand(&p->from, reg[D_BX]); - subreg(&pp, z, D_BX); + asmand(&p->from, reg[breg]); + subreg(&pp, z, breg); doasm(&pp); *andptr++ = 0x87; /* xchg lhs,bx */ - asmand(&p->from, reg[D_BX]); + asmand(&p->from, reg[breg]); } else { *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ subreg(&pp, z, D_AX); @@ -1215,13 +1341,13 @@ bad: } z = p->to.type; if(z >= D_BP && z <= D_DI) { - if(isax(&p->from)) { + if((breg = byteswapreg(&p->from)) != D_AX) { *andptr++ = 0x87; /* xchg rhs,bx */ - asmand(&p->to, reg[D_BX]); - subreg(&pp, z, D_BX); + asmand(&p->to, reg[breg]); + subreg(&pp, z, breg); doasm(&pp); *andptr++ = 0x87; /* xchg rhs,bx */ - asmand(&p->to, reg[D_BX]); + asmand(&p->to, reg[breg]); } else { *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ subreg(&pp, z, D_AX); |