elfread.c - scc - simple c99 compiler
(HTM) git clone git://git.simple-cc.org/scc
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) LICENSE
---
elfread.c (14837B)
---
1 #include <assert.h>
2 #include <errno.h>
3 #include <limits.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <scc/mach.h>
9 #include <scc/elf.h>
10
11 #include <scc/elf/elftypes.h>
12 #include <scc/elf/elfhdr.h>
13 #include <scc/elf/elfphdr.h>
14 #include <scc/elf/elfshdr.h>
15 #include <scc/elf/elfent.h>
16 #include <scc/elf/elfrel.h>
17
18 #include "../libmach.h"
19 #include "fun.h"
20
21 struct elfunpack {
22 void (*hdr)(int, unsigned char *, Elfhdr *);
23 void (*phdr)(int, unsigned char *, Elfphdr *);
24 void (*sec)(int, unsigned char *, Elfsec *);
25 void (*sym)(int, unsigned char *, Elfsym *);
26 void (*rel)(int, unsigned char *, Elfrel *);
27 void (*rela)(int, unsigned char *, Elfrel *);
28
29 int hdrsiz;
30 int phdrsiz;
31 int shentsiz;
32 int symsiz;
33 int relsiz;
34 int relasiz;
35 };
36
37 struct elfunpack unpack64;
38 struct elfunpack unpack32;
39
40 static void
41 unpack_hdr64(int order, unsigned char *buf, Elfhdr *hdr)
42 {
43 Elf64_Ehdr ehdr;
44 int n;
45
46 n = unpack(order,
47 buf,
48 "'16sslqqqlssssss",
49 ehdr.e_ident,
50 &ehdr.e_type,
51 &ehdr.e_machine,
52 &ehdr.e_version,
53 &ehdr.e_entry,
54 &ehdr.e_phoff,
55 &ehdr.e_shoff,
56 &ehdr.e_flags,
57 &ehdr.e_ehsize,
58 &ehdr.e_phentsize,
59 &ehdr.e_phnum,
60 &ehdr.e_shentsize,
61 &ehdr.e_shnum,
62 &ehdr.e_shstrndx);
63
64 assert(n == ELFH64SZ);
65
66 memcpy(hdr->ident, ehdr.e_ident, EI_NIDENT);
67 hdr->type = ehdr.e_type;
68 hdr->machine = ehdr.e_machine;
69 hdr->version = ehdr.e_version;
70 hdr->entry = ehdr.e_entry;
71 hdr->phoff = ehdr.e_phoff;
72 hdr->shoff = ehdr.e_shoff;
73 hdr->flags = ehdr.e_flags;
74 hdr->ehsize = ehdr.e_ehsize;
75 hdr->phentsize = ehdr.e_phentsize;
76 hdr->phnum = ehdr.e_phnum;
77 hdr->shentsize = ehdr.e_shentsize;
78 hdr->shnum = ehdr.e_shnum;
79 hdr->shstrndx = ehdr.e_shstrndx;
80 }
81
82 static void
83 unpack_hdr32(int order, unsigned char *buf, Elfhdr *hdr)
84 {
85 Elf32_Ehdr ehdr;
86 int n;
87
88 n = unpack(order,
89 buf,
90 "'16sslllllssssss",
91 ehdr.e_ident,
92 &ehdr.e_type,
93 &ehdr.e_machine,
94 &ehdr.e_version,
95 &ehdr.e_entry,
96 &ehdr.e_phoff,
97 &ehdr.e_shoff,
98 &ehdr.e_flags,
99 &ehdr.e_ehsize,
100 &ehdr.e_phentsize,
101 &ehdr.e_phnum,
102 &ehdr.e_shentsize,
103 &ehdr.e_shnum,
104 &ehdr.e_shstrndx);
105
106 assert(n == ELFH32SZ);
107
108 memcpy(hdr->ident, ehdr.e_ident, EI_NIDENT);
109 hdr->type = ehdr.e_type;
110 hdr->machine = ehdr.e_machine;
111 hdr->version = ehdr.e_version;
112 hdr->entry = ehdr.e_entry;
113 hdr->phoff = ehdr.e_phoff;
114 hdr->shoff = ehdr.e_shoff;
115 hdr->flags = ehdr.e_flags;
116 hdr->ehsize = ehdr.e_ehsize;
117 hdr->phentsize = ehdr.e_phentsize;
118 hdr->phnum = ehdr.e_phnum;
119 hdr->shentsize = ehdr.e_shentsize;
120 hdr->shnum = ehdr.e_shnum;
121 hdr->shstrndx = ehdr.e_shstrndx;
122 }
123
124 static void
125 unpack_phdr64(int order, unsigned char *buf, Elfphdr *hdr)
126 {
127 int n;
128 Elf64_Phdr phdr;
129
130 n = unpack(order,
131 buf,
132 "llqqqqqq",
133 &phdr.p_type,
134 &phdr.p_flags,
135 &phdr.p_offset,
136 &phdr.p_vaddr,
137 &phdr.p_paddr,
138 &phdr.p_filesz,
139 &phdr.p_memsz,
140 &phdr.p_align);
141
142 assert(n == ELFP64SZ);
143
144 hdr->type = phdr.p_type;
145 hdr->flags = phdr.p_flags;
146 hdr->offset = phdr.p_offset;
147 hdr->vaddr = phdr.p_vaddr;
148 hdr->paddr = phdr.p_paddr;
149 hdr->filesz = phdr.p_filesz;
150 hdr->memsz = phdr.p_memsz;
151 hdr->align = phdr.p_align;
152 }
153
154 static void
155 unpack_phdr32(int order, unsigned char *buf, Elfphdr *hdr)
156 {
157 int n;
158 Elf32_Phdr phdr;
159
160 n = unpack(order,
161 buf,
162 "llllllll",
163 &phdr.p_type,
164 &phdr.p_offset,
165 &phdr.p_vaddr,
166 &phdr.p_paddr,
167 &phdr.p_filesz,
168 &phdr.p_memsz,
169 &phdr.p_flags,
170 &phdr.p_align);
171
172 assert(n == ELFP32SZ);
173
174 hdr->type = phdr.p_type;
175 hdr->flags = phdr.p_flags;
176 hdr->offset = phdr.p_offset;
177 hdr->vaddr = phdr.p_vaddr;
178 hdr->paddr = phdr.p_paddr;
179 hdr->filesz = phdr.p_filesz;
180 hdr->memsz = phdr.p_memsz;
181 hdr->align = phdr.p_align;
182 }
183
184 static void
185 unpack_shdr64(int order, unsigned char *buf, Elfsec *sec)
186 {
187 int n;
188 Elf64_Shdr shdr;
189
190 n = unpack(order,
191 buf,
192 "llqqqqllqq",
193 &shdr.sh_name,
194 &shdr.sh_type,
195 &shdr.sh_flags,
196 &shdr.sh_addr,
197 &shdr.sh_offset,
198 &shdr.sh_size,
199 &shdr.sh_link,
200 &shdr.sh_info,
201 &shdr.sh_addralign,
202 &shdr.sh_entsize);
203
204 assert(n == ELFS64SZ);
205
206 sec->sh_name = shdr.sh_name;
207 sec->type = shdr.sh_type;
208 sec->flags = shdr.sh_flags;
209 sec->addr = shdr.sh_addr;
210 sec->offset = shdr.sh_offset;
211 sec->size = shdr.sh_size;
212 sec->link = shdr.sh_link;
213 sec->info = shdr.sh_info;
214 sec->addralign = shdr.sh_addralign;
215 sec->entsize = shdr.sh_entsize;
216 }
217
218 static void
219 unpack_shdr32(int order, unsigned char *buf, Elfsec *sec)
220 {
221 int n;
222 Elf32_Shdr shdr;
223
224 n = unpack(order,
225 buf,
226 "llllllllll",
227 &shdr.sh_name,
228 &shdr.sh_type,
229 &shdr.sh_flags,
230 &shdr.sh_addr,
231 &shdr.sh_offset,
232 &shdr.sh_size,
233 &shdr.sh_link,
234 &shdr.sh_info,
235 &shdr.sh_addralign,
236 &shdr.sh_entsize);
237
238 assert(n == ELFS32SZ);
239
240 sec->sh_name = shdr.sh_name;
241 sec->type = shdr.sh_type;
242 sec->flags = shdr.sh_flags;
243 sec->addr = shdr.sh_addr;
244 sec->offset = shdr.sh_offset;
245 sec->size = shdr.sh_size;
246 sec->link = shdr.sh_link;
247 sec->info = shdr.sh_info;
248 sec->addralign = shdr.sh_addralign;
249 sec->entsize = shdr.sh_entsize;
250 }
251
252 static void
253 unpack_sym64(int order, unsigned char *buf, Elfsym *sym)
254 {
255 int n;
256 Elf64_Sym ent;
257
258 n = unpack(order,
259 buf,
260 "lccsqq",
261 &ent.st_name,
262 &ent.st_info,
263 &ent.st_other,
264 &ent.st_shndx,
265 &ent.st_value,
266 &ent.st_size);
267
268 assert(n == ELFE64SZ);
269
270 sym->st_name = ent.st_name;
271 sym->info = ent.st_info;
272 sym->other = ent.st_other;
273 sym->shndx = ent.st_shndx;
274 sym->value = ent.st_value;
275 sym->size = ent.st_size;
276 }
277
278 static void
279 unpack_sym32(int order, unsigned char *buf, Elfsym *sym)
280 {
281 int n;
282 Elf32_Sym ent;
283
284 n = unpack(order,
285 buf,
286 "lllccs",
287 &ent.st_name,
288 &ent.st_value,
289 &ent.st_size,
290 &ent.st_info,
291 &ent.st_other,
292 &ent.st_shndx);
293
294 assert(n == ELFE32SZ);
295
296 sym->st_name = ent.st_name;
297 sym->info = ent.st_info;
298 sym->other = ent.st_other;
299 sym->shndx = ent.st_shndx;
300 sym->value = ent.st_value;
301 sym->size = ent.st_size;
302 }
303
304 static void
305 unpack_rel64(int order, unsigned char *buf, Elfrel *rp)
306 {
307 int n;
308 Elf64_Rel r;
309
310 n = unpack(order,
311 buf,
312 "qq",
313 &r.r_offset,
314 &r.r_info);
315
316 assert(n == ELFR64SZ);
317
318 rp->off = r.r_offset;
319 rp->info = r.r_info;
320 rp->addend = 0;
321 }
322
323 static void
324 unpack_rel32(int order, unsigned char *buf, Elfrel *rp)
325 {
326 int n;
327 Elf32_Rel r;
328
329 n = unpack(order,
330 buf,
331 "ll",
332 &r.r_offset,
333 &r.r_info);
334
335 assert(n == ELFR32SZ);
336
337 rp->off = r.r_offset;
338 rp->info = r.r_info;
339 rp->addend = 0;
340 }
341
342 static void
343 unpack_rela64(int order, unsigned char *buf, Elfrel *rp)
344 {
345 int n;
346 Elf64_Rela r;
347
348 n = unpack(order,
349 buf,
350 "qqq",
351 &r.r_offset,
352 &r.r_info,
353 &r.r_addend);
354
355 assert(n == ELFRA64SZ);
356
357 rp->off = r.r_offset;
358 rp->info = r.r_info;
359 rp->addend = r.r_addend;
360 }
361
362 static void
363 unpack_rela32(int order, unsigned char *buf, Elfrel *rp)
364 {
365 int n;
366 Elf32_Rela r;
367
368 n = unpack(order,
369 buf,
370 "lll",
371 &r.r_offset,
372 &r.r_info,
373 &r.r_addend);
374
375 assert(n == ELFRA32SZ);
376
377 rp->off = r.r_offset;
378 rp->info = r.r_info;
379 rp->addend = r.r_addend;
380 }
381
382 static int
383 readhdr(Obj *obj, FILE *fp)
384 {
385 Elf *elf = obj->data;
386 Elfhdr *hdr = &elf->hdr;
387 Elfunpack *u = elf->unpack;
388 unsigned char buf[ELFH64SZ];
389
390 if (fread(buf, u->hdrsiz, 1, fp) != 1)
391 return 0;
392 (*u->hdr)(ORDER(obj->type), buf, hdr);
393
394 if (hdr->shnum > INT_MAX || hdr->phnum > INT_MAX)
395 return 0;
396
397 switch (hdr->type) {
398 case ET_REL:
399 case ET_EXEC:
400 case ET_DYN:
401 return 1;
402 default:
403 return 0;
404 }
405 }
406
407 static int
408 readphdr(Obj *obj, FILE *fp)
409 {
410 int i, r;
411 Elfphdr *phdr;
412 Elf *elf = obj->data;
413 Elfhdr *hdr = &elf->hdr;
414 Elfunpack *u = elf->unpack;
415 unsigned char *buf;
416
417 r = 0;
418 if (hdr->phnum > 0
419 && (hdr->phoff == 0 || hdr->phentsize < u->phdrsiz)) {
420 errno = ERANGE;
421 goto err0;
422 }
423 if (hdr->phoff == 0 || hdr->phnum == 0)
424 return 1;
425
426 if ((buf = malloc(hdr->phentsize)) == NULL)
427 goto err0;
428 if ((phdr = calloc(hdr->phnum, sizeof(*phdr))) == NULL)
429 goto err1;
430 elf->phdr = phdr;
431
432 if (!objpos(obj, fp, hdr->phoff))
433 goto err1;
434
435 for (i = 0; i < hdr->phnum; i++) {
436 if (fread(buf, hdr->phentsize, 1, fp) != 1)
437 goto err1;
438 (*u->phdr)(ORDER(obj->type), buf, &phdr[i]);
439 if (phdr[i].offset > LONG_MAX)
440 goto err1;
441 }
442 r = 1;
443
444 err1:
445 free(buf);
446 err0:
447 return r;
448 }
449
450 static int
451 readshdr(Obj *obj, FILE *fp)
452 {
453 int r, nsec;
454 Elfsec *sec;
455 Elf *elf = obj->data;
456 Elfhdr *hdr = &elf->hdr;
457 Elfunpack *u = elf->unpack;
458 unsigned char *buf;
459
460 if (hdr->shoff == 0)
461 return 1;
462
463 if (!objpos(obj, fp, hdr->shoff))
464 return 0;
465
466 if (hdr->shnum != SHN_UNDEF) {
467 if (hdr->shnum > INT_MAX)
468 return 0;
469 nsec = hdr->shnum;
470 } else {
471 Elfsec sec0;
472 fpos_t pos;
473 unsigned char buf0[ELFS64SZ];
474
475 fgetpos(fp, &pos);
476 fread(buf0, u->shentsiz, 1, fp);
477 fsetpos(fp, &pos);
478
479 if (ferror(fp))
480 return 0;
481
482 (*u->sec)(ORDER(obj->type), buf0, &sec0);
483 if (sec0.size > INT_MAX)
484 return 0;
485 nsec = sec0.size;
486 }
487
488 if (nsec == 0)
489 return 1;
490
491 r = 0;
492 if ((buf = malloc(hdr->shentsize)) == NULL)
493 return 0;
494 if ((sec = calloc(nsec, sizeof(*sec))) == NULL)
495 goto err;
496 elf->secs = sec;
497 elf->nsec = nsec;
498
499 for ( ; nsec-- > 0; ++sec) {
500 if (fread(buf, hdr->shentsize, 1, fp) != 1)
501 goto err;
502 (*u->sec)(ORDER(obj->type), buf, sec);
503 }
504 r = 1;
505 err:
506 free(buf);
507 return r;
508 }
509
510 static int
511 readstrtbl(Obj *obj, FILE *fp)
512 {
513 char *s;
514 int idx;
515 Elfsec *tbl, *sec;
516 Elf *elf = obj->data;
517 Elfhdr *hdr = &elf->hdr;
518
519 if (hdr->shstrndx != SHN_XINDEX) {
520 idx = hdr->shstrndx;
521 } else {
522 if (hdr->shnum == 0)
523 return 0;
524 sec = elf->secs;
525 if (sec->link > INT_MAX)
526 return 0;
527 idx = sec->link;
528 }
529 if (idx > elf->nsec || elf->secs[idx].type != SHT_STRTAB)
530 return 0;
531 elf->secstrtbl = idx;
532
533 for (sec = elf->secs; sec < &elf->secs[elf->nsec]; ++sec) {
534 if (sec->type != SHT_STRTAB)
535 continue;
536
537 if (sec->size > SIZE_MAX)
538 return 0;
539 if ((s = malloc(sec->size)) == NULL)
540 return 0;
541 sec->strtbl = s;
542
543 if (!objpos(obj, fp, sec->offset))
544 return 0;
545 if (fread(s, sec->size, 1, fp) != 1)
546 return 0;
547 }
548
549 return 1;
550 }
551
552 static int
553 secsize(Elfsec *sec, int onent, int entsiz)
554 {
555 unsigned long long nent;
556
557 if (sec->entsize == 0 || sec->entsize < entsiz)
558 return -1;
559 nent = sec->size / sec->entsize;
560 if (nent > INT_MAX - onent)
561 return -1;
562
563 return nent;
564 }
565
566 static int
567 readsyms(Obj *obj, Elfsec *sec, FILE *fp)
568 {
569 int r = 0, n, oldn;
570 Elfsym *sym;
571 Elfsec *tbl;
572 Elf *elf = obj->data;
573 Elfunpack *u = elf->unpack;
574 Elfhdr *hdr = &elf->hdr;
575 unsigned char *buf;
576
577 if ((n = secsize(sec, elf->nsym, u->symsiz)) <= 0)
578 return n;
579 if ((buf = malloc(sec->entsize)) == NULL)
580 return 0;
581
582 oldn = elf->nsym;
583 sym = realloc(elf->syms, (oldn + n) * sizeof(Elfsym));
584 if (!sym)
585 goto err;
586 elf->syms = sym;
587 elf->nsym += n;
588
589 if (!objpos(obj, fp, sec->offset))
590 goto err;
591
592 if (sec->link >= hdr->shnum)
593 goto err;
594 tbl = &elf->secs[sec->link];
595 if (tbl->type != SHT_STRTAB)
596 goto err;
597
598 for (sym = &elf->syms[oldn] ; n-- > 0 ; ++sym) {
599 if (fread(buf, sec->entsize, 1, fp) != 1)
600 goto err;
601 (*u->sym)(ORDER(obj->type), buf, sym);
602 sym->symsec = sec;
603 if (sym->st_name >= tbl->size)
604 goto err;
605 sym->name = &tbl->strtbl[sym->st_name];
606
607 switch (sym->shndx) {
608 case SHN_XINDEX:
609 /*
610 * Elf supports an extension mechanism to allow
611 * indexes bigger than 4 bytes. We don't care
612 * and we reject elf files using this feature.
613 */
614 goto err;
615 case SHN_UNDEF:
616 case SHN_ABS:
617 case SHN_COMMON:
618 break;
619 default:
620 if (sym->shndx >= elf->nsec)
621 goto err;
622 break;
623 }
624 }
625 r = 1;
626
627 err:
628 free(buf);
629 return r;
630 }
631
632 static int
633 readrels(Obj *obj, Elfsec *sec, FILE *fp)
634 {
635 int r = 0, oldn, n, min;
636 Elf *elf = obj->data;
637 Elfunpack *u = elf->unpack;
638 Elfrel *rp;
639 void (*fn)(int, unsigned char *, Elfrel *);
640 unsigned char *buf;
641
642 if (sec->type == SHT_RELA) {
643 fn = u->rela;
644 min = u->relasiz;
645 } else {
646 fn = u->rel;
647 min = u->relsiz;
648 }
649
650 if (!objpos(obj, fp, sec->offset))
651 goto err;
652
653 if ((n = secsize(sec, elf->nrel, min)) <= 0)
654 return n;
655 if ((buf = malloc(sec->entsize)) == NULL)
656 return 0;
657
658 oldn = elf->nrel;
659 rp = realloc(elf->rels, (oldn + n) * sizeof(Elfrel));
660 if (!rp)
661 goto err;
662 elf->rels = rp;
663 elf->nrel += n;
664
665 for (rp = &elf->rels[oldn]; n-- > 0; ++rp) {
666 if (fread(buf, sec->entsize, 1, fp) != 1)
667 goto err;
668 (*fn)(ORDER(obj->type), buf, rp);
669 }
670 r = 1;
671
672 err:
673 free(buf);
674 return r;
675 }
676
677 static int
678 procsecs(Obj *obj, FILE *fp)
679 {
680 Elf *elf = obj->data;
681 Elfsec *tbl, *sec;
682
683 tbl = &elf->secs[elf->secstrtbl];
684 for (sec = elf->secs; sec < &elf->secs[elf->nsec]; ++sec) {
685 if (sec->sh_name >= tbl->size)
686 return 0;
687 sec->name = &tbl->strtbl[sec->sh_name];
688
689 switch (sec->type) {
690 case SHT_DYNSYM:
691 case SHT_SYMTAB:
692 if (!readsyms(obj, sec, fp))
693 return 0;
694 break;
695 case SHT_RELA:
696 case SHT_REL:
697 if (!readrels(obj, sec, fp))
698 return 0;
699 break;
700 }
701 }
702
703 return 1;
704 }
705
706 int
707 elfread(Obj *obj, FILE *fp)
708 {
709 fpos_t pos;
710 Elf *elf = obj->data;
711 unsigned char buf[EI_CLASS+1];
712
713 fgetpos(fp, &pos);
714 fread(buf, sizeof(buf), 1, fp);
715 fsetpos(fp, &pos);
716
717 if (buf[EI_CLASS] == ELFCLASS64) {
718 if (elf->is32)
719 return 0;
720 elf->is32 = 0;
721 elf->unpack = &unpack64;
722 } else {
723 elf->is32 = 1;
724 elf->unpack = &unpack32;
725 }
726
727 if (!readhdr(obj, fp))
728 return -1;
729 if (!readphdr(obj, fp))
730 return -1;
731 if (!readshdr(obj, fp))
732 return -1;
733 if (!readstrtbl(obj, fp))
734 return -1;
735 if (!procsecs(obj, fp))
736 return -1;
737
738 return 0;
739 }
740
741 struct elfunpack unpack64 = {
742 .hdr = unpack_hdr64,
743 .phdr = unpack_phdr64,
744 .sec = unpack_shdr64,
745 .sym = unpack_sym64,
746 .rel = unpack_rel64,
747 .rela = unpack_rela64,
748
749 .hdrsiz = ELFH64SZ,
750 .phdrsiz = ELFP64SZ,
751 .shentsiz = ELFS64SZ,
752 .symsiz = ELFE64SZ,
753 .relsiz = ELFR64SZ,
754 .relasiz = ELFRA64SZ,
755 };
756
757 struct elfunpack unpack32 = {
758 .hdr = unpack_hdr32,
759 .phdr = unpack_phdr32,
760 .sec = unpack_shdr32,
761 .sym = unpack_sym32,
762 .rel = unpack_rel32,
763 .rela = unpack_rela32,
764
765 .hdrsiz = ELFH32SZ,
766 .phdrsiz = ELFP32SZ,
767 .shentsiz = ELFS32SZ,
768 .symsiz = ELFE32SZ,
769 .relsiz = ELFR32SZ,
770 .relasiz = ELFRA32SZ,
771 };