Add LMA memory region functionality.
authorTimothy Wall <twall@alum.mit.edu>
Wed, 16 Feb 2000 18:53:32 +0000 (18:53 +0000)
committerTimothy Wall <twall@alum.mit.edu>
Wed, 16 Feb 2000 18:53:32 +0000 (18:53 +0000)
ld/ChangeLog
ld/emultempl/armelf.em
ld/emultempl/elf32.em
ld/emultempl/pe.em
ld/ld.texinfo
ld/ldgram.y
ld/ldlang.c
ld/ldlang.h
ld/mri.c

index 1ceee7ae6d49ac8d8c2933c8a8aa7355c9bdfdd2..da28575c50f348eb3d48789c25fc4637b1a5073c 100644 (file)
@@ -1,3 +1,24 @@
+2000-02-16  Timothy Wall  <twall@cygnus.com>
+
+       * mri.c (mri_draw_tree): Add default LMA region argument to call
+       to lang_leave_output_section_statement.
+       * ldlang.h: Update prototypes with LMA region arguments.
+       * ldlang.c (lang_size_sections): Encapsulate region bounds
+       checking in os_check_region call.
+       (os_check_region): New function.
+       (lang_output_section_statement_lookup): Initialize lma_region.
+       (lang_leave_output_section_statement): Add LMA region argument.
+       (lang_leave_overlay): Ditto.
+       * ldgram.y: Handle LMA region syntax.
+       * ld.texinfo (Output Section Description): Describe LMA region usage.
+       * emultempl/armelf.em (gld$place_orphan): Add default value for
+       lma region in call to lang_leave_output_statement.
+       * emultempl/elf32.em (gld$place_orphan): Add default value for
+       lma region in call to lang_leave_output_statement.
+       * emultempl/pe.em (gld$place_orphan): Add default value for
+       lma region in call to lang_leave_output_statement.
+       
+       
 2000-02-04  Timothy Wall  <twall@redhat.com>
 
        * ldlang.c (lang_check_section_addresses): Use bytes instead of
index 345b12ce50ba462e5fae597677e4dbd9136ab947..f6d5ef4b27710baf85296185b7d50a56e1ab99ff 100644 (file)
@@ -942,7 +942,8 @@ gld${EMULATION_NAME}_place_orphan (file, s)
   wild_doit (&os->children, s, os, file);
 
   lang_leave_output_section_statement
-    ((bfd_vma) 0, "*default*", (struct lang_output_section_phdr_list *) NULL);
+    ((bfd_vma) 0, "*default*", (struct lang_output_section_phdr_list *) NULL,
+     "*default*");
   stat_ptr = &add;
 
   if (*ps == '\0' && config.build_constructors)
index f2ff4d89b231501f91193bd2971b059b837c3d87..78676e11fe33ba790e8ca9e70b0752e2d503cb60 100644 (file)
@@ -1024,7 +1024,8 @@ gld${EMULATION_NAME}_place_orphan (file, s)
   wild_doit (&os->children, s, os, file);
 
   lang_leave_output_section_statement
-    ((bfd_vma) 0, "*default*", (struct lang_output_section_phdr_list *) NULL);
+    ((bfd_vma) 0, "*default*", (struct lang_output_section_phdr_list *) NULL,
+     "*default*");
   stat_ptr = &add;
 
   if (*ps == '\0' && config.build_constructors)
index 1ebc0910b335b3a25e436908405628ca0292a4a7..0112c4667897c6f21b228fcc8ee0de1d88842b59 100644 (file)
@@ -1146,7 +1146,8 @@ gld_${EMULATION_NAME}_place_orphan (file, s)
 
       lang_leave_output_section_statement
        ((bfd_vma) 0, "*default*",
-        (struct lang_output_section_phdr_list *) NULL);
+        (struct lang_output_section_phdr_list *) NULL,
+       "*default*");
 
       /* Now stick the new statement list right after PLACE.  */
       if (place != NULL)
