From 099bb8fb97d79d03a20926d6014a5fc27a5ca75e Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sat, 26 May 2018 04:27:09 -0700 Subject: [PATCH] ld: Add _bfd_elf_link_hide_sym_by_version bfd_hide_sym_by_version can't be used to check if a versioned symbol is hidden. This patch adds _bfd_elf_link_hide_sym_by_version to support both versioned and unversioned symbols by extracting versioned symbol check from _bfd_elf_link_assign_sym_version. bfd/ PR ld/23194 * elf-bfd.h (_bfd_elf_link_hide_sym_by_version): New. * elflink.c (_bfd_elf_link_hide_versioned_symbol): New function. Extracted from _bfd_elf_link_assign_sym_version. (_bfd_elf_link_hide_sym_by_version): New function. (_bfd_elf_link_assign_sym_version): Use _bfd_elf_link_hide_versioned_symbol. * elfxx-x86.c (_bfd_x86_elf_link_symbol_references_local): Call _bfd_elf_link_hide_sym_by_version instead of bfd_hide_sym_by_version. Don't check unversioned symbol. ld/ PR ld/23194 * testsuite/ld-i386/pr23194.d: Expect only R_386_GLOB_DAT against foobar. * testsuite/ld-i386/pr23194.map: Add foobar. * testsuite/ld-x86-64/pr23194.map: Likewise. * testsuite/ld-i386/pr23194.s: Add a common foobar symbol. * testsuite/ld-x86-64/pr23194.s: Likewise. * testsuite/ld-x86-64/pr23194.d: Expect only R_X86_64_GLOB_DAT against foobar. --- bfd/ChangeLog | 13 +++ bfd/elf-bfd.h | 3 + bfd/elflink.c | 164 +++++++++++++++++++++++++++---------- bfd/elfxx-x86.c | 11 +-- ld/ChangeLog | 12 +++ ld/testsuite/ld-i386/pr23194.d | 2 +- ld/testsuite/ld-i386/pr23194.map | 1 + ld/testsuite/ld-i386/pr23194.s | 3 +- ld/testsuite/ld-x86-64/pr23194.d | 2 +- ld/testsuite/ld-x86-64/pr23194.map | 1 + ld/testsuite/ld-x86-64/pr23194.s | 3 +- 11 files changed, 158 insertions(+), 57 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 4cccb96..0419bec 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,16 @@ +2018-05-26 H.J. Lu + + PR ld/23194 + * elf-bfd.h (_bfd_elf_link_hide_sym_by_version): New. + * elflink.c (_bfd_elf_link_hide_versioned_symbol): New function. + Extracted from _bfd_elf_link_assign_sym_version. + (_bfd_elf_link_hide_sym_by_version): New function. + (_bfd_elf_link_assign_sym_version): Use + _bfd_elf_link_hide_versioned_symbol. + * elfxx-x86.c (_bfd_x86_elf_link_symbol_references_local): Call + _bfd_elf_link_hide_sym_by_version instead of + bfd_hide_sym_by_version. Don't check unversioned symbol. + 2018-05-25 Alan Modra * Makefile.in: Regenerate. diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index e051c9c..032e11f 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -2186,6 +2186,9 @@ extern const struct bfd_elf_special_section *_bfd_elf_get_special_section extern const struct bfd_elf_special_section *_bfd_elf_get_sec_type_attr (bfd *, asection *); +extern bfd_boolean _bfd_elf_link_hide_sym_by_version + (struct bfd_link_info *, struct elf_link_hash_entry *); + /* If the target doesn't have reloc handling written yet: */ extern bfd_boolean _bfd_elf_no_info_to_howto (bfd *, arelent *, Elf_Internal_Rela *); diff --git a/bfd/elflink.c b/bfd/elflink.c index 0383e4e..05664b4 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -2222,6 +2222,115 @@ _bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h, return TRUE; } +/* Return TRUE and set *HIDE to TRUE if the versioned symbol is + hidden. Set *T_P to NULL if there is no match. */ + +static bfd_boolean +_bfd_elf_link_hide_versioned_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h, + const char *version_p, + struct bfd_elf_version_tree **t_p, + bfd_boolean *hide) +{ + struct bfd_elf_version_tree *t; + + /* Look for the version. If we find it, it is no longer weak. */ + for (t = info->version_info; t != NULL; t = t->next) + { + if (strcmp (t->name, version_p) == 0) + { + size_t len; + char *alc; + struct bfd_elf_version_expr *d; + + len = version_p - h->root.root.string; + alc = (char *) bfd_malloc (len); + if (alc == NULL) + return FALSE; + memcpy (alc, h->root.root.string, len - 1); + alc[len - 1] = '\0'; + if (alc[len - 2] == ELF_VER_CHR) + alc[len - 2] = '\0'; + + h->verinfo.vertree = t; + t->used = TRUE; + d = NULL; + + if (t->globals.list != NULL) + d = (*t->match) (&t->globals, NULL, alc); + + /* See if there is anything to force this symbol to + local scope. */ + if (d == NULL && t->locals.list != NULL) + { + d = (*t->match) (&t->locals, NULL, alc); + if (d != NULL + && h->dynindx != -1 + && ! info->export_dynamic) + *hide = TRUE; + } + + free (alc); + break; + } + } + + *t_p = t; + + return TRUE; +} + +/* Return TRUE if the symbol H is hidden by version script. */ + +bfd_boolean +_bfd_elf_link_hide_sym_by_version (struct bfd_link_info *info, + struct elf_link_hash_entry *h) +{ + const char *p; + bfd_boolean hide = FALSE; + const struct elf_backend_data *bed + = get_elf_backend_data (info->output_bfd); + + /* Version script only hides symbols defined in regular objects. */ + if (!h->def_regular && !ELF_COMMON_DEF_P (h)) + return TRUE; + + p = strchr (h->root.root.string, ELF_VER_CHR); + if (p != NULL && h->verinfo.vertree == NULL) + { + struct bfd_elf_version_tree *t; + + ++p; + if (*p == ELF_VER_CHR) + ++p; + + if (*p != '\0' + && _bfd_elf_link_hide_versioned_symbol (info, h, p, &t, &hide) + && hide) + { + if (hide) + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + return TRUE; + } + } + + /* If we don't have a version for this symbol, see if we can find + something. */ + if (h->verinfo.vertree == NULL && info->version_info != NULL) + { + h->verinfo.vertree + = bfd_find_version_for_sym (info->version_info, + h->root.root.string, &hide); + if (h->verinfo.vertree != NULL && hide) + { + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + return TRUE; + } + } + + return FALSE; +} + /* Figure out appropriate versions for all the symbols. We may not have the version number script until we have read all of the input files, so until that point we don't know which symbols should be @@ -2235,6 +2344,7 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) const struct elf_backend_data *bed; struct elf_info_failed eif; char *p; + bfd_boolean hide; sinfo = (struct elf_info_failed *) data; info = sinfo->info; @@ -2254,6 +2364,7 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) if (!h->def_regular) return TRUE; + hide = FALSE; bed = get_elf_backend_data (info->output_bfd); p = strchr (h->root.root.string, ELF_VER_CHR); if (p != NULL && h->verinfo.vertree == NULL) @@ -2268,50 +2379,15 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) if (*p == '\0') return TRUE; - /* Look for the version. If we find it, it is no longer weak. */ - for (t = sinfo->info->version_info; t != NULL; t = t->next) + if (!_bfd_elf_link_hide_versioned_symbol (info, h, p, &t, &hide)) { - if (strcmp (t->name, p) == 0) - { - size_t len; - char *alc; - struct bfd_elf_version_expr *d; - - len = p - h->root.root.string; - alc = (char *) bfd_malloc (len); - if (alc == NULL) - { - sinfo->failed = TRUE; - return FALSE; - } - memcpy (alc, h->root.root.string, len - 1); - alc[len - 1] = '\0'; - if (alc[len - 2] == ELF_VER_CHR) - alc[len - 2] = '\0'; - - h->verinfo.vertree = t; - t->used = TRUE; - d = NULL; - - if (t->globals.list != NULL) - d = (*t->match) (&t->globals, NULL, alc); - - /* See if there is anything to force this symbol to - local scope. */ - if (d == NULL && t->locals.list != NULL) - { - d = (*t->match) (&t->locals, NULL, alc); - if (d != NULL - && h->dynindx != -1 - && ! info->export_dynamic) - (*bed->elf_backend_hide_symbol) (info, h, TRUE); - } - - free (alc); - break; - } + sinfo->failed = TRUE; + return FALSE; } + if (hide) + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + /* If we are building an application, we need to create a version node for this version. */ if (t == NULL && bfd_link_executable (info)) @@ -2367,10 +2443,10 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) /* If we don't have a version for this symbol, see if we can find something. */ - if (h->verinfo.vertree == NULL && sinfo->info->version_info != NULL) + if (!hide + && h->verinfo.vertree == NULL + && sinfo->info->version_info != NULL) { - bfd_boolean hide; - h->verinfo.vertree = bfd_find_version_for_sym (sinfo->info->version_info, h->root.root.string, &hide); diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index 710417f..3a7573f 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -2038,21 +2038,14 @@ _bfd_x86_elf_link_symbol_references_local (struct bfd_link_info *info, && htab->interp == NULL) || info->dynamic_undefined_weak == 0)) || ((h->def_regular || ELF_COMMON_DEF_P (h)) - && h->versioned == unversioned && info->version_info != NULL - && bfd_hide_sym_by_version (info->version_info, - h->root.root.string))) + && _bfd_elf_link_hide_sym_by_version (info, h))) { eh->local_ref = 2; return TRUE; } - /* bfd_hide_sym_by_version can't be used to check if a versioned symbol - is hidden. It has to be syncd with _bfd_elf_link_assign_sym_version - to get the correct answer. */ - if (h->versioned == unversioned) - eh->local_ref = 1; - + eh->local_ref = 1; return FALSE; } diff --git a/ld/ChangeLog b/ld/ChangeLog index d418b20..fa5f222 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,15 @@ +2018-05-26 H.J. Lu + + PR ld/23194 + * testsuite/ld-i386/pr23194.d: Expect only R_386_GLOB_DAT + against foobar. + * testsuite/ld-i386/pr23194.map: Add foobar. + * testsuite/ld-x86-64/pr23194.map: Likewise. + * testsuite/ld-i386/pr23194.s: Add a common foobar symbol. + * testsuite/ld-x86-64/pr23194.s: Likewise. + * testsuite/ld-x86-64/pr23194.d: Expect only R_X86_64_GLOB_DAT + against foobar. + 2018-05-25 Alan Modra * po/BLD-POTFILES.in: Regenerate. diff --git a/ld/testsuite/ld-i386/pr23194.d b/ld/testsuite/ld-i386/pr23194.d index b5e8c33..f6d2a03 100644 --- a/ld/testsuite/ld-i386/pr23194.d +++ b/ld/testsuite/ld-i386/pr23194.d @@ -4,4 +4,4 @@ Relocation section '.rel.dyn' at offset 0x[0-9a-f]+ contains 1 entry: Offset Info Type Sym. Value Symbol's Name -[0-9a-f]+ +[0-9a-f]+ +R_386_RELATIVE + +[0-9a-f]+ +[0-9a-f]+ +R_386_GLOB_DAT +[0-9a-f]+ +foobar@@FOO diff --git a/ld/testsuite/ld-i386/pr23194.map b/ld/testsuite/ld-i386/pr23194.map index 353c194..196dac9 100644 --- a/ld/testsuite/ld-i386/pr23194.map +++ b/ld/testsuite/ld-i386/pr23194.map @@ -1,6 +1,7 @@ FOO { global: bar; + foobar; local: *; }; diff --git a/ld/testsuite/ld-i386/pr23194.s b/ld/testsuite/ld-i386/pr23194.s index 32693fe..a64bae1 100644 --- a/ld/testsuite/ld-i386/pr23194.s +++ b/ld/testsuite/ld-i386/pr23194.s @@ -3,10 +3,11 @@ .globl foo .type foo, @function foo: - ret + movl foobar@GOT(%ebx), %eax .size foo, .-foo .globl bar .type bar, @function bar: jmp *foo@GOT(%eax) .size bar, .-bar + .comm foobar,30,4 diff --git a/ld/testsuite/ld-x86-64/pr23194.d b/ld/testsuite/ld-x86-64/pr23194.d index 6b12060..b907afb 100644 --- a/ld/testsuite/ld-x86-64/pr23194.d +++ b/ld/testsuite/ld-x86-64/pr23194.d @@ -4,4 +4,4 @@ Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 1 entry: Offset Info Type Symbol's Value Symbol's Name \+ Addend -[0-9a-f]+ +[0-9a-f]+ +R_X86_64_RELATIVE +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +R_X86_64_GLOB_DAT +[0-9a-f]+ +foobar@@FOO \+ 0 diff --git a/ld/testsuite/ld-x86-64/pr23194.map b/ld/testsuite/ld-x86-64/pr23194.map index 353c194..196dac9 100644 --- a/ld/testsuite/ld-x86-64/pr23194.map +++ b/ld/testsuite/ld-x86-64/pr23194.map @@ -1,6 +1,7 @@ FOO { global: bar; + foobar; local: *; }; diff --git a/ld/testsuite/ld-x86-64/pr23194.s b/ld/testsuite/ld-x86-64/pr23194.s index 277c19d..34517bc 100644 --- a/ld/testsuite/ld-x86-64/pr23194.s +++ b/ld/testsuite/ld-x86-64/pr23194.s @@ -3,10 +3,11 @@ .globl foo .type foo, @function foo: - ret + movq foobar@GOTPCREL(%rip), %rax .size foo, .-foo .globl bar .type bar, @function bar: jmp *foo@GOTPCREL(%rip) .size bar, .-bar + .comm foobar,30,4 -- 2.7.4