resolve.c revision 1.58
1/* $OpenBSD: resolve.c,v 1.58 2012/06/14 21:30:50 kettenis 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 object->obj_type = objtype; 111 112 if (_dl_loading_object == NULL) { 113 /* 114 * no loading object, object is the loading object, 115 * as it is either executable, or dlopened() 116 */ 117 _dl_loading_object = object; 118 DL_DEB(("head %s\n", object->load_name)); 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 DL_DEB(("obj %s has %s as head\n", object->load_name, 172 _dl_loading_object->load_name )); 173 object->refcount = 0; 174 TAILQ_INIT(&object->child_list); 175 object->opencount = 0; /* # dlopen() & exe */ 176 object->grprefcount = 0; 177 /* default dev, inode for dlopen-able objects. */ 178 object->dev = 0; 179 object->inode = 0; 180 object->lastlookup = 0; 181 TAILQ_INIT(&object->grpsym_list); 182 TAILQ_INIT(&object->grpref_list); 183 184 return(object); 185} 186 187void 188_dl_tailq_free(struct dep_node *n) 189{ 190 struct dep_node *next; 191 192 while (n != NULL) { 193 next = TAILQ_NEXT(n, next_sib); 194 _dl_free(n); 195 n = next; 196 } 197} 198 199elf_object_t *free_objects; 200 201void _dl_cleanup_objects(void); 202void 203_dl_cleanup_objects() 204{ 205 elf_object_t *nobj, *head; 206 struct dep_node *n, *next; 207 208 n = TAILQ_FIRST(&_dlopened_child_list); 209 while (n != NULL) { 210 next = TAILQ_NEXT(n, next_sib); 211 if (OBJECT_DLREF_CNT(n->data) == 0) { 212 TAILQ_REMOVE(&_dlopened_child_list, n, next_sib); 213 _dl_free(n); 214 } 215 n = next; 216 } 217 218 head = free_objects; 219 free_objects = NULL; 220 while (head != NULL) { 221 if (head->load_name) 222 _dl_free(head->load_name); 223 if (head->sod.sod_name) 224 _dl_free((char *)head->sod.sod_name); 225 _dl_tailq_free(TAILQ_FIRST(&head->grpsym_list)); 226 _dl_tailq_free(TAILQ_FIRST(&head->child_list)); 227 _dl_tailq_free(TAILQ_FIRST(&head->grpref_list)); 228 nobj = head->next; 229 _dl_free(head); 230 head = nobj; 231 } 232} 233 234void 235_dl_remove_object(elf_object_t *object) 236{ 237 object->prev->next = object->next; 238 if (object->next) 239 object->next->prev = object->prev; 240 241 if (_dl_last_object == object) 242 _dl_last_object = object->prev; 243 244 object->next = free_objects; 245 free_objects = object; 246} 247 248 249int _dl_find_symbol_obj(elf_object_t *object, const char *name, 250 unsigned long hash, int flags, const Elf_Sym **ref, 251 const Elf_Sym **weak_sym, 252 elf_object_t **weak_object); 253 254sym_cache *_dl_symcache; 255int _dl_symcachestat_hits; 256int _dl_symcachestat_lookups; 257 258 259Elf_Addr 260_dl_find_symbol_bysym(elf_object_t *req_obj, unsigned int symidx, 261 const Elf_Sym **this, int flags, const Elf_Sym *ref_sym, const elf_object_t **pobj) 262{ 263 Elf_Addr ret; 264 const Elf_Sym *sym; 265 const char *symn; 266 const elf_object_t *sobj; 267 268 _dl_symcachestat_lookups ++; 269 if (_dl_symcache != NULL && 270 symidx < req_obj->nchains && 271 _dl_symcache[symidx].obj != NULL && 272 _dl_symcache[symidx].sym != NULL && 273 _dl_symcache[symidx].flags == flags) { 274 275 _dl_symcachestat_hits++; 276 sobj = _dl_symcache[symidx].obj; 277 *this = _dl_symcache[symidx].sym; 278 if (pobj) 279 *pobj = sobj; 280 if (_dl_prebind_validate) /* XXX */ 281 prebind_validate(req_obj, symidx, flags, ref_sym); 282 return sobj->obj_base; 283 } 284 285 sym = req_obj->dyn.symtab; 286 sym += symidx; 287 symn = req_obj->dyn.strtab + sym->st_name; 288 289 ret = _dl_find_symbol(symn, this, flags, ref_sym, req_obj, &sobj); 290 291 if (pobj) 292 *pobj = sobj; 293 294 if (_dl_symcache != NULL && symidx < req_obj->nchains) { 295#if 0 296 DL_DEB(("cache miss %d %p %p, %p %p %s %s %d %d %s\n", 297 symidx, 298 _dl_symcache[symidx].sym, *this, 299 _dl_symcache[symidx].obj, sobj, sobj->load_name, 300 sobj->dyn.strtab + (*this)->st_name, 301 _dl_symcache[symidx].flags, flags, req_obj->load_name)); 302#endif 303 304 _dl_symcache[symidx].sym = *this; 305 _dl_symcache[symidx].obj = sobj; 306 _dl_symcache[symidx].flags = flags; 307 } 308 309 return ret; 310} 311 312int _dl_searchnum = 0; 313void 314_dl_newsymsearch(void) 315{ 316 _dl_searchnum += 1; 317 318 if (_dl_searchnum < 0) { 319 /* 320 * If the signed number rolls over, reset all counters so 321 * we dont get accidental collision. 322 */ 323 elf_object_t *walkobj; 324 for (walkobj = _dl_objects; 325 walkobj != NULL; 326 walkobj = walkobj->next) { 327 walkobj->lastlookup = 0; 328 } 329 _dl_searchnum = 1; 330 } 331} 332 333Elf_Addr 334_dl_find_symbol(const char *name, const Elf_Sym **this, 335 int flags, const Elf_Sym *ref_sym, elf_object_t *req_obj, 336 const elf_object_t **pobj) 337{ 338 const Elf_Sym *weak_sym = NULL; 339 unsigned long h = 0; 340 const char *p = name; 341 elf_object_t *object = NULL, *weak_object = NULL; 342 int found = 0; 343 struct dep_node *n, *m; 344 345 346 while (*p) { 347 unsigned long g; 348 h = (h << 4) + *p++; 349 if ((g = h & 0xf0000000)) 350 h ^= g >> 24; 351 h &= ~g; 352 } 353 354 if (req_obj->dyn.symbolic) 355 if (_dl_find_symbol_obj(req_obj, name, h, flags, this, &weak_sym, 356 &weak_object)) { 357 object = req_obj; 358 found = 1; 359 goto found; 360 } 361 362 if (flags & SYM_SEARCH_OBJ) { 363 if (_dl_find_symbol_obj(req_obj, name, h, flags, this, 364 &weak_sym, &weak_object)) { 365 object = req_obj; 366 found = 1; 367 } 368 } else if (flags & SYM_DLSYM) { 369 if (_dl_find_symbol_obj(req_obj, name, h, flags, this, 370 &weak_sym, &weak_object)) { 371 object = req_obj; 372 found = 1; 373 } 374 if (weak_object != NULL && found == 0) { 375 object=weak_object; 376 *this = weak_sym; 377 found = 1; 378 } 379 /* search dlopened obj and all children */ 380 381 if (found == 0) { 382 TAILQ_FOREACH(n, &req_obj->load_object->grpsym_list, 383 next_sib) { 384 if (_dl_find_symbol_obj(n->data, name, h, 385 flags, this, 386 &weak_sym, &weak_object)) { 387 object = n->data; 388 found = 1; 389 break; 390 } 391 } 392 } 393 } else { 394 int skip = 0; 395 396 if ((flags & SYM_SEARCH_SELF) || (flags & SYM_SEARCH_NEXT)) 397 skip = 1; 398 399 _dl_newsymsearch(); 400 401 /* 402 * search dlopened objects: global or req_obj == dlopened_obj 403 * and and it's children 404 */ 405 TAILQ_FOREACH(n, &_dlopened_child_list, next_sib) { 406 if (((n->data->obj_flags & DF_1_GLOBAL) == 0) && 407 (n->data != req_obj->load_object)) 408 continue; 409 410 n->data->lastlookup_head = _dl_searchnum; 411 TAILQ_FOREACH(m, &n->data->grpsym_list, next_sib) { 412 if (skip == 1) { 413 if (m->data == req_obj) { 414 skip = 0; 415 if (flags & SYM_SEARCH_NEXT) 416 continue; 417 } else 418 continue; 419 } 420 if ((flags & SYM_SEARCH_OTHER) && 421 (m->data == req_obj)) 422 continue; 423 m->data->lastlookup = _dl_searchnum; 424 if (_dl_find_symbol_obj(m->data, name, h, flags, 425 this, &weak_sym, &weak_object)) { 426 object = m->data; 427 found = 1; 428 goto found; 429 } 430 } 431 } 432 } 433 434found: 435 if (weak_object != NULL && found == 0) { 436 object=weak_object; 437 *this = weak_sym; 438 found = 1; 439 } 440 441 442 if (found == 0) { 443 if ((ref_sym == NULL || 444 (ELF_ST_BIND(ref_sym->st_info) != STB_WEAK)) && 445 (flags & SYM_WARNNOTFOUND)) 446 _dl_printf("%s:%s: undefined symbol '%s'\n", 447 _dl_progname, req_obj->load_name, name); 448 return (0); 449 } 450 451 if (ref_sym != NULL && ref_sym->st_size != 0 && 452 (ref_sym->st_size != (*this)->st_size) && 453 (ELF_ST_TYPE((*this)->st_info) != STT_FUNC) ) { 454 _dl_printf("%s:%s: %s : WARNING: " 455 "symbol(%s) size mismatch, relink your program\n", 456 _dl_progname, req_obj->load_name, 457 object->load_name, name); 458 } 459 460 if (pobj) 461 *pobj = object; 462 463 return (object->obj_base); 464} 465 466int 467_dl_find_symbol_obj(elf_object_t *object, const char *name, unsigned long hash, 468 int flags, const Elf_Sym **this, const Elf_Sym **weak_sym, 469 elf_object_t **weak_object) 470{ 471 const Elf_Sym *symt = object->dyn.symtab; 472 const char *strt = object->dyn.strtab; 473 long si; 474 const char *symn; 475 476 for (si = object->buckets[hash % object->nbuckets]; 477 si != STN_UNDEF; si = object->chains[si]) { 478 const Elf_Sym *sym = symt + si; 479 480 if (sym->st_value == 0) 481 continue; 482 483 if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE && 484 ELF_ST_TYPE(sym->st_info) != STT_OBJECT && 485 ELF_ST_TYPE(sym->st_info) != STT_FUNC) 486 continue; 487 488 symn = strt + sym->st_name; 489 if (sym != *this && _dl_strcmp(symn, name)) 490 continue; 491 492 /* allow this symbol if we are referring to a function 493 * which has a value, even if section is UNDEF. 494 * this allows &func to refer to PLT as per the 495 * ELF spec. st_value is checked above. 496 * if flags has SYM_PLT set, we must have actual 497 * symbol, so this symbol is skipped. 498 */ 499 if (sym->st_shndx == SHN_UNDEF) { 500 if ((flags & SYM_PLT) || sym->st_value == 0 || 501 ELF_ST_TYPE(sym->st_info) != STT_FUNC) 502 continue; 503 } 504 505 if (ELF_ST_BIND(sym->st_info) == STB_GLOBAL) { 506 *this = sym; 507 return 1; 508 } else if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { 509 if (!*weak_sym) { 510 *weak_sym = sym; 511 *weak_object = object; 512 } 513 } 514 } 515 return 0; 516} 517 518void 519_dl_debug_state(void) 520{ 521 /* Debugger stub */ 522} 523