* powerpc.cc (Stub_control::can_add_to_stub_group): Don't set
authorAlan Modra <amodra@gmail.com>
Sat, 13 Apr 2013 10:12:30 +0000 (10:12 +0000)
committerAlan Modra <amodra@gmail.com>
Sat, 13 Apr 2013 10:12:30 +0000 (10:12 +0000)
owner when sections are not adjacent and exceed group size.
(Target_powerpc::group_sections): Handle corner case.
(Target_powerpc::Branch_info::make_stub): Handle case where
stub table doesn't exist due to branches in non-exec sections.
(Target_powerpc::Relocate::relocate): Likewise.

gold/ChangeLog
gold/powerpc.cc

index 8f154a2d1bba8bf0382f0f0982eb28c2599c1ed6..26058749ab9b0845407ff9fa18c3a6a11dd65943 100644 (file)
@@ -1,3 +1,12 @@
+2013-04-13  Alan Modra  <amodra@gmail.com>
+
+       * powerpc.cc (Stub_control::can_add_to_stub_group): Don't set
+       owner when sections are not adjacent and exceed group size.
+       (Target_powerpc::group_sections): Handle corner case.
+       (Target_powerpc::Branch_info::make_stub): Handle case where
+       stub table doesn't exist due to branches in non-exec sections.
+       (Target_powerpc::Relocate::relocate): Likewise.
+
 2013-04-11  Alan Modra  <amodra@gmail.com>
 
        PR gold/15354
index 53bc39345d5c4415bb4b79ffcdd7af7c40665196..fdb68a1cb4d78e72b4dde110862e179331a3ac20 100644 (file)
@@ -1085,7 +1085,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
                                  reloc, this->rela_dyn_section(layout));
   }
 
-  // Look over all the input sections, deciding where to place stub.
+  // Look over all the input sections, deciding where to place stubs.
   void
   group_sections(Layout*, const Task*);
 
@@ -2226,7 +2226,7 @@ class Stub_control
   Output_section* output_section_;
 };
 
-// Return true iff input section can be handled by current stub/
+// Return true iff input section can be handled by current stub
 // group.
 
 bool
@@ -2258,7 +2258,9 @@ Stub_control::can_add_to_stub_group(Output_section* o,
                 i->relobj()->section_name(i->shndx()).c_str());
 
   if (this->state_ != HAS_STUB_SECTION
-      && (!whole_sec || this->output_section_ != o))
+      && (!whole_sec || this->output_section_ != o)
+      && (this->state_ == NO_GROUP
+         || this->group_end_addr_ - end_addr < group_size))
     {
       this->owner_ = i;
       this->output_section_ = o;
@@ -2331,7 +2333,25 @@ Target_powerpc<size, big_endian>::group_sections(Layout* layout,
        }
     }
   if (stub_table != NULL)
-    stub_table->init(stub_control.owner(), stub_control.output_section());
+    {
+      const Output_section::Input_section* i = stub_control.owner();
+      if (!i->is_input_section())
+       {
+         // 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.
+         gold_assert(this->stub_tables_.size() >= 2);
+         this->stub_tables_.pop_back();
+         delete stub_table;
+         Powerpc_relobj<size, big_endian>* ppcobj = static_cast
+           <Powerpc_relobj<size, big_endian>*>(i->relobj());
+         ppcobj->set_stub_table(i->shndx(), this->stub_tables_.back());
+       }
+      else
+       stub_table->init(i, stub_control.output_section());
+    }
 }
 
 // If this branch needs a plt call stub, or a long branch stub, make one.
@@ -2429,17 +2449,26 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
       to += this->addend_;
       if (stub_table == NULL)
        stub_table = this->object_->stub_table(this->shndx_);
-      gold_assert(stub_table != NULL);
       if (size == 64 && is_branch_reloc(this->r_type_))
        {
          unsigned int dest_shndx;
-         to = stub_table->targ()->symval_for_branch(symtab, to, gsym,
-                                                    this->object_,
-                                                    &dest_shndx);
+         Target_powerpc<size, big_endian>* target =
+           static_cast<Target_powerpc<size, big_endian>*>(
+               parameters->sized_target<size, big_endian>());
+         to = target->symval_for_branch(symtab, to, gsym,
+                                        this->object_, &dest_shndx);
        }
       Address delta = to - from;
       if (delta + max_branch_offset >= 2 * max_branch_offset)
        {
+         if (stub_table == NULL)
+           {
+             gold_warning(_("%s:%s: branch in non-executable section,"
+                            " no long branch stub for you"),
+                          this->object_->name().c_str(),
+                          this->object_->section_name(this->shndx_).c_str());
+             return;
+           }
          stub_table->add_long_branch_entry(this->object_, to);
        }
     }
@@ -6590,10 +6619,13 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
        {
          Stub_table<size, big_endian>* stub_table
            = object->stub_table(relinfo->data_shndx);
-         gold_assert(stub_table != NULL);
-         Address off = stub_table->find_long_branch_entry(object, value);
-         if (off != invalid_address)
-           value = stub_table->stub_address() + stub_table->plt_size() + off;
+         if (stub_table != NULL)
+           {
+             Address off = stub_table->find_long_branch_entry(object, value);
+             if (off != invalid_address)
+               value = (stub_table->stub_address() + stub_table->plt_size()
+                        + off);
+           }
        }
     }