Patch for erratum-843419 (2 of 2 - fix erratum occurrences).
authorHan Shen <shenhan@google.com>
Wed, 10 Jun 2015 16:50:22 +0000 (09:50 -0700)
committerHan Shen <shenhan@google.com>
Wed, 10 Jun 2015 17:02:15 +0000 (10:02 -0700)
Now fixing for 843419 is fully functional.

The first part of the erratum fix CL is here -
https://sourceware.org/ml/binutils/2015-04/msg00229.html

gold/ChangeLog
2015-06-10  Han Shen  <shenhan@google.com>

    * aarch64.cc(global enum): New constants representing stub types.
    (Stub_template): New POD struct.
    (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.

gold/ChangeLog
gold/aarch64.cc

index 0ec1c2718c8d5a2bcaa99ff0dc36f3d4abb5f95d..97a03b4b8a0c055e5d63b56776bf4deb35261848 100644 (file)
@@ -1,3 +1,56 @@
+2015-06-10  Han Shen  <shenhan@google.com>
+       Patch for erratum-843419 (2 of 2 - fix erratum occurrences).
+
+       Now fixing for 843419 is fully functional.
+
+       The first part of the erratum fix CL is here -
+       https://sourceware.org/ml/binutils/2015-04/msg00229.html
+
+       * aarch64.cc(global enum): New constants representing stub types.
+       (Stub_template): New POD struct.
+       (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.
+
 2015-06-08  Nick Clifton  <nickc@redhat.com>
 
        * po/fr.po: New French Translation.
index 27457760a154e2e5d4319e3a688e0d3f2e3092e9..130fcc2cba0760ffdbf231234e8427c131733271 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <cstring>
 #include <map>
+#include <set>
 
 #include "elfcpp.h"
 #include "dwarf.h"
@@ -576,91 +577,177 @@ template<int size, bool big_endian>
 class AArch64_output_section;
 
 
-// Reloc stub class.
-
 template<int size, bool big_endian>
-class Reloc_stub
+class AArch64_relobj;
+
+
+// Stub type enum constants.
+
+enum
 {
- public:
-  typedef Reloc_stub<size, big_endian> This;
-  typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
+  ST_NONE = 0,
 
-  // 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 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-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,
 
-    // 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,
 
-  } Stub_type;
+  // Number of total stub types.
+  ST_NUMBER = 5
+};
 
-  // 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);
 
-  // Constant used to determine if an offset fits in the adrp instruction
-  // encoding.
-  static const int MAX_ADRP_IMM = (1 << 20) - 1;
-  static const int MIN_ADRP_IMM = -(1 << 20);
+// Struct that wraps insns for a particular stub. All stub templates are
+// created/initialized as constants by Stub_template_repertoire.
 
-  static const int BYTES_PER_INSN = 4;
-  static const int STUB_ADDR_ALIGN = 4;
+template<bool big_endian>
+struct Stub_template
+{
+  const typename AArch64_insn_utilities<big_endian>::Insntype* insns;
+  const int insn_num;
+};
 
-  // Determine whether the offset fits in the jump/branch instruction.
-  static bool
-  aarch64_valid_branch_offset_p(int64_t offset)
-  { return offset >= MIN_BRANCH_OFFSET && offset <= MAX_BRANCH_OFFSET; }
 
-  // Determine whether the offset fits in the adrp immediate field.
-  static bool
-  aarch64_valid_for_adrp_p(AArch64_address location, AArch64_address dest)
+// 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;
+
+  // Single static method to get stub template for a given stub type.
+  static const Stub_template<big_endian>*
+  get_stub_template(int type)
   {
-    typedef AArch64_relocate_functions<size, big_endian> Reloc;
-    int64_t adrp_imm = (Reloc::Page(dest) - Reloc::Page(location)) >> 12;
-    return adrp_imm >= MIN_ADRP_IMM && adrp_imm <= MAX_ADRP_IMM;
+    static Stub_template_repertoire<big_endian> singleton;
+    return singleton.stub_templates_[type];
   }
 
-  // Determine the stub type for a certain relocation or ST_NONE, if no stub is
-  // needed.
-  static Stub_type
-  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)
+private:
+  // Constructor - creates/initializes all stub templates.
+  Stub_template_repertoire();
+  ~Stub_template_repertoire()
   { }
 
