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

  1. /* Elf relocation routines.
  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_reloc.c,v 1.1.1.1 1998/01/06 20:51:08 ewt Exp $"
  23.  
  24. #include <string.h>
  25. #include <assert.h>
  26. #include <alloca.h>
  27.  
  28. #include <obj.h>
  29. #include <util.h>
  30.  
  31. /*======================================================================*/
  32.  
  33. int
  34. obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
  35.          const char *string)
  36. {
  37.   struct obj_string_patch *p;
  38.   struct obj_section *strsec;
  39.   size_t len = strlen(string)+1;
  40.   char *loc;
  41.  
  42.   p = xmalloc(sizeof(*p));
  43.   p->next = f->string_patches;
  44.   p->reloc_secidx = secidx;
  45.   p->reloc_offset = offset;
  46.   f->string_patches = p;
  47.  
  48.   strsec = obj_find_section(f, ".kstrtab");
  49.   if (strsec == NULL)
  50.     {
  51.       strsec = obj_create_alloced_section(f, ".kstrtab", 1, len);
  52.       p->string_offset = 0;
  53.       loc = strsec->contents;
  54.     }
  55.   else
  56.     {
  57.       p->string_offset = strsec->header.sh_size;
  58.       loc = obj_extend_section(strsec, len);
  59.     }
  60.   memcpy(loc, string, len);
  61.  
  62.   return 1;
  63. }
  64.  
  65. int
  66. obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
  67.          struct obj_symbol *sym)
  68. {
  69.   struct obj_symbol_patch *p;
  70.  
  71.   p = xmalloc(sizeof(*p));
  72.   p->next = f->symbol_patches;
  73.   p->reloc_secidx = secidx;
  74.   p->reloc_offset = offset;
  75.   p->sym = sym;
  76.   f->symbol_patches = p;
  77.  
  78.   return 1;
  79. }
  80.  
  81. int
  82. obj_allocate_commons_and_check_undefineds(struct obj_file *f)
  83. {
  84.   struct common_entry
  85.   {
  86.     struct common_entry *next;
  87.     struct obj_symbol *sym;
  88.   } *common_head = NULL;
  89.  
  90.   int i, ret = 1;
  91.  
  92.   for (i = 0; i < HASH_BUCKETS; ++i)
  93.     {
  94.       struct obj_symbol *sym;
  95.       for (sym = f->symtab[i]; sym ; sym = sym->next)
  96.     switch (sym->secidx)
  97.       {
  98.       case SHN_UNDEF:
  99.         if (ELFW(ST_BIND)(sym->info) == STB_WEAK)
  100.           {
  101.         sym->secidx = SHN_ABS;
  102.         sym->value = 0;
  103.           }
  104.         else
  105.           {
  106.         error("unresolved symbol %s", sym->name);
  107.         ret = 0;
  108.           }
  109.         break;
  110.  
  111.       case SHN_COMMON:
  112.         /* Collect all COMMON symbols and sort them by size so as to
  113.            minimize space wasted by alignment requirements.  */
  114.         {
  115.           struct common_entry **p, *n;
  116.           for (p = &common_head; *p ; p = &(*p)->next)
  117.         if (sym->size <= (*p)->sym->size)
  118.           break;
  119.  
  120.           n = alloca(sizeof(*n));
  121.           n->next = *p;
  122.           n->sym = sym;
  123.           *p = n;
  124.         }
  125.       break;
  126.       }
  127.     }
  128.  
  129.   if (!ret)
  130.     return ret;
  131.  
  132.   if (common_head)
  133.     {
  134.       /* Find the bss section.  */
  135.       for (i = 0; i < f->header.e_shnum; ++i)
  136.     if (f->sections[i]->header.sh_type == SHT_NOBITS)
  137.       break;
  138.  
  139.       /* If for some reason there hadn't been one, create one.  */
  140.       if (i == f->header.e_shnum)
  141.     {
  142.       struct obj_section *sec;
  143.  
  144.       f->sections = xrealloc(f->sections, (i+1) * sizeof(sec));
  145.       f->sections[i] = sec = arch_new_section();
  146.       f->header.e_shnum = i+1;
  147.  
  148.       memset(sec, 0, sizeof(*sec));
  149.       sec->header.sh_type = SHT_NOBITS;
  150.       sec->header.sh_flags = SHF_WRITE|SHF_ALLOC;
  151.       sec->name = ".bss";
  152.       sec->idx = i;
  153.     }
  154.  
  155.       /* Allocate the COMMONS.  */
  156.       {
  157.     ElfW(Addr) bss_size = f->sections[i]->header.sh_size;
  158.     ElfW(Addr) max_align = f->sections[i]->header.sh_addralign;
  159.     struct common_entry *c;
  160.  
  161.     for (c = common_head; c ; c = c->next)
  162.       {
  163.         ElfW(Addr) align = c->sym->value;
  164.  
  165.         if (align > max_align)
  166.           max_align = align;
  167.         if (bss_size & (align - 1))
  168.           bss_size = (bss_size | (align - 1)) + 1;
  169.  
  170.         c->sym->secidx = i;
  171.         c->sym->value = bss_size;
  172.  
  173.         bss_size += c->sym->size;
  174.       }
  175.  
  176.     f->sections[i]->header.sh_size = bss_size;
  177.     f->sections[i]->header.sh_addralign = max_align;
  178.       }
  179.     }
  180.  
  181.   /* For the sake of patch relocation and parameter initialization,
  182.      allocate zeroed data for NOBITS sections now.  Note that after
  183.      this we cannot assume NOBITS are really empty.  */
  184.   for (i = 0; i < f->header.e_shnum; ++i)
  185.     {
  186.       struct obj_section *s = f->sections[i];
  187.       if (s->header.sh_type == SHT_NOBITS)
  188.     {
  189.       s->contents = memset(xmalloc(s->header.sh_size),
  190.                    0, s->header.sh_size);
  191.     }
  192.     }
  193.  
  194.   return ret;
  195. }
  196.  
  197. unsigned long
  198. obj_load_size (struct obj_file *f)
  199. {
  200.   unsigned long dot = 0;
  201.   struct obj_section *sec;
  202.  
  203.   /* Finalize the positions of the sections relative to one another.  */
  204.  
  205.   for (sec = f->load_order; sec ; sec = sec->load_next)
  206.     {
  207.       ElfW(Addr) align;
  208.  
  209.       align = sec->header.sh_addralign;
  210.       if (align && (dot & (align - 1)))
  211.     dot = (dot | (align - 1)) + 1;
  212.  
  213.       sec->header.sh_addr = dot;
  214.       dot += sec->header.sh_size;
  215.     }
  216.  
  217.   return dot;
  218. }
  219.  
  220. int
  221. obj_relocate (struct obj_file *f, ElfW(Addr) base)
  222. {
  223.   int i, n = f->header.e_shnum;
  224.   int ret = 1;
  225.  
  226.   /* Finalize the addresses of the sections.  */
  227.  
  228.   f->baseaddr = base;
  229.   for (i = 0; i < n; ++i)
  230.     f->sections[i]->header.sh_addr += base;
  231.  
  232.   /* And iterate over all of the relocations.  */
  233.  
  234.   for (i = 0; i < n; ++i)
  235.     {
  236.       struct obj_section *relsec, *symsec, *targsec, *strsec;
  237.       ElfW(RelM) *rel, *relend;
  238.       ElfW(Sym) *symtab;
  239.       const char *strtab;
  240.  
  241.       relsec = f->sections[i];
  242.       if (relsec->header.sh_type != SHT_RELM)
  243.     continue;
  244.  
  245.       symsec = f->sections[relsec->header.sh_link];
  246.       targsec = f->sections[relsec->header.sh_info];
  247.       strsec = f->sections[symsec->header.sh_link];
  248.  
  249.       rel = (ElfW(RelM) *)relsec->contents;
  250.       relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
  251.       symtab = (ElfW(Sym) *)symsec->contents;
  252.       strtab = (const char *)strsec->contents;
  253.  
  254.       for (; rel < relend; ++rel)
  255.     {
  256.       ElfW(Addr) value = 0;
  257.       struct obj_symbol *intsym = NULL;
  258.       unsigned long symndx;
  259.       ElfW(Sym) *extsym = 0;
  260.       const char *errmsg;
  261.  
  262.       /* Attempt to find a value to use for this relocation.  */
  263.  
  264.       symndx = ELFW(R_SYM)(rel->r_info);
  265.       if (symndx)
  266.         {
  267.           /* Note we've already checked for undefined symbols.  */
  268.           const char *name;
  269.  
  270.           extsym = &symtab[symndx];
  271.           if (extsym->st_name)
  272.         name = strtab + extsym->st_name;
  273.           else
  274.         name = f->sections[extsym->st_shndx]->name;
  275.  
  276.           intsym = obj_find_symbol(f, name);
  277.           value = obj_symbol_final_value(f, intsym);
  278.           intsym->referenced = 1;
  279.         }
  280. #if SHT_RELM == SHT_RELA
  281. #if defined(__alpha__) && defined(AXP_BROKEN_GAS)
  282.           /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9.  */
  283.           if (!extsym || !extsym->st_name ||
  284.               ELFW(ST_BIND)(extsym->st_info) != STB_LOCAL)
  285. #endif
  286.       value += rel->r_addend;
  287. #endif
  288.  
  289.       /* Do it! */
  290.       switch (arch_apply_relocation(f,targsec,symsec,intsym,rel,value))
  291.         {
  292.         case obj_reloc_ok:
  293.           break;
  294.  
  295.         case obj_reloc_overflow:
  296.           errmsg = "Relocation overflow";
  297.           goto bad_reloc;
  298.         case obj_reloc_dangerous:
  299.           errmsg = "Dangerous relocation";
  300.           goto bad_reloc;
  301.         case obj_reloc_unhandled:
  302.           errmsg = "Unhandled relocation";
  303.         bad_reloc:
  304.           if (extsym)
  305.         {
  306.           error("%s of type %ld for %s", errmsg,
  307.             (long)ELFW(R_TYPE)(rel->r_info),
  308.             strtab + extsym->st_name);
  309.         }
  310.           else
  311.         {
  312.           error("%s of type %ld", errmsg,
  313.             (long)ELFW(R_TYPE)(rel->r_info));
  314.         }
  315.           ret = 0;
  316.           break;
  317.         }
  318.     }
  319.     }
  320.  
  321.   /* Finally, take care of the patches.  */
  322.  
  323.   if (f->string_patches)
  324.     {
  325.       struct obj_string_patch *p;
  326.       struct obj_section *strsec;
  327.       ElfW(Addr) strsec_base;
  328.       strsec = obj_find_section(f, ".kstrtab");
  329.       strsec_base = strsec->header.sh_addr;
  330.  
  331.       for (p = f->string_patches; p ; p = p->next)
  332.     {
  333.       struct obj_section *targsec = f->sections[p->reloc_secidx];
  334.       if (targsec->header.sh_type == SHT_NOBITS)
  335.         {
  336.           /* Convert the section to PROGBITS so we can write to it.  */
  337.           targsec->contents = memset(xmalloc(targsec->header.sh_size),
  338.                      0, targsec->header.sh_size);
  339.           targsec->header.sh_type = SHT_PROGBITS;
  340.         }
  341.       *(ElfW(Addr) *)(targsec->contents + p->reloc_offset)
  342.         = strsec_base + p->string_offset;
  343.     }
  344.     }
  345.  
  346.   if (f->symbol_patches)
  347.     {
  348.       struct obj_symbol_patch *p;
  349.  
  350.       for (p = f->symbol_patches; p; p = p->next)
  351.     {
  352.       struct obj_section *targsec = f->sections[p->reloc_secidx];
  353.       if (targsec->header.sh_type == SHT_NOBITS)
  354.         {
  355.           /* Convert the section to PROGBITS so we can write to it.  */
  356.           targsec->contents = memset(xmalloc(targsec->header.sh_size),
  357.                      0, targsec->header.sh_size);
  358.           targsec->header.sh_type = SHT_PROGBITS;
  359.         }
  360.       *(ElfW(Addr) *)(targsec->contents + p->reloc_offset)
  361.         = obj_symbol_final_value(f, p->sym);
  362.     }
  363.     }
  364.  
  365.   return ret;
  366. }
  367.  
  368. int
  369. obj_create_image (struct obj_file *f, char *image)
  370. {
  371.   struct obj_section *sec;
  372.   ElfW(Addr) base = f->baseaddr;
  373.  
  374.   for (sec = f->load_order; sec ; sec = sec->load_next)
  375.     {
  376.       char *secimg;
  377.  
  378.       if (sec->header.sh_size == 0)
  379.     continue;
  380.  
  381.       secimg = image + (sec->header.sh_addr - base);
  382.  
  383.       /* Note that we allocated data for NOBITS sections earlier.  */
  384.       memcpy(secimg, sec->contents, sec->header.sh_size);
  385.     }
  386.  
  387.   return 1;
  388. }
  389.