|
|
446cf2 |
commit 4a2ab5843a5cc4a5db1b3b79916a520ea8b115dc
|
|
|
446cf2 |
Author: Florian Weimer <fweimer@redhat.com>
|
|
|
446cf2 |
Date: Fri Nov 8 15:48:51 2019 +0100
|
|
|
446cf2 |
|
|
|
446cf2 |
dlsym: Do not determine caller link map if not needed
|
|
|
446cf2 |
|
|
|
446cf2 |
Obtaining the link map is potentially very slow because it requires
|
|
|
446cf2 |
iterating over all loaded objects in the current implementation. If
|
|
|
446cf2 |
the caller supplied an explicit handle (i.e., not one of the RTLD_*
|
|
|
446cf2 |
constants), the dlsym implementation does not need the identity of the
|
|
|
446cf2 |
caller (except in the special case of auditing), so this change
|
|
|
446cf2 |
avoids computing it in that case.
|
|
|
446cf2 |
|
|
|
446cf2 |
Even in the minimal case (dlsym called from a main program linked with
|
|
|
446cf2 |
-dl), this shows a small speedup, perhaps around five percent. The
|
|
|
446cf2 |
performance improvement can be arbitrarily large in principle (if
|
|
|
446cf2 |
_dl_find_dso_for_object has to iterate over many link maps).
|
|
|
446cf2 |
|
|
|
446cf2 |
Change-Id: Ide5d9e2cc7ac25a0ffae8fb4c26def0c898efa29
|
|
|
446cf2 |
|
|
|
446cf2 |
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
|
|
|
446cf2 |
index 286cf7e27fd59f20..b133850a3c6657a4 100644
|
|
|
446cf2 |
--- a/elf/dl-sym.c
|
|
|
446cf2 |
+++ b/elf/dl-sym.c
|
|
|
446cf2 |
@@ -80,6 +80,18 @@ call_dl_lookup (void *ptr)
|
|
|
446cf2 |
args->flags, NULL);
|
|
|
446cf2 |
}
|
|
|
446cf2 |
|
|
|
446cf2 |
+/* Return the link map containing the caller address. */
|
|
|
446cf2 |
+static inline struct link_map *
|
|
|
446cf2 |
+find_caller_link_map (ElfW(Addr) caller)
|
|
|
446cf2 |
+{
|
|
|
446cf2 |
+ struct link_map *l = _dl_find_dso_for_object (caller);
|
|
|
446cf2 |
+ if (l != NULL)
|
|
|
446cf2 |
+ return l;
|
|
|
446cf2 |
+ else
|
|
|
446cf2 |
+ /* If the address is not recognized the call comes from the main
|
|
|
446cf2 |
+ program (we hope). */
|
|
|
446cf2 |
+ return GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
|
|
446cf2 |
+}
|
|
|
446cf2 |
|
|
|
446cf2 |
static void *
|
|
|
446cf2 |
do_sym (void *handle, const char *name, void *who,
|
|
|
446cf2 |
@@ -89,13 +101,13 @@ do_sym (void *handle, const char *name, void *who,
|
|
|
446cf2 |
lookup_t result;
|
|
|
446cf2 |
ElfW(Addr) caller = (ElfW(Addr)) who;
|
|
|
446cf2 |
|
|
|
446cf2 |
- struct link_map *l = _dl_find_dso_for_object (caller);
|
|
|
446cf2 |
- /* If the address is not recognized the call comes from the main
|
|
|
446cf2 |
- program (we hope). */
|
|
|
446cf2 |
- struct link_map *match = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
|
|
446cf2 |
+ /* Link map of the caller if needed. */
|
|
|
446cf2 |
+ struct link_map *match = NULL;
|
|
|
446cf2 |
|
|
|
446cf2 |
if (handle == RTLD_DEFAULT)
|
|
|
446cf2 |
{
|
|
|
446cf2 |
+ match = find_caller_link_map (caller);
|
|
|
446cf2 |
+
|
|
|
446cf2 |
/* Search the global scope. We have the simple case where
|
|
|
446cf2 |
we look up in the scope of an object which was part of
|
|
|
446cf2 |
the initial binary. And then the more complex part
|
|
|
446cf2 |
@@ -128,6 +140,8 @@ do_sym (void *handle, const char *name, void *who,
|
|
|
446cf2 |
}
|
|
|
446cf2 |
else if (handle == RTLD_NEXT)
|
|
|
446cf2 |
{
|
|
|
446cf2 |
+ match = find_caller_link_map (caller);
|
|
|
446cf2 |
+
|
|
|
446cf2 |
if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
|
|
|
446cf2 |
{
|
|
|
446cf2 |
if (match == NULL
|
|
|
446cf2 |
@@ -187,6 +201,9 @@ RTLD_NEXT used in code not dynamically loaded"));
|
|
|
446cf2 |
unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
|
|
|
446cf2 |
l_info[DT_SYMTAB]));
|
|
|
446cf2 |
|
|
|
446cf2 |
+ if (match == NULL)
|
|
|
446cf2 |
+ match = find_caller_link_map (caller);
|
|
|
446cf2 |
+
|
|
|
446cf2 |
if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
|
|
|
446cf2 |
{
|
|
|
446cf2 |
unsigned int altvalue = 0;
|