* elf/dl-close.c (free_mem): Free _dl_scope_free_list.
[glibc.git] / elf / dl-sym.c
blobb12ff375fe205f4ac1b9283114be9b81ff966bb6
1 /* Look up a symbol in a shared object loaded by `dlopen'.
2 Copyright (C) 1999-2002,2004,2006,2007 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <assert.h>
21 #include <stddef.h>
22 #include <setjmp.h>
23 #include <libintl.h>
25 #include <dlfcn.h>
26 #include <ldsodefs.h>
27 #include <dl-hash.h>
28 #include <sysdep-cancel.h>
29 #include <dl-tls.h>
32 #ifdef SHARED
33 /* Systems which do not have tls_index also probably have to define
34 DONT_USE_TLS_INDEX. */
36 # ifndef __TLS_GET_ADDR
37 # define __TLS_GET_ADDR __tls_get_addr
38 # endif
40 /* Return the symbol address given the map of the module it is in and
41 the symbol record. This is used in dl-sym.c. */
42 static void *
43 internal_function
44 _dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
46 # ifndef DONT_USE_TLS_INDEX
47 tls_index tmp =
49 .ti_module = map->l_tls_modid,
50 .ti_offset = ref->st_value
53 return __TLS_GET_ADDR (&tmp);
54 # else
55 return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
56 # endif
58 #endif
61 struct call_dl_lookup_args
63 /* Arguments to do_dlsym. */
64 struct link_map *map;
65 const char *name;
66 struct r_found_version *vers;
67 int flags;
69 /* Return values of do_dlsym. */
70 lookup_t loadbase;
71 const ElfW(Sym) **refp;
74 static void
75 call_dl_lookup (void *ptr)
77 struct call_dl_lookup_args *args = (struct call_dl_lookup_args *) ptr;
78 args->map = GLRO(dl_lookup_symbol_x) (args->name, args->map, args->refp,
79 args->map->l_scope, args->vers, 0,
80 args->flags, NULL);
84 static void *
85 internal_function
86 do_sym (void *handle, const char *name, void *who,
87 struct r_found_version *vers, int flags)
89 const ElfW(Sym) *ref = NULL;
90 lookup_t result;
91 ElfW(Addr) caller = (ElfW(Addr)) who;
93 /* If the address is not recognized the call comes from the main
94 program (we hope). */
95 struct link_map *match = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
97 /* Find the highest-addressed object that CALLER is not below. */
98 for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
99 for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
100 l = l->l_next)
101 if (caller >= l->l_map_start && caller < l->l_map_end
102 && (l->l_contiguous || _dl_addr_inside_object (l, caller)))
104 match = l;
105 break;
108 if (handle == RTLD_DEFAULT)
110 /* Search the global scope. We have the simple case where
111 we look up in the scope of an object which was part of
112 the initial binary. And then the more complex part
113 where the object is dynamically loaded and the scope
114 array can change. */
115 if (RTLD_SINGLE_THREAD_P)
116 result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
117 match->l_scope, vers, 0,
118 flags | DL_LOOKUP_ADD_DEPENDENCY,
119 NULL);
120 else
122 struct call_dl_lookup_args args;
123 args.name = name;
124 args.map = match;
125 args.vers = vers;
126 args.flags = flags | DL_LOOKUP_ADD_DEPENDENCY;
127 args.refp = &ref;
129 THREAD_GSCOPE_SET_FLAG ();
131 const char *objname;
132 const char *errstring = NULL;
133 bool malloced;
134 int err = GLRO(dl_catch_error) (&objname, &errstring, &malloced,
135 call_dl_lookup, &args);
137 THREAD_GSCOPE_RESET_FLAG ();
139 if (__builtin_expect (errstring != NULL, 0))
141 /* The lookup was unsuccessful. Rethrow the error. */
142 char *errstring_dup = strdupa (errstring);
143 char *objname_dup = strdupa (objname);
144 if (malloced)
145 free ((char *) errstring);
147 GLRO(dl_signal_error) (err, objname_dup, NULL, errstring_dup);
148 /* NOTREACHED */
151 result = args.map;
154 else if (handle == RTLD_NEXT)
156 if (__builtin_expect (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded, 0))
158 if (match == NULL
159 || caller < match->l_map_start
160 || caller >= match->l_map_end)
161 GLRO(dl_signal_error) (0, NULL, NULL, N_("\
162 RTLD_NEXT used in code not dynamically loaded"));
165 struct link_map *l = match;
166 while (l->l_loader != NULL)
167 l = l->l_loader;
169 result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
170 vers, 0, 0, match);
172 else
174 /* Search the scope of the given object. */
175 struct link_map *map = handle;
176 result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
177 vers, 0, flags, NULL);
180 if (ref != NULL)
182 void *value;
184 #ifdef SHARED
185 if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
186 /* The found symbol is a thread-local storage variable.
187 Return the address for to the current thread. */
188 value = _dl_tls_symaddr (result, ref);
189 else
190 #endif
191 value = DL_SYMBOL_ADDRESS (result, ref);
193 #ifdef SHARED
194 /* Auditing checkpoint: we have a new binding. Provide the
195 auditing libraries the possibility to change the value and
196 tell us whether further auditing is wanted. */
197 if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
199 const char *strtab = (const char *) D_PTR (result,
200 l_info[DT_STRTAB]);
201 /* Compute index of the symbol entry in the symbol table of
202 the DSO with the definition. */
203 unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
204 l_info[DT_SYMTAB]));
206 if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
208 unsigned int altvalue = 0;
209 struct audit_ifaces *afct = GLRO(dl_audit);
210 /* Synthesize a symbol record where the st_value field is
211 the result. */
212 ElfW(Sym) sym = *ref;
213 sym.st_value = (ElfW(Addr)) value;
215 for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
217 if (afct->symbind != NULL
218 && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
219 != 0
220 || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
221 != 0)))
223 unsigned int flags = altvalue | LA_SYMB_DLSYM;
224 uintptr_t new_value
225 = afct->symbind (&sym, ndx,
226 &match->l_audit[cnt].cookie,
227 &result->l_audit[cnt].cookie,
228 &flags, strtab + ref->st_name);
229 if (new_value != (uintptr_t) sym.st_value)
231 altvalue = LA_SYMB_ALTVALUE;
232 sym.st_value = new_value;
236 afct = afct->next;
239 value = (void *) sym.st_value;
242 #endif
244 return value;
247 return NULL;
251 void *
252 internal_function
253 _dl_vsym (void *handle, const char *name, const char *version, void *who)
255 struct r_found_version vers;
257 /* Compute hash value to the version string. */
258 vers.name = version;
259 vers.hidden = 1;
260 vers.hash = _dl_elf_hash (version);
261 /* We don't have a specific file where the symbol can be found. */
262 vers.filename = NULL;
264 return do_sym (handle, name, who, &vers, 0);
268 void *
269 internal_function
270 _dl_sym (void *handle, const char *name, void *who)
272 return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);