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