home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / modutils / obj / obj_load.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-06  |  5.7 KB  |  228 lines

  1. /* Elf file reader.
  2.    Copyright 1996, 1997 Linux International.
  3.  
  4.    Contributed by Richard Henderson <rth@tamu.edu>
  5.  
  6.    This file is part of the Linux modutils.
  7.  
  8.    This program is free software; you can redistribute it and/or modify it
  9.    under the terms of the GNU General Public License as published by the
  10.    Free Software Foundation; either version 2 of the License, or (at your
  11.    option) any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful, but
  14.    WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.    General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software Foundation,
  20.    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  21.  
  22. #ident "$Id: obj_load.c,v 1.1.1.1 1998/01/06 20:51:08 ewt Exp $"
  23.  
  24. #include <alloca.h>
  25. #include <string.h>
  26.  
  27. #include <obj.h>
  28. #include <util.h>
  29.  
  30. /*======================================================================*/
  31.  
  32. struct obj_file *
  33. obj_load (FILE *fp)
  34. {
  35.   struct obj_file *f;
  36.   ElfW(Shdr) *section_headers;
  37.   int shnum, i;
  38.   char *shstrtab;
  39.  
  40.   /* Read the file header.  */
  41.  
  42.   f = arch_new_file();
  43.   memset(f, 0, sizeof(*f));
  44.   f->symbol_cmp = strcmp;
  45.   f->symbol_hash = obj_elf_hash;
  46.   f->load_order_search_start = &f->load_order;
  47.  
  48.   fseek(fp, 0, SEEK_SET);
  49.   if (fread(&f->header, sizeof(f->header), 1, fp) != 1)
  50.     {
  51.       error("error reading ELF header: %m");
  52.       return NULL;
  53.     }
  54.  
  55.   if (f->header.e_ident[EI_MAG0] != ELFMAG0
  56.       || f->header.e_ident[EI_MAG1] != ELFMAG1
  57.       || f->header.e_ident[EI_MAG2] != ELFMAG2
  58.       || f->header.e_ident[EI_MAG3] != ELFMAG3)
  59.     {
  60.       error("not an ELF file");
  61.       return NULL;
  62.     }
  63.   if (f->header.e_ident[EI_CLASS] != ELFCLASSM
  64.       || f->header.e_ident[EI_DATA] != ELFDATAM
  65.       || f->header.e_ident[EI_VERSION] != EV_CURRENT
  66.       || !MATCH_MACHINE(f->header.e_machine))
  67.     {
  68.       error("ELF file not for this architecture");
  69.       return NULL;
  70.     }
  71.   if (f->header.e_type != ET_REL)
  72.     {
  73.       error("ELF file not a relocatable object");
  74.       return NULL;
  75.     }
  76.  
  77.   /* Read the section headers.  */
  78.  
  79.   if (f->header.e_shentsize != sizeof(ElfW(Shdr)))
  80.     {
  81.       error("section header size mismatch: %lu != %lu",
  82.         (unsigned long)f->header.e_shentsize,
  83.         (unsigned long)sizeof(ElfW(Shdr)));
  84.       return NULL;
  85.     }
  86.  
  87.   shnum = f->header.e_shnum;
  88.   f->sections = xmalloc(sizeof(struct obj_section *) * shnum);
  89.   memset(f->sections, 0, sizeof(struct obj_section *) * shnum);
  90.  
  91.   section_headers = alloca(sizeof(ElfW(Shdr)) * shnum);
  92.   fseek(fp, f->header.e_shoff, SEEK_SET);
  93.   if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum)
  94.     {
  95.       error("error reading ELF section headers: %m");
  96.       return NULL;
  97.     }
  98.  
  99.   /* Read the section data.  */
  100.  
  101.   for (i = 0; i < shnum; ++i)
  102.     {
  103.       struct obj_section *sec;
  104.  
  105.       f->sections[i] = sec = arch_new_section();
  106.       memset(sec, 0, sizeof(*sec));
  107.  
  108.       sec->header = section_headers[i];
  109.       sec->idx = i;
  110.  
  111.       switch (sec->header.sh_type)
  112.      {
  113.     case SHT_NULL:
  114.     case SHT_NOTE:
  115.     case SHT_NOBITS:
  116.       /* ignore */
  117.       break;
  118.  
  119.     case SHT_PROGBITS:
  120.     case SHT_SYMTAB:
  121.     case SHT_STRTAB:
  122.     case SHT_RELM:
  123.       if (sec->header.sh_size > 0)
  124.         {
  125.           sec->contents = xmalloc(sec->header.sh_size);
  126.           fseek(fp, sec->header.sh_offset, SEEK_SET);
  127.           if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1)
  128.             {
  129.               error("error reading ELF section data: %m");
  130.               return NULL;
  131.             }
  132.         }
  133.       else
  134.         sec->contents = NULL;
  135.       break;
  136.  
  137. #if SHT_RELM == SHT_REL
  138.     case SHT_RELA:
  139.       error("RELA relocations not supported on this architecture");
  140.       return NULL;
  141. #else
  142.     case SHT_REL:
  143.       error("REL relocations not supported on this architecture");
  144.       return NULL;
  145. #endif
  146.  
  147.     default:
  148.       if (sec->header.sh_type >= SHT_LOPROC)
  149.         {
  150.           /* Assume processor specific section types are debug
  151.          info and can safely be ignored.  If this is ever not
  152.          the case (Hello MIPS?), don't put ifdefs here but
  153.          create an arch_load_proc_section().  */
  154.           break;
  155.         }
  156.  
  157.       error("can't handle sections of type %ld",
  158.         (long)sec->header.sh_type);
  159.       return NULL;
  160.     }
  161.     }
  162.  
  163.   /* Do what sort of interpretation as needed by each section.  */
  164.  
  165.   shstrtab = f->sections[f->header.e_shstrndx]->contents;
  166.  
  167.   for (i = 0; i < shnum; ++i)
  168.     {
  169.       struct obj_section *sec = f->sections[i];
  170.       sec->name = shstrtab + sec->header.sh_name;
  171.     }
  172.  
  173.   for (i = 0; i < shnum; ++i)
  174.     {
  175.       struct obj_section *sec = f->sections[i];
  176.  
  177.       if (sec->header.sh_flags & SHF_ALLOC)
  178.     obj_insert_section_load_order(f, sec);
  179.  
  180.       switch (sec->header.sh_type)
  181.     {
  182.     case SHT_SYMTAB:
  183.       {
  184.         unsigned long nsym, j;
  185.         char *strtab;
  186.         ElfW(Sym) *sym;
  187.  
  188.         if (sec->header.sh_entsize != sizeof(ElfW(Sym)))
  189.           {
  190.         error("symbol size mismatch: %lu != %lu",
  191.               (unsigned long)sec->header.sh_entsize,
  192.               (unsigned long)sizeof(ElfW(Sym)));
  193.         return NULL;
  194.           }
  195.  
  196.         nsym = sec->header.sh_size / sizeof(ElfW(Sym));
  197.         strtab = f->sections[sec->header.sh_link]->contents;
  198.         sym = (ElfW(Sym) *) sec->contents;
  199.  
  200.         for (j = 1, ++sym; j < nsym; ++j, ++sym)
  201.           {
  202.         const char *name;
  203.         if (sym->st_name)
  204.           name = strtab+sym->st_name;
  205.         else
  206.           name = f->sections[sym->st_shndx]->name;
  207.  
  208.         obj_add_symbol(f, name, sym->st_info, sym->st_shndx,
  209.                    sym->st_value, sym->st_size);
  210.           }
  211.       }
  212.     break;
  213.  
  214.     case SHT_RELM:
  215.       if (sec->header.sh_entsize != sizeof(ElfW(RelM)))
  216.         {
  217.           error("relocation entry size mismatch: %lu != %lu",
  218.             (unsigned long)sec->header.sh_entsize,
  219.             (unsigned long)sizeof(ElfW(RelM)));
  220.           return NULL;
  221.         }
  222.       break;
  223.     }
  224.     }
  225.  
  226.   return f;
  227. }
  228.