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]

Re: The current linker failed to generate working Linux kernel


On Tue, Aug 15, 2006 at 06:10:42PM -0700, H. J. Lu wrote:
> FYI, I opened a linker bug
> 
> http://sources.redhat.com/bugzilla/show_bug.cgi?id=3052
> 
> The current linker failed to generate working Linux 2.6 x86-64 kernel.
> There is a small testcase in the bug report.

The kernel script is invalid because it moves dot backwards.  Sigh.

This patch moves the code the sets section lmas from lang_do_assignments
to lang_size_sections, which I think is a more natural place to do
this.  I've also tweaked the lma code to fall back to lma == vma if dot
moves backwards, for compatibility with buggy ld scripts.

ld/
	PR 3052
	* ldlang.h (lang_output_section_statement_type): Replace
	"processed" field with "processed_vma" and "processed_lma".
	* ldlang.c (lang_do_assignments_1): Move lma setting code..
	(lang_size_sections_1): ..to here.
	(lang_reset_memory_regions): Adjust for
	lang_output_section_statement_type change.
	* ldexp.c (fold_name): Likewise.

And this is something I forgot the check in from the previous patch.

ld/testsuite/
	* ld-scripts/overlay-size-map.d: Adjust.

Index: ld/ldlang.h
===================================================================
RCS file: /cvs/src/src/ld/ldlang.h,v
retrieving revision 1.65
diff -u -p -r1.65 ldlang.h
--- ld/ldlang.h	8 Aug 2006 16:08:47 -0000	1.65
+++ ld/ldlang.h	16 Aug 2006 08:03:00 -0000
@@ -150,7 +150,8 @@ typedef struct lang_output_section_state
   int constraint;
   flagword flags;
   enum section_type sectype;
