Fix abmon for bem_ZM
[glibc.git] / elf / dl-sym.c
blobfb54a918587c02655e0bf1bbc26f26e9975043cc
1 /* Look up a symbol in a shared object loaded by `dlopen'.
2 Copyright (C) 1999-2017 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 struct link_map *l = _dl_find_dso_for_object (caller);
95 /* If the address is not recognized the call comes from the main
96 program (we hope). */
97 struct link_map *match = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
99 if (handle == RTLD_DEFAULT)
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. */
106 if (RTLD_SINGLE_THREAD_P)
107 result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
108 match->l_scope, vers, 0,
109 flags | DL_LOOKUP_ADD_DEPENDENCY,
110 NULL);
111 else
113 struct call_dl_lookup_args args;
114 args.name = name;
115 args.map = match;
116 args.vers = vers;
117 args.flags
118 = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
119 args.refp = &ref;
121 THREAD_GSCOPE_SET_FLAG ();
122 struct dl_exception exception;
123 int err = _dl_catch_exception (&exception, call_dl_lookup, &args);
124 THREAD_GSCOPE_RESET_FLAG ();
125 if (__glibc_unlikely (exception.errstring != NULL))
126 _dl_signal_exception (err, &exception, NULL);
128 result = args.map;
131 else if (handle == RTLD_NEXT)
133 if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
135 if (match == NULL
136 || caller < match->l_map_start
137 || caller >= match->l_map_end)
138 _dl_signal_error (0, NULL, NULL, N_("\
139 RTLD_NEXT used in code not dynamically loaded"));
142 struct link_map *l = match;
143 while (l->l_loader != NULL)
144 l = l->l_loader;
146 result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
147 vers, 0, 0, match);
149 else
151 /* Search the scope of the given object. */
152 struct link_map *map = handle;
153 result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
154 vers, 0, flags, NULL);
157 if (ref != NULL)
159 void *value;
161 #ifdef SHARED
162 if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
163 /* The found symbol is a thread-local storage variable.
164 Return the address for to the current thread. */
165 value = _dl_tls_symaddr (result, ref);
166 else
167 #endif
168 value = DL_SYMBOL_ADDRESS (result, ref);
170 /* Resolve indirect function address. */
171 if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
173 DL_FIXUP_VALUE_TYPE fixup
174 = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
175 fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
176 value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
179 #ifdef SHARED
180 /* Auditing checkpoint: we have a new binding. Provide the
181 auditing libraries the possibility to change the value and
182 tell us whether further auditing is wanted. */
183 if (__glibc_unlikely (GLRO(dl_naudit) > 0))
185 const char *strtab = (const char *) D_PTR (result,
186 l_info[DT_STRTAB]);
187 /* Compute index of the symbol entry in the symbol table of
188 the DSO with the definition. */
189 unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
190 l_info[DT_SYMTAB]));
192 if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
194 unsigned int altvalue = 0;
195 struct audit_ifaces *afct = GLRO(dl_audit);
196 /* Synthesize a symbol record where the st_value field is
197 the result. */
198 ElfW(Sym) sym = *ref;
199 sym.st_value = (ElfW(Addr)) value;
201 for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
203 if (afct->symbind != NULL
204 && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
205 != 0
206 || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
207 != 0)))
209 unsigned int flags = altvalue | LA_SYMB_DLSYM;
210 uintptr_t new_value
211 = afct->symbind (&sym, ndx,
212 &match->l_audit[cnt].cookie,
213 &result->l_audit[cnt].cookie,
214 &flags, strtab + ref->st_name);
215 if (new_value != (uintptr_t) sym.st_value)
217 altvalue = LA_SYMB_ALTVALUE;
218 sym.st_value = new_value;
222 afct = afct->next;
225 value = (void *) sym.st_value;
228 #endif
230 return value;
233 return NULL;
237 void *
238 internal_function
239 _dl_vsym (void *handle, const char *name, const char *version, void *who)
241 struct r_found_version vers;
243 /* Compute hash value to the version string. */
244 vers.name = version;
245 vers.hidden = 1;
246 vers.hash = _dl_elf_hash (version);
247 /* We don't have a specific file where the symbol can be found. */
248 vers.filename = NULL;
250 return do_sym (handle, name, who, &vers, 0);
254 void *
255 internal_function
256 _dl_sym (void *handle, const char *name, void *who)
258 return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);