Commit d37c572a authored by Russ Cox's avatar Russ Cox

cmd/ld: move symtab, ELF generation to portable code

More cleanup in preparation for fixing issue 4069.

This CL replaces the three nearly identical copies of the
asmb ELF code with a single asmbelf function in elf.c.

In addition to the ELF code movement, remove the elfstr
array in favor of a simpler lookup, and identify sections by
name throughout instead of computing fragile indices.

The CL also replaces the three nearly identical copies of the
genasmsym code with a single genasmsym function in lib.c.

The ARM linker still compiles and generates binaries,
but I haven't tested the binaries. They may not work.

R=ken2
CC=golang-dev
https://golang.org/cl/7062047
parent b006cd9b
......@@ -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);
}
......@@ -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;
......
......@@ -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;
}
......
......@@ -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);
}
......@@ -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;
......
......@@ -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);
}
......@@ -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;
......
......@@ -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)
......
......@@ -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);
}
......@@ -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;
/*
......
......@@ -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;
......
......@@ -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);
}
......@@ -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;
......
......@@ -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;
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment