Home
       elf64read.c - scc - simple c99 compiler
  HTML git clone git://git.simple-cc.org/scc
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR 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 }