-  ~Reloc_stub()
-  { }
+  // Disallowing copy ctor and copy assignment operator.
+  Stub_template_repertoire(Stub_template_repertoire&);
+  Stub_template_repertoire& operator=(Stub_template_repertoire&);
 
-  // Return offset of code stub from beginning of its containing stub table.
-  section_offset_type
-  offset() const
+  // Data that stores all insn templates.
+  const Stub_template<big_endian>* stub_templates_[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) \
+  const static Stub_template<big_endian> template_##T = {  \
+    T##_INSNS, sizeof(T##_INSNS) / sizeof(T##_INSNS[0]) }; \
+  this->stub_templates_[T] = &template_##T
+
+  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
+}
+
+
+// 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)
+  {}
+
+  ~Stub_base()
+  {}
+
+  // Get stub type.
+  int
+  type() const
+  { return this->type_; }
+
+  // Get stub template that provides stub insn information.
+  const Stub_template<big_endian>*
+  stub_template() const
   {
-    gold_assert(this->offset_ != invalid_offset);
-    return this->offset_;
+    return Stub_template_repertoire<big_endian>::
+      get_stub_template(this->type());
   }
 
-  // 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.
+  // Get destination address.
   AArch64_address
   destination_address() const
   {
@@ -681,38 +768,254 @@ class Reloc_stub
   reset_destination_address()
   { this->destination_address_ = this->invalid_address; }
 
-  // Return the stub type.
-  Stub_type
-  stub_type() const
-  { return stub_type_; }
+  // 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_;
+  }
 
-  // Return the stub size.
-  uint32_t
-  stub_size() const
-  { return this->stub_insn_number() * BYTES_PER_INSN; }
+  // Set stub offset.
+  void
+  set_offset(section_offset_type offset)
+  { this->offset_ = offset; }
 
-  // Return the instruction number of this stub instance.
-  int
-  stub_insn_number() const
-  { return stub_insns_[this->stub_type_][0]; }
+  // Return the stub insn.
+  const Insntype*
+  insns() const
+  { return this->stub_template()->insns; }
 