-  unsigned int processed : 1;
+  unsigned int processed_vma : 1;
+  unsigned int processed_lma : 1;
   unsigned int all_input_readonly : 1;
   unsigned int ignored : 1; 
 } lang_output_section_statement_type;
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.233
diff -u -p -r1.233 ldlang.c
--- ld/ldlang.c	8 Aug 2006 16:08:47 -0000	1.233
+++ ld/ldlang.c	16 Aug 2006 08:02:59 -0000
@@ -4228,11 +4228,12 @@ lang_size_sections_1
 	  {
 	    bfd_vma newdot, after;
 	    lang_output_section_statement_type *os;
+	    lang_memory_region_type *r;
 
 	    os = &s->output_section_statement;
 	    if (os->addr_tree != NULL)
 	      {
-		os->processed = FALSE;
+		os->processed_vma = FALSE;
 		exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
 
 		if (!expld.result.valid_p
@@ -4361,24 +4362,90 @@ lang_size_sections_1
 	    lang_size_sections_1 (os->children.head, os, &os->children.head,
 				  os->fill, newdot, relax, check_regions);
 
-	    os->processed = TRUE;
+	    os->processed_vma = TRUE;
 
 	    if (bfd_is_abs_section (os->bfd_section) || os->ignored)
+	      ASSERT (os->bfd_section->size == 0);
+	    else
 	      {
-		ASSERT (os->bfd_section->size == 0);
-		break;
+		dot = os->bfd_section->vma;
+
+		/* Put the section within the requested block size, or
+		   align at the block boundary.  */
+		after = ((dot
+			  + TO_ADDR (os->bfd_section->size)
+			  + os->block_value - 1)
+			 & - (bfd_vma) os->block_value);
+
+		os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma);
+	      }
+
+	    /* Set section lma.  */
+	    r = os->region;
+	    if (r == NULL)
+	      r = lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
+
+	    if (os->load_base)
+	      {
+		bfd_vma lma = exp_get_abs_int (os->load_base, 0, "load base");
+		os->bfd_section->lma = lma;
+	      }
+	    else if (os->region != NULL
+		     && os->lma_region != NULL
+		     && os->lma_region != os->region)
+	      {
+		bfd_vma lma = os->lma_region->current;
+
+		if (os->section_alignment != -1)
+		  lma = align_power (lma, os->section_alignment);
+		os->bfd_section->lma = lma;
 	      }
+	    else if (r->last_os != NULL)
+	      {
+		bfd_vma lma;
+		asection *last;
+
+		last = r->last_os->output_section_statement.bfd_section;
+		/* If dot moved backwards (which is invalid according
+		   to ld docs) then leave lma equal to vma.  This
+		   keeps users of buggy ld scripts happy.  */
+		if (dot >= last->vma)
+		  {
+		    /* If the current vma overlaps the previous section,
+		       then set the current lma to that at the end of
+		       the previous section.  The previous section was
+		       probably an overlay.  */
+		    if ((dot >= last->vma
+			 && dot < last->vma + last->size)
+			|| (last->vma >= dot
+			    && last->vma < dot + os->bfd_section->size))
+		      lma = last->lma + last->size;
 
-	    dot = os->bfd_section->vma;
+		    /* Otherwise, keep the same lma to vma relationship
+		       as the previous section.  */
+		    else
+		      lma = dot + last->lma - last->vma;
+
+		    if (os->section_alignment != -1)
+		      lma = align_power (lma, os->section_alignment);
+		    os->bfd_section->lma = lma;
+		  }
+	      }
+	    os->processed_lma = TRUE;
 
-	    /* Put the section within the requested block size, or
-	       align at the block boundary.  */
-	    after = ((dot
-		      + TO_ADDR (os->bfd_section->size)
-		      + os->block_value - 1)
-		     & - (bfd_vma) os->block_value);
+	    if (bfd_is_abs_section (os->bfd_section) || os->ignored)
+	      break;
 
-	    os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma);
+	    /* Keep track of normal sections using the default
+	       lma region.  We use this to set the lma for
+	       following sections.  Overlays or other linker
+	       script assignment to lma might mean that the
+	       default lma == vma is incorrect.  */
+	    if (((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
+		 || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0)
+		&& os->lma_region == NULL
+		&& !link_info.relocatable)
+	      r->last_os = s;
 
 	    /* .tbss sections effectively have zero size.  */
 	    if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
@@ -4410,14 +4477,12 @@ lang_size_sections_1
 
 		if (os->lma_region != NULL && os->lma_region != os->region)
 		  {
-		    /* Set load_base, which will be handled later.  */
-		    os->load_base = exp_intop (os->lma_region->current);
-		    os->lma_region->current +=
-		      TO_ADDR (os->bfd_section->size);
+		    os->lma_region->current
+		      = os->bfd_section->lma + TO_ADDR (os->bfd_section->size);
 
 		    if (check_regions)
 		      os_region_check (os, os->lma_region, NULL,
-				       os->lma_region->current);
+				       os->bfd_section->lma);
 		  }
 	      }
 	  }
@@ -4717,62 +4782,15 @@ lang_do_assignments_1 (lang_statement_un
 	    os = &(s->output_section_statement);
 	    if (os->bfd_section != NULL && !os->ignored)
 	      {
-		lang_memory_region_type *r;
-
 		dot = os->bfd_section->vma;
-		r = os->region;
-		if (r == NULL)
-		  r = lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
-
-		if (os->load_base)
-		  os->bfd_section->lma
-		    = exp_get_abs_int (os->load_base, 0, "load base");
-		else if (r->last_os != NULL)
-		  {
-		    asection *last;
-		    bfd_vma lma;
-
-		    last = r->last_os->output_section_statement.bfd_section;
-
-		    /* If the current vma overlaps the previous section,
-		       then set the current lma to that at the end of
-		       the previous section.  The previous section was
-		       probably an overlay.  */
-		    if ((dot >= last->vma
-			 && dot < last->vma + last->size)
-			|| (last->vma >= dot
-			    && last->vma < dot + os->bfd_section->size))
-		      lma = last->lma + last->size;
-
-		    /* Otherwise, keep the same lma to vma relationship
-		       as the previous section.  */
-		    else
-		      lma = dot + last->lma - last->vma;
-
-		    if (os->section_alignment != -1)
-		      lma = align_power (lma, os->section_alignment);
-		    os->bfd_section->lma = lma;
-		  }
 
-		lang_do_assignments_1 (os->children.head,
-				       os, os->fill, dot);
+		lang_do_assignments_1 (os->children.head, os, os->fill, dot);
 
 		/* .tbss sections effectively have zero size.  */
 		if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
 		    || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
 		    || link_info.relocatable)
-		  {
-		    dot += TO_ADDR (os->bfd_section->size);
-
-		    /* Keep track of normal sections using the default
-		       lma region.  We use this to set the lma for
-		       following sections.  Overlays or other linker
-		       script assignment to lma might mean that the
-		       default lma == vma is incorrect.  */
-		    if (!link_info.relocatable
-			&& os->lma_region == NULL)
-		      r->last_os = s;
-		  }
+		  dot += TO_ADDR (os->bfd_section->size);
 	      }
 	  }
 	  break;
