home *** CD-ROM | disk | FTP | other *** search
- /* Run an ELF binary on a linux system.
-
- Copyright (C) 1993, Eric Youngdale.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
-
- /* Various symbol table handling functions, including symbol lookup */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #ifdef IBCS_COMPATIBLE
- #include <ibcs/unistd.h>
- #else
- #include <linux/unistd.h>
- #endif
- #include "hash.h"
- #include "linuxelf.h"
- #include "syscall.h"
- #include "string.h"
-
-
- /*
- * This is the start of the linked list that describes all of the files present
- * in the system with pointers to all of the symbol, string, and hash tables,
- * as well as all of the other good stuff in the binary.
- */
-
- struct elf_resolve * _dl_loaded_modules = NULL;
-
- /*
- * This is the list of modules that are loaded when the image is first
- * started. As we add more via dlopen, they get added into other
- * chains.
- */
- struct dyn_elf * _dl_symbol_tables = NULL;
-
- /*
- * This is the hash function that is used by the ELF linker to generate
- * the hash table that each executable and library is required to
- * have. We need it to decode the hash table.
- */
-
- unsigned long _dl_elf_hash(const char * name){
- unsigned long hash = 0;
- unsigned long tmp;
-
- while (*name){
- hash = (hash << 4) + *name++;
- if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24;
- hash &= ~tmp;
- };
- return hash;
- }
-
- /*
- * Check to see if a library has already been added to the hash chain.
- */
- struct elf_resolve * _dl_check_hashed_files(char * libname){
- struct elf_resolve * tpnt;
- tpnt = _dl_loaded_modules;
- while(tpnt){
- if(_dl_strcmp(tpnt->libname, libname) == 0) return tpnt;
- tpnt = tpnt->next;
- };
- return NULL;
- }
-
- /*
- * We call this function when we have just read an ELF library or executable.
- * We add the relevant info to the symbol chain, so that we can resolve all
- * externals properly.
- */
-
- struct elf_resolve * _dl_add_elf_hash_table(char * libname,
- char * loadaddr,
- unsigned int * dynamic_info,
- unsigned int dynamic_addr,
- unsigned int dynamic_size){
- unsigned int * hash_addr;
- struct elf_resolve * tpnt;
- int i;
-
- if (!_dl_loaded_modules)
- tpnt = _dl_loaded_modules =
- (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
- else {
- tpnt = _dl_loaded_modules;
- while(tpnt->next) tpnt = tpnt->next;
- tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
- tpnt = tpnt->next;
- };
-
- hash_addr = (unsigned int *) (dynamic_info[DT_HASH] + loadaddr);
- tpnt->next = NULL;
- tpnt->init_flag = 0;
- tpnt->nbucket = *hash_addr++;
- tpnt->nchain = *hash_addr++;
- tpnt->libname = _dl_strdup(libname);
- tpnt->elf_buckets = hash_addr;
- hash_addr += tpnt->nbucket;
- tpnt->dynamic_addr = dynamic_addr;
- tpnt->dynamic_size = dynamic_size;
- tpnt->libtype = elf_lib;
-
- tpnt->chains = hash_addr;
- tpnt->loadaddr = loadaddr;
- for(i=0; i<24; i++) tpnt->dynamic_info[i] = dynamic_info[i];
- return tpnt;
- }
-
-
- /*
- * This function resolves externals, and this is either called when we process
- * relocations or when we call an entry in the PLT table for the first time.
- */
-
- char * _dl_find_hash(char * name, struct dyn_elf * rpnt1,
- unsigned int instr_addr, struct elf_resolve * f_tpnt){
- struct elf_resolve * tpnt;
- int si;
- char * pnt;
- char * strtab;
- struct Elf32_Sym * symtab;
- unsigned int elf_hash_number, hn;
- char * weak_result;
- struct elf_resolve * first_def;
- struct dyn_elf * rpnt;
-
- weak_result = 0;
- elf_hash_number = _dl_elf_hash(name);
-
- for(rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables);
- rpnt; rpnt = rpnt->next) {
- tpnt = rpnt->dyn;
- hn = elf_hash_number % tpnt->nbucket;
- symtab = (struct Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] +
- tpnt->loadaddr);
- strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
- /*
- * This crap is required because the first instance of a symbol on the
- * chain will be used for all symbol references. Thus this instance
- * must be resolved to an address that contains the actual function,
- */
-
- first_def = NULL;
-
- for(si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]){
- pnt = strtab + symtab[si].st_name;
-
- if(_dl_strcmp(pnt, name) == 0 &&
- (ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC ||
- ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) &&
- symtab[si].st_value != 0) {
-
- /* Here we make sure that we find a module where the symbol is
- * actually defined.
- */
-
- if(!first_def) first_def = tpnt;
- if(f_tpnt && first_def == f_tpnt && symtab[si].st_shndx == 0)
- continue;
-
- switch(ELF32_ST_BIND(symtab[si].st_info)){
- case STB_GLOBAL:
- return tpnt->loadaddr + symtab[si].st_value;
- case STB_WEAK:
- if (!weak_result) weak_result = tpnt->loadaddr + symtab[si].st_value;
- break;
- default: /* Do local symbols need to be examined? */
- break;
- }
- }
- }
- }
- return weak_result;
- }
-
-
-