]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/ld: move symtab, ELF generation to portable code
authorRuss Cox <rsc@golang.org>
Sun, 6 Jan 2013 19:32:45 +0000 (14:32 -0500)
committerRuss Cox <rsc@golang.org>
Sun, 6 Jan 2013 19:32:45 +0000 (14:32 -0500)
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

14 files changed:
src/cmd/5l/asm.c
src/cmd/5l/l.h
src/cmd/5l/span.c
src/cmd/6l/asm.c
src/cmd/6l/l.h
src/cmd/8l/asm.c
src/cmd/8l/l.h
src/cmd/ld/data.c
src/cmd/ld/elf.c
src/cmd/ld/elf.h
src/cmd/ld/go.c
src/cmd/ld/lib.c
src/cmd/ld/lib.h
src/cmd/ld/symtab.c

index 1937d899ab8ac2d7a7c711820bbfc21121d1c0f9..7c45268117d36df78824e4697896784ed5288ae0 100644 (file)
@@ -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; h<NHASH; h++) {
-               for(s=hash[h]; s!=S; s=s->hash) {
-                       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);
-}
index 50531bb2092b334b63812b485d8985aaa1d1a2af..16f7e58925e441e204955f9b6eb202c0da0725ae 100644 (file)
@@ -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;
index 59c0590b4713ecbb733003a3add213d0fb7920e2..8266e5d2aeff825f40cfda3b6977182ed45b504c 100644 (file)
@@ -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;
 }
index b0ff15423a5856bb456dae1ad18092dc96a675dd..ebe412074cec1fb7b6a3717393bf6eaa7d986a9e 100644 (file)
@@ -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);
-}
index 91926a13a01318b2b8d7824e819cd21e0b9cdd06..9f18b475c808c240f29ec4c777c0a77ff5e70566 100644 (file)
@@ -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;
index e83e4a87922f7703d7e1f947e0ce8c1bf4c18180..c5121f0b96966a123e4f3c63f79759fa3e9983fb 100644 (file)
@@ -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; h<NHASH; h++) {
-               for(s=hash[h]; s!=S; s=s->hash) {
-                       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);
-}
index 96b425874dc5e47124949117bebcaefdc03296bc..26f0eb016dcb5b4aec77adda3872de2506342a87 100644 (file)
@@ -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;
index 88808d75f7ae0ef86dfb23fd98e1d71a8ffc92ae..28e3848fd94b803d4719b54f3f5b7ed6cc0b6903 100644 (file)
@@ -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)
index 7fa41e237235bba80b7bc042901430d205a4789a..485d74c6a3b6527217272750e0a16b3d8952b10f 100644 (file)
@@ -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; i<nelfstr; i++) {
-               if(strcmp(sect->name, 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);
+}
index 3eb13ae398d71f460ee4850a5c722059f2440c67..9f1e16a88a90e00b249d2c0a82ecad0c13cb2356 100644 (file)
@@ -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;
 
 /*
index be5b6d33e64e4ad62426565a3e9210e17152a850..ab19d7c0094dd6744857096d323ed01074396850 100644 (file)
@@ -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;
index 0f51e6b9f270c1fffaee16f5a8a22d44f232164f..4e1d79a5068f9e64c2cafe77b8d0bcbdddb009c3 100644 (file)
@@ -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);
+}
index 0a582b9b101395d50016a3abe1c4c5486475cf89..13009d2a3ad181a953d8d1c4f3d8c46a0dd63489 100644 (file)
@@ -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;
index 92627f5986769b159deb745581045f89feff2d1b..4b83e36b0152ec52442a9b4584aa0463d85c1696 100644 (file)
@@ -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;
                }
        }