summaryrefslogtreecommitdiff
path: root/src/cmd/6l
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/6l')
-rw-r--r--src/cmd/6l/6.out.h34
-rw-r--r--src/cmd/6l/asm.c643
-rw-r--r--src/cmd/6l/doc.go4
-rw-r--r--src/cmd/6l/l.h35
-rw-r--r--src/cmd/6l/obj.c131
-rw-r--r--src/cmd/6l/optab.c81
-rw-r--r--src/cmd/6l/pass.c91
-rw-r--r--src/cmd/6l/span.c80
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);
+ }
}