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] Patch for erratum-843419 (2 of 2 - fix erratum occurrences)


Hi Cary, here is the 2nd patch for erratum 843419 - fixing the erratum.

(Our customers are waiting for gold-aarch64 errata fixes, without this 843419
fix and 835769 (which will be my next CL), they have to temporarily revert to
bfd linker.)

For each erratum occurrence, a stub is generated and inserted into the stub
table. To implement this, a new stub type Erratum_stub is created and some
refactoring work is done to factor out common fields/operations in Erratum_stub
and Reloc_stub into Stub_base.

Test
- build successfully on x86-64 host and aarch64 host box.
- passed all gold aarch64 tests (which were created during the
development of gold-aarch64)
- passed bfd erratum-843419 test - erratum843419.s

Ok for trunk?

Thanks,
Han

gold/ChangeLog:

2015-05-12 Han Shen  <shenhan@google.com>

    * aarch64.cc(Stub_type): New constants representing stub types.
    (Stub_template): New class.
    (Stub_template_repertoire): New class.
    (Stub_base): New class.
    (Erratum_stub): New class.
    (Reloc_stub): Refactored to be a subclass of Stub_base.
    (Reloc_stub::Stub_type): Removed.
    (Reloc_stub::offset): Moved to Stub_base.
    (Reloc_stub::set_offset): Moved to Stub_base.
    (Reloc_stub::destination_address): Moved to Stub_base.
    (Reloc_stub::set_destination_address): Moved to Stub_base.
    (Reloc_stub::reset_destination_address): Moved to Stub_base.
    (Reloc_stub::stub_type): Renamed and moved to Stub_base.
    (Reloc_stub::stub_size): Renamed and moved to Stub_base.
    (Reloc_stub::stub_insns): Renamed and moved to Stub_base.
    (Reloc_stub::write): Moved to Stub_base.
    (Reloc_stub::invalid_offset): Moved to Stub_base.
    (Reloc_stub::invalid_address): Moved to Stub_base.
    (Reloc_stub::stub_type_): Renamed and moved to Stub_base.
    (Reloc_stub::stub_insns_): Moved to Stub_base.
    (Reloc_stub::offset_): Moved to Stub_base.
    (Reloc_stub::destination_address_): Moved to Stub_base.
    (Stub_table::The_aarch64_relobj): New typedef.
    (Stub_table::The_erratum_stub): New typedef.
    (Stub_table::The_erratum_stub_less): New typedef.
    (Stub_table::The_erratum_stub_set): New typedef.
    (Stub_table::The_erratum_stub_set_iter): New typedef.
    (Stub_table::empty): Added emptiness testing for erratum stubs.
    (Stub_table::add_erratum_stub): New method to add an erratum stub.
    (Stub_table::find_erratum_stub): New method.
    (Stub_table::find_erratum_stubs_for_input_section): New method.
    (Stub_table::erratum_stub_address): New method.
    (Stub_table::update_date_size_changed_p): Modified to handle erratum stubs.
    (Stub_table::do_addralign): Modified to handle erratum stubs.
    (Stub_table::erratum_stubs_): New member.
    (Stub_table::erratum_stub_size_): New member.
    (Stub_table::relocate_stubs): Modified to handle erratum stubs.
    (Stub_table::do_write): Modified to handle erratum stubs.
    (AArch64_relobj::The_erratum_stub): New typedef.
    (AArch64_relobj::Erratum_stub_set_iter): New typedef.
    (AArch64_relobj::fix_errata): New method.
    (Target_aarch64::The_reloc_stub_type): Removed.
    (Target_aarch64::The_erratum_stub): New typede.
    (AArch64_relocate_functions::construct_b): New method.
diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index 2745776..aa1558f 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -22,10 +22,11 @@
 
 #include "gold.h"
 
 #include <cstring>
 #include <map>
+#include <set>
 
 #include "elfcpp.h"
 #include "dwarf.h"
 #include "parameters.h"
 #include "reloc.h"
@@ -574,40 +575,440 @@ class AArch64_input_section;
 
 template<int size, bool big_endian>
 class AArch64_output_section;
 
 
