Annotation of src/libexec/ld.elf_so/symbol.c, Revision 1.39
1.39 ! chs 1: /* $NetBSD: symbol.c,v 1.38 2005/01/11 21:58:27 martin Exp $ */
1.1 cgd 2:
3: /*
4: * Copyright 1996 John D. Polstra.
5: * Copyright 1996 Matt Thomas <matt@3am-software.com>
1.25 mycroft 6: * Copyright 2002 Charles M. Hannum <root@ihack.net>
1.1 cgd 7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by John Polstra.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: */
34:
35: /*
36: * Dynamic linker for ELF.
37: *
38: * John Polstra <jdp@polstra.com>.
39: */
40:
1.37 skrll 41: #include <sys/cdefs.h>
42: #ifndef lint
1.39 ! chs 43: __RCSID("$NetBSD: symbol.c,v 1.38 2005/01/11 21:58:27 martin Exp $");
1.37 skrll 44: #endif /* not lint */
45:
1.1 cgd 46: #include <err.h>
47: #include <errno.h>
48: #include <fcntl.h>
49: #include <stdarg.h>
50: #include <stdio.h>
51: #include <stdlib.h>
52: #include <string.h>
53: #include <unistd.h>
54: #include <sys/types.h>
55: #include <sys/mman.h>
56: #include <dirent.h>
57:
58: #include "debug.h"
59: #include "rtld.h"
60:
1.39 ! chs 61: typedef void (*fptr_t)(void);
! 62:
1.33 skrll 63: static bool
64: _rtld_is_exported(const Elf_Sym *def)
65: {
1.39 ! chs 66: static fptr_t _rtld_exports[] = {
! 67: (fptr_t)dlopen,
! 68: (fptr_t)dlclose,
! 69: (fptr_t)dlsym,
! 70: (fptr_t)dlerror,
! 71: (fptr_t)dladdr,
! 72: NULL
1.33 skrll 73: };
74: int i;
1.39 ! chs 75: fptr_t value;
1.33 skrll 76:
1.39 ! chs 77: value = (fptr_t)(_rtld_objself.relocbase + def->st_value);
! 78: for (i = 0; _rtld_exports[i] != NULL; i++) {
1.33 skrll 79: if (value == _rtld_exports[i])
80: return true;
81: }
82: return false;
83: }
84:
1.1 cgd 85: /*
86: * Hash function for symbol table lookup. Don't even think about changing
87: * this. It is specified by the System V ABI.
88: */
89: unsigned long
1.31 skrll 90: _rtld_elf_hash(const char *name)
1.1 cgd 91: {
1.3 christos 92: const unsigned char *p = (const unsigned char *) name;
93: unsigned long h = 0;
94: unsigned long g;
1.24 mycroft 95: unsigned long c;
1.3 christos 96:
1.24 mycroft 97: for (; __predict_true((c = *p) != '\0'); p++) {
98: h <<= 4;
99: h += c;
100: if ((g = h & 0xf0000000) != 0) {
101: h ^= g;
1.3 christos 102: h ^= g >> 24;
1.24 mycroft 103: }
1.3 christos 104: }
1.24 mycroft 105: return (h);
1.1 cgd 106: }
107:
1.5 mycroft 108: const Elf_Sym *
1.23 mycroft 109: _rtld_symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
1.31 skrll 110: const Obj_Entry **defobj_out, bool in_plt)
1.5 mycroft 111: {
112: const Elf_Sym *symp;
113: const Elf_Sym *def;
1.27 mycroft 114: const Obj_Entry *defobj;
1.5 mycroft 115: const Objlist_Entry *elm;
116:
117: def = NULL;
1.27 mycroft 118: defobj = NULL;
1.12 lukem 119: SIMPLEQ_FOREACH(elm, objlist, link) {
1.23 mycroft 120: rdbg(("search object %p (%s)", elm->obj, elm->obj->path));
1.21 mycroft 121: if ((symp = _rtld_symlook_obj(name, hash, elm->obj, in_plt))
1.5 mycroft 122: != NULL) {
123: if ((def == NULL) ||
1.6 thorpej 124: (ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
1.5 mycroft 125: def = symp;
1.27 mycroft 126: defobj = elm->obj;
1.6 thorpej 127: if (ELF_ST_BIND(def->st_info) != STB_WEAK)
1.5 mycroft 128: break;
129: }
130: }
131: }
1.27 mycroft 132: if (def != NULL)
133: *defobj_out = defobj;
1.5 mycroft 134: return def;
135: }
136:
1.1 cgd 137: /*
138: * Search the symbol table of a single shared object for a symbol of
139: * the given name. Returns a pointer to the symbol, or NULL if no
140: * definition was found.
141: *
142: * The symbol's hash value is passed in for efficiency reasons; that
143: * eliminates many recomputations of the hash value.
144: */
145: const Elf_Sym *
1.31 skrll 146: _rtld_symlook_obj(const char *name, unsigned long hash,
147: const Obj_Entry *obj, bool in_plt)
1.1 cgd 148: {
1.20 mycroft 149: unsigned long symnum;
1.1 cgd 150:
1.20 mycroft 151: for (symnum = obj->buckets[hash % obj->nbuckets];
152: symnum != ELF_SYM_UNDEFINED;
153: symnum = obj->chains[symnum]) {
1.3 christos 154: const Elf_Sym *symp;
155: const char *strp;
156:
157: assert(symnum < obj->nchains);
158: symp = obj->symtab + symnum;
159: strp = obj->strtab + symp->st_name;
1.38 martin 160: rdbg(("check \"%s\" vs \"%s\" in %p", name, strp, obj));
1.20 mycroft 161: if (name[1] == strp[1] && !strcmp(name, strp)) {
162: if (symp->st_shndx != SHN_UNDEF)
1.3 christos 163: return symp;
1.21 mycroft 164: #ifndef __mips__
1.22 mycroft 165: /*
166: * XXX DANGER WILL ROBINSON!
167: * If we have a function pointer in the executable's
168: * data section, it points to the executable's PLT
169: * slot, and there is NO relocation emitted. To make
170: * the function pointer comparable to function pointers
171: * in shared libraries, we must resolve data references
172: * in the libraries to point to PLT slots in the
173: * executable, if they exist.
174: */
1.21 mycroft 175: else if (!in_plt && symp->st_value != 0 &&
176: ELF_ST_TYPE(symp->st_info) == STT_FUNC)
177: return symp;
178: #endif
1.19 mycroft 179: else
180: return NULL;
1.3 christos 181: }
1.1 cgd 182: }
183:
1.3 christos 184: return NULL;
1.1 cgd 185: }
186:
187: /*
188: * Given a symbol number in a referencing object, find the corresponding
189: * definition of the symbol. Returns a pointer to the symbol, or NULL if
190: * no definition was found. Returns a pointer to the Obj_Entry of the
191: * defining object via the reference parameter DEFOBJ_OUT.
192: */
193: const Elf_Sym *
1.31 skrll 194: _rtld_find_symdef(unsigned long symnum, const Obj_Entry *refobj,
195: const Obj_Entry **defobj_out, bool in_plt)
1.1 cgd 196: {
1.27 mycroft 197: const Elf_Sym *ref;
1.5 mycroft 198: const Elf_Sym *def;
199: const Elf_Sym *symp;
1.3 christos 200: const Obj_Entry *obj;
1.27 mycroft 201: const Obj_Entry *defobj;
1.5 mycroft 202: const Objlist_Entry *elm;
1.27 mycroft 203: const char *name;
1.3 christos 204: unsigned long hash;
205:
1.27 mycroft 206: ref = refobj->symtab + symnum;
207: name = refobj->strtab + ref->st_name;
208:
1.3 christos 209: hash = _rtld_elf_hash(name);
1.5 mycroft 210: def = NULL;
1.27 mycroft 211: defobj = NULL;
1.5 mycroft 212:
1.32 skrll 213: /* Look first in the referencing object if linked symbolically */
214: if (refobj->symbolic) {
1.21 mycroft 215: symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
1.5 mycroft 216: if (symp != NULL) {
217: def = symp;
1.27 mycroft 218: defobj = refobj;
1.5 mycroft 219: }
220: }
221:
222: /* Search all objects loaded at program start up. */
1.6 thorpej 223: if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
1.23 mycroft 224: rdbg(("search _rtld_list_main"));
1.21 mycroft 225: symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, in_plt);
1.5 mycroft 226: if (symp != NULL &&
1.6 thorpej 227: (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
1.5 mycroft 228: def = symp;
1.27 mycroft 229: defobj = obj;
1.5 mycroft 230: }
231: }
232:
1.35 mrauch 233: /* Search all RTLD_GLOBAL objects. */
234: if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
235: rdbg(("search _rtld_list_global"));
236: symp = _rtld_symlook_list(name, hash, &_rtld_list_global, &obj, in_plt);
1.5 mycroft 237: if (symp != NULL &&
1.6 thorpej 238: (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
1.5 mycroft 239: def = symp;
1.27 mycroft 240: defobj = obj;
1.3 christos 241: }
242: }
1.5 mycroft 243:
1.35 mrauch 244: /* Search all dlopened DAGs containing the referencing object. */
245: SIMPLEQ_FOREACH(elm, &refobj->dldags, link) {
246: if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
247: break;
248: rdbg(("search DAG with root %p (%s)", elm->obj, elm->obj->path));
249: symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt);
1.5 mycroft 250: if (symp != NULL &&
1.6 thorpej 251: (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
1.5 mycroft 252: def = symp;
1.27 mycroft 253: defobj = obj;
1.3 christos 254: }
255: }
1.5 mycroft 256:
1.27 mycroft 257: /*
1.33 skrll 258: * Search the dynamic linker itself, and possibly resolve the
259: * symbol from there. This is how the application links to
260: * dynamic linker services such as dlopen. Only the values listed
261: * in the "_rtld_exports" array can be resolved from the dynamic linker.
262: */
263: if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
1.39 ! chs 264: rdbg(("search rtld itself"));
1.33 skrll 265: symp = _rtld_symlook_obj(name, hash, &_rtld_objself, in_plt);
266: if (symp != NULL && _rtld_is_exported(symp)) {
267: def = symp;
268: defobj = &_rtld_objself;
269: }
270: }
271:
272: /*
1.27 mycroft 273: * If we found no definition and the reference is weak, treat the
274: * symbol as having the value zero.
275: */
276: if (def == NULL && ELF_ST_BIND(ref->st_info) == STB_WEAK) {
277: rdbg((" returning _rtld_sym_zero@_rtld_objmain"));
278: def = &_rtld_sym_zero;
279: defobj = _rtld_objmain;
280: }
1.33 skrll 281:
1.27 mycroft 282: if (def != NULL)
283: *defobj_out = defobj;
284: else {
285: rdbg(("lookup failed"));
286: _rtld_error("%s: Undefined %ssymbol \"%s\" (symnum = %ld)",
287: refobj->path, in_plt ? "PLT " : "", name, symnum);
288: }
1.26 mycroft 289: return def;
1.28 christos 290: }
291:
292: /*
293: * Given a symbol name in a referencing object, find the corresponding
294: * definition of the symbol. Returns a pointer to the symbol, or NULL if
295: * no definition was found. Returns a pointer to the Obj_Entry of the
296: * defining object via the reference parameter DEFOBJ_OUT.
297: */
298: const Elf_Sym *
299: _rtld_symlook_default(const char *name, unsigned long hash,
300: const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt)
301: {
1.29 skrll 302: const Elf_Sym *def;
303: const Elf_Sym *symp;
304: const Obj_Entry *obj;
305: const Obj_Entry *defobj;
306: const Objlist_Entry *elm;
307: def = NULL;
308: defobj = NULL;
309:
310: /* Look first in the referencing object if linked symbolically. */
311: if (refobj->symbolic) {
312: symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
313: if (symp != NULL) {
314: def = symp;
315: defobj = refobj;
316: }
317: }
318:
319: /* Search all objects loaded at program start up. */
320: if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
321: symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, in_plt);
322: if (symp != NULL &&
323: (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
324: def = symp;
325: defobj = obj;
326: }
327: }
328:
329: /* Search all dlopened DAGs containing the referencing object. */
330: SIMPLEQ_FOREACH(elm, &refobj->dldags, link) {
331: if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
332: break;
333: symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj,
334: in_plt);
335: if (symp != NULL &&
336: (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
337: def = symp;
338: defobj = obj;
339: }
340: }
341:
342: /* Search all DAGs whose roots are RTLD_GLOBAL objects. */
343: SIMPLEQ_FOREACH(elm, &_rtld_list_global, link) {
344: if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
345: break;
346: symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj,
347: in_plt);
348: if (symp != NULL &&
349: (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
350: def = symp;
351: defobj = obj;
352: }
1.28 christos 353: }
354:
355: #ifdef notyet
1.29 skrll 356: /*
357: * Search the dynamic linker itself, and possibly resolve the
358: * symbol from there. This is how the application links to
359: * dynamic linker services such as dlopen. Only the values listed
360: * in the "exports" array can be resolved from the dynamic linker.
361: */
362: if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
1.30 skrll 363: symp = _rtld_symlook_obj(name, hash, &_rtld_objself, in_plt);
1.29 skrll 364: if (symp != NULL && is_exported(symp)) {
365: def = symp;
1.30 skrll 366: defobj = &_rtld_objself;
1.29 skrll 367: }
1.28 christos 368: }
369: #endif
370:
1.29 skrll 371: if (def != NULL)
372: *defobj_out = defobj;
373: return def;
1.1 cgd 374: }
CVSweb <webmaster@jp.NetBSD.org>