index a786dd2c7520522ce03fe1592d6dc285960404e4..8ecdef2ba04daefa1fa45ca3d9a0d7f49e463f7f 100644 (file)
@@ -2127,7 +2127,7 @@ The full description of an output section looks like this:
     @var{output-section-command}
     @var{output-section-command}
     @dots{}
-  @} [>@var{region}] [:@var{phdr} :@var{phdr} @dots{}] [=@var{fillexp}]
+  @} [>@var{region}] [AT>@var{lma_region}] [:@var{phdr} :@var{phdr} @dots{}] [=@var{fillexp}]
 @end group
 @end smallexample
 
@@ -2632,7 +2632,7 @@ like this:
     @var{output-section-command}
     @var{output-section-command}
     @dots{}
-  @} [>@var{region}] [:@var{phdr} :@var{phdr} @dots{}] [=@var{fillexp}]
+  @} [>@var{region}] [AT>@var{lma_region}] [:@var{phdr} :@var{phdr} @dots{}] [=@var{fillexp}]
 @end group
 @end smallexample
 We've already described @var{section}, @var{address}, and
@@ -2686,6 +2686,7 @@ SECTIONS @{
 
 @node Output Section LMA
 @subsubsection Output section LMA
+@kindex AT>@var{lma_region}
 @kindex AT(@var{lma})
 @cindex load address
 @cindex section load address
@@ -2696,7 +2697,9 @@ Address}).
 
 The linker will normally set the LMA equal to the VMA.  You can change
 that by using the @code{AT} keyword.  The expression @var{lma} that
-follows the @code{AT} keyword specifies the load address of the section.
+follows the @code{AT} keyword specifies the load address of the
+section.  Alternatively, with @samp{AT>@var{lma_region}} expression,
+you may specify a memory region for the section's load address. @xref{MEMORY}.
 
 @cindex ROM initialized data
 @cindex initialized data in ROM
index 73ee4952f55c3237a5972b6288630d037f5d0709..718981281576188e9ca4d6d0ec1e99df39c901cf 100644 (file)
@@ -92,6 +92,7 @@ static int error_index;
 %type <integer> fill_opt
 %type <name_list> exclude_name_list
 %type <name> memspec_opt casesymlist
+%type <name> memspec_at_opt
 %type <cname> wildcard_name
 %type <wildcard> wildcard_spec
 %token <integer> INT  
@@ -799,6 +800,11 @@ exp        :
        ;
 
 
+memspec_at_opt:
+                AT '>' NAME { $$ = $3; }
+        |       { $$ = "*default*"; }
+        ;
+
 opt_at:
                AT '(' exp ')' { $$ = $3; }
        |       { $$ = 0; }
@@ -815,10 +821,10 @@ section:  NAME            { ldlex_expression(); }
                        }
                statement_list_opt      
                '}' { ldlex_popstate (); ldlex_expression (); }
-               memspec_opt phdr_opt fill_opt
+               memspec_opt memspec_at_opt phdr_opt fill_opt
                {
                  ldlex_popstate ();
-                 lang_leave_output_section_statement ($13, $11, $12);
+                 lang_leave_output_section_statement ($14, $11, $13, $12);
                }
                opt_comma
        |       OVERLAY
@@ -832,10 +838,10 @@ section:  NAME            { ldlex_expression(); }
                overlay_section
                '}'
                        { ldlex_popstate (); ldlex_expression (); }
