aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--elf/dl-addr.c1
-rw-r--r--elf/dl-lookup.c4
-rw-r--r--elf/dl-reloc.c3
-rw-r--r--sysdeps/generic/ldsodefs.h13
5 files changed, 29 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index a7ca1ff..29a92f5 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 291ff55..1b16a58 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 6d299c1..52c994e 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 14709f9..42bddc1 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 ddec0be..f68fdf4 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)