This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Xtensa] add LD workaround for inconsistent linkonce sections


This is patch is a workaround for a problem with .gnu.linkonce sections that is better solved by using COMDAT groups. Xtensa "property tables" describing linkonce sections must be kept together with those sections in a link. If a linkonce section is taken from one input file, and the corresponding property table is taken from a different input file, bad things happen. This doesn't normally happen, but it can occur when a particular property table is missing from one input file. (I think an alternate solution would be to require property tables to exist even when they are empty.) When property tables are kept in COMDAT groups with the sections they describe, the whole problem will be nicely avoided. In the meantime, this patch iterates over all the sections included in the link and throws out any property tables that are inconsistent, i.e., that refer to sections from different input files.

Tested with an xtensa-elf build and committed on the mainline.

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.
Index: emultempl/xtensaelf.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/xtensaelf.em,v
retrieving revision 1.11
diff -u -p -r1.11 xtensaelf.em
--- emultempl/xtensaelf.em	27 Dec 2005 22:56:02 -0000	1.11
+++ emultempl/xtensaelf.em	14 Apr 2006 21:19:35 -0000
@@ -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_
 #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)
 {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]