ld/
authorAlan Modra <amodra@gmail.com>
Thu, 14 Oct 2004 12:54:47 +0000 (12:54 +0000)
committerAlan Modra <amodra@gmail.com>
Thu, 14 Oct 2004 12:54:47 +0000 (12:54 +0000)
PR 63
* ldlang.h (lang_output_section_statement_type): Make "next" a
struct lang_output_section_statement_struct *.
(struct orphan_save): Move from elf32.em.  Add "name" and "flags".
(lang_output_section_find_by_flags, lang_insert_orphan): Declare.
* ldlang.c (lang_output_section_find_1): Adjust for changed
output_section_statement "next".
(strip_excluded_output_sections): Likewise.
(lang_record_phdrs): Likewise.
(lang_output_section_find_by_flags): New function.
(output_prev_sec_find): Move from pe.em.  Adjust iterator.
(lang_insert_orphan): New function.  Tail end of elf32.em's
place_orphan merged with that from pe.em.  Allow bfd_section to
be placed first.  New heuristic for placing new output section
statement in existing script, and accompanying split of __start
symbol alignment into a separate assignment to dot.
(lang_add_section): Consistently use output->bfd_section rather than
an alias, section->output_section.
(map_input_to_output_sections): Rename overly long arg.  Move
initialization of data_statement output section to here..
(lang_check_section_addresses): ..from here.
(print_assignment): Correct printing of etree_assert.
(print_all_symbols): Don't bomb if userdata is NULL.
(IGNORE_SECTION): Rearrange.
* emultempl/elf32.em (output_rel_find): Adjust interator.
(output_prev_sec_find): Delete.
(struct orphan_save): Delete.
(gld${EMULATION_NAME}_place_orphan): Cater for zero bfd_section
flags without creating a duplicate output section statement.
Revise code holding history of various orphan section placements.
Allow orphan sections to place before script specified output
sections.  Call lang_output_section_find_by_flags when placement
by name fails.  Use lang_insert_orphan.
* emultempl/mmo.em (output_prev_sec_find): Delete.
(struct orphan_save): Delete.
(mmo_place_orphan): Revise code holding history of orphan placement.
Allow orphans to place before existing output sections.  Use
lang_insert_orphan.
* emultempl/pe.em (output_prev_sec_find): Delete.
(struct orphan_save): Delete.
(gld_${EMULATION_NAME}_place_orphan): Revise to suit use of
lang_insert_orphan.
ld/testsuite/
* ld-scripts/overlay-size.d: Update for changed orphan section
placement.
* ld-mmix/bpo-18.d: Likewise.

ld/ChangeLog
ld/emultempl/elf32.em
ld/emultempl/mmo.em
ld/emultempl/pe.em
ld/ldlang.c
ld/ldlang.h
ld/testsuite/ChangeLog
ld/testsuite/ld-mmix/bpo-18.d
ld/testsuite/ld-scripts/overlay-size.d

index bc1e142f341b56c61e284440b0cdd2e4b6151915..fc61f7f8ede5373a2f8a98f81c3951e3b1a0545e 100644 (file)
@@ -1,3 +1,48 @@
+2004-10-14  Alan Modra  <amodra@bigpond.net.au>
+
+       PR 63
+       * ldlang.h (lang_output_section_statement_type): Make "next" a
+       struct lang_output_section_statement_struct *.
+       (struct orphan_save): Move from elf32.em.  Add "name" and "flags".
+       (lang_output_section_find_by_flags, lang_insert_orphan): Declare.
+       * ldlang.c (lang_output_section_find_1): Adjust for changed
+       output_section_statement "next".
+       (strip_excluded_output_sections): Likewise.
+       (lang_record_phdrs): Likewise.
+       (lang_output_section_find_by_flags): New function.
+       (output_prev_sec_find): Move from pe.em.  Adjust iterator.
+       (lang_insert_orphan): New function.  Tail end of elf32.em's
+       place_orphan merged with that from pe.em.  Allow bfd_section to
+       be placed first.  New heuristic for placing new output section
+       statement in existing script, and accompanying split of __start
+       symbol alignment into a separate assignment to dot.
+       (lang_add_section): Consistently use output->bfd_section rather than
+       an alias, section->output_section.
+       (map_input_to_output_sections): Rename overly long arg.  Move
+       initialization of data_statement output section to here..
+       (lang_check_section_addresses): ..from here.
+       (print_assignment): Correct printing of etree_assert.
+       (print_all_symbols): Don't bomb if userdata is NULL.
+       (IGNORE_SECTION): Rearrange.
+       * emultempl/elf32.em (output_rel_find): Adjust interator.
+       (output_prev_sec_find): Delete.
+       (struct orphan_save): Delete.
+       (gld${EMULATION_NAME}_place_orphan): Cater for zero bfd_section
+       flags without creating a duplicate output section statement.
+       Revise code holding history of various orphan section placements.
+       Allow orphan sections to place before script specified output
+       sections.  Call lang_output_section_find_by_flags when placement
+       by name fails.  Use lang_insert_orphan.
+       * emultempl/mmo.em (output_prev_sec_find): Delete.
+       (struct orphan_save): Delete.
+       (mmo_place_orphan): Revise code holding history of orphan placement.
+       Allow orphans to place before existing output sections.  Use
+       lang_insert_orphan.
+       * emultempl/pe.em (output_prev_sec_find): Delete.
+       (struct orphan_save): Delete.
+       (gld_${EMULATION_NAME}_place_orphan): Revise to suit use of
+       lang_insert_orphan.
+
 2004-10-13  Mark Mitchell  <mark@codesourcery.com>
 
        * scripttempl/armbpabi.sc: Do not put .gnu.version.* into a
index 6273f0e90c81a824a6da1da33e687a784979207f..f9e2cf962553715c4c6c09afeaf9b9d448fe3a13 100644 (file)
@@ -1172,12 +1172,11 @@ fi
 if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then
 cat >>e${EMULATION_NAME}.c <<EOF
 
-/* A variant of lang_output_section_find.  Used by place_orphan.  */
+/* A variant of lang_output_section_find used by place_orphan.  */
 
 static lang_output_section_statement_type *
 output_rel_find (asection *sec, int isdyn)
 {
-  lang_statement_union_type *u;
   lang_output_section_statement_type *lookup;
   lang_output_section_statement_type *last = NULL;
   lang_output_section_statement_type *last_alloc = NULL;
@@ -1185,9 +1184,10 @@ output_rel_find (asection *sec, int isdyn)
   lang_output_section_statement_type *last_rel_alloc = NULL;
   int rela = sec->name[4] == 'a';
 
-  for (u = lang_output_section_statement.head; u; u = lookup->next)
+  for (lookup = &lang_output_section_statement.head->output_section_statement;
+       lookup != NULL;
+       lookup = lookup->next)
     {
-      lookup = &u->output_section_statement;
       if (lookup->constraint != -1
          && strncmp (".rel", lookup->name, 4) == 0)
        {
@@ -1229,63 +1229,52 @@ output_rel_find (asection *sec, int isdyn)
   return last;
 }
 
-/* Find the last output section before given output statement.
-   Used by place_orphan.  */
-
-static asection *
-output_prev_sec_find (lang_output_section_statement_type *os)
-{
-  asection *s = (asection *) NULL;
-  lang_statement_union_type *u;
-  lang_output_section_statement_type *lookup;
-
-  for (u = lang_output_section_statement.head;
-       u != (lang_statement_union_type *) NULL;
-       u = lookup->next)
-    {
-      lookup = &u->output_section_statement;
-      if (lookup == os)
-       return s;
-
-      if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
-       s = lookup->bfd_section;
-    }
-
-  return NULL;
-}
-
 /* Place an orphan section.  We use this to put random SHF_ALLOC
    sections in the right segment.  */
 
-struct orphan_save {
-  lang_output_section_statement_type *os;
-  asection **section;
-  lang_statement_union_type **stmt;
-  lang_statement_union_type **os_tail;
-};
-
 static bfd_boolean
 gld${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s)
 {
-  static struct orphan_save hold_text;
-  static struct orphan_save hold_rodata;
-  static struct orphan_save hold_data;
-  static struct orphan_save hold_bss;
-  static struct orphan_save hold_rel;
-  static struct orphan_save hold_interp;
-  static struct orphan_save hold_sdata;
-  static int count = 1;
+  static struct orphan_save hold[] =
+    {
+      { ".text",
+       SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE,
+       0, 0, 0, 0 },
+      { ".rodata",
+       SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
+       0, 0, 0, 0 },
+      { ".data",
+       SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA,
+       0, 0, 0, 0 },
+      { ".bss",
+       SEC_ALLOC,
+       0, 0, 0, 0 },
+      { 0,
+       SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
+       0, 0, 0, 0 },
+      { ".interp",
+       SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
+       0, 0, 0, 0 },
+      { ".sdata",
+       SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_SMALL_DATA,
+       0, 0, 0, 0 }
+    };
+  enum orphan_save_index
+    {
+      orphan_text = 0,
+      orphan_rodata,
+      orphan_data,
+      orphan_bss,
+      orphan_rel,
+      orphan_interp,
+      orphan_sdata
+    };
+  static int orphan_init_done = 0;
   struct orphan_save *place;
-  lang_statement_list_type *old;
-  lang_statement_list_type add;
-  etree_type *address;
   const char *secname;
-  const char *ps = NULL;
+  lang_output_section_statement_type *after;
   lang_output_section_statement_type *os;
-  lang_statement_union_type **os_tail;
-  etree_type *load_base;
   int isdyn = 0;
-  asection *sec;
 
   secname = bfd_get_section_name (s->owner, s);
 
@@ -1308,27 +1297,42 @@ gld${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s)
 
       if (os != NULL
          && (os->bfd_section == NULL
+             || os->bfd_section->flags == 0
              || ((s->flags ^ os->bfd_section->flags)
                  & (SEC_LOAD | SEC_ALLOC)) == 0))
        {
          /* We already have an output section statement with this
-            name, and its bfd section, if any, has compatible flags.  */
+            name, and its bfd section, if any, has compatible flags.
+            If the section already exists but does not have any flags
+            set, then it has been created by the linker, probably as a
+            result of a --section-start command line switch.  */
          lang_add_section (&os->children, s, os, file);
          return TRUE;
        }
     }
 
-  if (hold_text.os == NULL)
-    hold_text.os = lang_output_section_find (".text");
+  if (!orphan_init_done)
+    {
+      struct orphan_save *ho;
+      for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho)
+       if (ho->name != NULL)
+         {
+           ho->os = lang_output_section_find (ho->name);
+           if (ho->os != NULL && ho->os->flags == 0)
+             ho->os->flags = ho->flags;
+         }
+      orphan_init_done = 1;
+    }
 
   /* If this is a final link, then always put .gnu.warning.SYMBOL
      sections into the .text section to get them out of the way.  */
   if (link_info.executable
       && ! link_info.relocatable
       && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0
-      && hold_text.os != NULL)
+      && hold[orphan_text].os != NULL)
     {
-      lang_add_section (&hold_text.os->children, s, hold_text.os, file);
+      lang_add_section (&hold[orphan_text].os->children, s,
+                       hold[orphan_text].os, file);
       return TRUE;
     }
 
