]> sourceware.org Git - glibc.git/blob - elf/dl-sym.c
2.5-18.1
[glibc.git] / elf / dl-sym.c
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.
4
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.
9
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.
14
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. */
19
20 #include <assert.h>
21 #include <stddef.h>
22 #include <setjmp.h>
23 #include <libintl.h>
24
25 #include <dlfcn.h>
26 #include <ldsodefs.h>
27 #include <dl-hash.h>
28 #include <sysdep-cancel.h>
29 #ifdef USE_TLS
30 # include <dl-tls.h>
31 #endif
32
33
34 #if defined USE_TLS && defined SHARED
35 /* Systems which do not have tls_index also probably have to define
36 DONT_USE_TLS_INDEX. */
37
38 # ifndef __TLS_GET_ADDR
39 # define __TLS_GET_ADDR __tls_get_addr
40 # endif
41
42 /* Return the symbol address given the map of the module it is in and
43 the symbol record. This is used in dl-sym.c. */
44 static void *
45 internal_function
46 _dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
47 {
48 # ifndef DONT_USE_TLS_INDEX
49 tls_index tmp =
50 {
51 .ti_module = map->l_tls_modid,
52 .ti_offset = ref->st_value
53 };
54
55 return __TLS_GET_ADDR (&tmp);
56 # else
57 return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
58 # endif
59 }
60 #endif
61
62
63 struct call_dl_lookup_args
64 {
65 /* Arguments to do_dlsym. */
66 struct link_map *map;
67 const char *name;
68 struct r_found_version *vers;
69 int flags;
70
71 /* Return values of do_dlsym. */
72 lookup_t loadbase;
73 const ElfW(Sym) **refp;
74 };
75
76 static void
77 call_dl_lookup (void *ptr)
78 {
79 struct call_dl_lookup_args *args = (struct call_dl_lookup_args *) ptr;
80 args->map = GLRO(dl_lookup_symbol_x) (args->name, args->map, args->refp,
81 args->map->l_scope, args->vers, 0,
82 args->flags, NULL);
83 }
84
85
86 static void *
87 internal_function
88 do_sym (void *handle, const char *name, void *who,
89 struct r_found_version *vers, int flags)
90 {
91 const ElfW(Sym) *ref = NULL;
92 lookup_t result;
93 ElfW(Addr) caller = (ElfW(Addr)) who;
94
95 /* If the address is not recognized the call comes from the main
96 program (we hope). */
97 struct link_map *match = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
98
99 /* Find the highest-addressed object that CALLER is not below. */
100 for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
101 for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
102 l = l->l_next)
103 if (caller >= l->l_map_start && caller < l->l_map_end
104 && (l->l_contiguous || _dl_addr_inside_object (l, caller)))
105 {
106 match = l;
107 break;
108 }
109
110 if (handle == RTLD_DEFAULT)
111 {
112 /* Search the global scope. We have the simple case where
113 we look up in the scope of an object which was part of
114 the initial binary. And then the more complex part
115 where the object is dynamically loaded and the scope
116 array can change. */
117 if (RTLD_SINGLE_THREAD_P)
118 result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
119 match->l_scope, vers, 0,
120 flags | DL_LOOKUP_ADD_DEPENDENCY,
121 NULL);
122 else
123 {
124 struct call_dl_lookup_args args;
125 args.name = name;
126 args.map = match;
127 args.vers = vers;
128 args.flags = flags | DL_LOOKUP_ADD_DEPENDENCY;
129 args.refp = &ref;
130
131 THREAD_GSCOPE_SET_FLAG ();
132
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);
138
139 THREAD_GSCOPE_RESET_FLAG ();
140
141 if (__builtin_expect (errstring != NULL, 0))
142 {
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);
148
149 GLRO(dl_signal_error) (err, objname_dup, NULL, errstring_dup);
150 /* NOTREACHED */
151 }
152
153 result = args.map;
154 }
155 }
156 else if (handle == RTLD_NEXT)
157 {
158 if (__builtin_expect (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded, 0))
159 {
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"));
165 }
166
167 struct link_map *l = match;
168 while (l->l_loader != NULL)
169 l = l->l_loader;
170
171 result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
172 vers, 0, 0, match);
173 }
174 else
175 {
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);
180 }
181
182 if (ref != NULL)
183 {
184 void *value;
185
186 #if defined USE_TLS && defined 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);
194
195 #ifdef SHARED
196 /* Auditing checkpoint: we have a new binding. Provide the
197 auditing libraries the possibility to change the value and
198 tell us whether further auditing is wanted. */
199 if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
200 {
201 const char *strtab = (const char *) D_PTR (result,
202 l_info[DT_STRTAB]);
203 /* Compute index of the symbol entry in the symbol table of
204 the DSO with the definition. */
205 unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
206 l_info[DT_SYMTAB]));
207
208 if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
209 {
210 unsigned int altvalue = 0;
211 struct audit_ifaces *afct = GLRO(dl_audit);
212 /* Synthesize a symbol record where the st_value field is
213 the result. */
214 ElfW(Sym) sym = *ref;
215 sym.st_value = (ElfW(Addr)) value;
216
217 for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
218 {
219 if (afct->symbind != NULL
220 && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
221 != 0
222 || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
223 != 0)))
224 {
225 unsigned int flags = altvalue | LA_SYMB_DLSYM;
226 uintptr_t new_value
227 = afct->symbind (&sym, ndx,
228 &match->l_audit[cnt].cookie,
229 &result->l_audit[cnt].cookie,
230 &flags, strtab + ref->st_name);
231 if (new_value != (uintptr_t) sym.st_value)
232 {
233 altvalue = LA_SYMB_ALTVALUE;
234 sym.st_value = new_value;
235 }
236 }
237
238 afct = afct->next;
239 }
240
241 value = (void *) sym.st_value;
242 }
243 }
244 #endif
245
246 return value;
247 }
248
249 return NULL;
250 }
251
252
253 void *
254 internal_function
255 _dl_vsym (void *handle, const char *name, const char *version, void *who)
256 {
257 struct r_found_version vers;
258
259 /* Compute hash value to the version string. */
260 vers.name = version;
261 vers.hidden = 1;
262 vers.hash = _dl_elf_hash (version);
263 /* We don't have a specific file where the symbol can be found. */
264 vers.filename = NULL;
265
266 return do_sym (handle, name, who, &vers, 0);
267 }
268
269
270 void *
271 internal_function
272 _dl_sym (void *handle, const char *name, void *who)
273 {
274 return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);
275 }
This page took 0.053162 seconds and 6 git commands to generate.