aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/elf.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-04-19 19:29:25 +0000
committerrsc <devnull@localhost>2004-04-19 19:29:25 +0000
commita84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 (patch)
tree59a0e921597e5aa53e83d487c16727a7bf01547a /src/libmach/elf.c
parent0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff)
downloadplan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip
libmach
Diffstat (limited to 'src/libmach/elf.c')
-rw-r--r--src/libmach/elf.c405
1 files changed, 405 insertions, 0 deletions
diff --git a/src/libmach/elf.c b/src/libmach/elf.c
new file mode 100644
index 00000000..6a387fd3
--- /dev/null
+++ b/src/libmach/elf.c
@@ -0,0 +1,405 @@
+/*
+ * Parse 32-bit ELF files.
+ * Copyright (c) 2004 Russ Cox. See LICENSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <mach.h>
+#include "elf.h"
+
+typedef struct ElfHdrBytes ElfHdrBytes;
+typedef struct ElfSectBytes ElfSectBytes;
+typedef struct ElfProgBytes ElfProgBytes;
+typedef struct ElfSymBytes ElfSymBytes;
+
+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 ElfSectBytes
+{
+ uchar name[4];
+ uchar type[4];
+ uchar flags[4];
+ uchar addr[4];
+ uchar offset[4];
+ uchar size[4];
+ uchar link[4];
+ uchar info[4];
+ uchar align[4];
+ uchar entsize[4];
+};
+
+struct ElfSymBytes
+{
+ uchar name[4];
+ uchar value[4];
+ uchar size[4];
+ uchar info; /* top4: bind, bottom4: type */
+ uchar other;
+ uchar shndx[2];
+};
+
+struct ElfProgBytes
+{
+ uchar type[4];
+ uchar offset[4];
+ uchar vaddr[4];
+ uchar paddr[4];
+ uchar filesz[4];
+ uchar memsz[4];
+ uchar flags[4];
+ uchar align[4];
+};
+
+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 char *elftypes[] = {
+ "none",
+ "relocatable",
+ "executable",
+ "shared object",
+ "core",
+};
+
+char*
+elftype(int t)
+{
+ if(t < 0 || t >= nelem(elftypes))
+ return "unknown";
+ return elftypes[t];
+}
+
+static char *elfmachs[] = {
+ "none",
+ "32100",
+ "sparc",
+ "386",
+ "68000",
+ "88000",
+ "486",
+ "860",
+ "MIPS",
+};
+
+char*
+elfmachine(int t)
+{
+ if(t < 0 || t >= nelem(elfmachs))
+ return "unknown";
+ return elfmachs[t];
+}
+
+Elf*
+elfopen(char *name)
+{
+ int fd;
+ Elf *e;
+
+ if((fd = open(name, OREAD)) < 0)
+ return nil;
+ if((e = elfinit(fd)) == nil)
+ close(fd);
+ return e;
+}
+
+Elf*
+elfinit(int fd)
+{
+ int i;
+ Elf *e;
+ ElfHdr *h;
+ ElfHdrBytes hdrb;
+ ElfProgBytes progb;
+ ElfSectBytes sectb;
+ ElfSect *s;
+
+ e = mallocz(sizeof(Elf), 1);
+ if(e == nil)
+ return nil;
+ e->fd = fd;
+
+ /*
+ * parse header
+ */
+ seek(fd, 0, 0);
+ if(readn(fd, &hdrb, sizeof hdrb) != sizeof hdrb)
+ goto err;
+ h = &e->hdr;
+ unpackhdr(h, &hdrb);
+ if(h->class != ElfClass32){
+ werrstr("bad ELF class - not 32-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){
+ werrstr("bad ELF encoding - version mismatch %02ux and %08ux",
+ (uint)hdrb.ident[6], (uint)h->version);
+ goto err;
+ }
+
+ /*
+ * the prog+section info is almost always small - just load it into memory.
+ */
+ e->nprog = h->phnum;
+ e->prog = mallocz(sizeof(ElfProg)*e->nprog, 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)
+ goto err;
+ unpackprog(h, &e->prog[i], &progb);
+ }
+
+ e->nsect = h->shnum;
+ if(e->nsect == 0)
+ goto nosects;
+ e->sect = mallocz(sizeof(ElfSect)*e->nsect, 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)
+ goto err;
+ unpacksect(h, &e->sect[i], &sectb);
+ }
+
+ if(h->shstrndx >= e->nsect){
+ fprint(2, "warning: bad string section index %d >= %d", h->shstrndx, e->nsect);
+ h->shnum = 0;
+ e->nsect = 0;
+ goto nosects;
+ }
+ s = &e->sect[h->shstrndx];
+ if(elfmap(e, s) < 0)
+ goto err;
+
+ for(i=0; i<e->nsect; i++)
+ if(e->sect[i].name)
+ e->sect[i].name = s->base + (ulong)e->sect[i].name;
+
+ e->symtab = elfsection(e, ".symtab");
+ if(e->symtab){
+ if(e->symtab->link >= e->nsect)
+ e->symtab = nil;
+ else{
+ e->symstr = &e->sect[e->symtab->link];
+ e->nsymtab = e->symtab->size / sizeof(ElfSymBytes);
+ }
+ }
+ e->dynsym = elfsection(e, ".dynsym");
+ if(e->dynsym){
+ if(e->dynsym->link >= e->nsect)
+ e->dynsym = nil;
+ else{
+ e->dynstr = &e->sect[e->dynsym->link];
+ e->ndynsym = e->dynsym->size / sizeof(ElfSymBytes);
+ }
+ }
+
+ e->bss = elfsection(e, ".bss");
+
+nosects:
+ return e;
+
+err:
+ free(e->sect);
+ free(e->prog);
+ free(e->shstrtab);
+ free(e);
+ return nil;
+}
+
+void
+elfclose(Elf *elf)
+{
+ int i;
+
+ for(i=0; i<elf->nsect; i++)
+ free(elf->sect[i].base);
+ free(elf->sect);
+ free(elf->prog);
+ free(elf->shstrtab);
+ free(elf);
+}
+
+static void
+unpackhdr(ElfHdr *h, ElfHdrBytes *b)
+{
+ u16int (*e2)(uchar*);
+ u32int (*e4)(uchar*);
+ u64int (*e8)(uchar*);
+
+ memmove(h->magic, b->ident, 4);
+ h->class = b->ident[4];
+ h->encoding = b->ident[5];
+ switch(h->encoding){
+ case ElfDataLsb:
+ e2 = leload2;
+ e4 = leload4;
+ e8 = leload8;
+ break;
+ case ElfDataMsb:
+ e2 = beload2;
+ e4 = beload4;
+ e8 = beload8;
+ break;
+ default:
+ return;
+ }
+ h->abi = b->ident[7];
+ h->abiversion = b->ident[8];
+
+ h->e2 = e2;
+ h->e4 = e4;
+ h->e8 = e8;
+
+ h->type = e2(b->type);
+ h->machine = e2(b->machine);
+ h->version = e4(b->version);
+ h->entry = e4(b->entry);
+ h->phoff = e4(b->phoff);
+ h->shoff = e4(b->shoff);
+ h->flags = e4(b->flags);
+ h->ehsize = e2(b->ehsize);
+ h->phentsize = e2(b->phentsize);
+ h->phnum = e2(b->phnum);
+ h->shentsize = e2(b->shentsize);
+ h->shnum = e2(b->shnum);
+ h->shstrndx = e2(b->shstrndx);
+}
+
+static void
+unpackprog(ElfHdr *h, ElfProg *p, ElfProgBytes *b)
+{
+ u32int (*e4)(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);
+}
+
+static void
+unpacksect(ElfHdr *h, ElfSect *s, ElfSectBytes *b)
+{
+ u32int (*e4)(uchar*);
+
+ e4 = h->e4;
+ s->name = (char*)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);
+}
+
+ElfSect*
+elfsection(Elf *elf, char *name)
+{
+ int i;
+
+ for(i=0; i<elf->nsect; i++){
+ if(elf->sect[i].name == name)
+ return &elf->sect[i];
+ if(elf->sect[i].name && name
+ && strcmp(elf->sect[i].name, name) == 0)
+ return &elf->sect[i];
+ }
+ werrstr("elf section '%s' not found", name);
+ return nil;
+}
+
+int
+elfmap(Elf *elf, ElfSect *sect)
+{
+ if(sect->base)
+ return 0;
+ if((sect->base = malloc(sect->size)) == nil)
+ return -1;
+ werrstr("short read");
+ if(seek(elf->fd, sect->offset, 0) < 0
+ || readn(elf->fd, sect->base, sect->size) != sect->size){
+ free(sect->base);
+ sect->base = nil;
+ return -1;
+ }
+ return 0;
+}
+
+int
+elfsym(Elf *elf, int i, ElfSym *sym)
+{
+ ElfSect *symtab, *strtab;
+ uchar *p;
+ char *s;
+ ulong x;
+
+ if(i < 0){
+ werrstr("bad index %d in elfsym", i);
+ return -1;
+ }
+
+ if(i < elf->nsymtab){
+ symtab = elf->symtab;
+ strtab = elf->symstr;
+ extract:
+ if(elfmap(elf, symtab) < 0 || elfmap(elf, strtab) < 0)
+ return -1;
+ p = symtab->base + i * sizeof(ElfSymBytes);
+ s = 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);
+ return 0;
+ }
+ i -= elf->nsymtab;
+ if(i < elf->ndynsym){
+ symtab = elf->dynsym;
+ strtab = elf->dynstr;
+ goto extract;
+ }
+ /* i -= elf->ndynsym */
+
+ werrstr("symbol index out of range");
+ return -1;
+}
+