]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dl-sym.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / elf / dl-sym.c
CommitLineData
94e365c6 1/* Look up a symbol in a shared object loaded by `dlopen'.
bfff8b1b 2 Copyright (C) 1999-2017 Free Software Foundation, Inc.
94e365c6
UD
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
41bdb6e2
AJ
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.
94e365c6
UD
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
41bdb6e2 13 Lesser General Public License for more details.
94e365c6 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
94e365c6 18
1100f849 19#include <assert.h>
94e365c6
UD
20#include <stddef.h>
21#include <setjmp.h>
176790a7 22#include <stdlib.h>
94e365c6
UD
23#include <libintl.h>
24
25#include <dlfcn.h>
26#include <ldsodefs.h>
27#include <dl-hash.h>
609cf614 28#include <sysdep-cancel.h>
11bf311e 29#include <dl-tls.h>
42675c6f 30#include <dl-irel.h>
154d10bd
UD
31
32
11bf311e 33#ifdef SHARED
154d10bd
UD
34/* Systems which do not have tls_index also probably have to define
35 DONT_USE_TLS_INDEX. */
36
37# ifndef __TLS_GET_ADDR
38# define __TLS_GET_ADDR __tls_get_addr
39# endif
40
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. */
43static void *
44internal_function
45_dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
46{
47# ifndef DONT_USE_TLS_INDEX
48 tls_index tmp =
49 {
50 .ti_module = map->l_tls_modid,
51 .ti_offset = ref->st_value
52 };
53
54 return __TLS_GET_ADDR (&tmp);
55# else
56 return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
57# endif
58}
59#endif
60
94e365c6 61
1100f849
UD
62struct call_dl_lookup_args
63{
64 /* Arguments to do_dlsym. */
65 struct link_map *map;
66 const char *name;
1100f849
UD
67 struct r_found_version *vers;
68 int flags;
69
70 /* Return values of do_dlsym. */
71 lookup_t loadbase;
72 const ElfW(Sym) **refp;
73};
74
75static void
76call_dl_lookup (void *ptr)
77{
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,
c0a777e8 80 args->map->l_scope, args->vers, 0,
1100f849
UD
81 args->flags, NULL);
82}
83
84
53761a8b 85static void *
94e365c6 86internal_function
f0323886
UD
87do_sym (void *handle, const char *name, void *who,
88 struct r_found_version *vers, int flags)
94e365c6 89{
94e365c6 90 const ElfW(Sym) *ref = NULL;
c0282c06 91 lookup_t result;
2b7238dd 92 ElfW(Addr) caller = (ElfW(Addr)) who;
94e365c6 93
be179c8a 94 struct link_map *l = _dl_find_dso_for_object (caller);
f92338be
UD
95 /* If the address is not recognized the call comes from the main
96 program (we hope). */
be179c8a 97 struct link_map *match = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
2b7238dd 98
94e365c6 99 if (handle == RTLD_DEFAULT)
1100f849
UD
100 {
101 /* Search the global scope. We have the simple case where
102 we look up in the scope of an object which was part of
103 the initial binary. And then the more complex part
104 where the object is dynamically loaded and the scope
105 array can change. */
e4eb675d 106 if (RTLD_SINGLE_THREAD_P)
1100f849 107 result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
c0a777e8 108 match->l_scope, vers, 0,
1100f849
UD
109 flags | DL_LOOKUP_ADD_DEPENDENCY,
110 NULL);
111 else
112 {
1100f849
UD
113 struct call_dl_lookup_args args;
114 args.name = name;
115 args.map = match;
1100f849 116 args.vers = vers;
b90395e6
UD
117 args.flags
118 = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
1100f849
UD
119 args.refp = &ref;
120
e4eb675d
UD
121 THREAD_GSCOPE_SET_FLAG ();
122
1100f849
UD
123 const char *objname;
124 const char *errstring = NULL;
125 bool malloced;
9e78f6f6
FW
126 int err = _dl_catch_error (&objname, &errstring, &malloced,
127 call_dl_lookup, &args);
1100f849 128
e4eb675d 129 THREAD_GSCOPE_RESET_FLAG ();
1100f849 130
a1ffb40e 131 if (__glibc_unlikely (errstring != NULL))
1100f849
UD
132 {
133 /* The lookup was unsuccessful. Rethrow the error. */
134 char *errstring_dup = strdupa (errstring);
135 char *objname_dup = strdupa (objname);
136 if (malloced)
137 free ((char *) errstring);
138
9e78f6f6 139 _dl_signal_error (err, objname_dup, NULL, errstring_dup);
1100f849
UD
140 /* NOTREACHED */
141 }
142
143 result = args.map;
144 }
145 }
94e365c6
UD
146 else if (handle == RTLD_NEXT)
147 {
a1ffb40e 148 if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
2373b30e 149 {
173a06ec
UD
150 if (match == NULL
151 || caller < match->l_map_start
152 || caller >= match->l_map_end)
9e78f6f6 153 _dl_signal_error (0, NULL, NULL, N_("\
94e365c6 154RTLD_NEXT used in code not dynamically loaded"));
2373b30e 155 }
94e365c6 156
53761a8b 157 struct link_map *l = match;
f92338be 158 while (l->l_loader != NULL)
94e365c6
UD
159 l = l->l_loader;
160
74c5693b 161 result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
53761a8b 162 vers, 0, 0, match);
94e365c6
UD
163 }
164 else
165 {
166 /* Search the scope of the given object. */
167 struct link_map *map = handle;
021723ab 168 result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
53761a8b 169 vers, 0, flags, NULL);
94e365c6
UD
170 }
171
f92338be 172 if (ref != NULL)
aed283dd 173 {
9dcafc55
UD
174 void *value;
175
11bf311e 176#ifdef SHARED
aed283dd
UD
177 if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
178 /* The found symbol is a thread-local storage variable.
179 Return the address for to the current thread. */
9dcafc55
UD
180 value = _dl_tls_symaddr (result, ref);
181 else
182#endif
183 value = DL_SYMBOL_ADDRESS (result, ref);
184
bc5e8462 185 /* Resolve indirect function address. */
a1ffb40e 186 if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
8608ae1f
L
187 {
188 DL_FIXUP_VALUE_TYPE fixup
189 = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
42675c6f 190 fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
8608ae1f
L
191 value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
192 }
bc5e8462 193
9dcafc55
UD
194#ifdef SHARED
195 /* Auditing checkpoint: we have a new binding. Provide the
196 auditing libraries the possibility to change the value and
197 tell us whether further auditing is wanted. */
a1ffb40e 198 if (__glibc_unlikely (GLRO(dl_naudit) > 0))
9dcafc55
UD
199 {
200 const char *strtab = (const char *) D_PTR (result,
201 l_info[DT_STRTAB]);
202 /* Compute index of the symbol entry in the symbol table of
203 the DSO with the definition. */
204 unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
205 l_info[DT_SYMTAB]));
206
207 if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
208 {
209 unsigned int altvalue = 0;
210 struct audit_ifaces *afct = GLRO(dl_audit);
211 /* Synthesize a symbol record where the st_value field is
212 the result. */
213 ElfW(Sym) sym = *ref;
214 sym.st_value = (ElfW(Addr)) value;
215
216 for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
217 {
218 if (afct->symbind != NULL
219 && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
220 != 0
221 || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
222 != 0)))
223 {
224 unsigned int flags = altvalue | LA_SYMB_DLSYM;
225 uintptr_t new_value
226 = afct->symbind (&sym, ndx,
227 &match->l_audit[cnt].cookie,
228 &result->l_audit[cnt].cookie,
229 &flags, strtab + ref->st_name);
230 if (new_value != (uintptr_t) sym.st_value)
231 {
232 altvalue = LA_SYMB_ALTVALUE;
233 sym.st_value = new_value;
234 }
235 }
236
237 afct = afct->next;
238 }
239
240 value = (void *) sym.st_value;
241 }
242 }
aed283dd
UD
243#endif
244
9dcafc55 245 return value;
aed283dd 246 }
5e76a346 247
94e365c6
UD
248 return NULL;
249}
53761a8b
UD
250
251
53761a8b
UD
252void *
253internal_function
254_dl_vsym (void *handle, const char *name, const char *version, void *who)
255{
256 struct r_found_version vers;
257
258 /* Compute hash value to the version string. */
259 vers.name = version;
260 vers.hidden = 1;
261 vers.hash = _dl_elf_hash (version);
262 /* We don't have a specific file where the symbol can be found. */
263 vers.filename = NULL;
264
f0323886 265 return do_sym (handle, name, who, &vers, 0);
53761a8b
UD
266}
267
268
269void *
270internal_function
271_dl_sym (void *handle, const char *name, void *who)
272{
f0323886 273 return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);
53761a8b 274}