summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Wilson <bob.wilson@acm.org>2006-04-14 21:31:16 +0000
committerBob Wilson <bob.wilson@acm.org>2006-04-14 21:31:16 +0000
commit34e0f4f7c00562ad0e8e63ec1b375aeacb8ed91a (patch)
tree7e6a697004209853d31b97b9818c66db916ba52c
parent2284978869124dfbc85920d2bc59c4b4ddf778c1 (diff)
downloadbinutils-redhat-34e0f4f7c00562ad0e8e63ec1b375aeacb8ed91a.tar.gz
* emultempl/xtensaelf.em (elf_xtensa_before_allocation): Call new
function to strip inconsistent linkonce sections. (input_section_linked_worker, input_section_linked): New. (is_inconsistent_linkonce_section): New. (xtensa_strip_inconsistent_linkonce_sections): New.
-rw-r--r--ld/ChangeLog9
-rw-r--r--ld/emultempl/xtensaelf.em145
2 files changed, 153 insertions, 1 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index bbadba41d8..f8b1e9f3c3 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,12 @@
+2006-04-14 David Heine <dlheine@tensilica.com>
+ Bob Wilson <bob.wilson@acm.org>
+
+ * emultempl/xtensaelf.em (elf_xtensa_before_allocation): Call new
+ function to strip inconsistent linkonce sections.
+ (input_section_linked_worker, input_section_linked): New.
+ (is_inconsistent_linkonce_section): New.
+ (xtensa_strip_inconsistent_linkonce_sections): New.
+
2006-04-11 Diego Pettenò <flameeyes@gentoo.org>
* emultempl/elf32.em: Add support for elf-hints.h on FreeBSD
diff --git a/ld/emultempl/xtensaelf.em b/ld/emultempl/xtensaelf.em
index 16feed1f79..f5d2ba9cea 100644
--- a/ld/emultempl/xtensaelf.em
+++ b/ld/emultempl/xtensaelf.em
@@ -1,5 +1,5 @@
# This shell script emits a C file. -*- C -*-
-# Copyright 2003, 2004, 2005
+# Copyright 2003, 2004, 2005, 2006
# Free Software Foundation, Inc.
#
# This file is part of GLD, the Gnu Linker.
@@ -32,6 +32,8 @@ cat >>e${EMULATION_NAME}.c <<EOF
static void xtensa_wild_group_interleave (lang_statement_union_type *);
static void xtensa_colocate_output_literals (lang_statement_union_type *);
+static void xtensa_strip_inconsistent_linkonce_sections
+ (lang_statement_list_type *);
/* Flag for the emulation-specific "--no-relax" option. */
@@ -370,6 +372,8 @@ elf_xtensa_before_allocation (void)
if (!disable_relaxation)
command_line.relax = TRUE;
+ xtensa_strip_inconsistent_linkonce_sections (stat_ptr);
+
gld${EMULATION_NAME}_before_allocation ();
xtensa_wild_group_interleave (stat_ptr->head);
@@ -1157,6 +1161,145 @@ ld_count_children (lang_statement_union_type *s)
#endif /* EXTRA_VALIDATION */
+/* Check if a particular section is included in the link. This will only
+ be true for one instance of a particular linkonce section. */
+
+static bfd_boolean input_section_found = FALSE;
+static asection *input_section_target = NULL;
+
+static void
+input_section_linked_worker (lang_statement_union_type *statement)
+{
+ if ((statement->header.type == lang_input_section_enum
+ && (statement->input_section.section == input_section_target)))
+ input_section_found = TRUE;
+}
+
+static bfd_boolean
+input_section_linked (asection *sec)
+{
+ input_section_found = FALSE;
+ input_section_target = sec;
+ lang_for_each_statement_worker (input_section_linked_worker, stat_ptr->head);
+ return input_section_found;
+}
+
+
+/* Strip out any linkonce literal sections or property tables where the
+ associated linkonce text is from a different object file. Normally,
+ a matching set of linkonce sections is taken from the same object file,
+ but sometimes the files are compiled differently so that some of the
+ linkonce sections are not present in all files. Stripping the
+ inconsistent sections like this is not completely robust -- a much
+ better solution is to use comdat groups. */
+
+static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
+
+static bfd_boolean
+is_inconsistent_linkonce_section (asection *sec)
+{
+ bfd *abfd = sec->owner;
+ const char *sec_name = bfd_get_section_name (abfd, sec);
+ char *prop_tag = 0;
+
+ if ((bfd_get_section_flags (abfd, sec) & SEC_LINK_ONCE) == 0
+ || strncmp (sec_name, ".gnu.linkonce.", linkonce_len) != 0)
+ return FALSE;
+
+ /* Check if this is an Xtensa property section. */
+ if (strncmp (sec_name + linkonce_len, "p.", 2) == 0)
+ prop_tag = "p.";
+ else if (strncmp (sec_name + linkonce_len, "prop.", 5) == 0)
+ prop_tag = "prop.";
+ if (prop_tag)
+ {
+ int tag_len = strlen (prop_tag);
+ char *dep_sec_name = xmalloc (strlen (sec_name));
+ asection *dep_sec;
+
+ /* Get the associated linkonce text section and check if it is
+ included in the link. If not, this section is inconsistent
+ and should be stripped. */
+ strcpy (dep_sec_name, ".gnu.linkonce.");
+ strcat (dep_sec_name, sec_name + linkonce_len + tag_len);
+ dep_sec = bfd_get_section_by_name (abfd, dep_sec_name);
+ if (dep_sec == NULL || ! input_section_linked (dep_sec))
+ {
+ free (dep_sec_name);
+ return TRUE;
+ }
+ free (dep_sec_name);
+ }
+
+ return FALSE;
+}
+
+
+static void
+xtensa_strip_inconsistent_linkonce_sections (lang_statement_list_type *slist)
+{
+ lang_statement_union_type **s_p = &slist->head;
+ while (*s_p)
+ {
+ lang_statement_union_type *s = *s_p;
+ lang_statement_union_type *s_next = (*s_p)->header.next;
+
+ switch (s->header.type)
+ {
+ case lang_input_section_enum:
+ if (is_inconsistent_linkonce_section (s->input_section.section))
+ {
+ *s_p = s_next;
+ continue;
+ }
+ break;
+
+ case lang_constructors_statement_enum:
+ xtensa_strip_inconsistent_linkonce_sections (&constructor_list);
+ break;
+
+ case lang_output_section_statement_enum:
+ if (s->output_section_statement.children.head)
+ xtensa_strip_inconsistent_linkonce_sections
+ (&s->output_section_statement.children);
+ break;
+
+ case lang_wild_statement_enum:
+ xtensa_strip_inconsistent_linkonce_sections
+ (&s->wild_statement.children);
+ break;
+
+ case lang_group_statement_enum:
+ xtensa_strip_inconsistent_linkonce_sections
+ (&s->group_statement.children);
+ break;
+
+ case lang_data_statement_enum:
+ case lang_reloc_statement_enum:
+ case lang_object_symbols_statement_enum:
+ case lang_output_statement_enum:
+ case lang_target_statement_enum:
+ case lang_input_statement_enum:
+ case lang_assignment_statement_enum:
+ case lang_padding_statement_enum:
+ case lang_address_statement_enum:
+ case lang_fill_statement_enum:
+ break;
+
+ default:
+ FAIL ();
+ break;
+ }
+
+ s_p = &(*s_p)->header.next;
+ }
+
+ /* Reset the tail of the list, in case the last entry was removed. */
+ if (s_p != slist->tail)
+ slist->tail = s_p;
+}
+
+
static void
xtensa_wild_group_interleave_callback (lang_statement_union_type *statement)
{