Sort BZ # in NEWS
[glibc.git] / elf / dl-sym.c
blob6480f2359c2c2eb247a2bfb500231816ffaa5951
1 /* Look up a symbol in a shared object loaded by `dlopen'.
2 Copyright (C) 1999-2012 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, see
17 <http://www.gnu.org/licenses/>. */
19 #include <assert.h>
20 #include <stddef.h>
21 #include <setjmp.h>
22 #include <stdlib.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>
30 #include <dl-irel.h>
33 #ifdef SHARED
34 /* Systems which do not have tls_index also probably have to define
35 DONT_USE_TLS_INDEX. */
37 # ifndef __TLS_GET_ADDR
38 # define __TLS_GET_ADDR __tls_get_addr
39 # endif
41 /* Return the symbol address given the map of the module it is in and
42 the symbol record. This is used in dl-sym.c. */
43 static void *
44 internal_function
45 _dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
47 # ifndef DONT_USE_TLS_INDEX
48 tls_index tmp =
50 .ti_module = map->l_tls_modid,
51 .ti_offset = ref->st_value
54 return __TLS_GET_ADDR (&tmp);
55 # else
56 return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
57 # endif
59 #endif
62 struct call_dl_lookup_args
64 /* Arguments to do_dlsym. */
65 struct link_map *map;
66 const char *name;
67 struct r_found_version *vers;
68 int flags;
70 /* Return values of do_dlsym. */
71 lookup_t loadbase;
72 const ElfW(Sym) **refp;
75 static void
76 call_dl_lookup (void *ptr)
78 struct call_dl_lookup_args *args = (struct call_dl_lookup_args *) ptr;
79 args->map = GLRO(dl_lookup_symbol_x) (args->name, args->map, args->refp,
80 args->map->l_scope, args->vers, 0,
81 args->flags, NULL);
85 static void *
86 internal_function
87 do_sym (void *handle, const char *name, void *who,
88 struct r_found_version *vers, int flags)
90 const ElfW(Sym) *ref = NULL;
91 lookup_t result;
92 ElfW(Addr) caller = (ElfW(Addr)) who;
94 /* If the address is not recognized the call comes from the main
95 program (we hope). */
96 struct link_map *match = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
98 /* Find the highest-addressed object that CALLER is not below. */
99 for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
100 for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
101 l = l->l_next)
102 if (caller >= l->l_map_start && caller < l->l_map_end
103 && (l->l_contiguous || _dl_addr_inside_object (l, caller)))
105 match = l;
106 break;
109 if (handle == RTLD_DEFAULT)
111 /* Search the global scope. We have the simple case where
112 we look up in the scope of an object which was part of
113 the initial binary. And then the more complex part
114 where the object is dynamically loaded and the scope
115 array can change. */
116 if (RTLD_SINGLE_THREAD_P)
117 result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
118 match->l_scope, vers, 0,
119 flags | DL_LOOKUP_ADD_DEPENDENCY,
120 NULL);
121 else
123 struct call_dl_lookup_args args;
124 args.name = name;
125 args.map = match;
126 args.vers = vers;
127 args.flags
128 = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
129 args.refp = &ref;
131 THREAD_GSCOPE_SET_FLAG ();
133 const char *objname;
134 const char *errstring = NULL;
135 bool malloced;
136 int err = GLRO(dl_catch_error) (&objname, &errstring, &malloced,
137 call_dl_lookup, &args);
139 THREAD_GSCOPE_RESET_FLAG ();
141 if (__builtin_expect (errstring != NULL, 0))
143 /* The lookup was unsuccessful. Rethrow the error. */
144 char *errstring_dup = strdupa (errstring);
145 char *objname_dup = strdupa (objname);
146 if (malloced)
147 free ((char *) errstring);
149 GLRO(dl_signal_error) (err, objname_dup, NULL, errstring_dup);
150 /* NOTREACHED */
153 result = args.map;
156 else if (handle == RTLD_NEXT)
158 if (__builtin_expect (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded, 0))
160 if (match == NULL
161 || caller < match->l_map_start
162 || caller >= match->l_map_end)
163 GLRO(dl_signal_error) (0, NULL, NULL, N_("\
164 RTLD_NEXT used in code not dynamically loaded"));
167 struct link_map *l = match;
168 while (l->l_loader != NULL)
169 l = l->l_loader;
171 result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
172 vers, 0, 0, match);
174 else
176 /* Search the scope of the given object. */
177 struct link_map *map = handle;
178 result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
179 vers, 0, flags, NULL);
182 if (ref != NULL)
184 void *value;
186 #ifdef SHARED
187 if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
188 /* The found symbol is a thread-local storage variable.
189 Return the address for to the current thread. */
190 value = _dl_tls_symaddr (result, ref);
191 else
192 #endif
193 value = DL_SYMBOL_ADDRESS (result, ref);
195 /* Resolve indirect function address. */
196 if (__builtin_expect (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC, 0))
198 DL_FIXUP_VALUE_TYPE fixup
199 = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
200 fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
201 value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
204 #ifdef SHARED
205 /* Auditing checkpoint: we have a new binding. Provide the
206 auditing libraries the possibility to change the value and
207 tell us whether further auditing is wanted. */
208 if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
210 const char *strtab = (const char *) D_PTR (result,
211 l_info[DT_STRTAB]);
212 /* Compute index of the symbol entry in the symbol table of
213 the DSO with the definition. */
214 unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
215 l_info[DT_SYMTAB]));
217 if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
219 unsigned int altvalue = 0;
220 struct audit_ifaces *afct = GLRO(dl_audit);
221 /* Synthesize a symbol record where the st_value field is
222 the result. */
223 ElfW(Sym) sym = *ref;
224 sym.st_value = (ElfW(Addr)) value;
226 for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
228 if (afct->symbind != NULL
229 && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
230 != 0
231 || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
232 != 0)))
234 unsigned int flags = altvalue | LA_SYMB_DLSYM;
235 uintptr_t new_value
236 = afct->symbind (&sym, ndx,
237 &match->l_audit[cnt].cookie,
238 &result->l_audit[cnt].cookie,
239 &flags, strtab + ref->st_name);
240 if (new_value != (uintptr_t) sym.st_value)
242 altvalue = LA_SYMB_ALTVALUE;
243 sym.st_value = new_value;
247 afct = afct->next;
250 value = (void *) sym.st_value;
253 #endif
255 return value;
258 return NULL;
262 void *
263 internal_function
264 _dl_vsym (void *handle, const char *name, const char *version, void *who)
266 struct r_found_version vers;
268 /* Compute hash value to the version string. */
269 vers.name = version;
270 vers.hidden = 1;
271 vers.hash = _dl_elf_hash (version);
272 /* We don't have a specific file where the symbol can be found. */
273 vers.filename = NULL;
275 return do_sym (handle, name, who, &vers, 0);
279 void *
280 internal_function
281 _dl_sym (void *handle, const char *name, void *who)
283 return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);