@@ -5451,7 +5469,10 @@ lang_reset_memory_regions (void)
   for (os = &lang_output_section_statement.head->output_section_statement;
        os != NULL;
        os = os->next)
-    os->processed = FALSE;
+    {
+      os->processed_vma = FALSE;
+      os->processed_lma = FALSE;
+    }
 
   for (o = output_bfd->sections; o != NULL; o = o->next)
     {
Index: ld/ldexp.c
===================================================================
RCS file: /cvs/src/src/ld/ldexp.c,v
retrieving revision 1.61
diff -u -p -r1.61 ldexp.c
--- ld/ldexp.c	26 Jul 2006 05:05:52 -0000	1.61
+++ ld/ldexp.c	16 Aug 2006 08:02:56 -0000
@@ -563,7 +563,7 @@ fold_name (etree_type *tree)
 	  lang_output_section_statement_type *os;
 
 	  os = lang_output_section_find (tree->name.name);
-	  if (os != NULL && os->processed)
+	  if (os != NULL && os->processed_vma)
 	    new_rel (0, NULL, os->bfd_section);
 	}
       break;
@@ -574,7 +574,7 @@ fold_name (etree_type *tree)
 	  lang_output_section_statement_type *os;
 
 	  os = lang_output_section_find (tree->name.name);
-	  if (os != NULL && os->processed)
+	  if (os != NULL && os->processed_lma)
 	    {
 	      if (os->load_base == NULL)
 		new_rel (os->bfd_section->lma - os->bfd_section->vma,
@@ -594,7 +594,7 @@ fold_name (etree_type *tree)
 	  os = lang_output_section_find (tree->name.name);
 	  if (os == NULL)
 	    new_abs (0);
-	  else if (os->processed)
+	  else if (os->processed_vma)
 	    new_abs (os->bfd_section->size / opb);
 	}
       break;
Index: ld/testsuite/ld-scripts/overlay-size-map.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-scripts/overlay-size-map.d,v
retrieving revision 1.2
diff -u -p -r1.2 overlay-size-map.d
--- ld/testsuite/ld-scripts/overlay-size-map.d	26 Jul 2006 05:10:05 -0000	1.2
+++ ld/testsuite/ld-scripts/overlay-size-map.d	16 Aug 2006 08:03:02 -0000
@@ -5,19 +5,19 @@
 #...
 \.bss3 *0x0*20000 *0x20
 #...
-\.mtext *0x0*10000 *0x20 load address 0x0*30000
+\.mtext *0x0*10000 *0x20
 #...
 \.mbss *0x0*20030 *0x230 load address 0x0*20060
 #...
-\.text1 *0x0*10020 *0x80 load address 0x0*30020
+\.text1 *0x0*10020 *0x80
 #...
-\.text2 *0x0*10020 *0x40 load address 0x0*300a0
+\.text2 *0x0*10020 *0x40
 #...
-\.text3 *0x0*10020 *0x20 load address 0x0*300e0
+\.text3 *0x0*10020 *0x20
 #...
-\.data1 *0x0*20260 *0x30 load address 0x0*30100
+\.data1 *0x0*20260 *0x30
 #...
-\.data2 *0x0*20260 *0x40 load address 0x0*30130
+\.data2 *0x0*20260 *0x40
 #...
-\.data3 *0x0*20260 *0x50 load address 0x0*30170
+\.data3 *0x0*20260 *0x50
 #pass

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


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