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