-  // 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_]; }
+  // 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 containing 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_;
+};  // End of "Stub_base".
+
+
+// Erratum stub class. An erratum stub differs from a reloc stub in that for
+// each erratum occurrence, we generate 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. (More to the point, reloc
+// stubs can be shared because they're used to reach a specific target, whereas
+// erratum stubs branch back to the original control flow.)
+
+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
+  // problematic 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 : public Stub_base<size, big_endian>
+{
+ public:
+  typedef Reloc_stub<size, big_endian> This;
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
+
+  // 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);
+
+  // Constant used to determine if an offset fits in the adrp instruction
+  // encoding.
+  static const int MAX_ADRP_IMM = (1 << 20) - 1;
+  static const int MIN_ADRP_IMM = -(1 << 20);
+
+  static const int BYTES_PER_INSN = 4;
+  static const int STUB_ADDR_ALIGN = 4;
+
+  // Determine whether the offset fits in the jump/branch instruction.
+  static bool
+  aarch64_valid_branch_offset_p(int64_t offset)
+  { return offset >= MIN_BRANCH_OFFSET && offset <= MAX_BRANCH_OFFSET; }
+
+  // Determine whether the offset fits in the adrp immediate field.
+  static bool
+  aarch64_valid_for_adrp_p(AArch64_address location, AArch64_address dest)
+  {
+    typedef AArch64_relocate_functions<size, big_endian> Reloc;
+    int64_t adrp_imm = (Reloc::Page(dest) - Reloc::Page(location)) >> 12;
+    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 int
+  stub_type_for_reloc(unsigned int r_type, AArch64_address address,
+                     AArch64_address target);
+
+  Reloc_stub(int type)
+    : Stub_base<size, big_endian>(type)
+  { }
+
+  ~Reloc_stub()
+  { }
+
   // 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)
        {
@@ -731,9 +1034,9 @@ class Reloc_stub
     { }
 
     // 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
@@ -754,7 +1057,7 @@ class Reloc_stub
     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)
@@ -771,7 +1074,7 @@ class Reloc_stub
          ? 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)
@@ -795,7 +1098,7 @@ class Reloc_stub
 
    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_;
@@ -820,17 +1123,7 @@ class Reloc_stub
   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
 
 
@@ -842,66 +1135,19 @@ 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)
 {
@@ -937,9 +1183,12 @@ 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;
@@ -949,8 +1198,12 @@ class Stub_table : public Output_data
   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()
@@ -963,7 +1216,7 @@ class Stub_table : public Output_data
   // 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
@@ -975,6 +1228,32 @@ class Stub_table : public Output_data
   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()
@@ -1003,7 +1282,9 @@ class Stub_table : public Output_data
   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;
@@ -1017,7 +1298,10 @@ class Stub_table : public Output_data
   // 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
@@ -1045,13 +1329,79 @@ class Stub_table : public Output_data
   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, 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 section. 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, 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.
 
@@ -1060,7 +1410,7 @@ 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
@@ -1091,6 +1441,35 @@ relocate_stubs(const The_relocate_info* relinfo,
       p != this->reloc_stubs_.end(); ++p)
     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;
+
+  // 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 ST_E_843419:
+         // 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(
+             view + (stub_b_insn_address - this->address()),
+             ((unsigned int)(b_offset)) & 0xfffffff);
+         break;
+       default:
+         gold_unreachable();
+         break;
+       }
+    }
 }
 
 
@@ -1140,6 +1519,17 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
       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);
 }
 
@@ -1155,6 +1545,8 @@ class AArch64_relobj : public Sized_relobj_file<size, big_endian>
   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);
@@ -1258,6 +1650,10 @@ class AArch64_relobj : public Sized_relobj_file<size, big_endian>
                         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>&,
@@ -1353,6 +1749,48 @@ 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>
@@ -1370,6 +1808,9 @@ AArch64_relobj<size, big_endian>::do_relocate_sections(
   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;
@@ -2088,7 +2529,7 @@ class Target_aarch64 : public Sized_target<size, big_endian>
   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;
@@ -3028,9 +3469,9 @@ Target_aarch64<size, big_endian>::scan_reloc_for_stub(
       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 == ST_NONE)
     return;
 
   The_stub_table* stub_table = aarch64_relobj->stub_table(relinfo->data_shndx);
@@ -3284,20 +3725,20 @@ relocate_stub(The_reloc_stub* stub,
   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 ST_ADRP_BRANCH:
       {
        // 1st reloc is ADR_PREL_PG_HI21
        The_reloc_functions_status status =
@@ -3318,12 +3759,12 @@ relocate_stub(The_reloc_stub* stub,
       }
       break;
 
-    case The_reloc_stub::ST_LONG_BRANCH_ABS:
+    case 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 ST_LONG_BRANCH_PCREL:
       {
        // "PC" calculation is the 2nd insn in the stub.
        uint64_t offset = dest - (address + 4);
@@ -4272,7 +4713,6 @@ class AArch64_relocate_functions
   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;
@@ -4405,6 +4845,15 @@ class AArch64_relocate_functions
 
  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>
@@ -4650,9 +5099,9 @@ maybe_apply_stub(unsigned int r_type,
 
   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 == ST_NONE)
     return false;
 
   const The_aarch64_relobj* aarch64_relobj =
@@ -7258,9 +7707,15 @@ Target_aarch64<size, big_endian>::scan_erratum_843419_span(
        {
          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
@@ -7277,15 +7732,41 @@ Target_aarch64<size, big_endian>::scan_erratum_843419_span(
 
                  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, 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);
+               }
            }
        }
 
@@ -7297,7 +7778,7 @@ Target_aarch64<size, big_endian>::scan_erratum_843419_span(
       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.