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