scc

A fork of https://git.simple-cc.org/scc/ for Qute

git clone https://git.8pit.net/scc.git

  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
 21struct 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
 37struct elfunpack unpack64;
 38struct elfunpack unpack32;
 39
 40static void
 41unpack_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
 82static void
 83unpack_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
124static void
125unpack_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
154static void
155unpack_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
184static void
185unpack_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
218static void
219unpack_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
252static void
253unpack_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
278static void
279unpack_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
304static void
305unpack_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
323static void
324unpack_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
342static void
343unpack_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
362static void
363unpack_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
382static int
383readhdr(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
407static int
408readphdr(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
444err1:
445	free(buf);
446err0:
447	return r;
448}
449
450static int
451readshdr(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;
505err:
506	free(buf);
507	return r;
508}
509
510static int
511readstrtbl(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
552static int
553secsize(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
566static int
567readsyms(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
627err:
628	free(buf);
629	return r;
630}
631
632static int
633readrels(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
672err:
673	free(buf);
674	return r;
675}
676
677static int
678procsecs(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
706int
707elfread(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
741struct 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
757struct 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};