Properly handle indirect symbols

2012-07-03  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/3351
	* elflink.c (_bfd_elf_update_dynamic_flags): New.
	(_bfd_elf_merge_symbol): Update both real and indirect symbol
	dynamic flags.
	(_bfd_elf_add_default_symbol): Make the real symbol dynamic if
	the indirect symbol is defined in a shared library.
	(elf_link_add_object_symbols): Likewise.  If the indirect
	symbol has been forced local, don't make the real symbol
	dynamic.
	(elf_link_check_versioned_symbol): Check indirect symbol.
	(elf_link_output_extsym): Use real symbol definition when
	reporting indirect symbol error.  Check version info for
	dynamic versioned symbol.

2012-07-03  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/3351
	* ld-elf/indirect.exp: New file.
	* ld-elf/indirect1a.c: Likewise.
	* ld-elf/indirect1b.c: Likewise.
	* ld-elf/indirect1c.c: Likewise.
	* ld-elf/indirect2.c: Likewise.
	* ld-elf/indirect3.out: Likewise.
	* ld-elf/indirect3a.c: Likewise.
	* ld-elf/indirect3b.c: Likewise.
	* ld-elf/indirect3c.c: Likewise.
	* ld-elf/indirect4.out: Likewise.
	* ld-elf/indirect4a.c: Likewise.
	* ld-elf/indirect4b.c: Likewise.
	* ld-elf/indirect4c.c: Likewise.
This commit is contained in:
H.J. Lu 2012-07-03 14:44:35 +00:00
parent 3146fac428
commit 90c984fc53
16 changed files with 360 additions and 29 deletions

View File

@ -1,3 +1,19 @@
2012-07-03 H.J. Lu <hongjiu.lu@intel.com>
PR ld/3351
* elflink.c (_bfd_elf_update_dynamic_flags): New.
(_bfd_elf_merge_symbol): Update both real and indirect symbol
dynamic flags.
(_bfd_elf_add_default_symbol): Make the real symbol dynamic if
the indirect symbol is defined in a shared library.
(elf_link_add_object_symbols): Likewise. If the indirect
symbol has been forced local, don't make the real symbol
dynamic.
(elf_link_check_versioned_symbol): Check indirect symbol.
(elf_link_output_extsym): Use real symbol definition when
reporting indirect symbol error. Check version info for
dynamic versioned symbol.
2012-07-03 Alan Modra <amodra@gmail.com>
PR ld/14207

View File

