1 /* $NetBSD: symbol.c,v 1.11 2001/10/14 23:13:21 rafal Exp $ */ 2 3 /* 4 * Copyright 1996 John D. Polstra. 5 * Copyright 1996 Matt Thomas <matt@3am-software.com> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by John Polstra. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Dynamic linker for ELF. 36 * 37 * John Polstra <jdp@polstra.com>. 38 */ 39 40 #include <err.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <stdarg.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <sys/types.h> 49 #include <sys/mman.h> 50 #include <dirent.h> 51 52 #include "debug.h" 53 #include "rtld.h" 54 55 /* 56 * Hash function for symbol table lookup. Don't even think about changing 57 * this. It is specified by the System V ABI. 58 */ 59 unsigned long 60 _rtld_elf_hash(name) 61 const char *name; 62 { 63 const unsigned char *p = (const unsigned char *) name; 64 unsigned long h = 0; 65 unsigned long g; 66 67 while (*p != '\0') { 68 h = (h << 4) + *p++; 69 if ((g = h & 0xf0000000) != 0) 70 h ^= g >> 24; 71 h &= ~g; 72 } 73 return h; 74 } 75 76 const Elf_Sym * 77 _rtld_symlook_list(const char *name, unsigned long hash, Objlist *objlist, 78 const Obj_Entry **defobj_out, bool in_plt) 79 { 80 const Elf_Sym *symp; 81 const Elf_Sym *def; 82 const Obj_Entry *defobj; 83 const Objlist_Entry *elm; 84 85 def = NULL; 86 defobj = NULL; 87 for (elm = SIMPLEQ_FIRST(objlist); elm; elm = SIMPLEQ_NEXT(elm, link)) { 88 if (elm->obj->mark == _rtld_curmark) 89 continue; 90 elm->obj->mark = _rtld_curmark; 91 if ((symp = _rtld_symlook_obj(name, hash, elm->obj, in_plt)) 92 != NULL) { 93 if ((def == NULL) || 94 (ELF_ST_BIND(symp->st_info) != STB_WEAK)) { 95 def = symp; 96 defobj = elm->obj; 97 if (ELF_ST_BIND(def->st_info) != STB_WEAK) 98 break; 99 } 100 } 101 } 102 if (def != NULL) 103 *defobj_out = defobj; 104 return def; 105 } 106 107 /* 108 * Search the symbol table of a single shared object for a symbol of 109 * the given name. Returns a pointer to the symbol, or NULL if no 110 * definition was found. 111 * 112 * The symbol's hash value is passed in for efficiency reasons; that 113 * eliminates many recomputations of the hash value. 114 */ 115 const Elf_Sym * 116 _rtld_symlook_obj(name, hash, obj, in_plt) 117 const char *name; 118 unsigned long hash; 119 const Obj_Entry *obj; 120 bool in_plt; 121 { 122 unsigned long symnum = obj->buckets[hash % obj->nbuckets]; 123 124 while (symnum != ELF_SYM_UNDEFINED) { 125 const Elf_Sym *symp; 126 const char *strp; 127 128 assert(symnum < obj->nchains); 129 symp = obj->symtab + symnum; 130 strp = obj->strtab + symp->st_name; 131 #if 0 132 assert(symp->st_name != 0); 133 #endif 134 if (strcmp(name, strp) == 0) { 135 if (symp->st_shndx != SHN_UNDEF 136 #if !defined(__mips__) /* Following doesn't work on MIPS? mhitch */ 137 || (!in_plt && symp->st_value != 0 && 138 ELF_ST_TYPE(symp->st_info) == STT_FUNC) 139 #endif 140 ) { 141 return symp; 142 } 143 } 144 symnum = obj->chains[symnum]; 145 } 146 147 return NULL; 148 } 149 150 /* 151 * Given a symbol number in a referencing object, find the corresponding 152 * definition of the symbol. Returns a pointer to the symbol, or NULL if 153 * no definition was found. Returns a pointer to the Obj_Entry of the 154 * defining object via the reference parameter DEFOBJ_OUT. 155 */ 156 const Elf_Sym * 157 _rtld_find_symdef(obj_list, r_info, name, refobj, defobj_out, in_plt) 158 const Obj_Entry *obj_list; 159 Elf_Addr r_info; 160 const char *name; 161 Obj_Entry *refobj; 162 const Obj_Entry **defobj_out; 163 bool in_plt; 164 { 165 Elf_Addr symnum = ELF_R_SYM(r_info); 166 const Elf_Sym *ref; 167 const Elf_Sym *def; 168 const Elf_Sym *symp; 169 const Obj_Entry *obj; 170 const Obj_Entry *defobj; 171 const Objlist_Entry *elm; 172 unsigned long hash; 173 174 ref = refobj->symtab + symnum; 175 if (name == NULL) 176 name = refobj->strtab + ref->st_name; 177 178 hash = _rtld_elf_hash(name); 179 def = NULL; 180 defobj = NULL; 181 _rtld_curmark++; 182 183 if (refobj->symbolic) { /* Look first in the referencing object */ 184 symp = _rtld_symlook_obj(name, hash, refobj, in_plt); 185 refobj->mark = _rtld_curmark; 186 if (symp != NULL) { 187 def = symp; 188 defobj = refobj; 189 } 190 } 191 192 /* Search all objects loaded at program start up. */ 193 if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { 194 symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, in_plt); 195 if (symp != NULL && 196 (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { 197 def = symp; 198 defobj = obj; 199 } 200 } 201 202 /* Search all dlopened DAGs containing the referencing object. */ 203 for (elm = SIMPLEQ_FIRST(&refobj->dldags); elm; elm = SIMPLEQ_NEXT(elm, link)) { 204 if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK) 205 break; 206 symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj, 207 in_plt); 208 if (symp != NULL && 209 (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { 210 def = symp; 211 defobj = obj; 212 } 213 } 214 215 /* Search all RTLD_GLOBAL objects. */ 216 if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { 217 symp = _rtld_symlook_list(name, hash, &_rtld_list_global, &obj, in_plt); 218 if (symp != NULL && 219 (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { 220 def = symp; 221 defobj = obj; 222 } 223 } 224 225 /* 226 * If we found no definition and the reference is weak, treat the 227 * symbol as having the value zero. 228 */ 229 if (def == NULL && ELF_ST_BIND(ref->st_info) == STB_WEAK) { 230 rdbg(1, (" returning _rtld_sym_zero@_rtld_objmain")); 231 def = &_rtld_sym_zero; 232 defobj = _rtld_objmain; 233 } 234 235 if (def != NULL) 236 *defobj_out = defobj; 237 else if (ELF_R_TYPE(r_info) != R_TYPE(NONE)) { 238 _rtld_error( 239 "%s: Undefined %ssymbol \"%s\" (reloc type = %ld, symnum = %ld)", 240 refobj->path, in_plt ? "PLT " : "", name, 241 (u_long) ELF_R_TYPE(r_info), (u_long) symnum); 242 } 243 return def; 244 } 245