+template<int size, bool big_endian>
+class AArch64_relobj;
+
+
+// Stub type enum constants wrapped in a struct, so we refer to them as
+// Stub_type::ST_XXX instead of ST_XXX.
+struct Stub_type
+{
+  enum
+    {
+      ST_NONE = 0,
+
+      // Using adrp/add pair, 4 insns (including alignment) without mem access,
+      // the fastest stub. This has a limited jump distance, which is tested by
+      // aarch64_valid_for_adrp_p.
+      ST_ADRP_BRANCH = 1,
+
+      // Using ldr-absolute-address/br-register, 4 insns with 1 mem access,
+      // unlimited in jump distance.
+      ST_LONG_BRANCH_ABS = 2,
+
+      // Using ldr/calculate-pcrel/jump, 8 insns (including alignment) with 1
+      // mem access, slowest one. Only used in position independent executables.
+      ST_LONG_BRANCH_PCREL = 3,
+
+      // Stub for erratum 843419 handling.
+      ST_E_843419 = 4,
+
+      // Number of total stub types.
+      ST_NUMBER = 5
+    };
+
+private:
+  // Never allow any such instance.
+  Stub_type();
+};
+
+
+// Class that wraps insns for a particular stub. All stub templates are
+// created/initialized as constants by Stub_template_repertoire.
+
+template<bool big_endian>
+class Stub_template
+{
+public:
+  typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
+
+  Stub_template(const Insntype* insns, const int insn_num)
+    : insns_(insns), insn_num_(insn_num)
+  {}
+
+  ~Stub_template() {}
+
+  // Get number of stub insns.
+  int
+  insn_num() const
+  { return this->insn_num_; }
+
+  // Get the stub insn array.
+  const Insntype*
+  insns() const
+  { return this->insns_; }
+
+private:
+  // Stub insn array.
+  const Insntype* insns_;
+  // Number of stub insns.
+  const int insn_num_;
+};  // End of "class Stub_template".
+
+
+// Simple singleton class that creates/initializes/stores all types of stub
+// templates.
+
+template<bool big_endian>
+class Stub_template_repertoire
+{
+public:
+  typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
+
+  // Get singleton instance.
+  static Stub_template_repertoire<big_endian>*
+  get_instance()
+  {
+    static Stub_template_repertoire<big_endian> singleton;
+    return &singleton;
+  }
+
+  // Get stub template for a given stub type.
+  Stub_template<big_endian>*
+  get_stub_template(int type)
+  { return this->stub_templates_[type]; }
+
+private:
+  // Constructor - creates/initilizes all stub templates.
+  Stub_template_repertoire();
+
+  // Destructor - deletes all stub templates.
+  ~Stub_template_repertoire();
+
+  Stub_template_repertoire(Stub_template_repertoire&);
+  Stub_template_repertoire& operator = (Stub_template_repertoire&);
+
+  // Data that stores all insn templates.
+  Stub_template<big_endian>* stub_templates_[Stub_type::ST_NUMBER];
+};  // End of "class Stub_template_repertoire".
+
+
+// Constructor - creates/initilizes all stub templates.
+
+template<bool big_endian>
+Stub_template_repertoire<big_endian>::Stub_template_repertoire()
+{
+  // Insn array definitions.
+  const static Insntype ST_NONE_INSNS[] = {};
+
+  const static Insntype ST_ADRP_BRANCH_INSNS[] =
+    {
+      0x90000010,	/*	adrp	ip0, X		   */
+			/*	  ADR_PREL_PG_HI21(X)	   */
+      0x91000210,	/*	add	ip0, ip0, :lo12:X  */
+			/*	  ADD_ABS_LO12_NC(X)	   */
+      0xd61f0200,	/*	br	ip0		   */
+      0x00000000,	/*	alignment padding	   */
+    };
+
+  const static Insntype ST_LONG_BRANCH_ABS_INSNS[] =
+    {
+      0x58000050,	/*	ldr   ip0, 0x8		   */
+      0xd61f0200,	/*	br    ip0		   */
+      0x00000000,	/*	address field		   */
+      0x00000000,	/*	address fields		   */
+    };
+
+  const static Insntype ST_LONG_BRANCH_PCREL_INSNS[] =
+    {
+      0x58000090,	/*	ldr   ip0, 0x10            */
+      0x10000011,	/*	adr   ip1, #0		   */
+      0x8b110210,	/*	add   ip0, ip0, ip1	   */
+      0xd61f0200,	/*	br    ip0		   */
+      0x00000000,	/*	address field		   */
+      0x00000000,	/*	address field		   */
+      0x00000000,	/*	alignment padding	   */
+      0x00000000,	/*	alignment padding	   */
+    };
+
+  const static Insntype ST_E_843419_INSNS[] =
+    {
+      0x00000000,    /* Placeholder for erratum insn. */
+      0x14000000,    /* b <label> */
+    };
+
+#define install_insn_template(T) \
+  this->stub_templates_[Stub_type::T] = new Stub_template<big_endian>( \
+    T##_INSNS, sizeof(T##_INSNS) / sizeof(T##_INSNS[0]))
+
+  install_insn_template(ST_NONE);
+  install_insn_template(ST_ADRP_BRANCH);
+  install_insn_template(ST_LONG_BRANCH_ABS);
+  install_insn_template(ST_LONG_BRANCH_PCREL);
+  install_insn_template(ST_E_843419);
+
+#undef install_insn_template
+}
+
+
+// Destructor that deletes all stub templates.
+
+template<bool big_endian>
+Stub_template_repertoire<big_endian>::~Stub_template_repertoire()
+{
+  for (int i = 0; i < Stub_type::ST_NUMBER; ++i)
+    delete stub_templates_[i];
+}
+
+
+// Base class for stubs.
+
+template<int size, bool big_endian>
+class Stub_base
+{
+public:
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
+  typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
+
+  static const AArch64_address invalid_address =
+    static_cast<AArch64_address>(-1);
+
+  static const section_offset_type invalid_offset =
+    static_cast<section_offset_type>(-1);
+
+  Stub_base(int type)
+    : destination_address_(invalid_address),
+      offset_(invalid_offset),
+      type_(type),
+      // Initialize a stub template by stub type from stub repertoire.
+      stub_template_(Stub_template_repertoire<big_endian>::
+		     get_instance()->get_stub_template(type))
+  {}
+
+  ~Stub_base()
+  {}
+
+  // Get stub type.
+  int
+  type() const
+  { return this->type_; }
+
+  // Get destination address.
+  AArch64_address
+  destination_address() const
+  {
+    gold_assert(this->destination_address_ != this->invalid_address);
+    return this->destination_address_;
+  }
+
+  // Set destination address.
+  void
+  set_destination_address(AArch64_address address)
+  {
+    gold_assert(address != this->invalid_address);
+    this->destination_address_ = address;
+  }
+
+  // Reset the destination address.
+  void
+  reset_destination_address()
+  { this->destination_address_ = this->invalid_address; }
+
+  // Get offset of code stub. For Reloc_stub, it is the offset from the
+  // beginning of its containing stub table; for Erratum_stub, it is the offset
+  // from the end of reloc_stubs.
+  section_offset_type
+  offset() const
+  {
+    gold_assert(this->offset_ != this->invalid_offset);
+    return this->offset_;
+  }
+
+  // Set stub offset.
+  void
+  set_offset(section_offset_type offset)
+  { this->offset_ = offset; }
+
+  // Return the stub insn.
+  const Insntype*
+  insns() const
+  { return this->stub_template_->insns(); }
+
+  // Return num of stub insns.
+  unsigned int
+  insn_num() const
+  { return this->stub_template_->insn_num(); }
+
+  // Get size of the stub.
+  int
+  stub_size() const
+  {
+    return this->insn_num() *
+      AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
+  }
+
+  // Write stub to output file.
+  void
+  write(unsigned char* view, section_size_type view_size)
+  { this->do_write(view, view_size); }
+
+protected:
+  // Abstract method to be implemented by sub-classes.
+  virtual void
+  do_write(unsigned char*, section_size_type) = 0;
+
+private:
+  // The last insn of a stub is a jump to destination insn. This field records
+  // the destination address.
+  AArch64_address destination_address_;
+  // The stub offset. Note this has difference interpretations between an
+  // Reloc_stub and an Erratum_stub. For Reloc_stub this is the offset from the
+  // beginning of the containng stub_table, whereas for Erratum_stub, this is
+  // the offset from the end of reloc_stubs.
+  section_offset_type offset_;
+  // Stub type.
+  const int type_;
+  // Stub template that provides stub insn information.
+  const Stub_template<big_endian>* stub_template_;
+};  // End of "Stub_base".
+
+
+// Erratum stub class. An erratum stub differs from a reloc stub in that for
+// each erratum occurrence, we generates an erratum stub, we never share erratum
+// stubs, whereas for reloc stubs, different branches insns share a single reloc
+// stub as long as the branch targets are the same.
+
+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 typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
+
+  static const int STUB_ADDR_ALIGN = 4;
+
+  static const Insntype invalid_insn = static_cast<Insntype>(-1);
+
+  Erratum_stub(The_aarch64_relobj* relobj, int type,
+	       unsigned shndx, unsigned int sh_offset)
+    : Stub_base<size, big_endian>(type), relobj_(relobj),
+      shndx_(shndx), sh_offset_(sh_offset),
+      erratum_insn_(invalid_insn),
+      erratum_address_(this->invalid_address)
+  {}
+
+  ~Erratum_stub() {}
+
+  // Return the object that contains the erratum.
+  The_aarch64_relobj*
+  relobj()
+  { return this->relobj_; }
+
+  // Get section index of the erratum.
+  unsigned int
+  shndx() const
+  { return this->shndx_; }
+
+  // Get section offset of the erratum.
+  unsigned int
+  sh_offset() const
+  { return this->sh_offset_; }
+
+  // Get the erratum insn. This is the insn located at erratum_insn_address.
+  Insntype
+  erratum_insn() const
+  {
+    gold_assert(this->erratum_insn_ != this->invalid_insn);
+    return this->erratum_insn_;
+  }
+
+  // Set the insn that the erratum happens to.
+  void
+  set_erratum_insn(Insntype insn)
+  { this->erratum_insn_ = insn; }
+
+  // Return the address where an erratum must be done.
+  AArch64_address
+  erratum_address() const
+  {
+    gold_assert(this->erratum_address_ != this->invalid_address);
+    return this->erratum_address_;
+  }
+
+  // Set the address where an erratum must be done.
+  void
+  set_erratum_address(AArch64_address addr)
+  { this->erratum_address_ = addr; }
+
+  // Comparator used to group Erratum_stubs in a set by (obj, shndx,
+  // sh_offset). We do not include 'type' in the calculation, becuase there is
+  // at most one stub type at (obj, shndx, sh_offset).
+  bool
+  operator<(const Erratum_stub<size, big_endian>& k) const
+  {
+    if (this == &k)
+      return false;
+    // We group stubs by relobj.
+    if (this->relobj_ != k.relobj_)
+      return this->relobj_ < k.relobj_;
+    // Then by section index.
+    if (this->shndx_ != k.shndx_)
+      return this->shndx_ < k.shndx_;
+    // Lastly by section offset.
+    return this->sh_offset_ < k.sh_offset_;
+  }
+
+protected:
+  virtual void
+  do_write(unsigned char*, section_size_type);
+
+private:
+  // The object that needs to be fixed.
+  The_aarch64_relobj* relobj_;
+  // The shndx in the object that needs to be fixed.
+  const unsigned int shndx_;
+  // The section offset in the obejct that needs to be fixed.
+  const unsigned int sh_offset_;
+  // The insn to be fixed.
+  Insntype erratum_insn_;
+  // The address of the above insn.
+  AArch64_address erratum_address_;
+};  // End of "Erratum_stub".
+
+
+// Comparator used in set definition.
+template<int size, bool big_endian>
+struct Erratum_stub_less
+{
+  bool
+  operator()(const Erratum_stub<size, big_endian>* s1,
+	     const Erratum_stub<size, big_endian>* s2) const
+  { return *s1 < *s2; }
+};
+
+// Erratum_stub implementation for writing stub to output file.
+
+template<int size, bool big_endian>
+void
+Erratum_stub<size, big_endian>::do_write(unsigned char* view, section_size_type)
+{
+  typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
+  const Insntype* insns = this->insns();
+  uint32_t num_insns = this->insn_num();
+  Insntype* ip = reinterpret_cast<Insntype*>(view);
+  // For current implemnted erratum 843419, (and 835769 which is to be
+  // implemented soon), the first insn in the stub is always a copy of the
+  // problmatic insn (in 843419, the mem access insn), followed by a jump-back.
+  elfcpp::Swap<32, big_endian>::writeval(ip, this->erratum_insn());
+  for (uint32_t i = 1; i < num_insns; ++i)
+    elfcpp::Swap<32, big_endian>::writeval(ip + i, insns[i]);
+}
+
+
 // Reloc stub class.
 
 template<int size, bool big_endian>
