ld 2.18 --gc-sections bug? (with testcase)

Alan Modra amodra@bigpond.net.au
Sat Sep 8 11:04:00 GMT 2007


This one turns out to be nothing to do with --gc-sections, but a
rather more serious bug.  If an input section with contents is linked
in to a bss output section, the ELF linker currently leaves the output
section as NOBITS.  File space is thus not allocated for the output
section, but a number of places write to the file regardless,
typically trashing the symbol table, string table, or debug sections.

bfd/
	PR ld/2864, ld/5006
	* elf.c (special_sections): Comment typo.
	(elf_fake_sections): Force SHT_PROGBITS for sections that are
	SHT_NOBITS if BFD section flags say they have contents.
ld/
	* ldwrite.c (build_link_order <lang_padding_statement_enum>): Correct
	condition under which we build a bfd_data_link_order.

Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.413
diff -u -p -r1.413 elf.c
--- bfd/elf.c	25 Aug 2007 13:20:41 -0000	1.413
+++ bfd/elf.c	8 Sep 2007 08:07:42 -0000
@@ -2084,7 +2084,7 @@ static const struct bfd_elf_special_sect
 static const struct bfd_elf_special_section *special_sections[] =
 {
   special_sections_b,		/* 'b' */
-  special_sections_c,		/* 'b' */
+  special_sections_c,		/* 'c' */
   special_sections_d,		/* 'd' */
   NULL,				/* 'e' */
   special_sections_f,		/* 'f' */
@@ -2475,16 +2475,28 @@ elf_fake_sections (bfd *abfd, asection *
 
   /* If the section type is unspecified, we set it based on
      asect->flags.  */
+  if ((asect->flags & SEC_GROUP) != 0)
+    sh_type = SHT_GROUP;
+  else if ((asect->flags & SEC_ALLOC) != 0
+	   && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+	       || (asect->flags & SEC_NEVER_LOAD) != 0))
+    sh_type = SHT_NOBITS;
+  else
+    sh_type = SHT_PROGBITS;
+
   if (this_hdr->sh_type == SHT_NULL)
-    {
-      if ((asect->flags & SEC_GROUP) != 0)
-	this_hdr->sh_type = SHT_GROUP;
-      else if ((asect->flags & SEC_ALLOC) != 0
-	       && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
-		   || (asect->flags & SEC_NEVER_LOAD) != 0))
-	this_hdr->sh_type = SHT_NOBITS;
-      else
-	this_hdr->sh_type = SHT_PROGBITS;
+    this_hdr->sh_type = sh_type;
+  else if (this_hdr->sh_type == SHT_NOBITS
+	   && sh_type == SHT_PROGBITS
+	   && (asect->flags & SEC_ALLOC) != 0)
+    {
+      /* Warn if we are changing a NOBITS section to PROGBITS, but
+	 allow the link to proceed.  This can happen when users link
+	 non-bss input sections to bss output sections, or emit data
+	 to a bss output section via a linker script.  */
+      (*_bfd_error_handler)
+	(_("section `%A' type changed to PROGBITS"), asect);
+      this_hdr->sh_type = sh_type;
     }
 
   switch (this_hdr->sh_type)
Index: ld/ldwrite.c
===================================================================
RCS file: /cvs/src/src/ld/ldwrite.c,v
retrieving revision 1.26
diff -u -p -r1.26 ldwrite.c
--- ld/ldwrite.c	6 Jul 2007 14:09:41 -0000	1.26
+++ ld/ldwrite.c	8 Sep 2007 08:08:37 -0000
@@ -270,7 +270,10 @@ build_link_order (lang_statement_union_t
 	output_section = statement->padding_statement.output_section;
 	ASSERT (statement->padding_statement.output_section->owner
 		== output_bfd);
-	if ((output_section->flags & SEC_HAS_CONTENTS) != 0)
+	if (((output_section->flags & SEC_HAS_CONTENTS) != 0
+	     || ((output_section->flags & SEC_LOAD) != 0
+		 && (output_section->flags & SEC_THREAD_LOCAL)))
+	    && (output_section->flags & SEC_NEVER_LOAD) == 0)
 	  {
 	    link_order = bfd_new_link_order (output_bfd, output_section);
 	    link_order->type = bfd_data_link_order;

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list