This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PowerPC gold failures building linux kernel


This fixes some gold failures found when building a recent powerpc64
linux kernel.  head_64.o has some "interesting" ftr (feature?) code
sections without exec permission set, containing branches.

  [ 7] __ftr_alt_97      PROGBITS        0000000000000000 00b1e0 00016c 00   A  0   0  4
  [ 8] .rela__ftr_alt_97 RELA            0000000000000000 014498 000060 18     21   7  8
  [ 9] __ftr_fixup       PROGBITS        0000000000000000 00b350 003900 00   A  0   0  8
  [10] .rela__ftr_fixup  RELA            0000000000000000 0144f8 007200 18     21   9  8
  [11] .toc              PROGBITS        0000000000000000 00ec50 000008 00  WA  0   0  8
  [12] __ftr_alt_66      PROGBITS        0000000000000000 00ec58 0002c4 00   A  0   0  4
  [13] __mmu_ftr_fixup   PROGBITS        0000000000000000 00ef20 000060 00   A  0   0  8
  [14] .rela__mmu_ftr_fixup RELA            0000000000000000 01b6f8 0000c0 18     21  13  8
  [15] __ftr_alt_96      PROGBITS        0000000000000000 00ef80 000000 00   A  0   0  4
  [16] __fw_ftr_fixup    PROGBITS        0000000000000000 00ef80 000540 00   A  0   0  8
  [17] .rela__fw_ftr_fixup RELA            0000000000000000 01b7b8 000a80 18     21  16  8

These sections are not considered when setting up stub groups, but the
branches are later examined to see whether they might need long branch
stubs, and hit assertions.  Fixed by the make_stub() and relocate()
changes.  If the branches actually need a stub, gold will warn about
the non-exec code section, and give a relocation overflow.

Another gold failure occurred due to trying to use the same section as
owner for two stub tables.  See the "Corner case" comment below.

Lastly, I failed to consider the possibility of non-exec sections and
padding between exec sections when setting up stub groups.  Either of
those could lead to stub groups being too large for branches to reach
the stubs.  Fixed by the change to can_add_to_stub_group().

	* 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.

Index: gold/powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.89
diff -u -p -r1.89 powerpc.cc
--- gold/powerpc.cc	11 Apr 2013 01:28:27 -0000	1.89
+++ gold/powerpc.cc	12 Apr 2013 05:02:30 -0000
@@ -1085,7 +1085,7 @@ class Target_powerpc : public Sized_targ
 				  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(Outp
 		 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_
 	}
     }
   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
       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>::Reloca
 	{
 	  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);
+	    }
 	}
     }
 

-- 
Alan Modra
Australia Development Lab, IBM


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]