resolve.c revision 1.57
1/* $OpenBSD: resolve.c,v 1.57 2011/11/28 20:59:03 guenther Exp $ */ 2 3/* 4 * Copyright (c) 1998 Per Fogelstrom, Opsycon AB 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29#define _DYN_LOADER 30 31#include <sys/types.h> 32 33#include <nlist.h> 34#include <link.h> 35#include "syscall.h" 36#include "archdep.h" 37#include "resolve.h" 38#include "dl_prebind.h" 39 40elf_object_t *_dl_objects; 41elf_object_t *_dl_last_object; 42elf_object_t *_dl_loading_object; 43 44/* 45 * Add a new dynamic object to the object list. 46 */ 47void 48_dl_add_object(elf_object_t *object) 49{ 50 /* if a .so is marked nodelete, then add a reference */ 51 if (object->obj_flags & DF_1_NODELETE && 52 (object->status & STAT_NODELETE) == 0) { 53 DL_DEB(("objname %s is nodelete\n", object->load_name)); 54 object->refcount++; 55 object->status |= STAT_NODELETE; 56 } 57 58 /* 59 * if this is a new object, prev will be NULL 60 * != NULL if an object already in the list 61 * prev == NULL for the first item in the list, but that will 62 * be the executable. 63 */ 64 if (object->prev != NULL) 65 return; 66 67 if (_dl_objects == NULL) { /* First object ? */ 68 _dl_last_object = _dl_objects = object; 69 } else { 70 _dl_last_object->next = object; 71 object->prev = _dl_last_object; 72 _dl_last_object = object; 73 } 74} 75 76/* 77 * Initialize a new dynamic object. 78 */ 79elf_object_t * 80_dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp, 81 int phdrc, const int objtype, const long lbase, const long obase) 82{ 83 elf_object_t *object; 84#if 0 85 _dl_printf("objname [%s], dynp %p, objtype %x lbase %lx, obase %lx\n", 86 objname, dynp, objtype, lbase, obase); 87#endif 88 object = _dl_malloc(sizeof(elf_object_t)); 89 object->prev = object->next = NULL; 90 91 object->load_dyn = dynp; 92 while (dynp->d_tag != DT_NULL) { 93 if (dynp->d_tag < DT_NUM) 94 object->Dyn.info[dynp->d_tag] = dynp->d_un.d_val; 95 else if (dynp->d_tag >= DT_LOPROC && 96 dynp->d_tag < DT_LOPROC + DT_PROCNUM) 97 object->Dyn.info[dynp->d_tag + DT_NUM - DT_LOPROC] = 98 dynp->d_un.d_val; 99 if (dynp->d_tag == DT_TEXTREL) 100 object->dyn.textrel = 1; 101 if (dynp->d_tag == DT_SYMBOLIC) 102 object->dyn.symbolic = 1; 103 if (dynp->d_tag == DT_BIND_NOW) 104 object->obj_flags |= DF_1_NOW; 105 if (dynp->d_tag == DT_FLAGS_1) 106 object->obj_flags |= dynp->d_un.d_val; 107 dynp++; 108 } 109 DL_DEB((" flags %s = 0x%x\n", objname, object->obj_flags )); 110 111 /* 112 * Now relocate all pointer to dynamic info, but only 113 * the ones which have pointer values. 114 */ 115 if (object->Dyn.info[DT_PLTGOT]) 116 object->Dyn.info[DT_PLTGOT] += obase; 117 if (object->Dyn.info[DT_HASH]) 118 object->Dyn.info[DT_HASH] += obase; 119 if (object->Dyn.info[DT_STRTAB]) 120 object->Dyn.info[DT_STRTAB] += obase; 121 if (object->Dyn.info[DT_SYMTAB]) 122 object->Dyn.info[DT_SYMTAB] += obase; 123 if (object->Dyn.info[DT_RELA]) 124 object->Dyn.info[DT_RELA] += obase; 125 if (object->Dyn.info[DT_SONAME]) 126 object->Dyn.info[DT_SONAME] += object->Dyn.info[DT_STRTAB]; 127 if (object->Dyn.info[DT_RPATH]) 128 object->Dyn.info[DT_RPATH] += object->Dyn.info[DT_STRTAB]; 129 if (object->Dyn.info[DT_REL]) 130 object->Dyn.info[DT_REL] += obase; 131 if (object->Dyn.info[DT_INIT]) 132 object->Dyn.info[DT_INIT] += obase; 133 if (object->Dyn.info[DT_FINI]) 134 object->Dyn.info[DT_FINI] += obase; 135 if (object->Dyn.info[DT_JMPREL]) 136 object->Dyn.info[DT_JMPREL] += obase; 137 138 if (object->Dyn.info[DT_HASH] != 0) { 139 Elf_Word *hashtab = (Elf_Word *)object->Dyn.info[DT_HASH]; 140 141 object->nbuckets = hashtab[0]; 142 object->nchains = hashtab[1]; 143 object->buckets = hashtab + 2; 144 object->chains = object->buckets + object->nbuckets; 145 } 146 147 object->phdrp = phdrp; 148 object->phdrc = phdrc; 149 object->obj_type = objtype; 150 object->load_base = lbase; 151 object->obj_base = obase; 152 object->load_name = _dl_strdup(objname); 153 if (_dl_loading_object == NULL) { 154 /* 155 * no loading object, object is the loading object, 156 * as it is either executable, or dlopened() 157 */ 158 _dl_loading_object = object->load_object = object; 159 DL_DEB(("head %s\n", object->load_name )); 160 } else { 161 object->load_object = _dl_loading_object; 162 } 163 DL_DEB(("obj %s has %s as head\n", object->load_name, 164 _dl_loading_object->load_name )); 165 object->refcount = 0; 166 TAILQ_INIT(&object->child_list); 167 object->opencount = 0; /* # dlopen() & exe */ 168 object->grprefcount = 0; 169 /* default dev, inode for dlopen-able objects. */ 170 object->dev = 0; 171 object->inode = 0; 172 object->lastlookup = 0; 173 TAILQ_INIT(&object->grpsym_list); 174 TAILQ_INIT(&object->grpref_list); 175 176 return(object); 177} 178 179void 180_dl_tailq_free(struct dep_node *n) 181{ 182 struct dep_node *next; 183 184 while (n != NULL) { 185 next = TAILQ_NEXT(n, next_sib); 186 _dl_free(n); 187 n = next; 188 } 189} 190 191elf_object_t *free_objects; 192 193void _dl_cleanup_objects(void); 194void 195_dl_cleanup_objects() 196{ 197 elf_object_t *nobj, *head; 198 struct dep_node *n, *next; 199 200 n = TAILQ_FIRST(&_dlopened_child_list); 201 while (n != NULL) { 202 next = TAILQ_NEXT(n, next_sib); 203 if (OBJECT_DLREF_CNT(n->data) == 0) { 204 TAILQ_REMOVE(&_dlopened_child_list, n, next_sib); 205 _dl_free(n); 206 } 207 n = next; 208 } 209 210 head = free_objects; 211 free_objects = NULL; 212 while (head != NULL) { 213 if (head->load_name) 214 _dl_free(head->load_name); 215 if (head->sod.sod_name) 216 _dl_free((char *)head->sod.sod_name); 217 _dl_tailq_free(TAILQ_FIRST(&head->grpsym_list)); 218 _dl_tailq_free(TAILQ_FIRST(&head->child_list)); 219 _dl_tailq_free(TAILQ_FIRST(&head->grpref_list)); 220 nobj = head->next; 221 _dl_free(head); 222 head = nobj; 223 } 224} 225 226void 227_dl_remove_object(elf_object_t *object) 228{ 229 object->prev->next = object->next; 230 if (object->next) 231 object->next->prev = object->prev; 232 233 if (_dl_last_object == object) 234 _dl_last_object = object->prev; 235 236 object->next = free_objects; 237 free_objects = object; 238} 239 240 241int _dl_find_symbol_obj(elf_object_t *object, const char *name, 242 unsigned long hash, int flags, const Elf_Sym **ref, 243 const Elf_Sym **weak_sym, 244 elf_object_t **weak_object); 245 246sym_cache *_dl_symcache; 247int _dl_symcachestat_hits; 248int _dl_symcachestat_lookups; 249 250 251Elf_Addr 252_dl_find_symbol_bysym(elf_object_t *req_obj, unsigned int symidx, 253 const Elf_Sym **this, int flags, const Elf_Sym *ref_sym, const elf_object_t **pobj) 254{ 255 Elf_Addr ret; 256 const Elf_Sym *sym; 257 const char *symn; 258 const elf_object_t *sobj; 259 260 _dl_symcachestat_lookups ++; 261 if (_dl_symcache != NULL && 262 symidx < req_obj->nchains && 263 _dl_symcache[symidx].obj != NULL && 264 _dl_symcache[symidx].sym != NULL && 265 _dl_symcache[symidx].flags == flags) { 266 267 _dl_symcachestat_hits++; 268 sobj = _dl_symcache[symidx].obj; 269 *this = _dl_symcache[symidx].sym; 270 if (pobj) 271 *pobj = sobj; 272 if (_dl_prebind_validate) /* XXX */ 273 prebind_validate(req_obj, symidx, flags, ref_sym); 274 return sobj->obj_base; 275 } 276 277 sym = req_obj->dyn.symtab; 278 sym += symidx; 279 symn = req_obj->dyn.strtab + sym->st_name; 280 281 ret = _dl_find_symbol(symn, this, flags, ref_sym, req_obj, &sobj); 282 283 if (pobj) 284 *pobj = sobj; 285 286 if (_dl_symcache != NULL && symidx < req_obj->nchains) { 287#if 0 288 DL_DEB(("cache miss %d %p %p, %p %p %s %s %d %d %s\n", 289 symidx, 290 _dl_symcache[symidx].sym, *this, 291 _dl_symcache[symidx].obj, sobj, sobj->load_name, 292 sobj->dyn.strtab + (*this)->st_name, 293 _dl_symcache[symidx].flags, flags, req_obj->load_name)); 294#endif 295 296 _dl_symcache[symidx].sym = *this; 297 _dl_symcache[symidx].obj = sobj; 298 _dl_symcache[symidx].flags = flags; 299 } 300 301 return ret; 302} 303 304int _dl_searchnum = 0; 305void 306_dl_newsymsearch(void) 307{ 308 _dl_searchnum += 1; 309 310 if (_dl_searchnum < 0) { 311 /* 312 * If the signed number rolls over, reset all counters so 313 * we dont get accidental collision. 314 */ 315 elf_object_t *walkobj; 316 for (walkobj = _dl_objects; 317 walkobj != NULL; 318 walkobj = walkobj->next) { 319 walkobj->lastlookup = 0; 320 } 321 _dl_searchnum = 1; 322 } 323} 324 325Elf_Addr 326_dl_find_symbol(const char *name, const Elf_Sym **this, 327 int flags, const Elf_Sym *ref_sym, elf_object_t *req_obj, 328 const elf_object_t **pobj) 329{ 330 const Elf_Sym *weak_sym = NULL; 331 unsigned long h = 0; 332 const char *p = name; 333 elf_object_t *object = NULL, *weak_object = NULL; 334 int found = 0; 335 struct dep_node *n, *m; 336 337 338 while (*p) { 339 unsigned long g; 340 h = (h << 4) + *p++; 341 if ((g = h & 0xf0000000)) 342 h ^= g >> 24; 343 h &= ~g; 344 } 345 346 if (req_obj->dyn.symbolic) 347 if (_dl_find_symbol_obj(req_obj, name, h, flags, this, &weak_sym, 348 &weak_object)) { 349 object = req_obj; 350 found = 1; 351 goto found; 352 } 353 354 if (flags & SYM_SEARCH_OBJ) { 355 if (_dl_find_symbol_obj(req_obj, name, h, flags, this, 356 &weak_sym, &weak_object)) { 357 object = req_obj; 358 found = 1; 359 } 360 } else if (flags & SYM_DLSYM) { 361 if (_dl_find_symbol_obj(req_obj, name, h, flags, this, 362 &weak_sym, &weak_object)) { 363 object = req_obj; 364 found = 1; 365 } 366 if (weak_object != NULL && found == 0) { 367 object=weak_object; 368 *this = weak_sym; 369 found = 1; 370 } 371 /* search dlopened obj and all children */ 372 373 if (found == 0) { 374 TAILQ_FOREACH(n, &req_obj->load_object->grpsym_list, 375 next_sib) { 376 if (_dl_find_symbol_obj(n->data, name, h, 377 flags, this, 378 &weak_sym, &weak_object)) { 379 object = n->data; 380 found = 1; 381 break; 382 } 383 } 384 } 385 } else { 386 int skip = 0; 387 388 if ((flags & SYM_SEARCH_SELF) || (flags & SYM_SEARCH_NEXT)) 389 skip = 1; 390 391 _dl_newsymsearch(); 392 393 /* 394 * search dlopened objects: global or req_obj == dlopened_obj 395 * and and it's children 396 */ 397 TAILQ_FOREACH(n, &_dlopened_child_list, next_sib) { 398 if (((n->data->obj_flags & DF_1_GLOBAL) == 0) && 399 (n->data != req_obj->load_object)) 400 continue; 401 402 n->data->lastlookup_head = _dl_searchnum; 403 TAILQ_FOREACH(m, &n->data->grpsym_list, next_sib) { 404 if (skip == 1) { 405 if (m->data == req_obj) { 406 skip = 0; 407 if (flags & SYM_SEARCH_NEXT) 408 continue; 409 } else 410 continue; 411 } 412 if ((flags & SYM_SEARCH_OTHER) && 413 (m->data == req_obj)) 414 continue; 415 m->data->lastlookup = _dl_searchnum; 416 if (_dl_find_symbol_obj(m->data, name, h, flags, 417 this, &weak_sym, &weak_object)) { 418 object = m->data; 419 found = 1; 420 goto found; 421 } 422 } 423 } 424 } 425 426found: 427 if (weak_object != NULL && found == 0) { 428 object=weak_object; 429 *this = weak_sym; 430 found = 1; 431 } 432 433 434 if (found == 0) { 435 if ((ref_sym == NULL || 436 (ELF_ST_BIND(ref_sym->st_info) != STB_WEAK)) && 437 (flags & SYM_WARNNOTFOUND)) 438 _dl_printf("%s:%s: undefined symbol '%s'\n", 439 _dl_progname, req_obj->load_name, name); 440 return (0); 441 } 442 443 if (ref_sym != NULL && ref_sym->st_size != 0 && 444 (ref_sym->st_size != (*this)->st_size) && 445 (ELF_ST_TYPE((*this)->st_info) != STT_FUNC) ) { 446 _dl_printf("%s:%s: %s : WARNING: " 447 "symbol(%s) size mismatch, relink your program\n", 448 _dl_progname, req_obj->load_name, 449 object->load_name, name); 450 } 451 452 if (pobj) 453 *pobj = object; 454 455 return (object->obj_base); 456} 457 458int 459_dl_find_symbol_obj(elf_object_t *object, const char *name, unsigned long hash, 460 int flags, const Elf_Sym **this, const Elf_Sym **weak_sym, 461 elf_object_t **weak_object) 462{ 463 const Elf_Sym *symt = object->dyn.symtab; 464 const char *strt = object->dyn.strtab; 465 long si; 466 const char *symn; 467 468 for (si = object->buckets[hash % object->nbuckets]; 469 si != STN_UNDEF; si = object->chains[si]) { 470 const Elf_Sym *sym = symt + si; 471 472 if (sym->st_value == 0) 473 continue; 474 475 if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE && 476 ELF_ST_TYPE(sym->st_info) != STT_OBJECT && 477 ELF_ST_TYPE(sym->st_info) != STT_FUNC) 478 continue; 479 480 symn = strt + sym->st_name; 481 if (sym != *this && _dl_strcmp(symn, name)) 482 continue; 483 484 /* allow this symbol if we are referring to a function 485 * which has a value, even if section is UNDEF. 486 * this allows &func to refer to PLT as per the 487 * ELF spec. st_value is checked above. 488 * if flags has SYM_PLT set, we must have actual 489 * symbol, so this symbol is skipped. 490 */ 491 if (sym->st_shndx == SHN_UNDEF) { 492 if ((flags & SYM_PLT) || sym->st_value == 0 || 493 ELF_ST_TYPE(sym->st_info) != STT_FUNC) 494 continue; 495 } 496 497 if (ELF_ST_BIND(sym->st_info) == STB_GLOBAL) { 498 *this = sym; 499 return 1; 500 } else if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { 501 if (!*weak_sym) { 502 *weak_sym = sym; 503 *weak_object = object; 504 } 505 } 506 } 507 return 0; 508} 509 510void 511_dl_debug_state(void) 512{ 513 /* Debugger stub */ 514} 515