Mention IFUNC enhancements to testsuite in NEWS.
[platform/upstream/glibc.git] / elf / dl-sym.c
1 /* Look up a symbol in a shared object loaded by `dlopen'.
2    Copyright (C) 1999-2012 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, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <assert.h>
20 #include <stddef.h>
21 #include <setjmp.h>
22 #include <stdlib.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 #include <dl-tls.h>
30 #include <dl-irel.h>
31
32
33 #ifdef SHARED
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.  */
43 static void *
44 internal_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
61
62 struct call_dl_lookup_args
63 {
64   /* Arguments to do_dlsym.  */
65   struct link_map *map;
66   const char *name;
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
75 static void
76 call_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,
80                                         args->map->l_scope, args->vers, 0,
81                                         args->flags, NULL);
82 }
83
84
85 static void *
86 internal_function
87 do_sym (void *handle, const char *name, void *who,
88         struct r_found_version *vers, int flags)
89 {
90   const ElfW(Sym) *ref = NULL;
91   lookup_t result;
92   ElfW(Addr) caller = (ElfW(Addr)) who;
93
94   /* If the address is not recognized the call comes from the main
95      program (we hope).  */
96   struct link_map *match = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
97
98   /* Find the highest-addressed object that CALLER is not below.  */
99   for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
100     for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
101          l = l->l_next)
102       if (caller >= l->l_map_start && caller < l->l_map_end
103           && (l->l_contiguous || _dl_addr_inside_object (l, caller)))
104         {
105           match = l;
106           break;
107         }
108
109   if (handle == RTLD_DEFAULT)
110     {
111       /* Search the global scope.  We have the simple case where
112          we look up in the scope of an object which was part of
113          the initial binary.  And then the more complex part
114          where the object is dynamically loaded and the scope
115          array can change.  */
116       if (RTLD_SINGLE_THREAD_P)
117         result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
118                                            match->l_scope, vers, 0,
119                                            flags | DL_LOOKUP_ADD_DEPENDENCY,
120                                            NULL);
121       else
122         {
123           struct call_dl_lookup_args args;
124           args.name = name;
125           args.map = match;
126           args.vers = vers;
127           args.flags
128             = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
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 #ifdef 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       /* Resolve indirect function address.  */
196       if (__builtin_expect (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC, 0))
197         {
198           DL_FIXUP_VALUE_TYPE fixup
199             = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
200           fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
201           value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
202         }
203
204 #ifdef SHARED
205       /* Auditing checkpoint: we have a new binding.  Provide the
206          auditing libraries the possibility to change the value and
207          tell us whether further auditing is wanted.  */
208       if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
209         {
210           const char *strtab = (const char *) D_PTR (result,
211                                                      l_info[DT_STRTAB]);
212           /* Compute index of the symbol entry in the symbol table of
213              the DSO with the definition.  */
214           unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
215                                                          l_info[DT_SYMTAB]));
216
217           if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
218             {
219               unsigned int altvalue = 0;
220               struct audit_ifaces *afct = GLRO(dl_audit);
221               /* Synthesize a symbol record where the st_value field is
222                  the result.  */
223               ElfW(Sym) sym = *ref;
224               sym.st_value = (ElfW(Addr)) value;
225
226               for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
227                 {
228                   if (afct->symbind != NULL
229                       && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
230                           != 0
231                           || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
232                               != 0)))
233                     {
234                       unsigned int flags = altvalue | LA_SYMB_DLSYM;
235                       uintptr_t new_value
236                         = afct->symbind (&sym, ndx,
237                                          &match->l_audit[cnt].cookie,
238                                          &result->l_audit[cnt].cookie,
239                                          &flags, strtab + ref->st_name);
240                       if (new_value != (uintptr_t) sym.st_value)
241                         {
242                           altvalue = LA_SYMB_ALTVALUE;
243                           sym.st_value = new_value;
244                         }
245                     }
246
247                   afct = afct->next;
248                 }
249
250               value = (void *) sym.st_value;
251             }
252         }
253 #endif
254
255       return value;
256     }
257
258   return NULL;
259 }
260
261
262 void *
263 internal_function
264 _dl_vsym (void *handle, const char *name, const char *version, void *who)
265 {
266   struct r_found_version vers;
267
268   /* Compute hash value to the version string.  */
269   vers.name = version;
270   vers.hidden = 1;
271   vers.hash = _dl_elf_hash (version);
272   /* We don't have a specific file where the symbol can be found.  */
273   vers.filename = NULL;
274
275   return do_sym (handle, name, who, &vers, 0);
276 }
277
278
279 void *
280 internal_function
281 _dl_sym (void *handle, const char *name, void *who)
282 {
283   return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);
284 }