@@ -1337,220 +1341,57 @@ gld${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s)
      right after the .interp section, so that the PT_NOTE segment is
      stored right after the program headers where the OS can read it
      in the first page.  */
-#define HAVE_SECTION(hold, name) \
-(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
 
   place = NULL;
   if ((s->flags & SEC_ALLOC) == 0)
     ;
   else if ((s->flags & SEC_LOAD) != 0
-          && strncmp (secname, ".note", 5) == 0
-          && HAVE_SECTION (hold_interp, ".interp"))
-    place = &hold_interp;
-  else if ((s->flags & SEC_HAS_CONTENTS) == 0
-          && HAVE_SECTION (hold_bss, ".bss"))
-    place = &hold_bss;
-  else if ((s->flags & SEC_SMALL_DATA) != 0
-          && HAVE_SECTION (hold_sdata, ".sdata"))
-    place = &hold_sdata;
-  else if ((s->flags & SEC_READONLY) == 0
-          && HAVE_SECTION (hold_data, ".data"))
-    place = &hold_data;
+          && strncmp (secname, ".note", 5) == 0)
+    place = &hold[orphan_interp];
+  else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+    place = &hold[orphan_bss];
+  else if ((s->flags & SEC_SMALL_DATA) != 0)
+    place = &hold[orphan_sdata];
+  else if ((s->flags & SEC_READONLY) == 0)
+    place = &hold[orphan_data];
   else if (strncmp (secname, ".rel", 4) == 0
-          && (s->flags & SEC_LOAD) != 0
-          && (hold_rel.os != NULL
-              || (hold_rel.os = output_rel_find (s, isdyn)) != NULL))
-    place = &hold_rel;
-  else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY
-          && HAVE_SECTION (hold_rodata, ".rodata"))
-    place = &hold_rodata;
-  else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY)
-          && hold_text.os != NULL)
-    place = &hold_text;
-
-#undef HAVE_SECTION
-
-  /* Choose a unique name for the section.  This will be needed if the
-     same section name appears in the input file with different
-     loadable or allocatable characteristics.  But if the section
-     already exists but does not have any flags set, then it has been
-     created by the linker, probably as a result of a --section-start
-     command line switch.  */
-  if ((sec = bfd_get_section_by_name (output_bfd, secname)) != NULL
-      && bfd_get_section_flags (output_bfd, sec) != 0)
-    {
-      secname = bfd_get_unique_section_name (output_bfd, secname, &count);
-      if (secname == NULL)
-       einfo ("%F%P: place_orphan failed: %E\n");
-    }
-
-  /* Start building a list of statements for this section.
-     First save the current statement pointer.  */
-  old = stat_ptr;
+          && (s->flags & SEC_LOAD) != 0)
+    place = &hold[orphan_rel];
+  else if ((s->flags & SEC_CODE) == 0)
+    place = &hold[orphan_rodata];
+  else
+    place = &hold[orphan_text];
 
-  /* If we have found an appropriate place for the output section
-     statements for this orphan, add them to our own private list,
-     inserting them later into the global statement list.  */
+  after = NULL;
   if (place != NULL)
     {
-      stat_ptr = &add;
-      lang_list_init (stat_ptr);
-    }
-
-  if (config.build_constructors)
-    {
-      /* If the name of the section is representable in C, then create
-        symbols to mark the start and the end of the section.  */
-      for (ps = secname; *ps != '\0'; ps++)
-       if (! ISALNUM (*ps) && *ps != '_')
-         break;
-      if (*ps == '\0')
+      if (place->os == NULL)
        {
-         char *symname;
-         etree_type *e_align;
-
-         symname = (char *) xmalloc (ps - secname + sizeof "__start_");
-         sprintf (symname, "__start_%s", secname);
-         e_align = exp_unop (ALIGN_K,
-                             exp_intop ((bfd_vma) 1 << s->alignment_power));
-         lang_add_assignment (exp_assop ('=', symname, e_align));
+         if (place->name != NULL)
+           place->os = lang_output_section_find (place->name);
+         else
+           place->os = output_rel_find (s, isdyn);
        }
+      after = place->os;
+      if (after == NULL)
+       after = lang_output_section_find_by_flags (s, &place->os);
+      if (after == NULL)
+       /* *ABS* is always the first output section statement.  */
+       after = &lang_output_section_statement.head->output_section_statement;
     }
 
-  address = NULL;
-  if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
-    address = exp_intop ((bfd_vma) 0);
-
-  load_base = NULL;
-  if (place != NULL && place->os->load_base != NULL)
-    {
-      etree_type *lma_from_vma;
-      lma_from_vma = exp_binop ('-', place->os->load_base,
-                               exp_nameop (ADDR, place->os->name));
-      load_base = exp_binop ('+', lma_from_vma,
-                            exp_nameop (ADDR, secname));
-    }
-
-  os_tail = lang_output_section_statement.tail;
-  os = lang_enter_output_section_statement (secname, address, 0,
-                                           (etree_type *) NULL,
-                                           (etree_type *) NULL,
-                                           load_base, 0);
-
-  lang_add_section (&os->children, s, os, file);
-
-  lang_leave_output_section_statement
-    ((bfd_vma) 0, "*default*",
-     (struct lang_output_section_phdr_list *) NULL, NULL);
-
-  if (config.build_constructors && *ps == '\0')
+  /* Choose a unique name for the section.  This will be needed if the
+     same section name appears in the input file with different
+     loadable or allocatable characteristics.  */
+  if (bfd_get_section_by_name (output_bfd, secname) != NULL)
     {
-      char *symname;
-
-      /* lang_leave_ouput_section_statement resets stat_ptr.  Put
-        stat_ptr back where we want it.  */
-      if (place != NULL)
-       stat_ptr = &add;
-
-      symname = (char *) xmalloc (ps - secname + sizeof "__stop_");
-      sprintf (symname, "__stop_%s", secname);
-      lang_add_assignment (exp_assop ('=', symname,
-                                     exp_nameop (NAME, ".")));
+      static int count = 1;
+      secname = bfd_get_unique_section_name (output_bfd, secname, &count);
+      if (secname == NULL)
+       einfo ("%F%P: place_orphan failed: %E\n");
     }
 
-  /* Restore the global list pointer.  */
-  stat_ptr = old;
-
-  if (place != NULL && os->bfd_section != NULL)
-    {
-      asection *snew, **pps;
-
-      snew = os->bfd_section;
-
-      /* Shuffle the bfd section list to make the output file look
-        neater.  This is really only cosmetic.  */
-      if (place->section == NULL)
-       {
-         asection *bfd_section = place->os->bfd_section;
-
-         /* If the output statement hasn't been used to place
-            any input sections (and thus doesn't have an output
-            bfd_section), look for the closest prior output statement
-            having an output section.  */
-         if (bfd_section == NULL)
-           bfd_section = output_prev_sec_find (place->os);
-
-         if (bfd_section != NULL && bfd_section != snew)
-           place->section = &bfd_section->next;
-       }
-
-      if (place->section != NULL)
-       {
-         /* Unlink the section.  */
-         for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
-           ;
-         bfd_section_list_remove (output_bfd, pps);
-
-         /* Now tack it on to the "place->os" section list.  */
-         bfd_section_list_insert (output_bfd, place->section, snew);
-       }
-
-      /* Save the end of this list.  Further ophans of this type will
-        follow the one we've just added.  */
-      place->section = &snew->next;
-
-      /* The following is non-cosmetic.  We try to put the output
-        statements in some sort of reasonable order here, because
-        they determine the final load addresses of the orphan
-        sections.  In addition, placing output statements in the
-        wrong order may require extra segments.  For instance,
-        given a typical situation of all read-only sections placed
-        in one segment and following that a segment containing all
-        the read-write sections, we wouldn't want to place an orphan
-        read/write section before or amongst the read-only ones.  */
-      if (add.head != NULL)
-       {
-         lang_statement_union_type *newly_added_os;
-
-         if (place->stmt == NULL)
-           {
-             /* Put the new statement list right at the head.  */
-             *add.tail = place->os->header.next;
-             place->os->header.next = add.head;
-
-             place->os_tail = &place->os->next;
-           }
-         else
-           {
-             /* Put it after the last orphan statement we added.  */
-             *add.tail = *place->stmt;
-             *place->stmt = add.head;
-           }
-
-         /* Fix the global list pointer if we happened to tack our
-            new list at the tail.  */
-         if (*old->tail == add.head)
-           old->tail = add.tail;
-
-         /* Save the end of this list.  */
-         place->stmt = add.tail;
-
-         /* Do the same for the list of output section statements.  */
-         newly_added_os = *os_tail;
-         *os_tail = NULL;
-         newly_added_os->output_section_statement.next = *place->os_tail;
-         *place->os_tail = newly_added_os;
-         place->os_tail = &newly_added_os->output_section_statement.next;
-
-         /* Fixing the global list pointer here is a little different.
-            We added to the list in lang_enter_output_section_statement,
-            trimmed off the new output_section_statment above when
-            assigning *os_tail = NULL, but possibly added it back in
-            the same place when assigning *place->os_tail.  */
-         if (*os_tail == NULL)
-           lang_output_section_statement.tail = os_tail;
-       }
-    }
+  lang_insert_orphan (file, s, secname, after, place, NULL, NULL);
 
   return TRUE;
 }
