diff options
Diffstat (limited to 'src/cmd/ld/ldelf.c')
-rw-r--r-- | src/cmd/ld/ldelf.c | 816 |
1 files changed, 0 insertions, 816 deletions
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c deleted file mode 100644 index 8334e988e..000000000 --- a/src/cmd/ld/ldelf.c +++ /dev/null @@ -1,816 +0,0 @@ -/* -Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c -http://code.swtch.com/plan9port/src/tip/src/libmach/ - - Copyright © 2004 Russ Cox. - Portions Copyright © 2008-2010 Google Inc. - Portions Copyright © 2010 The Go Authors. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include "l.h" -#include "lib.h" -#include "../ld/elf.h" - -enum -{ - ElfClassNone = 0, - ElfClass32, - ElfClass64, - - ElfDataNone = 0, - ElfDataLsb, - ElfDataMsb, - - ElfTypeNone = 0, - ElfTypeRelocatable, - ElfTypeExecutable, - ElfTypeSharedObject, - ElfTypeCore, - /* 0xFF00 - 0xFFFF reserved for processor-specific types */ - - ElfMachNone = 0, - ElfMach32100, /* AT&T WE 32100 */ - ElfMachSparc, /* SPARC */ - ElfMach386, /* Intel 80386 */ - ElfMach68000, /* Motorola 68000 */ - ElfMach88000, /* Motorola 88000 */ - ElfMach486, /* Intel 80486, no longer used */ - ElfMach860, /* Intel 80860 */ - ElfMachMips, /* MIPS RS3000 */ - ElfMachS370, /* IBM System/370 */ - ElfMachMipsLe, /* MIPS RS3000 LE */ - ElfMachParisc = 15, /* HP PA RISC */ - ElfMachVpp500 = 17, /* Fujitsu VPP500 */ - ElfMachSparc32Plus, /* SPARC V8+ */ - ElfMach960, /* Intel 80960 */ - ElfMachPower, /* PowerPC */ - ElfMachPower64, /* PowerPC 64 */ - ElfMachS390, /* IBM System/390 */ - ElfMachV800 = 36, /* NEC V800 */ - ElfMachFr20, /* Fujitsu FR20 */ - ElfMachRh32, /* TRW RH-32 */ - ElfMachRce, /* Motorola RCE */ - ElfMachArm, /* ARM */ - ElfMachAlpha, /* Digital Alpha */ - ElfMachSH, /* Hitachi SH */ - ElfMachSparc9, /* SPARC V9 */ - ElfMachAmd64 = 62, - /* and the list goes on... */ - - ElfAbiNone = 0, - ElfAbiSystemV = 0, /* [sic] */ - ElfAbiHPUX, - ElfAbiNetBSD, - ElfAbiLinux, - ElfAbiSolaris = 6, - ElfAbiAix, - ElfAbiIrix, - ElfAbiFreeBSD, - ElfAbiTru64, - ElfAbiModesto, - ElfAbiOpenBSD, - ElfAbiARM = 97, - ElfAbiEmbedded = 255, - - /* some of sections 0xFF00 - 0xFFFF reserved for various things */ - ElfSectNone = 0, - ElfSectProgbits, - ElfSectSymtab, - ElfSectStrtab, - ElfSectRela, - ElfSectHash, - ElfSectDynamic, - ElfSectNote, - ElfSectNobits, - ElfSectRel, - ElfSectShlib, - ElfSectDynsym, - - ElfSectFlagWrite = 0x1, - ElfSectFlagAlloc = 0x2, - ElfSectFlagExec = 0x4, - /* 0xF0000000 are reserved for processor specific */ - - ElfSymBindLocal = 0, - ElfSymBindGlobal, - ElfSymBindWeak, - /* 13-15 reserved */ - - ElfSymTypeNone = 0, - ElfSymTypeObject, - ElfSymTypeFunc, - ElfSymTypeSection, - ElfSymTypeFile, - /* 13-15 reserved */ - - ElfSymShnNone = 0, - ElfSymShnAbs = 0xFFF1, - ElfSymShnCommon = 0xFFF2, - /* 0xFF00-0xFF1F reserved for processors */ - /* 0xFF20-0xFF3F reserved for operating systems */ - - ElfProgNone = 0, - ElfProgLoad, - ElfProgDynamic, - ElfProgInterp, - ElfProgNote, - ElfProgShlib, - ElfProgPhdr, - - ElfProgFlagExec = 0x1, - ElfProgFlagWrite = 0x2, - ElfProgFlagRead = 0x4, - - ElfNotePrStatus = 1, - ElfNotePrFpreg = 2, - ElfNotePrPsinfo = 3, - ElfNotePrTaskstruct = 4, - ElfNotePrAuxv = 6, - ElfNotePrXfpreg = 0x46e62b7f /* for gdb/386 */ -}; - -typedef struct ElfHdrBytes ElfHdrBytes; -typedef struct ElfSectBytes ElfSectBytes; -typedef struct ElfProgBytes ElfProgBytes; -typedef struct ElfSymBytes ElfSymBytes; - -typedef struct ElfHdrBytes64 ElfHdrBytes64; -typedef struct ElfSectBytes64 ElfSectBytes64; -typedef struct ElfProgBytes64 ElfProgBytes64; -typedef struct ElfSymBytes64 ElfSymBytes64; - -struct ElfHdrBytes -{ - uchar ident[16]; - uchar type[2]; - uchar machine[2]; - uchar version[4]; - uchar entry[4]; - uchar phoff[4]; - uchar shoff[4]; - uchar flags[4]; - uchar ehsize[2]; - uchar phentsize[2]; - uchar phnum[2]; - uchar shentsize[2]; - uchar shnum[2]; - uchar shstrndx[2]; -}; - -struct ElfHdrBytes64 -{ - uchar ident[16]; - uchar type[2]; - uchar machine[2]; - uchar version[4]; - uchar entry[8]; - uchar phoff[8]; - uchar shoff[8]; - uchar flags[4]; - uchar ehsize[2]; - uchar phentsize[2]; - uchar phnum[2]; - uchar shentsize[2]; - uchar shnum[2]; - uchar shstrndx[2]; -}; - -struct ElfSectBytes -{ - uchar name[4]; - uchar type[4]; - uchar flags[4]; - uchar addr[4]; - uchar off[4]; - uchar size[4]; - uchar link[4]; - uchar info[4]; - uchar align[4]; - uchar entsize[4]; -}; - -struct ElfSectBytes64 -{ - uchar name[4]; - uchar type[4]; - uchar flags[8]; - uchar addr[8]; - uchar off[8]; - uchar size[8]; - uchar link[4]; - uchar info[4]; - uchar align[8]; - uchar entsize[8]; -}; - -struct ElfSymBytes -{ - uchar name[4]; - uchar value[4]; - uchar size[4]; - uchar info; /* top4: bind, bottom4: type */ - uchar other; - uchar shndx[2]; -}; - -struct ElfSymBytes64 -{ - uchar name[4]; - uchar info; /* top4: bind, bottom4: type */ - uchar other; - uchar shndx[2]; - uchar value[8]; - uchar size[8]; -}; - -typedef struct ElfSect ElfSect; -typedef struct ElfObj ElfObj; -typedef struct ElfSym ElfSym; - -struct ElfSect -{ - char *name; - uint32 type; - uint64 flags; - uint64 addr; - uint64 off; - uint64 size; - uint32 link; - uint32 info; - uint64 align; - uint64 entsize; - uchar *base; - Sym *sym; -}; - -struct ElfObj -{ - Biobuf *f; - int64 base; // offset in f where ELF begins - int64 len; // length of ELF - int is64; - char *name; - - Endian *e; - ElfSect *sect; - uint nsect; - char *shstrtab; - int nsymtab; - ElfSect *symtab; - ElfSect *symstr; - - uint32 type; - uint32 machine; - uint32 version; - uint64 entry; - uint64 phoff; - uint64 shoff; - uint32 flags; - uint32 ehsize; - uint32 phentsize; - uint32 phnum; - uint32 shentsize; - uint32 shnum; - uint32 shstrndx; -}; - -struct ElfSym -{ - char* name; - uint64 value; - uint64 size; - uchar bind; - uchar type; - uchar other; - uint16 shndx; - Sym* sym; -}; - -uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' }; - -static ElfSect* section(ElfObj*, char*); -static int map(ElfObj*, ElfSect*); -static int readsym(ElfObj*, int i, ElfSym*); -static int reltype(char*, int, uchar*); - -void -ldelf(Biobuf *f, char *pkg, int64 len, char *pn) -{ - int32 base; - uint64 add, info; - char *name; - int i, j, rela, is64, n; - uchar hdrbuf[64]; - uchar *p; - ElfHdrBytes *hdr; - ElfObj *obj; - ElfSect *sect, *rsect; - ElfSym sym; - Endian *e; - Reloc *r, *rp; - Sym *s; - - USED(pkg); - if(debug['v']) - Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn); - - version++; - base = Boffset(f); - - if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf) - goto bad; - hdr = (ElfHdrBytes*)hdrbuf; - if(memcmp(hdr->ident, ElfMagic, 4) != 0) - goto bad; - switch(hdr->ident[5]) { - case ElfDataLsb: - e = ≤ - break; - case ElfDataMsb: - e = &be; - break; - default: - goto bad; - } - - // read header - obj = mal(sizeof *obj); - obj->e = e; - obj->f = f; - obj->base = base; - obj->len = len; - obj->name = pn; - - is64 = 0; - if(hdr->ident[4] == ElfClass64) { - ElfHdrBytes64* hdr; - - is64 = 1; - hdr = (ElfHdrBytes64*)hdrbuf; - obj->type = e->e16(hdr->type); - obj->machine = e->e16(hdr->machine); - obj->version = e->e32(hdr->version); - obj->phoff = e->e64(hdr->phoff); - obj->shoff = e->e64(hdr->shoff); - obj->flags = e->e32(hdr->flags); - obj->ehsize = e->e16(hdr->ehsize); - obj->phentsize = e->e16(hdr->phentsize); - obj->phnum = e->e16(hdr->phnum); - obj->shentsize = e->e16(hdr->shentsize); - obj->shnum = e->e16(hdr->shnum); - obj->shstrndx = e->e16(hdr->shstrndx); - } else { - obj->type = e->e16(hdr->type); - obj->machine = e->e16(hdr->machine); - obj->version = e->e32(hdr->version); - obj->entry = e->e32(hdr->entry); - obj->phoff = e->e32(hdr->phoff); - obj->shoff = e->e32(hdr->shoff); - obj->flags = e->e32(hdr->flags); - obj->ehsize = e->e16(hdr->ehsize); - obj->phentsize = e->e16(hdr->phentsize); - obj->phnum = e->e16(hdr->phnum); - obj->shentsize = e->e16(hdr->shentsize); - obj->shnum = e->e16(hdr->shnum); - obj->shstrndx = e->e16(hdr->shstrndx); - } - obj->is64 = is64; - - if(hdr->ident[6] != obj->version) - goto bad; - - if(e->e16(hdr->type) != ElfTypeRelocatable) { - diag("%s: elf but not elf relocatable object"); - return; - } - - switch(thechar) { - default: - diag("%s: elf %s unimplemented", thestring); - return; - case '5': - if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) { - diag("%s: elf object but not arm", pn); - return; - } - break; - case '6': - if(e != &le || obj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) { - diag("%s: elf object but not amd64", pn); - return; - } - break; - case '8': - if(e != &le || obj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) { - diag("%s: elf object but not 386", pn); - return; - } - break; - } - - // load section list into memory. - obj->sect = mal(obj->shnum*sizeof obj->sect[0]); - obj->nsect = obj->shnum; - for(i=0; i<obj->nsect; i++) { - if(Bseek(f, base+obj->shoff+i*obj->shentsize, 0) < 0) - goto bad; - sect = &obj->sect[i]; - if(is64) { - ElfSectBytes64 b; - - werrstr("short read"); - if(Bread(f, &b, sizeof b) != sizeof b) - goto bad; - - sect->name = (char*)(uintptr)e->e32(b.name); - sect->type = e->e32(b.type); - sect->flags = e->e64(b.flags); - sect->addr = e->e64(b.addr); - sect->off = e->e64(b.off); - sect->size = e->e64(b.size); - sect->link = e->e32(b.link); - sect->info = e->e32(b.info); - sect->align = e->e64(b.align); - sect->entsize = e->e64(b.entsize); - } else { - ElfSectBytes b; - - werrstr("short read"); - if(Bread(f, &b, sizeof b) != sizeof b) - goto bad; - - sect->name = (char*)(uintptr)e->e32(b.name); - sect->type = e->e32(b.type); - sect->flags = e->e32(b.flags); - sect->addr = e->e32(b.addr); - sect->off = e->e32(b.off); - sect->size = e->e32(b.size); - sect->link = e->e32(b.link); - sect->info = e->e32(b.info); - sect->align = e->e32(b.align); - sect->entsize = e->e32(b.entsize); - } - } - - // read section string table and translate names - if(obj->shstrndx >= obj->nsect) { - werrstr("shstrndx out of range %d >= %d", obj->shstrndx, obj->nsect); - goto bad; - } - sect = &obj->sect[obj->shstrndx]; - if(map(obj, sect) < 0) - goto bad; - for(i=0; i<obj->nsect; i++) - if(obj->sect[i].name != nil) - obj->sect[i].name = (char*)sect->base + (uintptr)obj->sect[i].name; - - // load string table for symbols into memory. - obj->symtab = section(obj, ".symtab"); - if(obj->symtab == nil) { - // our work is done here - no symbols means nothing can refer to this file - return; - } - if(obj->symtab->link <= 0 || obj->symtab->link >= obj->nsect) { - diag("%s: elf object has symbol table with invalid string table link", pn); - return; - } - obj->symstr = &obj->sect[obj->symtab->link]; - if(is64) - obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes64); - else - obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes); - - if(map(obj, obj->symtab) < 0) - goto bad; - if(map(obj, obj->symstr) < 0) - goto bad; - - // load text and data segments into memory. - // they are not as small as the section lists, but we'll need - // the memory anyway for the symbol images, so we might - // as well use one large chunk. - - // create symbols for mapped sections - for(i=0; i<obj->nsect; i++) { - sect = &obj->sect[i]; - if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc)) - continue; - if(sect->type != ElfSectNobits && map(obj, sect) < 0) - goto bad; - - name = smprint("%s(%s)", pn, sect->name); - s = lookup(name, version); - free(name); - switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) { - default: - werrstr("unexpected flags for ELF section %s", sect->name); - goto bad; - case ElfSectFlagAlloc: - s->type = SRODATA; - break; - case ElfSectFlagAlloc + ElfSectFlagWrite: - s->type = SDATA; - break; - case ElfSectFlagAlloc + ElfSectFlagExec: - s->type = STEXT; - break; - } - if(sect->type == ElfSectProgbits) { - s->p = sect->base; - s->np = sect->size; - } - s->size = sect->size; - if(s->type == STEXT) { - if(etextp) - etextp->next = s; - else - textp = s; - etextp = s; - } - sect->sym = s; - } - - // load relocations - for(i=0; i<obj->nsect; i++) { - rsect = &obj->sect[i]; - if(rsect->type != ElfSectRela && rsect->type != ElfSectRel) - continue; - if(rsect->info >= obj->nsect || obj->sect[rsect->info].base == nil) - continue; - sect = &obj->sect[rsect->info]; - if(map(obj, rsect) < 0) - goto bad; - rela = rsect->type == ElfSectRela; - n = rsect->size/(4+4*is64)/(2+rela); - r = mal(n*sizeof r[0]); - p = rsect->base; - for(j=0; j<n; j++) { - add = 0; - rp = &r[j]; - if(is64) { - // 64-bit rel/rela - rp->off = e->e64(p); - p += 8; - info = e->e64(p); - p += 8; - if(rela) { - add = e->e64(p); - p += 8; - } - } else { - // 32-bit rel/rela - rp->off = e->e32(p); - p += 4; - info = e->e32(p); - info = info>>8<<32 | (info&0xff); // convert to 64-bit info - p += 4; - if(rela) { - add = e->e32(p); - p += 4; - } - } - if(readsym(obj, info>>32, &sym) < 0) - goto bad; - if(sym.sym == nil) { - werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", - sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type); - goto bad; - } - rp->sym = sym.sym; - rp->type = reltype(pn, (uint32)info, &rp->siz); - if(rela) - rp->add = add; - else { - // load addend from image - if(rp->siz == 4) - rp->add = e->e32(sect->base+rp->off); - else if(rp->siz == 8) - rp->add = e->e64(sect->base+rp->off); - else - diag("invalid rela size %d", rp->siz); - } - } - qsort(r, n, sizeof r[0], rbyoff); // just in case - - s = sect->sym; - s->r = r; - s->nr = n; - } - - // enter sub-symbols into symbol table. - // symbol 0 is the null symbol. - for(i=1; i<obj->nsymtab; i++) { - if(readsym(obj, i, &sym) < 0) - goto bad; - if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone) - continue; - if(sym.shndx == ElfSymShnCommon) { - s = sym.sym; - if(s->size < sym.size) - s->size = sym.size; - if(s->type == 0 || s->type == SXREF) - s->type = SBSS; - continue; - } - if(sym.shndx >= obj->nsect || sym.shndx == 0) - continue; - sect = obj->sect+sym.shndx; - if(sect->sym == nil) { - diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type); - continue; - } - s = sym.sym; - s->sub = sect->sym->sub; - sect->sym->sub = s; - s->type = sect->sym->type | SSUB; - if(!s->dynexport) { - s->dynimplib = nil; // satisfy dynimport - s->dynimpname = nil; // satisfy dynimport - } - s->value = sym.value; - s->size = sym.size; - s->outer = sect->sym; - if(sect->sym->type == STEXT) { - Prog *p; - - if(s->text != P) - diag("%s: duplicate definition of %s", pn, s->name); - // build a TEXT instruction with a unique pc - // just to make the rest of the linker happy. - p = prg(); - p->as = ATEXT; - p->from.type = D_EXTERN; - p->from.sym = s; - p->textflag = 7; - p->to.type = D_CONST; - p->link = nil; - p->pc = pc++; - s->text = p; - - etextp->next = s; - etextp = s; - } - } - return; - -bad: - diag("%s: malformed elf file: %r", pn); -} - -static ElfSect* -section(ElfObj *obj, char *name) -{ - int i; - - for(i=0; i<obj->nsect; i++) - if(obj->sect[i].name && name && strcmp(obj->sect[i].name, name) == 0) - return &obj->sect[i]; - return nil; -} - -static int -map(ElfObj *obj, ElfSect *sect) -{ - if(sect->base != nil) - return 0; - - if(sect->off+sect->size > obj->len) { - werrstr("elf section past end of file"); - return -1; - } - - sect->base = mal(sect->size); - werrstr("short read"); - if(Bseek(obj->f, obj->base+sect->off, 0) < 0 || Bread(obj->f, sect->base, sect->size) != sect->size) - return -1; - - return 0; -} - -static int -readsym(ElfObj *obj, int i, ElfSym *sym) -{ - Sym *s; - - if(i >= obj->nsymtab || i < 0) { - werrstr("invalid elf symbol index"); - return -1; - } - - if(obj->is64) { - ElfSymBytes64 *b; - - b = (ElfSymBytes64*)(obj->symtab->base + i*sizeof *b); - sym->name = (char*)obj->symstr->base + obj->e->e32(b->name); - sym->value = obj->e->e64(b->value); - sym->size = obj->e->e64(b->size); - sym->shndx = obj->e->e16(b->shndx); - sym->bind = b->info>>4; - sym->type = b->info&0xf; - sym->other = b->other; - } else { - ElfSymBytes *b; - - b = (ElfSymBytes*)(obj->symtab->base + i*sizeof *b); - sym->name = (char*)obj->symstr->base + obj->e->e32(b->name); - sym->value = obj->e->e32(b->value); - sym->size = obj->e->e32(b->size); - sym->shndx = obj->e->e16(b->shndx); - sym->bind = b->info>>4; - sym->type = b->info&0xf; - sym->other = b->other; - } - - s = nil; - if(strcmp(sym->name, "_GLOBAL_OFFSET_TABLE_") == 0) - sym->name = ".got"; - if(strcmp(sym->name, "__stack_chk_fail_local") == 0) - sym->other = 0; // rewrite hidden -> default visibility - switch(sym->type) { - case ElfSymTypeSection: - s = obj->sect[sym->shndx].sym; - break; - case ElfSymTypeObject: - case ElfSymTypeFunc: - case ElfSymTypeNone: - switch(sym->bind) { - case ElfSymBindGlobal: - if(sym->other != 2) { - s = lookup(sym->name, 0); - break; - } - // fall through - case ElfSymBindLocal: - s = lookup(sym->name, version); - break; - default: - werrstr("%s: invalid symbol binding %d", sym->name, sym->bind); - return -1; - } - break; - } - if(s != nil && s->type == 0 && sym->type != ElfSymTypeSection) - s->type = SXREF; - sym->sym = s; - - return 0; -} - -int -rbyoff(const void *va, const void *vb) -{ - Reloc *a, *b; - - a = (Reloc*)va; - b = (Reloc*)vb; - if(a->off < b->off) - return -1; - if(a->off > b->off) - return +1; - return 0; -} - -#define R(x, y) ((x)|((y)<<24)) - -static int -reltype(char *pn, int elftype, uchar *siz) -{ - switch(R(thechar, elftype)) { - default: - diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype); - case R('6', R_X86_64_PC32): - case R('6', R_X86_64_PLT32): - case R('6', R_X86_64_GOTPCREL): - case R('8', R_386_32): - case R('8', R_386_PC32): - case R('8', R_386_GOT32): - case R('8', R_386_PLT32): - case R('8', R_386_GOTOFF): - case R('8', R_386_GOTPC): - *siz = 4; - break; - case R('6', R_X86_64_64): - *siz = 8; - break; - } - - return 256+elftype; -} |