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]

[gold][aarch64] Fix internal error while fixing 843419


Hi Cary, here is the patch for gold internal error while fixing
erratum 843419 (reported by Android NDK).

The crash reason is that the insn to be moved to stub may be a
relocation spot, so instead of placing the origin insn (that is insn
before-relocation) to the stub, I have to place the relocated one.
Note the relocation involved is non-pc-relative, so it is safe to move
the relocated insn.

Testing - Build the problematic android component, assembly examined
(also add this to local aarch64 test set). And passed all previous
tests.

Ok for trunk?

gold/ChangeLog:
        * AArch64.cc (Erratum_stub::Insn_utilities): New typedef.
        (Erratum_stub::update_erratum_insn): New method.
        (Stub_table::relocate_stubs): Modified to place relocated insn.
        (AArch64_relobj::fix_errata): Modified gold_assert.
diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index 72a65db..acdc0e8 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -892,10 +892,11 @@ template<int size, bool big_endian>
 class Erratum_stub : public Stub_base<size, big_endian>
 {
 public:
   typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
   typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
+  typedef AArch64_insn_utilities<big_endian> Insn_utilities;
   typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
 
   static const int STUB_ADDR_ALIGN;
 
   static const Insntype invalid_insn = static_cast<Insntype>(-1);
@@ -936,10 +937,43 @@ public:
   // Set the insn that the erratum happens to.
   void
   set_erratum_insn(Insntype insn)
   { this->erratum_insn_ = insn; }
 
+  // For 843419, the erratum insn is ld/st xt, [xn, #uimm], which may
+  // be a relocation spot, in this case, the erratum_insn_ recorded at
+  // scanning phase is no long the one we want to write out to the
+  // stub, update erratum_insn_ with relocated version. Also note that
+  // in this case xn must not be "PC", so it is safe to move the
+  // erratum insn from the origin place to the stub. For 835769, the
+  // erratum insn is multiply-accumulate insn, which could not be a
+  // relocation spot (assertion added though).
+  void
+  update_erratum_insn(Insntype insn)
+  {
+    gold_assert(this->erratum_insn_ != this->invalid_insn);
+    switch (this->type())
+      {
+      case ST_E_843419:
+	gold_assert(Insn_utilities::aarch64_ldst_uimm(insn));
+	gold_assert(Insn_utilities::aarch64_ldst_uimm(this->erratum_insn()));
+	gold_assert(Insn_utilities::aarch64_rd(insn) ==
+		    Insn_utilities::aarch64_rd(this->erratum_insn()));
+	gold_assert(Insn_utilities::aarch64_rn(insn) ==
+		    Insn_utilities::aarch64_rn(this->erratum_insn()));
+	// Update plain ld/st insn with relocated insn.
+	this->erratum_insn_ = insn;
+	break;
+      case ST_E_835769:
+	gold_assert(insn == this->erratum_insn());
+	break;
+      default:
+	gold_unreachable();
+      }
+  }
+
+
   // Return the address where an erratum must be done.
   AArch64_address
   erratum_address() const
   {
     gold_assert(this->erratum_address_ != this->invalid_address);
@@ -1415,11 +1449,11 @@ Stub_table<size, big_endian>::add_erratum_stub(The_erratum_stub* stub)
   stub->set_offset(this->erratum_stubs_size_);
   this->erratum_stubs_size_ += stub->stub_size();
 }
 
 
-// Find if such erratum exists for givein (obj, shndx, sh_offset).
+// Find if such erratum exists for given (obj, shndx, sh_offset).
 
 template<int size, bool big_endian>
 Erratum_stub<size, big_endian>*
 Stub_table<size, big_endian>::find_erratum_stub(
     The_aarch64_relobj* a64relobj, unsigned int shndx, unsigned int sh_offset)
@@ -1502,10 +1536,11 @@ relocate_stubs(const The_relocate_info* relinfo,
     relocate_stub(p->second, relinfo, target_aarch64, output_section,
 		  view, address, view_size);
 
   // Just for convenience.
   const int BPI = AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
+  typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
 
   // Now 'relocate' erratum stubs.
   for(Erratum_stub_set_iter i = this->erratum_stubs_.begin();
       i != this->erratum_stubs_.end(); ++i)
     {
@@ -1516,10 +1551,17 @@ relocate_stubs(const The_relocate_info* relinfo,
       int b_offset = 0;
       switch ((*i)->type())
 	{
 	case ST_E_843419:
 	case ST_E_835769:
+	  // The 1st insn of the erratum could be a relocation spot,
+	  // in this case we need to fix it with
+	  // "(*i)->erratum_insn()".
+	  elfcpp::Swap<32, big_endian>::writeval(
+	      reinterpret_cast<Insntype*>(
+		  view + (stub_address - this->address())),
+	      (*i)->erratum_insn());
 	  // For the erratum, the 2nd insn is a b-insn to be patched
 	  // (relocated).
 	  stub_b_insn_address = stub_address + 1 * BPI;
 	  b_offset = (*i)->destination_address() - stub_b_insn_address;
 	  AArch64_relocate_functions<size, big_endian>::construct_b(
@@ -1833,17 +1875,21 @@ AArch64_relobj<size, big_endian>::fix_errata(
 	  The_erratum_stub* stub = *p;
 	  typename Sized_relobj_file<size, big_endian>::View_size&
 	    pview((*pviews)[i]);
 
 	  // Double check data before fix.
+	  gold_assert(pview.address + stub->sh_offset()
+		      == stub->erratum_address());
+
+	  // Update previously recorded erratum insn with relocated
+	  // version.
 	  Insntype* ip =
 	    reinterpret_cast<Insntype*>(pview.view + stub->sh_offset());
 	  Insntype insn_to_fix = ip[0];
-	  gold_assert(insn_to_fix == stub->erratum_insn());
-	  gold_assert(pview.address + stub->sh_offset()
-		      == stub->erratum_address());
+	  stub->update_erratum_insn(insn_to_fix);
 
+	  // Replace the erratum insn with a branch-to-stub.
 	  AArch64_address stub_address =
 	    stub_table->erratum_stub_address(stub);
 	  unsigned int b_offset = stub_address - stub->erratum_address();
 	  AArch64_relocate_functions<size, big_endian>::construct_b(
 	    pview.view + stub->sh_offset(), b_offset & 0xfffffff);

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