[GOLD] powerpc64le-linux fails to link large Linux kernel
authorAlan Modra <amodra@gmail.com>
Wed, 7 Dec 2016 03:42:26 +0000 (14:12 +1030)
committerAlan Modra <amodra@gmail.com>
Wed, 7 Dec 2016 03:45:44 +0000 (14:15 +1030)
Gold attaches stubs to an existing section in contrast to ld.bfd which
inserts a new section for stubs.  If we want stubs before branches,
then the stubs must be added to the previous section.  Adding to the
previous section is a disaster if there is a large gap between the
previous section and the group.

PR gold/20878
* powerpc.cc (Stub_control): Replace stubs_always_before_branch_
with stubs_always_after_branch_, group_end_addr_ with
group_start_addr_.
(Stub_control::can_add_to_stub_group): Rewrite to suit scanning
sections by increasing address.
(Target_powerpc::group_sections): Scan that way.  Delete corner
case.
* options.h (--stub-group-size): Update help string.

gold/ChangeLog
gold/options.h
gold/powerpc.cc

index 50af9a2..367cb02 100644 (file)
@@ -1,5 +1,17 @@
 2016-12-07  Alan Modra  <amodra@gmail.com>
 
+       PR gold/20878
+       * powerpc.cc (Stub_control): Replace stubs_always_before_branch_
+       with stubs_always_after_branch_, group_end_addr_ with
+       group_start_addr_.
+       (Stub_control::can_add_to_stub_group): Rewrite to suit scanning
+       sections by increasing address.
+       (Target_powerpc::group_sections): Scan that way.  Delete corner
+       case.
+       * options.h (--stub-group-size): Update help string.
+
+2016-12-07  Alan Modra  <amodra@gmail.com>
+
        * powerpc.cc (Stub_table_owner): Provide constructor.
        (Powerpc_relobj::set_stub_table): Resize fill with -1.
        (Target_powerpc::Branch_info::make_stub): Provide target debug
index d21b935..90ccc80 100644 (file)
@@ -1216,8 +1216,7 @@ class General_options
   DEFINE_int(stub_group_size, options::TWO_DASHES , '\0', 1,
             N_("(ARM, PowerPC only) The maximum distance from instructions "
                "in a group of sections to their stubs. Negative values mean "
-               "stubs are always after (PowerPC before) the group. 1 means "
-               "use default size"),
+               "stubs are always after the group. 1 means use default size"),
             N_("SIZE"));
 
   DEFINE_uint(split_stack_adjust_size, options::TWO_DASHES, '\0', 0x4000,
index a850c36..f763618 100644 (file)
@@ -2439,13 +2439,13 @@ class Stub_control
  public:
   // Determine the stub group size.  The group size is the absolute
   // value of the parameter --stub-group-size.  If --stub-group-size
-  // is passed a negative value, we restrict stubs to be always before
+  // is passed a negative value, we restrict stubs to be always after
   // the stubbed branches.
   Stub_control(int32_t size, bool no_size_errors)
     : state_(NO_GROUP), stub_group_size_(abs(size)),
-      stubs_always_before_branch_(size < 0),
+      stubs_always_after_branch_(size < 0),
       suppress_size_errors_(no_size_errors), group_size_(0),
-      group_end_addr_(0), owner_(NULL), output_section_(NULL)
+      group_start_addr_(0), owner_(NULL), output_section_(NULL)
   {
   }
 
@@ -2482,13 +2482,13 @@ class Stub_control
 
   State state_;
   uint32_t stub_group_size_;
-  bool stubs_always_before_branch_;
+  bool stubs_always_after_branch_;
   bool suppress_size_errors_;
   // Current max size of group.  Starts at stub_group_size_ but is
   // reduced to stub_group_size_/1024 on seeing a section with
   // external conditional branches.
   uint32_t group_size_;
-  uint64_t group_end_addr_;
+  uint64_t group_start_addr_;
   // owner_ and output_section_ specify the section to which stubs are
   // attached.  The stubs are placed at the end of this section.
   const Output_section::Input_section* owner_;
@@ -2496,8 +2496,8 @@ class Stub_control
 };
 
 // Return true iff input section can be handled by current stub
-// group.  Sections are presented to this function in reverse order,
-// so the first section is the tail of the group.
+// group.  Sections are presented to this function in order,
+// so the first section is the head of the group.
 
 bool
 Stub_control::can_add_to_stub_group(Output_section* o,
@@ -2518,6 +2518,7 @@ Stub_control::can_add_to_stub_group(Output_section* o,
       this_size = i->data_size();
     }
 
+  uint64_t end_addr = start_addr + this_size;
   uint32_t group_size = this->stub_group_size_;
   if (has14)
     this->group_size_ = group_size = group_size >> 10;
@@ -2532,64 +2533,56 @@ Stub_control::can_add_to_stub_group(Output_section* o,
             i->relobj()->name().c_str(),
             i->relobj()->section_name(i->shndx()).c_str(),
             (long long) this_size,
-            (long long) this->group_end_addr_ - start_addr);
+            (this->state_ == NO_GROUP
+             ? this_size
+             : (long long) end_addr - this->group_start_addr_));
 
-  uint64_t end_addr = start_addr + this_size;
   if (this->state_ == HAS_STUB_SECTION)
     {
-      // Can we add this section, which is before the stubs, to the
+      // Can we add this section, which is after the stubs, to the
       // group?
-      if (this->group_end_addr_ - start_addr <= this->group_size_)
+      if (end_addr - this->group_start_addr_ <= this->group_size_)
        return true;
     }
