From: Russ Cox Date: Sun, 6 Jan 2013 19:32:45 +0000 (-0500) Subject: cmd/ld: move symtab, ELF generation to portable code X-Git-Tag: go1.1rc2~1478 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=d37c572ad54921319653a4abdd749221f7779bb5;p=gostls13.git cmd/ld: move symtab, ELF generation to portable code More cleanup in preparation for fixing issue 4069. This CL replaces the three nearly identical copies of the asmb ELF code with a single asmbelf function in elf.c. In addition to the ELF code movement, remove the elfstr array in favor of a simpler lookup, and identify sections by name throughout instead of computing fragile indices. The CL also replaces the three nearly identical copies of the genasmsym code with a single genasmsym function in lib.c. The ARM linker still compiles and generates binaries, but I haven't tested the binaries. They may not work. R=ken2 CC=golang-dev https://golang.org/cl/7062047 --- diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c index 1937d899ab..7c45268117 100644 --- a/src/cmd/5l/asm.c +++ b/src/cmd/5l/asm.c @@ -39,6 +39,8 @@ static Prog *PP; char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI char freebsddynld[] = "/usr/libexec/ld-elf.so.1"; +char openbsddynld[] = "XXX"; +char netbsddynld[] = "XXX"; int32 entryvalue(void) @@ -57,36 +59,6 @@ entryvalue(void) return s->value; } -enum { - ElfStrEmpty, - ElfStrInterp, - ElfStrHash, - ElfStrGot, - ElfStrGotPlt, - ElfStrDynamic, - ElfStrDynsym, - ElfStrDynstr, - ElfStrRel, - ElfStrText, - ElfStrData, - ElfStrBss, - ElfStrSymtab, - ElfStrStrtab, - ElfStrShstrtab, - ElfStrRelPlt, - ElfStrPlt, - ElfStrGnuVersion, - ElfStrGnuVersionR, - ElfStrNoteNetbsdIdent, - ElfStrNoteOpenbsdIdent, - ElfStrNoteBuildInfo, - ElfStrNoPtrData, - ElfStrNoPtrBss, - NElfStr -}; - -vlong elfstr[NElfStr]; - static int needlib(char *name) { @@ -254,7 +226,7 @@ adddynrel(Sym *s, Reloc *r) diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); } -static void +void elfsetupplt(void) { Sym *plt, *got; @@ -501,138 +473,6 @@ 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"); - if(HEADTYPE == Hopenbsd) - elfstr[ElfStrNoteOpenbsdIdent] = addstring(shstrtab, ".note.openbsd.ident"); - if(buildinfolen > 0) - elfstr[ElfStrNoteBuildInfo] = addstring(shstrtab, ".note.gnu.build-id"); - addstring(shstrtab, ".rodata"); - addstring(shstrtab, ".typelink"); - addstring(shstrtab, ".gcdata"); - addstring(shstrtab, ".gcbss"); - 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); - // elfdynhash will finish it - } -} - vlong datoff(vlong addr) { @@ -644,44 +484,20 @@ datoff(vlong addr) return 0; } -void -shsym(Elf64_Shdr *sh, Sym *s) -{ - vlong addr; - addr = symaddr(s); - if(sh->flags&SHF_ALLOC) - sh->addr = addr; - sh->off = datoff(addr); - sh->size = s->size; -} - -void -phsh(Elf64_Phdr *ph, Elf64_Shdr *sh) -{ - ph->vaddr = sh->addr; - ph->paddr = ph->vaddr; - ph->off = sh->off; - ph->filesz = sh->size; - ph->memsz = sh->size; - ph->align = sh->addralign; -} - void asmb(void) { int32 t; - int a, dynsym; - uint32 fo, symo, startva, resoff; - ElfEhdr *eh; - ElfPhdr *ph, *pph, *pnote; - ElfShdr *sh; + uint32 symo; Section *sect; - int o; 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); @@ -699,21 +515,6 @@ asmb(void) cseek(segdata.fileoff); datblk(segdata.vaddr, segdata.filelen); - if(iself) { - /* index of elf text section; needed by asmelfsym, double-checked below */ - /* !debug['d'] causes extra sections before the .text section */ - elftextsh = 2; - if(!debug['d']) { - elftextsh += 10; - if(elfverneed) - elftextsh += 2; - } - if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) - elftextsh += 1; - if(buildinfolen > 0) - elftextsh += 1; - } - /* output symbol table */ symsize = 0; lcsize = 0; @@ -766,8 +567,6 @@ asmb(void) cseek(0L); switch(HEADTYPE) { default: - if(iself) - goto Elfput; case Hnoheader: /* no header */ break; case Hrisc: /* aif for risc os */ @@ -810,16 +609,6 @@ asmb(void) lput(0L); lput(lcsize); break; - case Hnetbsd: /* boot for NetBSD */ - lput((143<<16)|0413); /* magic */ - lputl(rnd(HEADR+textsize, 4096)); - lputl(rnd(segdata.filelen, 4096)); - lputl(segdata.len - segdata.filelen); - lputl(symsize); /* nsyms */ - lputl(entryvalue()); /* va of entry */ - lputl(0L); - lputl(0L); - break; case Hixp1200: /* boot for IXP1200 */ break; case Hipaq: /* boot for ipaq */ @@ -828,284 +617,11 @@ asmb(void) lputl(0xe3300000); /* nop */ lputl(0xe3300000); /* nop */ break; - Elfput: - /* elf arm */ - eh = getElfEhdr(); - fo = HEADR; - startva = INITTEXT - fo; /* va of byte 0 of file */ - resoff = ELFRESERVE; - - /* This null SHdr must appear before all others */ - newElfShdr(elfstr[ElfStrEmpty]); - - /* program header info */ - pph = newElfPhdr(); - pph->type = PT_PHDR; - pph->flags = PF_R + PF_X; - pph->off = eh->ehsize; - pph->vaddr = INITTEXT - HEADR + pph->off; - pph->paddr = INITTEXT - HEADR + pph->off; - pph->align = INITRND; - - /* - * PHDR must be in a loaded segment. Adjust the text - * segment boundaries downwards to include it. - */ - o = segtext.vaddr - pph->vaddr; - segtext.vaddr -= o; - segtext.len += o; - o = segtext.fileoff - pph->off; - segtext.fileoff -= o; - segtext.filelen += o; - - if(!debug['d']) { - /* interpreter for dynamic linking */ - sh = newElfShdr(elfstr[ElfStrInterp]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC; - sh->addralign = 1; - if(interpreter == nil) { - switch(HEADTYPE) { - case Hlinux: - interpreter = linuxdynld; - break; - case Hfreebsd: - interpreter = freebsddynld; - break; - } - } - resoff -= elfinterp(sh, startva, resoff, interpreter); - - ph = newElfPhdr(); - ph->type = PT_INTERP; - ph->flags = PF_R; - phsh(ph, sh); - } - - pnote = nil; - if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) { - sh = nil; - switch(HEADTYPE) { - case Hnetbsd: - sh = newElfShdr(elfstr[ElfStrNoteNetbsdIdent]); - resoff -= elfnetbsdsig(sh, startva, resoff); - break; - case Hopenbsd: - sh = newElfShdr(elfstr[ElfStrNoteOpenbsdIdent]); - resoff -= elfopenbsdsig(sh, startva, resoff); - break; - } - - pnote = newElfPhdr(); - pnote->type = PT_NOTE; - pnote->flags = PF_R; - phsh(pnote, sh); - } - - if(buildinfolen > 0) { - sh = newElfShdr(elfstr[ElfStrNoteBuildInfo]); - resoff -= elfbuildinfo(sh, startva, resoff); - - if(pnote == nil) { - pnote = newElfPhdr(); - pnote->type = PT_NOTE; - pnote->flags = PF_R; - } - phsh(pnote, sh); - } - USED(resoff); - - elfphload(&segtext); - elfphload(&segdata); - - /* Dynamic linking sections */ - if(!debug['d']) { /* -d suppresses dynamic loader format */ - /* S headers for dynamic linking */ - dynsym = eh->shnum; - sh = newElfShdr(elfstr[ElfStrDynsym]); - sh->type = SHT_DYNSYM; - sh->flags = SHF_ALLOC; - sh->entsize = ELF32SYMSIZE; - sh->addralign = 4; - sh->link = dynsym+1; // dynstr - // sh->info = index of first non-local symbol (number of local symbols) - shsym(sh, lookup(".dynsym", 0)); - - sh = newElfShdr(elfstr[ElfStrDynstr]); - sh->type = SHT_STRTAB; - sh->flags = SHF_ALLOC; - sh->addralign = 1; - shsym(sh, lookup(".dynstr", 0)); - - sh = newElfShdr(elfstr[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)); - - // ARM ELF needs .plt to be placed before .got - 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[ElfStrGotPlt]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = 4; - sh->addralign = 4; - shsym(sh, lookup(".got.plt", 0)); - - 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)); - - 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[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); - - // .tbss (optional) and TLS phdr - // Do not emit PT_TLS for OpenBSD since ld.so(1) does - // not currently support it. This is handled - // appropriately in runtime/cgo. - if(tlsoffset != 0 && HEADTYPE != Hopenbsd) { - 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; - - ph = newElfPhdr(); - ph->type = PT_PAX_FLAGS; - ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled - 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; - } - - eh->type = ET_EXEC; - eh->machine = EM_ARM; - eh->version = EV_CURRENT; - eh->entry = entryvalue(); - - if(pph != nil) { - pph->filesz = eh->phnum * eh->phentsize; - pph->memsz = pph->filesz; - } - - cseek(0); - a = 0; - a += elfwritehdr(); - a += elfwritephdrs(); - a += elfwriteshdrs(); - a += elfwriteinterp(elfstr[ElfStrInterp]); - if(HEADTYPE == Hnetbsd) - a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]); - if(HEADTYPE == Hopenbsd) - a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]); - if(buildinfolen > 0) - a += elfwritebuildinfo(elfstr[ElfStrNoteBuildInfo]); - if(a > ELFRESERVE) - diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); + case Hlinux: + case Hfreebsd: + case Hnetbsd: + case Hopenbsd: + asmbelf(symo); break; } cflush(); @@ -2330,82 +1846,3 @@ chipfloat(Ieee *e) no: return -1; } - - -void -genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) -{ - Auto *a; - Sym *s; - int h; - - s = lookup("etext", 0); - if(s->type == STEXT) - put(s, s->name, 'T', s->value, s->size, s->version, 0); - - for(h=0; hhash) { - if(s->hide) - continue; - switch(s->type&SMASK) { - case SCONST: - case SRODATA: - case SDATA: - case SELFROSECT: - case STYPE: - case SSTRING: - case SGOSTRING: - case SNOPTRDATA: - case SSYMTAB: - case SPCLNTAB: - case SGCDATA: - case SGCBSS: - if(!s->reachable) - continue; - put(s, s->name, 'D', s->value, s->size, s->version, s->gotype); - continue; - - case SBSS: - case SNOPTRBSS: - if(!s->reachable) - continue; - if(s->np > 0) - diag("%s should not be bss (size=%d type=%d special=%d)", s->name, (int)s->np, s->type, s->special); - put(s, s->name, 'B', s->value, s->size, s->version, s->gotype); - continue; - - case SFILE: - put(nil, s->name, 'f', s->value, 0, s->version, 0); - continue; - } - } - } - - for(s = textp; s != nil; s = s->next) { - 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 = %ud\n", symsize); - Bflush(&bso); -} diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h index 50531bb209..16f7e58925 100644 --- a/src/cmd/5l/l.h +++ b/src/cmd/5l/l.h @@ -145,6 +145,7 @@ struct Sym int32 sig; int32 size; int32 align; // if non-zero, required alignment in bytes + int32 elfsym; uchar special; uchar fnptr; // used as fn ptr Sym* hash; // in hash table @@ -159,6 +160,7 @@ struct Sym char* dynimpname; char* dynimplib; char* dynimpvers; + struct Section* sect; // STEXT Auto* autom; diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c index 59c0590b47..8266e5d2ae 100644 --- a/src/cmd/5l/span.c +++ b/src/cmd/5l/span.c @@ -96,10 +96,15 @@ span(void) Bprint(&bso, "%5.2f span\n", cputime()); Bflush(&bso); + sect = addsection(&segtext, ".text", 05); + lookup("text", 0)->sect = sect; + lookup("etext", 0)->sect = sect; + bflag = 0; c = INITTEXT; otxt = c; for(cursym = textp; cursym != nil; cursym = cursym->next) { + cursym->sect = sect; p = cursym->text; if(p == P || p->link == P) { // handle external functions and ELF section symbols if(cursym->type & SSUB) @@ -254,7 +259,6 @@ span(void) } } } - sect = addsection(&segtext, ".text", 05); sect->vaddr = INITTEXT; sect->len = c - INITTEXT; } diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index b0ff15423a..ebe412074c 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -74,36 +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, - ElfStrNoteOpenbsdIdent, - ElfStrNoteBuildInfo, - ElfStrNoPtrData, - ElfStrNoPtrBss, - NElfStr -}; - -vlong elfstr[NElfStr]; - static int needlib(char *name) { @@ -309,7 +279,7 @@ archreloc(Reloc *r, Sym *s, vlong *val) return -1; } -static void +void elfsetupplt(void) { Sym *plt, *got; @@ -575,185 +545,26 @@ 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"); - if(HEADTYPE == Hopenbsd) - elfstr[ElfStrNoteOpenbsdIdent] = addstring(shstrtab, ".note.openbsd.ident"); - if(buildinfolen > 0) - elfstr[ElfStrNoteBuildInfo] = addstring(shstrtab, ".note.gnu.build-id"); - addstring(shstrtab, ".elfdata"); - addstring(shstrtab, ".rodata"); - addstring(shstrtab, ".typelink"); - addstring(shstrtab, ".gcdata"); - addstring(shstrtab, ".gcbss"); - 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, *pnote; - ElfShdr *sh; + int i; + vlong vl, symo, dwarfoff, machlink; Section *sect; Sym *sym; - int i, o; 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); @@ -801,18 +612,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 || HEADTYPE == Hopenbsd) - elftextsh += 1; - if(buildinfolen > 0) - elftextsh += 1; break; case Hwindows: break; @@ -923,288 +722,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); - } - - pnote = nil; - if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) { - sh = nil; - switch(HEADTYPE) { - case Hnetbsd: - sh = newElfShdr(elfstr[ElfStrNoteNetbsdIdent]); - resoff -= elfnetbsdsig(sh, startva, resoff); - break; - case Hopenbsd: - sh = newElfShdr(elfstr[ElfStrNoteOpenbsdIdent]); - resoff -= elfopenbsdsig(sh, startva, resoff); - break; - } - - pnote = newElfPhdr(); - pnote->type = PT_NOTE; - pnote->flags = PF_R; - phsh(pnote, sh); - } - - if(buildinfolen > 0) { - sh = newElfShdr(elfstr[ElfStrNoteBuildInfo]); - resoff -= elfbuildinfo(sh, startva, resoff); - - if(pnote == nil) { - pnote = newElfPhdr(); - pnote->type = PT_NOTE; - pnote->flags = PF_R; - } - phsh(pnote, 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). - */ - // Do not emit PT_TLS for OpenBSD since ld.so(1) does - // not currently support it. This is handled - // appropriately in runtime/cgo. - if(tlsoffset != 0 && HEADTYPE != Hopenbsd) { - 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; - - ph = newElfPhdr(); - ph->type = PT_PAX_FLAGS; - ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled - 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(HEADTYPE == Hopenbsd) - a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]); - if(buildinfolen > 0) - a += elfwritebuildinfo(elfstr[ElfStrNoteBuildInfo]); - if(a > ELFRESERVE) - diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); + asmbelf(symo); break; case Hwindows: asmbpe(); @@ -1227,80 +745,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&SMASK) { - case SCONST: - case SRODATA: - case SSYMTAB: - case SPCLNTAB: - case SDATA: - case SNOPTRDATA: - case SELFROSECT: - case SMACHOGOT: - case STYPE: - case SSTRING: - case SGOSTRING: - case SWINDOWS: - case SGCDATA: - case SGCBSS: - 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/l.h b/src/cmd/6l/l.h index 91926a13a0..9f18b475c8 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -153,6 +153,7 @@ struct Sym int32 plt; int32 got; int32 align; // if non-zero, required alignment in bytes + int32 elfsym; Sym* hash; // in hash table Sym* allsym; // in all symbol list Sym* next; // in text or data list @@ -167,6 +168,7 @@ struct Sym char* dynimpname; char* dynimplib; char* dynimpvers; + struct Section* sect; // STEXT Auto* autom; diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index e83e4a8792..c5121f0b96 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -70,36 +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, - ElfStrNoteOpenbsdIdent, - ElfStrNoteBuildInfo, - ElfStrNoPtrData, - ElfStrNoPtrBss, - NElfStr -}; - -vlong elfstr[NElfStr]; - static int needlib(char *name) { @@ -284,7 +254,7 @@ adddynrel(Sym *s, Reloc *r) diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); } -static void +void elfsetupplt(void) { Sym *plt, *got; @@ -551,180 +521,22 @@ 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"); - if(HEADTYPE == Hopenbsd) - elfstr[ElfStrNoteOpenbsdIdent] = addstring(shstrtab, ".note.openbsd.ident"); - if(buildinfolen > 0) - elfstr[ElfStrNoteBuildInfo] = addstring(shstrtab, ".note.gnu.build-id"); - addstring(shstrtab, ".elfdata"); - addstring(shstrtab, ".rodata"); - addstring(shstrtab, ".typelink"); - addstring(shstrtab, ".gcdata"); - addstring(shstrtab, ".gcbss"); - 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, *pnote; - 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); @@ -757,21 +569,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 || HEADTYPE == Hopenbsd) - elftextsh += 1; - if(buildinfolen > 0) - elftextsh += 1; - } - symsize = 0; spsize = 0; lcsize = 0; @@ -852,8 +649,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 */ @@ -979,304 +774,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); - } - - pnote = nil; - if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) { - sh = nil; - switch(HEADTYPE) { - case Hnetbsd: - sh = newElfShdr(elfstr[ElfStrNoteNetbsdIdent]); - resoff -= elfnetbsdsig(sh, startva, resoff); - break; - case Hopenbsd: - sh = newElfShdr(elfstr[ElfStrNoteOpenbsdIdent]); - resoff -= elfopenbsdsig(sh, startva, resoff); - break; - } - - pnote = newElfPhdr(); - pnote->type = PT_NOTE; - pnote->flags = PF_R; - phsh(pnote, sh); - } - - if(buildinfolen > 0) { - sh = newElfShdr(elfstr[ElfStrNoteBuildInfo]); - resoff -= elfbuildinfo(sh, startva, resoff); - - if(pnote == nil) { - pnote = newElfPhdr(); - pnote->type = PT_NOTE; - pnote->flags = PF_R; - } - phsh(pnote, 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). - */ - // Do not emit PT_TLS for OpenBSD since ld.so(1) does - // not currently support it. This is handled - // appropriately in runtime/cgo. - if(tlsoffset != 0 && HEADTYPE != Hopenbsd) { - 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; - - ph = newElfPhdr(); - ph->type = PT_PAX_FLAGS; - ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled - 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(HEADTYPE == Hopenbsd) - a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]); - if(buildinfolen > 0) - a += elfwritebuildinfo(elfstr[ElfStrNoteBuildInfo]); - 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; @@ -1309,82 +815,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; hhash) { - if(s->hide) - continue; - switch(s->type&SMASK) { - 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: - case SGCDATA: - case SGCBSS: - 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/l.h b/src/cmd/8l/l.h index 96b425874d..26f0eb016d 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -137,6 +137,7 @@ struct Sym int32 plt; int32 got; int32 align; // if non-zero, required alignment in bytes + int32 elfsym; Sym* hash; // in hash table Sym* allsym; // in all symbol list Sym* next; // in text or data list @@ -149,6 +150,7 @@ struct Sym char* dynimpname; char* dynimplib; char* dynimpvers; + struct Section* sect; // STEXT Auto* autom; diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 88808d75f7..28e3848fd9 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -982,7 +982,8 @@ dodata(void) /* skip symbols belonging to segtext */ s = datap; - for(; s != nil && s->type < SELFSECT; s = s->next); + for(; s != nil && s->type < SELFSECT; s = s->next) + ; /* writable ELF sections */ datsize = 0; @@ -991,6 +992,7 @@ dodata(void) if(s->align != 0) datsize = rnd(datsize, s->align); sect->vaddr = datsize; + s->sect = sect; s->type = SDATA; s->value = datsize; datsize += rnd(s->size, PtrSize); @@ -1000,7 +1002,10 @@ dodata(void) /* pointer-free data */ sect = addsection(&segdata, ".noptrdata", 06); sect->vaddr = datsize; + lookup("noptrdata", 0)->sect = sect; + lookup("enoptrdata", 0)->sect = sect; for(; s != nil && s->type < SDATA; s = s->next) { + s->sect = sect; s->type = SDATA; t = alignsymsize(s->size); datsize = aligndatsize(datsize, s); @@ -1013,7 +1018,10 @@ dodata(void) /* data */ sect = addsection(&segdata, ".data", 06); sect->vaddr = datsize; + lookup("data", 0)->sect = sect; + lookup("edata", 0)->sect = sect; for(; s != nil && s->type < SBSS; s = s->next) { + s->sect = sect; s->type = SDATA; t = alignsymsize(s->size); datsize = aligndatsize(datsize, s); @@ -1030,7 +1038,10 @@ dodata(void) /* bss */ sect = addsection(&segdata, ".bss", 06); sect->vaddr = datsize; + lookup("bss", 0)->sect = sect; + lookup("ebss", 0)->sect = sect; for(; s != nil && s->type < SNOPTRBSS; s = s->next) { + s->sect = sect; t = alignsymsize(s->size); datsize = aligndatsize(datsize, s); s->value = datsize; @@ -1046,26 +1057,33 @@ dodata(void) /* pointer-free bss */ sect = addsection(&segdata, ".noptrbss", 06); sect->vaddr = datsize; + lookup("noptrbss", 0)->sect = sect; + lookup("enoptrbss", 0)->sect = sect; for(; s != nil; s = s->next) { if(s->type > SNOPTRBSS) { cursym = s; diag("unexpected symbol type %d", s->type); } + s->sect = sect; t = alignsymsize(s->size); datsize = aligndatsize(datsize, s); s->value = datsize; datsize += t; } sect->len = datsize - sect->vaddr; + lookup("end", 0)->sect = sect; /* we finished segdata, begin segtext */ /* read-only data */ sect = addsection(&segtext, ".rodata", 04); sect->vaddr = 0; + lookup("rodata", 0)->sect = sect; + lookup("erodata", 0)->sect = sect; datsize = 0; s = datap; for(; s != nil && s->type < STYPELINK; s = s->next) { + s->sect = sect; if(s->align != 0) datsize = rnd(datsize, s->align); s->type = SRODATA; @@ -1078,7 +1096,10 @@ dodata(void) /* type */ sect = addsection(&segtext, ".typelink", 04); sect->vaddr = datsize; + lookup("typelink", 0)->sect = sect; + lookup("etypelink", 0)->sect = sect; for(; s != nil && s->type == STYPELINK; s = s->next) { + s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; @@ -1089,7 +1110,10 @@ dodata(void) /* gcdata */ sect = addsection(&segtext, ".gcdata", 04); sect->vaddr = datsize; + lookup("gcdata", 0)->sect = sect; + lookup("egcdata", 0)->sect = sect; for(; s != nil && s->type == SGCDATA; s = s->next) { + s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; @@ -1100,7 +1124,10 @@ dodata(void) /* gcbss */ sect = addsection(&segtext, ".gcbss", 04); sect->vaddr = datsize; + lookup("gcbss", 0)->sect = sect; + lookup("egcbss", 0)->sect = sect; for(; s != nil && s->type == SGCBSS; s = s->next) { + s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; @@ -1111,7 +1138,10 @@ dodata(void) /* gosymtab */ sect = addsection(&segtext, ".gosymtab", 04); sect->vaddr = datsize; + lookup("symtab", 0)->sect = sect; + lookup("esymtab", 0)->sect = sect; for(; s != nil && s->type < SPCLNTAB; s = s->next) { + s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; @@ -1122,7 +1152,10 @@ dodata(void) /* gopclntab */ sect = addsection(&segtext, ".gopclntab", 04); sect->vaddr = datsize; + lookup("pclntab", 0)->sect = sect; + lookup("epclntab", 0)->sect = sect; for(; s != nil && s->type < SELFROSECT; s = s->next) { + s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; @@ -1136,6 +1169,7 @@ dodata(void) if(s->align != 0) datsize = rnd(datsize, s->align); sect->vaddr = datsize; + s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += rnd(s->size, PtrSize); @@ -1158,9 +1192,12 @@ textaddress(void) // Could parallelize, by assigning to text // and then letting threads copy down, but probably not worth it. sect = segtext.sect; + lookup("text", 0)->sect = sect; + lookup("etext", 0)->sect = sect; va = INITTEXT; sect->vaddr = va; for(sym = textp; sym != nil; sym = sym->next) { + sym->sect = sect; if(sym->type & SSUB) continue; if(sym->align != 0) diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c index 7fa41e2372..485d74c6a3 100644 --- a/src/cmd/ld/elf.c +++ b/src/cmd/ld/elf.c @@ -194,13 +194,6 @@ newElfPhdr(void) return e; } -ElfShdr* -newElfShstrtab(vlong name) -{ - hdr.shstrndx = hdr.shnum; - return newElfShdr(name); -} - ElfShdr* newElfShdr(vlong name) { @@ -208,6 +201,7 @@ newElfShdr(vlong name) e = mal(sizeof *e); e->name = name; + e->shnum = hdr.shnum; if (hdr.shnum >= NSECT) { diag("too many shdrs"); } else { @@ -337,17 +331,11 @@ elfinterp(ElfShdr *sh, uint64 startva, uint64 resoff, char *p) } int -elfwriteinterp(vlong stridx) +elfwriteinterp(void) { - ElfShdr *sh = nil; - int i; - - for(i = 0; i < hdr.shnum; i++) - if(shdr[i]->name == stridx) - sh = shdr[i]; - if(sh == nil || interp == nil) - return 0; - + ElfShdr *sh; + + sh = elfshname(".interp"); cseek(sh->off); cwrite(interp, sh->size); return sh->size; @@ -371,16 +359,11 @@ elfnote(ElfShdr *sh, uint64 startva, uint64 resoff, int sz) } ElfShdr * -elfwritenotehdr(vlong stridx, uint32 namesz, uint32 descsz, uint32 tag) +elfwritenotehdr(char *str, uint32 namesz, uint32 descsz, uint32 tag) { - ElfShdr *sh = nil; - int i; - - for(i = 0; i < hdr.shnum; i++) - if(shdr[i]->name == stridx) - sh = shdr[i]; - if(sh == nil) - return nil; + ElfShdr *sh; + + sh = elfshname(str); // Write Elf_Note header. cseek(sh->off); @@ -408,12 +391,12 @@ elfnetbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff) } int -elfwritenetbsdsig(vlong stridx) +elfwritenetbsdsig(void) { ElfShdr *sh; // Write Elf_Note header. - sh = elfwritenotehdr(stridx, ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG); + sh = elfwritenotehdr(".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG); if(sh == nil) return 0; @@ -441,12 +424,12 @@ elfopenbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff) } int -elfwriteopenbsdsig(vlong stridx) +elfwriteopenbsdsig(void) { ElfShdr *sh; // Write Elf_Note header. - sh = elfwritenotehdr(stridx, ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG); + sh = elfwritenotehdr(".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG); if(sh == nil) return 0; @@ -513,11 +496,11 @@ elfbuildinfo(ElfShdr *sh, uint64 startva, uint64 resoff) } int -elfwritebuildinfo(vlong stridx) +elfwritebuildinfo(void) { ElfShdr *sh; - sh = elfwritenotehdr(stridx, ELF_NOTE_BUILDINFO_NAMESZ, buildinfolen, ELF_NOTE_BUILDINFO_TAG); + sh = elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, buildinfolen, ELF_NOTE_BUILDINFO_TAG); if(sh == nil) return 0; @@ -721,18 +704,18 @@ elfphload(Segment *seg) } ElfShdr* -elfshbits(Section *sect) +elfshname(char *name) { int i, off; ElfShdr *sh; for(i=0; iname, elfstr[i].s) == 0) { + if(strcmp(name, elfstr[i].s) == 0) { off = elfstr[i].off; goto found; } } - diag("cannot find elf name %s", sect->name); + diag("cannot find elf name %s", name); errorexit(); return nil; @@ -742,8 +725,30 @@ found: if(sh->name == off) return sh; } - + sh = newElfShdr(off); + return sh; +} + +ElfShdr* +elfshalloc(Section *sect) +{ + ElfShdr *sh; + + sh = elfshname(sect->name); + sect->elfsect = sh; + return sh; +} + +ElfShdr* +elfshbits(Section *sect) +{ + ElfShdr *sh; + + sh = elfshalloc(sect); + if(sh->type > 0) + return sh; + if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen) sh->type = SHT_PROGBITS; else @@ -757,6 +762,541 @@ found: sh->addralign = PtrSize; sh->size = sect->len; sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr; - + return sh; } + +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; + + addstring(shstrtab, ""); + addstring(shstrtab, ".text"); + addstring(shstrtab, ".noptrdata"); + addstring(shstrtab, ".data"); + addstring(shstrtab, ".bss"); + addstring(shstrtab, ".noptrbss"); + if(HEADTYPE == Hnetbsd) + addstring(shstrtab, ".note.netbsd.ident"); + if(HEADTYPE == Hopenbsd) + addstring(shstrtab, ".note.openbsd.ident"); + if(buildinfolen > 0) + addstring(shstrtab, ".note.gnu.build-id"); + addstring(shstrtab, ".elfdata"); + addstring(shstrtab, ".rodata"); + addstring(shstrtab, ".typelink"); + addstring(shstrtab, ".gcdata"); + addstring(shstrtab, ".gcbss"); + addstring(shstrtab, ".gosymtab"); + addstring(shstrtab, ".gopclntab"); + + if(!debug['s']) { + addstring(shstrtab, ".symtab"); + addstring(shstrtab, ".strtab"); + dwarfaddshstrings(shstrtab); + } + addstring(shstrtab, ".shstrtab"); + + if(!debug['d']) { /* -d suppresses dynamic loader format */ + addstring(shstrtab, ".interp"); + addstring(shstrtab, ".hash"); + addstring(shstrtab, ".got"); + addstring(shstrtab, ".got.plt"); + addstring(shstrtab, ".dynamic"); + addstring(shstrtab, ".dynsym"); + addstring(shstrtab, ".dynstr"); + if(thechar == '6') { + addstring(shstrtab, ".rela"); + addstring(shstrtab, ".rela.plt"); + } else { + addstring(shstrtab, ".rel"); + addstring(shstrtab, ".rel.plt"); + } + addstring(shstrtab, ".plt"); + addstring(shstrtab, ".gnu.version"); + addstring(shstrtab, ".gnu.version_r"); + + /* dynamic symbol table - first entry all zeros */ + s = lookup(".dynsym", 0); + s->type = SELFROSECT; + s->reachable = 1; + if(thechar == '6') + s->size += ELF64SYMSIZE; + else + s->size += ELF32SYMSIZE; + + /* dynamic string table */ + s = lookup(".dynstr", 0); + s->type = SELFROSECT; + s->reachable = 1; + if(s->size == 0) + addstring(s, ""); + dynstr = s; + + /* relocation table */ + if(thechar == '6') + s = lookup(".rela", 0); + else + 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; + + s = lookup(".got.plt", 0); + s->reachable = 1; + s->type = SELFSECT; // writable + + s = lookup(".plt", 0); + s->reachable = 1; + s->type = SELFROSECT; + + elfsetupplt(); + + if(thechar == '6') + s = lookup(".rela.plt", 0); + else + 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; + + /* 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)); + if(thechar == '6') + elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE); + else + elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE); + elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0)); + elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0)); + if(thechar == '6') { + elfwritedynentsym(s, DT_RELA, lookup(".rela", 0)); + elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0)); + elfwritedynent(s, DT_RELAENT, ELF64RELASIZE); + } else { + 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)); + + if(thechar == '6') { + elfwritedynent(s, DT_PLTREL, DT_RELA); + elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0)); + elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0)); + } else { + 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(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 +asmbelfsetup(void) +{ + Section *sect; + + /* This null SHdr must appear before all others */ + elfshname(""); + + for(sect=segtext.sect; sect!=nil; sect=sect->next) + elfshalloc(sect); + for(sect=segdata.sect; sect!=nil; sect=sect->next) + elfshalloc(sect); +} + +void +asmbelf(vlong symo) +{ + int a, o; + vlong startva, resoff; + ElfEhdr *eh; + ElfPhdr *ph, *pph, *pnote; + ElfShdr *sh; + Section *sect; + + eh = getElfEhdr(); + switch(thechar) { + default: + diag("unknown architecture in asmbelf"); + errorexit(); + case '5': + eh->machine = EM_ARM; + break; + case '6': + eh->machine = EM_X86_64; + break; + case '8': + eh->machine = EM_386; + break; + } + + startva = INITTEXT - HEADR; + resoff = ELFRESERVE; + + /* 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 = elfshname(".interp"); + 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); + } + + pnote = nil; + if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) { + sh = nil; + switch(HEADTYPE) { + case Hnetbsd: + sh = elfshname(".note.netbsd.ident"); + resoff -= elfnetbsdsig(sh, startva, resoff); + break; + case Hopenbsd: + sh = elfshname(".note.openbsd.ident"); + resoff -= elfopenbsdsig(sh, startva, resoff); + break; + } + + pnote = newElfPhdr(); + pnote->type = PT_NOTE; + pnote->flags = PF_R; + phsh(pnote, sh); + } + + if(buildinfolen > 0) { + sh = elfshname(".note.gnu.build-id"); + resoff -= elfbuildinfo(sh, startva, resoff); + + if(pnote == nil) { + pnote = newElfPhdr(); + pnote->type = PT_NOTE; + pnote->flags = PF_R; + } + phsh(pnote, 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 */ + sh = elfshname(".dynsym"); + sh->type = SHT_DYNSYM; + sh->flags = SHF_ALLOC; + if(PtrSize == 8) + sh->entsize = ELF64SYMSIZE; + else + sh->entsize = ELF32SYMSIZE; + sh->addralign = PtrSize; + sh->link = elfshname(".dynstr")->shnum; + // sh->info = index of first non-local symbol (number of local symbols) + shsym(sh, lookup(".dynsym", 0)); + + sh = elfshname(".dynstr"); + sh->type = SHT_STRTAB; + sh->flags = SHF_ALLOC; + sh->addralign = 1; + shsym(sh, lookup(".dynstr", 0)); + + if(elfverneed) { + sh = elfshname(".gnu.version"); + sh->type = SHT_GNU_VERSYM; + sh->flags = SHF_ALLOC; + sh->addralign = 2; + sh->link = elfshname(".dynsym")->shnum; + sh->entsize = 2; + shsym(sh, lookup(".gnu.version", 0)); + + sh = elfshname(".gnu.version_r"); + sh->type = SHT_GNU_VERNEED; + sh->flags = SHF_ALLOC; + sh->addralign = PtrSize; + sh->info = elfverneed; + sh->link = elfshname(".dynstr")->shnum; + shsym(sh, lookup(".gnu.version_r", 0)); + } + + switch(eh->machine) { + case EM_X86_64: + sh = elfshname(".rela.plt"); + sh->type = SHT_RELA; + sh->flags = SHF_ALLOC; + sh->entsize = ELF64RELASIZE; + sh->addralign = PtrSize; + sh->link = elfshname(".dynsym")->shnum; + sh->info = elfshname(".plt")->shnum; + shsym(sh, lookup(".rela.plt", 0)); + + sh = elfshname(".rela"); + sh->type = SHT_RELA; + sh->flags = SHF_ALLOC; + sh->entsize = ELF64RELASIZE; + sh->addralign = 8; + sh->link = elfshname(".dynsym")->shnum; + shsym(sh, lookup(".rela", 0)); + break; + + default: + sh = elfshname(".rel.plt"); + sh->type = SHT_REL; + sh->flags = SHF_ALLOC; + sh->entsize = ELF32RELSIZE; + shsym(sh, lookup(".rel.plt", 0)); + + sh = elfshname(".rel"); + sh->type = SHT_REL; + sh->flags = SHF_ALLOC; + sh->entsize = ELF32RELSIZE; + sh->addralign = 4; + sh->link = elfshname(".dynsym")->shnum; + shsym(sh, lookup(".rel", 0)); + break; + } + + sh = elfshname(".plt"); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC+SHF_EXECINSTR; + if(eh->machine == EM_X86_64) + sh->entsize = 16; + else + sh->entsize = 4; + sh->addralign = 4; + shsym(sh, lookup(".plt", 0)); + + sh = elfshname(".got"); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC+SHF_WRITE; + sh->entsize = PtrSize; + sh->addralign = PtrSize; + shsym(sh, lookup(".got", 0)); + + sh = elfshname(".got.plt"); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC+SHF_WRITE; + sh->entsize = PtrSize; + sh->addralign = PtrSize; + shsym(sh, lookup(".got.plt", 0)); + + sh = elfshname(".hash"); + sh->type = SHT_HASH; + sh->flags = SHF_ALLOC; + sh->entsize = 4; + sh->addralign = PtrSize; + sh->link = elfshname(".dynsym")->shnum; + shsym(sh, lookup(".hash", 0)); + + /* sh and PT_DYNAMIC for .dynamic section */ + sh = elfshname(".dynamic"); + sh->type = SHT_DYNAMIC; + sh->flags = SHF_ALLOC+SHF_WRITE; + sh->entsize = 2*PtrSize; + sh->addralign = PtrSize; + sh->link = elfshname(".dynstr")->shnum; + 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). + */ + // Do not emit PT_TLS for OpenBSD since ld.so(1) does + // not currently support it. This is handled + // appropriately in runtime/cgo. + if(tlsoffset != 0 && HEADTYPE != Hopenbsd) { + ph = newElfPhdr(); + ph->type = PT_TLS; + ph->flags = PF_R; + ph->memsz = -tlsoffset; + ph->align = PtrSize; + } + } + + ph = newElfPhdr(); + ph->type = PT_GNU_STACK; + ph->flags = PF_W+PF_R; + ph->align = PtrSize; + + ph = newElfPhdr(); + ph->type = PT_PAX_FLAGS; + ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled + ph->align = PtrSize; + + sh = elfshname(".shstrtab"); + sh->type = SHT_STRTAB; + sh->addralign = 1; + shsym(sh, lookup(".shstrtab", 0)); + eh->shstrndx = sh->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 = elfshname(".symtab"); + sh->type = SHT_SYMTAB; + sh->off = symo; + sh->size = symsize; + sh->addralign = PtrSize; + sh->entsize = 8+2*PtrSize; + sh->link = elfshname(".strtab")->shnum; + sh->info = elfglobalsymndx; + + sh = elfshname(".strtab"); + 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; + if(PtrSize == 8) + eh->ident[EI_CLASS] = ELFCLASS64; + else + eh->ident[EI_CLASS] = ELFCLASS32; + eh->ident[EI_DATA] = ELFDATA2LSB; + eh->ident[EI_VERSION] = EV_CURRENT; + + eh->type = ET_EXEC; + 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(); + if(!debug['d']) + a += elfwriteinterp(); + if(HEADTYPE == Hnetbsd) + a += elfwritenetbsdsig(); + if(HEADTYPE == Hopenbsd) + a += elfwriteopenbsdsig(); + if(buildinfolen > 0) + a += elfwritebuildinfo(); + if(a > ELFRESERVE) + diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); +} diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h index 3eb13ae398..9f1e16a88a 100644 --- a/src/cmd/ld/elf.h +++ b/src/cmd/ld/elf.h @@ -841,7 +841,8 @@ typedef struct { * Section header. */ -typedef struct { +typedef struct Elf64_Shdr Elf64_Shdr; +struct Elf64_Shdr { Elf64_Word name; /* Section name (index into the section header string table). */ Elf64_Word type; /* Section type. */ @@ -853,7 +854,9 @@ typedef struct { Elf64_Word info; /* Depends on section type. */ Elf64_Xword addralign; /* Alignment in bytes. */ Elf64_Xword entsize; /* Size of each entry in section. */ -} Elf64_Shdr; + + int shnum; /* section number, not stored on disk */ +}; /* * Program header. @@ -957,7 +960,6 @@ typedef Elf64_Phdr ElfPhdr; void elfinit(void); ElfEhdr *getElfEhdr(void); -ElfShdr *newElfShstrtab(vlong); ElfShdr *newElfShdr(vlong); ElfPhdr *newElfPhdr(void); uint32 elfwritehdr(void); @@ -974,23 +976,38 @@ extern int numelfshdr; extern int iself; extern int elfverneed; int elfinterp(ElfShdr*, uint64, uint64, char*); -int elfwriteinterp(vlong); +int elfwriteinterp(void); int elfnetbsdsig(ElfShdr*, uint64, uint64); -int elfwritenetbsdsig(vlong); +int elfwritenetbsdsig(void); int elfopenbsdsig(ElfShdr*, uint64, uint64); -int elfwriteopenbsdsig(vlong); +int elfwriteopenbsdsig(void); void addbuildinfo(char*); int elfbuildinfo(ElfShdr*, uint64, uint64); -int elfwritebuildinfo(vlong); +int elfwritebuildinfo(void); void elfdynhash(void); ElfPhdr* elfphload(Segment*); ElfShdr* elfshbits(Section*); +ElfShdr* elfshalloc(Section*); +ElfShdr* elfshname(char*); +ElfShdr* elfshreloc(Section*); void elfsetstring(char*, int); void elfaddverneed(Sym*); +void elfemitreloc(void); +void shsym(ElfShdr*, Sym*); +void phsh(ElfPhdr*, ElfShdr*); +void doelf(void); +void elfsetupplt(void); +void dwarfaddshstrings(Sym*); +void dwarfaddelfheaders(void); +void asmbelf(vlong symo); +void asmbelfsetup(void); +extern char linuxdynld[]; +extern char freebsddynld[]; +extern char netbsddynld[]; +extern char openbsddynld[]; EXTERN int elfstrsize; EXTERN char* elfstrdat; -EXTERN int elftextsh; EXTERN int buildinfolen; /* diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c index be5b6d33e6..ab19d7c009 100644 --- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -815,6 +815,7 @@ doweak(void) if(t && t->type != 0 && t->reachable) { s->value = t->value; s->type = t->type; + s->outer = t; } else { s->type = SCONST; s->value = 0; diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index 0f51e6b9f2..4e1d79a506 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -1501,3 +1501,85 @@ cwrite(void *buf, int n) } coutpos += n; } + +void +genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) +{ + Auto *a; + Sym *s; + + // These symbols won't show up in the first loop below because we + // skip STEXT symbols. Normal STEXT symbols are emitted by walking textp. + s = lookup("text", 0); + if(s->type == STEXT) + put(s, s->name, 'T', s->value, s->size, s->version, 0); + 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&SMASK) { + case SCONST: + case SRODATA: + case SSYMTAB: + case SPCLNTAB: + case SDATA: + case SNOPTRDATA: + case SELFROSECT: + case SMACHOGOT: + case STYPE: + case SSTRING: + case SGOSTRING: + case SWINDOWS: + case SGCDATA: + case SGCBSS: + 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+PtrSize, 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/ld/lib.h b/src/cmd/ld/lib.h index 0a582b9b10..13009d2a3a 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -105,6 +105,7 @@ struct Section uvlong len; Section *next; // in segment list Segment *seg; + struct Elf64_Shdr *elfsect; }; extern char symname[]; @@ -133,6 +134,7 @@ EXTERN char* thestring; EXTERN int ndynexp; EXTERN int havedynamic; EXTERN int iscgo; +EXTERN int elfglobalsymndx; EXTERN char* tracksym; EXTERN Segment segtext; diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c index 92627f5986..4b83e36b01 100644 --- a/src/cmd/ld/symtab.c +++ b/src/cmd/ld/symtab.c @@ -82,10 +82,14 @@ putelfsyment(int off, vlong addr, vlong size, int info, int shndx, int other) } } +static int numelfsym = 1; // 0 is reserved +static int elfbind; + static void putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) { - int bind, type, shndx, off; + int bind, type, off; + Sym *xo; USED(go); switch(t) { @@ -93,25 +97,37 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) return; case 'T': type = STT_FUNC; - shndx = elftextsh + 0; break; case 'D': type = STT_OBJECT; - if((x->type&SMASK) == SRODATA) - shndx = elftextsh + 1; - else - shndx = elftextsh + 2; break; case 'B': type = STT_OBJECT; - shndx = elftextsh + 3; break; } - // TODO(minux): we need to place all STB_LOCAL precede all STB_GLOBAL and - // STB_WEAK symbols in the symbol table + xo = x; + while(xo->outer != nil) + xo = xo->outer; + if(xo->sect == nil) { + cursym = x; + diag("missing section in putelfsym"); + return; + } + if(xo->sect->elfsect == nil) { + cursym = x; + diag("missing ELF section in putelfsym"); + return; + } + + // One pass for each binding: STB_LOCAL, STB_GLOBAL, + // maybe one day STB_WEAK. bind = (ver || (x->type & SHIDDEN)) ? STB_LOCAL : STB_GLOBAL; + if(bind != elfbind) + return; + off = putelfstr(s); - putelfsyment(off, addr, size, (bind<<4)|(type&0xf), shndx, (x->type & SHIDDEN) ? 2 : 0); + putelfsyment(off, addr, size, (bind<<4)|(type&0xf), xo->sect->elfsect->shnum, (x->type & SHIDDEN) ? 2 : 0); + x->elfsym = numelfsym++; } void @@ -119,6 +135,12 @@ asmelfsym(void) { // the first symbol entry is reserved putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0); + + elfbind = STB_LOCAL; + genasmsym(putelfsym); + + elfbind = STB_GLOBAL; + elfglobalsymndx = numelfsym; genasmsym(putelfsym); } @@ -354,8 +376,7 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ) void symtab(void) { - Sym *s; - + Sym *s, *symtype, *symtypelink, *symgostring; dosymtype(); // Define these so that they'll get put into the symbol table. @@ -387,11 +408,15 @@ symtab(void) s->type = STYPE; s->size = 0; s->reachable = 1; + symtype = s; s = lookup("go.string.*", 0); s->type = SGOSTRING; s->size = 0; s->reachable = 1; + symgostring = s; + + symtypelink = lookup("typelink", 0); symt = lookup("symtab", 0); symt->type = SSYMTAB; @@ -408,14 +433,17 @@ symtab(void) if(strncmp(s->name, "type.", 5) == 0) { s->type = STYPE; s->hide = 1; + s->outer = symtype; } if(strncmp(s->name, "go.typelink.", 12) == 0) { s->type = STYPELINK; s->hide = 1; + s->outer = symtypelink; } if(strncmp(s->name, "go.string.", 10) == 0) { s->type = SGOSTRING; s->hide = 1; + s->outer = symgostring; } }