-               memspec_opt phdr_opt fill_opt
+               memspec_opt memspec_at_opt phdr_opt fill_opt
                        {
                          ldlex_popstate ();
-                         lang_leave_overlay ($14, $12, $13);
+                         lang_leave_overlay ($15, $12, $14, $13);
                        }
                opt_comma
        |       /* The GROUP case is just enough to support the gcc
index 6913a38e0667190d676c336167ce3171b4d4d403..a514ea0affd596bea029d7ffb05edc0db3bc7262 100644 (file)
@@ -682,6 +682,7 @@ lang_output_section_statement_lookup (name)
       lookup = (lang_output_section_statement_type *)
        new_stat (lang_output_section_statement, stat_ptr);
       lookup->region = (lang_memory_region_type *) NULL;
+      lookup->lma_region = (lang_memory_region_type *) NULL;
       lookup->fill = 0;
       lookup->block_value = 1;
       lookup->name = name;
@@ -2695,6 +2696,43 @@ _("%X%P: section %s [%V -> %V] overlaps section %s [%V -> %V]\n"),
 
 static boolean relax_again;
 
+/* Make sure the new address is within the region.  We explicitly permit the
+   current address to be at the exact end of the region when the address is
+   non-zero, in case the region is at the end of addressable memory and the
+   calculation wraps around.  */ 
+
+static void
+os_region_check (os, region, tree, base)
+  lang_output_section_statement_type *os;
+  struct memory_region_struct *region;
+  etree_type *tree;
+  bfd_vma base;
+{
+  if ((region->current < region->origin
+       || (region->current - region->origin > region->length))
+      && ((region->current != region->origin + region->length)
+           || base == 0))
+    {
+      if (tree != (etree_type *) NULL)
+        {
+          einfo (_("%X%P: address 0x%v of %B section %s is not within region %s\n"),
+                 region->current,
+                 os->bfd_section->owner,
+                 os->bfd_section->name,
+                 region->name);
+        }
+      else
+        {
+          einfo (_("%X%P: region %s is full (%B section %s)\n"),
+                 region->name,
+                 os->bfd_section->owner,
+                 os->bfd_section->name);
+        }
+      /* Reset the region pointer.  */
+      region->current = region->origin;
+    }
+}
+
 /* Set the sizes for all the output sections.  */
 
 bfd_vma
@@ -2853,37 +2891,35 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
              {
                os->region->current = dot;
                
-               /* Make sure the new address is within the region.  We
-                   explicitly permit the current address to be at the
-                   exact end of the region when the VMA is non-zero,
-                   in case the region is at the end of addressable
-                   memory and the calculation wraps around.  */
-               if ((os->region->current < os->region->origin
-                    || (os->region->current - os->region->origin
-                        > os->region->length))
-                   && ((os->region->current
-                        != os->region->origin + os->region->length)
-                       || os->bfd_section->vma == 0))
-
-                 {
-                   if (os->addr_tree != (etree_type *) NULL)
-                     {
-                       einfo (_("%X%P: address 0x%v of %B section %s is not within region %s\n"),
-                              os->region->current,
-                              os->bfd_section->owner,
-                              os->bfd_section->name,
-                              os->region->name);
-                     }
-                   else
-                     {
-                       einfo (_("%X%P: region %s is full (%B section %s)\n"),
-                              os->region->name,
-                              os->bfd_section->owner,
-                              os->bfd_section->name);
-                     }
-                   /* Reset the region pointer.  */
-                   os->region->current = os->region->origin;
-                 }
+               /* Make sure the new address is within the region.  */
+                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)
+                  {
+                    if (os->load_base != NULL)
+                      {
+                        einfo (_("%X%P: use an absolute load address or a load memory region, not both\n"));
+                      }
+                    else
+                      {
+                        /* don't allocate twice */
+                        if (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 += 
+                              os->bfd_section->_raw_size / opb;
+                            os_region_check (os, os->lma_region, NULL,
+                                             os->bfd_section->lma);
+                          }
+                      }
+                  }
              }
          }
          break;
@@ -4259,13 +4295,22 @@ lang_float (maybe)
 }
 
 void
-lang_leave_output_section_statement (fill, memspec, phdrs)
+lang_leave_output_section_statement (fill, memspec, phdrs, lma_memspec)
      bfd_vma fill;
      const char *memspec;
      struct lang_output_section_phdr_list *phdrs;
+     const char *lma_memspec;
 {
   current_section->fill = fill;
   current_section->region = lang_memory_region_lookup (memspec);
+  if (strcmp (lma_memspec, "*default*") != 0)
+    {
+      current_section->lma_region = lang_memory_region_lookup (lma_memspec);
+      /* if no runtime region has been given, but the load region has been,
+         use the load region */
+      if (strcmp (memspec, "*default*") == 0)
+        current_section->region = lang_memory_region_lookup (lma_memspec);
+    }
   current_section->phdrs = phdrs;
   stat_ptr = &statement_list;
 }
