| /* | |
| 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; | |
| 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(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; | |
| } |