@ -892,6 +892,33 @@ elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
}
}
/* Mark if a symbol has a definition in a dynamic object or is
weak in all dynamic objects. */
static void
_bfd_elf_mark_dynamic_def_weak (struct elf_link_hash_entry *h,
asection *sec, int bind)
{
if (!h->dynamic_def)
{
if (!bfd_is_und_section (sec))
h->dynamic_def = 1;
else
{
/* Check if this symbol is weak in all dynamic objects. If it
is the first time we see it in a dynamic object, we mark
if it is weak. Otherwise, we clear it. */
if (!h->ref_dynamic)
{
if (bind == STB_WEAK)
h->dynamic_weak = 1;
}
else if (bind != STB_WEAK)
h->dynamic_weak = 0;
}
}
}
/* This function is called when we want to define a new symbol. It
handles the various cases which arise when we find a definition in
a dynamic object, or when there is already a definition in a
@ -920,6 +947,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
{
asection *sec, *oldsec;
struct elf_link_hash_entry *h;
struct elf_link_hash_entry *hi;
struct elf_link_hash_entry *flip;
int bind;
bfd *oldbfd;
@ -958,8 +986,9 @@ _bfd_elf_merge_symbol (bfd *abfd,
if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
return TRUE;
/* For merging, we only care about real symbols. */
/* For merging, we only care about real symbols. But we need to make
sure that indirect symbol dynamic flags are updated. */
hi = h;
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
@ -1135,23 +1164,11 @@ _bfd_elf_merge_symbol (bfd *abfd,
/* We need to remember if a symbol has a definition in a dynamic
object or is weak in all dynamic objects. Internal and hidden
visibility will make it unavailable to dynamic objects. */
if (newdyn && !h->dynamic_def)
if (newdyn)
{
if (!bfd_is_und_section (sec))
h->dynamic_def = 1;
else
{
/* Check if this symbol is weak in all dynamic objects. If it
is the first time we see it in a dynamic object, we mark
if it is weak. Otherwise, we clear it. */
if (!h->ref_dynamic)
{
if (bind == STB_WEAK)
h->dynamic_weak = 1;
}
else if (bind != STB_WEAK)
h->dynamic_weak = 0;
}
_bfd_elf_mark_dynamic_def_weak (h, sec, bind);
if (h != hi)
_bfd_elf_mark_dynamic_def_weak (hi, sec, bind);
}
/* If the old symbol has non-default visibility, we ignore the new
@ -1163,6 +1180,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
*skip = TRUE;
/* Make sure this symbol is dynamic. */
h->ref_dynamic = 1;
hi->ref_dynamic = 1;
/* A protected symbol has external availability. Make sure it is
recorded as dynamic.
@ -1723,6 +1741,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
if (! dynamic)
{
if (! info->executable
|| hi->def_dynamic
|| hi->ref_dynamic)
*dynsym = TRUE;
}
@ -3838,6 +3857,7 @@ error_free_dyn:
flagword flags;
const char *name;
struct elf_link_hash_entry *h;
struct elf_link_hash_entry *hi;
bfd_boolean definition;
bfd_boolean size_change_ok;
bfd_boolean type_change_ok;
@ -4170,6 +4190,9 @@ error_free_dyn:
goto error_free_vers;
h = *sym_hash;
/* We need to make sure that indirect symbol dynamic flags are
updated. */
hi = h;
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
@ -4358,25 +4381,38 @@ error_free_dyn:
h->ref_dynamic = 1;
}
}
if (! info->executable
/* If the indirect symbol has been forced local, don't
make the real symbol dynamic. */
if ((h == hi || !hi->forced_local)
&& (! info->executable
|| h->def_dynamic
|| h->ref_dynamic)
|| h->ref_dynamic))
dynsym = TRUE;
}
else
{
if (! definition)
{
h->ref_dynamic = 1;
hi->ref_dynamic = 1;
}
else
{
h->def_dynamic = 1;
h->dynamic_def = 1;
hi->def_dynamic = 1;
hi->dynamic_def = 1;
}
if (h->def_regular
/* If the indirect symbol has been forced local, don't
make the real symbol dynamic. */
if ((h == hi || !hi->forced_local)
&& (h->def_regular
|| h->ref_regular
|| (h->u.weakdef != NULL
&& ! new_weakdef
&& h->u.weakdef->dynindx != -1))
&& h->u.weakdef->dynindx != -1)))
dynsym = TRUE;
}
@ -8441,6 +8477,10 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
if (!is_elf_hash_table (info->hash))
return FALSE;
/* Check indirect symbol. */
while (h->root.type == bfd_link_hash_indirect)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
switch (h->root.type)
{
default:
@ -8670,6 +8710,11 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
{
bfd *def_bfd;
const char *msg;
struct elf_link_hash_entry *hi = h;
/* Check indirect symbol. */
while (hi->root.type == bfd_link_hash_indirect)
hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
msg = _("%B: internal symbol `%s' in %B is referenced by DSO");
@ -8678,8 +8723,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
else
msg = _("%B: local symbol `%s' in %B is referenced by DSO");
def_bfd = flinfo->output_bfd;
if (h->root.u.def.section != bfd_abs_section_ptr)
def_bfd = h->root.u.def.section->owner;
if (hi->root.u.def.section != bfd_abs_section_ptr)
def_bfd = hi->root.u.def.section->owner;
(*_bfd_error_handler) (msg, flinfo->output_bfd, def_bfd,
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
@ -8929,6 +8974,23 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
{
bfd_byte *esym;
/* Since there is no version information in the dynamic string,
if there is no version info in symbol version section, we will
have a run-time problem. */
if (h->verinfo.verdef == NULL)
{
char *p = strrchr (h->root.root.string, ELF_VER_CHR);
if (p && p [1] != '\0')
{
(*_bfd_error_handler)
(_("%B: No symbol version section for versioned symbol `%s'"),
flinfo->output_bfd, h->root.root.string);
eoinfo->failed = TRUE;
return FALSE;
}
}
sym.st_name = h->dynstr_index;
esym = flinfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym;
if (!check_dynsym (flinfo->output_bfd, &sym))

View File

@ -1,3 +1,20 @@
2012-07-03 H.J. Lu <hongjiu.lu@intel.com>
PR ld/3351
* ld-elf/indirect.exp: New file.
* ld-elf/indirect1a.c: Likewise.
* ld-elf/indirect1b.c: Likewise.
* ld-elf/indirect1c.c: Likewise.
* ld-elf/indirect2.c: Likewise.
* ld-elf/indirect3.out: Likewise.
* ld-elf/indirect3a.c: Likewise.
* ld-elf/indirect3b.c: Likewise.
* ld-elf/indirect3c.c: Likewise.
* ld-elf/indirect4.out: Likewise.
* ld-elf/indirect4a.c: Likewise.
* ld-elf/indirect4b.c: Likewise.
* ld-elf/indirect4c.c: Likewise.
2012-07-02 Roland McGrath <mcgrathr@google.com>
* ld/testsuite/ld-i386/tlsbin-nacl.rd: Update for symbol table changes.

View File

@ -0,0 +1,126 @@
# Expect script for various indirect symbol tests.
# Copyright 2012 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
#
#
# Written by H.J. Lu (hongjiu.lu@intel.com)
#
# Exclude non-ELF targets.
if ![is_elf_format] {
return
}
# Check if compiler works
if { [which $CC] == 0 } {
return
}
proc check_link_message { cmd string testname } {
send_log "$cmd\n"
verbose "$cmd"
catch "exec $cmd" exec_output
send_log "$exec_output\n"
verbose "$exec_output"
foreach str $string {
if [string match "*$str*" $exec_output] {
pass "$testname: $str"
} else {
fail "$testname: $str"
}
}
}
if { ![ld_compile $CC $srcdir/$subdir/indirect1a.c tmpdir/indirect1a.o]
|| ![ld_compile $CC $srcdir/$subdir/indirect1b.c tmpdir/indirect1b.o]
|| ![ld_compile "$CC -fPIC" $srcdir/$subdir/indirect2.c tmpdir/indirect2.o]
|| ![ld_compile $CC $srcdir/$subdir/indirect3a.c tmpdir/indirect3a.o]
|| ![ld_compile $CC $srcdir/$subdir/indirect3b.c tmpdir/indirect3b.o]
|| ![ld_compile $CC $srcdir/$subdir/indirect4a.c tmpdir/indirect4a.o]
|| ![ld_compile $CC $srcdir/$subdir/indirect4b.c tmpdir/indirect4b.o] } {
unresolved "Indirect symbol tests"
return
}
set build_tests {
{"Build libindirect1c.so"
"-shared" "-fPIC"
{indirect1c.c} {} "libindirect1c.so"}
{"Build libindirect3c.so"
"-shared" "-fPIC"
{indirect3c.c} {} "libindirect3c.so"}
{"Build libindirect4c.so"
"-shared" "-fPIC"
{indirect4c.c} {} "libindirect4c.so"}
}
run_cc_link_tests $build_tests
global ld
set string ": final link failed: Bad value"
set string1 ": local symbol \`foo\' in tmpdir/indirect1b.o is referenced by DSO"
set testname "Indirect symbol 1a"
set cmd "$ld -e start -o tmpdir/indirect1 tmpdir/indirect1a.o tmpdir/indirect1b.o tmpdir/libindirect1c.so"
check_link_message "$cmd" [list $string1 $string] "$testname"
set testname "Indirect symbol 1b"
set cmd "$ld -e start -o tmpdir/indirect1 tmpdir/indirect1a.o tmpdir/libindirect1c.so tmpdir/indirect1b.o"
check_link_message "$cmd" [list $string1 $string] "$testname"
set string ": final link failed: Nonrepresentable section on output"
set string2 ": No symbol version section for versioned symbol \`foo@FOO\'"
set testname "Indirect symbol 2"
set cmd "$ld -shared -o tmpdir/indirect2.so tmpdir/indirect2.o"
check_link_message "$cmd" [list $string2 $string] "$testname"
# The following tests require running the executable generated by ld.
if ![isnative] {
return
}
set run_tests {
{"Run with libindirect3c.so 1"
"tmpdir/indirect3a.o tmpdir/indirect3b.o tmpdir/libindirect3c.so" ""
{dummy.c} "indirect3a" "indirect3.out"}
{"Run with libindirect3c.so 2"
"tmpdir/indirect3a.o tmpdir/libindirect3c.so tmpdir/indirect3b.o" ""
{dummy.c} "indirect3b" "indirect3.out"}
{"Run with libindirect3c.so 3"
"tmpdir/indirect3b.o tmpdir/libindirect3c.so tmpdir/indirect3a.o" ""
{dummy.c} "indirect3c" "indirect3.out"}
{"Run with libindirect3c.so 4"
"tmpdir/libindirect3c.so tmpdir/indirect3b.o tmpdir/indirect3a.o" ""
{dummy.c} "indirect3d" "indirect3.out"}
{"Run with libindirect4c.so 1"
"tmpdir/indirect4a.o tmpdir/indirect4b.o tmpdir/libindirect4c.so" ""
{dummy.c} "indirect4a" "indirect4.out"}
{"Run with libindirect4c.so 2"
"tmpdir/indirect4a.o tmpdir/libindirect4c.so tmpdir/indirect4b.o" ""
{dummy.c} "indirect4b" "indirect4.out"}
{"Run with libindirect4c.so 3"
"tmpdir/indirect4b.o tmpdir/libindirect4c.so tmpdir/indirect4a.o" ""
{dummy.c} "indirect4c" "indirect4.out"}
{"Run with libindirect4c.so 4"
"tmpdir/libindirect4c.so tmpdir/indirect4b.o tmpdir/indirect4a.o" ""
{dummy.c} "indirect4d" "indirect4.out"}
}
run_ld_link_exec_tests [] $run_tests

View File

@ -0,0 +1,8 @@
extern void bar (void);
int
start (void)
{
bar ();
return 0;
}

View File

@ -0,0 +1,6 @@
void
foo (void)
{
}
asm (".symver foo,foo@FOO");

View File

@ -0,0 +1,7 @@
extern void foo (void);
void
bar (void)
{
foo ();
}

View File

@ -0,0 +1,9 @@
extern void foo (void);
asm (".symver foo,foo@@@FOO");
void
bar (void)
{
foo ();
}

View File

@ -0,0 +1,2 @@
MAIN
DSO

View File

@ -0,0 +1,10 @@
extern void bar (void);
extern void foo (void);
int
main (void)
{
foo ();
bar ();
return 0;
}

View File

@ -0,0 +1,9 @@
#include <stdio.h>
void
foo (void)
{
printf ("MAIN\n");
}
asm (".symver foo,foo@FOO");

View File

@ -0,0 +1,15 @@
#include <stdio.h>
extern void foo (void);
void
foo (void)
{
printf ("DSO\n");
}
void
bar (void)
{
foo ();
}

View File

@ -0,0 +1,2 @@
MAIN2
MAIN2

View File

@ -0,0 +1,10 @@
extern void bar (void);
extern void foo (void);
int
main (void)
{
foo ();
bar ();
return 0;
}

View File

@ -0,0 +1,17 @@
#include <stdio.h>
void
foo2 (void)
{
printf ("MAIN2\n");
}
asm (".symver foo2,foo@@FOO2");
void
foo1 (void)
{
printf ("MAIN1\n");
}
asm (".symver foo1,foo@FOO1");

View File

@ -0,0 +1,15 @@
#include <stdio.h>
extern void foo (void);
void
foo (void)
{
printf ("DSO\n");
}
void
bar (void)
{
foo ();
}