]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dl-sym.c
iconv, localedef: avoid floating point rounding differences [BZ #24372]
[thirdparty/glibc.git] / elf / dl-sym.c
CommitLineData
94e365c6 1/* Look up a symbol in a shared object loaded by `dlopen'.
04277e02 2 Copyright (C) 1999-2019 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 *
154d10bd
UD
44_dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
45{
46# ifndef DONT_USE_TLS_INDEX
47 tls_index tmp =
48 {
49 .ti_module = map->l_tls_modid,
50 .ti_offset = ref->st_value
51 };
52
53 return __TLS_GET_ADDR (&tmp);
54# else
55 return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
56# endif
57}
58#endif
59
94e365c6 60
1100f849
UD
61struct call_dl_lookup_args
62{
63 /* Arguments to do_dlsym. */
64 struct link_map *map;
65 const char *name;
1100f849
UD
66 struct r_found_version *vers;
67 int flags;
68
69 /* Return values of do_dlsym. */
70 lookup_t loadbase;
71 const ElfW(Sym) **refp;
72};
73
74static void
75call_dl_lookup (void *ptr)
76{
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,
c0a777e8 79 args->map->l_scope, args->vers, 0,
1100f849
UD
80 args->flags, NULL);
81}
82
83
53761a8b 84static void *
f0323886
UD
85do_sym (void *handle, const char *name, void *who,
86 struct r_found_version *vers, int flags)
94e365c6 87{
94e365c6 88 const ElfW(Sym) *ref = NULL;
c0282c06 89 lookup_t result;
2b7238dd 90 ElfW(Addr) caller = (ElfW(Addr)) who;
94e365c6 91
be179c8a 92 struct link_map *l = _dl_find_dso_for_object (caller);
f92338be
UD
93 /* If the address is not recognized the call comes from the main
94 program (we hope). */
be179c8a 95 struct link_map *match = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
2b7238dd 96
94e365c6 97 if (handle == RTLD_DEFAULT)
1100f849
UD
98 {
99 /* Search the global scope. We have the simple case where
100 we look up in the scope of an object which was part of
101 the initial binary. And then the more complex part
102 where the object is dynamically loaded and the scope
103 array can change. */
e4eb675d 104 if (RTLD_SINGLE_THREAD_P)
1100f849 105 result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
c0a777e8 106 match->l_scope, vers, 0,
1100f849
UD
107 flags | DL_LOOKUP_ADD_DEPENDENCY,
108 NULL);
109 else
110 {
1100f849
UD
111 struct call_dl_lookup_args args;
112 args.name = name;
113 args.map = match;
1100f849 114 args.vers = vers;
b90395e6
UD
115 args.flags
116 = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
1100f849
UD
117 args.refp = &ref;
118
e4eb675d 119 THREAD_GSCOPE_SET_FLAG ();
2449ae7b
FW
120 struct dl_exception exception;
121 int err = _dl_catch_exception (&exception, call_dl_lookup, &args);
e4eb675d 122 THREAD_GSCOPE_RESET_FLAG ();
2449ae7b
FW
123 if (__glibc_unlikely (exception.errstring != NULL))
124 _dl_signal_exception (err, &exception, NULL);
1100f849
UD
125
126 result = args.map;
127 }
128 }
94e365c6
UD
129 else if (handle == RTLD_NEXT)
130 {
a1ffb40e 131 if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
2373b30e 132 {
173a06ec
UD
133 if (match == NULL
134 || caller < match->l_map_start
135 || caller >= match->l_map_end)
9e78f6f6 136 _dl_signal_error (0, NULL, NULL, N_("\
94e365c6 137RTLD_NEXT used in code not dynamically loaded"));
2373b30e 138 }
94e365c6 139
53761a8b 140 struct link_map *l = match;
f92338be 141 while (l->l_loader != NULL)
94e365c6
UD
142 l = l->l_loader;
143
74c5693b 144 result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
53761a8b 145 vers, 0, 0, match);
94e365c6
UD
146 }
147 else
148 {
149 /* Search the scope of the given object. */
150 struct link_map *map = handle;
021723ab 151 result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
53761a8b 152 vers, 0, flags, NULL);
94e365c6
UD
153 }
154
f92338be 155 if (ref != NULL)
aed283dd 156 {
9dcafc55
UD
157 void *value;
158
11bf311e 159#ifdef SHARED
aed283dd
UD
160 if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
161 /* The found symbol is a thread-local storage variable.
162 Return the address for to the current thread. */
9dcafc55
UD
163 value = _dl_tls_symaddr (result, ref);
164 else
165#endif
166 value = DL_SYMBOL_ADDRESS (result, ref);
167
bc5e8462 168 /* Resolve indirect function address. */
a1ffb40e 169 if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
8608ae1f
L
170 {
171 DL_FIXUP_VALUE_TYPE fixup
172 = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
42675c6f 173 fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
8608ae1f
L
174 value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
175 }
bc5e8462 176
9dcafc55
UD
177#ifdef SHARED
178 /* Auditing checkpoint: we have a new binding. Provide the
179 auditing libraries the possibility to change the value and
180 tell us whether further auditing is wanted. */
a1ffb40e 181 if (__glibc_unlikely (GLRO(dl_naudit) > 0))
9dcafc55
UD
182 {
183 const char *strtab = (const char *) D_PTR (result,
184 l_info[DT_STRTAB]);
185 /* Compute index of the symbol entry in the symbol table of
186 the DSO with the definition. */
187 unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
188 l_info[DT_SYMTAB]));
189
190 if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
191 {
192 unsigned int altvalue = 0;
193 struct audit_ifaces *afct = GLRO(dl_audit);
194 /* Synthesize a symbol record where the st_value field is
195 the result. */
196 ElfW(Sym) sym = *ref;
197 sym.st_value = (ElfW(Addr)) value;
198
199 for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
200 {
201 if (afct->symbind != NULL
202 && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
203 != 0
204 || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
205 != 0)))
206 {
207 unsigned int flags = altvalue | LA_SYMB_DLSYM;
208 uintptr_t new_value
209 = afct->symbind (&sym, ndx,
210 &match->l_audit[cnt].cookie,
211 &result->l_audit[cnt].cookie,
212 &flags, strtab + ref->st_name);
213 if (new_value != (uintptr_t) sym.st_value)
214 {
215 altvalue = LA_SYMB_ALTVALUE;
216 sym.st_value = new_value;
217 }
218 }
219
220 afct = afct->next;
221 }
222
223 value = (void *) sym.st_value;
224 }
225 }
aed283dd
UD
226#endif
227
9dcafc55 228 return value;
aed283dd 229 }
5e76a346 230
94e365c6
UD
231 return NULL;
232}
53761a8b
UD
233
234
53761a8b 235void *
53761a8b
UD
236_dl_vsym (void *handle, const char *name, const char *version, void *who)
237{
238 struct r_found_version vers;
239
240 /* Compute hash value to the version string. */
241 vers.name = version;
242 vers.hidden = 1;
243 vers.hash = _dl_elf_hash (version);
244 /* We don't have a specific file where the symbol can be found. */
245 vers.filename = NULL;
246
f0323886 247 return do_sym (handle, name, who, &vers, 0);
53761a8b
UD
248}
249
250
251void *
53761a8b
UD
252_dl_sym (void *handle, const char *name, void *who)
253{
f0323886 254 return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);
53761a8b 255}