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)
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)
{
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;
}
}
-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)
{
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);
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;
cseek(0L);
switch(HEADTYPE) {
default:
- if(iself)
- goto Elfput;
case Hnoheader: /* no header */
break;
case Hrisc: /* aif for risc os */
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 */
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();
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);
-}
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
char* dynimpname;
char* dynimplib;
char* dynimpvers;
+ struct Section* sect;
// STEXT
Auto* autom;
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)
}
}
}
- sect = addsection(&segtext, ".text", 05);
sect->vaddr = INITTEXT;
sect->len = c - INITTEXT;
}
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)
{
return -1;
}
-static void
+void
elfsetupplt(void)
{
Sym *plt, *got;
}
}
-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);
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;
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();
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);
-}
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
char* dynimpname;
char* dynimplib;
char* dynimpvers;
+ struct Section* sect;
// STEXT
Auto* autom;
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)
{
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;
}
}
-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);
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;
cseek(0L);
switch(HEADTYPE) {
default:
- if(iself)
- goto Elfput;
case Hgarbunix: /* garbage */
lputb(0x160L<<16); /* magic and sections */
lputb(0L); /* time and date */
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;
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);
-}
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
char* dynimpname;
char* dynimplib;
char* dynimpvers;
+ struct Section* sect;
// STEXT
Auto* autom;
/* 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;
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);
/* 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);
/* 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);
/* 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;
/* 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;
/* 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;
/* 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;
/* 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;
/* 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;
/* 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;
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);
// 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)
return e;
}
-ElfShdr*
-newElfShstrtab(vlong name)
-{
- hdr.shstrndx = hdr.shnum;
- return newElfShdr(name);
-}
-
ElfShdr*
newElfShdr(vlong name)
{
e = mal(sizeof *e);
e->name = name;
+ e->shnum = hdr.shnum;
if (hdr.shnum >= NSECT) {
diag("too many shdrs");
} else {
}
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;
}
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);
}
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;
}
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;
}
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;
}
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;
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
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);
+}
* 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. */
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.
void elfinit(void);
ElfEhdr *getElfEhdr(void);
-ElfShdr *newElfShstrtab(vlong);
ElfShdr *newElfShdr(vlong);
ElfPhdr *newElfPhdr(void);
uint32 elfwritehdr(void);
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;
/*
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;
}
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);
+}
uvlong len;
Section *next; // in segment list
Segment *seg;
+ struct Elf64_Shdr *elfsect;
};
extern char symname[];
EXTERN int ndynexp;
EXTERN int havedynamic;
EXTERN int iscgo;
+EXTERN int elfglobalsymndx;
EXTERN char* tracksym;
EXTERN Segment segtext;
}
}
+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) {
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
{
// 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);
}
void
symtab(void)
{
- Sym *s;
-
+ Sym *s, *symtype, *symtypelink, *symgostring;
dosymtype();
// Define these so that they'll get put into the symbol table.
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;
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;
}
}