Fix edge cases in orphan section placement.
authorCary Coutant <ccoutant@gmail.com>
Tue, 13 Dec 2016 01:52:09 +0000 (17:52 -0800)
committerCary Coutant <ccoutant@gmail.com>
Tue, 13 Dec 2016 01:52:53 +0000 (17:52 -0800)
There were still some cases I found where orphan section placement
was screwy -- where the script has no output section description for
either .data or .bss, a .bss orphan section ends up getting placed
before the .data section. In addition, if there is an output section
description for a data section not named .data (e.g., .rela.dyn),
the orphan .bss gets placed before it. This patch cleans that up,
by tracking the last allocated section even as we're adding orphans.

I've also improved segment layout in the absence of a PHDRS clause.
A zero-length NOBITS section will no longer force a new segment
when followed by a PROGBITS section.

2016-12-12  Cary Coutant  <ccoutant@gmail.com>

gold/
* script-sections.cc (Orphan_section_placement::update_last_alloc):
New method.
(Orphan_section_placement::find_place): Place orphan .data section
after either RODATA or TEXT.
(Script_sections::place_orphan): Call update_last_alloc for allocated
sections.
(Script_sections::create_segments): Improve handling of BSS.

gold/ChangeLog
gold/script-sections.cc

index ef0dc13..aeec389 100644 (file)
@@ -1,3 +1,13 @@
+2016-12-12  Cary Coutant  <ccoutant@gmail.com>
+
+       * script-sections.cc (Orphan_section_placement::update_last_alloc):
+       New method.
+       (Orphan_section_placement::find_place): Place orphan .data section
+       after either RODATA or TEXT.
+       (Script_sections::place_orphan): Call update_last_alloc for allocated
+       sections.
+       (Script_sections::create_segments): Improve handling of BSS.
+
 2016-12-13  Alan Modra  <amodra@gmail.com>
 
        PR gold/16711
index ae81f89..d970e57 100644 (file)
@@ -313,6 +313,10 @@ class Orphan_section_placement
   bool
   find_place(Output_section*, Elements_iterator** pwhere);
 
+  // Update PLACE_LAST_ALLOC.
+  void
+  update_last_alloc(Elements_iterator where);
+
   // Return the iterator being used for sections at the very end of
   // the linker script.
   Elements_iterator
@@ -519,6 +523,11 @@ Orphan_section_placement::find_place(Output_section* os,
        case PLACE_RODATA:
          follow = PLACE_TEXT;
          break;
+       case PLACE_DATA:
+         follow = PLACE_RODATA;
+         if (!this->places_[PLACE_RODATA].have_location)
+           follow = PLACE_TEXT;
+         break;
        case PLACE_BSS:
          follow = PLACE_LAST_ALLOC;
          break;
@@ -557,6 +566,20 @@ Orphan_section_placement::find_place(Output_section* os,
   return ret;
 }
 
+// Update PLACE_LAST_ALLOC.
+void
+Orphan_section_placement::update_last_alloc(Elements_iterator elem)
+{
+  Elements_iterator prev = elem;
+  --prev;
+  if (this->places_[PLACE_LAST_ALLOC].have_location
+      && this->places_[PLACE_LAST_ALLOC].location == prev)
+    {
+      this->places_[PLACE_LAST_ALLOC].have_location = true;
+      this->places_[PLACE_LAST_ALLOC].location = elem;
+    }
+}
+
 // Return the iterator being used for sections at the very end of the
 // linker script.
 
@@ -3617,6 +3640,9 @@ Script_sections::place_orphan(Output_section* os)
       Sections_elements::iterator last = osp->last_place();
       *where = this->sections_elements_->insert(last, orphan);
     }
+
+  if ((os->flags() & elfcpp::SHF_ALLOC) != 0)
+    osp->update_last_alloc(*where);
 }
 
 // Set the addresses of all the output sections.  Walk through all the
@@ -3926,10 +3952,10 @@ Script_sections::create_segments(Layout* layout, uint64_t dot_alignment)
   Output_segment* first_seg = NULL;
   Output_segment* current_seg = NULL;
   bool is_current_seg_readonly = true;
-  Layout::Section_list::iterator plast = sections.end();
   uint64_t last_vma = 0;
   uint64_t last_lma = 0;
   uint64_t last_size = 0;
+  bool in_bss = false;
   for (Layout::Section_list::iterator p = sections.begin();
        p != sections.end();
        ++p)
@@ -3956,7 +3982,7 @@ Script_sections::create_segments(Layout* layout, uint64_t dot_alignment)
          // skipping a page.
          need_new_segment = true;
        }
-      else if (is_bss_section(*plast) && !is_bss_section(*p))
+      else if (in_bss && !is_bss_section(*p))
        {
          // A non-BSS section can not follow a BSS section in the
          // same segment.
@@ -3988,6 +4014,7 @@ Script_sections::create_segments(Layout* layout, uint64_t dot_alignment)
          if (first_seg == NULL)
            first_seg = current_seg;
          is_current_seg_readonly = true;
+         in_bss = false;
        }
 
       current_seg->add_output_section_to_load(layout, *p, seg_flags);
@@ -3995,7 +4022,9 @@ Script_sections::create_segments(Layout* layout, uint64_t dot_alignment)
       if (((*p)->flags() & elfcpp::SHF_WRITE) != 0)
        is_current_seg_readonly = false;
 
-      plast = p;
+      if (is_bss_section(*p) && size > 0)
+        in_bss = true;
+
       last_vma = vma;
       last_lma = lma;
       last_size = size;