-class Reloc_stub
+class Reloc_stub : public Stub_base<size, big_endian>
 {
  public:
   typedef Reloc_stub<size, big_endian> This;
   typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
 
-  // Do not change the value of the enums, they are used to index into
-  // stub_insns array.
-  typedef enum
-  {
-    ST_NONE = 0,
-
-    // Using adrp/add pair, 4 insns (including alignment) without mem access,
-    // the fastest stub. This has a limited jump distance, which is tested by
-    // aarch64_valid_for_adrp_p.
-    ST_ADRP_BRANCH = 1,
-
-    // Using ldr-absolute-address/br-register, 4 insns with 1 mem access,
-    // unlimited in jump distance.
-    ST_LONG_BRANCH_ABS = 2,
-
-    // Using ldr/calculate-pcrel/jump, 8 insns (including alignment) with 1 mem
-    // access, slowest one. Only used in position independent executables.
-    ST_LONG_BRANCH_PCREL = 3,
-
-  } Stub_type;
-
   // Branch range. This is used to calculate the section group size, as well as
   // determine whether a stub is needed.
   static const int MAX_BRANCH_OFFSET = ((1 << 25) - 1) << 2;
   static const int MIN_BRANCH_OFFSET = -((1 << 25) << 2);
 
@@ -633,88 +1034,28 @@ class Reloc_stub
     return adrp_imm >= MIN_ADRP_IMM && adrp_imm <= MAX_ADRP_IMM;
   }
 
   // Determine the stub type for a certain relocation or ST_NONE, if no stub is
   // needed.
-  static Stub_type
+  static int
   stub_type_for_reloc(unsigned int r_type, AArch64_address address,
 		      AArch64_address target);
 
-  Reloc_stub(Stub_type stub_type)
-    : stub_type_(stub_type), offset_(invalid_offset),
-      destination_address_(invalid_address)
+  Reloc_stub(int type)
+    : Stub_base<size, big_endian>(type)
   { }
 
   ~Reloc_stub()
   { }
 
