scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

elf64read.c (6503B)


      1 #include <assert.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 
      5 #include <scc/mach.h>
      6 #include <scc/elf64.h>
      7 
      8 #include "../libmach.h"
      9 #include "fun.h"
     10 
     11 static int
     12 unpack_hdr(int order, unsigned char *buf, Elf_Ehdr *hdr)
     13 {
     14 	int n;
     15 
     16 	n = unpack(order,
     17 	           buf,
     18 	           "'16sslqqqlssssss",
     19 	           hdr->e_ident,
     20 	           &hdr->e_type,
     21 	           &hdr->e_machine,
     22 	           &hdr->e_version,
     23 	           &hdr->e_entry,
     24 	           &hdr->e_phoff,
     25 	           &hdr->e_shoff,
     26 	           &hdr->e_flags,
     27 	           &hdr->e_ehsize,
     28 	           &hdr->e_phentsize,
     29 	           &hdr->e_phnum,
     30 	           &hdr->e_shentsize,
     31 	           &hdr->e_shnum,
     32 	           &hdr->e_shstrndx);
     33 
     34 	assert(n == ELFHSZ);
     35 
     36 	return n;
     37 }
     38 
     39 static int
     40 unpack_phdr(int order, unsigned char *buf, Elf_Phdr *phdr)
     41 {
     42 	int n;
     43 
     44 	n = unpack(order,
     45 	           buf,
     46 	           "llqqqqqq",
     47 	           &phdr->p_type,
     48 	           &phdr->p_flags,
     49 	           &phdr->p_offset,
     50 	           &phdr->p_vaddr,
     51 	           &phdr->p_paddr,
     52 	           &phdr->p_filesz,
     53 	           &phdr->p_memsz,
     54 	           &phdr->p_align);
     55 
     56 	assert(n == ELFPSZ);
     57 
     58 	return n;
     59 }
     60 
     61 static int
     62 unpack_shdr(int order, unsigned char *buf, Elf_Shdr *shdr)
     63 {
     64 	int n;
     65 
     66 	n = unpack(order,
     67 	           buf,
     68 	           "llqqqqllqq",
     69 	           &shdr->sh_name,
     70 	           &shdr->sh_type,
     71 	           &shdr->sh_flags,
     72 	           &shdr->sh_addr,
     73 	           &shdr->sh_offset,
     74 	           &shdr->sh_size,
     75 	           &shdr->sh_link,
     76 	           &shdr->sh_info,
     77 	           &shdr->sh_addralign,
     78 	           &shdr->sh_entsize);
     79 
     80 	assert(n == ELFSSZ);
     81 
     82 	return n;
     83 }
     84 
     85 static int
     86 unpack_sym(int order, unsigned char *buf, Elf_Sym *sym)
     87 {
     88 	int n;
     89 
     90 	n = unpack(order,
     91 	           buf,
     92 	           "lccsqq",
     93 	           &sym->st_name,
     94 	           &sym->st_info,
     95 	           &sym->st_other,
     96 	           &sym->st_shndx,
     97 	           &sym->st_value,
     98 	           &sym->st_size);
     99 	assert(n == ELFESZ);
    100 
    101 	return n;
    102 }
    103 
    104 static int
    105 readhdr(Obj *obj, FILE *fp)
    106 {
    107 	Elf64 *elf;
    108 	Elf_Ehdr *hdr;
    109 	unsigned char buf[ELFHSZ];
    110 
    111 	elf = obj->data;
    112 	hdr = &elf->hdr;
    113 
    114 	if (fread(buf, ELFHSZ, 1, fp) != 1)
    115 		return 0;
    116 	unpack_hdr(ORDER(obj->type), buf, hdr);
    117 
    118 	switch (hdr->e_type) {
    119 	case ET_REL:
    120 	case ET_EXEC:
    121 	case ET_DYN:
    122 		return 1;
    123 	default:
    124 		return 0;
    125 	}
    126 }
    127 
    128 static int
    129 readphdr(Obj *obj, FILE *fp)
    130 {
    131 	long long i;
    132 	Elf_Ehdr *hdr;
    133 	Elf_Phdr *phdr;
    134 	Elf64 *elf;
    135 	unsigned char buf[ELFPSZ];
    136 
    137 	elf = obj->data;
    138 	hdr = &elf->hdr;
    139 
    140 	if (hdr->e_phoff == 0 || hdr->e_phnum == 0)
    141 		return 1;
    142 
    143 	phdr = calloc(hdr->e_phnum, sizeof(*phdr));
    144 	if (!phdr)
    145 		return 0;
    146 	elf->phdr = phdr;
    147 
    148 	if (!objpos(obj, fp, hdr->e_phoff))
    149 		return 0;
    150 	for (i = 0; i < hdr->e_phnum; i++) {
    151 		if (fread(buf, ELFPSZ, 1, fp) != 1)
    152 			return 0;
    153 		unpack_phdr(ORDER(obj->type), buf, &phdr[i]);
    154 	}
    155 
    156 	return 1;
    157 }
    158 
    159 static int
    160 readshdr(Obj *obj, FILE *fp)
    161 {
    162 	unsigned long long i, nsec;
    163 	Elf_Ehdr *hdr;
    164 	Elf_Shdr *shdr;
    165 	Elf64 *elf;
    166 	unsigned char buf[ELFSSZ + ELFHSZ];
    167 
    168 	elf = obj->data;
    169 	hdr = &elf->hdr;
    170 	elf->nsec = 0;
    171 	elf->shdr = NULL;
    172 
    173 	if (hdr->e_shoff == 0)
    174 		return 1;
    175 
    176 	if (!objpos(obj, fp, hdr->e_shoff))
    177 		return 0;
    178 
    179 	if (hdr->e_shnum != SHN_UNDEF) {
    180 		nsec = hdr->e_shnum;
    181 	} else {
    182 		Elf_Shdr sec0;
    183 		fpos_t pos;
    184 
    185 		fgetpos(fp, &pos);
    186 		fread(buf, ELFHSZ, 1, fp);
    187 		fsetpos(fp, &pos);
    188 
    189 		if (ferror(fp))
    190 			return 0;
    191 
    192 		unpack_shdr(ORDER(obj->type), buf, &sec0);
    193 		nsec = sec0.sh_size;
    194 	}
    195 
    196 	if (nsec > SIZE_MAX)
    197 		return 0;
    198 	if (nsec == 0)
    199 		return 1;
    200 
    201 	shdr = calloc(nsec, sizeof(*shdr));
    202 	if (!shdr)
    203 		return 0;
    204 	elf->shdr = shdr;
    205 	elf->nsec = nsec;
    206 
    207 	for (i = 0; i < nsec; i++) {
    208 		if (fread(buf, ELFSSZ, 1, fp) != 1)
    209 			return 0;
    210 		unpack_shdr(ORDER(obj->type), buf, &shdr[i]);
    211 		if (shdr[i].sh_type == SHT_SYMTAB) {
    212 			/*
    213 			 * elf supports multiple symbol table, but we don't
    214 			 * care and we only support one, and we reject elf
    215 			 * files with more of one symbol table.
    216 			 */
    217 			if (elf->symtab)
    218 				return 0;
    219 			elf->symtab = &shdr[i];
    220 		}
    221 	}
    222 
    223 	return 1;
    224 }
    225 
    226 static int
    227 readsecstr(Obj *obj, FILE *fp)
    228 {
    229 	long idx;
    230 	size_t siz;
    231 	char *str;
    232 	Elf_Shdr *shdr;
    233 	Elf64 *elf;
    234 	Elf_Ehdr *hdr;
    235 
    236 	elf = obj->data;
    237 	hdr = &elf->hdr;
    238 	idx = hdr->e_shstrndx;
    239 	if (idx == SHN_UNDEF)
    240 		return 0;
    241 	if (idx == SHN_XINDEX) {
    242 		if (hdr->e_shnum == 0)
    243 			return 0;
    244 		idx = elf->shdr[0].sh_link;
    245 	}
    246 
    247 	if (idx >= hdr->e_shnum)
    248 		return 0;
    249 	shdr = &elf->shdr[idx];
    250 
    251 	if (shdr->sh_size > SIZE_MAX)
    252 		return 0;
    253 
    254 	siz = shdr->sh_size;
    255 	if (siz == 0)
    256 		return 1;
    257 	str = malloc(siz);
    258 	if (!str)
    259 		return 0;
    260 
    261 	elf->strtbl[SEC_STRTBL] = str;
    262 	elf->strsiz[SEC_STRTBL] = siz;
    263 
    264 	if (!objpos(obj, fp, shdr->sh_offset))
    265 		return 0;
    266 	if (fread(str, siz, 1, fp) != 1)
    267 		return 0;
    268 
    269 	return 1;
    270 }
    271 
    272 static int
    273 readsymstr(Obj *obj, FILE *fp)
    274 {
    275 	long idx;
    276 	size_t siz;
    277 	char *str;
    278 	Elf64 *elf;
    279 	Elf_Shdr *shdr;
    280 
    281 	elf = obj->data;
    282 	if (!elf->symtab)
    283 		return 1;
    284 
    285 	idx = elf->symtab->sh_link;
    286 	if (idx >= elf->nsec)
    287 		return 0;
    288 	shdr = &elf->shdr[idx];
    289 
    290 	if (shdr->sh_size > SIZE_MAX)
    291 		return 0;
    292 
    293 	siz = shdr->sh_size;
    294 	if (siz == 0)
    295 		return 1;
    296 	str = malloc(siz);
    297 	if (!str)
    298 		return 0;
    299 
    300 	elf->strtbl[SYM_STRTBL] = str;
    301 	elf->strsiz[SYM_STRTBL] = siz;
    302 
    303 	if (!objpos(obj, fp, shdr->sh_offset))
    304 		return 0;
    305 	if (fread(str, siz, 1, fp) != 1)
    306 		return 0;
    307 
    308 	return 1;
    309 }
    310 
    311 static int
    312 readsym(Obj *obj, FILE *fp)
    313 {
    314 	long nsym, i;
    315 	int sec;
    316 	Elf64 *elf;
    317 	Elf_Sym *syms;
    318 	Elf_Shdr *shdr;
    319 	unsigned char buf[ELFSSZ];
    320 
    321 	elf = obj->data;
    322 	if (!elf->symtab)
    323 		return 1;
    324 	shdr = elf->symtab;
    325 
    326 	assert(shdr->sh_type == SHT_SYMTAB);
    327 
    328 	nsym = shdr->sh_size / shdr->sh_entsize;
    329 	if (nsym >= SIZE_MAX)
    330 		return 0;
    331 
    332 	syms = calloc(nsym, sizeof(*syms));
    333 	if (!syms)
    334 		return 0;
    335 	elf->syms = syms;
    336 	elf->nsym = nsym;
    337 
    338 	if (!objpos(obj, fp, shdr->sh_offset))
    339 		return 0;
    340 
    341 	for (i = 0; i < nsym; i++) {
    342 		if (fread(buf, ELFESZ, 1, fp) != 1)
    343 			return 0;
    344 		unpack_sym(ORDER(obj->type), buf, &syms[i]);
    345 
    346 		sec = syms[i].st_shndx;
    347 		switch (sec) {
    348 		case SHN_XINDEX:
    349 			/*
    350 			 * Elf supports an extension mechanism to allow
    351 			 * indexes bigger than 4 bytes. We don't care
    352 			 * and we reject elf files using this feature.
    353 			 */
    354 			return 0;
    355 		case SHN_UNDEF:
    356 		case SHN_ABS:
    357 		case SHN_COMMON:
    358 			break;
    359 		default:
    360 			if (sec >= elf->nsec)
    361 				return 0;
    362 			break;
    363 		}
    364 	}
    365 
    366 	return 1;
    367 }
    368 
    369 int
    370 elf64read(Obj *obj, FILE *fp)
    371 {
    372 	if (!readhdr(obj, fp))
    373 		return -1;
    374 	if (!readphdr(obj, fp))
    375 		return -1;
    376 	if (!readshdr(obj, fp))
    377 		return -1;
    378 	if (!readsym(obj, fp))
    379 		return -1;
    380 	if (!readsecstr(obj, fp))
    381 		return -1;
    382 	if (!readsymstr(obj, fp))
    383 		return -1;
    384 
    385 	return 0;
    386 }