Mark the plugin symbol undefined

LTO may optimize out a plugin symbol, which is also referenced by a
non-IR file.  When that happens, we should mark the plugin symbol
undefined.  It isn't the problem since LTO already determined the
symbols in the non-IR file aren't used.

bfd/

	PR ld/12365
	PR ld/14272
	* elflink.c (_bfd_elf_fix_symbol_flags): Mark the plugin symbol
	undefined if it is referenced from a non-IR file.

ld/testsuite/

	PR ld/12365
	* ld-plugin/pr12365a.c: New file.
	* ld-plugin/pr12365b.c: Likewise.
	* ld-plugin/pr12365c.c: Likewise.

	* ld-plugin/lto.exp (lto_link_tests): Prepare for the PR ld/12365
	test.
	Run the PR ld/12365 test.
This commit is contained in:
H.J. Lu 2015-02-03 09:03:23 -08:00
parent 9910b1c8f3
commit 60f7927512
7 changed files with 193 additions and 0 deletions

View File

@ -1,3 +1,10 @@
2015-02-03 H.J. Lu <hongjiu.lu@intel.com>
PR ld/12365
PR ld/14272
* elflink.c (_bfd_elf_fix_symbol_flags): Mark the plugin symbol
undefined if it is referenced from a non-IR file.
2015-02-03 Nick Clifton <nickc@redhat.com>
PR binutils/17512

View File

@ -2423,6 +2423,20 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
}
else
{
/* If a plugin symbol is referenced from a non-IR file, mark
the symbol as undefined, except for symbol for linker
created section. */
if (h->root.non_ir_ref
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& (h->root.u.def.section->flags & SEC_LINKER_CREATED) == 0
&& h->root.u.def.section->owner != NULL
&& (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0)
{
h->root.type = bfd_link_hash_undefined;
h->root.u.undef.abfd = h->root.u.def.section->owner;
}
/* Unfortunately, NON_ELF is only correct if the symbol
was first seen in a non-ELF file. Fortunately, if the symbol
was first seen in an ELF file, we're probably OK unless the

View File

@ -1,3 +1,14 @@
2015-02-03 H.J. Lu <hongjiu.lu@intel.com>
PR ld/12365
* ld-plugin/pr12365a.c: New file.
* ld-plugin/pr12365b.c: Likewise.
* ld-plugin/pr12365c.c: Likewise.
* ld-plugin/lto.exp (lto_link_tests): Prepare for the PR ld/12365
test.
Run the PR ld/12365 test.
2015-02-03 H.J. Lu <hongjiu.lu@intel.com>
PR ld/14918

View File

@ -88,6 +88,9 @@ set lto_link_tests [list \
[list "LTO 6" \
"-O2 -flto -fuse-linker-plugin" "" \
{lto-6.c} {} "lto-6.exe" "c"] \
[list "Compile PR ld/12365" \
"" "-flto -O2 $lto_fat" \
{pr12365a.c pr12365b.c pr12365c.c} {} ""] \
[list "Compile 9" \
"" "-O2 -finline -flto" \
{lto-9.cc} {} "" "c++"] \
@ -380,6 +383,13 @@ if {![string match "" $catch_output]} {
if { [at_least_gcc_version 4 7] } {
# Check expected LTO linker errors.
set testname "PR ld/12365"
set exec_output [run_host_cmd "$CC" "-O2 -flto -fuse-linker-plugin tmpdir/pr12365a.o tmpdir/pr12365b.o tmpdir/pr12365c.o"]
if { [ regexp "undefined reference to `my_bcopy'" $exec_output ] } {
pass $testname
} {
fail $testname
}
set testname "PR ld/12942 (3)"
set exec_output [run_host_cmd "$CXX" "-O2 -flto -fuse-linker-plugin tmpdir/pr12942b.o tmpdir/pr12942a.o"]
if { [ regexp "undefined reference to `link_error\\(\\)'" $exec_output ] } {

View File

@ -0,0 +1,25 @@
extern void abort(void);
extern void main_test (void);
extern void abort (void);
int inside_main;
int
main ()
{
inside_main = 1;
main_test ();
inside_main = 0;
return 0;
}
/* When optimizing, all the constant cases should have been
constant folded, so no calls to link_error should remain.
In any case, link_error should not be called. */
#ifndef __OPTIMIZE__
void
link_error (void)
{
abort ();
}
#endif

View File

@ -0,0 +1,47 @@
#define ASMNAME(cname) ASMNAME2 (__USER_LABEL_PREFIX__, cname)
#define ASMNAME2(prefix, cname) STRING (prefix) cname
#define STRING(x) #x
typedef __SIZE_TYPE__ size_t;
extern void abort (void);
extern void *memcpy (void *, const void *, size_t)
__asm (ASMNAME ("my_memcpy"));
extern void bcopy (const void *, void *, size_t)
__asm (ASMNAME ("my_bcopy"));
extern void *memset (void *, int, size_t)
__asm (ASMNAME ("my_memset"));
extern void bzero (void *, size_t)
__asm (ASMNAME ("my_bzero"));
extern int memcmp (const void *, const void *, size_t);
struct A { char c[32]; } a = { "foobar" };
char x[64] = "foobar", y[64];
int i = 39, j = 6, k = 4;
extern int inside_main;
void
main_test (void)
{
struct A b = a;
struct A c = { { 'x' } };
inside_main = 1;
if (memcmp (b.c, x, 32) || c.c[0] != 'x' || memcmp (c.c + 1, x + 32, 31))
abort ();
if (__builtin_memcpy (y, x, i) != y || memcmp (x, y, 64))
abort ();
if (memcpy (y + 6, x, j) != y + 6
|| memcmp (x, y, 6) || memcmp (x, y + 6, 58))
abort ();
if (__builtin_memset (y + 2, 'X', k) != y + 2
|| memcmp (y, "foXXXXfoobar", 13))
abort ();
bcopy (y + 1, y + 2, 6);
if (memcmp (y, "fooXXXXfobar", 13))
abort ();
__builtin_bzero (y + 4, 2);
if (memcmp (y, "fooX\0\0Xfobar", 13))
abort ();
}

View File

@ -0,0 +1,79 @@
extern void abort (void);
extern int inside_main;
typedef __SIZE_TYPE__ size_t;
#define TEST_ABORT if (inside_main) abort()
void *
my_memcpy (void *d, const void *s, size_t n)
{
char *dst = (char *) d;
const char *src = (const char *) s;
while (n--)
*dst++ = *src++;
return (char *) d;
}
void
my_bcopy (const void *s, void *d, size_t n)
{
char *dst = (char *) d;
const char *src = (const char *) s;
if (src >= dst)
while (n--)
*dst++ = *src++;
else
{
dst += n;
src += n;
while (n--)
*--dst = *--src;
}
}
void *
my_memset (void *d, int c, size_t n)
{
char *dst = (char *) d;
while (n--)
*dst++ = c;
return (char *) d;
}
void
my_bzero (void *d, size_t n)
{
char *dst = (char *) d;
while (n--)
*dst++ = '\0';
}
void *
memcpy (void *d, const void *s, size_t n)
{
void *result = my_memcpy (d, s, n);
TEST_ABORT;
return result;
}
void
bcopy (const void *s, void *d, size_t n)
{
my_bcopy (s, d, n);
TEST_ABORT;
}
void *
memset (void *d, int c, size_t n)
{
void *result = my_memset (d, c, n);
TEST_ABORT;
return result;
}
void
bzero (void *d, size_t n)
{
my_bzero (d, n);
TEST_ABORT;
}