Mark internal netlink functions with attribute_hidden [BZ #18822]
[glibc.git] / elf / dl-sym.c
blob3e23555b786deffdb9601da325be07b132b856a9
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 _dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
46 # ifndef DONT_USE_TLS_INDEX
47 tls_index tmp =
49 .ti_module = map->l_tls_modid,
50 .ti_offset = ref->st_value
53 return __TLS_GET_ADDR (&tmp);
54 # else
55 return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
56 # endif
58 #endif
61 struct call_dl_lookup_args
63 /* Arguments to do_dlsym. */
64 struct link_map *map;
65 const char *name;
66 struct r_found_version *vers;
67 int flags;
69 /* Return values of do_dlsym. */
70 lookup_t loadbase;
71 const ElfW(Sym) **refp;
74 static void
75 call_dl_lookup (void *ptr)
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,
79 args->map->l_scope, args->vers, 0,
80 args->flags, NULL);
84 static void *
85 do_sym (void *handle, const char *name, void *who,
86 struct r_found_version *vers, int flags)
88 const ElfW(Sym) *ref = NULL;
89 lookup_t result;
90 ElfW(Addr) caller = (ElfW(Addr)) who;
92 struct link_map *l = _dl_find_dso_for_object (caller);
93 /* If the address is not recognized the call comes from the main
94 program (we hope). */
95 struct link_map *match = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
97 if (handle == RTLD_DEFAULT)
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. */
104 if (RTLD_SINGLE_THREAD_P)
105 result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
106 match->l_scope, vers, 0,
107 flags | DL_LOOKUP_ADD_DEPENDENCY,
108 NULL);
109 else
111 struct call_dl_lookup_args args;
112 args.name = name;
113 args.map = match;
114 args.vers = vers;
115 args.flags
116 = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
117 args.refp = &ref;
119 THREAD_GSCOPE_SET_FLAG ();
120 struct dl_exception exception;
121 int err = _dl_catch_exception (&exception, call_dl_lookup, &args);
122 THREAD_GSCOPE_RESET_FLAG ();
123 if (__glibc_unlikely (exception.errstring != NULL))
124 _dl_signal_exception (err, &exception, NULL);
126 result = args.map;
129 else if (handle == RTLD_NEXT)
131 if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
133 if (match == NULL
134 || caller < match->l_map_start
135 || caller >= match->l_map_end)
136 _dl_signal_error (0, NULL, NULL, N_("\
137 RTLD_NEXT used in code not dynamically loaded"));
140 struct link_map *l = match;
141 while (l->l_loader != NULL)
142 l = l->l_loader;
144 result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
145 vers, 0, 0, match);
147 else
149 /* Search the scope of the given object. */
150 struct link_map *map = handle;
151 result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
152 vers, 0, flags, NULL);
155 if (ref != NULL)
157 void *value;
159 #ifdef SHARED
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. */
163 value = _dl_tls_symaddr (result, ref);
164 else
165 #endif
166 value = DL_SYMBOL_ADDRESS (result, ref);
168 /* Resolve indirect function address. */
169 if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
171 DL_FIXUP_VALUE_TYPE fixup
172 = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
173 fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
174 value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
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. */
181 if (__glibc_unlikely (GLRO(dl_naudit) > 0))
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]));
190 if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
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;
199 for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
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)))
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)
215 altvalue = LA_SYMB_ALTVALUE;
216 sym.st_value = new_value;
220 afct = afct->next;
223 value = (void *) sym.st_value;
226 #endif
228 return value;
231 return NULL;
235 void *
236 _dl_vsym (void *handle, const char *name, const char *version, void *who)
238 struct r_found_version vers;
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;
247 return do_sym (handle, name, who, &vers, 0);
251 void *
252 _dl_sym (void *handle, const char *name, void *who)
254 return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);