* emultempl/xtensaelf.em (elf_xtensa_before_allocation): Call new
authorBob Wilson <bob.wilson@acm.org>
Fri, 14 Apr 2006 21:31:16 +0000 (21:31 +0000)
committerBob Wilson <bob.wilson@acm.org>
Fri, 14 Apr 2006 21:31:16 +0000 (21:31 +0000)
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.

ld/ChangeLog
ld/emultempl/xtensaelf.em

index bbadba4..f8b1e9f 100644 (file)
@@ -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
index 16feed1..f5d2ba9 100644 (file)
@@ -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)
 {