Blob


1 /*
2 * Parse 32-bit ELF files.
3 * Copyright (c) 2004 Russ Cox. See LICENSE.
4 */
6 #include <u.h>
7 #include <libc.h>
8 #include <mach.h>
9 #include "elf.h"
11 typedef struct ElfHdrBytes ElfHdrBytes;
12 typedef struct ElfSectBytes ElfSectBytes;
13 typedef struct ElfProgBytes ElfProgBytes;
14 typedef struct ElfSymBytes ElfSymBytes;
16 struct ElfHdrBytes
17 {
18 uchar ident[16];
19 uchar type[2];
20 uchar machine[2];
21 uchar version[4];
22 uchar entry[4];
23 uchar phoff[4];
24 uchar shoff[4];
25 uchar flags[4];
26 uchar ehsize[2];
27 uchar phentsize[2];
28 uchar phnum[2];
29 uchar shentsize[2];
30 uchar shnum[2];
31 uchar shstrndx[2];
32 };
34 struct ElfSectBytes
35 {
36 uchar name[4];
37 uchar type[4];
38 uchar flags[4];
39 uchar addr[4];
40 uchar offset[4];
41 uchar size[4];
42 uchar link[4];
43 uchar info[4];
44 uchar align[4];
45 uchar entsize[4];
46 };
48 struct ElfSymBytes
49 {
50 uchar name[4];
51 uchar value[4];
52 uchar size[4];
53 uchar info; /* top4: bind, bottom4: type */
54 uchar other;
55 uchar shndx[2];
56 };
58 struct ElfProgBytes
59 {
60 uchar type[4];
61 uchar offset[4];
62 uchar vaddr[4];
63 uchar paddr[4];
64 uchar filesz[4];
65 uchar memsz[4];
66 uchar flags[4];
67 uchar align[4];
68 };
70 uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
72 static void unpackhdr(ElfHdr*, ElfHdrBytes*);
73 static void unpackprog(ElfHdr*, ElfProg*, ElfProgBytes*);
74 static void unpacksect(ElfHdr*, ElfSect*, ElfSectBytes*);
76 static char *elftypes[] = {
77 "none",
78 "relocatable",
79 "executable",
80 "shared object",
81 "core",
82 };
84 char*
85 elftype(int t)
86 {
87 if(t < 0 || t >= nelem(elftypes))
88 return "unknown";
89 return elftypes[t];
90 }
92 static char *elfmachs[] = {
93 "none",
94 "32100",
95 "sparc",
96 "386",
97 "68000",
98 "88000",
99 "486",
100 "860",
101 "MIPS",
102 };
104 char*
105 elfmachine(int t)
107 if(t < 0 || t >= nelem(elfmachs))
108 return "unknown";
109 return elfmachs[t];
112 Elf*
113 elfopen(char *name)
115 int fd;
116 Elf *e;
118 if((fd = open(name, OREAD)) < 0)
119 return nil;
120 if((e = elfinit(fd)) == nil)
121 close(fd);
122 return e;
125 Elf*
126 elfinit(int fd)
128 int i;
129 Elf *e;
130 ElfHdr *h;
131 ElfHdrBytes hdrb;
132 ElfProgBytes progb;
133 ElfSectBytes sectb;
134 ElfSect *s;
136 e = mallocz(sizeof(Elf), 1);
137 if(e == nil)
138 return nil;
139 e->fd = fd;
141 /*
142 * parse header
143 */
144 seek(fd, 0, 0);
145 if(readn(fd, &hdrb, sizeof hdrb) != sizeof hdrb)
146 goto err;
147 h = &e->hdr;
148 unpackhdr(h, &hdrb);
149 if(h->class != ElfClass32){
150 werrstr("bad ELF class - not 32-bit");
151 goto err;
153 if(h->encoding != ElfDataLsb && h->encoding != ElfDataMsb){
154 werrstr("bad ELF encoding - not LSB, MSB");
155 goto err;
157 if(hdrb.ident[6] != h->version){
158 werrstr("bad ELF encoding - version mismatch %02ux and %08ux",
159 (uint)hdrb.ident[6], (uint)h->version);
160 goto err;
163 /*
164 * the prog+section info is almost always small - just load it into memory.
165 */
166 e->nprog = h->phnum;
167 e->prog = mallocz(sizeof(ElfProg)*e->nprog, 1);
168 for(i=0; i<e->nprog; i++){
169 if(seek(fd, h->phoff+i*h->phentsize, 0) < 0
170 || readn(fd, &progb, sizeof progb) != sizeof progb)
171 goto err;
172 unpackprog(h, &e->prog[i], &progb);
175 e->nsect = h->shnum;
176 if(e->nsect == 0)
177 goto nosects;
178 e->sect = mallocz(sizeof(ElfSect)*e->nsect, 1);
179 for(i=0; i<e->nsect; i++){
180 if(seek(fd, h->shoff+i*h->shentsize, 0) < 0
181 || readn(fd, &sectb, sizeof sectb) != sizeof sectb)
182 goto err;
183 unpacksect(h, &e->sect[i], &sectb);
186 if(h->shstrndx >= e->nsect){
187 fprint(2, "warning: bad string section index %d >= %d", h->shstrndx, e->nsect);
188 h->shnum = 0;
189 e->nsect = 0;
190 goto nosects;
192 s = &e->sect[h->shstrndx];
193 if(elfmap(e, s) < 0)
194 goto err;
196 for(i=0; i<e->nsect; i++)
197 if(e->sect[i].name)
198 e->sect[i].name = (char*)s->base + (ulong)e->sect[i].name;
200 e->symtab = elfsection(e, ".symtab");
201 if(e->symtab){
202 if(e->symtab->link >= e->nsect)
203 e->symtab = nil;
204 else{
205 e->symstr = &e->sect[e->symtab->link];
206 e->nsymtab = e->symtab->size / sizeof(ElfSymBytes);
209 e->dynsym = elfsection(e, ".dynsym");
210 if(e->dynsym){
211 if(e->dynsym->link >= e->nsect)
212 e->dynsym = nil;
213 else{
214 e->dynstr = &e->sect[e->dynsym->link];
215 e->ndynsym = e->dynsym->size / sizeof(ElfSymBytes);
219 e->bss = elfsection(e, ".bss");
221 nosects:
222 return e;
224 err:
225 free(e->sect);
226 free(e->prog);
227 free(e->shstrtab);
228 free(e);
229 return nil;
232 void
233 elfclose(Elf *elf)
235 int i;
237 for(i=0; i<elf->nsect; i++)
238 free(elf->sect[i].base);
239 free(elf->sect);
240 free(elf->prog);
241 free(elf->shstrtab);
242 free(elf);
245 static void
246 unpackhdr(ElfHdr *h, ElfHdrBytes *b)
248 u16int (*e2)(uchar*);
249 u32int (*e4)(uchar*);
250 u64int (*e8)(uchar*);
252 memmove(h->magic, b->ident, 4);
253 h->class = b->ident[4];
254 h->encoding = b->ident[5];
255 switch(h->encoding){
256 case ElfDataLsb:
257 e2 = leload2;
258 e4 = leload4;
259 e8 = leload8;
260 break;
261 case ElfDataMsb:
262 e2 = beload2;
263 e4 = beload4;
264 e8 = beload8;
265 break;
266 default:
267 return;
269 h->abi = b->ident[7];
270 h->abiversion = b->ident[8];
272 h->e2 = e2;
273 h->e4 = e4;
274 h->e8 = e8;
276 h->type = e2(b->type);
277 h->machine = e2(b->machine);
278 h->version = e4(b->version);
279 h->entry = e4(b->entry);
280 h->phoff = e4(b->phoff);
281 h->shoff = e4(b->shoff);
282 h->flags = e4(b->flags);
283 h->ehsize = e2(b->ehsize);
284 h->phentsize = e2(b->phentsize);
285 h->phnum = e2(b->phnum);
286 h->shentsize = e2(b->shentsize);
287 h->shnum = e2(b->shnum);
288 h->shstrndx = e2(b->shstrndx);
291 static void
292 unpackprog(ElfHdr *h, ElfProg *p, ElfProgBytes *b)
294 u32int (*e4)(uchar*);
296 e4 = h->e4;
297 p->type = e4(b->type);
298 p->offset = e4(b->offset);
299 p->vaddr = e4(b->vaddr);
300 p->paddr = e4(b->paddr);
301 p->filesz = e4(b->filesz);
302 p->memsz = e4(b->memsz);
303 p->flags = e4(b->flags);
304 p->align = e4(b->align);
307 static void
308 unpacksect(ElfHdr *h, ElfSect *s, ElfSectBytes *b)
310 u32int (*e4)(uchar*);
312 e4 = h->e4;
313 s->name = (char*)(uintptr)e4(b->name);
314 s->type = e4(b->type);
315 s->flags = e4(b->flags);
316 s->addr = e4(b->addr);
317 s->offset = e4(b->offset);
318 s->size = e4(b->size);
319 s->link = e4(b->link);
320 s->info = e4(b->info);
321 s->align = e4(b->align);
322 s->entsize = e4(b->entsize);
325 ElfSect*
326 elfsection(Elf *elf, char *name)
328 int i;
330 for(i=0; i<elf->nsect; i++){
331 if(elf->sect[i].name == name)
332 return &elf->sect[i];
333 if(elf->sect[i].name && name
334 && strcmp(elf->sect[i].name, name) == 0)
335 return &elf->sect[i];
337 werrstr("elf section '%s' not found", name);
338 return nil;
341 int
342 elfmap(Elf *elf, ElfSect *sect)
344 if(sect->base)
345 return 0;
346 if((sect->base = malloc(sect->size)) == nil)
347 return -1;
348 werrstr("short read");
349 if(seek(elf->fd, sect->offset, 0) < 0
350 || readn(elf->fd, sect->base, sect->size) != sect->size){
351 free(sect->base);
352 sect->base = nil;
353 return -1;
355 return 0;
358 int
359 elfsym(Elf *elf, int i, ElfSym *sym)
361 ElfSect *symtab, *strtab;
362 uchar *p;
363 char *s;
364 ulong x;
366 if(i < 0){
367 werrstr("bad index %d in elfsym", i);
368 return -1;
371 if(i < elf->nsymtab){
372 symtab = elf->symtab;
373 strtab = elf->symstr;
374 extract:
375 if(elfmap(elf, symtab) < 0 || elfmap(elf, strtab) < 0)
376 return -1;
377 p = symtab->base + i * sizeof(ElfSymBytes);
378 s = (char*)strtab->base;
379 x = elf->hdr.e4(p);
380 if(x >= strtab->size){
381 werrstr("bad symbol name offset 0x%lux", x);
382 return -1;
384 sym->name = s + x;
385 sym->value = elf->hdr.e4(p+4);
386 sym->size = elf->hdr.e4(p+8);
387 x = p[12];
388 sym->bind = x>>4;
389 sym->type = x & 0xF;
390 sym->other = p[13];
391 sym->shndx = elf->hdr.e2(p+14);
392 return 0;
394 i -= elf->nsymtab;
395 if(i < elf->ndynsym){
396 symtab = elf->dynsym;
397 strtab = elf->dynstr;
398 goto extract;
400 /* i -= elf->ndynsym */
402 werrstr("symbol index out of range");
403 return -1;