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]

ld lma assignment


While playing with overlays recently, I noticed an annoying linker
script requirement.  An output section following an overlay must have
its lma specified (with AT or AT>).  As must any section following one
with an lma adjustment, because ld defaults to setting lma equal to
vma and this may cause lma overlap.  So I decided to teach ld how to
track lma assignments, to make following sections have reasonable
default lmas.  In the process I discovered a bug with LOADADDR
expressions, easily fixed, and found that code setting load_base for
orphans and overlays was no longer needed.

BTW, does anyone know why section lmas are set by lang_do_assignhments
rather than lang_size_sections?  If there is no good reason, I'll move
the code so that both vma and lma are set in lang_size_sections.

ld/
	* ldexp.c (fold_name <LOADADDR>): Use the lma.
	* ldlang.h (lang_memory_region_type): Delete old_length.  Add
	last_os.
	* ldlang.c (lang_memory_region_lookup): Init new field.
	(lang_reset_memory_regions): Reset new field.
	(lang_insert_orphan): Don't set load_base.
	(lang_leave_overlay): Likewise.
	(lang_size_sections_1): Delete unnecessary code setting lma_region
	to region.  Correct lma region check.
	(lang_do_assignments_1): Rename output_section_statement parm
	to current_os.  Set lma from previous section in region.
ld/testsuite/
	* ld-scripts/overlay-size-map.d: Update.

Index: ld/ldexp.c
===================================================================
RCS file: /cvs/src/src/ld/ldexp.c,v
retrieving revision 1.60
diff -u -p -r1.60 ldexp.c
--- ld/ldexp.c	19 Jun 2006 13:17:44 -0000	1.60
+++ ld/ldexp.c	26 Jul 2006 01:08:19 -0000
@@ -577,7 +577,8 @@ fold_name (etree_type *tree)
 	  if (os != NULL && os->processed)
 	    {
 	      if (os->load_base == NULL)
-		new_rel (0, NULL, os->bfd_section);
+		new_rel (os->bfd_section->lma - os->bfd_section->vma,
+			 NULL, os->bfd_section);
 	      else
 		exp_fold_tree_1 (os->load_base);
 	    }
Index: ld/ldlang.h
===================================================================
RCS file: /cvs/src/src/ld/ldlang.h,v
retrieving revision 1.63
diff -u -p -r1.63 ldlang.h
--- ld/ldlang.h	20 Jun 2006 16:37:29 -0000	1.63
+++ ld/ldlang.h	26 Jul 2006 01:08:23 -0000
@@ -54,7 +54,7 @@ typedef struct memory_region_struct
   bfd_vma origin;
   bfd_size_type length;
   bfd_vma current;
-  bfd_size_type old_length;
+  union lang_statement_union *last_os;
   flagword flags;
   flagword not_flags;
   bfd_boolean had_full_message;
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.229
diff -u -p -r1.229 ldlang.c
--- ld/ldlang.c	26 Jul 2006 00:42:33 -0000	1.229
+++ ld/ldlang.c	26 Jul 2006 01:08:22 -0000
@@ -1164,16 +1164,17 @@ lang_memory_region_lookup (const char *c
 
   new->name = xstrdup (name);
   new->next = NULL;
-
-  *lang_memory_region_list_tail = new;
-  lang_memory_region_list_tail = &new->next;
   new->origin = 0;
-  new->flags = 0;
-  new->not_flags = 0;
   new->length = ~(bfd_size_type) 0;
   new->current = 0;
+  new->last_os = NULL;
+  new->flags = 0;
+  new->not_flags = 0;
   new->had_full_message = FALSE;
 
+  *lang_memory_region_list_tail = new;
+  lang_memory_region_list_tail = &new->next;
+
   return new;
 }
 
@@ -1462,7 +1463,6 @@ lang_insert_orphan (asection *s,
   lang_statement_list_type *old;
   lang_statement_list_type add;
   const char *ps;
-  etree_type *load_base;
   lang_output_section_statement_type *os;
   lang_output_section_statement_type **os_tail;
 
@@ -1506,20 +1506,10 @@ lang_insert_orphan (asection *s,
   if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
     address = exp_intop (0);
 
-  load_base = NULL;
-  if (after != NULL && after->load_base != NULL)
-    {
-      etree_type *lma_from_vma;
-      lma_from_vma = exp_binop ('-', after->load_base,
-				exp_nameop (ADDR, after->name));
-      load_base = exp_binop ('+', lma_from_vma,
-			     exp_nameop (ADDR, secname));
-    }
-
   os_tail = ((lang_output_section_statement_type **)
 	     lang_output_section_statement.tail);
   os = lang_enter_output_section_statement (secname, address, 0, NULL, NULL,
-					    load_base, 0);
+					    NULL, 0);
 
   if (add_child == NULL)
     add_child = &os->children;
@@ -4417,20 +4407,16 @@ lang_size_sections_1
 		  os_region_check (os, os->region, os->addr_tree,
 				   os->bfd_section->vma);
 
-		/* If there's no load address specified, use the run
-		   region as the load region.  */
-		if (os->lma_region == NULL && os->load_base == NULL)
-		  os->lma_region = os->region;
-
 		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);
