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.
This commit is contained in:
H.J. Lu 2018-05-26 04:27:09 -07:00
parent d7460de3ea
commit 099bb8fb97
11 changed files with 158 additions and 57 deletions

View File

@ -1,3 +1,16 @@
2018-05-26 H.J. Lu <hongjiu.lu@intel.com>
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 <amodra@gmail.com>
* Makefile.in: Regenerate.

View File

@ -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 *);

View File

@ -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);

View File

@ -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;
}

View File

@ -1,3 +1,15 @@
2018-05-26 H.J. Lu <hongjiu.lu@intel.com>
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 <amodra@gmail.com>
* po/BLD-POTFILES.in: Regenerate.

View File

@ -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

View File

@ -1,6 +1,7 @@
FOO {
global:
bar;
foobar;
local:
*;
};

View File

@ -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

View File

@ -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

View File

@ -1,6 +1,7 @@
FOO {
global:
bar;
foobar;
local:
*;
};

View File

@ -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