summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHan Shen <shenhan@google.com>2015-06-16 22:00:58 (GMT)
committerDan Albert <danalbert@google.com>2015-07-29 17:58:40 (GMT)
commitec8f12bcfe31bcd5020c48c28c7b5247e3749647 (patch)
tree1c3f873615e246cb69bdc371765e70e075afbd03
parent3f3b4a87d2780f36eddc287dd830478550f031c6 (diff)
downloadtoolchain_binutils-ec8f12bcfe31bcd5020c48c28c7b5247e3749647.zip
toolchain_binutils-ec8f12bcfe31bcd5020c48c28c7b5247e3749647.tar.gz
toolchain_binutils-ec8f12bcfe31bcd5020c48c28c7b5247e3749647.tar.bz2
Patch for gold internal error while fixing erratum 843419.
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. gold/ChangeLog: 2015-06-29 Han Shen <shenhan@google.com> * 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. Change-Id: I9d90ac6e569bbbab086f877c7446dc6f9ea96247 (cherry picked from commit 56b06706ebe6bb3decc674b788b6f5b243b8610d)
-rw-r--r--binutils-2.25/gold/ChangeLog9
-rw-r--r--binutils-2.25/gold/aarch64.cc51
2 files changed, 56 insertions, 4 deletions
diff --git a/binutils-2.25/gold/ChangeLog b/binutils-2.25/gold/ChangeLog
index fd3415e..babb95e 100644
--- a/binutils-2.25/gold/ChangeLog
+++ b/binutils-2.25/gold/ChangeLog
@@ -1,3 +1,12 @@
+2015-06-29 Han Shen <shenhan@google.com>
+
+ Patch for erratum 843419 internal error.
+
+ * 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.
+
2015-06-16 Yiran Wang <yiran@google.com>
* resolve.cc disable the warning of a hidden symbol matches a
reference to be resolved
diff --git a/binutils-2.25/gold/aarch64.cc b/binutils-2.25/gold/aarch64.cc
index e8f5e1f..7fc18f6 100644
--- a/binutils-2.25/gold/aarch64.cc
+++ b/binutils-2.25/gold/aarch64.cc
@@ -894,6 +894,7 @@ 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 = 4;
@@ -938,6 +939,38 @@ public:
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 longer 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
@@ -1413,7 +1446,7 @@ Stub_table<size, big_endian>::add_erratum_stub(The_erratum_stub* stub)
}
-// 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>*
@@ -1514,6 +1547,12 @@ relocate_stubs(const The_relocate_info* relinfo,
{
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(
+ 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;
@@ -1831,13 +1870,17 @@ AArch64_relobj<size, big_endian>::fix_errata(
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();