mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-15 11:20:03 +00:00
406 lines
7.2 KiB
C
406 lines
7.2 KiB
C
|
/*
|
||
|
* 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, §b, sizeof sectb) != sizeof sectb)
|
||
|
goto err;
|
||
|
unpacksect(h, &e->sect[i], §b);
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|