aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/elf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmach/elf.c')
-rw-r--r--src/libmach/elf.c251
1 files changed, 200 insertions, 51 deletions
diff --git a/src/libmach/elf.c b/src/libmach/elf.c
index 72c0bd3e..2459a291 100644
--- a/src/libmach/elf.c
+++ b/src/libmach/elf.c
@@ -13,6 +13,11 @@ 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];
@@ -31,6 +36,24 @@ struct ElfHdrBytes
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];
@@ -45,6 +68,20 @@ struct ElfSectBytes
uchar entsize[4];
};
+struct ElfSectBytes64
+{
+ uchar name[4];
+ uchar type[4];
+ uchar flags[8];
+ uchar addr[8];
+ uchar offset[8];
+ uchar size[8];
+ uchar link[4];
+ uchar info[4];
+ uchar align[8];
+ uchar entsize[8];
+};
+
struct ElfSymBytes
{
uchar name[4];
@@ -55,6 +92,16 @@ struct ElfSymBytes
uchar shndx[2];
};
+struct ElfSymBytes64
+{
+ uchar name[4];
+ uchar info;
+ uchar other;
+ uchar shndx[2];
+ uchar value[8];
+ uchar size[8];
+};
+
struct ElfProgBytes
{
uchar type[4];
@@ -67,11 +114,23 @@ struct ElfProgBytes
uchar align[4];
};
+struct ElfProgBytes64
+{
+ uchar type[4];
+ uchar flags[4];
+ uchar offset[8];
+ uchar vaddr[8];
+ uchar paddr[8];
+ uchar filesz[8];
+ uchar memsz[8];
+ uchar align[8];
+};
+
uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
-static void unpackhdr(ElfHdr*, ElfHdrBytes*);
-static void unpackprog(ElfHdr*, ElfProg*, ElfProgBytes*);
-static void unpacksect(ElfHdr*, ElfSect*, ElfSectBytes*);
+static void unpackhdr(ElfHdr*, void*);
+static void unpackprog(ElfHdr*, ElfProg*, void*);
+static void unpacksect(ElfHdr*, ElfSect*, void*);
static char *elftypes[] = {
"none",
@@ -128,9 +187,11 @@ elfinit(int fd)
int i;
Elf *e;
ElfHdr *h;
- ElfHdrBytes hdrb;
- ElfProgBytes progb;
- ElfSectBytes sectb;
+ union {
+ ElfHdrBytes h32;
+ ElfHdrBytes64 h64;
+ } hdrb;
+ void *p;
ElfSect *s;
e = mallocz(sizeof(Elf), 1);
@@ -146,17 +207,17 @@ elfinit(int fd)
goto err;
h = &e->hdr;
unpackhdr(h, &hdrb);
- if(h->class != ElfClass32){
- werrstr("bad ELF class - not 32-bit");
+ if(h->class != ElfClass32 && h->class != ElfClass64){
+ werrstr("bad ELF class - not 32-bit, 64-bit");
goto err;
}
if(h->encoding != ElfDataLsb && h->encoding != ElfDataMsb){
werrstr("bad ELF encoding - not LSB, MSB");
goto err;
}
- if(hdrb.ident[6] != h->version){
+ if(hdrb.h32.ident[6] != h->version){
werrstr("bad ELF encoding - version mismatch %02ux and %08ux",
- (uint)hdrb.ident[6], (uint)h->version);
+ (uint)hdrb.h32.ident[6], (uint)h->version);
goto err;
}
@@ -165,23 +226,27 @@ elfinit(int fd)
*/
e->nprog = h->phnum;
e->prog = mallocz(sizeof(ElfProg)*e->nprog, 1);
+ p = mallocz(h->phentsize, 1);
for(i=0; i<e->nprog; i++){
if(seek(fd, h->phoff+i*h->phentsize, 0) < 0
- || readn(fd, &progb, sizeof progb) != sizeof progb)
+ || readn(fd, p, h->phentsize) != h->phentsize)
goto err;
- unpackprog(h, &e->prog[i], &progb);
+ unpackprog(h, &e->prog[i], p);
}
+ free(p);
e->nsect = h->shnum;
if(e->nsect == 0)
goto nosects;
e->sect = mallocz(sizeof(ElfSect)*e->nsect, 1);
+ p = mallocz(h->shentsize, 1);
for(i=0; i<e->nsect; i++){
if(seek(fd, h->shoff+i*h->shentsize, 0) < 0
- || readn(fd, &sectb, sizeof sectb) != sizeof sectb)
+ || readn(fd, p, h->shentsize) != h->shentsize)
goto err;
- unpacksect(h, &e->sect[i], &sectb);
+ unpacksect(h, &e->sect[i], p);
}
+ free(p);
if(h->shstrndx >= e->nsect){
fprint(2, "warning: bad string section index %d >= %d", h->shstrndx, e->nsect);
@@ -243,12 +308,15 @@ elfclose(Elf *elf)
}
static void
-unpackhdr(ElfHdr *h, ElfHdrBytes *b)
+unpackhdr(ElfHdr *h, void *v)
{
u16int (*e2)(uchar*);
u32int (*e4)(uchar*);
u64int (*e8)(uchar*);
+ ElfHdrBytes *b;
+ ElfHdrBytes64 *b64;
+ b = v;
memmove(h->magic, b->ident, 4);
h->class = b->ident[4];
h->encoding = b->ident[5];
@@ -273,6 +341,9 @@ unpackhdr(ElfHdr *h, ElfHdrBytes *b)
h->e4 = e4;
h->e8 = e8;
+ if(h->class == ElfClass64)
+ goto b64;
+
h->type = e2(b->type);
h->machine = e2(b->machine);
h->version = e4(b->version);
@@ -286,40 +357,100 @@ unpackhdr(ElfHdr *h, ElfHdrBytes *b)
h->shentsize = e2(b->shentsize);
h->shnum = e2(b->shnum);
h->shstrndx = e2(b->shstrndx);
+ return;
+
+b64:
+ b64 = v;
+ h->type = e2(b64->type);
+ h->machine = e2(b64->machine);
+ h->version = e4(b64->version);
+ h->entry = e8(b64->entry);
+ h->phoff = e8(b64->phoff);
+ h->shoff = e8(b64->shoff);
+ h->flags = e4(b64->flags);
+ h->ehsize = e2(b64->ehsize);
+ h->phentsize = e2(b64->phentsize);
+ h->phnum = e2(b64->phnum);
+ h->shentsize = e2(b64->shentsize);
+ h->shnum = e2(b64->shnum);
+ h->shstrndx = e2(b64->shstrndx);
+ return;
}
static void
-unpackprog(ElfHdr *h, ElfProg *p, ElfProgBytes *b)
+unpackprog(ElfHdr *h, ElfProg *p, void *v)
{
u32int (*e4)(uchar*);
+ u64int (*e8)(uchar*);
- e4 = h->e4;
- p->type = e4(b->type);
- p->offset = e4(b->offset);
- p->vaddr = e4(b->vaddr);
- p->paddr = e4(b->paddr);
- p->filesz = e4(b->filesz);
- p->memsz = e4(b->memsz);
- p->flags = e4(b->flags);
- p->align = e4(b->align);
+ if(h->class == ElfClass32) {
+ ElfProgBytes *b;
+
+ b = v;
+ e4 = h->e4;
+ p->type = e4(b->type);
+ p->offset = e4(b->offset);
+ p->vaddr = e4(b->vaddr);
+ p->paddr = e4(b->paddr);
+ p->filesz = e4(b->filesz);
+ p->memsz = e4(b->memsz);
+ p->flags = e4(b->flags);
+ p->align = e4(b->align);
+ } else {
+ ElfProgBytes64 *b;
+
+ b = v;
+ e4 = h->e4;
+ e8 = h->e8;
+ p->type = e4(b->type);
+ p->offset = e8(b->offset);
+ p->vaddr = e8(b->vaddr);
+ p->paddr = e8(b->paddr);
+ p->filesz = e8(b->filesz);
+ p->memsz = e8(b->memsz);
+ p->flags = e4(b->flags);
+ p->align = e8(b->align);
+ }
}
static void
-unpacksect(ElfHdr *h, ElfSect *s, ElfSectBytes *b)
+unpacksect(ElfHdr *h, ElfSect *s, void *v)
{
u32int (*e4)(uchar*);
+ u64int (*e8)(uchar*);
- e4 = h->e4;
- s->name = (char*)(uintptr)e4(b->name);
- s->type = e4(b->type);
- s->flags = e4(b->flags);
- s->addr = e4(b->addr);
- s->offset = e4(b->offset);
- s->size = e4(b->size);
- s->link = e4(b->link);
- s->info = e4(b->info);
- s->align = e4(b->align);
- s->entsize = e4(b->entsize);
+ if(h->class == ElfClass32) {
+ ElfSectBytes *b;
+
+ b = v;
+ e4 = h->e4;
+ s->name = (char*)(uintptr)e4(b->name);
+ s->type = e4(b->type);
+ s->flags = e4(b->flags);
+ s->addr = e4(b->addr);
+ s->offset = e4(b->offset);
+ s->size = e4(b->size);
+ s->link = e4(b->link);
+ s->info = e4(b->info);
+ s->align = e4(b->align);
+ s->entsize = e4(b->entsize);
+ } else {
+ ElfSectBytes64 *b;
+
+ b = v;
+ e4 = h->e4;
+ e8 = h->e8;
+ s->name = (char*)(uintptr)e4(b->name);
+ s->type = e4(b->type);
+ s->flags = e8(b->flags);
+ s->addr = e8(b->addr);
+ s->offset = e8(b->offset);
+ s->size = e8(b->size);
+ s->link = e4(b->link);
+ s->info = e4(b->info);
+ s->align = e8(b->align);
+ s->entsize = e8(b->entsize);
+ }
}
ElfSect*
@@ -374,21 +505,39 @@ elfsym(Elf *elf, int i, ElfSym *sym)
extract:
if(elfmap(elf, symtab) < 0 || elfmap(elf, strtab) < 0)
return -1;
- p = symtab->base + i * sizeof(ElfSymBytes);
- s = (char*)strtab->base;
- x = elf->hdr.e4(p);
- if(x >= strtab->size){
- werrstr("bad symbol name offset 0x%lux", x);
- return -1;
+ if(elf->hdr.class == ElfClass32) {
+ p = symtab->base + i * sizeof(ElfSymBytes);
+ s = (char*)strtab->base;
+ x = elf->hdr.e4(p);
+ if(x >= strtab->size){
+ werrstr("bad symbol name offset 0x%lux", x);
+ return -1;
+ }
+ sym->name = s + x;
+ sym->value = elf->hdr.e4(p+4);
+ sym->size = elf->hdr.e4(p+8);
+ x = p[12];
+ sym->bind = x>>4;
+ sym->type = x & 0xF;
+ sym->other = p[13];
+ sym->shndx = elf->hdr.e2(p+14);
+ } else {
+ p = symtab->base + i * sizeof(ElfSymBytes64);
+ s = (char*)strtab->base;
+ x = elf->hdr.e4(p);
+ if(x >= strtab->size){
+ werrstr("bad symbol name offset 0x%lux", x);
+ return -1;
+ }
+ sym->name = s + x;
+ x = p[4];
+ sym->bind = x>>4;
+ sym->type = x & 0xF;
+ sym->other = p[5];
+ sym->shndx = elf->hdr.e2(p+6);
+ sym->value = elf->hdr.e8(p+8);
+ sym->size = elf->hdr.e8(p+16);
}
- sym->name = s + x;
- sym->value = elf->hdr.e4(p+4);
- sym->size = elf->hdr.e4(p+8);
- x = p[12];
- sym->bind = x>>4;
- sym->type = x & 0xF;
- sym->other = p[13];
- sym->shndx = elf->hdr.e2(p+14);
return 0;
}
i -= elf->nsymtab;