diff options
Diffstat (limited to 'src/cmd/6l')
-rw-r--r-- | src/cmd/6l/6.out.h | 34 | ||||
-rw-r--r-- | src/cmd/6l/asm.c | 643 | ||||
-rw-r--r-- | src/cmd/6l/doc.go | 4 | ||||
-rw-r--r-- | src/cmd/6l/l.h | 35 | ||||
-rw-r--r-- | src/cmd/6l/obj.c | 131 | ||||
-rw-r--r-- | src/cmd/6l/optab.c | 81 | ||||
-rw-r--r-- | src/cmd/6l/pass.c | 91 | ||||
-rw-r--r-- | src/cmd/6l/span.c | 80 |
8 files changed, 446 insertions, 653 deletions
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h index 849915954..805b3fc6f 100644 --- a/src/cmd/6l/6.out.h +++ b/src/cmd/6l/6.out.h @@ -736,6 +736,30 @@ enum as ACRC32B, ACRC32Q, AIMUL3Q, + + APREFETCHT0, + APREFETCHT1, + APREFETCHT2, + APREFETCHNTA, + + AMOVQL, + ABSWAPL, + ABSWAPQ, + + AUNDEF, + + AAESENC, + AAESENCLAST, + AAESDEC, + AAESDECLAST, + AAESIMC, + AAESKEYGENASSIST, + + APSHUFD, + + AUSEFIELD, + ALOCALS, + ATYPE, ALAST }; @@ -794,6 +818,14 @@ enum D_X5, D_X6, D_X7, + D_X8, + D_X9, + D_X10, + D_X11, + D_X12, + D_X13, + D_X14, + D_X15, D_CS = 68, D_SS, @@ -854,7 +886,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/6l/asm.c b/src/cmd/6l/asm.c index ee31a05cd..5fb75ba4d 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -74,34 +74,6 @@ datoff(vlong addr) return 0; } -enum { - ElfStrEmpty, - ElfStrInterp, - ElfStrHash, - ElfStrGot, - ElfStrGotPlt, - ElfStrDynamic, - ElfStrDynsym, - ElfStrDynstr, - ElfStrRela, - ElfStrText, - ElfStrData, - ElfStrBss, - ElfStrShstrtab, - ElfStrSymtab, - ElfStrStrtab, - ElfStrRelaPlt, - ElfStrPlt, - ElfStrGnuVersion, - ElfStrGnuVersionR, - ElfStrNoteNetbsdIdent, - ElfStrNoPtrData, - ElfStrNoPtrBss, - NElfStr -}; - -vlong elfstr[NElfStr]; - static int needlib(char *name) { @@ -127,6 +99,20 @@ int nelfsym = 1; static void addpltsym(Sym*); static void addgotsym(Sym*); +Sym * +lookuprel(void) +{ + return lookup(".rela", 0); +} + +void +adddynrela(Sym *rela, Sym *s, Reloc *r) +{ + addaddrplus(rela, s, r->off); + adduint64(rela, R_X86_64_RELATIVE); + addaddrplus(rela, r->sym, r->add); // Addend +} + void adddynrel(Sym *s, Reloc *r) { @@ -299,6 +285,37 @@ adddynrel(Sym *s, Reloc *r) } int +elfreloc1(Reloc *r, vlong off, int32 elfsym, vlong add) +{ + VPUT(off); + + switch(r->type) { + default: + return -1; + + case D_ADDR: + if(r->siz == 4) + VPUT(R_X86_64_32 | (uint64)elfsym<<32); + else if(r->siz == 8) + VPUT(R_X86_64_64 | (uint64)elfsym<<32); + else + return -1; + break; + + case D_PCREL: + if(r->siz == 4) + VPUT(R_X86_64_PC32 | (uint64)elfsym<<32); + else + return -1; + add -= r->siz; + break; + } + + VPUT(add); + return 0; +} + +int archreloc(Reloc *r, Sym *s, vlong *val) { USED(r); @@ -307,7 +324,7 @@ archreloc(Reloc *r, Sym *s, vlong *val) return -1; } -static void +void elfsetupplt(void) { Sym *plt, *got; @@ -434,6 +451,7 @@ adddynsym(Sym *s) Sym *d, *str; int t; char *name; + vlong off; if(s->dynid >= 0) return; @@ -452,7 +470,7 @@ adddynsym(Sym *s) adduint32(d, addstring(lookup(".dynstr", 0), name)); /* 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; @@ -490,7 +508,7 @@ adddynsym(Sym *s) addaddr(d, s); /* size of object */ - adduint64(d, 0); + adduint64(d, s->size); if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) { elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, @@ -502,35 +520,51 @@ adddynsym(Sym *s) name = s->dynimpname; if(name == nil) name = s->name; - s->dynid = d->size/16; + if(d->size == 0 && ndynexp > 0) { // pre-allocate for dynexps + symgrow(d, ndynexp*16); + } + if(s->dynid <= -100) { // pre-allocated, see cmd/ld/go.c:^sortdynexp() + s->dynid = -s->dynid-100; + off = s->dynid*16; + } else { + off = d->size; + s->dynid = off/16; + } // 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); if(s->type == SDYNIMPORT) { - adduint8(d, 0x01); // type - N_EXT - external symbol - adduint8(d, 0); // section + setuint8(d, off, 0x01); // type - N_EXT - external symbol + off++; + setuint8(d, off, 0); // section + off++; } else { - adduint8(d, 0x0f); + setuint8(d, off, 0x0f); + off++; switch(s->type) { default: case STEXT: - adduint8(d, 1); + setuint8(d, off, 1); break; case SDATA: - adduint8(d, 2); + setuint8(d, off, 2); break; case SBSS: - adduint8(d, 4); + setuint8(d, off, 4); break; } + off++; } - adduint16(d, 0); // desc + setuint16(d, off, 0); // desc + off += 2; if(s->type == SDYNIMPORT) - adduint64(d, 0); // value + setuint64(d, off, 0); // value else - addaddr(d, s); + setaddr(d, off, s); + off += 8; } else if(HEADTYPE != Hwindows) { diag("adddynsym: unsupported binary format"); } @@ -557,181 +591,30 @@ adddynlib(char *lib) } void -doelf(void) -{ - Sym *s, *shstrtab, *dynstr; - - if(HEADTYPE != Hlinux && HEADTYPE != Hfreebsd && HEADTYPE != Hopenbsd && HEADTYPE != Hnetbsd) - 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[ElfStrRela] = addstring(shstrtab, ".rela"); - elfstr[ElfStrRelaPlt] = addstring(shstrtab, ".rela.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 += ELF64SYMSIZE; - - /* 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(".rela", 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; - - s = lookup(".got.plt", 0); - s->reachable = 1; - s->type = SELFSECT; // writable - - s = lookup(".plt", 0); - s->reachable = 1; - s->type = SELFROSECT; - - elfsetupplt(); - - s = lookup(".rela.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; - - /* 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, ELF64SYMSIZE); - elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0)); - elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0)); - elfwritedynentsym(s, DT_RELA, lookup(".rela", 0)); - elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0)); - elfwritedynent(s, DT_RELAENT, ELF64RELASIZE); - if(rpath) - elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath)); - - elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0)); - elfwritedynent(s, DT_PLTREL, DT_RELA); - elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0)); - elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0)); - - elfwritedynent(s, DT_DEBUG, 0); - - // Do not write DT_NULL. elfdynhash will finish it. - } -} - -void -shsym(ElfShdr *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(ElfPhdr *ph, ElfShdr *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 magic; - int a, dynsym; - vlong vl, startva, symo, dwarfoff, machlink, resoff; - ElfEhdr *eh; - ElfPhdr *ph, *pph; - ElfShdr *sh; + int i; + vlong vl, symo, dwarfoff, machlink; Section *sect; - int o; + Sym *sym; if(debug['v']) Bprint(&bso, "%5.2f asmb\n", cputime()); Bflush(&bso); - elftextsh = 0; - if(debug['v']) Bprint(&bso, "%5.2f codeblk\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); @@ -763,6 +646,7 @@ asmb(void) default: diag("unknown header type %d", HEADTYPE); case Hplan9x32: + case Hplan9x64: case Helf: break; case Hdarwin: @@ -773,16 +657,6 @@ asmb(void) case Hnetbsd: case Hopenbsd: debug['8'] = 1; /* 64-bit addresses */ - /* 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; break; case Hwindows: break; @@ -798,7 +672,7 @@ asmb(void) Bflush(&bso); switch(HEADTYPE) { default: - case Hplan9x32: + case Hplan9x64: case Helf: debug['s'] = 1; symo = HEADR+segtext.len+segdata.filelen; @@ -831,6 +705,22 @@ asmb(void) Bprint(&bso, "%5.2f dwarf\n", cputime()); dwarfemitdebugsections(); + + if(isobj) + elfemitreloc(); + } + break; + case Hplan9x64: + asmplan9sym(); + cflush(); + + sym = lookup("pclntab", 0); + if(sym != nil) { + lcsize = sym->np; + for(i=0; i < lcsize; i++) + cput(sym->p[i]); + + cflush(); } break; case Hwindows: @@ -848,7 +738,7 @@ asmb(void) cseek(0L); switch(HEADTYPE) { default: - case Hplan9x32: /* plan9 */ + case Hplan9x64: /* plan9 */ magic = 4*26*26+7; magic |= 0x00008000; /* fat header */ lputb(magic); /* magic */ @@ -862,7 +752,7 @@ asmb(void) lputb(lcsize); /* line offsets */ vputb(vl); /* va of entry */ break; - case Hplan9x64: /* plan9 */ + case Hplan9x32: /* plan9 */ magic = 4*26*26+7; lputb(magic); /* magic */ lputb(segtext.filelen); /* sizes */ @@ -880,257 +770,7 @@ asmb(void) case Hfreebsd: case Hnetbsd: case Hopenbsd: - /* elf amd-64 */ - - 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); - } - - 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 = 8; - sh->addralign = 8; - shsym(sh, lookup(".got", 0)); - - sh = newElfShdr(elfstr[ElfStrGotPlt]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = 8; - sh->addralign = 8; - shsym(sh, lookup(".got.plt", 0)); - - dynsym = eh->shnum; - sh = newElfShdr(elfstr[ElfStrDynsym]); - sh->type = SHT_DYNSYM; - sh->flags = SHF_ALLOC; - sh->entsize = ELF64SYMSIZE; - sh->addralign = 8; - 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 = 8; - sh->info = elfverneed; - sh->link = dynsym+1; // dynstr - shsym(sh, lookup(".gnu.version_r", 0)); - } - - sh = newElfShdr(elfstr[ElfStrRelaPlt]); - sh->type = SHT_RELA; - sh->flags = SHF_ALLOC; - sh->entsize = ELF64RELASIZE; - sh->addralign = 8; - sh->link = dynsym; - sh->info = eh->shnum; // .plt - shsym(sh, lookup(".rela.plt", 0)); - - sh = newElfShdr(elfstr[ElfStrPlt]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC+SHF_EXECINSTR; - sh->entsize = 16; - sh->addralign = 4; - shsym(sh, lookup(".plt", 0)); - - sh = newElfShdr(elfstr[ElfStrHash]); - sh->type = SHT_HASH; - sh->flags = SHF_ALLOC; - sh->entsize = 4; - sh->addralign = 8; - sh->link = dynsym; - shsym(sh, lookup(".hash", 0)); - - sh = newElfShdr(elfstr[ElfStrRela]); - sh->type = SHT_RELA; - sh->flags = SHF_ALLOC; - sh->entsize = ELF64RELASIZE; - sh->addralign = 8; - sh->link = dynsym; - shsym(sh, lookup(".rela", 0)); - - /* sh and PT_DYNAMIC for .dynamic section */ - sh = newElfShdr(elfstr[ElfStrDynamic]); - sh->type = SHT_DYNAMIC; - sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = 16; - sh->addralign = 8; - 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 = 8; - } - } - - ph = newElfPhdr(); - ph->type = PT_GNU_STACK; - ph->flags = PF_W+PF_R; - ph->align = 8; - - 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 = 8; - sh->entsize = 24; - 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'; - if(HEADTYPE == Hfreebsd) - eh->ident[EI_OSABI] = ELFOSABI_FREEBSD; - else if(HEADTYPE == Hnetbsd) - eh->ident[EI_OSABI] = ELFOSABI_NETBSD; - else if(HEADTYPE == Hopenbsd) - eh->ident[EI_OSABI] = ELFOSABI_OPENBSD; - eh->ident[EI_CLASS] = ELFCLASS64; - eh->ident[EI_DATA] = ELFDATA2LSB; - eh->ident[EI_VERSION] = EV_CURRENT; - - eh->type = ET_EXEC; - eh->machine = EM_X86_64; - eh->version = EV_CURRENT; - eh->entry = entryvalue(); - - 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); + asmbelf(symo); break; case Hwindows: asmbpe(); @@ -1153,78 +793,3 @@ rnd(vlong v, vlong r) v -= c; return v; } - -void -genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) -{ - Auto *a; - Sym *s; - - s = lookup("etext", 0); - if(s->type == STEXT) - put(s, s->name, 'T', s->value, s->size, s->version, 0); - - for(s=allsym; s!=S; s=s->allsym) { - if(s->hide) - continue; - switch(s->type&~SSUB) { - case SCONST: - case SRODATA: - case SSYMTAB: - case SPCLNTAB: - case SDATA: - case SNOPTRDATA: - case SELFROSECT: - case SMACHOGOT: - case STYPE: - case SSTRING: - case SGOSTRING: - case SWINDOWS: - 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; - 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', 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+8, 0, 0, 0); - - for(a=s->autom; a; a=a->link) - if(a->type == D_AUTO) - put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype); - else - if(a->type == D_PARAM) - put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype); - } - if(debug['v'] || debug['n']) - Bprint(&bso, "symsize = %ud\n", symsize); - Bflush(&bso); -} diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go index 4d94b209b..6287dd9be 100644 --- a/src/cmd/6l/doc.go +++ b/src/cmd/6l/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 + /* 6l is the linker for the x86-64. @@ -10,4 +12,4 @@ The $GOARCH for these tools is amd64. The flags are documented in ../ld/doc.go. */ -package documentation +package main diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index 5f62239a1..ffb8a4552 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -40,7 +40,26 @@ enum { thechar = '6', - PtrSize = 8 + PtrSize = 8, + IntSize = 8, + + // Loop alignment constants: + // want to align loop entry to LoopAlign-byte boundary, + // and willing to insert at most MaxLoopPad bytes of NOP to do so. + // We define a loop entry as the target of a backward jump. + // + // gcc uses MaxLoopPad = 10 for its 'generic x86-64' config, + // and it aligns all jump targets, not just backward jump targets. + // + // As of 6/1/2012, the effect of setting MaxLoopPad = 10 here + // is very slight but negative, so the alignment is disabled by + // setting MaxLoopPad = 0. The code is here for reference and + // for future experiments. + // + LoopAlign = 16, + MaxLoopPad = 0, + + FuncAlign = 16 }; #define P ((Prog*)0) @@ -134,11 +153,16 @@ 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 SSUB list Sym* outer; // container of sub + Sym* reachparent; + Sym* queue; vlong value; vlong size; Sym* gotype; @@ -146,6 +170,7 @@ struct Sym char* dynimpname; char* dynimplib; char* dynimpvers; + struct Section* sect; // STEXT Auto* autom; @@ -158,6 +183,7 @@ struct Sym Reloc* r; int32 nr; int32 maxr; + int rel_ro; }; struct Optab { @@ -294,9 +320,10 @@ enum EXTERN int32 HEADR; EXTERN int32 HEADTYPE; EXTERN int32 INITRND; -EXTERN vlong INITTEXT; -EXTERN vlong INITDAT; +EXTERN int64 INITTEXT; +EXTERN int64 INITDAT; EXTERN char* INITENTRY; /* entry point */ +EXTERN char* LIBINITENTRY; /* shared library entry point */ EXTERN char* pcstr; EXTERN Auto* curauto; EXTERN Auto* curhist; @@ -304,7 +331,7 @@ EXTERN Prog* curp; EXTERN Sym* cursym; EXTERN Sym* datap; EXTERN vlong elfdatsize; -EXTERN char debug[128]; +EXTERN int debug[128]; EXTERN char literal[32]; EXTERN Sym* textp; EXTERN Sym* etextp; diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index 692cab7b8..10e4a9860 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -58,8 +58,8 @@ Header headers[] = { }; /* - * -Hplan9x32 -T4136 -R4096 is plan9 64-bit format - * -Hplan9 -T4128 -R4096 is plan9 32-bit format + * -Hplan9x32 -T4128 -R4096 is plan9 32-bit format + * -Hplan9 -T0x200028 -R0x200000 is plan9 64-bit format * -Helf -T0x80110000 -R4096 is ELF32 * -Hdarwin -Tx -Rx is apple MH-exec * -Hlinux -Tx -Rx is linux elf-exec @@ -67,23 +67,11 @@ Header headers[] = { * -Hnetbsd -Tx -Rx is NetBSD elf-exec * -Hopenbsd -Tx -Rx is OpenBSD elf-exec * -Hwindows -Tx -Rx is MS Windows PE32+ - * - * options used: 189BLQSWabcjlnpsvz */ void -usage(void) -{ - fprint(2, "usage: 6l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.6\n"); - exits("usage"); -} - -void main(int argc, char *argv[]) { - int c; - char *name, *val; - Binit(&bso, 1, OWRITE); listinit(); memset(debug, 0, sizeof(debug)); @@ -94,52 +82,46 @@ 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']); + flagcount("8", "assume 64-bit addresses", &debug['8']); + flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); + flagint64("D", "addr: data address", &INITDAT); + flagstr("E", "sym: entry symbol", &INITENTRY); + 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']); + flagint64("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); + 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(); @@ -149,6 +131,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 = "6.out.exe"; @@ -163,7 +154,7 @@ main(int argc, char *argv[]) diag("unknown -H option"); errorexit(); case Hplan9x32: /* plan 9 */ - HEADR = 32L+8L; + HEADR = 32L; if(INITTEXT == -1) INITTEXT = 4096+HEADR; if(INITDAT == -1) @@ -172,13 +163,13 @@ main(int argc, char *argv[]) INITRND = 4096; break; case Hplan9x64: /* plan 9 */ - HEADR = 32L; + HEADR = 32L + 8L; if(INITTEXT == -1) - INITTEXT = 4096+32; + INITTEXT = 0x200000+HEADR; if(INITDAT == -1) INITDAT = 0; if(INITRND == -1) - INITRND = 4096; + INITRND = 0x200000; break; case Helf: /* elf32 executable */ HEADR = rnd(52L+3*32L, 16); @@ -506,8 +497,6 @@ loop: p->line = Bget4(f); p->back = 2; p->mode = mode; - p->ft = 0; - p->tt = 0; zaddr(pn, f, &p->from, h); fromgotype = adrgotype; zaddr(pn, f, &p->to, h); @@ -597,6 +586,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) { @@ -640,6 +638,7 @@ loop: } s->type = STEXT; s->value = pc; + s->args = p->to.offset >> 32; lastp = p; p->pc = pc++; goto loop; @@ -677,7 +676,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; } @@ -711,7 +710,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/6l/optab.c b/src/cmd/6l/optab.c index 5746ded19..a163e6faa 100644 --- a/src/cmd/6l/optab.c +++ b/src/cmd/6l/optab.c @@ -269,7 +269,7 @@ uchar yimul[] = }; uchar yimul3[] = { - Yml, Yrl, Zibm_r, 1, + Yml, Yrl, Zibm_r, 2, 0 }; uchar ybyte[] = @@ -302,6 +302,11 @@ uchar ypopl[] = Ynone, Ym, Zo_m, 2, 0 }; +uchar ybswap[] = +{ + Ynone, Yrl, Z_rp, 2, + 0, +}; uchar yscond[] = { Ynone, Ymb, Zo_m, 2, @@ -309,7 +314,9 @@ uchar yscond[] = }; uchar yjcond[] = { - Ynone, Ybr, Zbr, 1, + Ynone, Ybr, Zbr, 0, + Yi0, Ybr, Zbr, 0, + Yi1, Ybr, Zbr, 1, 0 }; uchar yloop[] = @@ -319,7 +326,8 @@ uchar yloop[] = }; uchar ycall[] = { - Ynone, Yml, Zo_m64, 2, + Ynone, Yml, Zo_m64, 0, + Yrx, Yrx, Zo_m64, 2, Ynone, Ybr, Zcall, 1, 0 }; @@ -511,17 +519,17 @@ uchar ymrxr[] = }; uchar ymshuf[] = { - Ymm, Ymr, Zibm_r, 1, + Ymm, Ymr, Zibm_r, 2, 0 }; uchar yxshuf[] = { - Yxm, Yxr, Zibm_r, 1, + Yxm, Yxr, Zibm_r, 2, 0 }; uchar yextrw[] = { - Yxr, Yrl, Zibm_r, 1, + Yxr, Yrl, Zibm_r, 2, 0 }; uchar ypsdq[] = @@ -539,6 +547,21 @@ uchar ycrc32l[] = { Yml, Yrl, Zlitm_r, 0, }; +uchar yprefetch[] = +{ + Ym, Ynone, Zm_o, 2, + 0, +}; +uchar yaes[] = +{ + Yxm, Yxr, Zlitm_r, 2, + 0 +}; +uchar yaes2[] = +{ + Yxm, Yxr, Zibm_r, 2, + 0 +}; /* * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32, @@ -636,6 +659,8 @@ Optab optab[] = { ABSRL, yml_rl, Pm, 0xbd }, { ABSRQ, yml_rl, Pw, 0x0f,0xbd }, { ABSRW, yml_rl, Pq, 0xbd }, + { ABSWAPL, ybswap, Px, 0x0f,0xc8 }, + { ABSWAPQ, ybswap, Pw, 0x0f,0xc8 }, { ABTCL, ybtl, Pm, 0xba,(07),0xbb }, { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb }, { ABTCW, ybtl, Pq, 0xba,(07),0xbb }, @@ -777,7 +802,7 @@ Optab optab[] = { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf }, { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf }, { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf }, - { AIMUL3Q, yimul3, Pw, 0x6b }, + { AIMUL3Q, yimul3, Pw, 0x6b,(00) }, { AINB, yin, Pb, 0xe4,0xec }, { AINCB, yincb, Pb, 0xfe,(00) }, { AINCL, yincl, Px, 0xff,(00) }, @@ -936,7 +961,7 @@ Optab optab[] = { APCMPGTB, ymm, Py, 0x64,Pe,0x64 }, { APCMPGTL, ymm, Py, 0x66,Pe,0x66 }, { APCMPGTW, ymm, Py, 0x65,Pe,0x65 }, - { APEXTRW, yextrw, Pq, 0xc5 }, + { APEXTRW, yextrw, Pq, 0xc5,(00) }, { APF2IL, ymfp, Px, 0x1d }, { APF2IW, ymfp, Px, 0x1c }, { API2FL, ymfp, Px, 0x0d }, @@ -957,7 +982,7 @@ Optab optab[] = { APFRSQRT, ymfp, Px, 0x97 }, { APFSUB, ymfp, Px, 0x9a }, { APFSUBR, ymfp, Px, 0xaa }, - { APINSRW, yextrw, Pq, 0xc4 }, + { APINSRW, yextrw, Pq, 0xc4,(00) }, { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 }, { APMAXSW, yxm, Pe, 0xee }, { APMAXUB, yxm, Pe, 0xde }, @@ -979,10 +1004,10 @@ Optab optab[] = { APOPW, ypopl, Pe, 0x58,0x8f,(00) }, { APOR, ymm, Py, 0xeb,Pe,0xeb }, { APSADBW, yxm, Pq, 0xf6 }, - { APSHUFHW, yxshuf, Pf3, 0x70 }, - { APSHUFL, yxshuf, Pq, 0x70 }, - { APSHUFLW, yxshuf, Pf2, 0x70 }, - { APSHUFW, ymshuf, Pm, 0x70 }, + { APSHUFHW, yxshuf, Pf3, 0x70,(00) }, + { APSHUFL, yxshuf, Pq, 0x70,(00) }, + { APSHUFLW, yxshuf, Pf2, 0x70,(00) }, + { APSHUFW, ymshuf, Pm, 0x70,(00) }, { APSLLO, ypsdq, Pq, 0x73,(07) }, { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) }, { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06) }, @@ -1087,8 +1112,8 @@ Optab optab[] = { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, - { ASHUFPD, yxshuf, Pq, 0xc6 }, - { ASHUFPS, yxshuf, Pm, 0xc6 }, + { ASHUFPD, yxshuf, Pq, 0xc6,(00) }, + { ASHUFPS, yxshuf, Pm, 0xc6,(00) }, { ASQRTPD, yxm, Pe, 0x51 }, { ASQRTPS, yxm, Pm, 0x51 }, { ASQRTSD, yxm, Pf2, 0x51 }, @@ -1270,8 +1295,30 @@ Optab optab[] = { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 }, { AXADDW, yrl_ml, Pe, 0x0f,0xc1 }, - { ACRC32B, ycrc32l,Px, 0xf2,0x0f,0x38,0xf0,0}, - { ACRC32Q, ycrc32l,Pw, 0xf2,0x0f,0x38,0xf1,0}, + { ACRC32B, ycrc32l,Px, 0xf2,0x0f,0x38,0xf0,0 }, + { ACRC32Q, ycrc32l,Pw, 0xf2,0x0f,0x38,0xf1,0 }, + + { APREFETCHT0, yprefetch, Pm, 0x18,(01) }, + { APREFETCHT1, yprefetch, Pm, 0x18,(02) }, + { APREFETCHT2, yprefetch, Pm, 0x18,(03) }, + { APREFETCHNTA, yprefetch, Pm, 0x18,(00) }, + + { AMOVQL, yrl_ml, Px, 0x89 }, + + { AUNDEF, ynone, Px, 0x0f, 0x0b }, + + { AAESENC, yaes, Pq, 0x38,0xdc,(0) }, + { AAESENCLAST, yaes, Pq, 0x38,0xdd,(0) }, + { AAESDEC, yaes, Pq, 0x38,0xde,(0) }, + { AAESDECLAST, yaes, Pq, 0x38,0xdf,(0) }, + { AAESIMC, yaes, Pq, 0x38,0xdb,(0) }, + { AAESKEYGENASSIST, yaes2, Pq, 0x3a,0xdf,(0) }, + + { APSHUFD, yaes2, Pq, 0x70,(0) }, + + { AUSEFIELD, ynop, Px, 0,0 }, + { ALOCALS }, + { ATYPE }, { AEND }, 0 diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c index c9b477627..0054b329f 100644 --- a/src/cmd/6l/pass.c +++ b/src/cmd/6l/pass.c @@ -79,6 +79,7 @@ nofollow(int a) case ARETFL: case ARETFQ: case ARETFW: + case AUNDEF: return 1; } return 0; @@ -192,20 +193,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; @@ -295,7 +310,8 @@ patch(void) } } if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd - || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd) { + || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd + || HEADTYPE == Hplan9x64) { // ELF uses FS instead of GS. if(p->from.type == D_INDIR+D_GS) p->from.type = D_INDIR+D_FS; @@ -307,7 +323,7 @@ patch(void) 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; @@ -405,7 +421,7 @@ dostkoff(void) for(cursym = textp; cursym != nil; cursym = cursym->next) { if(cursym->text == nil || cursym->text->link == nil) - continue; + continue; p = cursym->text; parsetextconst(p->to.offset); @@ -413,6 +429,14 @@ dostkoff(void) if(autoffset < 0) autoffset = 0; + if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) { + for(q = p; q != P; q = q->link) + if(q->as == ACALL) + goto noleaf; + p->from.scale |= NOSPLIT; + noleaf:; + } + q = P; if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) diag("nosplit func likely to overflow stack"); @@ -421,7 +445,8 @@ dostkoff(void) p = appendp(p); // load g into CX p->as = AMOVQ; if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd - || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd) // ELF uses FS + || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd + || HEADTYPE == Hplan9x64) // ELF uses FS p->from.type = D_INDIR+D_FS; else p->from.type = D_INDIR+D_GS; @@ -579,6 +604,16 @@ 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; @@ -618,6 +653,34 @@ dostkoff(void) q1->pcond = p; } + if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) { + // 6l -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 = AMOVQ; + p->from.type = D_SP; + p->to.type = D_DI; + + p = appendp(p); + p->as = AMOVQ; + p->from.type = D_CONST; + p->from.offset = autoffset/8; + p->to.type = D_CX; + + p = appendp(p); + p->as = AMOVQ; + 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 = ASTOSQ; + } + for(; p != P; p = p->link) { pcsize = p->mode/8; a = p->from.type; diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c index 28eb38f40..283a0e349 100644 --- a/src/cmd/6l/span.c +++ b/src/cmd/6l/span.c @@ -37,6 +37,37 @@ static int rexflag; static int asmode; static vlong vaddr(Adr*, Reloc*); +// single-instruction no-ops of various lengths. +// constructed by hand and disassembled with gdb to verify. +// see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion. +static uchar nop[][16] = { + {0x90}, + {0x66, 0x90}, + {0x0F, 0x1F, 0x00}, + {0x0F, 0x1F, 0x40, 0x00}, + {0x0F, 0x1F, 0x44, 0x00, 0x00}, + {0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00}, + {0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00}, + {0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, +}; + +static void +fillnop(uchar *p, int n) +{ + int m; + + while(n > 0) { + m = n; + if(m > nelem(nop)) + m = nelem(nop); + memmove(p, nop[m-1], m); + p += m; + n -= m; + } +} + void span1(Sym *s) { @@ -52,8 +83,10 @@ span1(Sym *s) for(p = s->text; p != P; p = p->link) { p->back = 2; // use short branches first time through - if((q = p->pcond) != P && (q->back & 2)) + if((q = p->pcond) != P && (q->back & 2)) { p->back |= 1; // backward jump + q->back |= 4; // loop head + } if(p->as == AADJSP) { p->to.type = D_SP; @@ -78,6 +111,16 @@ span1(Sym *s) s->np = 0; c = 0; for(p = s->text; p != P; p = p->link) { + if((p->back & 4) && (c&(LoopAlign-1)) != 0) { + // pad with NOPs + v = -c&(LoopAlign-1); + if(v <= MaxLoopPad) { + symgrow(s, c+v); + fillnop(s->p+c, v); + c += v; + } + } + p->pc = c; // process forward jumps to p @@ -329,7 +372,10 @@ oclass(Adr *a) switch(a->index) { case D_EXTERN: case D_STATIC: - return Yi32; /* TO DO: Yi64 */ + if(flag_shared) + return Yiauto; + else + return Yi32; /* TO DO: Yi64 */ case D_AUTO: case D_PARAM: return Yiauto; @@ -688,7 +734,10 @@ vaddr(Adr *a, Reloc *r) diag("need reloc for %D", a); errorexit(); } - r->type = D_ADDR; + if(flag_shared) + r->type = D_PCREL; + else + r->type = D_ADDR; r->siz = 4; // TODO: 8 for external symbols r->off = -1; // caller must fill in r->sym = s; @@ -717,6 +766,8 @@ asmandsz(Adr *a, int r, int rex, int m64) goto bad; case D_STATIC: case D_EXTERN: + if(flag_shared) + goto bad; t = D_NONE; v = vaddr(a, &rel); break; @@ -777,7 +828,7 @@ asmandsz(Adr *a, int r, int rex, int m64) rexflag |= (regrex[t] & Rxb) | rex; if(t == D_NONE || (D_CS <= t && t <= D_GS)) { - if(asmode != 64){ + if(flag_shared && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || asmode != 64) { *andptr++ = (0 << 6) | (5 << 0) | (r << 3); goto putrelv; } @@ -1204,7 +1255,8 @@ found: break; case Zibm_r: - *andptr++ = op; + while ((op = o->op[z++]) != 0) + *andptr++ = op; asmand(&p->from, &p->to); *andptr++ = p->to.offset; break; @@ -1574,7 +1626,9 @@ bad: pp = *p; z = p->from.type; if(z >= D_BP && z <= D_DI) { - if(isax(&p->to)) { + if(isax(&p->to) || p->to.type == D_NONE) { + // We certainly don't want to exchange + // with AX if the op is MUL or DIV. *andptr++ = 0x87; /* xchg lhs,bx */ asmando(&p->from, reg[D_BX]); subreg(&pp, z, D_BX); @@ -1730,13 +1784,17 @@ asmins(Prog *p) if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26) break; } - for(r=cursym->r+cursym->nr; r-- > cursym->r; ) { - if(r->off < p->pc) - break; - r->off++; - } memmove(and+np+1, and+np, n-np); and[np] = 0x40 | rexflag; andptr++; } + n = andptr - and; + for(r=cursym->r+cursym->nr; r-- > cursym->r; ) { + if(r->off < p->pc) + break; + if(rexflag) + r->off++; + if(r->type == D_PCREL) + r->add -= p->pc + n - (r->off + r->siz); + } } |