diff options
Diffstat (limited to 'src/libmach/elf.c')
-rw-r--r-- | src/libmach/elf.c | 251 |
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, §b, sizeof sectb) != sizeof sectb) + || readn(fd, p, h->shentsize) != h->shentsize) goto err; - unpacksect(h, &e->sect[i], §b); + 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; |