@@ -1603,49 +1444,49 @@ cat >>e${EMULATION_NAME}.c <<EOF
   if (link_info.relocatable && config.build_constructors)
     return
 EOF
-sed $sc ldscripts/${EMULATION_NAME}.xu                 >> e${EMULATION_NAME}.c
-echo '  ; else if (link_info.relocatable) return'     >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xr                 >> e${EMULATION_NAME}.c
-echo '  ; else if (!config.text_read_only) return'     >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xbn                >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xu                 >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.relocatable) return'      >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xr                 >> e${EMULATION_NAME}.c
+echo '  ; else if (!config.text_read_only) return'     >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xbn                        >> e${EMULATION_NAME}.c
 if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : ; else
-echo '  ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xn                 >> e${EMULATION_NAME}.c
+echo '  ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xn                 >> e${EMULATION_NAME}.c
 fi
 if test -n "$GENERATE_PIE_SCRIPT" ; then
 if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
 echo '  ; else if (link_info.pie && link_info.combreloc' >> e${EMULATION_NAME}.c
 echo '             && link_info.relro' >> e${EMULATION_NAME}.c
 echo '             && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xdw                >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xdw                        >> e${EMULATION_NAME}.c
 echo '  ; else if (link_info.pie && link_info.combreloc) return' >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xdc                >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xdc                        >> e${EMULATION_NAME}.c
 fi
-echo '  ; else if (link_info.pie) return'             >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xd                 >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.pie) return'              >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xd                 >> e${EMULATION_NAME}.c
 fi
 if test -n "$GENERATE_SHLIB_SCRIPT" ; then
 if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
 echo '  ; else if (link_info.shared && link_info.combreloc' >> e${EMULATION_NAME}.c
 echo '             && link_info.relro' >> e${EMULATION_NAME}.c
 echo '             && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xsw                >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xsw                        >> e${EMULATION_NAME}.c
 echo '  ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xsc                >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xsc                        >> e${EMULATION_NAME}.c
 fi
-echo '  ; else if (link_info.shared) return'          >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xs                 >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.shared) return'           >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xs                 >> e${EMULATION_NAME}.c
 fi
 if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
 echo '  ; else if (link_info.combreloc && link_info.relro' >> e${EMULATION_NAME}.c
 echo '             && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xw                 >> e${EMULATION_NAME}.c
-echo '  ; else if (link_info.combreloc) return'        >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xc                 >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xw                 >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.combreloc) return'                >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xc                 >> e${EMULATION_NAME}.c
 fi
-echo '  ; else return'                                 >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.x                  >> e${EMULATION_NAME}.c
-echo '; }'                                             >> e${EMULATION_NAME}.c
+echo '  ; else return'                                 >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.x                  >> e${EMULATION_NAME}.c
+echo '; }'                                             >> e${EMULATION_NAME}.c
 
 else
 # Scripts read from the filesystem.
index d6d30e676c0b9da16bb6e62f75523d38ca1f1df8..cbe51082141a9b3c37e887016375fca24f5d5754 100644 (file)
@@ -32,47 +32,6 @@ EOF
 
 cat >>e${EMULATION_NAME}.c <<EOF
 
-/* Find the last output section before given output statement.
-   Used by place_orphan.  */
-
-static asection *
-output_prev_sec_find (lang_output_section_statement_type *os)
-{
-  asection *s = NULL;
-  lang_statement_union_type *u;
-  lang_output_section_statement_type *lookup;
-
-  for (u = lang_output_section_statement.head;
-       u != (lang_statement_union_type *) NULL;
-       u = lookup->next)
-    {
-      lookup = &u->output_section_statement;
-      if (lookup->constraint == -1)
-       continue;
-      if (lookup == os)
-       break;
-      if (lookup->bfd_section != NULL
-         && lookup->bfd_section != bfd_abs_section_ptr
-         && lookup->bfd_section != bfd_com_section_ptr
-         && lookup->bfd_section != bfd_und_section_ptr)
-       s = lookup->bfd_section;
-    }
-
-  if (u == NULL)
-    return NULL;
-
-  return s;
-}
-
-struct orphan_save {
-  lang_output_section_statement_type *os;
-  asection **section;
-  lang_statement_union_type **stmt;
-};
-
-#define HAVE_SECTION(hold, name) \
-(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
-
 /* Place an orphan section.  We use this to put random SEC_CODE or
    SEC_READONLY sections right after MMO_TEXT_SECTION_NAME.  Much borrowed
    from elf32.em.  */
@@ -80,21 +39,25 @@ struct orphan_save {
 static bfd_boolean
 mmo_place_orphan (lang_input_statement_type *file, asection *s)
 {
-  static struct orphan_save hold_text;
+  static struct orphan_save hold_text =
+    {
+      MMO_TEXT_SECTION_NAME,
+      SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE,
+      0, 0, 0, 0
+    };
   struct orphan_save *place;
+  const char *secname;
+  lang_output_section_statement_type *after;
   lang_output_section_statement_type *os;
-  lang_statement_list_type *old;
-  lang_statement_list_type add;
-  asection *snew, **pps, *bfd_section;
 
   /* We have nothing to say for anything other than a final link.  */
   if (link_info.relocatable
-      || (bfd_get_section_flags (s->owner, s)
-         & (SEC_EXCLUDE | SEC_LOAD)) != SEC_LOAD)
+      || (s->flags & (SEC_EXCLUDE | SEC_LOAD)) != SEC_LOAD)
     return FALSE;
 
   /* Only care for sections we're going to load.  */
-  os = lang_output_section_find (bfd_get_section_name (s->owner, s));
+  secname = s->name;
+  os = lang_output_section_find (secname);
 
   /* We have an output section by this name.  Place the section inside it
      (regardless of whether the linker script lists it as input).  */
@@ -106,108 +69,28 @@ mmo_place_orphan (lang_input_statement_type *file, asection *s)
 
   /* If this section does not have .text-type section flags or there's no
      MMO_TEXT_SECTION_NAME, we don't have anything to say.  */
-  if ((bfd_get_section_flags (s->owner, s) & (SEC_CODE | SEC_READONLY)) == 0)
+  if ((s->flags & (SEC_CODE | SEC_READONLY)) == 0)
     return FALSE;
 
   if (hold_text.os == NULL)
-    hold_text.os = lang_output_section_find (MMO_TEXT_SECTION_NAME);
+    hold_text.os = lang_output_section_find (hold_text.name);
 
   place = &hold_text;
+  if (hold_text.os != NULL)
+    after = hold_text.os;
+  else
+    after = &lang_output_section_statement.head->output_section_statement;
 
   /* If there's an output section by this name, we'll use it, regardless
      of section flags, in contrast to what's done in elf32.em.  */
-
-  /* Start building a list of statements for this section.
-     First save the current statement pointer.  */
-  old = stat_ptr;
-
-  /* Add the output section statements for this orphan to our own private
-     list, inserting them later into the global statement list.  */
-  stat_ptr = &add;
-  lang_list_init (stat_ptr);
-
-  os = lang_enter_output_section_statement (bfd_get_section_name (s->owner,
-                                                                 s),
-                                           NULL, 0,
-                                           (etree_type *) NULL,
-                                           (etree_type *) NULL,
-                                           (etree_type *) NULL, 0);
-
-  lang_add_section (&os->children, s, os, file);
-
-  lang_leave_output_section_statement
-    ((bfd_vma) 0, "*default*",
-     (struct lang_output_section_phdr_list *) NULL, NULL);
-
-  /* Restore the global list pointer.  */
-  stat_ptr = old;
-
-  snew = os->bfd_section;
-  if (snew == NULL)
-    /* /DISCARD/ section.  */
-    return TRUE;
+  os = lang_insert_orphan (file, s, secname, after, place, NULL, NULL);
 
   /* We need an output section for .text as a root, so if there was none
      (might happen with a peculiar linker script such as in "map
      addresses", map-address.exp), we grab the output section created
      above.  */
   if (hold_text.os == NULL)
-    {
-      if (os == NULL)
-       return FALSE;
-      hold_text.os = os;
-    }
-
-  bfd_section = place->os->bfd_section;
-  if (place->section == NULL && bfd_section == NULL)
-    bfd_section = output_prev_sec_find (place->os);
-
-  if (place->section != NULL
-      || (bfd_section != NULL
-         && bfd_section != snew))
-    {
-      /* Shuffle the section to make the output file look neater.  This is
-        really only cosmetic.  */
-      if (place->section == NULL)
-       /* Put orphans after the first section on the list.  */
-       place->section = &bfd_section->next;
-
-      /* Unlink the section.  */
-      for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
-       ;
-      bfd_section_list_remove (output_bfd, pps);
-
-      /* Now tack it on to the "place->os" section list.  */
-      bfd_section_list_insert (output_bfd, place->section, snew);
-    }
-  place->section = &snew->next;        /* Save the end of this list.  */
-
-  if (add.head != NULL)
-    {
-      /* We try to put the output statements in some sort of reasonable
-        order here, because they determine the final load addresses of
-        the orphan sections.  */
-      if (place->stmt == NULL)
-       {
-         /* Put the new statement list right at the head.  */
-         *add.tail = place->os->header.next;
-         place->os->header.next = add.head;
-       }
-      else
-       {
-         /* Put it after the last orphan statement we added.  */
-         *add.tail = *place->stmt;
-         *place->stmt = add.head;
-       }
-
-      /* Fix the global list pointer if we happened to tack our new list
-        at the tail.  */
-      if (*old->tail == add.head)
-       old->tail = add.tail;
-
-      /* Save the end of this list.  */
-      place->stmt = add.tail;
-    }
+    hold_text.os = os;
 
   return TRUE;
 }
index 7f674502c7f3b6ce6dd7b9faccdde8c0df4c2835..8e52b7bc8a01e63c4ffd0a3158725d5097600e2d 100644 (file)
@@ -1485,33 +1485,6 @@ gld_${EMULATION_NAME}_finish (void)
 }
 
 \f