-  else
+  else if (this->state_ == FINDING_STUB_SECTION)
     {
-      // Stubs are added at the end of "owner_".
-      // The current section can always be the stub owner, except when
-      // whole_sec is true and the current section isn't the last of
-      // the pasted sections.  (This restriction for the whole_sec
-      // case is just to simplify the corner case mentioned in
-      // group_sections.)
-      // Note that "owner_" itself is not necessarily part of the
-      // group of sections served by these stubs!
-      if (!whole_sec || this->output_section_ != o)
+      if ((whole_sec && this->output_section_ == o)
+         || end_addr - this->group_start_addr_ <= this->group_size_)
        {
+         // Stubs are added at the end of "owner_".
          this->owner_ = i;
          this->output_section_ = o;
+         return true;
        }
-
-      if (this->state_ == FINDING_STUB_SECTION)
-       {
-         if (this->group_end_addr_ - start_addr <= this->group_size_)
-           return true;
-         // The group after the stubs has reached maximum size.
-         // Now see about adding sections before the stubs to the
-         // group.  If the current section has a 14-bit branch and
-         // the group after the stubs exceeds group_size_ (because
-         // they didn't have 14-bit branches), don't add sections
-         // before the stubs:  The size of stubs for such a large
-         // group may exceed the reach of a 14-bit branch.
-         if (!this->stubs_always_before_branch_
-             && this_size <= this->group_size_
-             && this->group_end_addr_ - end_addr <= this->group_size_)
-           {
-             gold_debug(DEBUG_TARGET, "adding before stubs");
-             this->state_ = HAS_STUB_SECTION;
-             this->group_end_addr_ = end_addr;
-             return true;
-           }
-       }
-      else if (this->state_ == NO_GROUP)
+      // The group before the stubs has reached maximum size.
+      // Now see about adding sections after the stubs to the
+      // group.  If the current section has a 14-bit branch and
+      // the group before the stubs exceeds group_size_ (because
+      // they didn't have 14-bit branches), don't add sections
+      // after the stubs:  The size of stubs for such a large
+      // group may exceed the reach of a 14-bit branch.
+      if (!this->stubs_always_after_branch_
+         && this_size <= this->group_size_
+         && start_addr - this->group_start_addr_ <= this->group_size_)
        {
-         // Only here on very first use of Stub_control
-         this->state_ = FINDING_STUB_SECTION;
-         this->group_size_ = group_size;
-         this->group_end_addr_ = end_addr;
+         gold_debug(DEBUG_TARGET, "adding after stubs");
+         this->state_ = HAS_STUB_SECTION;
+         this->group_start_addr_ = start_addr;
          return true;
        }
-      else
-       gold_unreachable();
     }
+  else if (this->state_ == NO_GROUP)
+    {
+      // Only here on very first use of Stub_control
+      this->owner_ = i;
+      this->output_section_ = o;
+      this->state_ = FINDING_STUB_SECTION;
+      this->group_size_ = group_size;
+      this->group_start_addr_ = start_addr;
+      return true;
+    }
+  else
+    gold_unreachable();
 
   gold_debug(DEBUG_TARGET, "nope, didn't fit\n");
 
@@ -2599,7 +2592,7 @@ Stub_control::can_add_to_stub_group(Output_section* o,
   // group.
   this->state_ = FINDING_STUB_SECTION;
   this->group_size_ = group_size;
-  this->group_end_addr_ = end_addr;
+  this->group_start_addr_ = start_addr;
   return false;
 }
 
@@ -2619,14 +2612,14 @@ Target_powerpc<size, big_endian>::group_sections(Layout* layout,
   Layout::Section_list section_list;
   layout->get_executable_sections(&section_list);
   std::stable_sort(section_list.begin(), section_list.end(), Sort_sections());
-  for (Layout::Section_list::reverse_iterator o = section_list.rbegin();
-       o != section_list.rend();
+  for (Layout::Section_list::iterator o = section_list.begin();
+       o != section_list.end();
        ++o)
     {
       typedef Output_section::Input_section_list Input_section_list;
-      for (Input_section_list::const_reverse_iterator i
-            = (*o)->input_sections().rbegin();
-          i != (*o)->input_sections().rend();
+      for (Input_section_list::const_iterator i
+            = (*o)->input_sections().begin();
+          i != (*o)->input_sections().end();
           ++i)
        {
          if (i->is_input_section()
@@ -2653,26 +2646,8 @@ Target_powerpc<size, big_endian>::group_sections(Layout* layout,
     }
   if (table_owner != NULL)
     {
-      const Output_section::Input_section* i = stub_control.owner();
-
-      if (tables.size() >= 2 && tables[tables.size() - 2]->owner == i)
-       {
-         // Corner case.  A new stub group was made for the first
-         // section (last one looked at here) for some reason, but
-         // the first section is already being used as the owner for
-         // a stub table for following sections.  Force it into that
-         // stub group.
-         tables.pop_back();
-         delete table_owner;
-         Powerpc_relobj<size, big_endian>* ppcobj = static_cast
-           <Powerpc_relobj<size, big_endian>*>(i->relobj());
-         ppcobj->set_stub_table(i->shndx(), tables.size() - 1);
-       }
-      else
-       {
-         table_owner->output_section = stub_control.output_section();
-         table_owner->owner = i;
-       }
+      table_owner->output_section = stub_control.output_section();
+      table_owner->owner = stub_control.owner();;
     }
   for (typename std::vector<Stub_table_owner*>::iterator t = tables.begin();
        t != tables.end();