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

  1. /* Elf file, section, and symbol manipulation 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_common.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. /* Standard ELF hash function.  */
  34. inline unsigned long
  35. obj_elf_hash_n(const char *name, unsigned long n)
  36. {
  37.   unsigned long h = 0;
  38.   unsigned long g;
  39.   unsigned char ch;
  40.  
  41.   while (n > 0)
  42.     {
  43.       ch = *name++;
  44.       h = (h << 4) + ch;
  45.       if ((g = (h & 0xf0000000)) != 0)
  46.     {
  47.       h ^= g >> 24;
  48.       h &= ~g;
  49.     }
  50.       n--;
  51.     }
  52.   return h;
  53. }
  54.  
  55. unsigned long
  56. obj_elf_hash (const char *name)
  57. {
  58.   return obj_elf_hash_n(name, strlen(name));
  59. }
  60.  
  61. void
  62. obj_set_symbol_compare (struct obj_file *f,
  63.                 int (*cmp)(const char *, const char *),
  64.             unsigned long (*hash)(const char *))
  65. {
  66.   if (cmp)
  67.     f->symbol_cmp = cmp;
  68.   if (hash)
  69.     {
  70.       struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next;
  71.       int i;
  72.  
  73.       f->symbol_hash = hash;
  74.  
  75.       memcpy(tmptab, f->symtab, sizeof(tmptab));
  76.       memset(f->symtab, 0, sizeof(f->symtab));
  77.  
  78.       for (i = 0; i < HASH_BUCKETS; ++i)
  79.     for (sym = tmptab[i]; sym ; sym = next)
  80.       {
  81.         unsigned long h = hash(sym->name) % HASH_BUCKETS;
  82.         next = sym->next;
  83.         sym->next = f->symtab[h];
  84.         f->symtab[h] = sym;
  85.       }
  86.     }
  87. }
  88.  
  89. struct obj_symbol *
  90. obj_add_symbol (struct obj_file *f, const char *name,
  91.         int info, int secidx, ElfW(Addr) value, unsigned long size)
  92. {
  93.   struct obj_symbol *sym;
  94.   unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
  95.  
  96.   for (sym = f->symtab[hash]; sym; sym = sym->next)
  97.     if (f->symbol_cmp(sym->name, name) == 0)
  98.       {
  99.     int o_secidx = sym->secidx;
  100.     int o_info = sym->info;
  101.     int o_type = ELFW(ST_TYPE)(o_info);
  102.     int o_binding = ELFW(ST_BIND)(o_info);
  103.     int n_type = ELFW(ST_TYPE)(info);
  104.     int n_binding = ELFW(ST_BIND)(info);
  105.  
  106.     /* A redefinition!  Is it legal?  */
  107.  
  108.     if (secidx == SHN_UNDEF)
  109.       return sym;
  110.     else if (o_secidx == SHN_UNDEF)
  111.       goto found;
  112.     else if (n_binding == STB_LOCAL)
  113.       goto found;
  114.     else if (o_binding == STB_LOCAL)
  115.       return sym;
  116.     else if (n_binding == STB_WEAK)
  117.       return sym;
  118.     else if (o_binding == STB_WEAK)
  119.       goto found;
  120.     /* Don't unify COMMON symbols with object types the programmer
  121.        doesn't expect.  */
  122.     else if (secidx == SHN_COMMON
  123.          && (o_type == STT_NOTYPE || o_type == STT_OBJECT))
  124.       return sym;
  125.     else if (o_secidx == SHN_COMMON
  126.          && (n_type == STT_NOTYPE || n_type == STT_OBJECT))
  127.       goto found;
  128.     else
  129.       {
  130.         /* Don't report an error if the symbol is coming from
  131.            the kernel or some external module.  */
  132.         if (secidx <= SHN_HIRESERVE)
  133.           error("%s multiply defined", name);
  134.         return sym;
  135.       }
  136.       }
  137.  
  138.   /* Completely new symbol.  */
  139.   sym = arch_new_symbol();
  140.   sym->next = f->symtab[hash];
  141.   f->symtab[hash] = sym;
  142.   sym->ksymidx = -1;
  143.  
  144. found:
  145.   sym->name = name;
  146.   sym->value = value;
  147.   sym->size = size;
  148.   sym->secidx = secidx;
  149.   sym->info = info;
  150.  
  151.   return sym;
  152. }
  153.  
  154. struct obj_symbol *
  155. obj_find_symbol (struct obj_file *f, const char *name)
  156. {
  157.   struct obj_symbol *sym;
  158.   unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
  159.  
  160.   for (sym = f->symtab[hash]; sym; sym = sym->next)
  161.     if (f->symbol_cmp(sym->name, name) == 0)
  162.       return sym;
  163.  
  164.   return NULL;
  165. }
  166.  
  167. ElfW(Addr)
  168. obj_symbol_final_value (struct obj_file *f, struct obj_symbol *sym)
  169. {
  170.   if (sym)
  171.     {
  172.       if (sym->secidx >= SHN_LORESERVE)
  173.     return sym->value;
  174.  
  175.       return sym->value + f->sections[sym->secidx]->header.sh_addr;
  176.     }
  177.   else
  178.     {
  179.       /* As a special case, a NULL sym has value zero.  */
  180.       return 0;
  181.     }
  182. }
  183.  
  184. struct obj_section *
  185. obj_find_section (struct obj_file *f, const char *name)
  186. {
  187.   int i, n = f->header.e_shnum;
  188.  
  189.   for (i = 0; i < n; ++i)
  190.     if (strcmp(f->sections[i]->name, name) == 0)
  191.       return f->sections[i];
  192.  
  193.   return NULL;
  194. }
  195.  
  196. static int
  197. obj_load_order_cmp(struct obj_section *a, struct obj_section *b)
  198. {
  199.   unsigned long af, bf, ac, bc;
  200.  
  201.   af = a->header.sh_flags;
  202.   bf = b->header.sh_flags;
  203.  
  204.   ac = 0;
  205.   if (af & SHF_ALLOC) ac |= 16;
  206.   if (!(af & SHF_WRITE)) ac |= 8;
  207.   if (af & SHF_EXECINSTR) ac |= 4;
  208.   if (a->header.sh_type != SHT_NOBITS) ac |= 2;
  209.  
  210.   bc = 0;
  211.   if (bf & SHF_ALLOC) bc |= 16;
  212.   if (!(bf & SHF_WRITE)) bc |= 8;
  213.   if (bf & SHF_EXECINSTR) bc |= 4;
  214.   if (b->header.sh_type != SHT_NOBITS) bc |= 2;
  215.  
  216.   return bc - ac;
  217. }
  218.  
  219. void
  220. obj_insert_section_load_order (struct obj_file *f, struct obj_section *sec)
  221. {
  222.   struct obj_section **p;
  223.   for (p = f->load_order_search_start; *p ; p = &(*p)->load_next)
  224.     if (obj_load_order_cmp(sec, *p) < 0)
  225.       break;
  226.   sec->load_next = *p;
  227.   *p = sec;
  228. }
  229.  
  230. struct obj_section *
  231. obj_create_alloced_section (struct obj_file *f, const char *name,
  232.                 unsigned long align, unsigned long size)
  233. {
  234.   int newidx = f->header.e_shnum++;
  235.   struct obj_section *sec;
  236.  
  237.   f->sections = xrealloc(f->sections, (newidx+1) * sizeof(sec));
  238.   f->sections[newidx] = sec = arch_new_section();
  239.  
  240.   memset(sec, 0, sizeof(*sec));
  241.   sec->header.sh_type = SHT_PROGBITS;
  242.   sec->header.sh_flags = SHF_WRITE|SHF_ALLOC;
  243.   sec->header.sh_size = size;
  244.   sec->header.sh_addralign = align;
  245.   sec->name = name;
  246.   sec->idx = newidx;
  247.   if (size)
  248.     sec->contents = xmalloc(size);
  249.  
  250.   obj_insert_section_load_order(f, sec);
  251.  
  252.   return sec;
  253. }
  254.  
  255. struct obj_section *
  256. obj_create_alloced_section_first (struct obj_file *f, const char *name,
  257.                   unsigned long align, unsigned long size)
  258. {
  259.   int newidx = f->header.e_shnum++;
  260.   struct obj_section *sec;
  261.  
  262.   f->sections = xrealloc(f->sections, (newidx+1) * sizeof(sec));
  263.   f->sections[newidx] = sec = arch_new_section();
  264.  
  265.   memset(sec, 0, sizeof(*sec));
  266.   sec->header.sh_type = SHT_PROGBITS;
  267.   sec->header.sh_flags = SHF_WRITE|SHF_ALLOC;
  268.   sec->header.sh_size = size;
  269.   sec->header.sh_addralign = align;
  270.   sec->name = name;
  271.   sec->idx = newidx;
  272.   if (size)
  273.     sec->contents = xmalloc(size);
  274.  
  275.   sec->load_next = f->load_order;
  276.   f->load_order = sec;
  277.   if (f->load_order_search_start == &f->load_order)
  278.     f->load_order_search_start = &sec->load_next;
  279.  
  280.   return sec;
  281. }
  282.  
  283. void *
  284. obj_extend_section (struct obj_section *sec, unsigned long more)
  285. {
  286.   unsigned long oldsize = sec->header.sh_size;
  287.   sec->contents = xrealloc(sec->contents, sec->header.sh_size += more);
  288.   return sec->contents + oldsize;
  289. }
  290.