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