-  // Return offset of code stub from beginning of its containing stub table.
-  section_offset_type
-  offset() const
-  {
-    gold_assert(this->offset_ != invalid_offset);
-    return this->offset_;
-  }
-
-  // Set offset of code stub from beginning of its containing stub table.
-  void
-  set_offset(section_offset_type offset)
-  { this->offset_ = offset; }
-
-  // Return destination address.
-  AArch64_address
-  destination_address() const
-  {
-    gold_assert(this->destination_address_ != this->invalid_address);
-    return this->destination_address_;
-  }
-
-  // Set destination address.
-  void
-  set_destination_address(AArch64_address address)
-  {
-    gold_assert(address != this->invalid_address);
-    this->destination_address_ = address;
-  }
-
-  // Reset the destination address.
-  void
-  reset_destination_address()
-  { this->destination_address_ = this->invalid_address; }
-
-  // Return the stub type.
-  Stub_type
-  stub_type() const
-  { return stub_type_; }
-
-  // Return the stub size.
-  uint32_t
-  stub_size() const
-  { return this->stub_insn_number() * BYTES_PER_INSN; }
-
-  // Return the instruction number of this stub instance.
-  int
-  stub_insn_number() const
-  { return stub_insns_[this->stub_type_][0]; }
-
-  // Note the first "insn" is the number of total insns in this array.
-  const uint32_t*
-  stub_insns() const
-  { return stub_insns_[this->stub_type_]; }
-
-  // Write stub to output file.
-  void
-  write(unsigned char* view, section_size_type view_size)
-  { this->do_write(view, view_size); }
-
   // The key class used to index the stub instance in the stub table's stub map.
   class Key
   {
    public:
-    Key(Stub_type stub_type, const Symbol* symbol, const Relobj* relobj,
+    Key(int type, const Symbol* symbol, const Relobj* relobj,
 	unsigned int r_sym, int32_t addend)
-      : stub_type_(stub_type), addend_(addend)
+      : type_(type), addend_(addend)
     {
       if (symbol != NULL)
 	{
 	  this->r_sym_ = Reloc_stub::invalid_index;
 	  this->u_.symbol = symbol;
@@ -729,13 +1070,13 @@ class Reloc_stub
 
     ~Key()
     { }
 
     // Return stub type.
-    Stub_type
-    stub_type() const
-    { return this->stub_type_; }
+    int
+    type() const
+    { return this->type_; }
 
     // Return the local symbol index or invalid_index.
     unsigned int
     r_sym() const
     { return this->r_sym_; }
@@ -752,11 +1093,11 @@ class Reloc_stub
 
     // Whether this equals to another key k.
     bool
     eq(const Key& k) const
     {
-      return ((this->stub_type_ == k.stub_type_)
+      return ((this->type_ == k.type_)
 	      && (this->r_sym_ == k.r_sym_)
 	      && ((this->r_sym_ != Reloc_stub::invalid_index)
 		  ? (this->u_.relobj == k.u_.relobj)
 		  : (this->u_.symbol == k.u_.symbol))
 	      && (this->addend_ == k.addend_));
@@ -769,11 +1110,11 @@ class Reloc_stub
       size_t name_hash_value = gold::string_hash<char>(
 	  (this->r_sym_ != Reloc_stub::invalid_index)
 	  ? this->u_.relobj->name().c_str()
 	  : this->u_.symbol->name());
       // We only have 4 stub types.
-      size_t stub_type_hash_value = 0x03 & this->stub_type_;
+      size_t stub_type_hash_value = 0x03 & this->type_;
       return (name_hash_value
 	      ^ stub_type_hash_value
 	      ^ ((this->r_sym_ & 0x3fff) << 2)
 	      ^ ((this->addend_ & 0xffff) << 16));
     }
@@ -793,11 +1134,11 @@ class Reloc_stub
       { return k1.eq(k2); }
     };
 
    private:
     // Stub type.
-    const Stub_type stub_type_;
+    const int type_;
     // If this is a local symbol, this is the index in the defining object.
     // Otherwise, it is invalid_index for a global symbol.
     unsigned int r_sym_;
     // If r_sym_ is an invalid index, this points to a global symbol.
     // Otherwise, it points to a relobj.  We used the unsized and target
@@ -818,21 +1159,11 @@ class Reloc_stub
   // This may be overridden in the child class.
   virtual void
   do_write(unsigned char*, section_size_type);
 
  private:
-  static const section_offset_type invalid_offset =
-      static_cast<section_offset_type>(-1);
   static const unsigned int invalid_index = static_cast<unsigned int>(-1);
-  static const AArch64_address invalid_address =
-      static_cast<AArch64_address>(-1);
-
-  static const uint32_t stub_insns_[][10];
-
-  const Stub_type stub_type_;
-  section_offset_type offset_;
-  AArch64_address destination_address_;
 };  // End of Reloc_stub
 
 
 // Write data to output file.
 
@@ -840,70 +1171,23 @@ template<int size, bool big_endian>
 void
 Reloc_stub<size, big_endian>::
 do_write(unsigned char* view, section_size_type)
 {
   typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
-  const uint32_t* insns = this->stub_insns();
-  uint32_t num_insns = this->stub_insn_number();
+  const uint32_t* insns = this->insns();
+  uint32_t num_insns = this->insn_num();
   Insntype* ip = reinterpret_cast<Insntype*>(view);
-  for (uint32_t i = 1; i <= num_insns; ++i)
-    elfcpp::Swap<32, big_endian>::writeval(ip + i - 1, insns[i]);
+  for (uint32_t i = 0; i < num_insns; ++i)
+    elfcpp::Swap<32, big_endian>::writeval(ip + i, insns[i]);
 }
 
 
-// Stubs instructions definition.
-
-template<int size, bool big_endian>
-const uint32_t
-Reloc_stub<size, big_endian>::stub_insns_[][10] =
-  {
-    // The first element of each group is the num of the insns.
-
-    // ST_NONE
-    {0, 0},
-
-    // ST_ADRP_BRANCH
-    {
-	4,
-	0x90000010,	/*	adrp	ip0, X		   */
-			/*	  ADR_PREL_PG_HI21(X)	   */
-	0x91000210,	/*	add	ip0, ip0, :lo12:X  */
-			/*	  ADD_ABS_LO12_NC(X)	   */
-	0xd61f0200,	/*	br	ip0		   */
-	0x00000000,	/*	alignment padding	   */
-    },
-
-    // ST_LONG_BRANCH_ABS
-    {
-	4,
-	0x58000050,	/*	ldr   ip0, 0x8		   */
-	0xd61f0200,	/*	br    ip0		   */
-	0x00000000,	/*	address field		   */
-	0x00000000,	/*	address fields		   */
-    },
-
-    // ST_LONG_BRANCH_PCREL
-    {
-      8,
-	0x58000090,	/*	ldr   ip0, 0x10            */
-	0x10000011,	/*	adr   ip1, #0		   */
-	0x8b110210,	/*	add   ip0, ip0, ip1	   */
-	0xd61f0200,	/*	br    ip0		   */
-	0x00000000,	/*	address field		   */
-	0x00000000,	/*	address field		   */
-	0x00000000,	/*	alignment padding	   */
-	0x00000000,	/*	alignment padding	   */
-    }
-  };
-
-
 // Determine the stub type for a certain relocation or ST_NONE, if no stub is
 // needed.
 
 template<int size, bool big_endian>
-inline
-typename Reloc_stub<size, big_endian>::Stub_type
+inline int
 Reloc_stub<size, big_endian>::stub_type_for_reloc(
     unsigned int r_type, AArch64_address location, AArch64_address dest)
 {
   int64_t branch_offset = 0;
   switch(r_type)
@@ -915,44 +1199,51 @@ Reloc_stub<size, big_endian>::stub_type_for_reloc(
     default:
       gold_unreachable();
     }
 
   if (aarch64_valid_branch_offset_p(branch_offset))
-    return ST_NONE;
+    return Stub_type::ST_NONE;
 
   if (aarch64_valid_for_adrp_p(location, dest))
-    return ST_ADRP_BRANCH;
+    return Stub_type::ST_ADRP_BRANCH;
 
   if (parameters->options().output_is_position_independent()
       && parameters->options().output_is_executable())
-    return ST_LONG_BRANCH_PCREL;
+    return Stub_type::ST_LONG_BRANCH_PCREL;
 
-  return ST_LONG_BRANCH_ABS;
+  return Stub_type::ST_LONG_BRANCH_ABS;
 }
 
 // A class to hold stubs for the ARM target.
 
 template<int size, bool big_endian>
 class Stub_table : public Output_data
 {
  public:
   typedef Target_aarch64<size, big_endian> The_target_aarch64;
   typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
+  typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
   typedef AArch64_input_section<size, big_endian> The_aarch64_input_section;
   typedef Reloc_stub<size, big_endian> The_reloc_stub;
   typedef typename The_reloc_stub::Key The_reloc_stub_key;
+  typedef Erratum_stub<size, big_endian> The_erratum_stub;
+  typedef Erratum_stub_less<size, big_endian> The_erratum_stub_less;
   typedef typename The_reloc_stub_key::hash The_reloc_stub_key_hash;
   typedef typename The_reloc_stub_key::equal_to The_reloc_stub_key_equal_to;
   typedef Stub_table<size, big_endian> The_stub_table;
   typedef Unordered_map<The_reloc_stub_key, The_reloc_stub*,
 			The_reloc_stub_key_hash, The_reloc_stub_key_equal_to>
 			Reloc_stub_map;
   typedef typename Reloc_stub_map::const_iterator Reloc_stub_map_const_iter;
   typedef Relocate_info<size, big_endian> The_relocate_info;
 
+  typedef std::set<The_erratum_stub*, The_erratum_stub_less> Erratum_stub_set;
+  typedef typename Erratum_stub_set::iterator Erratum_stub_set_iter;
+
   Stub_table(The_aarch64_input_section* owner)
-    : Output_data(), owner_(owner), reloc_stubs_size_(0), prev_data_size_(0)
+    : Output_data(), owner_(owner), reloc_stubs_size_(0),
+      erratum_stubs_size_(0), prev_data_size_(0)
   { }
 
   ~Stub_table()
   { }
 
@@ -961,11 +1252,11 @@ class Stub_table : public Output_data
   { return owner_; }
 
   // Whether this stub table is empty.
   bool
   empty() const
-  { return reloc_stubs_.empty(); }
+  { return reloc_stubs_.empty() && erratum_stubs_.empty(); }
 
   // Return the current data size.
   off_t
   current_data_size() const
   { return this->current_data_size_for_child(); }
@@ -973,10 +1264,36 @@ class Stub_table : public Output_data
   // Add a STUB using KEY.  The caller is responsible for avoiding addition
   // if a STUB with the same key has already been added.
   void
   add_reloc_stub(The_reloc_stub* stub, const The_reloc_stub_key& key);
 
+  // Add an erratum stub into the erratum stub set. The set is ordered by
+  // (relobj, shndx, sh_offset).
+  void
+  add_erratum_stub(The_erratum_stub* stub);
+
+  // Find if such erratum exists for any given (obj, shndx, sh_offset).
+  The_erratum_stub*
+  find_erratum_stub(The_aarch64_relobj* a64relobj,
+		    unsigned int shndx, unsigned int sh_offset);
+
+  // Find all the erratums for a given input section. The return value is a pair
+  // of iterators [begin, end).
+  std::pair<Erratum_stub_set_iter, Erratum_stub_set_iter>
+  find_erratum_stubs_for_input_section(The_aarch64_relobj* a64relobj,
+				       unsigned int shndx);
+
+  // Compute the erratum stub address.
+  AArch64_address
+  erratum_stub_address(The_erratum_stub* stub) const
+  {
+    AArch64_address r = align_address(this->address() + this->reloc_stubs_size_,
+				      The_erratum_stub::STUB_ADDR_ALIGN);
+    r += stub->offset();
+    return r;
+  }
+
   // Finalize stubs. No-op here, just for completeness.
   void
   finalize_stubs()
   { }
 
@@ -1001,11 +1318,13 @@ class Stub_table : public Output_data
   // is different from that of the previous relaxation pass.
   bool
   update_data_size_changed_p()
   {
     // No addralign changed here.
-    off_t s = this->reloc_stubs_size_;
+    off_t s = align_address(this->reloc_stubs_size_,
+			    The_erratum_stub::STUB_ADDR_ALIGN)
+	      + this->erratum_stubs_size_;
     bool changed = (s != this->prev_data_size_);
     this->prev_data_size_ = s;
     return changed;
   }
 
@@ -1015,11 +1334,14 @@ class Stub_table : public Output_data
   do_write(Output_file*);
 
   // Return the required alignment.
   uint64_t
   do_addralign() const
-  { return The_reloc_stub::STUB_ADDR_ALIGN; }
+  {
+    return std::max(The_reloc_stub::STUB_ADDR_ALIGN,
+		    The_erratum_stub::STUB_ADDR_ALIGN);
+  }
 
   // Reset address and file offset.
   void
   do_reset_address_and_file_offset()
   { this->set_current_data_size_for_child(this->prev_data_size_); }
@@ -1043,26 +1365,92 @@ class Stub_table : public Output_data
  private:
   // Owner of this stub table.
   The_aarch64_input_section* owner_;
   // The relocation stubs.
   Reloc_stub_map reloc_stubs_;
+  // The erratum stubs.
+  Erratum_stub_set erratum_stubs_;
   // Size of reloc stubs.
   off_t reloc_stubs_size_;
+  // Size of erratum stubs.
+  off_t erratum_stubs_size_;
   // data size of this in the previous pass.
   off_t prev_data_size_;
 };  // End of Stub_table
 
 
+// Add an erratum stub into the erratum stub set. The set is ordered by
+// (relobj, shndx, sh_offset).
+
+template<int size, bool big_endian>
+void
+Stub_table<size, big_endian>::add_erratum_stub(The_erratum_stub* stub)
+{
+  std::pair<Erratum_stub_set_iter, bool> ret =
+    this->erratum_stubs_.insert(stub);
+  gold_assert(ret.second);
+  this->erratum_stubs_size_ = align_address(
+	this->erratum_stubs_size_, The_erratum_stub::STUB_ADDR_ALIGN);
+  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).
+
+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)
+{
+  // A dummy object used as key to search in the set.
+  The_erratum_stub key(a64relobj, Stub_type::ST_NONE,
+			 shndx, sh_offset);
+  Erratum_stub_set_iter i = this->erratum_stubs_.find(&key);
+  if (i != this->erratum_stubs_.end())
+    {
+	The_erratum_stub* stub(*i);
+	gold_assert(stub->erratum_insn() != 0);
+	return stub;
+    }
+  return NULL;
+}
+
+
+// Find all the errata for a given input sectin. The return value is a pair of
+// iterators [begin, end).
+
+template<int size, bool big_endian>
+std::pair<typename Stub_table<size, big_endian>::Erratum_stub_set_iter,
+	  typename Stub_table<size, big_endian>::Erratum_stub_set_iter>
+Stub_table<size, big_endian>::find_erratum_stubs_for_input_section(
+    The_aarch64_relobj* a64relobj, unsigned int shndx)
+{
+  typedef std::pair<Erratum_stub_set_iter, Erratum_stub_set_iter> Result_pair;
+  Erratum_stub_set_iter start, end;
+  The_erratum_stub low_key(a64relobj, Stub_type::ST_NONE, shndx, 0);
+  start = this->erratum_stubs_.lower_bound(&low_key);
+  if (start == this->erratum_stubs_.end())
+    return Result_pair(this->erratum_stubs_.end(),
+		       this->erratum_stubs_.end());
+  end = start;
+  while (end != this->erratum_stubs_.end() &&
+	 (*end)->relobj() == a64relobj && (*end)->shndx() == shndx)
+    ++end;
+  return Result_pair(start, end);
+}
+
+
 // Add a STUB using KEY.  The caller is responsible for avoiding addition
 // if a STUB with the same key has already been added.
 
 template<int size, bool big_endian>
 void
 Stub_table<size, big_endian>::add_reloc_stub(
     The_reloc_stub* stub, const The_reloc_stub_key& key)
 {
-  gold_assert(stub->stub_type() == key.stub_type());
+  gold_assert(stub->type() == key.type());
   this->reloc_stubs_[key] = stub;
 
   // Assign stub offset early.  We can do this because we never remove
   // reloc stubs and they are in the beginning of the stub table.
   this->reloc_stubs_size_ = align_address(this->reloc_stubs_size_,
@@ -1089,10 +1477,37 @@ relocate_stubs(const The_relocate_info* relinfo,
 	      view_size == static_cast<section_size_type>(this->data_size()));
   for(Reloc_stub_map_const_iter p = this->reloc_stubs_.begin();
       p != this->reloc_stubs_.end(); ++p)
     relocate_stub(p->second, relinfo, target_aarch64, output_section,
 		  view, address, view_size);
+
+  // Now 'relocate' erratum stubs.
+  for(Erratum_stub_set_iter i = this->erratum_stubs_.begin();
+      i != this->erratum_stubs_.end(); ++i)
+    {
+      AArch64_address stub_address = this->erratum_stub_address(*i);
+      // The address of "b" in the stub that is to be "relocated".
+      AArch64_address stub_b_insn_address;
+      // Branch offset that is to be filled in "b" insn.
+      int b_offset = 0;
+      switch ((*i)->type())
+	{
+	case Stub_type::ST_E_843419:
+	  // For the erratum, the 2nd insn is a b-insn to be patched
+	  // (relocated).
+	  stub_b_insn_address = stub_address
+	    + 1 * AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
+	  b_offset = (*i)->destination_address() - stub_b_insn_address;
+	  AArch64_relocate_functions<size, big_endian>::construct_b(
+	      view + (stub_b_insn_address - this->address()),
+	      ((unsigned int)(b_offset)) & 0xfffffff);
+	  break;
+	default:
+	  gold_unreachable();
+	  break;
+	}
+    }
 }
 
 
 // Relocate one stub.  This is a helper for Stub_table::relocate_stubs().
 
@@ -1138,10 +1553,21 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
       gold_assert(address ==
 		  align_address(address, The_reloc_stub::STUB_ADDR_ALIGN));
       stub->write(oview + stub->offset(), stub->stub_size());
     }
 
+  // Write erratum stubs.
+  unsigned int erratum_stub_start_offset =
+    align_address(this->reloc_stubs_size_, The_erratum_stub::STUB_ADDR_ALIGN);
+  for (typename Erratum_stub_set::iterator p = this->erratum_stubs_.begin();
+       p != this->erratum_stubs_.end(); ++p)
+    {
+      The_erratum_stub* stub(*p);
+      stub->write(oview + erratum_stub_start_offset + stub->offset(),
+		  stub->stub_size());
+    }
+
   of->write_output_view(this->offset(), oview_size, oview);
 }
 
 
 // AArch64_relobj class.
@@ -1153,10 +1579,12 @@ class AArch64_relobj : public Sized_relobj_file<size, big_endian>
   typedef AArch64_relobj<size, big_endian> This;
   typedef Target_aarch64<size, big_endian> The_target_aarch64;
   typedef AArch64_input_section<size, big_endian> The_aarch64_input_section;
   typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
   typedef Stub_table<size, big_endian> The_stub_table;
+  typedef Erratum_stub<size, big_endian> The_erratum_stub;
+  typedef typename The_stub_table::Erratum_stub_set_iter Erratum_stub_set_iter;
   typedef std::vector<The_stub_table*> Stub_table_list;
   static const AArch64_address invalid_address =
       static_cast<AArch64_address>(-1);
 
   AArch64_relobj(const std::string& name, Input_file* input_file, off_t offset,
@@ -1256,10 +1684,14 @@ class AArch64_relobj : public Sized_relobj_file<size, big_endian>
   virtual void
   do_count_local_symbols(Stringpool_template<char>*,
 			 Stringpool_template<char>*);
 
  private:
+  // Fix all errata in the object.
+  void
+  fix_errata(typename Sized_relobj_file<size, big_endian>::Views* pviews);
+
   // Whether a section needs to be scanned for relocation stubs.
   bool
   section_needs_reloc_stub_scanning(const elfcpp::Shdr<size, big_endian>&,
 				    const Relobj::Output_sections&,
 				    const Symbol_table*, const unsigned char*);
@@ -1351,10 +1783,52 @@ AArch64_relobj<size, big_endian>::do_count_local_symbols(
 	}
    }
 }
 
 
