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;