elf64read.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
       ---
       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 }