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