summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@bigpond.net.au>2011-04-27 07:17:34 +0000
committerAlan Modra <amodra@bigpond.net.au>2011-04-27 07:17:34 +0000
commit018b4aad88122833245fd59b389a7905e93ad63b (patch)
tree531107b19fae7cabb62ad1ec65b4c28a5d241862
parent3c1b2063230735bf199c001a4f5f2e92ffae63e7 (diff)
downloadbinutils-redhat-018b4aad88122833245fd59b389a7905e93ad63b.tar.gz
PR ld/12696
PR ld/12672 PR ld/12507 PR ld/12365 PR 10549 Backport fixes for these PRs.
-rw-r--r--bfd/ChangeLog58
-rw-r--r--bfd/bfd-in2.h7
-rw-r--r--bfd/bfd.c7
-rw-r--r--bfd/coff-aux.c2
-rw-r--r--bfd/elf-bfd.h6
-rw-r--r--bfd/elf.c5
-rw-r--r--bfd/elf32-i386.c5
-rw-r--r--bfd/elf32-ppc.c5
-rw-r--r--bfd/elf32-sparc.c5
-rw-r--r--bfd/elf64-ppc.c6
-rw-r--r--bfd/elf64-sparc.c5
-rw-r--r--bfd/elf64-x86-64.c5
-rw-r--r--bfd/elfcode.h14
-rw-r--r--bfd/elflink.c43
-rw-r--r--bfd/linker.c88
-rw-r--r--bfd/opncls.c2
-rw-r--r--bfd/plugin.c22
-rw-r--r--bfd/simple.c5
-rw-r--r--bfd/xcofflink.c10
-rw-r--r--gas/testsuite/ChangeLog8
-rw-r--r--gas/testsuite/gas/elf/elf.exp1
-rw-r--r--gas/testsuite/gas/elf/section9.d7
-rw-r--r--gas/testsuite/gas/elf/section9.s4
-rw-r--r--include/ChangeLog23
-rw-r--r--include/bfdlink.h37
-rw-r--r--ld/ChangeLog137
-rw-r--r--ld/ld.texinfo9
-rw-r--r--ld/ldfile.c28
-rw-r--r--ld/ldlang.c175
-rw-r--r--ld/ldlang.h5
-rw-r--r--ld/ldmain.c147
-rw-r--r--ld/lexsup.c21
-rw-r--r--ld/plugin.c320
-rw-r--r--ld/plugin.h21
-rw-r--r--ld/testsuite/ChangeLog26
-rw-r--r--ld/testsuite/ld-plugin/plugin-12.d6
-rw-r--r--ld/testsuite/ld-plugin/plugin-7.d1
-rw-r--r--ld/testsuite/ld-plugin/plugin-8.d1
-rw-r--r--ld/testsuite/ld-plugin/plugin.exp6
-rw-r--r--ld/testsuite/ld-unique/unique.exp249
-rw-r--r--ld/testsuite/ld-unique/unique.s8
-rw-r--r--ld/testsuite/ld-unique/unique_empty.s4
-rw-r--r--ld/testsuite/ld-unique/unique_shared.s3
43 files changed, 1134 insertions, 413 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 6e8c81c780..b36b15b686 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,61 @@
+2011-04-27 Alan Modra <amodra@gmail.com>
+
+ Backport from mainline
+ 2011-04-24 Alan Modra <amodra@gmail.com>
+ PR ld/12365
+ PR ld/12696
+ * coff-aux.c (coff_m68k_aux_link_add_one_symbol): Update "notice" call.
+ * linker.c (_bfd_link_hash_newfunc): Clear bitfields.
+ (_bfd_generic_link_add_one_symbol): Update "notice" call.
+ * elflink.c (_bfd_elf_merge_symbol): Don't skip weak redefs when
+ it is a redef of an IR symbol in a real BFD.
+
+ 2011-04-20 Alan Modra <amodra@gmail.com>
+ PR ld/12365
+ * elfcode.h (elf_slurp_symbol_table): Put common plugin IR symbols
+ in their own common section.
+ * elflink.c (elf_link_add_object_symbols): Likewise.
+ * linker.c (generic_link_check_archive_element): Don't lose flags
+ if common section is pre-existing.
+ (_bfd_generic_link_add_one_symbol): Likewise.
+
+ 2011-04-20 Alan Modra <amodra@gmail.com>
+ PR ld/12365
+ * elflink.c (_bfd_elf_merge_symbol): Update multiple_common calls.
+ * linker.c (_bfd_generic_link_add_one_symbol): Likewise. Call
+ multiple_definition regardless of allow_multiple_definition.
+ * simple.c (simple_dummy_multiple_definition): Update.
+ * xcofflink.c (xcoff_link_add_symbols): Update multiple_definition
+ calls.
+
+ 2011-04-18 Alan Modra <amodra@gmail.com>
+ PR ld/12365
+ PR ld/12672
+ * bfd.c (BFD_PLUGIN): Define.
+ (BFD_FLAGS_SAVED, BFD_FLAGS_FOR_BFD_USE_MASK): Add BFD_PLUGIN.
+ * bfd-in2.h: Regenerate.
+ * elflink.c (elf_link_output_extsym): Strip undefined plugin syms.
+ * opncls.c (bfd_make_readable): Don't lose original bfd flags.
+
+ 2011-04-11 Mark Wielaard <mjw@redhat.com>
+ PR 10549
+ * elf-bfd.h (has_ifunc_symbols): Renamed to has_gnu_symbols.
+ (has_gnu_symbols): Renamed from has_ifunc_symbols.
+ * elf.c (_bfd_elf_set_osabi): Use new has_gnu_symbols name.
+ * elf32-i386.c (elf_i386_add_symbol_hook): Likewise.
+ * elf32-ppc.c (ppc_elf_add_symbol_hook): Likewise.
+ * elf32-sparc.c (elf32_sparc_add_symbol_hook): Likewise.
+ * elf64-ppc.c (ppc64_elf_add_symbol_hook): Likewise.
+ * elf64-sparc.c (elf64_sparc_add_symbol_hook): Likewise.
+ * elf64-x86-64.c (elf_x86_64_add_symbol_hook): Likewise.
+
+ 2011-02-25 Rafael Ávila de Espíndola <respindola@mozilla.com>
+ * plugin.c (bfd_plugin_object_p): Correctly set the filesize
+ and handle claim_file seeking. Only try to load the plugin once.
+
+ 2010-12-12 H.J. Lu <hongjiu.lu@intel.com>
+ * elf.c (special_sections_g): Add ".gnu.lto_".
+
2011-04-20 Jan Kratochvil <jan.kratochvil@redhat.com>
* elf-bfd.h (RELOC_AGAINST_DISCARDED_SECTION): Fix +1 overrun of
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index f3e2b45791..0907784a40 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5084,14 +5084,17 @@ struct bfd
/* Decompress sections in this BFD. */
#define BFD_DECOMPRESS 0x10000
+ /* BFD is a dummy, for plugins. */
+#define BFD_PLUGIN 0x20000
+
/* Flags bits to be saved in bfd_preserve_save. */
#define BFD_FLAGS_SAVED \
- (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS)
+ (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN)
/* Flags bits which are for BFD use only. */
#define BFD_FLAGS_FOR_BFD_USE_MASK \
(BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
- | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT)
+ | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT)
/* Currently my_archive is tested before adding origin to
anything. I believe that this can become always an add of
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 77582ec82f..c729d63170 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -157,14 +157,17 @@ CODE_FRAGMENT
. {* Decompress sections in this BFD. *}
.#define BFD_DECOMPRESS 0x10000
.
+. {* BFD is a dummy, for plugins. *}
+.#define BFD_PLUGIN 0x20000
+.
. {* Flags bits to be saved in bfd_preserve_save. *}
.#define BFD_FLAGS_SAVED \
-. (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS)
+. (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN)
.
. {* Flags bits which are for BFD use only. *}
.#define BFD_FLAGS_FOR_BFD_USE_MASK \
. (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
-. | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT)
+. | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT)
.
. {* Currently my_archive is tested before adding origin to
. anything. I believe that this can become always an add of
diff --git a/bfd/coff-aux.c b/bfd/coff-aux.c
index af1db03836..052892445b 100644
--- a/bfd/coff-aux.c
+++ b/bfd/coff-aux.c
@@ -105,7 +105,7 @@ coff_m68k_aux_link_add_one_symbol (info, abfd, name, flags, section, value,
&& (bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE)
!= (struct bfd_hash_entry *) NULL))
{
- if (! (*info->callbacks->notice) (info, name, abfd, section, value))
+ if (! (*info->callbacks->notice) (info, h, abfd, section, value))
return FALSE;
}
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 73806dd911..0c5b0cbd34 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1631,9 +1631,9 @@ struct elf_obj_tdata
bfd_byte *build_id;
/* True if the bfd contains symbols that have the STT_GNU_IFUNC
- symbol type. Used to set the osabi field in the ELF header
- structure. */
- bfd_boolean has_ifunc_symbols;
+ symbol type or STB_GNU_UNIQUE binding. Used to set the osabi
+ field in the ELF header structure. */
+ bfd_boolean has_gnu_symbols;
/* An identifier used to distinguish different target
specific extensions to this structure. */
diff --git a/bfd/elf.c b/bfd/elf.c
index f54448659f..c0ffbd078b 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -2082,6 +2082,7 @@ static const struct bfd_elf_special_section special_sections_f[] =
static const struct bfd_elf_special_section special_sections_g[] =
{
{ STRING_COMMA_LEN (".gnu.linkonce.b"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".gnu.lto_"), -1, SHT_PROGBITS, SHF_EXCLUDE },
{ STRING_COMMA_LEN (".got"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".gnu.version"), 0, SHT_GNU_versym, 0 },
{ STRING_COMMA_LEN (".gnu.version_d"), 0, SHT_GNU_verdef, 0 },
@@ -9480,9 +9481,9 @@ _bfd_elf_set_osabi (bfd * abfd,
/* To make things simpler for the loader on Linux systems we set the
osabi field to ELFOSABI_LINUX if the binary contains symbols of
- the STT_GNU_IFUNC type. */
+ the STT_GNU_IFUNC type or STB_GNU_UNIQUE binding. */
if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE
- && elf_tdata (abfd)->has_ifunc_symbols)
+ && elf_tdata (abfd)->has_gnu_symbols)
i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_LINUX;
}
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index ae749c6b4e..1071f015d0 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -4695,8 +4695,9 @@ elf_i386_add_symbol_hook (bfd * abfd,
bfd_vma * valp ATTRIBUTE_UNUSED)
{
if ((abfd->flags & DYNAMIC) == 0
- && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
- elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+ && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+ || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
return TRUE;
}
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 9e097ad624..c7363753d4 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -3113,8 +3113,9 @@ ppc_elf_add_symbol_hook (bfd *abfd,
}
if ((abfd->flags & DYNAMIC) == 0
- && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
- elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+ && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+ || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
return TRUE;
}
diff --git a/bfd/elf32-sparc.c b/bfd/elf32-sparc.c
index 187d46698d..2d9deabb60 100644
--- a/bfd/elf32-sparc.c
+++ b/bfd/elf32-sparc.c
@@ -180,8 +180,9 @@ elf32_sparc_add_symbol_hook (bfd * abfd,
bfd_vma * valp ATTRIBUTE_UNUSED)
{
if ((abfd->flags & DYNAMIC) == 0
- && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
- elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+ && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+ || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
return TRUE;
}
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 4cbd941baa..eb07b1fb7c 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -4569,10 +4569,14 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
asection **sec,
bfd_vma *value ATTRIBUTE_UNUSED)
{
+ if ((ibfd->flags & DYNAMIC) == 0
+ && ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE)
+ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{
if ((ibfd->flags & DYNAMIC) == 0)
- elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
}
else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC)
;
diff --git a/bfd/elf64-sparc.c b/bfd/elf64-sparc.c
index 9f05b85fa5..4d093984b5 100644
--- a/bfd/elf64-sparc.c
+++ b/bfd/elf64-sparc.c
@@ -426,8 +426,9 @@ elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
static const char *const stt_types[] = { "NOTYPE", "OBJECT", "FUNCTION" };
if ((abfd->flags & DYNAMIC) == 0
- && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
- elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+ && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+ || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
if (ELF_ST_TYPE (sym->st_info) == STT_REGISTER)
{
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 83656aead1..09af249dfe 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -4303,8 +4303,9 @@ elf64_x86_64_add_symbol_hook (bfd *abfd,
}
if ((abfd->flags & DYNAMIC) == 0
- && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
- elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+ && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+ || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
return TRUE;
}
diff --git a/bfd/elfcode.h b/bfd/elfcode.h
index 5ef461018d..29cd22845e 100644
--- a/bfd/elfcode.h
+++ b/bfd/elfcode.h
@@ -1281,6 +1281,20 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
else if (isym->st_shndx == SHN_COMMON)
{
sym->symbol.section = bfd_com_section_ptr;
+ if ((abfd->flags & BFD_PLUGIN) != 0)
+ {
+ asection *xc = bfd_get_section_by_name (abfd, "COMMON");
+
+ if (xc == NULL)
+ {
+ flagword flags = (SEC_ALLOC | SEC_IS_COMMON | SEC_KEEP
+ | SEC_EXCLUDE);
+ xc = bfd_make_section_with_flags (abfd, "COMMON", flags);
+ if (xc == NULL)
+ goto error_return;
+ }
+ sym->symbol.section = xc;
+ }
/* Elf puts the alignment into the `value' field, and
the size into the `size' field. BFD wants to see the
size in the value field, and doesn't care (at the
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 6136a94cfd..5a9d457d38 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -1361,8 +1361,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
symbols defined in dynamic objects. */
if (! ((*info->callbacks->multiple_common)
- (info, h->root.root.string, oldbfd, bfd_link_hash_common,
- h->size, abfd, bfd_link_hash_common, sym->st_size)))
+ (info, &h->root, abfd, bfd_link_hash_common, sym->st_size)))
return FALSE;
if (sym->st_size > h->size)
@@ -1428,7 +1427,10 @@ _bfd_elf_merge_symbol (bfd *abfd,
/* Skip weak definitions of symbols that are already defined. */
if (newdef && olddef && newweak)
{
- *skip = TRUE;
+ /* Don't skip new non-IR weak syms. */
+ if (!((oldbfd->flags & BFD_PLUGIN) != 0
+ && (abfd->flags & BFD_PLUGIN) == 0))
+ *skip = TRUE;
/* Merge st_other. If the symbol already has a dynamic index,
but visibility says it should not be visible, turn it into a
@@ -1513,8 +1515,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
common symbol, but we don't know what to use for the section
or the alignment. */
if (! ((*info->callbacks->multiple_common)
- (info, h->root.root.string, oldbfd, bfd_link_hash_common,
- h->size, abfd, bfd_link_hash_common, sym->st_size)))
+ (info, &h->root, abfd, bfd_link_hash_common, sym->st_size)))
return FALSE;
/* If the presumed common symbol in the dynamic object is
@@ -3939,18 +3940,31 @@ error_free_dyn:
goto error_free_vers;
if (isym->st_shndx == SHN_COMMON
- && ELF_ST_TYPE (isym->st_info) == STT_TLS
- && !info->relocatable)
+ && (abfd->flags & BFD_PLUGIN) != 0)
+ {
+ asection *xc = bfd_get_section_by_name (abfd, "COMMON");
+
+ if (xc == NULL)
+ {
+ flagword sflags = (SEC_ALLOC | SEC_IS_COMMON | SEC_KEEP
+ | SEC_EXCLUDE);
+ xc = bfd_make_section_with_flags (abfd, "COMMON", sflags);
+ if (xc == NULL)
+ goto error_free_vers;
+ }
+ sec = xc;
+ }
+ else if (isym->st_shndx == SHN_COMMON
+ && ELF_ST_TYPE (isym->st_info) == STT_TLS
+ && !info->relocatable)
{
asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon");
if (tcomm == NULL)
{
- tcomm = bfd_make_section_with_flags (abfd, ".tcommon",
- (SEC_ALLOC
- | SEC_IS_COMMON
- | SEC_LINKER_CREATED
- | SEC_THREAD_LOCAL));
+ flagword sflags = (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_IS_COMMON
+ | SEC_LINKER_CREATED);
+ tcomm = bfd_make_section_with_flags (abfd, ".tcommon", sflags);
if (tcomm == NULL)
goto error_free_vers;
}
@@ -8699,6 +8713,11 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
|| h->root.type == bfd_link_hash_defweak)
&& elf_discarded_section (h->root.u.def.section))
strip = TRUE;
+ else if ((h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak)
+ && h->root.u.undef.abfd != NULL
+ && (h->root.u.undef.abfd->flags & BFD_PLUGIN) != 0)
+ strip = TRUE;
else
strip = FALSE;
diff --git a/bfd/linker.c b/bfd/linker.c
index 2b52ba9651..1f02cbab54 100644
--- a/bfd/linker.c
+++ b/bfd/linker.c
@@ -465,10 +465,8 @@ _bfd_link_hash_newfunc (struct bfd_hash_entry *entry,
struct bfd_link_hash_entry *h = (struct bfd_link_hash_entry *) entry;
/* Initialize the local fields. */
- h->type = bfd_link_hash_new;
- memset (&h->u.undef.next, 0,
- (sizeof (struct bfd_link_hash_entry)
- - offsetof (struct bfd_link_hash_entry, u.undef.next)));
+ memset ((char *) &h->root + sizeof (h->root), 0,
+ sizeof (*h) - sizeof (h->root));
}
return entry;
@@ -1296,7 +1294,7 @@ generic_link_check_archive_element (bfd *abfd,
else
h->u.c.p->section = bfd_make_section_old_way (symbfd,
p->section->name);
- h->u.c.p->section->flags = SEC_ALLOC;
+ h->u.c.p->section->flags |= SEC_ALLOC;
}
else
{
@@ -1609,8 +1607,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
|| (info->notice_hash != NULL
&& bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL))
{
- if (! (*info->callbacks->notice) (info, h->root.string, abfd, section,
- value))
+ if (! (*info->callbacks->notice) (info, h, abfd, section, value))
return FALSE;
}
@@ -1651,9 +1648,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
previously common. */
BFD_ASSERT (h->type == bfd_link_hash_common);
if (! ((*info->callbacks->multiple_common)
- (info, h->root.string,
- h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size,
- abfd, bfd_link_hash_defined, 0)))
+ (info, h, abfd, bfd_link_hash_defined, 0)))
return FALSE;
/* Fall through. */
case DEF:
@@ -1758,13 +1753,13 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
if (section == bfd_com_section_ptr)
{
h->u.c.p->section = bfd_make_section_old_way (abfd, "COMMON");
- h->u.c.p->section->flags = SEC_ALLOC;
+ h->u.c.p->section->flags |= SEC_ALLOC;
}
else if (section->owner != abfd)
{
h->u.c.p->section = bfd_make_section_old_way (abfd,
section->name);
- h->u.c.p->section->flags = SEC_ALLOC;
+ h->u.c.p->section->flags |= SEC_ALLOC;
}
else
h->u.c.p->section = section;
@@ -1782,9 +1777,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
two sizes, and use the section required by the larger symbol. */
BFD_ASSERT (h->type == bfd_link_hash_common);
if (! ((*info->callbacks->multiple_common)
- (info, h->root.string,
- h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size,
- abfd, bfd_link_hash_common, value)))
+ (info, h, abfd, bfd_link_hash_common, value)))
return FALSE;
if (value > h->u.c.size)
{
@@ -1807,13 +1800,13 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
{
h->u.c.p->section
= bfd_make_section_old_way (abfd, "COMMON");
- h->u.c.p->section->flags = SEC_ALLOC;
+ h->u.c.p->section->flags |= SEC_ALLOC;
}
else if (section->owner != abfd)
{
h->u.c.p->section
= bfd_make_section_old_way (abfd, section->name);
- h->u.c.p->section->flags = SEC_ALLOC;
+ h->u.c.p->section->flags |= SEC_ALLOC;
}
else
h->u.c.p->section = section;
@@ -1821,23 +1814,11 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
break;
case CREF:
- {
- bfd *obfd;
-
- /* We have found a common definition for a symbol which
- was already defined. FIXME: It would nice if we could
- report the BFD which defined an indirect symbol, but we
- don't have anywhere to store the information. */
- if (h->type == bfd_link_hash_defined
- || h->type == bfd_link_hash_defweak)
- obfd = h->u.def.section->owner;
- else
- obfd = NULL;
- if (! ((*info->callbacks->multiple_common)
- (info, h->root.string, obfd, h->type, 0,
- abfd, bfd_link_hash_common, value)))
- return FALSE;
- }
+ /* We have found a common definition for a symbol which
+ was already defined. */
+ if (! ((*info->callbacks->multiple_common)
+ (info, h, abfd, bfd_link_hash_common, value)))
+ return FALSE;
break;
case MIND:
@@ -1848,47 +1829,16 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
/* Fall through. */
case MDEF:
/* Handle a multiple definition. */
- if (!info->allow_multiple_definition)
- {
- asection *msec = NULL;
- bfd_vma mval = 0;
-
- switch (h->type)
- {
- case bfd_link_hash_defined:
- msec = h->u.def.section;
- mval = h->u.def.value;
- break;
- case bfd_link_hash_indirect:
- msec = bfd_ind_section_ptr;
- mval = 0;
- break;
- default:
- abort ();
- }
-
- /* Ignore a redefinition of an absolute symbol to the
- same value; it's harmless. */
- if (h->type == bfd_link_hash_defined
- && bfd_is_abs_section (msec)
- && bfd_is_abs_section (section)
- && value == mval)
- break;
-
- if (! ((*info->callbacks->multiple_definition)
- (info, h->root.string, msec->owner, msec, mval,
- abfd, section, value)))
- return FALSE;
- }
+ if (! ((*info->callbacks->multiple_definition)
+ (info, h, abfd, section, value)))
+ return FALSE;
break;
case CIND:
/* Create an indirect symbol from an existing common symbol. */
BFD_ASSERT (h->type == bfd_link_hash_common);
if (! ((*info->callbacks->multiple_common)
- (info, h->root.string,
- h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size,
- abfd, bfd_link_hash_indirect, 0)))
+ (info, h, abfd, bfd_link_hash_indirect, 0)))
return FALSE;
/* Fall through. */
case IND:
diff --git a/bfd/opncls.c b/bfd/opncls.c
index 3597daee01..40432000c0 100644
--- a/bfd/opncls.c
+++ b/bfd/opncls.c
@@ -875,7 +875,7 @@ bfd_make_readable (bfd *abfd)
abfd->section_count = 0;
abfd->usrdata = NULL;
abfd->cacheable = FALSE;
- abfd->flags = BFD_IN_MEMORY;
+ abfd->flags |= BFD_IN_MEMORY;
abfd->mtime_set = FALSE;
abfd->target_defaulted = TRUE;
diff --git a/bfd/plugin.c b/bfd/plugin.c
index 61cd687336..bc36f1fac7 100644
--- a/bfd/plugin.c
+++ b/bfd/plugin.c
@@ -232,11 +232,17 @@ static const bfd_target *
bfd_plugin_object_p (bfd *abfd)
{
int claimed = 0;
- int t = load_plugin ();
struct ld_plugin_input_file file;
bfd *iobfd;
+ static int have_loaded = 0;
+ static int have_plugin = 0;
- if (!t)
+ if (!have_loaded)
+ {
+ have_loaded = 1;
+ have_plugin = load_plugin ();
+ }
+ if (!have_plugin)
return NULL;
file.name = abfd->filename;
@@ -251,7 +257,7 @@ bfd_plugin_object_p (bfd *abfd)
{
iobfd = abfd;
file.offset = 0;
- file.filesize = 0; /*FIXME*/
+ file.filesize = 0;
}
if (!iobfd->iostream && !bfd_open_file (iobfd))
@@ -259,8 +265,18 @@ bfd_plugin_object_p (bfd *abfd)
file.fd = fileno ((FILE *) iobfd->iostream);
+ if (!abfd->my_archive)
+ {
+ struct stat stat_buf;
+ if (fstat (file.fd, &stat_buf))
+ return NULL;
+ file.filesize = stat_buf.st_size;
+ }
+
file.handle = abfd;
+ off_t cur_offset = lseek(file.fd, 0, SEEK_CUR);
claim_file (&file, &claimed);
+ lseek(file.fd, cur_offset, SEEK_SET);
if (!claimed)
return NULL;
diff --git a/bfd/simple.c b/bfd/simple.c
index 03d1a15885..1f4d72d8f3 100644
--- a/bfd/simple.c
+++ b/bfd/simple.c
@@ -82,10 +82,7 @@ simple_dummy_unattached_reloc (struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
static bfd_boolean
simple_dummy_multiple_definition (struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
- const char *name ATTRIBUTE_UNUSED,
- bfd *obfd ATTRIBUTE_UNUSED,
- asection *osec ATTRIBUTE_UNUSED,
- bfd_vma oval ATTRIBUTE_UNUSED,
+ struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED,
bfd *nbfd ATTRIBUTE_UNUSED,
asection *nsec ATTRIBUTE_UNUSED,
bfd_vma nval ATTRIBUTE_UNUSED)
diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index d3e9043dc3..ad2f4cd4b0 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -1996,11 +1996,7 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
handle them, and that would only be a warning,
not an error. */
if (! ((*info->callbacks->multiple_definition)
- (info, (*sym_hash)->root.root.string,
- NULL, NULL, (bfd_vma) 0,
- (*sym_hash)->root.u.def.section->owner,
- (*sym_hash)->root.u.def.section,
- (*sym_hash)->root.u.def.value)))
+ (info, &(*sym_hash)->root, NULL, NULL, (bfd_vma) 0)))
goto error_return;
/* Try not to give this error too many times. */
(*sym_hash)->flags &= ~XCOFF_MULTIPLY_DEFINED;
@@ -3119,9 +3115,7 @@ bfd_xcoff_import_symbol (bfd *output_bfd,
|| h->root.u.def.value != val))
{
if (! ((*info->callbacks->multiple_definition)
- (info, h->root.root.string, h->root.u.def.section->owner,
- h->root.u.def.section, h->root.u.def.value,
- output_bfd, bfd_abs_section_ptr, val)))
+ (info, &h->root, output_bfd, bfd_abs_section_ptr, val)))
return FALSE;
}
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index 06bf4453b3..be59223771 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2011-04-27 Alan Modra <amodra@gmail.com>
+
+ Apply from mainline.
+ 2010-12-12 H.J. Lu <hongjiu.lu@intel.com>
+ * gas/elf/elf.exp: Run section9.
+ * gas/elf/section9.d: New.
+ * gas/elf/section9.s: Likewise.
+
2011-02-10 Vincent Rivière <vincent.riviere@freesbee.fr>
PR gas/6957
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index 3babe0b1cb..7f86266e11 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -174,6 +174,7 @@ if { ([istarget "*-*-*elf*"]
run_dump_test "section6"
run_dump_test "section7"
run_dump_test "section8"
+ run_dump_test "section9"
run_dump_test "dwarf2-1"
run_dump_test "dwarf2-2"
run_dump_test "dwarf2-3"
diff --git a/gas/testsuite/gas/elf/section9.d b/gas/testsuite/gas/elf/section9.d
new file mode 100644
index 0000000000..1acf63e819
--- /dev/null
+++ b/gas/testsuite/gas/elf/section9.d
@@ -0,0 +1,7 @@
+#readelf: -S --wide
+#name: section flags
+
+#...
+[ ]*\[.*\][ ]+\.gnu\.lto_main[ ]+PROGBITS.*[ ]+E[ ]+.*
+[ ]*\[.*\][ ]+\.gnu\.lto_\.pureconst[ ]+PROGBITS.*[ ]+E[ ]+.*
+#pass
diff --git a/gas/testsuite/gas/elf/section9.s b/gas/testsuite/gas/elf/section9.s
new file mode 100644
index 0000000000..6b8b1074ca
--- /dev/null
+++ b/gas/testsuite/gas/elf/section9.s
@@ -0,0 +1,4 @@
+ .section .gnu.lto_main,"",%progbits
+ .byte 0,0,0,0
+ .section .gnu.lto_.pureconst,"",%progbits
+ .byte 0,0,0,0
diff --git a/include/ChangeLog b/include/ChangeLog
index aa8e29e4a4..684e7b5d99 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,20 @@
+2011-04-27 Alan Modra <amodra@gmail.com>
+
+ Backport from mainline.
+ 2011-04-24 Alan Modra <amodra@gmail.com>
+ PR ld/12365
+ PR ld/12696
+ * bfdlink.h (ENUM_BITFIELD): Define.
+ (struct bfd_link_hash_entry): Make "type" a bitfield. Add "non_ir_ref".
+ (struct bfd_link_callbacks <notice>): Pass bfd_link_hash_entry pointer
+ rather than "name".
+
+ 2011-04-20 Alan Modra <amodra@gmail.com>
+ PR ld/12365
+ * bfdlink.h (struct bfd_link_callbacks): Modify multiple_definition
+ and multiple_common parameters to pass in a bfd_link_hash_entry
+ pointer rather than name,bfd etc. found in the hash entry.
+
2010-11-25 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
* opcode/s390.h (enum s390_opcode_cpu_val): Add S390_OPCODE_MAXCPU.
@@ -6,19 +23,19 @@
* simple-object.h: New file.
-2010-10-15 Dave Korn <dave.korn.cygwin@gmail.com>
+2010-10-15 Dave Korn <dave.korn.cygwin@gmail.com>
Sync LD plugin patch series (part 1/6) with src/include/.
* plugin-api.h (LDPT_GNU_LD_VERSION): New ld_plugin_tag enum member.
-2010-10-14 Dave Korn <dave.korn.cygwin@gmail.com>
+2010-10-14 Dave Korn <dave.korn.cygwin@gmail.com>
Apply LD plugin patch series (part 6/6).
* bfdlink.h (struct_bfd_link_callbacks): Document new argument
to add_archive_element callback used to return a replacement bfd which
is to be added to the hash table in place of the original element.
-2010-10-14 Dave Korn <dave.korn.cygwin@gmail.com>
+2010-10-14 Dave Korn <dave.korn.cygwin@gmail.com>
Apply LD plugin patch series (part 1/6).
* plugin-api.h (LDPT_GNU_LD_VERSION): New ld_plugin_tag enum member.
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 0d6e9f8aeb..66f76455b1 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -23,6 +23,12 @@
#ifndef BFDLINK_H
#define BFDLINK_H
+#if (__GNUC__ * 1000 + __GNUC_MINOR__ > 2000)
+#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE
+#else
+#define ENUM_BITFIELD(TYPE) unsigned int
+#endif
+
/* Which symbols to strip during a link. */
enum bfd_link_strip
{
@@ -90,7 +96,9 @@ struct bfd_link_hash_entry
struct bfd_hash_entry root;
/* Type of this entry. */
- enum bfd_link_hash_type type;
+ ENUM_BITFIELD (bfd_link_hash_type) type : 8;
+
+ unsigned int non_ir_ref : 1;
/* A union of information depending upon the type. */
union
@@ -487,29 +495,20 @@ struct bfd_link_callbacks
bfd_boolean (*add_archive_element)
(struct bfd_link_info *, bfd *abfd, const char *name, bfd **subsbfd);
/* A function which is called when a symbol is found with multiple
- definitions. NAME is the symbol which is defined multiple times.
- OBFD is the old BFD, OSEC is the old section, OVAL is the old
- value, NBFD is the new BFD, NSEC is the new section, and NVAL is
- the new value. OBFD may be NULL. OSEC and NSEC may be
- bfd_com_section or bfd_ind_section. */
+ definitions. H is the symbol which is defined multiple times.
+ NBFD is the new BFD, NSEC is the new section, and NVAL is the new
+ value. NSEC may be bfd_com_section or bfd_ind_section. */
bfd_boolean (*multiple_definition)
- (struct bfd_link_info *, const char *name,
- bfd *obfd, asection *osec, bfd_vma oval,
+ (struct bfd_link_info *, struct bfd_link_hash_entry *h,
bfd *nbfd, asection *nsec, bfd_vma nval);
/* A function which is called when a common symbol is defined
- multiple times. NAME is the symbol appearing multiple times.
- OBFD is the BFD of the existing symbol; it may be NULL if this is
- not known. OTYPE is the type of the existing symbol, which may
- be bfd_link_hash_defined, bfd_link_hash_defweak,
- bfd_link_hash_common, or bfd_link_hash_indirect. If OTYPE is
- bfd_link_hash_common, OSIZE is the size of the existing symbol.
+ multiple times. H is the symbol appearing multiple times.
NBFD is the BFD of the new symbol. NTYPE is the type of the new
symbol, one of bfd_link_hash_defined, bfd_link_hash_common, or
bfd_link_hash_indirect. If NTYPE is bfd_link_hash_common, NSIZE
is the size of the new symbol. */
bfd_boolean (*multiple_common)
- (struct bfd_link_info *, const char *name,
- bfd *obfd, enum bfd_link_hash_type otype, bfd_vma osize,
+ (struct bfd_link_info *, struct bfd_link_hash_entry *h,
bfd *nbfd, enum bfd_link_hash_type ntype, bfd_vma nsize);
/* A function which is called to add a symbol to a set. ENTRY is
the link hash table entry for the set itself (e.g.,
@@ -578,11 +577,11 @@ struct bfd_link_callbacks
(struct bfd_link_info *, const char *name,
bfd *abfd, asection *section, bfd_vma address);
/* A function which is called when a symbol in notice_hash is
- defined or referenced. NAME is the symbol. ABFD, SECTION and
- ADDRESS are the value of the symbol. If SECTION is
+ defined or referenced. H is the symbol. ABFD, SECTION and
+ ADDRESS are the (new) value of the symbol. If SECTION is
bfd_und_section, this is a reference. */
bfd_boolean (*notice)
- (struct bfd_link_info *, const char *name,
+ (struct bfd_link_info *, struct bfd_link_hash_entry *h,
bfd *abfd, asection *section, bfd_vma address);
/* Error or warning link info message. */
void (*einfo)
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 2a1ede179d..c1218b5ac5 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,140 @@
+2011-04-27 Alan Modra <amodra@gmail.com>
+
+ Backport from mainline.
+ 2011-04-24 Alan Modra <amodra@gmail.com>
+ PR ld/12365
+ PR ld/12696
+ * ldmain.c (notice): Delete "name" param, add "h".
+ * plugin.c (plugin_notice): Likewise. Set non_ir_ref. Handle
+ redefinitions of IR symbols in real BFDs.
+ (plugin_multiple_definition, plugin_multiple_common): Delete.
+ (non_ironly_hash, init_non_ironly_hash): Delete.
+ (is_visible_from_outside): Traverse entry_symbol chain.
+ (get_symbols): Use non_ir_ref flag rather than hash lookup.
+
+ 2011-04-20 Alan Modra <amodra@gmail.com>
+ PR ld/12365
+ * ldfile.c (ldfile_try_open_bfd): Move code creating and switching
+ to plugin IR BFD..
+ * ldmain.c (add_archive_element): ..and similar code here..
+ * plugin.c (plugin_maybe_claim): ..to here. New function.
+ (plugin_call_claim_file): Make static.
+ (asymbol_from_plugin_symbol): Set ELF st_shndx for common syms.
+ (plugin_multiple_common): New function.
+ (plugin_call_all_symbols_read): Hook in plugin_multiple_common.
+ * plugin.h (plugin_call_claim_file): Don't declare.
+ (plugin_maybe_claim): Declare.
+
+ 2011-04-20 Alan Modra <amodra@gmail.com>
+ PR ld/12365
+ * ldmain.c (multiple_definition): Take a bfd_link_hash_entry
+ pointer arg rather than "name", "obfd", "osec", "oval". Add code
+ removed from linker.c. Hack around xcofflink.c oddity in
+ passing NULL nbfd.
+ (multiple_common): Similarly.
+ * plugin.c (orig_allow_multiple_defs): Delete.
+ (plugin_call_all_symbols_read): Don't twiddle allow_multiple_definition.
+ (plugin_multiple_definition): Update.
+
+ 2011-04-18 Alan Modra <amodra@gmail.com>
+ PR ld/12365
+ PR ld/12672
+ * ldfile.c (ldfile_try_open_bfd): Don't attempt any plugin action
+ when no_more_claiming.
+ * ldmain.c (add_archive_element): Likewise.
+ (multiple_definition): Remove plugin_multiple_definition call.
+ (notice): Remove plugin_notice call.
+ * ldlang.c (lang_list_insert_after, void lang_list_remove_tail): Move.
+ Delete prototype.
+ (plugin_insert): New static var.
+ (open_input_bfds): Only rescan libs after plugin insert point.
+ (lang_gc_sections): Omit plugin claimed files.
+ (lang_process): Set plugin_insert. Only rescan when plugin adds
+ objects.
+ * plugin.h (no_more_claiming): Declare.
+ (plugin_notice, plugin_multiple_definition): Don't declare.
+ * plugin.c: Formatting.
+ (orig_notice_all, orig_allow_multiple_defs, orig_callbacks,
+ plugin_callbacks): New static vars.
+ (no_more_claiming): Make global.
+ (plugin_cached_allow_multiple_defs): Delete.
+ (plugin_get_ir_dummy_bfd): Set SEC_EXCLUDE on dummy .text section,
+ use newer bfd_make_section variant. Make COMMON section too.
+ Error handling. Correct setting of gp size.
+ (asymbol_from_plugin_symbol): Properly cast last arg of concat.
+ (message): Likewise for ACONCAT.
+ (asymbol_from_plugin_symbol): Use our COMMON section.
+ (get_symbols): When report_plugin_symbols, show visibility too.
+ (init_non_ironly_hash): Move. Don't test non_ironly_hash.
+ (plugin_load_plugins): Save state of linker callbacks, set up to
+ call plugin_notice instead. Call init_non_ironly_hash here.
+ (plugin_call_all_symbols_read): Set plugin_multiple_definition in
+ plugin callbacks.
+ (plugin_notice): Rewrite.
+ (plugin_multiple_definition): Make static, call original callback.
+
+ 2011-04-15 Alan Modra <amodra@gmail.com>
+ PR ld/12672
+ * ldlang.c (enum open_bfd_mode): New.
+ (open_input_bfds): Replace "force" param with "mode". Reload
+ archives for rescan. Update all callers.
+ (lang_process): Make another open_input_bfds pass for plugins.
+
+ 2011-03-23 Joseph Myers <joseph@codesourcery.com>
+ * lexsup.c (parse_args): Only set report_plugin_symbols if plugins
+ are enabled. Mark level as possibly unused.
+
+ 2011-03-10 Dave Korn <dave.korn.cygwin@gmail.com>
+ * plugin.c (get_symbols): Use wrapped lookup for undefined symbols.
+
+ 2011-03-10 Dave Korn <dave.korn.cygwin@gmail.com>
+ * ldlang.c (lang_check): Don't run checks on dummy IR BFDs.
+
+ 2011-03-10 Dave Korn <dave.korn.cygwin@gmail.com>
+ * ldlang.h (lang_input_statement_type): Add new 'claim_archive' flag,
+ wrapping both it and 'claim' flag in #ifdef ENABLE_PLUGINS.
+ * ldmain.c (add_archive_element): Set it if the member is claimed.
+ * ldlang.c (new_afile): Initialise claim_archive and claimed members.
+ (find_replacements_insert_point): New helper function.
+ (lang_process): After adding and opening replacement files passed
+ from plugin, splice them into correct place in statement list and
+ file chains to preserve critical link order.
+ (lang_list_insert_after): New helper function.
+ (lang_list_remove_tail): Likewise.
+
+ 2011-03-10 Dave Korn <dave.korn.cygwin@gmail.com>
+ * plugin.c (IRONLY_SUFFIX): Revise to nicely human-readable form.
+ (IRONLY_SUFFIX_LEN): Delete.
+ (plugin_get_ir_dummy_bfd): Don't append IRONLY_SUFFIX.
+ (is_ir_dummy_bfd): Don't look for suffix; check claimed flag of
+ enclosing lang input statement instead.
+
+ 2011-03-04 H.J. Lu <hongjiu.lu@intel.com>
+ * ld.texinfo: Document --verbose[=NUMBER].
+ * lexsup.c (ld_options): Update --verbose.
+ (parse_args): Set report_plugin_symbols.
+ * plugin.c (report_plugin_symbols): New.
+ (get_symbols): Report plugin symbols if report_plugin_symbols
+ is TRUE.
+ * plugin.h (report_plugin_symbols): New.
+
+ 2011-02-24 H.J. Lu <hongjiu.lu@intel.com>
+ PR ld/12507
+ * plugin.c (get_symbols): Don't check entry symbol here.
+ (init_non_ironly_hash): Add entry_symbol chain into
+ non_ironly_hash.
+
+ 2011-02-24 H.J. Lu <hongjiu.lu@intel.com>
+ PR ld/12507
+ * plugin.c (get_symbols): Don't mark entry symbol IR only.
+
+ 2010-12-06 H.J. Lu <hongjiu.lu@intel.com>
+ * lexsup.c (ld_options): Add -flto and -flto-partition= for
+ GCC LTO option compatibility.
+
+ 2010-12-01 H.J. Lu <hongjiu.lu@intel.com>
+ * plugin.h: Re-indent.
+
2011-04-20 Tristan Gingold <gingold@adacore.com>
* emultempl/aix.em (_add_options): Ignore -bbigtoc switch.
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 1a9862acc6..879bcfcd19 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -1851,13 +1851,14 @@ Normally the linker will generate an error message for each reported
unresolved symbol but the option @option{--warn-unresolved-symbols}
can change this to a warning.
-@kindex --verbose
-@cindex verbose
+@kindex --verbose[=@var{NUMBER}]
+@cindex verbose[=@var{NUMBER}]
@item --dll-verbose
-@itemx --verbose
+@itemx --verbose[=@var{NUMBER}]
Display the version number for @command{ld} and list the linker emulations
supported. Display which input files can and cannot be opened. Display
-the linker script being used by the linker.
+the linker script being used by the linker. If the optional @var{NUMBER}
+argument > 1, plugin symbol status will also be displayed.
@kindex --version-script=@var{version-scriptfile}
@cindex version script, symbol versions
diff --git a/ld/ldfile.c b/ld/ldfile.c
index a9a69544d3..7cd501c98b 100644
--- a/ld/ldfile.c
+++ b/ld/ldfile.c
@@ -313,41 +313,19 @@ success:
will be needed when and if we want to bfd_create a new
one using this one as a template. */
if (bfd_check_format (entry->the_bfd, bfd_object)
- && plugin_active_plugins_p ())
+ && plugin_active_plugins_p ()
+ && !no_more_claiming)
{
int fd = open (attempt, O_RDONLY | O_BINARY);
if (fd >= 0)
{
struct ld_plugin_input_file file;
- int claimed = 0;
file.name = attempt;
file.offset = 0;
file.filesize = lseek (fd, 0, SEEK_END);
file.fd = fd;
- /* We create a dummy BFD, initially empty, to house
- whatever symbols the plugin may want to add. */
- file.handle = plugin_get_ir_dummy_bfd (attempt, entry->the_bfd);
- if (plugin_call_claim_file (&file, &claimed))
- einfo (_("%P%F: %s: plugin reported error claiming file\n"),
- plugin_error_plugin ());
- /* fd belongs to us, not the plugin; but we don't need it. */
- close (fd);
- if (claimed)
- {
- /* Discard the real file's BFD and substitute the dummy one. */
- bfd_close (entry->the_bfd);
- entry->the_bfd = file.handle;
- entry->claimed = TRUE;
- bfd_make_readable (entry->the_bfd);
- }
- else
- {
- /* If plugin didn't claim the file, we don't need the dummy
- bfd. Can't avoid speculatively creating it, alas. */
- bfd_close_all_done (file.handle);
- entry->claimed = FALSE;
- }
+ plugin_maybe_claim (&file, entry);
}
}
#endif /* ENABLE_PLUGINS */
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 7256495359..2885743a98 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -1074,6 +1074,10 @@ new_afile (const char *name,
p->whole_archive = whole_archive;
p->loaded = FALSE;
p->missing_file = FALSE;
+#ifdef ENABLE_PLUGINS
+ p->claimed = FALSE;
+ p->claim_archive = FALSE;
+#endif /* ENABLE_PLUGINS */
lang_statement_append (&input_file_chain,
(lang_statement_union_type *) p,
@@ -3110,26 +3114,37 @@ init_opb (void)
/* Open all the input files. */
+enum open_bfd_mode
+ {
+ OPEN_BFD_NORMAL = 0,
+ OPEN_BFD_FORCE = 1,
+ OPEN_BFD_RESCAN = 2
+ };
+#ifdef ENABLE_PLUGINS
+static lang_input_statement_type *plugin_insert = NULL;
+#endif
+
static void
-open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
+open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
{
for (; s != NULL; s = s->header.next)
{
switch (s->header.type)
{
case lang_constructors_statement_enum:
- open_input_bfds (constructor_list.head, force);
+ open_input_bfds (constructor_list.head, mode);
break;
case lang_output_section_statement_enum:
- open_input_bfds (s->output_section_statement.children.head, force);
+ open_input_bfds (s->output_section_statement.children.head, mode);
break;
case lang_wild_statement_enum:
/* Maybe we should load the file's symbols. */
- if (s->wild_statement.filename
+ if ((mode & OPEN_BFD_RESCAN) == 0
+ && s->wild_statement.filename
&& !wildcardp (s->wild_statement.filename)
&& !archive_path (s->wild_statement.filename))
lookup_name (s->wild_statement.filename);
- open_input_bfds (s->wild_statement.children.head, force);
+ open_input_bfds (s->wild_statement.children.head, mode);
break;
case lang_group_statement_enum:
{
@@ -3142,7 +3157,8 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
do
{
undefs = link_info.hash->undefs_tail;
- open_input_bfds (s->group_statement.children.head, TRUE);
+ open_input_bfds (s->group_statement.children.head,
+ mode | OPEN_BFD_FORCE);
}
while (undefs != link_info.hash->undefs_tail);
}
@@ -3161,8 +3177,12 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
/* If we are being called from within a group, and this
is an archive which has already been searched, then
force it to be researched unless the whole archive
- has been loaded already. */
- if (force
+ has been loaded already. Do the same for a rescan. */
+ if (mode != OPEN_BFD_NORMAL
+#ifdef ENABLE_PLUGINS
+ && ((mode & OPEN_BFD_RESCAN) == 0
+ || plugin_insert == NULL)
+#endif
&& !s->input_statement.whole_archive
&& s->input_statement.loaded
&& bfd_check_format (s->input_statement.the_bfd,
@@ -3198,6 +3218,12 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
}
}
}
+#ifdef ENABLE_PLUGINS
+ /* If we have found the point at which a plugin added new
+ files, clear plugin_insert to enable archive rescan. */
+ if (&s->input_statement == plugin_insert)
+ plugin_insert = NULL;
+#endif
break;
case lang_assignment_statement_enum:
if (s->assignment_statement.exp->assign.hidden)
@@ -5690,6 +5716,11 @@ lang_check (void)
for (file = file_chain.head; file != NULL; file = file->input_statement.next)
{
+#ifdef ENABLE_PLUGINS
+ /* Don't check format of files claimed by plugin. */
+ if (file->input_statement.claimed)
+ continue;
+#endif /* ENABLE_PLUGINS */
input_bfd = file->input_statement.the_bfd;
compatible
= bfd_arch_get_compatible (input_bfd, link_info.output_bfd,
@@ -6201,6 +6232,10 @@ lang_gc_sections (void)
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
asection *sec;
+#ifdef ENABLE_PLUGINS
+ if (f->claimed)
+ continue;
+#endif
for (sec = f->the_bfd->sections; sec != NULL; sec = sec->next)
if ((sec->flags & SEC_DEBUGGING) == 0)
sec->flags &= ~SEC_EXCLUDE;
@@ -6342,6 +6377,72 @@ lang_relax_sections (bfd_boolean need_layout)
}
}
+#ifdef ENABLE_PLUGINS
+/* Find the insert point for the plugin's replacement files. We
+ place them after the first claimed real object file, or if the
+ first claimed object is an archive member, after the last real
+ object file immediately preceding the archive. In the event
+ no objects have been claimed at all, we return the first dummy
+ object file on the list as the insert point; that works, but
+ the callee must be careful when relinking the file_chain as it
+ is not actually on that chain, only the statement_list and the
+ input_file list; in that case, the replacement files must be
+ inserted at the head of the file_chain. */
+
+static lang_input_statement_type *
+find_replacements_insert_point (void)
+{
+ lang_input_statement_type *claim1, *lastobject;
+ lastobject = &input_file_chain.head->input_statement;
+ for (claim1 = &file_chain.head->input_statement;
+ claim1 != NULL;
+ claim1 = &claim1->next->input_statement)
+ {
+ if (claim1->claimed)
+ return claim1->claim_archive ? lastobject : claim1;
+ /* Update lastobject if this is a real object file. */
+ if (claim1->the_bfd && (claim1->the_bfd->my_archive == NULL))
+ lastobject = claim1;
+ }
+ /* No files were claimed by the plugin. Choose the last object
+ file found on the list (maybe the first, dummy entry) as the
+ insert point. */
+ return lastobject;
+}
+
+/* Insert SRCLIST into DESTLIST after given element by chaining
+ on FIELD as the next-pointer. (Counterintuitively does not need
+ a pointer to the actual after-node itself, just its chain field.) */
+
+static void
+lang_list_insert_after (lang_statement_list_type *destlist,
+ lang_statement_list_type *srclist,
+ lang_statement_union_type **field)
+{
+ *(srclist->tail) = *field;
+ *field = srclist->head;
+ if (destlist->tail == field)
+ destlist->tail = srclist->tail;
+}
+
+/* Detach new nodes added to DESTLIST since the time ORIGLIST
+ was taken as a copy of it and leave them in ORIGLIST. */
+
+static void
+lang_list_remove_tail (lang_statement_list_type *destlist,
+ lang_statement_list_type *origlist)
+{
+ union lang_statement_union **savetail;
+ /* Check that ORIGLIST really is an earlier state of DESTLIST. */
+ ASSERT (origlist->head == destlist->head);
+ savetail = origlist->tail;
+ origlist->head = *(savetail);
+ origlist->tail = destlist->tail;
+ destlist->tail = savetail;
+ *savetail = NULL;
+}
+#endif /* ENABLE_PLUGINS */
+
void
lang_process (void)
{
@@ -6365,24 +6466,62 @@ lang_process (void)
/* Create a bfd for each input file. */
current_target = default_target;
- open_input_bfds (statement_list.head, FALSE);
+ open_input_bfds (statement_list.head, OPEN_BFD_NORMAL);
#ifdef ENABLE_PLUGINS
+ if (plugin_active_plugins_p ())
{
- union lang_statement_union **listend;
+ lang_statement_list_type added;
+ lang_statement_list_type files, inputfiles;
+
/* Now all files are read, let the plugin(s) decide if there
are any more to be added to the link before we call the
- emulation's after_open hook. */
- listend = statement_list.tail;
- ASSERT (!*listend);
+ emulation's after_open hook. We create a private list of
+ input statements for this purpose, which we will eventually
+ insert into the global statment list after the first claimed
+ file. */
+ added = *stat_ptr;
+ /* We need to manipulate all three chains in synchrony. */
+ files = file_chain;
+ inputfiles = input_file_chain;
if (plugin_call_all_symbols_read ())
einfo (_("%P%F: %s: plugin reported error after all symbols read\n"),
plugin_error_plugin ());
- /* If any new files were added, they will be on the end of the
- statement list, and we can open them now by getting open_input_bfds
- to carry on from where it ended last time. */
- if (*listend)
- open_input_bfds (*listend, FALSE);
+ /* Open any newly added files, updating the file chains. */
+ open_input_bfds (added.head, OPEN_BFD_NORMAL);
+ /* Restore the global list pointer now they have all been added. */
+ lang_list_remove_tail (stat_ptr, &added);
+ /* And detach the fresh ends of the file lists. */
+ lang_list_remove_tail (&file_chain, &files);
+ lang_list_remove_tail (&input_file_chain, &inputfiles);
+ /* Were any new files added? */
+ if (added.head != NULL)
+ {
+ /* If so, we will insert them into the statement list immediately
+ after the first input file that was claimed by the plugin. */
+ plugin_insert = find_replacements_insert_point ();
+ /* If a plugin adds input files without having claimed any, we
+ don't really have a good idea where to place them. Just putting
+ them at the start or end of the list is liable to leave them
+ outside the crtbegin...crtend range. */
+ ASSERT (plugin_insert != NULL);
+ /* Splice the new statement list into the old one. */
+ lang_list_insert_after (stat_ptr, &added,
+ &plugin_insert->header.next);
+ /* Likewise for the file chains. */
+ lang_list_insert_after (&input_file_chain, &inputfiles,
+ &plugin_insert->next_real_file);
+ /* We must be careful when relinking file_chain; we may need to
+ insert the new files at the head of the list if the insert
+ point chosen is the dummy first input file. */
+ if (plugin_insert->filename)
+ lang_list_insert_after (&file_chain, &files, &plugin_insert->next);
+ else
+ lang_list_insert_after (&file_chain, &files, &file_chain.head);
+
+ /* Rescan archives in case new undefined symbols have appeared. */
+ open_input_bfds (statement_list.head, OPEN_BFD_RESCAN);
+ }
}
#endif /* ENABLE_PLUGINS */
diff --git a/ld/ldlang.h b/ld/ldlang.h
index 9d4d41f443..cff4f252c5 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -287,9 +287,14 @@ typedef struct lang_input_statement_struct
/* Set if the file does not exist. */
unsigned int missing_file : 1;
+#ifdef ENABLE_PLUGINS
/* Set if the file was claimed by a plugin. */
unsigned int claimed : 1;
+ /* Set if the file was claimed from an archive. */
+ unsigned int claim_archive : 1;
+#endif /* ENABLE_PLUGINS */
+
} lang_input_statement_type;
typedef struct
diff --git a/ld/ldmain.c b/ld/ldmain.c
index 6e86c3d996..bfa6066b09 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -123,11 +123,11 @@ static char *get_emulation
static bfd_boolean add_archive_element
(struct bfd_link_info *, bfd *, const char *, bfd **);
static bfd_boolean multiple_definition
- (struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma,
+ (struct bfd_link_info *, struct bfd_link_hash_entry *,
bfd *, asection *, bfd_vma);
static bfd_boolean multiple_common
- (struct bfd_link_info *, const char *, bfd *, enum bfd_link_hash_type,
- bfd_vma, bfd *, enum bfd_link_hash_type, bfd_vma);
+ (struct bfd_link_info *, struct bfd_link_hash_entry *,
+ bfd *, enum bfd_link_hash_type, bfd_vma);
static bfd_boolean add_to_set
(struct bfd_link_info *, struct bfd_link_hash_entry *,
bfd_reloc_code_real_type, bfd *, asection *, bfd_vma);
@@ -150,7 +150,8 @@ static bfd_boolean reloc_dangerous
static bfd_boolean unattached_reloc
(struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma);
static bfd_boolean notice
- (struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma);
+ (struct bfd_link_info *, struct bfd_link_hash_entry *,
+ bfd *, asection *, bfd_vma);
static struct bfd_link_callbacks link_callbacks =
{
@@ -804,14 +805,16 @@ add_archive_element (struct bfd_link_info *info,
BFD, but we still want to output the original BFD filename. */
orig_input = *input;
#ifdef ENABLE_PLUGINS
- if (bfd_my_archive (abfd) != NULL && plugin_active_plugins_p ())
+ if (bfd_my_archive (abfd) != NULL
+ && plugin_active_plugins_p ()
+ && !no_more_claiming)
{
/* We must offer this archive member to the plugins to claim. */
int fd = open (bfd_my_archive (abfd)->filename, O_RDONLY | O_BINARY);
if (fd >= 0)
{
struct ld_plugin_input_file file;
- int claimed = 0;
+
/* Offset and filesize must refer to the individual archive
member, not the whole file, and must exclude the header.
Fortunately for us, that is how the data is stored in the
@@ -820,28 +823,12 @@ add_archive_element (struct bfd_link_info *info,
file.offset = abfd->origin;
file.filesize = arelt_size (abfd);
file.fd = fd;
- /* We create a dummy BFD, initially empty, to house
- whatever symbols the plugin may want to add. */
- file.handle = plugin_get_ir_dummy_bfd (abfd->filename, abfd);
- if (plugin_call_claim_file (&file, &claimed))
- einfo (_("%P%F: %s: plugin reported error claiming file\n"),
- plugin_error_plugin ());
- /* fd belongs to us, not the plugin; but we don't need it. */
- close (fd);
- if (claimed)
+ plugin_maybe_claim (&file, input);
+ if (input->claimed)
{
- /* Substitute the dummy BFD. */
- input->the_bfd = file.handle;
- input->claimed = TRUE;
- bfd_make_readable (input->the_bfd);
+ input->claim_archive = TRUE;
*subsbfd = input->the_bfd;
}
- else
- {
- /* Abandon the dummy BFD. */
- bfd_close_all_done (file.handle);
- input->claimed = FALSE;
- }
}
}
#endif /* ENABLE_PLUGINS */
@@ -934,31 +921,49 @@ add_archive_element (struct bfd_link_info *info,
multiple times. */
static bfd_boolean
-multiple_definition (struct bfd_link_info *info ATTRIBUTE_UNUSED,
- const char *name,
- bfd *obfd,
- asection *osec,
- bfd_vma oval,
+multiple_definition (struct bfd_link_info *info,
+ struct bfd_link_hash_entry *h,
bfd *nbfd,
asection *nsec,
bfd_vma nval)
{
-#ifdef ENABLE_PLUGINS
- /* We may get called back even when --allow-multiple-definition is in
- effect, as the plugin infrastructure needs to use this hook in
- order to swap out IR-only symbols for real ones. In that case,
- it will let us know not to continue by returning TRUE even if this
- is not an IR-only vs. non-IR symbol conflict. */
- if (plugin_multiple_definition (info, name, obfd, osec, oval, nbfd,
- nsec, nval))
+ const char *name;
+ bfd *obfd;
+ asection *osec;
+ bfd_vma oval;
+
+ if (info->allow_multiple_definition)
+ return TRUE;
+
+ switch (h->type)
+ {
+ case bfd_link_hash_defined:
+ osec = h->u.def.section;
+ oval = h->u.def.value;
+ obfd = h->u.def.section->owner;
+ break;
+ case bfd_link_hash_indirect:
+ osec = bfd_ind_section_ptr;
+ oval = 0;
+ obfd = NULL;
+ break;
+ default:
+ abort ();
+ }
+
+ /* Ignore a redefinition of an absolute symbol to the
+ same value; it's harmless. */
+ if (h->type == bfd_link_hash_defined
+ && bfd_is_abs_section (osec)
+ && bfd_is_abs_section (nsec)
+ && nval == oval)
return TRUE;
-#endif /* ENABLE_PLUGINS */
/* If either section has the output_section field set to
bfd_abs_section_ptr, it means that the section is being
discarded, and this is not really a multiple definition at all.
-FIXME: It would be cleaner to somehow ignore symbols defined in
-sections which are being discarded. */
+ FIXME: It would be cleaner to somehow ignore symbols defined in
+ sections which are being discarded. */
if ((osec->output_section != NULL
&& ! bfd_is_abs_section (osec)
&& bfd_is_abs_section (osec->output_section))
@@ -967,6 +972,14 @@ sections which are being discarded. */
&& bfd_is_abs_section (nsec->output_section)))
return TRUE;
+ name = h->root.string;
+ if (nbfd == NULL)
+ {
+ nbfd = obfd;
+ nsec = osec;
+ nval = oval;
+ obfd = NULL;
+ }
einfo (_("%X%C: multiple definition of `%T'\n"),
nbfd, nsec, nval, name);
if (obfd != NULL)
@@ -988,17 +1001,41 @@ sections which are being discarded. */
static bfd_boolean
multiple_common (struct bfd_link_info *info ATTRIBUTE_UNUSED,
- const char *name,
- bfd *obfd,
- enum bfd_link_hash_type otype,
- bfd_vma osize,
+ struct bfd_link_hash_entry *h,
bfd *nbfd,
enum bfd_link_hash_type ntype,
bfd_vma nsize)
{
- if (! config.warn_common)
+ const char *name;
+ bfd *obfd;
+ enum bfd_link_hash_type otype;
+ bfd_vma osize;
+
+ if (!config.warn_common)
return TRUE;
+ name = h->root.string;
+ otype = h->type;
+ if (otype == bfd_link_hash_common)
+ {
+ obfd = h->u.c.p->section->owner;
+ osize = h->u.c.size;
+ }
+ else if (otype == bfd_link_hash_defined
+ || otype == bfd_link_hash_defweak)
+ {
+ obfd = h->u.def.section->owner;
+ osize = 0;
+ }
+ else
+ {
+ /* FIXME: It would nice if we could report the BFD which defined
+ an indirect symbol, but we don't have anywhere to store the
+ information. */
+ obfd = NULL;
+ osize = 0;
+ }
+
if (ntype == bfd_link_hash_defined
|| ntype == bfd_link_hash_defweak
|| ntype == bfd_link_hash_indirect)
@@ -1443,29 +1480,23 @@ unattached_reloc (struct bfd_link_info *info ATTRIBUTE_UNUSED,
static bfd_boolean
notice (struct bfd_link_info *info,
- const char *name,
+ struct bfd_link_hash_entry *h,
bfd *abfd,
asection *section,
bfd_vma value)
{
- if (name == NULL)
+ const char *name;
+
+ if (h == NULL)
{
if (command_line.cref || nocrossref_list != NULL)
return handle_asneeded_cref (abfd, (enum notice_asneeded_action) value);
return TRUE;
}
-#ifdef ENABLE_PLUGINS
- /* We should hide symbols in the dummy IR BFDs from the nocrossrefs list
- and let the real object files that are generated and added later trip
- the error instead. Similarly would be better to trace the real symbol
- from the real file than the temporary dummy. */
- if (!plugin_notice (info, name, abfd, section, value))
- return TRUE;
-#endif /* ENABLE_PLUGINS */
-
+ name = h->root.string;
if (info->notice_hash != NULL
- && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL)
+ && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL)
{
if (bfd_is_und_section (section))
einfo ("%B: reference to %s\n", abfd, name);
diff --git a/ld/lexsup.c b/ld/lexsup.c
index b6274f8921..e9e89be193 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -283,6 +283,12 @@ static const struct ld_option ld_options[] =
'\0', N_("PLUGIN"), N_("Load named plugin"), ONE_DASH },
{ {"plugin-opt", required_argument, NULL, OPTION_PLUGIN_OPT},
'\0', N_("ARG"), N_("Send arg to last-loaded plugin"), ONE_DASH },
+ { {"flto", optional_argument, NULL, OPTION_IGNORE},
+ '\0', NULL, N_("Ignored for GCC LTO option compatibility"),
+ ONE_DASH },
+ { {"flto-partition=", required_argument, NULL, OPTION_IGNORE},
+ '\0', NULL, N_("Ignored for GCC LTO option compatibility"),
+ ONE_DASH },
#endif /* ENABLE_PLUGINS */
{ {"Qy", no_argument, NULL, OPTION_IGNORE},
'\0', NULL, N_("Ignored for SVR4 compatibility"), ONE_DASH },
@@ -555,8 +561,9 @@ static const struct ld_option ld_options[] =
" ignore-all, report-all, ignore-in-object-files,\n"
" ignore-in-shared-libs"),
TWO_DASHES },
- { {"verbose", no_argument, NULL, OPTION_VERBOSE},
- '\0', NULL, N_("Output lots of information during link"), TWO_DASHES },
+ { {"verbose", optional_argument, NULL, OPTION_VERBOSE},
+ '\0', N_("[=NUMBER]"),
+ N_("Output lots of information during link"), TWO_DASHES },
{ {"dll-verbose", no_argument, NULL, OPTION_VERBOSE}, /* Linux. */
'\0', NULL, NULL, NO_HELP },
{ {"version-script", required_argument, NULL, OPTION_VERSION_SCRIPT },
@@ -1321,6 +1328,16 @@ parse_args (unsigned argc, char **argv)
version_printed = TRUE;
trace_file_tries = TRUE;
overflow_cutoff_limit = -2;
+ if (optarg != NULL)
+ {
+ char *end;
+ int level ATTRIBUTE_UNUSED = strtoul (optarg, &end, 0);
+ if (*end)
+ einfo (_("%P%F: invalid number `%s'\n"), optarg);
+#ifdef ENABLE_PLUGINS
+ report_plugin_symbols = level > 1;
+#endif /* ENABLE_PLUGINS */
+ }
break;
case 'v':
ldversion (0);
diff --git a/ld/plugin.c b/ld/plugin.c
index 86d80ca4a1..42c737025b 100644
--- a/ld/plugin.c
+++ b/ld/plugin.c
@@ -36,14 +36,13 @@
#include <Windows.h>
#endif
+/* Report plugin symbols. */
+bfd_boolean report_plugin_symbols;
+
/* The suffix to append to the name of the real (claimed) object file
when generating a dummy BFD to hold the IR symbols sent from the
- plugin. */
-#define IRONLY_SUFFIX ".ironly\004"
-
-/* This is sizeof an array of chars, not sizeof a const char *. We
- also have to avoid inadvertently counting the trailing NUL. */
-#define IRONLY_SUFFIX_LEN (sizeof (IRONLY_SUFFIX) - 1)
+ plugin. For cosmetic use only; appears in maps, crefs etc. */
+#define IRONLY_SUFFIX " (symbol from plugin)"
/* Stores a single argument passed to a plugin. */
typedef struct plugin_arg
@@ -91,22 +90,16 @@ static plugin_t *called_plugin = NULL;
/* Last plugin to cause an error, if any. */
static const char *error_plugin = NULL;
-/* A hash table that records symbols referenced by non-IR files. Used
- at get_symbols time to determine whether any prevailing defs from
- IR files are referenced only from other IR files, so tthat we can
- we can distinguish the LDPR_PREVAILING_DEF and LDPR_PREVAILING_DEF_IRONLY
- cases when establishing symbol resolutions. */
-static struct bfd_hash_table *non_ironly_hash = NULL;
+/* State of linker "notice" interface before we poked at it. */
+static bfd_boolean orig_notice_all;
+
+/* Original linker callbacks, and the plugin version. */
+static const struct bfd_link_callbacks *orig_callbacks;
+static struct bfd_link_callbacks plugin_callbacks;
/* Set at all symbols read time, to avoid recursively offering the plugin
its own newly-added input files and libs to claim. */
-static bfd_boolean no_more_claiming = FALSE;
-
-/* If the --allow-multiple-definition command-line option is active, we
- have to disable it so that BFD always calls our hook, and simulate the
- effect (when not resolving IR vs. real symbols) ourselves by ensuring
- TRUE is returned from the hook. */
-static bfd_boolean plugin_cached_allow_multiple_defs = FALSE;
+bfd_boolean no_more_claiming = FALSE;
/* List of tags to set in the constant leading part of the tv array. */
static const enum ld_plugin_tag tv_header_tags[] =
@@ -131,6 +124,11 @@ static const enum ld_plugin_tag tv_header_tags[] =
/* How many entries in the constant leading part of the tv array. */
static const size_t tv_header_size = ARRAY_SIZE (tv_header_tags);
+/* Forward references. */
+static bfd_boolean plugin_notice (struct bfd_link_info *info,
+ struct bfd_link_hash_entry *h, bfd *abfd,
+ asection *section, bfd_vma value);
+
#if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
#define RTLD_NOW 0 /* Dummy value. */
@@ -226,38 +224,44 @@ plugin_opt_plugin_arg (const char *arg)
bfd *
plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate)
{
- asection *sec;
bfd *abfd;
bfd_use_reserved_id = 1;
- abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *)NULL),
+ abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *) NULL),
srctemplate);
- bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate));
- bfd_make_writable (abfd);
- bfd_copy_private_bfd_data (srctemplate, abfd);
- bfd_set_gp_size (abfd, bfd_get_gp_size (abfd));
- /* Create a minimal set of sections to own the symbols. */
- sec = bfd_make_section_old_way (abfd, ".text");
- bfd_set_section_flags (abfd, sec,
- (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY
- | SEC_ALLOC | SEC_LOAD | SEC_KEEP));
- sec->output_section = sec;
- sec->output_offset = 0;
- return abfd;
+ if (abfd != NULL)
+ {
+ abfd->flags |= BFD_LINKER_CREATED | BFD_PLUGIN;
+ bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate));
+ bfd_set_gp_size (abfd, bfd_get_gp_size (srctemplate));
+ if (bfd_make_writable (abfd)
+ && bfd_copy_private_bfd_data (srctemplate, abfd))
+ {
+ flagword flags;
+
+ /* Create sections to own the symbols. */
+ flags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY
+ | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE);
+ if (bfd_make_section_anyway_with_flags (abfd, ".text", flags))
+ return abfd;
+ }
+ }
+ einfo (_("could not create dummy IR bfd: %F%E\n"));
+ return NULL;
}
/* Check if the BFD passed in is an IR dummy object file. */
static bfd_boolean
is_ir_dummy_bfd (const bfd *abfd)
{
- size_t namlen;
-
- if (abfd == NULL)
- return FALSE;
- namlen = strlen (abfd->filename);
- if (namlen < IRONLY_SUFFIX_LEN)
- return FALSE;
- return !strcmp (abfd->filename + namlen - IRONLY_SUFFIX_LEN, IRONLY_SUFFIX);
+ /* ABFD can sometimes legitimately be NULL, e.g. when called from one
+ of the linker callbacks for a symbol in the *ABS* or *UND* sections.
+ Likewise, the usrdata field may be NULL if ABFD was added by the
+ backend without a corresponding input statement, as happens e.g.
+ when processing DT_NEEDED dependencies. */
+ return (abfd
+ && abfd->usrdata
+ && ((lang_input_statement_type *)(abfd->usrdata))->claimed);
}
/* Helpers to convert between BFD and GOLD symbol formats. */
@@ -270,7 +274,7 @@ asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym,
asym->the_bfd = abfd;
asym->name = (ldsym->version
- ? concat (ldsym->name, "@", ldsym->version, NULL)
+ ? concat (ldsym->name, "@", ldsym->version, (const char *) NULL)
: ldsym->name);
asym->value = 0;
switch (ldsym->def)
@@ -296,7 +300,10 @@ asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym,
asym->value = ldsym->size;
/* For ELF targets, set alignment of common symbol to 1. */
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
- ((elf_symbol_type *) asym)->internal_elf_sym.st_value = 1;
+ {
+ ((elf_symbol_type *) asym)->internal_elf_sym.st_shndx = SHN_COMMON;
+ ((elf_symbol_type *) asym)->internal_elf_sym.st_value = 1;
+ }
break;
default:
@@ -414,6 +421,8 @@ static inline bfd_boolean
is_visible_from_outside (struct ld_plugin_symbol *lsym, asection *section,
struct bfd_link_hash_entry *blhe)
{
+ struct bfd_sym_chain *sym;
+
/* Section's owner may be NULL if it is the absolute
section, fortunately is_ir_dummy_bfd handles that. */
if (!is_ir_dummy_bfd (section->owner))
@@ -442,6 +451,12 @@ is_visible_from_outside (struct ld_plugin_symbol *lsym, asection *section,
return (lsym->visibility == LDPV_DEFAULT
|| lsym->visibility == LDPV_PROTECTED);
}
+
+ for (sym = &entry_symbol; sym != NULL; sym = sym->next)
+ if (sym->name
+ && strcmp (sym->name, blhe->root.string) == 0)
+ return TRUE;
+
return FALSE;
}
@@ -457,13 +472,16 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
struct bfd_link_hash_entry *blhe;
bfd_boolean ironly;
asection *owner_sec;
-
- blhe = bfd_link_hash_lookup (link_info.hash, syms[n].name,
- FALSE, FALSE, TRUE);
+ if (syms[n].def != LDPK_UNDEF)
+ blhe = bfd_link_hash_lookup (link_info.hash, syms[n].name,
+ FALSE, FALSE, TRUE);
+ else
+ blhe = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info,
+ syms[n].name, FALSE, FALSE, TRUE);
if (!blhe)
{
syms[n].resolution = LDPR_UNKNOWN;
- continue;
+ goto report_symbol;
}
/* Determine resolution from blhe type and symbol's original type. */
@@ -471,7 +489,7 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
|| blhe->type == bfd_link_hash_undefweak)
{
syms[n].resolution = LDPR_UNDEF;
- continue;
+ goto report_symbol;
}
if (blhe->type != bfd_link_hash_defined
&& blhe->type != bfd_link_hash_defweak
@@ -485,16 +503,16 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
/* Find out which section owns the symbol. Since it's not undef,
it must have an owner; if it's not a common symbol, both defs
and weakdefs keep it in the same place. */
- owner_sec = (blhe->type == bfd_link_hash_common)
- ? blhe->u.c.p->section
- : blhe->u.def.section;
+ owner_sec = (blhe->type == bfd_link_hash_common
+ ? blhe->u.c.p->section
+ : blhe->u.def.section);
/* We need to know if the sym is referenced from non-IR files. Or
even potentially-referenced, perhaps in a future final link if
this is a partial one, perhaps dynamically at load-time if the
symbol is externally visible. */
- ironly = !is_visible_from_outside (&syms[n], owner_sec, blhe)
- && !bfd_hash_lookup (non_ironly_hash, syms[n].name, FALSE, FALSE);
+ ironly = !(blhe->non_ir_ref
+ || is_visible_from_outside (&syms[n], owner_sec, blhe));
/* If it was originally undefined or common, then it has been
resolved; determine how. */
@@ -515,7 +533,7 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
syms[n].resolution = LDPR_RESOLVED_DYN;
else
syms[n].resolution = LDPR_RESOLVED_EXEC;
- continue;
+ goto report_symbol;
}
/* Was originally def, or weakdef. Does it prevail? If the
@@ -528,13 +546,20 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
syms[n].resolution = (ironly
? LDPR_PREVAILING_DEF_IRONLY
: LDPR_PREVAILING_DEF);
- continue;
+ goto report_symbol;
}
/* Was originally def, weakdef, or common, but has been pre-empted. */
- syms[n].resolution = is_ir_dummy_bfd (owner_sec->owner)
- ? LDPR_PREEMPTED_IR
- : LDPR_PREEMPTED_REG;
+ syms[n].resolution = (is_ir_dummy_bfd (owner_sec->owner)
+ ? LDPR_PREEMPTED_IR
+ : LDPR_PREEMPTED_REG);
+
+ report_symbol:
+ if (report_plugin_symbols)
+ einfo (_("%P: %B: symbol `%s' "
+ "definition: %d, visibility: %d, resolution: %d\n"),
+ abfd, syms[n].name,
+ syms[n].def, syms[n].visibility, syms[n].resolution);
}
return LDPS_OK;
}
@@ -591,14 +616,13 @@ message (int level, const char *format, ...)
case LDPL_FATAL:
case LDPL_ERROR:
default:
- {
- char *newfmt = ACONCAT ((level == LDPL_FATAL
- ? "%P%F: " : "%P%X: ",
- format, "\n", NULL));
- fflush (stdout);
- vfinfo (stderr, newfmt, args, TRUE);
- fflush (stderr);
- }
+ {
+ char *newfmt = ACONCAT ((level == LDPL_FATAL ? "%P%F: " : "%P%X: ",
+ format, "\n", (const char *) NULL));
+ fflush (stdout);
+ vfinfo (stderr, newfmt, args, TRUE);
+ fflush (stderr);
+ }
break;
}
@@ -753,13 +777,18 @@ plugin_load_plugins (void)
/* Since plugin(s) inited ok, assume they're going to want symbol
resolutions, which needs us to track which symbols are referenced
by non-IR files using the linker's notice callback. */
+ orig_notice_all = link_info.notice_all;
+ orig_callbacks = link_info.callbacks;
+ plugin_callbacks = *orig_callbacks;
+ plugin_callbacks.notice = &plugin_notice;
link_info.notice_all = TRUE;
+ link_info.callbacks = &plugin_callbacks;
return 0;
}
/* Call 'claim file' hook for all plugins. */
-int
+static int
plugin_call_claim_file (const struct ld_plugin_input_file *file, int *claimed)
{
plugin_t *curplug = plugins_list;
@@ -782,6 +811,42 @@ plugin_call_claim_file (const struct ld_plugin_input_file *file, int *claimed)
return plugin_error_p () ? -1 : 0;
}
+void
+plugin_maybe_claim (struct ld_plugin_input_file *file,
+ lang_input_statement_type *entry)
+{
+ int claimed = 0;
+
+ /* We create a dummy BFD, initially empty, to house whatever symbols
+ the plugin may want to add. */
+ file->handle = plugin_get_ir_dummy_bfd (entry->the_bfd->filename,
+ entry->the_bfd);
+ if (plugin_call_claim_file (file, &claimed))
+ einfo (_("%P%F: %s: plugin reported error claiming file\n"),
+ plugin_error_plugin ());
+ /* fd belongs to us, not the plugin; but we don't need it. */
+ close (file->fd);
+ if (claimed)
+ {
+ /* Discard the real file's BFD and substitute the dummy one. */
+
+ /* BFD archive handling caches elements so we can't call
+ bfd_close for archives. */
+ if (entry->the_bfd->my_archive == NULL)
+ bfd_close (entry->the_bfd);
+ entry->the_bfd = file->handle;
+ entry->claimed = TRUE;
+ bfd_make_readable (entry->the_bfd);
+ }
+ else
+ {
+ /* If plugin didn't claim the file, we don't need the dummy bfd.
+ Can't avoid speculatively creating it, alas. */
+ bfd_close_all_done (file->handle);
+ entry->claimed = FALSE;
+ }
+}
+
/* Call 'all symbols read' hook for all plugins. */
int
plugin_call_all_symbols_read (void)
@@ -791,13 +856,6 @@ plugin_call_all_symbols_read (void)
/* Disable any further file-claiming. */
no_more_claiming = TRUE;
- /* If --allow-multiple-definition is in effect, we need to disable it,
- as the plugin infrastructure relies on the multiple_definition
- callback to swap out the dummy IR-only BFDs for new real ones
- when it starts opening the files added during this callback. */
- plugin_cached_allow_multiple_defs = link_info.allow_multiple_definition;
- link_info.allow_multiple_definition = FALSE;
-
while (curplug)
{
if (curplug->all_symbols_read_handler)
@@ -839,87 +897,49 @@ plugin_call_cleanup (void)
plugin_error_plugin ());
}
-/* Lazily init the non_ironly hash table. */
-static void
-init_non_ironly_hash (void)
-{
- if (non_ironly_hash == NULL)
- {
- non_ironly_hash =
- (struct bfd_hash_table *) xmalloc (sizeof (struct bfd_hash_table));
- if (!bfd_hash_table_init_n (non_ironly_hash,
- bfd_hash_newfunc,
- sizeof (struct bfd_hash_entry),
- 61))
- einfo (_("%P%F: bfd_hash_table_init failed: %E\n"));
- }
-}
-
/* To determine which symbols should be resolved LDPR_PREVAILING_DEF
and which LDPR_PREVAILING_DEF_IRONLY, we notice all the symbols as
- the linker adds them to the linker hash table. If we see a symbol
- being referenced from a non-IR file, we add it to the non_ironly hash
- table. If we can't find it there at get_symbols time, we know that
- it was referenced only by IR files. We have to notice_all symbols,
- because we won't necessarily know until later which ones will be
- contributed by IR files. */
-bfd_boolean
-plugin_notice (struct bfd_link_info *info ATTRIBUTE_UNUSED,
- const char *name, bfd *abfd,
- asection *section, bfd_vma value ATTRIBUTE_UNUSED)
-{
- bfd_boolean is_ref = bfd_is_und_section (section);
- bfd_boolean is_dummy = is_ir_dummy_bfd (abfd);
- init_non_ironly_hash ();
- /* We only care about refs, not defs, indicated by section pointing
- to the undefined section (according to the bfd linker notice callback
- interface definition). */
- if (is_ref && !is_dummy)
- {
- /* This is a ref from a non-IR file, so note the ref'd symbol
- in the non-IR-only hash. */
- if (!bfd_hash_lookup (non_ironly_hash, name, TRUE, TRUE))
- einfo (_("%P%X: %s: hash table failure adding symbol %s\n"),
- abfd->filename, name);
- }
- else if (!is_ref && is_dummy)
+ the linker adds them to the linker hash table. Mark those
+ referenced from a non-IR file with non_ir_ref. We have to
+ notice_all symbols, because we won't necessarily know until later
+ which ones will be contributed by IR files. */
+static bfd_boolean
+plugin_notice (struct bfd_link_info *info,
+ struct bfd_link_hash_entry *h,
+ bfd *abfd,
+ asection *section,
+ bfd_vma value)
+{
+ if (h != NULL)
{
- /* No further processing since this is a def from an IR dummy BFD. */
- return FALSE;
+ /* No further processing if this def/ref is from an IR dummy BFD. */
+ if (is_ir_dummy_bfd (abfd))
+ return TRUE;
+
+ /* If this is a ref, set non_ir_ref. */
+ if (bfd_is_und_section (section))
+ h->non_ir_ref = TRUE;
+
+ /* Otherwise, it must be a new def. Ensure any symbol defined
+ in an IR dummy BFD takes on a new value from a real BFD.
+ Weak symbols are not normally overridden by a new weak
+ definition, and strong symbols will normally cause multiple
+ definition errors. Avoid this by making the symbol appear
+ to be undefined. */
+ else if (((h->type == bfd_link_hash_defweak
+ || h->type == bfd_link_hash_defined)
+ && is_ir_dummy_bfd (h->u.def.section->owner))
+ || (h->type == bfd_link_hash_common
+ && is_ir_dummy_bfd (h->u.c.p->section->owner)))
+ h->type = bfd_link_hash_undefweak;
}
/* Continue with cref/nocrossref/trace-sym processing. */
+ if (h == NULL
+ || orig_notice_all
+ || (info->notice_hash != NULL
+ && bfd_hash_lookup (info->notice_hash, h->root.string,
+ FALSE, FALSE) != NULL))
+ return (*orig_callbacks->notice) (info, h, abfd, section, value);
return TRUE;
}
-
-/* When we add new object files to the link at all symbols read time,
- these contain the real code and symbols generated from the IR files,
- and so duplicate all the definitions already supplied by the dummy
- IR-only BFDs that we created at claim files time. We use the linker's
- multiple-definitions callback hook to fix up the clash, discarding
- the symbol from the IR-only BFD in favour of the symbol from the
- real BFD. We return true if this was not-really-a-clash because
- we've fixed it up, or anyway if --allow-multiple-definition was in
- effect (before we disabled it to ensure we got called back). */
-bfd_boolean
-plugin_multiple_definition (struct bfd_link_info *info, const char *name,
- bfd *obfd, asection *osec ATTRIBUTE_UNUSED,
- bfd_vma oval ATTRIBUTE_UNUSED,
- bfd *nbfd, asection *nsec, bfd_vma nval)
-{
- if (is_ir_dummy_bfd (obfd))
- {
- struct bfd_link_hash_entry *blhe
- = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, FALSE);
- if (!blhe)
- einfo (_("%P%X: %s: can't find IR symbol '%s'\n"), nbfd->filename,
- name);
- else if (blhe->type != bfd_link_hash_defined)
- einfo (_("%P%x: %s: bad IR symbol type %d\n"), name, blhe->type);
- /* Replace it with new details. */
- blhe->u.def.section = nsec;
- blhe->u.def.value = nval;
- return TRUE;
- }
- return plugin_cached_allow_multiple_defs;
-}
diff --git a/ld/plugin.h b/ld/plugin.h
index 49a27f9ca4..ee29b7ce1c 100644
--- a/ld/plugin.h
+++ b/ld/plugin.h
@@ -21,6 +21,12 @@
#ifndef GLD_PLUGIN_H
#define GLD_PLUGIN_H
+/* Report plugin symbols. */
+extern bfd_boolean report_plugin_symbols;
+
+/* Set at all symbols read time, to avoid recursively offering the plugin
+ its own newly-added input files and libs to claim. */
+extern bfd_boolean no_more_claiming;
/* This is the only forward declaration we need to avoid having
to include the plugin-api.h header in order to use this file. */
@@ -44,8 +50,8 @@ extern int plugin_load_plugins (void);
extern const char *plugin_error_plugin (void);
/* Call 'claim file' hook for all plugins. */
-extern int plugin_call_claim_file (const struct ld_plugin_input_file *file,
- int *claimed);
+extern void plugin_maybe_claim (struct ld_plugin_input_file *,
+ lang_input_statement_type *);
/* Call 'all symbols read' hook for all plugins. */
extern int plugin_call_all_symbols_read (void);
@@ -60,15 +66,4 @@ extern void plugin_call_cleanup (void);
add_symbols hook has been called so that it can be read when linking. */
extern bfd *plugin_get_ir_dummy_bfd (const char *name, bfd *template);
-/* Notice-symbol bfd linker callback hook. */
-extern bfd_boolean plugin_notice (struct bfd_link_info *info,
- const char *name, bfd *abfd, asection *section,
- bfd_vma value);
-
-/* Multiple-definition bfd linker callback hook. */
-extern bfd_boolean plugin_multiple_definition (struct bfd_link_info *info,
- const char *name,
- bfd *obfd, asection *osec, bfd_vma oval,
- bfd *nbfd, asection *nsec, bfd_vma nval);
-
#endif /* !def GLD_PLUGIN_H */
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index 11507d44b8..aa44f2f2c7 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,29 @@
+2011-04-27 Alan Modra <amodra@gmail.com>
+
+ Backport from mainline.
+ 2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
+ * ld-plugin/plugin-ignore.d: Removed.
+
+ 2011-04-18 H.J. Lu <hongjiu.lu@intel.com>
+ * ld-plugin/plugin-7.d: Update expected LTO linker errors for
+ GCC 4.6.
+ * ld-plugin/plugin-8.d: Likewise.
+
+ 2011-04-18 Alan Modra <amodra@gmail.com>
+ * ld-plugin/plugin-7.d: Adjust for plugin changes.
+ * ld-plugin/plugin-8.d: Likewise.
+ * ld-plugin/plugin.exp: Pass --verbose=2 for visibility test, and
+ compare ld output to..
+ * ld-plugin/plugin-12.d: New.
+
+ 2011-04-11 Mark Wielaard <mjw@redhat.com>
+ PR 10549
+ * ld-unique: New directory.
+ * ld-unique/unique.exp: New file: Run the UNIQUE tests.
+ * ld-unique/unique.s: New test file.
+ * ld-unique/unique_empty.s: Likewise.
+ * ld-unique/unique_shared.s: Likewise.
+
2011-04-11 Alan Modra <amodra@gmail.com>
* ld-elf/eh-frame-hdr.d: xfail avr.
diff --git a/ld/testsuite/ld-plugin/plugin-12.d b/ld/testsuite/ld-plugin/plugin-12.d
new file mode 100644
index 0000000000..10d772553d
--- /dev/null
+++ b/ld/testsuite/ld-plugin/plugin-12.d
@@ -0,0 +1,6 @@
+#...
+.*: symbol `func' definition: 0, visibility: 0, resolution: 2
+.*: symbol `func1' definition: 0, visibility: 1, resolution: 3
+.*: symbol `func2' definition: 0, visibility: 2, resolution: 3
+.*: symbol `func3' definition: 0, visibility: 3, resolution: 3
+#pass
diff --git a/ld/testsuite/ld-plugin/plugin-7.d b/ld/testsuite/ld-plugin/plugin-7.d
index 75f25e01b2..04f41392ca 100644
--- a/ld/testsuite/ld-plugin/plugin-7.d
+++ b/ld/testsuite/ld-plugin/plugin-7.d
@@ -26,5 +26,6 @@ hook called: claim_file tmpdir/func.o \[@0/.* CLAIMED
hook called: claim_file tmpdir/text.o \[@0/.* not claimed
#...
hook called: all symbols read.
+`func' referenced in section `\.text.*' of tmpdir/main.o: defined in discarded section .*
hook called: cleanup.
#...
diff --git a/ld/testsuite/ld-plugin/plugin-8.d b/ld/testsuite/ld-plugin/plugin-8.d
index e72b0392c0..003537c94f 100644
--- a/ld/testsuite/ld-plugin/plugin-8.d
+++ b/ld/testsuite/ld-plugin/plugin-8.d
@@ -30,5 +30,6 @@ hook called: claim_file tmpdir/text.o \[@0/.* not claimed
hook called: all symbols read.
Sym: '_?func' Resolution: LDPR_PREVAILING_DEF
Sym: '_?func2' Resolution: LDPR_PREVAILING_DEF_IRONLY
+`func' referenced in section `\.text.*' of tmpdir/main.o: defined in discarded section .*
hook called: cleanup.
#...
diff --git a/ld/testsuite/ld-plugin/plugin.exp b/ld/testsuite/ld-plugin/plugin.exp
index 3b5e077eb9..02319bfb1a 100644
--- a/ld/testsuite/ld-plugin/plugin.exp
+++ b/ld/testsuite/ld-plugin/plugin.exp
@@ -87,7 +87,7 @@ set testobjfiles "tmpdir/main.o tmpdir/func.o tmpdir/text.o"
set testobjfiles_notext "tmpdir/main.o tmpdir/func.o"
# Rather than having libs we just define dummy values for anything
# we may need to link a target exe; we aren't going to run it anyway.
-set libs "[ld_simple_link_defsyms] --defsym ${_}printf=0 --defsym ${_}puts=0"
+set libs "[ld_simple_link_defsyms] --defsym ${_}printf=${_}main --defsym ${_}puts=${_}main"
set plugin_tests [list \
[list "load plugin" "-plugin $plugin_path \
@@ -152,8 +152,8 @@ set plugin_extra_elf_tests [list \
-plugin-opt sym:${_}func2::0:2:0 \
-plugin-opt sym:${_}func3::0:3:0 \
-plugin-opt dumpresolutions \
- $testobjfiles $libs" "" "" {{ld plugin-ignore.d} \
- {readelf -s plugin-vis-1.d}} "main.x" ] \
+ -plugin-opt add:tmpdir/func.o \
+ $testobjfiles $libs --verbose=2" "" "" {{ld plugin-12.d}} "main.x" ] \
]
if { !$can_compile || $failed_compile } {
diff --git a/ld/testsuite/ld-unique/unique.exp b/ld/testsuite/ld-unique/unique.exp
new file mode 100644
index 0000000000..4d73e32f33
--- /dev/null
+++ b/ld/testsuite/ld-unique/unique.exp
@@ -0,0 +1,249 @@
+# Expect script for linker support of STB_GNU_UNIQUE symbols
+#
+# Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
+# Contributed by Red Hat.
+#
+# This file is part of the GNU Binutils.
+#
+# This program 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 3 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 Nick Clifton <nickc@redhat.com>
+# Adapted for unique checking by Mark J. Wielaard <mjw@redhat.com>
+
+
+# STB_GNU_UNIQUE support has only been implemented for the ix86, x86_64,
+# arm, powerpc, and sparc so far.
+if {!(([istarget "i?86-*-*"]
+ || [istarget "x86_64-*-*"]
+ || [istarget "arm-*-*"]
+ || [istarget "powerpc*-*-*"]
+ || [istarget "sparc*-*-*"])
+ && ([istarget "*-*-elf*"]
+ || (([istarget "*-*-linux*"]
+ || [istarget "*-*-gnu*"])
+ && ![istarget "*-*-*aout*"]
+ && ![istarget "*-*-*oldld*"]))) } {
+ verbose "UNIQUE tests not run - target does not support UNIQUE"
+ return
+}
+
+# We need a native system. FIXME: Strictly speaking this
+# is not true, we just need to know how to create a fully
+# linked executable, including the C and Z libraries, using
+# the linker that is under test.
+if ![isnative] {
+ verbose "UNIQUE tests not run - not a native toolchain"
+ return
+}
+
+# We need a working compiler. (Strictly speaking this is
+# not true, we could use target specific assembler files).
+if { [which $CC] == 0 } {
+ verbose "UNIQUE tests not run - no compiler available"
+ return
+}
+
+# A procedure to check the OS/ABI field in the ELF header of a binary file.
+proc check_osabi { binary_file expected_osabi } {
+ global READELF
+ global READELFFLAGS
+
+ catch "exec $READELF $READELFFLAGS --file-header $binary_file > readelf.out" got
+
+ if ![string match "" $got] then {
+ verbose "proc check_osabi: Readelf produced unexpected out processing $binary_file: $got"
+ return 0
+ }
+
+ if { ![regexp "\n\[ \]*OS/ABI:\[ \]*(.+)\n\[ \]*ABI" \
+ [file_contents readelf.out] nil osabi] } {
+ verbose "proc check_osabi: Readelf failed to extract an ELF header from $binary_file"
+ return 0
+ }
+
+ if { $osabi == $expected_osabi } {
+ return 1
+ }
+
+ verbose "Expected OSABI: $expected_osabi, Obtained osabi: $osabi"
+
+ return 0
+}
+
+# A procedure to confirm that a file contains the UNIQUE symbol.
+# Returns -1 upon error, 0 if the symbol was not found and 1 if it was found.
+proc contains_unique_symbol { binary_file } {
+ global READELF
+ global READELFFLAGS
+
+ catch "exec $READELF $READELFFLAGS --symbols $binary_file > readelf.out" got
+
+ if ![string match "" $got] then {
+ verbose "proc contains_unique_symbol: Readelf produced unexpected out processing $binary_file: $got"
+ return -1
+ }
+
+ # Look for a line like this:
+ # 54: 0000000000400474 4 OBJECT UNIQUE DEFAULT 13 a
+
+ if { ![regexp ".*\[ \]*OBJECT\[ \]+UNIQUE\[ \]+DEFAULT\[ \]+\[UND0-9\]+\[ \]+\[ab\]\n" [file_contents readelf.out]] } {
+ return 0
+ }
+
+ return 1
+}
+
+set fails 0
+
+# Create object file containing unique symbol.
+if ![ld_compile "$CC -c" "$srcdir/$subdir/unique.s" "tmpdir/unique.o"] {
+ fail "Could not create a unique object"
+ set fails [expr $fails + 1]
+}
+
+# Create object file NOT containing unique symbol.
+if ![ld_compile "$CC -c" "$srcdir/$subdir/unique_empty.s" "tmpdir/unique_empty.o"] {
+ fail "Could not create a non-unique object"
+ set fails [expr $fails + 1]
+}
+
+# Create pic object file containing unique symbol.
+if ![ld_compile "$CC -c -fPIC" "$srcdir/$subdir/unique_shared.s" "tmpdir/unique_shared.o"] {
+ fail "Could not create a pic unique object"
+ set fails [expr $fails + 1]
+}
+
+# Create executable containing unique symbol.
+if ![default_ld_link $ld "tmpdir/unique_prog" "tmpdir/unique.o"] {
+ fail "Could not link a unique executable"
+ set fails [expr $fails + 1]
+}
+
+# Create shared library containing unique symbol.
+if ![ld_simple_link $ld "tmpdir/libunique_shared.so" "-shared tmpdir/unique_shared.o"] {
+ fail "Could not create a shared library containing an unique symbol"
+ set fails [expr $fails + 1]
+}
+
+# Create executable NOT containing unique symbol linked against library.
+if ![default_ld_link $ld "tmpdir/unique_shared_prog" "-Ltmpdir tmpdir/unique_empty.o -Bdynamic -lunique_shared -rpath ./tmpdir"] {
+ fail "Could not link a dynamic executable"
+ set fails [expr $fails + 1]
+}
+
+if { $fails != 0 } {
+ return
+}
+
+# Check the object file.
+if {! [check_osabi tmpdir/unique.o {UNIX - Linux}]} {
+ fail "Object containing unique does not have an OS/ABI field of LINUX"
+ set fails [expr $fails + 1]
+}
+
+if {[contains_unique_symbol tmpdir/unique.o] != 1} {
+ fail "Object containing unique does not contain an UNIQUE symbol"
+ set fails [expr $fails + 1]
+}
+
+if { $fails == 0 } {
+ pass "Checking unique object"
+}
+
+# Check the executable.
+if {! [check_osabi tmpdir/unique_prog {UNIX - Linux}]} {
+ fail "Executable containing unique does not have an OS/ABI field of LINUX"
+ set fails [expr $fails + 1]
+}
+
+if {[contains_unique_symbol tmpdir/unique_prog] != 1} {
+ fail "Executable containing unique does not contain an UNIQUE symbol"
+ set fails [expr $fails + 1]
+}
+
+if { $fails == 0 } {
+ pass "Checking unique executable"
+}
+
+# Check the empty object file.
+if {! [check_osabi tmpdir/unique_empty.o {UNIX - System V}]} {
+ fail "Object NOT containing unique does not have an OS/ABI field of System V"
+ set fails [expr $fails + 1]
+}
+
+if {[contains_unique_symbol tmpdir/unique_empty.o] == 1} {
+ fail "Object NOT containing unique does contain an UNIQUE symbol"
+ set fails [expr $fails + 1]
+}
+
+if { $fails == 0 } {
+ pass "Checking empty unique object"
+}
+
+# Check the unique PIC file.
+if {! [check_osabi tmpdir/unique_shared.o {UNIX - Linux}]} {
+ fail "PIC Object containing unique does not have an OS/ABI field of LINUX"
+ set fails [expr $fails + 1]
+}
+
+if {[contains_unique_symbol tmpdir/unique_shared.o] != 1} {
+ fail "PIC Object containing unique does not contain an UNIQUE symbol"
+ set fails [expr $fails + 1]
+}
+
+if { $fails == 0 } {
+ pass "Checking unique PIC object"
+}
+
+# Check the unique shared library.
+if {! [check_osabi tmpdir/libunique_shared.so {UNIX - Linux}]} {
+ fail "Shared library containing unique does not have an OS/ABI field of LINUX"
+ set fails [expr $fails + 1]
+}
+
+if {[contains_unique_symbol tmpdir/libunique_shared.so] != 1} {
+ fail "Shared library containing unique does not contain an UNIQUE symbol"
+ set fails [expr $fails + 1]
+}
+
+if { $fails == 0 } {
+ pass "Checking unique PIC object"
+}
+
+# Check the empty executable linked against unique shared library.
+if {! [check_osabi tmpdir/unique_shared_prog {UNIX - System V}]} {
+ fail "Executable NOT containing unique does not have an OS/ABI field of System V"
+ set fails [expr $fails + 1]
+}
+
+if {[contains_unique_symbol tmpdir/unique_shared_prog] == 1} {
+ fail "Executable NOT containing unique does contain an UNIQUE symbol"
+ set fails [expr $fails + 1]
+}
+
+if { $fails == 0 } {
+ pass "Checking shared empty executable"
+}
+
+# Clean up, unless we are being verbose, in which case we leave the files available.
+if { $verbose < 1 } {
+ remote_file host delete "tmpdir/unique_empty.o"
+ remote_file host delete "tmpdir/unique.o"
+ remote_file host delete "tmpdir/unique_shared.o"
+ remote_file host delete "tmpdir/libunique_shared.so"
+ remote_file host delete "tmpdir/unique_prog"
+ remote_file host delete "tmpdir/unique_shared_prog"
+}
diff --git a/ld/testsuite/ld-unique/unique.s b/ld/testsuite/ld-unique/unique.s
new file mode 100644
index 0000000000..9b0593c2c2
--- /dev/null
+++ b/ld/testsuite/ld-unique/unique.s
@@ -0,0 +1,8 @@
+ .type a, @gnu_unique_object
+a: .long 0
+ .size a, .-a
+
+ .type main,"function"
+ .global main
+main:
+ .long 0
diff --git a/ld/testsuite/ld-unique/unique_empty.s b/ld/testsuite/ld-unique/unique_empty.s
new file mode 100644
index 0000000000..efd66839bc
--- /dev/null
+++ b/ld/testsuite/ld-unique/unique_empty.s
@@ -0,0 +1,4 @@
+ .type main,"function"
+ .global main
+main:
+ .long 0
diff --git a/ld/testsuite/ld-unique/unique_shared.s b/ld/testsuite/ld-unique/unique_shared.s
new file mode 100644
index 0000000000..b18a5b1b84
--- /dev/null
+++ b/ld/testsuite/ld-unique/unique_shared.s
@@ -0,0 +1,3 @@
+ .type b, @gnu_unique_object
+b: .long 0
+ .size b, .-b