home *** CD-ROM | disk | FTP | other *** search
/ Serving the Web / ServingTheWeb1995.disc1of1.iso / linux / slacksrce / d / libc / libc-4.6 / libc-4 / libc-linux / elf / d-link.old / hash.c next >
Encoding:
C/C++ Source or Header  |  1994-10-20  |  5.4 KB  |  194 lines

  1. /* Run an ELF binary on a linux system.
  2.  
  3.    Copyright (C) 1993, Eric Youngdale.
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19.  
  20.  
  21. /* Various symbol table handling functions, including symbol lookup */
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #ifdef IBCS_COMPATIBLE
  27. #include <ibcs/unistd.h>
  28. #else
  29. #include <linux/unistd.h>
  30. #endif
  31. #include "hash.h"
  32. #include "linuxelf.h"
  33. #include "syscall.h"
  34. #include "string.h"
  35.  
  36.  
  37. /*
  38.  * This is the start of the linked list that describes all of the files present
  39.  * in the system with pointers to all of the symbol, string, and hash tables, 
  40.  * as well as all of the other good stuff in the binary.
  41.  */
  42.  
  43. struct elf_resolve * _dl_loaded_modules = NULL;
  44.  
  45. /*
  46.  * This is the list of modules that are loaded when the image is first
  47.  * started.  As we add more via dlopen, they get added into other
  48.  * chains.
  49.  */
  50. struct dyn_elf * _dl_symbol_tables = NULL;
  51.  
  52. /*
  53.  * This is the hash function that is used by the ELF linker to generate
  54.  * the hash table that each executable and library is required to
  55.  * have.  We need it to decode the hash table.
  56.  */
  57.  
  58. unsigned long _dl_elf_hash(const char * name){
  59.   unsigned long hash = 0;
  60.   unsigned long tmp;
  61.  
  62.   while (*name){
  63.     hash = (hash << 4) + *name++;
  64.     if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24;
  65.     hash &= ~tmp;
  66.   };
  67.   return hash;
  68. }
  69.  
  70. /*
  71.  * Check to see if a library has already been added to the hash chain.
  72.  */
  73. struct elf_resolve * _dl_check_hashed_files(char * libname){
  74.   struct elf_resolve * tpnt;
  75.   tpnt = _dl_loaded_modules;
  76.   while(tpnt){
  77.     if(_dl_strcmp(tpnt->libname, libname) == 0) return tpnt;
  78.     tpnt = tpnt->next;
  79.   };
  80.   return NULL;
  81. }
  82.  
  83. /*
  84.  * We call this function when we have just read an ELF library or executable.
  85.  * We add the relevant info to the symbol chain, so that we can resolve all
  86.  * externals properly.
  87.  */
  88.  
  89. struct elf_resolve * _dl_add_elf_hash_table(char * libname,
  90.                     char * loadaddr,
  91.                     unsigned int * dynamic_info,
  92.                     unsigned int dynamic_addr,
  93.                     unsigned int dynamic_size){
  94.   unsigned int *  hash_addr;
  95.   struct elf_resolve * tpnt;
  96.   int i;
  97.  
  98.   if (!_dl_loaded_modules)
  99.     tpnt = _dl_loaded_modules = 
  100.       (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
  101.   else {
  102.     tpnt = _dl_loaded_modules;
  103.     while(tpnt->next) tpnt = tpnt->next;
  104.     tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
  105.     tpnt = tpnt->next;
  106.   };
  107.   
  108.   hash_addr = (unsigned int *) (dynamic_info[DT_HASH] + loadaddr);
  109.   tpnt->next = NULL;
  110.   tpnt->init_flag = 0;
  111.   tpnt->nbucket = *hash_addr++;
  112.   tpnt->nchain = *hash_addr++;
  113.   tpnt->libname = _dl_strdup(libname);
  114.   tpnt->elf_buckets = hash_addr;
  115.   hash_addr += tpnt->nbucket;
  116.   tpnt->dynamic_addr = dynamic_addr;
  117.   tpnt->dynamic_size = dynamic_size;
  118.   tpnt->libtype = elf_lib;
  119.  
  120.   tpnt->chains = hash_addr;
  121.   tpnt->loadaddr = loadaddr;
  122.   for(i=0; i<24; i++) tpnt->dynamic_info[i] = dynamic_info[i];
  123.   return tpnt;
  124. }
  125.  
  126.  
  127. /*
  128.  * This function resolves externals, and this is either called when we process
  129.  * relocations or when we call an entry in the PLT table for the first time.
  130.  */
  131.  
  132. char * _dl_find_hash(char * name, struct dyn_elf * rpnt1, 
  133.              unsigned int instr_addr, struct elf_resolve * f_tpnt){
  134.   struct elf_resolve * tpnt;
  135.   int si;
  136.   char * pnt;
  137.   char * strtab;
  138.   struct Elf32_Sym * symtab;
  139.   unsigned int elf_hash_number, hn;
  140.   char * weak_result;
  141.   struct elf_resolve * first_def;
  142.   struct dyn_elf * rpnt;
  143.  
  144.   weak_result = 0;
  145.   elf_hash_number = _dl_elf_hash(name);
  146.  
  147.   for(rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables); 
  148.       rpnt; rpnt = rpnt->next) {
  149.     tpnt = rpnt->dyn;
  150.     hn = elf_hash_number % tpnt->nbucket;
  151.     symtab = (struct Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + 
  152.                    tpnt->loadaddr);
  153.     strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
  154.     /*
  155.      * This crap is required because the first instance of a symbol on the
  156.      * chain will be used for all symbol references.  Thus this instance
  157.      * must be resolved to an address that contains the actual function,
  158.      */
  159.  
  160.     first_def = NULL;
  161.  
  162.     for(si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]){
  163.       pnt = strtab + symtab[si].st_name;
  164.  
  165.       if(_dl_strcmp(pnt, name) == 0 && 
  166.      (ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC ||
  167.       ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) &&
  168.      symtab[si].st_value != 0) {
  169.  
  170.     /* Here we make sure that we find a module where the symbol is
  171.      * actually defined.
  172.      */
  173.  
  174.     if(!first_def) first_def = tpnt;
  175.     if(f_tpnt && first_def == f_tpnt && symtab[si].st_shndx == 0)
  176.       continue;
  177.  
  178.     switch(ELF32_ST_BIND(symtab[si].st_info)){
  179.     case STB_GLOBAL:
  180.       return tpnt->loadaddr + symtab[si].st_value;
  181.     case STB_WEAK:
  182.       if (!weak_result) weak_result = tpnt->loadaddr + symtab[si].st_value;
  183.         break;
  184.     default:  /* Do local symbols need to be examined? */
  185.       break;
  186.     }
  187.       }
  188.     }
  189.   }
  190.   return weak_result;
  191. }
  192.  
  193.  
  194.