diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | elf/dl-addr.c | 1 | ||||
-rw-r--r-- | elf/dl-lookup.c | 4 | ||||
-rw-r--r-- | elf/dl-reloc.c | 3 | ||||
-rw-r--r-- | sysdeps/generic/ldsodefs.h | 13 |
5 files changed, 29 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog index a7ca1ff16e..29a92f5a5b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2016-07-01 Maciej W. Rozycki <macro@imgtec.com> + + * sysdeps/generic/ldsodefs.h + (dl_symbol_visibility_binds_local_p): New inline function. + * elf/dl-addr.c (determine_info): Treat hidden and internal + symbols as local. + * elf/dl-lookup.c (do_lookup_x): Likewise. + * elf/dl-reloc.c (RESOLVE_MAP): Likewise. + 2016-07-01 Aurelien Jarno <aurelien@aurel32.net> * sparc/sparc32/sparcv9/fpu/s_nearbyint.S (__nearbyint): Trigger an diff --git a/elf/dl-addr.c b/elf/dl-addr.c index 291ff55816..1b16a58ced 100644 --- a/elf/dl-addr.c +++ b/elf/dl-addr.c @@ -88,6 +88,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info, for (; (void *) symtab < (void *) symtabend; ++symtab) if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK) + && __glibc_likely (!dl_symbol_visibility_binds_local_p (symtab)) && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS && (symtab->st_shndx != SHN_UNDEF || symtab->st_value != 0) diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c index 6d299c1097..52c994e16c 100644 --- a/elf/dl-lookup.c +++ b/elf/dl-lookup.c @@ -516,6 +516,10 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash, #endif } + /* Hidden and internal symbols are local, ignore them. */ + if (__glibc_unlikely (dl_symbol_visibility_binds_local_p (sym))) + goto skip; + switch (ELFW(ST_BIND) (sym->st_info)) { case STB_WEAK: diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index 14709f960d..42bddc1e2c 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -233,7 +233,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code. */ #define RESOLVE_MAP(ref, version, r_type) \ - (ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \ + ((ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \ + && __glibc_likely (!dl_symbol_visibility_binds_local_p (*ref))) \ ? ((__builtin_expect ((*ref) == l->l_lookup_cache.sym, 0) \ && elf_machine_type_class (r_type) == l->l_lookup_cache.type_class) \ ? (bump_num_cache_relocations (), \ diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index ddec0be12c..f68fdf4501 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -88,6 +88,19 @@ typedef struct link_map *lookup_t; || (ADDR) < (L)->l_addr + (SYM)->st_value + (SYM)->st_size) \ && ((MATCHSYM) == NULL || (MATCHSYM)->st_value < (SYM)->st_value)) +/* According to the ELF gABI no STV_HIDDEN or STV_INTERNAL symbols are + expected to be present in dynamic symbol tables as they should have + been either removed or converted to STB_LOCAL binding by the static + linker. However some GNU binutils versions produce such symbols in + some cases. To prevent such symbols present in a buggy binary from + preempting global symbols we filter them out with this predicate. */ +static __always_inline bool +dl_symbol_visibility_binds_local_p (const ElfW(Sym) *sym) +{ + return (ELFW(ST_VISIBILITY) (sym->st_other) == STV_HIDDEN + || ELFW(ST_VISIBILITY) (sym->st_other) == STV_INTERNAL); +} + /* Unmap a loaded object, called by _dl_close (). */ #ifndef DL_UNMAP_IS_SPECIAL # define DL_UNMAP(map) _dl_unmap_segments (map) |