"Fossies" - the Fresh Open Source Software Archive

Member "modutils-2.4.27/obj/obj_arm.c" (22 Feb 2004, 7397 Bytes) of package /linux/misc/old/modutils-2.4.27.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "obj_arm.c" see the Fossies "Dox" file reference documentation.

    1 /* ARM specific support for Elf loading and relocation.
    2    Copyright 1996, 1997, 1998 Linux International.
    3 
    4    Contributed by Phil Blundell <philb@gnu.org>
    5    and wms <woody@corelcomputer.com>
    6    based on the i386 code by Richard Henderson <rth@tamu.edu>
    7    plt/got bugfix: Thomas Fleischmann <tfleischmann@gmx.de> September 2003
    8 
    9    This file is part of the Linux modutils.
   10 
   11    This program is free software; you can redistribute it and/or modify it
   12    under the terms of the GNU General Public License as published by the
   13    Free Software Foundation; either version 2 of the License, or (at your
   14    option) any later version.
   15 
   16    This program is distributed in the hope that it will be useful, but
   17    WITHOUT ANY WARRANTY; without even the implied warranty of
   18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   19    General Public License for more details.
   20 
   21    You should have received a copy of the GNU General Public License
   22    along with this program; if not, write to the Free Software Foundation,
   23    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
   24 
   25 #include <string.h>
   26 #include <assert.h>
   27 
   28 #include <module.h>
   29 #include <obj.h>
   30 #include <util.h>
   31 
   32 
   33 /*======================================================================*/
   34 
   35 struct arm_plt_entry
   36 {
   37   int offset;
   38   int allocated:1;
   39   int inited:1;                // has been set up
   40 };
   41 
   42 struct arm_got_entry
   43 {
   44   int offset;
   45   int allocated : 1;
   46   unsigned reloc_done : 1;
   47 };
   48 
   49 struct arm_file
   50 {
   51   struct obj_file root;
   52   struct obj_section *plt;
   53   struct obj_section *got;
   54 };
   55 
   56 struct arm_symbol
   57 {
   58   struct obj_symbol root;
   59   struct arm_plt_entry pltent;
   60   struct arm_got_entry gotent;
   61 };
   62 
   63 
   64 /*======================================================================*/
   65 
   66 struct obj_file *
   67 arch_new_file (void)
   68 {
   69   struct arm_file *f;
   70   f = xmalloc(sizeof(*f));
   71   f->got = NULL;
   72   return &f->root;
   73 }
   74 
   75 struct obj_section *
   76 arch_new_section (void)
   77 {
   78   return xmalloc(sizeof(struct obj_section));
   79 }
   80 
   81 struct obj_symbol *
   82 arch_new_symbol (void)
   83 {
   84   struct arm_symbol *sym;
   85   sym = xmalloc(sizeof(*sym));
   86   memset(&sym->gotent, 0, sizeof(sym->gotent));
   87   memset(&sym->pltent, 0, sizeof(sym->pltent));
   88   return &sym->root;
   89 }
   90 
   91 int
   92 arch_load_proc_section(struct obj_section *sec, int fp)
   93 {
   94     /* Assume it's just a debugging section that we can safely
   95        ignore ...  */
   96     sec->contents = NULL;
   97 
   98     return 0;
   99 }
  100 
  101 enum obj_reloc
  102 arch_apply_relocation (struct obj_file *f,
  103                struct obj_section *targsec,
  104                struct obj_section *symsec,
  105                struct obj_symbol *sym,
  106                Elf32_Rel *rel,
  107                Elf32_Addr v)
  108 {
  109   struct arm_file *afile = (struct arm_file *)f;
  110   struct arm_symbol *asym  = (struct arm_symbol *)sym;
  111 
  112   Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
  113   Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
  114   Elf32_Addr got = afile->got ? afile->got->header.sh_addr : 0;
  115   Elf32_Addr plt = afile->plt ? afile->plt->header.sh_addr : 0;
  116 
  117   struct arm_plt_entry *pe;
  118   unsigned long *ip;
  119 
  120   enum obj_reloc ret = obj_reloc_ok;
  121 
  122   switch (ELF32_R_TYPE(rel->r_info))
  123     {
  124     case R_ARM_NONE:
  125       break;
  126 
  127     case R_ARM_ABS32:
  128       *loc += v;
  129       break;
  130 
  131     case R_ARM_GOT32:
  132       /* needs an entry in the .got: set it, once */
  133       if (! asym->gotent.reloc_done)
  134     {
  135       asym->gotent.reloc_done = 1;
  136       *(Elf32_Addr *)(afile->got->contents + asym->gotent.offset) = v;
  137     }
  138       /* make the reloc with_respect_to_.got */
  139       *loc += asym->gotent.offset;
  140       break;
  141 
  142       /* relative reloc, always to _GLOBAL_OFFSET_TABLE_ (which is .got)
  143      similar to branch, but is full 32 bits relative */
  144     case R_ARM_GOTPC:
  145       assert(got);
  146       *loc += got - dot;
  147       break;
  148 
  149     case R_ARM_PC24:
  150     case R_ARM_PLT32:
  151       /* find the plt entry and initialize it if necessary */
  152       assert(asym != NULL);
  153       pe = (struct arm_plt_entry*) &asym->pltent;
  154       if (! pe->inited)
  155     {
  156       ip = (unsigned long *) (afile->plt->contents + pe->offset);
  157       ip[0] = 0xe51ff004;           /* ldr pc,[pc,#-4] */
  158       ip[1] = v;                /* sym@ */
  159       pe->inited = 1;
  160     }
  161 
  162       /* relative distance to target */
  163       v -= dot;
  164       /* if the target is too far away.... */
  165       if ((int)v < -0x02000000 || (int)v >= 0x02000000)
  166     {
  167       /* go via the plt */
  168       v = plt + pe->offset - dot;
  169     }
  170       if (v & 3)
  171     ret = obj_reloc_dangerous;
  172 
  173       /* Convert to words. */
  174       v >>= 2;
  175 
  176       /* merge the offset into the instruction. */
  177       *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
  178       break;
  179 
  180       /* address relative to the got */
  181     case R_ARM_GOTOFF:
  182       assert(got);
  183       *loc += v - got;
  184       break;
  185 
  186     default:
  187       printf("Warning: unhandled reloc %d\n",ELF32_R_TYPE(rel->r_info));
  188       ret = obj_reloc_unhandled;
  189       break;
  190     }
  191 
  192   return ret;
  193 }
  194 
  195 int
  196 arch_create_got (struct obj_file *f)
  197 {
  198   struct arm_file *afile = (struct arm_file *) f;
  199   int i;
  200   struct obj_section *sec, *syms, *strs;
  201   ElfW(Rel) *rel, *relend;
  202   ElfW(Sym) *symtab, *extsym;
  203   const char *strtab;
  204   struct arm_symbol *intsym;
  205   struct arm_plt_entry *pe;
  206   struct arm_got_entry *ge;
  207   int got_offset = 0, plt_offset = 0;
  208 
  209   for (i = 0; i < f->header.e_shnum; ++i)
  210     {
  211       sec = f->sections[i];
  212       if (sec->header.sh_type != SHT_RELM)
  213     continue;
  214       syms = f->sections[sec->header.sh_link];
  215       strs = f->sections[syms->header.sh_link];
  216 
  217       rel = (ElfW(RelM) *) sec->contents;
  218       relend = rel + (sec->header.sh_size / sizeof(ElfW(RelM)));
  219       symtab = (ElfW(Sym) *) syms->contents;
  220       strtab = (const char *) strs->contents;
  221 
  222       for (; rel < relend; ++rel)
  223     {
  224       extsym = &symtab[ELF32_R_SYM(rel->r_info)];
  225 
  226       switch(ELF32_R_TYPE(rel->r_info)) {
  227       case R_ARM_PC24:
  228       case R_ARM_PLT32:
  229         obj_find_relsym(intsym, f, f, rel, symtab, strtab);
  230 
  231         pe = &intsym->pltent;
  232 
  233         if (! pe->allocated)
  234           {
  235         pe->allocated = 1;
  236         pe->offset = plt_offset;
  237         plt_offset += 8;
  238         pe->inited = 0;
  239           }
  240         break;
  241 
  242         /* these two don_t need got entries, but they need
  243            the .got to exist */
  244       case R_ARM_GOTOFF:
  245       case R_ARM_GOTPC:
  246         if (got_offset==0) got_offset = 4;
  247         break;
  248 
  249       case R_ARM_GOT32:
  250         obj_find_relsym(intsym, f, f, rel, symtab, strtab);
  251 
  252         ge = (struct arm_got_entry *) &intsym->gotent;
  253         if (! ge->allocated)
  254           {
  255         ge->allocated = 1;
  256         ge->offset = got_offset;
  257         got_offset += sizeof(void*);
  258           }
  259         break;
  260 
  261       default:
  262         continue;
  263       }
  264     }
  265     }
  266 
  267   /* if there was a _GLOBAL_OFFSET_TABLE_, then the .got section
  268    exists already; find it and use it */
  269   if (got_offset)
  270   {
  271       struct obj_section* sec = obj_find_section(f, ".got");
  272       if (sec)
  273     obj_extend_section(sec, got_offset);
  274       else
  275     {
  276       sec = obj_create_alloced_section(f, ".got", 8, got_offset,
  277                        SHF_WRITE);
  278       assert(sec);
  279     }
  280       afile->got = sec;
  281   }
  282   else
  283     afile->got = NULL;
  284 
  285   if (plt_offset)
  286     afile->plt = obj_create_alloced_section(f, ".plt", 8, plt_offset,
  287                         SHF_WRITE);
  288   else
  289     afile->plt = NULL;
  290 
  291   return 1;
  292 }
  293 
  294 int
  295 arch_init_module (struct obj_file *f, struct module *mod)
  296 {
  297   return 1;
  298 }
  299 
  300 int
  301 arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
  302 {
  303   int  i, n = f->header.e_shnum;
  304 
  305   f->baseaddr = base;
  306   for (i = 0; i < n; ++i)
  307     f->sections[i]->header.sh_addr += base;
  308   return 1;
  309 }
  310 
  311 int
  312 arch_archdata (struct obj_file *fin, struct obj_section *sec)
  313 {
  314   return 0;
  315 }