-/* Find the last output section before given output statement.
-   Used by place_orphan.  */
-
-static asection *
-output_prev_sec_find (lang_output_section_statement_type *os)
-{
-  asection *s = (asection *) NULL;
-  lang_statement_union_type *u;
-  lang_output_section_statement_type *lookup;
-
-  for (u = lang_output_section_statement.head;
-       u != (lang_statement_union_type *) NULL;
-       u = lookup->next)
-    {
-      lookup = &u->output_section_statement;
-      if (lookup->constraint == -1)
-       continue;
-      if (lookup == os)
-       return s;
-
-      if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
-       s = lookup->bfd_section;
-    }
-
-  return NULL;
-}
-
 /* Place an orphan section.
 
    We use this to put sections in a reasonable place in the file, and
@@ -1525,280 +1498,132 @@ output_prev_sec_find (lang_output_section_statement_type *os)
    default linker script using wildcards, and are sorted by
    sort_sections.  */
 
-struct orphan_save
-{
-  lang_output_section_statement_type *os;
-  asection **section;
-  lang_statement_union_type **stmt;
-  lang_statement_union_type **os_tail;
-};
-
 static bfd_boolean
 gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s)
 {
   const char *secname;
-  char *hold_section_name;
+  const char *orig_secname;
   char *dollar = NULL;
-  const char *ps = NULL;
   lang_output_section_statement_type *os;
   lang_statement_list_type add_child;
 
   secname = bfd_get_section_name (s->owner, s);
 
   /* Look through the script to see where to place this section.  */
-  hold_section_name = xstrdup (secname);
-  if (!link_info.relocatable)
+  orig_secname = secname;
+  if (!link_info.relocatable
+      && (dollar = strchr (secname, '$')) != NULL)
     {
-      dollar = strchr (hold_section_name, '$');
-      if (dollar != NULL)
-       *dollar = '\0';
+      size_t len = dollar - orig_secname;
+      char *newname = xmalloc (len + 1);
+      memcpy (newname, orig_secname, len);
+      newname[len] = '\0';
+      secname = newname;
     }
 
-  os = lang_output_section_find (hold_section_name);
+  os = lang_output_section_find (secname);
 
   lang_list_init (&add_child);
 
   if (os != NULL
       && (os->bfd_section == NULL
+         || os->bfd_section->flags == 0
          || ((s->flags ^ os->bfd_section->flags)
              & (SEC_LOAD | SEC_ALLOC)) == 0))
     {
       /* We already have an output section statement with this
-        name, and its bfd section, if any, has compatible flags.  */
+        name, and its bfd section, if any, has compatible flags.
+        If the section already exists but does not have any flags set,
+        then it has been created by the linker, probably as a result of
+        a --section-start command line switch.  */
       lang_add_section (&add_child, s, os, file);
     }
   else
     {
+      static struct orphan_save hold[] =
+       {
+         { ".text",
+           SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE,
+           0, 0, 0, 0 },
+         { ".rdata",
+           SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
+           0, 0, 0, 0 },
+         { ".data",
+           SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA,
+           0, 0, 0, 0 },
+         { ".bss",
+           SEC_ALLOC,
+           0, 0, 0, 0 }
+       };
+      enum orphan_save_index
+       {
+         orphan_text = 0,
+         orphan_rodata,
+         orphan_data,
+         orphan_bss
+       };
+      static int orphan_init_done = 0;
       struct orphan_save *place;
-      static struct orphan_save hold_text;
-      static struct orphan_save hold_rdata;
-      static struct orphan_save hold_data;
-      static struct orphan_save hold_bss;
-      static int count = 1;
-      char *outsecname;
-      lang_statement_list_type *old;
-      lang_statement_list_type add;
-      lang_statement_union_type **os_tail;
+      lang_output_section_statement_type *after;
       etree_type *address;
-      etree_type *load_base;
-      asection *sec;
+
+      if (!orphan_init_done)
+       {
+         struct orphan_save *ho;
+         for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho)
+           if (ho->name != NULL)
+             {
+               ho->os = lang_output_section_find (ho->name);
+               if (ho->os != NULL && ho->os->flags == 0)
+                 ho->os->flags = ho->flags;
+             }
+         orphan_init_done = 1;
+       }
 
       /* Try to put the new output section in a reasonable place based
         on the section name and section flags.  */
-#define HAVE_SECTION(hold, name) \
-(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
 
       place = NULL;
       if ((s->flags & SEC_ALLOC) == 0)
        ;
-      else if ((s->flags & SEC_HAS_CONTENTS) == 0
-              && HAVE_SECTION (hold_bss, ".bss"))
-       place = &hold_bss;
-      else if ((s->flags & SEC_READONLY) == 0
-              && HAVE_SECTION (hold_data, ".data"))
-       place = &hold_data;
-      else if ((s->flags & SEC_CODE) == 0
-              && (s->flags & SEC_READONLY) != 0
-              && HAVE_SECTION (hold_rdata, ".rdata"))
-       place = &hold_rdata;
-      else if ((s->flags & SEC_CODE) != 0
-              && (s->flags & SEC_READONLY) != 0
-              && HAVE_SECTION (hold_text, ".text"))
-       place = &hold_text;
-
-#undef HAVE_SECTION
-
-      /* Choose a unique name for the section.  This will be needed if the
-        same section name appears in the input file with different
-        loadable or allocatable characteristics.  But if the section
-        already exists but does not have any flags set, then it has been
-        created by the linker, probably as a result of a --section-start
-        command line switch.  */
-      sec = bfd_get_section_by_name (output_bfd, hold_section_name);
-      if (sec != NULL
-         && bfd_get_section_flags (output_bfd, sec) != 0)
-       {
-         outsecname = bfd_get_unique_section_name (output_bfd,
-                                                   hold_section_name, &count);
-         if (outsecname == NULL)
-           einfo ("%F%P: place_orphan failed: %E\n");
-       }
+      else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+       place = &hold[orphan_bss];
+      else if ((s->flags & SEC_READONLY) == 0)
+       place = &hold[orphan_data];
+      else if ((s->flags & SEC_CODE) == 0)
+       place = &hold[orphan_rodata];
       else
-       outsecname = xstrdup (hold_section_name);
-
-      /* Start building a list of statements for this section.  */
-      old = stat_ptr;
+       place = &hold[orphan_text];
 
-      /* If we have found an appropriate place for the output section
-        statements for this orphan, add them to our own private list,
-        inserting them later into the global statement list.  */
+      after = NULL;
       if (place != NULL)
        {
-         stat_ptr = &add;
-         lang_list_init (stat_ptr);
-       }
-
-      if (config.build_constructors)
-       {
-         /* If the name of the section is representable in C, then create
-            symbols to mark the start and the end of the section.  */
-         for (ps = outsecname; *ps != '\0'; ps++)
-           if (! ISALNUM ((unsigned char) *ps) && *ps != '_')
-             break;
-         if (*ps == '\0')
-           {
-             char *symname;
-             etree_type *e_align;
-
-             symname = (char *) xmalloc (ps - outsecname + sizeof "___start_");
-             sprintf (symname, "___start_%s", outsecname);
-             e_align = exp_unop (ALIGN_K,
-                                 exp_intop ((bfd_vma) 1 << s->alignment_power));
-             lang_add_assignment (exp_assop ('=', symname, e_align));
-           }
-       }
-
-      if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
-       address = exp_intop ((bfd_vma) 0);
-      else
-       {
-         /* All sections in an executable must be aligned to a page
-            boundary.  */
-         address = exp_unop (ALIGN_K,
-                             exp_nameop (NAME, "__section_alignment__"));
+         if (place->os == NULL)
+           place->os = lang_output_section_find (place->name);
+         after = place->os;
+         if (after == NULL)
+           after = lang_output_section_find_by_flags (s, &place->os);
+         if (after == NULL)
+           /* *ABS* is always the first output section statement.  */
+           after = (&lang_output_section_statement.head
+                    ->output_section_statement);
        }
 
-      load_base = NULL;
-      if (place != NULL && place->os->load_base != NULL)
-       {
-         etree_type *lma_from_vma;
-         lma_from_vma = exp_binop ('-', place->os->load_base,
-                                   exp_nameop (ADDR, place->os->name));
-         load_base = exp_binop ('+', lma_from_vma,
-                                exp_nameop (ADDR, secname));
-       }
-
-      os_tail = lang_output_section_statement.tail;
-      os = lang_enter_output_section_statement (outsecname, address, 0,
-                                               (etree_type *) NULL,
-                                               (etree_type *) NULL,
-                                               load_base, 0);
-
-      lang_add_section (&add_child, s, os, file);
-
-      lang_leave_output_section_statement
-       ((bfd_vma) 0, "*default*",
-        (struct lang_output_section_phdr_list *) NULL, NULL);
-
-      if (config.build_constructors && *ps == '\0')
+      /* Choose a unique name for the section.  This will be needed if the
+        same section name appears in the input file with different
+        loadable or allocatable characteristics.  */
+      if (bfd_get_section_by_name (output_bfd, secname) != NULL)
        {
-         char *symname;
-
-         /* lang_leave_ouput_section_statement resets stat_ptr.
-            Put stat_ptr back where we want it.  */
-         if (place != NULL)
-           stat_ptr = &add;
-
-         symname = (char *) xmalloc (ps - outsecname + sizeof "___stop_");
-         sprintf (symname, "___stop_%s", outsecname);
-         lang_add_assignment (exp_assop ('=', symname,
-                                         exp_nameop (NAME, ".")));
+         static int count = 1;
+         secname = bfd_get_unique_section_name (output_bfd, secname, &count);
+         if (secname == NULL)
+           einfo ("%F%P: place_orphan failed: %E\n");
        }
 
-      stat_ptr = old;
-
-      if (place != NULL && os->bfd_section != NULL)
-       {
-         asection *snew, **pps;
-
-         snew = os->bfd_section;
-
-         /* Shuffle the bfd section list to make the output file look
-            neater.  This is really only cosmetic.  */
-         if (place->section == NULL)
-           {
-             asection *bfd_section = place->os->bfd_section;
-
-             /* If the output statement hasn't been used to place
-                any input sections (and thus doesn't have an output
-                bfd_section), look for the closest prior output statement
-                having an output section.  */
-             if (bfd_section == NULL)
-               bfd_section = output_prev_sec_find (place->os);
-
-             if (bfd_section != NULL && bfd_section != snew)
-               place->section = &bfd_section->next;
-           }
-
-         if (place->section != NULL)
-           {
-             /* Unlink the section.  */
-             for (pps = &output_bfd->sections;
-                  *pps != snew;
-                  pps = &(*pps)->next)
-               ;
-             bfd_section_list_remove (output_bfd, pps);
-
-             /* Now tack it on to the "place->os" section list.  */
-             bfd_section_list_insert (output_bfd, place->section, snew);
-           }
-
-         /* Save the end of this list.  Further ophans of this type will
-            follow the one we've just added.  */
-         place->section = &snew->next;
-
-         /* The following is non-cosmetic.  We try to put the output
-            statements in some sort of reasonable order here, because
-            they determine the final load addresses of the orphan
-            sections.  In addition, placing output statements in the
-            wrong order may require extra segments.  For instance,
-            given a typical situation of all read-only sections placed
-            in one segment and following that a segment containing all
-            the read-write sections, we wouldn't want to place an orphan
-            read/write section before or amongst the read-only ones.  */
-         if (add.head != NULL)
-           {
-             lang_statement_union_type *newly_added_os;
-
-             if (place->stmt == NULL)
-               {
-                 /* Put the new statement list right at the head.  */
-                 *add.tail = place->os->header.next;
-                 place->os->header.next = add.head;
-
-                 place->os_tail = &place->os->next;
-               }
-             else
-               {
-                 /* Put it after the last orphan statement we added.  */
-                 *add.tail = *place->stmt;
-                 *place->stmt = add.head;
-               }
-
-             /* Fix the global list pointer if we happened to tack our
-                new list at the tail.  */
-             if (*old->tail == add.head)
-               old->tail = add.tail;
-
-             /* Save the end of this list.  */
-             place->stmt = add.tail;
-
-             /* Do the same for the list of output section statements.  */
-             newly_added_os = *os_tail;
-             *os_tail = NULL;
-             newly_added_os->output_section_statement.next = *place->os_tail;
-             *place->os_tail = newly_added_os;
-             place->os_tail = &newly_added_os->output_section_statement.next;
-
-             /* Fixing the global list pointer here is a little different.
-                We added to the list in lang_enter_output_section_statement,
-                trimmed off the new output_section_statment above when
-                assigning *os_tail = NULL, but possibly added it back in
-                the same place when assigning *place->os_tail.  */
-             if (*os_tail == NULL)
-               lang_output_section_statement.tail = os_tail;
-           }
-       }
+      /* All sections in an executable must be aligned to a page boundary.  */
+      address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__"));
+      os = lang_insert_orphan (file, s, secname, after, place, address,
+                              &add_child);
     }
 
   {
@@ -1830,7 +1655,7 @@ gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s
            else
              {
                found_dollar = TRUE;
-               if (strcmp (secname, lname) < 0)
+               if (strcmp (orig_secname, lname) < 0)
                  break;
              }
          }
@@ -1843,8 +1668,6 @@ gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s
       }
   }
 
