scc

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

elf64read.c (6419B)


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