plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

elf.c (10236B)


      1 /*
      2  * Parse 32-bit ELF files.
      3  * Copyright (c) 2004 Russ Cox.  See LICENSE.
      4  */
      5 
      6 #include <u.h>
      7 #include <libc.h>
      8 #include <mach.h>
      9 #include "elf.h"
     10 
     11 typedef struct ElfHdrBytes ElfHdrBytes;
     12 typedef struct ElfSectBytes ElfSectBytes;
     13 typedef struct ElfProgBytes ElfProgBytes;
     14 typedef struct ElfSymBytes ElfSymBytes;
     15 
     16 typedef struct ElfHdrBytes64 ElfHdrBytes64;
     17 typedef struct ElfSectBytes64 ElfSectBytes64;
     18 typedef struct ElfProgBytes64 ElfProgBytes64;
     19 typedef struct ElfSymBytes64 ElfSymBytes64;
     20 
     21 struct ElfHdrBytes
     22 {
     23 	uchar	ident[16];
     24 	uchar	type[2];
     25 	uchar	machine[2];
     26 	uchar	version[4];
     27 	uchar	entry[4];
     28 	uchar	phoff[4];
     29 	uchar	shoff[4];
     30 	uchar	flags[4];
     31 	uchar	ehsize[2];
     32 	uchar	phentsize[2];
     33 	uchar	phnum[2];
     34 	uchar	shentsize[2];
     35 	uchar	shnum[2];
     36 	uchar	shstrndx[2];
     37 };
     38 
     39 struct ElfHdrBytes64
     40 {
     41 	uchar	ident[16];
     42 	uchar	type[2];
     43 	uchar	machine[2];
     44 	uchar	version[4];
     45 	uchar	entry[8];
     46 	uchar	phoff[8];
     47 	uchar	shoff[8];
     48 	uchar	flags[4];
     49 	uchar	ehsize[2];
     50 	uchar	phentsize[2];
     51 	uchar	phnum[2];
     52 	uchar	shentsize[2];
     53 	uchar	shnum[2];
     54 	uchar	shstrndx[2];
     55 };
     56 
     57 struct ElfSectBytes
     58 {
     59 	uchar	name[4];
     60 	uchar	type[4];
     61 	uchar	flags[4];
     62 	uchar	addr[4];
     63 	uchar	offset[4];
     64 	uchar	size[4];
     65 	uchar	link[4];
     66 	uchar	info[4];
     67 	uchar	align[4];
     68 	uchar	entsize[4];
     69 };
     70 
     71 struct ElfSectBytes64
     72 {
     73 	uchar	name[4];
     74 	uchar	type[4];
     75 	uchar	flags[8];
     76 	uchar	addr[8];
     77 	uchar	offset[8];
     78 	uchar	size[8];
     79 	uchar	link[4];
     80 	uchar	info[4];
     81 	uchar	align[8];
     82 	uchar	entsize[8];
     83 };
     84 
     85 struct ElfSymBytes
     86 {
     87 	uchar	name[4];
     88 	uchar	value[4];
     89 	uchar	size[4];
     90 	uchar	info;	/* top4: bind, bottom4: type */
     91 	uchar	other;
     92 	uchar	shndx[2];
     93 };
     94 
     95 struct ElfSymBytes64
     96 {
     97 	uchar	name[4];
     98 	uchar	info;
     99 	uchar	other;
    100 	uchar	shndx[2];
    101 	uchar	value[8];
    102 	uchar	size[8];
    103 };
    104 
    105 struct ElfProgBytes
    106 {
    107 	uchar	type[4];
    108 	uchar	offset[4];
    109 	uchar	vaddr[4];
    110 	uchar	paddr[4];
    111 	uchar	filesz[4];
    112 	uchar	memsz[4];
    113 	uchar	flags[4];
    114 	uchar	align[4];
    115 };
    116 
    117 struct ElfProgBytes64
    118 {
    119 	uchar	type[4];
    120 	uchar	flags[4];
    121 	uchar	offset[8];
    122 	uchar	vaddr[8];
    123 	uchar	paddr[8];
    124 	uchar	filesz[8];
    125 	uchar	memsz[8];
    126 	uchar	align[8];
    127 };
    128 
    129 uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
    130 
    131 static void	unpackhdr(ElfHdr*, void*);
    132 static void	unpackprog(ElfHdr*, ElfProg*, void*);
    133 static void	unpacksect(ElfHdr*, ElfSect*, void*);
    134 
    135 static char *elftypes[] = {
    136 	"none",
    137 	"relocatable",
    138 	"executable",
    139 	"shared object",
    140 	"core",
    141 };
    142 
    143 char*
    144 elftype(int t)
    145 {
    146 	if(t < 0 || t >= nelem(elftypes))
    147 		return "unknown";
    148 	return elftypes[t];
    149 }
    150 
    151 static char *elfmachs[] = {
    152 	"none",
    153 	"32100",
    154 	"sparc",
    155 	"386",
    156 	"68000",
    157 	"88000",
    158 	"486",
    159 	"860",
    160 	"MIPS",
    161 };
    162 
    163 char*
    164 elfmachine(int t)
    165 {
    166 	if(t < 0 || t >= nelem(elfmachs))
    167 		return "unknown";
    168 	return elfmachs[t];
    169 }
    170 
    171 Elf*
    172 elfopen(char *name)
    173 {
    174 	int fd;
    175 	Elf *e;
    176 
    177 	if((fd = open(name, OREAD)) < 0)
    178 		return nil;
    179 	if((e = elfinit(fd)) == nil)
    180 		close(fd);
    181 	return e;
    182 }
    183 
    184 Elf*
    185 elfinit(int fd)
    186 {
    187 	int i;
    188 	Elf *e;
    189 	ElfHdr *h;
    190 	union {
    191 		ElfHdrBytes h32;
    192 		ElfHdrBytes64 h64;
    193 	} hdrb;
    194 	void *p = nil;
    195 	ElfSect *s;
    196 
    197 	e = mallocz(sizeof(Elf), 1);
    198 	if(e == nil)
    199 		return nil;
    200 	e->fd = fd;
    201 
    202 	/*
    203 	 * parse header
    204 	 */
    205 	seek(fd, 0, 0);
    206 	if(readn(fd, &hdrb, sizeof hdrb) != sizeof hdrb)
    207 		goto err;
    208 	h = &e->hdr;
    209 	unpackhdr(h, &hdrb);
    210 	if(h->class != ElfClass32 && h->class != ElfClass64){
    211 		werrstr("bad ELF class - not 32-bit, 64-bit");
    212 		goto err;
    213 	}
    214 	if(h->encoding != ElfDataLsb && h->encoding != ElfDataMsb){
    215 		werrstr("bad ELF encoding - not LSB, MSB");
    216 		goto err;
    217 	}
    218 	if(hdrb.h32.ident[6] != h->version){
    219 		werrstr("bad ELF encoding - version mismatch %02ux and %08ux",
    220 			(uint)hdrb.h32.ident[6], (uint)h->version);
    221 		goto err;
    222 	}
    223 
    224 	/*
    225 	 * the prog+section info is almost always small - just load it into memory.
    226 	 */
    227 	e->nprog = h->phnum;
    228 	e->prog = mallocz(sizeof(ElfProg)*e->nprog, 1);
    229 	p = mallocz(h->phentsize, 1);
    230 	for(i=0; i<e->nprog; i++){
    231 		if(seek(fd, h->phoff+i*h->phentsize, 0) < 0
    232 		|| readn(fd, p, h->phentsize) != h->phentsize)
    233 			goto err;
    234 		unpackprog(h, &e->prog[i], p);
    235 	}
    236 	free(p);
    237 	p = nil;
    238 
    239 	e->nsect = h->shnum;
    240 	if(e->nsect == 0)
    241 		goto nosects;
    242 	e->sect = mallocz(sizeof(ElfSect)*e->nsect, 1);
    243 	p = mallocz(h->shentsize, 1);
    244 	for(i=0; i<e->nsect; i++){
    245 		if(seek(fd, h->shoff+i*h->shentsize, 0) < 0
    246 		|| readn(fd, p, h->shentsize) != h->shentsize)
    247 			goto err;
    248 		unpacksect(h, &e->sect[i], p);
    249 	}
    250 	free(p);
    251 	p = nil;
    252 
    253 	if(h->shstrndx >= e->nsect){
    254 		fprint(2, "warning: bad string section index %d >= %d", h->shstrndx, e->nsect);
    255 		h->shnum = 0;
    256 		e->nsect = 0;
    257 		goto nosects;
    258 	}
    259 	s = &e->sect[h->shstrndx];
    260 	if(elfmap(e, s) < 0)
    261 		goto err;
    262 
    263 	for(i=0; i<e->nsect; i++)
    264 		if(e->sect[i].name)
    265 			e->sect[i].name = (char*)s->base + (ulong)e->sect[i].name;
    266 
    267 	e->symtab = elfsection(e, ".symtab");
    268 	if(e->symtab){
    269 		if(e->symtab->link >= e->nsect)
    270 			e->symtab = nil;
    271 		else{
    272 			e->symstr = &e->sect[e->symtab->link];
    273 			e->nsymtab = e->symtab->size / sizeof(ElfSymBytes);
    274 		}
    275 	}
    276 	e->dynsym = elfsection(e, ".dynsym");
    277 	if(e->dynsym){
    278 		if(e->dynsym->link >= e->nsect)
    279 			e->dynsym = nil;
    280 		else{
    281 			e->dynstr = &e->sect[e->dynsym->link];
    282 			e->ndynsym = e->dynsym->size / sizeof(ElfSymBytes);
    283 		}
    284 	}
    285 
    286 	e->bss = elfsection(e, ".bss");
    287 
    288 nosects:
    289 	return e;
    290 
    291 err:
    292 	free(p);
    293 	free(e->sect);
    294 	free(e->prog);
    295 	free(e->shstrtab);
    296 	free(e);
    297 	return nil;
    298 }
    299 
    300 void
    301 elfclose(Elf *elf)
    302 {
    303 	int i;
    304 
    305 	for(i=0; i<elf->nsect; i++)
    306 		free(elf->sect[i].base);
    307 	free(elf->sect);
    308 	free(elf->prog);
    309 	free(elf->shstrtab);
    310 	free(elf);
    311 }
    312 
    313 static void
    314 unpackhdr(ElfHdr *h, void *v)
    315 {
    316 	u16int (*e2)(uchar*);
    317 	u32int (*e4)(uchar*);
    318 	u64int (*e8)(uchar*);
    319 	ElfHdrBytes *b;
    320 	ElfHdrBytes64 *b64;
    321 
    322 	b = v;
    323 	memmove(h->magic, b->ident, 4);
    324 	h->class = b->ident[4];
    325 	h->encoding = b->ident[5];
    326 	switch(h->encoding){
    327 	case ElfDataLsb:
    328 		e2 = leload2;
    329 		e4 = leload4;
    330 		e8 = leload8;
    331 		break;
    332 	case ElfDataMsb:
    333 		e2 = beload2;
    334 		e4 = beload4;
    335 		e8 = beload8;
    336 		break;
    337 	default:
    338 		return;
    339 	}
    340 	h->abi = b->ident[7];
    341 	h->abiversion = b->ident[8];
    342 
    343 	h->e2 = e2;
    344 	h->e4 = e4;
    345 	h->e8 = e8;
    346 
    347 	if(h->class == ElfClass64)
    348 		goto b64;
    349 
    350 	h->type = e2(b->type);
    351 	h->machine = e2(b->machine);
    352 	h->version = e4(b->version);
    353 	h->entry = e4(b->entry);
    354 	h->phoff = e4(b->phoff);
    355 	h->shoff = e4(b->shoff);
    356 	h->flags = e4(b->flags);
    357 	h->ehsize = e2(b->ehsize);
    358 	h->phentsize = e2(b->phentsize);
    359 	h->phnum = e2(b->phnum);
    360 	h->shentsize = e2(b->shentsize);
    361 	h->shnum = e2(b->shnum);
    362 	h->shstrndx = e2(b->shstrndx);
    363 	return;
    364 
    365 b64:
    366 	b64 = v;
    367 	h->type = e2(b64->type);
    368 	h->machine = e2(b64->machine);
    369 	h->version = e4(b64->version);
    370 	h->entry = e8(b64->entry);
    371 	h->phoff = e8(b64->phoff);
    372 	h->shoff = e8(b64->shoff);
    373 	h->flags = e4(b64->flags);
    374 	h->ehsize = e2(b64->ehsize);
    375 	h->phentsize = e2(b64->phentsize);
    376 	h->phnum = e2(b64->phnum);
    377 	h->shentsize = e2(b64->shentsize);
    378 	h->shnum = e2(b64->shnum);
    379 	h->shstrndx = e2(b64->shstrndx);
    380 	return;
    381 }
    382 
    383 static void
    384 unpackprog(ElfHdr *h, ElfProg *p, void *v)
    385 {
    386 	u32int (*e4)(uchar*);
    387 	u64int (*e8)(uchar*);
    388 
    389 	if(h->class == ElfClass32) {
    390 		ElfProgBytes *b;
    391 
    392 		b = v;
    393 		e4 = h->e4;
    394 		p->type = e4(b->type);
    395 		p->offset = e4(b->offset);
    396 		p->vaddr = e4(b->vaddr);
    397 		p->paddr = e4(b->paddr);
    398 		p->filesz = e4(b->filesz);
    399 		p->memsz = e4(b->memsz);
    400 		p->flags = e4(b->flags);
    401 		p->align = e4(b->align);
    402 	} else {
    403 		ElfProgBytes64 *b;
    404 
    405 		b = v;
    406 		e4 = h->e4;
    407 		e8 = h->e8;
    408 		p->type = e4(b->type);
    409 		p->offset = e8(b->offset);
    410 		p->vaddr = e8(b->vaddr);
    411 		p->paddr = e8(b->paddr);
    412 		p->filesz = e8(b->filesz);
    413 		p->memsz = e8(b->memsz);
    414 		p->flags = e4(b->flags);
    415 		p->align = e8(b->align);
    416 	}
    417 }
    418 
    419 static void
    420 unpacksect(ElfHdr *h, ElfSect *s, void *v)
    421 {
    422 	u32int (*e4)(uchar*);
    423 	u64int (*e8)(uchar*);
    424 
    425 	if(h->class == ElfClass32) {
    426 		ElfSectBytes *b;
    427 
    428 		b = v;
    429 		e4 = h->e4;
    430 		s->name = (char*)(uintptr)e4(b->name);
    431 		s->type = e4(b->type);
    432 		s->flags = e4(b->flags);
    433 		s->addr = e4(b->addr);
    434 		s->offset = e4(b->offset);
    435 		s->size = e4(b->size);
    436 		s->link = e4(b->link);
    437 		s->info = e4(b->info);
    438 		s->align = e4(b->align);
    439 		s->entsize = e4(b->entsize);
    440 	} else {
    441 		ElfSectBytes64 *b;
    442 
    443 		b = v;
    444 		e4 = h->e4;
    445 		e8 = h->e8;
    446 		s->name = (char*)(uintptr)e4(b->name);
    447 		s->type = e4(b->type);
    448 		s->flags = e8(b->flags);
    449 		s->addr = e8(b->addr);
    450 		s->offset = e8(b->offset);
    451 		s->size = e8(b->size);
    452 		s->link = e4(b->link);
    453 		s->info = e4(b->info);
    454 		s->align = e8(b->align);
    455 		s->entsize = e8(b->entsize);
    456 	}
    457 }
    458 
    459 ElfSect*
    460 elfsection(Elf *elf, char *name)
    461 {
    462 	int i;
    463 
    464 	for(i=0; i<elf->nsect; i++){
    465 		if(elf->sect[i].name == name)
    466 			return &elf->sect[i];
    467 		if(elf->sect[i].name && name
    468 		&& strcmp(elf->sect[i].name, name) == 0)
    469 			return &elf->sect[i];
    470 	}
    471 	werrstr("elf section '%s' not found", name);
    472 	return nil;
    473 }
    474 
    475 int
    476 elfmap(Elf *elf, ElfSect *sect)
    477 {
    478 	if(sect->base)
    479 		return 0;
    480 	if((sect->base = malloc(sect->size)) == nil)
    481 		return -1;
    482 	werrstr("short read");
    483 	if(seek(elf->fd, sect->offset, 0) < 0
    484 	|| readn(elf->fd, sect->base, sect->size) != sect->size){
    485 		free(sect->base);
    486 		sect->base = nil;
    487 		return -1;
    488 	}
    489 	return 0;
    490 }
    491 
    492 int
    493 elfsym(Elf *elf, int i, ElfSym *sym)
    494 {
    495 	ElfSect *symtab, *strtab;
    496 	uchar *p;
    497 	char *s;
    498 	ulong x;
    499 
    500 	if(i < 0){
    501 		werrstr("bad index %d in elfsym", i);
    502 		return -1;
    503 	}
    504 
    505 	if(i < elf->nsymtab){
    506 		symtab = elf->symtab;
    507 		strtab = elf->symstr;
    508 	extract:
    509 		if(elfmap(elf, symtab) < 0 || elfmap(elf, strtab) < 0)
    510 			return -1;
    511 		if(elf->hdr.class == ElfClass32) {
    512 			p = symtab->base + i * sizeof(ElfSymBytes);
    513 			s = (char*)strtab->base;
    514 			x = elf->hdr.e4(p);
    515 			if(x >= strtab->size){
    516 				werrstr("bad symbol name offset 0x%lux", x);
    517 				return -1;
    518 			}
    519 			sym->name = s + x;
    520 			sym->value = elf->hdr.e4(p+4);
    521 			sym->size = elf->hdr.e4(p+8);
    522 			x = p[12];
    523 			sym->bind = x>>4;
    524 			sym->type = x & 0xF;
    525 			sym->other = p[13];
    526 			sym->shndx = elf->hdr.e2(p+14);
    527 		} else {
    528 			p = symtab->base + i * sizeof(ElfSymBytes64);
    529 			s = (char*)strtab->base;
    530 			x = elf->hdr.e4(p);
    531 			if(x >= strtab->size){
    532 				werrstr("bad symbol name offset 0x%lux", x);
    533 				return -1;
    534 			}
    535 			sym->name = s + x;
    536 			x = p[4];
    537 			sym->bind = x>>4;
    538 			sym->type = x & 0xF;
    539 			sym->other = p[5];
    540 			sym->shndx = elf->hdr.e2(p+6);
    541 			sym->value = elf->hdr.e8(p+8);
    542 			sym->size = elf->hdr.e8(p+16);
    543 		}
    544 		return 0;
    545 	}
    546 	i -= elf->nsymtab;
    547 	if(i < elf->ndynsym){
    548 		symtab = elf->dynsym;
    549 		strtab = elf->dynstr;
    550 		goto extract;
    551 	}
    552 	/* i -= elf->ndynsym */
    553 
    554 	werrstr("symbol index out of range");
    555 	return -1;
    556 }