-  free (hold_section_name);
-
   return TRUE;
 }
 
index e520625e94ea390bcc9456003cac66db9cf00a6f..fee5950b6f17a8995e8e8337f3dfc92bbe8a5645 100644 (file)
@@ -612,13 +612,12 @@ lang_memory_default (asection *section)
 static lang_output_section_statement_type *
 lang_output_section_find_1 (const char *const name, int constraint)
 {
-  lang_statement_union_type *u;
   lang_output_section_statement_type *lookup;
 
-  for (u = lang_output_section_statement.head; u != NULL; u = lookup->next)
+  for (lookup = &lang_output_section_statement.head->output_section_statement;
+       lookup != NULL;
+       lookup = lookup->next)
     {
-      lookup = &u->output_section_statement;
-      
       if (strcmp (name, lookup->name) == 0
          && lookup->constraint != -1
          && (constraint == 0 || constraint == lookup->constraint))
@@ -666,7 +665,7 @@ lang_output_section_statement_lookup_1 (const char *const name, int constraint)
 
       lang_statement_append (&lang_output_section_statement,
                             (lang_statement_union_type *) lookup,
-                            &lookup->next);
+                            (lang_statement_union_type **) &lookup->next);
     }
   return lookup;
 }
@@ -677,6 +676,389 @@ lang_output_section_statement_lookup (const char *const name)
   return lang_output_section_statement_lookup_1 (name, 0);
 }
 
