1 /* Look up a symbol in a shared object loaded by `dlopen'.
2 Copyright (C) 1999-2023 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 <https://www.gnu.org/licenses/>. */
28 #include <sysdep-cancel.h>
31 #include <dl-sym-post.h>
35 /* Systems which do not have tls_index also probably have to define
36 DONT_USE_TLS_INDEX. */
38 # ifndef __TLS_GET_ADDR
39 # define __TLS_GET_ADDR __tls_get_addr
42 /* Return the symbol address given the map of the module it is in and
43 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,
85 do_sym (void *handle
, const char *name
, void *who
,
86 struct r_found_version
*vers
, int flags
)
88 const ElfW(Sym
) *ref
= NULL
;
90 ElfW(Addr
) caller
= (ElfW(Addr
)) who
;
92 /* Link map of the caller if needed. */
93 struct link_map
*match
= NULL
;
95 if (handle
== RTLD_DEFAULT
)
97 match
= _dl_sym_find_caller_link_map (caller
);
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
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
,
111 struct call_dl_lookup_args args
;
116 = flags
| DL_LOOKUP_ADD_DEPENDENCY
| DL_LOOKUP_GSCOPE_LOCK
;
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
);
129 else if (handle
== RTLD_NEXT
)
131 match
= _dl_sym_find_caller_link_map (caller
);
133 if (__glibc_unlikely (match
== GL(dl_ns
)[LM_ID_BASE
]._ns_loaded
))
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
)
146 result
= GLRO(dl_lookup_symbol_x
) (name
, match
, &ref
, l
->l_local_scope
,
147 vers
, 0, flags
, match
);
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
);
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
);
168 value
= DL_SYMBOL_ADDRESS (result
, ref
);
170 return _dl_sym_post (result
, ref
, value
, caller
, match
);
178 _dl_vsym (void *handle
, const char *name
, const char *version
, void *who
)
180 struct r_found_version vers
;
182 /* Compute hash value to the version string. */
185 vers
.hash
= _dl_elf_hash (version
);
186 /* We don't have a specific file where the symbol can be found. */
187 vers
.filename
= NULL
;
189 return do_sym (handle
, name
, who
, &vers
, 0);
193 _dl_sym (void *handle
, const char *name
, void *who
)
195 return do_sym (handle
, name
, who
, NULL
, DL_LOOKUP_RETURN_NEWEST
);