1 /* Look up a symbol in a shared object loaded by `dlopen'.
2 Copyright (C) 1999-2015 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/>. */
28 #include <sysdep-cancel.h>
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
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. */
45 _dl_tls_symaddr (struct link_map
*map
, const ElfW(Sym
) *ref
)
47 # ifndef DONT_USE_TLS_INDEX
50 .ti_module
= map
->l_tls_modid
,
51 .ti_offset
= ref
->st_value
54 return __TLS_GET_ADDR (&tmp
);
56 return __TLS_GET_ADDR (map
->l_tls_modid
, ref
->st_value
);
62 struct call_dl_lookup_args
64 /* Arguments to do_dlsym. */
67 struct r_found_version
*vers
;
70 /* Return values of do_dlsym. */
72 const ElfW(Sym
) **refp
;
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,
87 do_sym (void *handle
, const char *name
, void *who
,
88 struct r_found_version
*vers
, int flags
)
90 const ElfW(Sym
) *ref
= NULL
;
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
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
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
,
113 struct call_dl_lookup_args args
;
118 = flags
| DL_LOOKUP_ADD_DEPENDENCY
| DL_LOOKUP_GSCOPE_LOCK
;
121 THREAD_GSCOPE_SET_FLAG ();
124 const char *errstring
= NULL
;
126 int err
= GLRO(dl_catch_error
) (&objname
, &errstring
, &malloced
,
127 call_dl_lookup
, &args
);
129 THREAD_GSCOPE_RESET_FLAG ();
131 if (__glibc_unlikely (errstring
!= NULL
))
133 /* The lookup was unsuccessful. Rethrow the error. */
134 char *errstring_dup
= strdupa (errstring
);
135 char *objname_dup
= strdupa (objname
);
137 free ((char *) errstring
);
139 GLRO(dl_signal_error
) (err
, objname_dup
, NULL
, errstring_dup
);
146 else if (handle
== RTLD_NEXT
)
148 if (__glibc_unlikely (match
== GL(dl_ns
)[LM_ID_BASE
]._ns_loaded
))
151 || caller
< match
->l_map_start
152 || caller
>= match
->l_map_end
)
153 GLRO(dl_signal_error
) (0, NULL
, NULL
, N_("\
154 RTLD_NEXT used in code not dynamically loaded"));
157 struct link_map
*l
= match
;
158 while (l
->l_loader
!= NULL
)
161 result
= GLRO(dl_lookup_symbol_x
) (name
, match
, &ref
, l
->l_local_scope
,
166 /* Search the scope of the given object. */
167 struct link_map
*map
= handle
;
168 result
= GLRO(dl_lookup_symbol_x
) (name
, map
, &ref
, map
->l_local_scope
,
169 vers
, 0, flags
, NULL
);
177 if (ELFW(ST_TYPE
) (ref
->st_info
) == STT_TLS
)
178 /* The found symbol is a thread-local storage variable.
179 Return the address for to the current thread. */
180 value
= _dl_tls_symaddr (result
, ref
);
183 value
= DL_SYMBOL_ADDRESS (result
, ref
);
185 /* Resolve indirect function address. */
186 if (__glibc_unlikely (ELFW(ST_TYPE
) (ref
->st_info
) == STT_GNU_IFUNC
))
188 DL_FIXUP_VALUE_TYPE fixup
189 = DL_FIXUP_MAKE_VALUE (result
, (ElfW(Addr
)) value
);
190 fixup
= elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup
));
191 value
= (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup
);
195 /* Auditing checkpoint: we have a new binding. Provide the
196 auditing libraries the possibility to change the value and
197 tell us whether further auditing is wanted. */
198 if (__glibc_unlikely (GLRO(dl_naudit
) > 0))
200 const char *strtab
= (const char *) D_PTR (result
,
202 /* Compute index of the symbol entry in the symbol table of
203 the DSO with the definition. */
204 unsigned int ndx
= (ref
- (ElfW(Sym
) *) D_PTR (result
,
207 if ((match
->l_audit_any_plt
| result
->l_audit_any_plt
) != 0)
209 unsigned int altvalue
= 0;
210 struct audit_ifaces
*afct
= GLRO(dl_audit
);
211 /* Synthesize a symbol record where the st_value field is
213 ElfW(Sym
) sym
= *ref
;
214 sym
.st_value
= (ElfW(Addr
)) value
;
216 for (unsigned int cnt
= 0; cnt
< GLRO(dl_naudit
); ++cnt
)
218 if (afct
->symbind
!= NULL
219 && ((match
->l_audit
[cnt
].bindflags
& LA_FLG_BINDFROM
)
221 || ((result
->l_audit
[cnt
].bindflags
& LA_FLG_BINDTO
)
224 unsigned int flags
= altvalue
| LA_SYMB_DLSYM
;
226 = afct
->symbind (&sym
, ndx
,
227 &match
->l_audit
[cnt
].cookie
,
228 &result
->l_audit
[cnt
].cookie
,
229 &flags
, strtab
+ ref
->st_name
);
230 if (new_value
!= (uintptr_t) sym
.st_value
)
232 altvalue
= LA_SYMB_ALTVALUE
;
233 sym
.st_value
= new_value
;
240 value
= (void *) sym
.st_value
;
254 _dl_vsym (void *handle
, const char *name
, const char *version
, void *who
)
256 struct r_found_version vers
;
258 /* Compute hash value to the version string. */
261 vers
.hash
= _dl_elf_hash (version
);
262 /* We don't have a specific file where the symbol can be found. */
263 vers
.filename
= NULL
;
265 return do_sym (handle
, name
, who
, &vers
, 0);
271 _dl_sym (void *handle
, const char *name
, void *who
)
273 return do_sym (handle
, name
, who
, NULL
, DL_LOOKUP_RETURN_NEWEST
);