1 /* Look up a symbol in a shared object loaded by `dlopen'.
2 Copyright (C) 1999-2002,2004,2006,2007,2009 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 #include <sysdep-cancel.h>
33 /* Systems which do not have tls_index also probably have to define
34 DONT_USE_TLS_INDEX. */
36 # ifndef __TLS_GET_ADDR
37 # define __TLS_GET_ADDR __tls_get_addr
40 /* Return the symbol address given the map of the module it is in and
41 the symbol record. This is used in dl-sym.c. */
44 _dl_tls_symaddr (struct link_map
*map
, const ElfW(Sym
) *ref
)
46 # ifndef DONT_USE_TLS_INDEX
49 .ti_module
= map
->l_tls_modid
,
50 .ti_offset
= ref
->st_value
53 return __TLS_GET_ADDR (&tmp
);
55 return __TLS_GET_ADDR (map
->l_tls_modid
, ref
->st_value
);
61 struct call_dl_lookup_args
63 /* Arguments to do_dlsym. */
66 struct r_found_version
*vers
;
69 /* Return values of do_dlsym. */
71 const ElfW(Sym
) **refp
;
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,
86 do_sym (void *handle
, const char *name
, void *who
,
87 struct r_found_version
*vers
, int flags
)
89 const ElfW(Sym
) *ref
= NULL
;
91 ElfW(Addr
) caller
= (ElfW(Addr
)) who
;
93 /* If the address is not recognized the call comes from the main
95 struct link_map
*match
= GL(dl_ns
)[LM_ID_BASE
]._ns_loaded
;
97 /* Find the highest-addressed object that CALLER is not below. */
98 for (Lmid_t ns
= 0; ns
< GL(dl_nns
); ++ns
)
99 for (struct link_map
*l
= GL(dl_ns
)[ns
]._ns_loaded
; l
!= NULL
;
101 if (caller
>= l
->l_map_start
&& caller
< l
->l_map_end
102 && (l
->l_contiguous
|| _dl_addr_inside_object (l
, caller
)))
108 if (handle
== RTLD_DEFAULT
)
110 /* Search the global scope. We have the simple case where
111 we look up in the scope of an object which was part of
112 the initial binary. And then the more complex part
113 where the object is dynamically loaded and the scope
115 if (RTLD_SINGLE_THREAD_P
)
116 result
= GLRO(dl_lookup_symbol_x
) (name
, match
, &ref
,
117 match
->l_scope
, vers
, 0,
118 flags
| DL_LOOKUP_ADD_DEPENDENCY
,
122 struct call_dl_lookup_args args
;
127 = flags
| DL_LOOKUP_ADD_DEPENDENCY
| DL_LOOKUP_GSCOPE_LOCK
;
130 THREAD_GSCOPE_SET_FLAG ();
133 const char *errstring
= NULL
;
135 int err
= GLRO(dl_catch_error
) (&objname
, &errstring
, &malloced
,
136 call_dl_lookup
, &args
);
138 THREAD_GSCOPE_RESET_FLAG ();
140 if (__builtin_expect (errstring
!= NULL
, 0))
142 /* The lookup was unsuccessful. Rethrow the error. */
143 char *errstring_dup
= strdupa (errstring
);
144 char *objname_dup
= strdupa (objname
);
146 free ((char *) errstring
);
148 GLRO(dl_signal_error
) (err
, objname_dup
, NULL
, errstring_dup
);
155 else if (handle
== RTLD_NEXT
)
157 if (__builtin_expect (match
== GL(dl_ns
)[LM_ID_BASE
]._ns_loaded
, 0))
160 || caller
< match
->l_map_start
161 || caller
>= match
->l_map_end
)
162 GLRO(dl_signal_error
) (0, NULL
, NULL
, N_("\
163 RTLD_NEXT used in code not dynamically loaded"));
166 struct link_map
*l
= match
;
167 while (l
->l_loader
!= NULL
)
170 result
= GLRO(dl_lookup_symbol_x
) (name
, match
, &ref
, l
->l_local_scope
,
175 /* Search the scope of the given object. */
176 struct link_map
*map
= handle
;
177 result
= GLRO(dl_lookup_symbol_x
) (name
, map
, &ref
, map
->l_local_scope
,
178 vers
, 0, flags
, NULL
);
186 if (ELFW(ST_TYPE
) (ref
->st_info
) == STT_TLS
)
187 /* The found symbol is a thread-local storage variable.
188 Return the address for to the current thread. */
189 value
= _dl_tls_symaddr (result
, ref
);
192 value
= DL_SYMBOL_ADDRESS (result
, ref
);
194 /* Resolve indirect function address. */
195 if (__builtin_expect (ELFW(ST_TYPE
) (ref
->st_info
) == STT_GNU_IFUNC
, 0))
197 DL_FIXUP_VALUE_TYPE fixup
198 = DL_FIXUP_MAKE_VALUE (result
, (ElfW(Addr
)) value
);
200 ((DL_FIXUP_VALUE_TYPE (*) (void)) DL_FIXUP_VALUE_ADDR (fixup
)) ();
201 value
= (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup
);
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))
210 const char *strtab
= (const char *) D_PTR (result
,
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
,
217 if ((match
->l_audit_any_plt
| result
->l_audit_any_plt
) != 0)
219 unsigned int altvalue
= 0;
220 struct audit_ifaces
*afct
= GLRO(dl_audit
);
221 /* Synthesize a symbol record where the st_value field is
223 ElfW(Sym
) sym
= *ref
;
224 sym
.st_value
= (ElfW(Addr
)) value
;
226 for (unsigned int cnt
= 0; cnt
< GLRO(dl_naudit
); ++cnt
)
228 if (afct
->symbind
!= NULL
229 && ((match
->l_audit
[cnt
].bindflags
& LA_FLG_BINDFROM
)
231 || ((result
->l_audit
[cnt
].bindflags
& LA_FLG_BINDTO
)
234 unsigned int flags
= altvalue
| LA_SYMB_DLSYM
;
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
)
242 altvalue
= LA_SYMB_ALTVALUE
;
243 sym
.st_value
= new_value
;
250 value
= (void *) sym
.st_value
;
264 _dl_vsym (void *handle
, const char *name
, const char *version
, void *who
)
266 struct r_found_version vers
;
268 /* Compute hash value to the version string. */
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
;
275 return do_sym (handle
, name
, who
, &vers
, 0);
281 _dl_sym (void *handle
, const char *name
, void *who
)
283 return do_sym (handle
, name
, who
, NULL
, DL_LOOKUP_RETURN_NEWEST
);