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