+/* A variant of lang_output_section_find used by place_orphan.
+   Returns the output statement that should precede a new output
+   statement for SEC.  If an exact match is found on certain flags,
+   sets *EXACT too.  */
+
+lang_output_section_statement_type *
+lang_output_section_find_by_flags (const asection *sec,
+                                  lang_output_section_statement_type **exact)
+{
+  lang_output_section_statement_type *first, *look, *found;
+  flagword flags;
+
+  /* We know the first statement on this list is *ABS*.  May as well
+     skip it.  */
+  first = &lang_output_section_statement.head->output_section_statement;
+  first = first->next;
+
+  /* First try for an exact match.  */
+  found = NULL;
+  for (look = first; look; look = look->next)
+    {
+      flags = look->flags;
+      if (look->bfd_section != NULL)
+       flags = look->bfd_section->flags;
+      flags ^= sec->flags;
+      if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY
+                    | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+       found = look;
+    }
+  if (found != NULL)
+    {
+      *exact = found;
+      return found;
+    }
+
+  if (sec->flags & SEC_CODE)
+    {
+      /* Try for a rw code section.  */
+      for (look = first; look; look = look->next)
+       {
+         flags = look->flags;
+         if (look->bfd_section != NULL)
+           flags = look->bfd_section->flags;
+         flags ^= sec->flags;
+         if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                        | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+           found = look;
+       }
+      return found;
+    }
+
+  if (sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL))
+    {
+      /* .rodata can go after .text, .sdata2 after .rodata.  */
+      for (look = first; look; look = look->next)
+       {
+         flags = look->flags;
+         if (look->bfd_section != NULL)
+           flags = look->bfd_section->flags;
+         flags ^= sec->flags;
+         if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                        | SEC_READONLY))
+             && !(look->flags & (SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+           found = look;
+       }
+      return found;
+    }
+
+  if (sec->flags & SEC_SMALL_DATA)
+    {
+      /* .sdata goes after .data, .sbss after .sdata.  */
+      for (look = first; look; look = look->next)
+       {
+         flags = look->flags;
+         if (look->bfd_section != NULL)
+           flags = look->bfd_section->flags;
+         flags ^= sec->flags;
+         if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                        | SEC_THREAD_LOCAL))
+             || ((look->flags & SEC_SMALL_DATA)
+                 && !(sec->flags & SEC_HAS_CONTENTS)))
+           found = look;
+       }
+      return found;
+    }
+
+  if (sec->flags & SEC_HAS_CONTENTS)
+    {
+      /* .data goes after .rodata.  */
+      for (look = first; look; look = look->next)
+       {
+         flags = look->flags;
+         if (look->bfd_section != NULL)
+           flags = look->bfd_section->flags;
+         flags ^= sec->flags;
+         if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                        | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+           found = look;
+       }
+      return found;
+    }
+
+  /* .bss goes last.  */
+  for (look = first; look; look = look->next)
+    {
+      flags = look->flags;
+      if (look->bfd_section != NULL)
+       flags = look->bfd_section->flags;
+      flags ^= sec->flags;
+      if (!(flags & SEC_ALLOC))
+       found = look;
+    }
+
+  return found;
+}
+
+/* Find the last output section before given output statement.
+   Used by place_orphan.  */
+
+static asection *
+output_prev_sec_find (lang_output_section_statement_type *os)
+{
+  asection *s = (asection *) NULL;
+  lang_output_section_statement_type *lookup;
+
+  for (lookup = &lang_output_section_statement.head->output_section_statement;
+       lookup != NULL;
+       lookup = lookup->next)
+    {
+      if (lookup->constraint == -1)
+       continue;
+      if (lookup == os)
+       return s;
+
+      if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
+       s = lookup->bfd_section;
+    }
+
+  return NULL;
+}
+
+lang_output_section_statement_type *
+lang_insert_orphan (lang_input_statement_type *file,
+                   asection *s,
+                   const char *secname,
+                   lang_output_section_statement_type *after,
+                   struct orphan_save *place,
+                   etree_type *address,
+                   lang_statement_list_type *add_child)
+{
+  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;
+
+  /* Start building a list of statements for this section.
+     First save the current statement pointer.  */
+  old = stat_ptr;
+
+  /* If we have found an appropriate place for the output section
+     statements for this orphan, add them to our own private list,
+     inserting them later into the global statement list.  */
+  if (after != NULL)
+    {
+      stat_ptr = &add;
+      lang_list_init (stat_ptr);
+    }
+
+  ps = NULL;
+  if (config.build_constructors)
+    {
+      /* If the name of the section is representable in C, then create
+        symbols to mark the start and the end of the section.  */
+      for (ps = secname; *ps != '\0'; ps++)
+       if (! ISALNUM ((unsigned char) *ps) && *ps != '_')
+         break;
+      if (*ps == '\0')
+       {
+         char *symname;
+         etree_type *e_align;
+
+         symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1);
+         symname[0] = bfd_get_symbol_leading_char (output_bfd);
+         sprintf (symname + (symname[0] != 0), "__start_%s", secname);
+         e_align = exp_unop (ALIGN_K,
+                             exp_intop ((bfd_vma) 1 << s->alignment_power));
+         lang_add_assignment (exp_assop ('=', ".", e_align));
+         lang_add_assignment (exp_assop ('=', symname,
+                                         exp_nameop (NAME, ".")));
+       }
+    }
+
+  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);
+
+  if (add_child == NULL)
+    add_child = &os->children;
+  lang_add_section (add_child, s, os, file);
+
+  lang_leave_output_section_statement (0, "*default*", NULL, NULL);
+
+  if (config.build_constructors && *ps == '\0')
+    {
+      char *symname;
+
+      /* lang_leave_ouput_section_statement resets stat_ptr.
+        Put stat_ptr back where we want it.  */
+      if (after != NULL)
+       stat_ptr = &add;
+
+      symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1);
+      symname[0] = bfd_get_symbol_leading_char (output_bfd);
+      sprintf (symname + (symname[0] != 0), "__stop_%s", secname);
+      lang_add_assignment (exp_assop ('=', symname,
+                                     exp_nameop (NAME, ".")));
+    }
+
+  /* Restore the global list pointer.  */
+  if (after != NULL)
+    stat_ptr = old;
+
+  if (after != NULL && os->bfd_section != NULL)
+    {
+      asection *snew, **pps;
+
+      snew = os->bfd_section;
+
+      /* Shuffle the bfd section list to make the output file look
+        neater.  This is really only cosmetic.  */
+      if (place->section == NULL
+         && after != (&lang_output_section_statement.head
+                      ->output_section_statement))
+       {
+         asection *bfd_section = after->bfd_section;
+
+         /* If the output statement hasn't been used to place any input
+            sections (and thus doesn't have an output bfd_section),
+            look for the closest prior output statement having an
+            output section.  */
+         if (bfd_section == NULL)
+           bfd_section = output_prev_sec_find (after);
+
+         if (bfd_section != NULL && bfd_section != snew)
+           place->section = &bfd_section->next;
+       }
+
+      if (place->section == NULL)
+       place->section = &output_bfd->sections;
+
+      /* Unlink the section.  */
+      for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
+       continue;
+      bfd_section_list_remove (output_bfd, pps);
+
+      /* Now tack it back on in the right place.  */
+      bfd_section_list_insert (output_bfd, place->section, snew);
+
+      /* Save the end of this list.  Further ophans of this type will
+        follow the one we've just added.  */
+      place->section = &snew->next;
+
+      /* The following is non-cosmetic.  We try to put the output
+        statements in some sort of reasonable order here, because they
+        determine the final load addresses of the orphan sections.
+        In addition, placing output statements in the wrong order may
+        require extra segments.  For instance, given a typical
+        situation of all read-only sections placed in one segment and
+        following that a segment containing all the read-write
+        sections, we wouldn't want to place an orphan read/write
+        section before or amongst the read-only ones.  */
+      if (add.head != NULL)
+       {
+         lang_output_section_statement_type *newly_added_os;
+
+         if (place->stmt == NULL)
+           {
+             lang_statement_union_type **where;
+             lang_statement_union_type **assign = NULL;
+
+             /* Look for a suitable place for the new statement list.
+                The idea is to skip over anything that might be inside
+                a SECTIONS {} statement in a script, before we find
+                another output_section_statement.  Assignments to "dot"
+                before an output section statement are assumed to
+                belong to it.  */
+             for (where = &after->header.next;
+                  *where != NULL;
+                  where = &(*where)->header.next)
+               {
+                 switch ((*where)->header.type)
+                   {
+                   case lang_assignment_statement_enum:
+                     if (assign == NULL)
+                       {
+                         lang_assignment_statement_type *ass;
+                         ass = &(*where)->assignment_statement;
+                         if (ass->exp->type.node_class != etree_assert
+                             && ass->exp->assign.dst[0] == '.'
+                             && ass->exp->assign.dst[1] == 0)
+                           assign = where;
+                       }
+                     continue;
+                   case lang_wild_statement_enum:
+                   case lang_input_section_enum:
+                   case lang_object_symbols_statement_enum:
+                   case lang_fill_statement_enum:
+                   case lang_data_statement_enum:
+                   case lang_reloc_statement_enum:
+                   case lang_padding_statement_enum:
+                   case lang_constructors_statement_enum:
+                     assign = NULL;
+                     continue;
+                   case lang_output_section_statement_enum:
+                     if (assign != NULL)
+                       where = assign;
+                   case lang_input_statement_enum:
+                   case lang_address_statement_enum:
+                   case lang_target_statement_enum:
+                   case lang_output_statement_enum:
+                   case lang_group_statement_enum:
+                   case lang_afile_asection_pair_statement_enum:
+                     break;
+                   }
+                 break;
+               }
+
+             *add.tail = *where;
+             *where = add.head;
+
+             place->os_tail = &after->next;
+           }
+         else
+           {
+             /* Put it after the last orphan statement we added.  */
+             *add.tail = *place->stmt;
+             *place->stmt = add.head;
+           }
+
+         /* Fix the global list pointer if we happened to tack our
+            new list at the tail.  */
+         if (*old->tail == add.head)
+           old->tail = add.tail;
+
+         /* Save the end of this list.  */
+         place->stmt = add.tail;
+
+         /* Do the same for the list of output section statements.  */
+         newly_added_os = *os_tail;
+         *os_tail = NULL;
+         newly_added_os->next = *place->os_tail;
+         *place->os_tail = newly_added_os;
+         place->os_tail = &newly_added_os->next;
+
+         /* Fixing the global list pointer here is a little different.
+            We added to the list in lang_enter_output_section_statement,
+            trimmed off the new output_section_statment above when
+            assigning *os_tail = NULL, but possibly added it back in
+            the same place when assigning *place->os_tail.  */
+         if (*os_tail == NULL)
+           lang_output_section_statement.tail
+             = (lang_statement_union_type **) os_tail;
+       }
+    }
+  return os;
+}
+
 static void
 lang_map_flags (flagword flag)
 {
@@ -792,7 +1174,7 @@ sort_def_symbol (hash_entry, info)
        }
       else if  (!ud->map_symbol_def_tail)
        ud->map_symbol_def_tail = &ud->map_symbol_def_head;
-      
+
       def = obstack_alloc (&map_obstack, sizeof *def);
       def->entry = hash_entry;
       *(ud->map_symbol_def_tail) = def;
@@ -867,7 +1249,7 @@ exp_init_os (etree_type *exp)
     case etree_assert:
       exp_init_os (exp->assert_s.child);
       break;
-      
+
     case etree_unary:
       exp_init_os (exp->unary.child);
       break;
@@ -991,32 +1373,32 @@ lang_add_section (lang_statement_list_type *ptr,
        flags &= ~ (SEC_LINK_ONCE | SEC_LINK_DUPLICATES);
 
       /* If this is not the first input section, and the SEC_READONLY
-         flag is not currently set, then don't set it just because the
-         input section has it set.  */
+        flag is not currently set, then don't set it just because the
+        input section has it set.  */
 
-      if (! first && (section->output_section->flags & SEC_READONLY) == 0)
+      if (! first && (output->bfd_section->flags & SEC_READONLY) == 0)
        flags &= ~ SEC_READONLY;
 
       /* Keep SEC_MERGE and SEC_STRINGS only if they are the same.  */
       if (! first
-         && ((section->output_section->flags & (SEC_MERGE | SEC_STRINGS))
+         && ((output->bfd_section->flags & (SEC_MERGE | SEC_STRINGS))
              != (flags & (SEC_MERGE | SEC_STRINGS))
              || ((flags & SEC_MERGE)
-                 && section->output_section->entsize != section->entsize)))
+                 && output->bfd_section->entsize != section->entsize)))
        {
-         section->output_section->flags &= ~ (SEC_MERGE | SEC_STRINGS);
+         output->bfd_section->flags &= ~ (SEC_MERGE | SEC_STRINGS);
          flags &= ~ (SEC_MERGE | SEC_STRINGS);
        }
 