@@ -4644,7 +4689,8 @@ lang_leave_overlay_section (fill, phdrs)
 
   name = current_section->name;
 
-  lang_leave_output_section_statement (fill, "*default*", phdrs);
+  lang_leave_output_section_statement (fill, "*default*", 
+                                       phdrs, "*default*");
 
   /* Define the magic symbols.  */
 
@@ -4674,12 +4720,14 @@ lang_leave_overlay_section (fill, phdrs)
    looks through all the sections in the overlay and sets them.  */
 
 void
-lang_leave_overlay (fill, memspec, phdrs)
+lang_leave_overlay (fill, memspec, phdrs, lma_memspec)
      bfd_vma fill;
      const char *memspec;
      struct lang_output_section_phdr_list *phdrs;
+     const char *lma_memspec;
 {
   lang_memory_region_type *region;
+  lang_memory_region_type *lma_region;
   struct overlay_list *l;
   struct lang_nocrossref *nocrossref;
 
@@ -4688,6 +4736,11 @@ lang_leave_overlay (fill, memspec, phdrs)
   else
     region = lang_memory_region_lookup (memspec);
 
+  if (lma_memspec == NULL)
+    lma_region = NULL;
+  else
+    lma_region = lang_memory_region_lookup (lma_memspec);
+
   nocrossref = NULL;
 
   l = overlay_list;
@@ -4699,6 +4752,8 @@ lang_leave_overlay (fill, memspec, phdrs)
        l->os->fill = fill;
       if (region != NULL && l->os->region == NULL)
        l->os->region = region;
+      if (lma_region != NULL && l->os->lma_region == NULL)
+        l->os->lma_region = lma_region;
       if (phdrs != NULL && l->os->phdrs == NULL)
        l->os->phdrs = phdrs;
 
index 41ef5bac01c7c10a3661dcb828ea9fed88e973c3..068cd96ac840825c6622e5415043f1e108b512f7 100644 (file)
@@ -136,6 +136,7 @@ typedef struct lang_output_section_statement_struct
   flagword flags;              /* Or together of all input sections */
   enum section_type sectype;
   struct memory_region_struct *region;
+  struct memory_region_struct *lma_region;
   size_t block_value;
   fill_type fill;
 
@@ -409,7 +410,8 @@ extern void lang_add_attribute PARAMS ((enum statement_enum));
 extern void lang_startup PARAMS ((const char *));
 extern void lang_float PARAMS ((enum bfd_boolean));
 extern void lang_leave_output_section_statement
-  PARAMS ((bfd_vma, const char *, struct lang_output_section_phdr_list *));
+  PARAMS ((bfd_vma, const char *, struct lang_output_section_phdr_list *,
+           const char *));
 extern void lang_abs_symbol_at_end_of PARAMS ((const char *, const char *));
 extern void lang_abs_symbol_at_beginning_of PARAMS ((const char *,
                                                     const char *));
@@ -475,7 +477,8 @@ extern void lang_enter_overlay_section PARAMS ((const char *));
 extern void lang_leave_overlay_section
   PARAMS ((bfd_vma, struct lang_output_section_phdr_list *));
 extern void lang_leave_overlay
-  PARAMS ((bfd_vma, const char *, struct lang_output_section_phdr_list *));
+  PARAMS ((bfd_vma, const char *, struct lang_output_section_phdr_list *,
+           const char *));
 
 extern struct bfd_elf_version_tree *lang_elf_version_info;
 
index 54aaea29407f52ecbcbea9b0c273e4239209af09..d39186c61008505409a2073f68d64d9fbd788c35 100644 (file)
--- a/ld/mri.c
+++ b/ld/mri.c
@@ -266,7 +266,8 @@ mri_draw_tree ()
       }
 
       lang_leave_output_section_statement
-       (0, "*default*", (struct lang_output_section_phdr_list *) NULL);
+       (0, "*default*", (struct lang_output_section_phdr_list *) NULL, 
+         "*default*");
 
       p = p->next;
     }