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
This diff is collapsed.
......@@ -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;
}
......
This diff is collapsed.
......@@ -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;
......
This diff is collapsed.
......@@ -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)
......
This diff is collapsed.
......@@ -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