mirror of
https://github.com/golang/go
synced 2024-11-21 19:04:44 -07:00
ld: reading of ELF object files
R=iant CC=golang-dev https://golang.org/cl/3507041
This commit is contained in:
parent
7431a3165e
commit
4d8d6d5cda
822
src/cmd/ld/ldelf.c
Normal file
822
src/cmd/ld/ldelf.c
Normal file
@ -0,0 +1,822 @@
|
||||
/*
|
||||
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, *dp;
|
||||
ElfHdrBytes *hdr;
|
||||
ElfObj *obj;
|
||||
ElfSect *sect, *rsect, *text, *data, *bss, *rodata;
|
||||
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) {
|
||||
diag("%s: elf object has no symbol table", pn);
|
||||
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.
|
||||
text = section(obj, ".text");
|
||||
if(text && map(obj, text) < 0)
|
||||
goto bad;
|
||||
data = section(obj, ".data");
|
||||
if(data && map(obj, data) < 0)
|
||||
goto bad;
|
||||
bss = section(obj, ".bss");
|
||||
rodata = section(obj, ".rodata");
|
||||
if(rodata && map(obj, rodata) < 0)
|
||||
goto bad;
|
||||
|
||||
// create symbols for mapped sections
|
||||
for(i=0; i<obj->nsect; i++) {
|
||||
sect = &obj->sect[i];
|
||||
if(sect->type != ElfSectProgbits || !(sect->flags&ElfSectFlagAlloc))
|
||||
continue;
|
||||
if(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;
|
||||
}
|
||||
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;
|
||||
dp = sect->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("reloc of invalid sym %s shndx=%d type=%d", 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;
|
||||
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.
|
||||
// TODO: this is too 6l-specific ?
|
||||
p = prg();
|
||||
p->as = ATEXT;
|
||||
p->from.type = D_EXTERN;
|
||||
p->from.sym = s;
|
||||
p->from.scale = 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user