+// Fix all errata in the object.
+
+template<int size, bool big_endian>
+void
+AArch64_relobj<size, big_endian>::fix_errata(
+    typename Sized_relobj_file<size, big_endian>::Views* pviews)
+{
+  typedef typename elfcpp::Swap<32,big_endian>::Valtype Insntype;
+  unsigned int shnum = this->shnum();
+  for (unsigned int i = 1; i < shnum; ++i)
+    {
+      The_stub_table* stub_table = this->stub_table(i);
+      if (!stub_table)
+	continue;
+      std::pair<Erratum_stub_set_iter, Erratum_stub_set_iter>
+	ipair(stub_table->find_erratum_stubs_for_input_section(this, i));
+      Erratum_stub_set_iter p = ipair.first, end = ipair.second;
+      while (p != end)
+	{
+	  The_erratum_stub* stub = *p;
+	  typename Sized_relobj_file<size, big_endian>::View_size&
+	    pview((*pviews)[i]);
+
+	  // Double check data before fix.
+	  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());
+
+	  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);
+	  ++p;
+	}
+    }
+}
+
+
 // Relocate sections.
 
 template<int size, bool big_endian>
 void
 AArch64_relobj<size, big_endian>::do_relocate_sections(
@@ -1368,10 +1842,13 @@ AArch64_relobj<size, big_endian>::do_relocate_sections(
 
   // We do not generate stubs if doing a relocatable link.
   if (parameters->options().relocatable())
     return;
 
+  if (parameters->options().fix_cortex_a53_843419())
+    this->fix_errata(pviews);
+
   Relocate_info<size, big_endian> relinfo;
   relinfo.symtab = symtab;
   relinfo.layout = layout;
   relinfo.object = this;
 
@@ -2086,11 +2563,11 @@ class Target_aarch64 : public Sized_target<size, big_endian>
       Reloc_section;
   typedef Relocate_info<size, big_endian> The_relocate_info;
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
   typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
   typedef Reloc_stub<size, big_endian> The_reloc_stub;
-  typedef typename The_reloc_stub::Stub_type The_reloc_stub_type;
+  typedef Erratum_stub<size, big_endian> The_erratum_stub;
   typedef typename Reloc_stub<size, big_endian>::Key The_reloc_stub_key;
   typedef Stub_table<size, big_endian> The_stub_table;
   typedef std::vector<The_stub_table*> Stub_table_list;
   typedef typename Stub_table_list::iterator Stub_table_iterator;
   typedef AArch64_input_section<size, big_endian> The_aarch64_input_section;
@@ -3026,13 +3503,13 @@ Target_aarch64<size, big_endian>::scan_reloc_for_stub(
       break;
     default:
       gold_unreachable();
     }
 
-  typename The_reloc_stub::Stub_type stub_type = The_reloc_stub::
+  int stub_type = The_reloc_stub::
       stub_type_for_reloc(r_type, address, destination);
-  if (stub_type == The_reloc_stub::ST_NONE)
+  if (stub_type == Stub_type::ST_NONE)
     return;
 
   The_stub_table* stub_table = aarch64_relobj->stub_table(relinfo->data_shndx);
   gold_assert(stub_table != NULL);
 
@@ -3282,24 +3759,24 @@ relocate_stub(The_reloc_stub* stub,
   typedef AArch64_relocate_functions<size, big_endian> The_reloc_functions;
   typedef typename The_reloc_functions::Status The_reloc_functions_status;
   typedef typename elfcpp::Swap<32,big_endian>::Valtype Insntype;
 
   Insntype* ip = reinterpret_cast<Insntype*>(view);
-  int insn_number = stub->stub_insn_number();
-  const uint32_t* insns = stub->stub_insns();
+  int insn_number = stub->insn_num();
+  const uint32_t* insns = stub->insns();
   // Check the insns are really those stub insns.
   for (int i = 0; i < insn_number; ++i)
     {
       Insntype insn = elfcpp::Swap<32,big_endian>::readval(ip + i);
-      gold_assert(((uint32_t)insn == insns[i+1]));
+      gold_assert(((uint32_t)insn == insns[i]));
     }
 
   Address dest = stub->destination_address();
 
-  switch(stub->stub_type())
+  switch(stub->type())
     {
-    case The_reloc_stub::ST_ADRP_BRANCH:
+    case Stub_type::ST_ADRP_BRANCH:
       {
 	// 1st reloc is ADR_PREL_PG_HI21
 	The_reloc_functions_status status =
 	    The_reloc_functions::adrp(view, dest, address);
 	// An error should never arise in the above step. If so, please
@@ -3316,16 +3793,16 @@ relocate_stub(The_reloc_stub* stub,
 	// An error should never arise, it is an "_NC" relocation.
 	gold_assert(status == The_reloc_functions::STATUS_OKAY);
       }
       break;
 
-    case The_reloc_stub::ST_LONG_BRANCH_ABS:
+    case Stub_type::ST_LONG_BRANCH_ABS:
       // 1st reloc is R_AARCH64_PREL64, at offset 8
       elfcpp::Swap<64,big_endian>::writeval(view + 8, dest);
       break;
 
-    case The_reloc_stub::ST_LONG_BRANCH_PCREL:
+    case Stub_type::ST_LONG_BRANCH_PCREL:
       {
 	// "PC" calculation is the 2nd insn in the stub.
 	uint64_t offset = dest - (address + 4);
 	// Offset is placed at offset 4 and 5.
 	elfcpp::Swap<64,big_endian>::writeval(view + 16, offset);
@@ -4270,11 +4747,10 @@ class AArch64_relocate_functions
   typedef AArch64_relocate_functions<size, big_endian> This;
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
   typedef Relocate_info<size, big_endian> The_relocate_info;
   typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
   typedef Reloc_stub<size, big_endian> The_reloc_stub;
-  typedef typename The_reloc_stub::Stub_type The_reloc_stub_type;
   typedef Stub_table<size, big_endian> The_stub_table;
   typedef elfcpp::Rela<size, big_endian> The_rela;
   typedef typename elfcpp::Swap<size, big_endian>::Valtype AArch64_valtype;
 
   // Return the page address of the address.
@@ -4403,10 +4879,19 @@ class AArch64_relocate_functions
 	    : This::STATUS_OVERFLOW);
   }
 
  public:
 
+  // Construct a B insn. Note, although we group it here with other relocation
+  // operation, there is actually no 'relocation' involved here.
+  static inline void
+  construct_b(unsigned char* view, unsigned int branch_offset)
+  {
+    update_view_two_parts<32>(view, 0x05, (branch_offset >> 2),
+			      26, 0, 0xffffffff);
+  }
+
   // Do a simple rela relocation at unaligned addresses.
 
   template<int valsize>
   static inline typename This::Status
   rela_ua(unsigned char* view,
@@ -4648,13 +5133,13 @@ maybe_apply_stub(unsigned int r_type,
   if (parameters->options().relocatable())
     return false;
 
   typename elfcpp::Elf_types<size>::Elf_Swxword addend = rela.get_r_addend();
   Address branch_target = psymval->value(object, 0) + addend;
-  The_reloc_stub_type stub_type = The_reloc_stub::
-    stub_type_for_reloc(r_type, address, branch_target);
-  if (stub_type == The_reloc_stub::ST_NONE)
+  int stub_type =
+    The_reloc_stub::stub_type_for_reloc(r_type, address, branch_target);
+  if (stub_type == Stub_type::ST_NONE)
     return false;
 
   const The_aarch64_relobj* aarch64_relobj =
       static_cast<const The_aarch64_relobj*>(object);
   The_stub_table* stub_table = aarch64_relobj->stub_table(relinfo->data_shndx);
@@ -7256,13 +7741,19 @@ Target_aarch64<size, big_endian>::scan_erratum_843419_span(
       Insntype insn1 = ip[0];
       if (Insn_utilities::is_adrp(insn1))
 	{
 	  Insntype insn2 = ip[1];
 	  Insntype insn3 = ip[2];
+	  Insntype erratum_insn;
+	  unsigned insn_offset;
 	  bool do_report = false;
 	  if (is_erratum_843419_sequence(insn1, insn2, insn3))
-	    do_report = true;
+	    {
+	      do_report = true;
+	      erratum_insn = insn3;
+	      insn_offset = 2 * Insn_utilities::BYTES_PER_INSN;
+	    }
 	  else if (offset + 4 * Insn_utilities::BYTES_PER_INSN <= span_length)
 	    {
 	      // Optionally we can have an insn between ins2 and ins3
 	      Insntype insn_opt = ip[2];
 	      // And insn_opt must not be a branch.
@@ -7275,19 +7766,45 @@ Target_aarch64<size, big_endian>::scan_erratum_843419_span(
 		  // we do a conservative scan, which means we may fix/report
 		  // more than necessary, but it doesn't hurt.
 
 		  Insntype insn4 = ip[3];
 		  if (is_erratum_843419_sequence(insn1, insn2, insn4))
-		    do_report = true;
+		    {
+		      do_report = true;
+		      erratum_insn = insn4;
+		      insn_offset = 3 * Insn_utilities::BYTES_PER_INSN;
+		    }
 		}
 	    }
 	  if (do_report)
 	    {
-	      gold_error(_("Erratum 943419 found at \"%s\", section %d, "
-			   "offset 0x%08x."),
-			 relobj->name().c_str(), shndx,
-			 (unsigned int)(span_start + offset));
+	      gold_warning(_("Erratum 843419 found and fixed at \"%s\", "
+			     "section %d, offset 0x%08x."),
+			   relobj->name().c_str(), shndx,
+			   (unsigned int)(span_start + offset));
+	      unsigned int errata_insn_offset =
+		span_start + offset + insn_offset;
+	      The_stub_table* stub_table = relobj->stub_table(shndx);
+	      gold_assert(stub_table != NULL);
+	      if (stub_table->find_erratum_stub(relobj,
+						shndx,
+						errata_insn_offset) == NULL)
+		{
+		  The_erratum_stub* stub = new The_erratum_stub(
+		      relobj, Stub_type::ST_E_843419, shndx,
+		      errata_insn_offset);
+		  Address erratum_address =
+		    output_address + offset + insn_offset;
+		  // Stub destination address is the next insn after the
+		  // erratum.
+		  Address dest_address = erratum_address
+		    + Insn_utilities::BYTES_PER_INSN;
+		  stub->set_erratum_insn(erratum_insn);
+		  stub->set_erratum_address(erratum_address);
+		  stub->set_destination_address(dest_address);
+		  stub_table->add_erratum_stub(stub);
+		}
 	    }
 	}
 
       // Advance to next candidate instruction. We only consider instruction
       // sequences starting at a page offset of 0xff8 or 0xffc.
@@ -7295,11 +7812,11 @@ Target_aarch64<size, big_endian>::scan_erratum_843419_span(
       if (page_offset == 0xff8)
 	offset += 4;
       else  // (page_offset == 0xffc), we move to next page's 0xff8.
 	offset += 0xffc;
     }
-}
+}  // End of "Target_aarch64::scan_erratum_843419_span".
 
 
 // The selector for aarch64 object files.
 
 template<int size, bool big_endian>

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