-      section->output_section->flags |= flags;
+      output->bfd_section->flags |= flags;
 
       if (flags & SEC_MERGE)
-       section->output_section->entsize = section->entsize;
+       output->bfd_section->entsize = section->entsize;
 
       /* If SEC_READONLY is not set in the input section, then clear
-         it from the output section.  */
+        it from the output section.  */
       if ((section->flags & SEC_READONLY) == 0)
-       section->output_section->flags &= ~SEC_READONLY;
+       output->bfd_section->flags &= ~SEC_READONLY;
 
       switch (output->sectype)
        {
@@ -1036,7 +1418,7 @@ lang_add_section (lang_statement_list_type *ptr,
 
       /* Copy over SEC_SMALL_DATA.  */
       if (section->flags & SEC_SMALL_DATA)
-       section->output_section->flags |= SEC_SMALL_DATA;
+       output->bfd_section->flags |= SEC_SMALL_DATA;
 
       if (section->alignment_power > output->bfd_section->alignment_power)
        output->bfd_section->alignment_power = section->alignment_power;
@@ -1047,7 +1429,7 @@ lang_add_section (lang_statement_list_type *ptr,
 
       if (section->flags & SEC_BLOCK)
        {
-         section->output_section->flags |= SEC_BLOCK;
+         output->bfd_section->flags |= SEC_BLOCK;
          /* FIXME: This value should really be obtained from the bfd...  */
          output->block_value = 128;
        }
@@ -1122,7 +1504,7 @@ wild_sort (lang_wild_statement_type *wild,
       ls = &l->input_section;
 
       /* Sorting by filename takes precedence over sorting by section
-         name.  */
+        name.  */
 
       if (wild->filenames_sorted)
        {
@@ -1131,9 +1513,9 @@ wild_sort (lang_wild_statement_type *wild,
          int i;
 
          /* The PE support for the .idata section as generated by
-             dlltool assumes that files will be sorted by the name of
-             the archive and then the name of the file within the
-             archive.  */
+            dlltool assumes that files will be sorted by the name of
+            the archive and then the name of the file within the
+            archive.  */
 
          if (file->the_bfd != NULL
              && bfd_my_archive (file->the_bfd) != NULL)
@@ -1181,7 +1563,7 @@ wild_sort (lang_wild_statement_type *wild,
        }
 
       /* Here either the files are not sorted by name, or we are
-         looking at the sections for this file.  */
+        looking at the sections for this file.  */
 
       if (sec != NULL && sec->spec.sorted != none)
        {
@@ -1832,8 +2214,8 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
              s->input_statement.target = current_target;
 
              /* If we are being called from within a group, and this
-                 is an archive which has already been searched, then
-                 force it to be researched unless the whole archive
+                is an archive which has already been searched, then
+                force it to be researched unless the whole archive
                 has been loaded already.  */
              if (force
                  && !s->input_statement.whole_archive
@@ -2125,19 +2507,19 @@ update_wild_statements (lang_statement_union_type *s)
 static void
 map_input_to_output_sections
   (lang_statement_union_type *s, const char *target,
-   lang_output_section_statement_type *output_section_statement)
+   lang_output_section_statement_type *os)
 {
   for (; s != NULL; s = s->header.next)
     {
       switch (s->header.type)
        {
        case lang_wild_statement_enum:
-         wild (&s->wild_statement, target, output_section_statement);
+         wild (&s->wild_statement, target, os);
          break;
        case lang_constructors_statement_enum:
          map_input_to_output_sections (constructor_list.head,
                                        target,
-                                       output_section_statement);
+                                       os);
          break;
        case lang_output_section_statement_enum:
          if (s->output_section_statement.constraint)
@@ -2169,27 +2551,32 @@ map_input_to_output_sections
        case lang_group_statement_enum:
          map_input_to_output_sections (s->group_statement.children.head,
                                        target,
-                                       output_section_statement);
+                                       os);
          break;
        case lang_data_statement_enum:
          /* Make sure that any sections mentioned in the expression
             are initialized.  */
          exp_init_os (s->data_statement.exp);
-         /* FALLTHROUGH */
+         if (os != NULL && os->bfd_section == NULL)
+           init_os (os);
+         /* The output section gets contents, and then we inspect for
+            any flags set in the input script which override any ALLOC.  */
+         os->bfd_section->flags |= SEC_HAS_CONTENTS;
+         if (!(os->flags & SEC_NEVER_LOAD))
+           os->bfd_section->flags |= SEC_ALLOC | SEC_LOAD;
+         break;
        case lang_fill_statement_enum:
        case lang_input_section_enum:
        case lang_object_symbols_statement_enum:
        case lang_reloc_statement_enum:
        case lang_padding_statement_enum:
        case lang_input_statement_enum:
-         if (output_section_statement != NULL
-             && output_section_statement->bfd_section == NULL)
-           init_os (output_section_statement);
+         if (os != NULL && os->bfd_section == NULL)
+           init_os (os);
          break;
        case lang_assignment_statement_enum:
-         if (output_section_statement != NULL
-             && output_section_statement->bfd_section == NULL)
-           init_os (output_section_statement);
+         if (os != NULL && os->bfd_section == NULL)
+           init_os (os);
 
          /* Make sure that any sections mentioned in the assignment
             are initialized.  */
@@ -2201,13 +2588,13 @@ map_input_to_output_sections
        case lang_address_statement_enum:
          /* Mark the specified section with the supplied address.  */
          {
-           lang_output_section_statement_type *os =
-             lang_output_section_statement_lookup
-               (s->address_statement.section_name);
+           lang_output_section_statement_type *aos
+             = (lang_output_section_statement_lookup
+                (s->address_statement.section_name));
 
-           if (os->bfd_section == NULL)
-             init_os (os);
-           os->addr_tree = s->address_statement.address;
+           if (aos->bfd_section == NULL)
+             init_os (aos);
+           aos->addr_tree = s->address_statement.address;
          }
          break;
        }
@@ -2221,16 +2608,14 @@ map_input_to_output_sections
 static void
 strip_excluded_output_sections (void)
 {
-  lang_statement_union_type *u;
+  lang_output_section_statement_type *os;
 
-  for (u = lang_output_section_statement.head;
-       u != NULL;
-       u = u->output_section_statement.next)
+  for (os = &lang_output_section_statement.head->output_section_statement;
+       os != NULL;
+       os = os->next)
     {
-      lang_output_section_statement_type *os;
       asection *s;
 
-      os = &u->output_section_statement;
       if (os->constraint == -1)
        continue;
       s = os->bfd_section;
@@ -2302,23 +2687,35 @@ print_assignment (lang_assignment_statement_type *assignment,
                  lang_output_section_statement_type *output_section)
 {
   int i;
+  int is_dot;
+  etree_type *tree;
   etree_value_type result;
 
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
 
-  result = exp_fold_tree (assignment->exp->assign.src, output_section,
-                         lang_final_phase_enum, print_dot, &print_dot);
+  if (assignment->exp->type.node_class == etree_assert)
+    {
+      is_dot = 0;
+      tree = assignment->exp->assert_s.child;
+    }
+  else
+    {
+      const char *dst = assignment->exp->assign.dst;
+      is_dot = dst[0] == '.' && dst[1] == 0;
+      tree = assignment->exp->assign.src;
+    }
+
+  result = exp_fold_tree (tree, output_section, lang_final_phase_enum,
+                         print_dot, &print_dot);
   if (result.valid_p)
     {
-      const char *dst;
       bfd_vma value;
 
       value = result.value + result.section->bfd_section->vma;
-      dst = assignment->exp->assign.dst;
 
       minfo ("0x%V", value);
-      if (dst[0] == '.' && dst[1] == 0)
+      if (is_dot)
        print_dot = value;
     }
   else
@@ -2330,9 +2727,7 @@ print_assignment (lang_assignment_statement_type *assignment,
     }
 
   minfo ("                ");
-
   exp_print_tree (assignment->exp);
-
   print_nl ();
 }
 
@@ -2379,6 +2774,9 @@ print_all_symbols (sec)
   struct fat_user_section_struct *ud = get_userdata (sec);
   struct map_symbol_def *def;
 
+  if (!ud)
+    return;
+
   *ud->map_symbol_def_tail = 0;
   for (def = ud->map_symbol_def_head; def; def = def->next)
     print_one_symbol (def->entry, sec);
@@ -2863,14 +3261,15 @@ size_input_section
 }
 
 #define IGNORE_SECTION(s) \
-  (((s->flags & SEC_THREAD_LOCAL) != 0                         \
-    ? (s->flags & (SEC_LOAD | SEC_NEVER_LOAD)) != SEC_LOAD     \
-    : (s->flags & (SEC_ALLOC | SEC_NEVER_LOAD)) != SEC_ALLOC)  \
+  ((s->flags & SEC_NEVER_LOAD) != 0                            \
+   || (s->flags & SEC_ALLOC) == 0                              \
+   || ((s->flags & SEC_THREAD_LOCAL) != 0                      \
+       && (s->flags & SEC_LOAD) == 0)                          \
    || s->size == 0)
 
 /* Check to see if any allocated sections overlap with other allocated
-   sections.  This can happen when the linker script specifically specifies
-   the output section addresses of the two sections.  */
+   sections.  This can happen if a linker script specifies the output
+   section addresses of the two sections.  */
 
 static void
 lang_check_section_addresses (void)
@@ -3090,7 +3489,7 @@ lang_size_sections_1
                                       lang_allocating_phase_enum,
                                       dot, &dot);
                    os->processed = 0;
-                   
+
                    if (!r.valid_p)
                      einfo (_("%F%S: non constant or forward reference"
                               " address expression for section %s\n"),
@@ -3220,14 +3619,6 @@ lang_size_sections_1
              size = TO_SIZE ((unsigned) 1);
            dot += TO_ADDR (size);
            output_section_statement->bfd_section->size += size;
-           /* The output section gets contents, and then we inspect for
-              any flags set in the input script which override any ALLOC.  */
-           output_section_statement->bfd_section->flags |= SEC_HAS_CONTENTS;
-           if (!(output_section_statement->flags & SEC_NEVER_LOAD))
-             {
-               output_section_statement->bfd_section->flags |=
-                 SEC_ALLOC | SEC_LOAD;
-             }
          }
          break;
 
@@ -3714,7 +4105,7 @@ lang_finish (void)
       const char *send;
 
       /* We couldn't find the entry symbol.  Try parsing it as a
-         number.  */
+        number.  */
       val = bfd_scan_vma (entry_symbol.name, &send, 0);
       if (*send == '\0')
        {
@@ -3815,10 +4206,10 @@ lang_check (void)
          bfd_error_handler_type pfn = NULL;
 
          /* If we aren't supposed to warn about mismatched input
-             files, temporarily set the BFD error handler to a
-             function which will do nothing.  We still want to call
-             bfd_merge_private_bfd_data, since it may set up
-             information which is needed in the output file.  */
+            files, temporarily set the BFD error handler to a
+            function which will do nothing.  We still want to call
+            bfd_merge_private_bfd_data, since it may set up
+            information which is needed in the output file.  */
          if (! command_line.warn_mismatch)
            pfn = bfd_set_error_handler (ignore_bfd_errors);
          if (! bfd_merge_private_bfd_data (input_bfd, output_bfd))
@@ -3965,7 +4356,7 @@ lang_place_orphans (void)
          if (s->output_section == NULL)
            {
              /* This section of the file is not attached, root
-                around for a sensible place for it to go.  */
+                around for a sensible place for it to go.  */
 
              if (file->just_syms_flag)
                abort ();
@@ -3984,8 +4375,8 @@ lang_place_orphans (void)
                        {
 #if 0
                          /* This message happens when using the
-                             svr3.ifile linker script, so I have
-                             disabled it.  */
+                            svr3.ifile linker script, so I have
+                            disabled it.  */
                          info_msg (_("%P: no [COMMON] command,"
                                      " defaulting to .bss\n"));
 #endif
@@ -4855,7 +5246,7 @@ lang_record_phdrs (void)
   asection **secs;
   lang_output_section_phdr_list *last;
   struct lang_phdr *l;
-  lang_statement_union_type *u;
+  lang_output_section_statement_type *os;
 
   alc = 10;
   secs = xmalloc (alc * sizeof (asection *));
@@ -4867,14 +5258,12 @@ lang_record_phdrs (void)
       bfd_vma at;
 
       c = 0;
-      for (u = lang_output_section_statement.head;
-          u != NULL;
-          u = u->output_section_statement.next)
+      for (os = &lang_output_section_statement.head->output_section_statement;
+          os != NULL;
+          os = os->next)
        {
-         lang_output_section_statement_type *os;
          lang_output_section_phdr_list *pl;
 
-         os = &u->output_section_statement;
          if (os->constraint == -1)
            continue;
 
@@ -4930,22 +5319,22 @@ lang_record_phdrs (void)
   free (secs);
 
   /* Make sure all the phdr assignments succeeded.  */
-  for (u = lang_output_section_statement.head;
-       u != NULL;
-       u = u->output_section_statement.next)
+  for (os = &lang_output_section_statement.head->output_section_statement;
+       os != NULL;
+       os = os->next)
     {
       lang_output_section_phdr_list *pl;
 
-      if (u->output_section_statement.constraint == -1
-         || u->output_section_statement.bfd_section == NULL)
+      if (os->constraint == -1
+         || os->bfd_section == NULL)
        continue;
 
-      for (pl = u->output_section_statement.phdrs;
+      for (pl = os->phdrs;
           pl != NULL;
           pl = pl->next)
        if (! pl->used && strcmp (pl->name, "NONE") != 0)
          einfo (_("%X%P: section `%s' assigned to non-existent phdr `%s'\n"),
-                u->output_section_statement.name, pl->name);
+                os->name, pl->name);
     }
 }
 
index f7e2fa619e767e808ff0c6c782a86876fa52b29b..9b0f9eff18181d7b1170ee79660925a5fb2c8e26 100644 (file)
@@ -131,7 +131,7 @@ typedef struct lang_output_section_statement_struct
   union etree_union *addr_tree;
   lang_statement_list_type children;
   const char *memspec;
-  union lang_statement_union *next;
+  struct lang_output_section_statement_struct *next;
   const char *name;
 
   int processed;
@@ -410,6 +410,17 @@ struct lang_definedness_hash_entry
   int iteration;
 };
 
+/* Used by place_orphan to keep track of orphan sections and statements.  */
+
+struct orphan_save {
+  const char *name;
+  flagword flags;
+  lang_output_section_statement_type *os;
+  asection **section;
+  lang_statement_union_type **stmt;
+  lang_output_section_statement_type **os_tail;
+};
+
 extern struct unique_sections *unique_section_list;
 
 extern lang_output_section_statement_type *abs_output_section;
@@ -501,6 +512,12 @@ extern void ldlang_add_file
   (lang_input_statement_type *);
 extern lang_output_section_statement_type *lang_output_section_find
   (const char * const);
+extern lang_output_section_statement_type *lang_output_section_find_by_flags
+  (const asection *, lang_output_section_statement_type **exact);
+extern lang_output_section_statement_type *lang_insert_orphan
+  (lang_input_statement_type *, asection *, const char *,
+   lang_output_section_statement_type *, struct orphan_save *,
+   etree_type *, lang_statement_list_type *);
 extern lang_input_statement_type *lang_add_input_file
   (const char *, lang_input_file_enum_type, const char *);
 extern void lang_add_keepsyms_file
index da6dc8aac92c2a9ff2e6d92109160d25ab3de4c9..f9a8bd54f16468f35010380ae1eeb3f84d8ec846 100644 (file)
@@ -1,3 +1,9 @@
+2004-10-14  Alan Modra  <amodra@bigpond.net.au>
+
+       * ld-scripts/overlay-size.d: Update for changed orphan section
+       placement.
+       * ld-mmix/bpo-18.d: Likewise.
+
 2004-10-07  Bob Wilson  <bob.wilson@acm.org>
 
        * ld-xtensa/lcall1.s: Use .literal directive.
index 39c9282c45d8bf127c68809bb5ab0ebc59eca355..9a88569026f29e81e514df75df6838466c7ca57c 100644 (file)
@@ -12,9 +12,9 @@
 SYMBOL TABLE:
 0+100 l    d  \.text   0+ 
 4000000000001060 l    d  \.text\.away  0+ 
+400000000000106c l    d  \.data        0+ 
+400000000000106c l    d  \.bss 0+ 
 0+7e0 l    d  \.MMIX\.reg_contents     0+ 
-4000000000001088 l    d  \.data        0+ 
-4000000000001088 l    d  \.bss 0+ 
 0+ l    d  \*ABS\*     0+ 
 0+ l    d  \*ABS\*     0+ 
 0+ l    d  \*ABS\*     0+ 
index f54f56dfe71f4ac9277b6e1263c9162e6b70e381..9021aa438274f82010df8ef30871208eda781c44 100644 (file)
@@ -5,25 +5,25 @@
 # The .bss[123] LMAs are deliberately blanked out.  We can't
 # reliably map overlaid sections to segments.
 #...
 0 \.bss1 +0+010 +0+20000 .*
.. \.bss1 +0+010 +0+20000 .*
 #...
 1 \.bss2 +0+030 +0+20000 .*
.. \.bss2 +0+030 +0+20000 .*
 #...
 2 \.bss3 +0+020 +0+20000 .*
.. \.bss3 +0+020 +0+20000 .*
 #...
 3 \.mtext +0+020 +0+10000 +0+30000 .*
.. \.mtext +0+020 +0+10000 +0+30000 .*
 #...
 4 \.mbss +0+230 +0+20030 .*
.. \.mbss +0+230 +0+20030 .*
 #...
 5 \.text1 +0+080 +0+10020 +0+30020 .*
.. \.text1 +0+080 +0+10020 +0+30020 .*
 #...
 6 \.text2 +0+040 +0+10020 +0+300a0 .*
.. \.text2 +0+040 +0+10020 +0+300a0 .*
 #...
 7 \.text3 +0+020 +0+10020 +0+300e0 .*
.. \.text3 +0+020 +0+10020 +0+300e0 .*
 #...
 8 \.data1 +0+030 +0+20260 +0+30100 .*
.. \.data1 +0+030 +0+20260 +0+30100 .*
 #...
 9 \.data2 +0+040 +0+20260 +0+30130 .*
.. \.data2 +0+040 +0+20260 +0+30130 .*
 #...
10 \.data3 +0+050 +0+20260 +0+30170 .*
.. \.data3 +0+050 +0+20260 +0+30170 .*
 #pass