+
 		    if (check_regions)
 		      os_region_check (os, os->lma_region, NULL,
-				       os->bfd_section->lma);
+				       os->lma_region->current);
 		  }
 	      }
 	  }
@@ -4709,11 +4695,10 @@ lang_size_sections (bfd_boolean *relax, 
 /* Worker function for lang_do_assignments.  Recursiveness goes here.  */
 
 static bfd_vma
-lang_do_assignments_1
-  (lang_statement_union_type *s,
-   lang_output_section_statement_type *output_section_statement,
-   fill_type *fill,
-   bfd_vma dot)
+lang_do_assignments_1 (lang_statement_union_type *s,
+		       lang_output_section_statement_type *current_os,
+		       fill_type *fill,
+		       bfd_vma dot)
 {
   for (; s != NULL; s = s->header.next)
     {
@@ -4721,9 +4706,7 @@ lang_do_assignments_1
 	{
 	case lang_constructors_statement_enum:
 	  dot = lang_do_assignments_1 (constructor_list.head,
-				       output_section_statement,
-				       fill,
-				       dot);
+				       current_os, fill, dot);
 	  break;
 
 	case lang_output_section_statement_enum:
@@ -4733,22 +4716,61 @@ lang_do_assignments_1
 	    os = &(s->output_section_statement);
 	    if (os->bfd_section != NULL && !os->ignored)
 	      {
+		lang_memory_region_type *r;
+
 		dot = os->bfd_section->vma;
-		lang_do_assignments_1 (os->children.head, os, os->fill, dot);
+		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);
+
 		/* .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);
-	      }
-	    if (os->load_base)
-	      {
-		/* If nothing has been placed into the output section then
-		   it won't have a bfd_section.  */
-		if (os->bfd_section && !os->ignored)
 		  {
-		    os->bfd_section->lma
-		      = exp_get_abs_int (os->load_base, 0, "load base");
+		    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;
 		  }
 	      }
 	  }
@@ -4757,8 +4779,7 @@ lang_do_assignments_1
 	case lang_wild_statement_enum:
 
 	  dot = lang_do_assignments_1 (s->wild_statement.children.head,
-				       output_section_statement,
-				       fill, dot);
+				       current_os, fill, dot);
 	  break;
 
 	case lang_object_symbols_statement_enum:
@@ -4827,7 +4848,7 @@ lang_do_assignments_1
 
 	case lang_assignment_statement_enum:
 	  exp_fold_tree (s->assignment_statement.exp,
-			 output_section_statement->bfd_section,
+			 current_os->bfd_section,
 			 &dot);
 	  break;
 
@@ -4837,8 +4858,7 @@ lang_do_assignments_1
 
 	case lang_group_statement_enum:
 	  dot = lang_do_assignments_1 (s->group_statement.children.head,
-				       output_section_statement,
-				       fill, dot);
+				       current_os, fill, dot);
 	  break;
 
 	default:
@@ -5423,8 +5443,8 @@ lang_reset_memory_regions (void)
 
   for (p = lang_memory_region_list; p != NULL; p = p->next)
     {
-      p->old_length = (bfd_size_type) (p->current - p->origin);
       p->current = p->origin;
+      p->last_os = NULL;
     }
 
   for (os = &lang_output_section_statement.head->output_section_statement;
@@ -6350,10 +6370,6 @@ lang_leave_overlay (etree_type *lma_expr
 	 an LMA region was specified.  */
       if (l->next == 0)
 	l->os->load_base = lma_expr;
-      else if (lma_region == 0)
-	l->os->load_base = exp_binop ('+',
-				      exp_nameop (LOADADDR, l->next->os->name),
-				      exp_nameop (SIZEOF, l->next->os->name));
 
       if (phdrs != NULL && l->os->phdrs == NULL)
 	l->os->phdrs = phdrs;
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.1
diff -u -p -r1.1 overlay-size-map.d
--- ld/testsuite/ld-scripts/overlay-size-map.d	7 May 2002 11:08:57 -0000	1.1
+++ ld/testsuite/ld-scripts/overlay-size-map.d	26 Jul 2006 01:08:25 -0000
@@ -1,9 +1,9 @@
 #...
 \.bss1 *0x0*20000 *0x10
 #...
-\.bss2 *0x0*20000 *0x30 load address 0x0*20010
+\.bss2 *0x0*20000 *0x30
 #...
-\.bss3 *0x0*20000 *0x20 load address 0x0*20040
+\.bss3 *0x0*20000 *0x20
 #...
 \.mtext *0x0*10000 *0x20 load address 0x0*30000
 #...

-- 
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]