public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [gold][aarch64] Patch for erratum-843419 (2 of 2 - fix erratum occurrences)
@ 2015-05-12 18:20 Han Shen
  2015-06-01 21:39 ` Cary Coutant
  0 siblings, 1 reply; 6+ messages in thread
From: Han Shen @ 2015-05-12 18:20 UTC (permalink / raw)
  To: Cary Coutant, binutils

[-- Attachment #1: Type: text/plain, Size: 3207 bytes --]

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.

[-- Attachment #2: e843419.patch --]
[-- Type: text/x-patch, Size: 43032 bytes --]

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>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [gold][aarch64] Patch for erratum-843419 (2 of 2 - fix erratum occurrences)
  2015-05-12 18:20 [gold][aarch64] Patch for erratum-843419 (2 of 2 - fix erratum occurrences) Han Shen
@ 2015-06-01 21:39 ` Cary Coutant
  2015-06-05 18:50   ` Han Shen
  0 siblings, 1 reply; 6+ messages in thread
From: Cary Coutant @ 2015-06-01 21:39 UTC (permalink / raw)
  To: Han Shen; +Cc: binutils

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

Sorry for the delay. I'm back from vacation now.

-cary


+// 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();
+};

Instead of using a struct to get the effect of a namespace, why
not just use a namespace directly? (It's not clear to me that you
really need to enclose these constants in a namespace at all. The
entire source file is already in an anonymous namespace, so
there's no worry about conflicting with any names from another
source file.)

+// 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&);

No spaces around "=".

I'd suggest adding a comment that you're disallowing these
constructors.

+
+  // Data that stores all insn templates.
+  Stub_template<big_endian>* stub_templates_[Stub_type::ST_NUMBER];
+};  // End of "class Stub_template_repertoire".

This class seems overly complex. It seems to me that it would be
simpler and clearer to make Stub_template a simple struct with
two fields, and make your repertoire a statically-initialized
array.

If you decide to stick with the singleton class, however, I see
no need for the get_instance() method -- just make
get_stub_template() a static member, and put the singleton there.

+// Constructor - creates/initilizes all stub templates.

"initializes"

+  // 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

"containing"

+  // 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_;

This is always going to be get_stub_templates(this->type_), so why not make
this a method instead of a data member?

+// 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.

"... we generate an erratum stub. We never share ..."

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.

+  // 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.

"problematic"

+// Find all the errata for a given input sectin. The return value is a pair of

"section"

+         stub_b_insn_address = stub_address
+           + 1 * AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;

Need parentheses around the split expression. It might look nicer if
you declare a local const with a shorter name:

    const int BPI = AArch64_insn_utilities<big_endian>::BYTES_PER_INSN
    ...
          stub_b_insn_address = stub_address + 1 * BPI;

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [gold][aarch64] Patch for erratum-843419 (2 of 2 - fix erratum occurrences)
  2015-06-01 21:39 ` Cary Coutant
@ 2015-06-05 18:50   ` Han Shen
  2015-06-10  6:15     ` Cary Coutant
  0 siblings, 1 reply; 6+ messages in thread
From: Han Shen @ 2015-06-05 18:50 UTC (permalink / raw)
  To: Cary Coutant, binutils; +Cc: Luis Lozano, Bhaskar

[-- Attachment #1: Type: text/plain, Size: 5794 bytes --]

Hi Cary, thanks for the review. (I also just came back from an offsite...)

Attached the new patch e843419-2nd.patch. Also
"diff-against-prev-patch.patch" for ease of incremental review.

On Mon, Jun 1, 2015 at 2:39 PM, Cary Coutant <ccoutant@gmail.com> wrote:
>> Hi Cary, here is the 2nd patch for erratum 843419 - fixing the erratum.
>
> Sorry for the delay. I'm back from vacation now.
>
> -cary
>
>
> +// 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();
> +};
>
> Instead of using a struct to get the effect of a namespace, why
> not just use a namespace directly? (It's not clear to me that you
> really need to enclose these constants in a namespace at all. The
> entire source file is already in an anonymous namespace, so
> there's no worry about conflicting with any names from another
> source file.)

Removed wrapping struct, and define them as global enum constants.

>
> +// 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&);
>
> No spaces around "=".

Done

>
> I'd suggest adding a comment that you're disallowing these
> constructors.

Done

>
> +
> +  // Data that stores all insn templates.
> +  Stub_template<big_endian>* stub_templates_[Stub_type::ST_NUMBER];
> +};  // End of "class Stub_template_repertoire".
>
> This class seems overly complex. It seems to me that it would be
> simpler and clearer to make Stub_template a simple struct with
> two fields, and make your repertoire a statically-initialized
> array.

Reduced Stub_template to POD with 2 constant fields.

>
> If you decide to stick with the singleton class, however, I see
> no need for the get_instance() method -- just make
> get_stub_template() a static member, and put the singleton there.

Keep Stub_template_repertoire as a singleton class but removed get_instance.
Also in ctor, use static variable to avoid explicit deletion in
~Stub_template_repertoire dtor.

>
> +// Constructor - creates/initilizes all stub templates.
>
> "initializes"

Done

>
> +  // 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
>
> "containing"

Done

>
> +  // 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_;
>
> This is always going to be get_stub_templates(this->type_), so why not make
> this a method instead of a data member?

Yup, this is good point. Done.

>
> +// 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.
>
> "... we generate an erratum stub. We never share ..."

Done.

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

Added this to the comment.

>
> +  // 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.
>
> "problematic"
>
> +// Find all the errata for a given input sectin. The return value is a pair of
>
> "section"

Done.

>
> +         stub_b_insn_address = stub_address
> +           + 1 * AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
>
> Need parentheses around the split expression. It might look nicer if
> you declare a local const with a shorter name:
>
>     const int BPI = AArch64_insn_utilities<big_endian>::BYTES_PER_INSN
>     ...
>           stub_b_insn_address = stub_address + 1 * BPI;

Done.

Thanks,
Han

[-- Attachment #2: e843419-2nd.patch --]
[-- Type: text/x-patch, Size: 36975 bytes --]

diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index 2745776..130fcc2 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -24,6 +24,7 @@
 
 #include <cstring>
 #include <map>
+#include <set>
 
 #include "elfcpp.h"
 #include "dwarf.h"
@@ -576,36 +577,398 @@ template<int size, bool big_endian>
 class AArch64_output_section;
 
 
+template<int size, bool big_endian>
+class AArch64_relobj;
+
+
+// Stub type enum constants.
+
+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
+};
+
+
+// Struct that wraps insns for a particular stub. All stub templates are
+// created/initialized as constants by Stub_template_repertoire.
+
+template<bool big_endian>
+struct Stub_template
+{
+  const typename AArch64_insn_utilities<big_endian>::Insntype* insns;
+  const int insn_num;
+};
+
+
+// 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)
+  {
+    static Stub_template_repertoire<big_endian> singleton;
+    return singleton.stub_templates_[type];
+  }
+
+private:
+  // Constructor - creates/initializes all stub templates.
+  Stub_template_repertoire();
+  ~Stub_template_repertoire()
+  { }
+
+  // Disallowing copy ctor and copy assignment operator.
+  Stub_template_repertoire(Stub_template_repertoire&);
+  Stub_template_repertoire& operator=(Stub_template_repertoire&);
+
+  // 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
+  {
+    return Stub_template_repertoire<big_endian>::
+      get_stub_template(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 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
+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;
@@ -635,84 +998,24 @@ class Reloc_stub
 
   // 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)
 	{
@@ -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.

[-- Attachment #3: diff-against-prev-patch.patch --]
[-- Type: text/x-patch, Size: 13014 bytes --]

diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index aa1558f..130fcc2 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -581,71 +581,42 @@ 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
+// Stub type enum constants.
+
+enum
 {
-  enum
-    {
-      ST_NONE = 0,
+  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 for erratum 843419 handling.
+  ST_E_843419 = 4,
 
-      // Number of total stub types.
-      ST_NUMBER = 5
-    };
-
-private:
-  // Never allow any such instance.
-  Stub_type();
+  // Number of total stub types.
+  ST_NUMBER = 5
 };
 
 
-// Class that wraps insns for a particular stub. All stub templates are
+// Struct 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
+struct 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".
+  const typename AArch64_insn_utilities<big_endian>::Insntype* insns;
+  const int insn_num;
+};
 
 
 // Simple singleton class that creates/initializes/stores all types of stub
@@ -657,31 +628,26 @@ 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>*
+  // Single static method to get stub template for a given stub type.
+  static const Stub_template<big_endian>*
   get_stub_template(int type)
-  { return this->stub_templates_[type]; }
+  {
+    static Stub_template_repertoire<big_endian> singleton;
+    return singleton.stub_templates_[type];
+  }
 
 private:
-  // Constructor - creates/initilizes all stub templates.
+  // Constructor - creates/initializes all stub templates.
   Stub_template_repertoire();
+  ~Stub_template_repertoire()
+  { }
 
-  // Destructor - deletes all stub templates.
-  ~Stub_template_repertoire();
-
+  // Disallowing copy ctor and copy assignment operator.
   Stub_template_repertoire(Stub_template_repertoire&);
-  Stub_template_repertoire& operator = (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];
+  const Stub_template<big_endian>* stub_templates_[ST_NUMBER];
 };  // End of "class Stub_template_repertoire".
 
 
@@ -730,8 +696,9 @@ Stub_template_repertoire<big_endian>::Stub_template_repertoire()
     };
 
 #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]))
+  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);
@@ -743,16 +710,6 @@ Stub_template_repertoire<big_endian>::Stub_template_repertoire()
 }
 
 
-// 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>
@@ -771,10 +728,7 @@ public:
   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))
+      type_(type)
   {}
 
   ~Stub_base()
@@ -785,6 +739,14 @@ public:
   type() const
   { return this->type_; }
 
+  // Get stub template that provides stub insn information.
+  const Stub_template<big_endian>*
+  stub_template() const
+  {
+    return Stub_template_repertoire<big_endian>::
+      get_stub_template(this->type());
+  }
+
   // Get destination address.
   AArch64_address
   destination_address() const
@@ -824,12 +786,12 @@ public:
   // Return the stub insn.
   const Insntype*
   insns() const
-  { return this->stub_template_->insns(); }
+  { return this->stub_template()->insns; }
 
   // Return num of stub insns.
   unsigned int
   insn_num() const
-  { return this->stub_template_->insn_num(); }
+  { return this->stub_template()->insn_num; }
 
   // Get size of the stub.
   int
@@ -855,20 +817,20 @@ private:
   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
+  // 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_;
-  // 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
+// 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.
+// 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>
@@ -991,7 +953,7 @@ Erratum_stub<size, big_endian>::do_write(unsigned char* view, section_size_type)
   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.
+  // 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]);
@@ -1201,16 +1163,16 @@ Reloc_stub<size, big_endian>::stub_type_for_reloc(
     }
 
   if (aarch64_valid_branch_offset_p(branch_offset))
-    return Stub_type::ST_NONE;
+    return ST_NONE;
 
   if (aarch64_valid_for_adrp_p(location, dest))
-    return Stub_type::ST_ADRP_BRANCH;
+    return ST_ADRP_BRANCH;
 
   if (parameters->options().output_is_position_independent()
       && parameters->options().output_is_executable())
-    return Stub_type::ST_LONG_BRANCH_PCREL;
+    return ST_LONG_BRANCH_PCREL;
 
-  return Stub_type::ST_LONG_BRANCH_ABS;
+  return ST_LONG_BRANCH_ABS;
 }
 
 // A class to hold stubs for the ARM target.
@@ -1403,7 +1365,7 @@ 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,
+  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())
@@ -1416,7 +1378,7 @@ Stub_table<size, big_endian>::find_erratum_stub(
 }
 
 
-// Find all the errata for a given input sectin. The return value is a pair of
+// 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>
@@ -1427,7 +1389,7 @@ Stub_table<size, big_endian>::find_erratum_stubs_for_input_section(
 {
   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);
+  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(),
@@ -1480,6 +1442,9 @@ relocate_stubs(const The_relocate_info* relinfo,
     relocate_stub(p->second, relinfo, target_aarch64, output_section,
 		  view, address, view_size);
 
+  // Just for convenience.
+  const int BPI = AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
+
   // Now 'relocate' erratum stubs.
   for(Erratum_stub_set_iter i = this->erratum_stubs_.begin();
       i != this->erratum_stubs_.end(); ++i)
@@ -1491,11 +1456,10 @@ relocate_stubs(const The_relocate_info* relinfo,
       int b_offset = 0;
       switch ((*i)->type())
 	{
-	case Stub_type::ST_E_843419:
+	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 * AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
+	  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()),
@@ -3507,7 +3471,7 @@ Target_aarch64<size, big_endian>::scan_reloc_for_stub(
 
   int stub_type = The_reloc_stub::
       stub_type_for_reloc(r_type, address, destination);
-  if (stub_type == Stub_type::ST_NONE)
+  if (stub_type == ST_NONE)
     return;
 
   The_stub_table* stub_table = aarch64_relobj->stub_table(relinfo->data_shndx);
@@ -3774,7 +3738,7 @@ relocate_stub(The_reloc_stub* stub,
 
   switch(stub->type())
     {
-    case Stub_type::ST_ADRP_BRANCH:
+    case ST_ADRP_BRANCH:
       {
 	// 1st reloc is ADR_PREL_PG_HI21
 	The_reloc_functions_status status =
@@ -3795,12 +3759,12 @@ relocate_stub(The_reloc_stub* stub,
       }
       break;
 
-    case Stub_type::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 Stub_type::ST_LONG_BRANCH_PCREL:
+    case ST_LONG_BRANCH_PCREL:
       {
 	// "PC" calculation is the 2nd insn in the stub.
 	uint64_t offset = dest - (address + 4);
@@ -5137,7 +5101,7 @@ maybe_apply_stub(unsigned int r_type,
   Address branch_target = psymval->value(object, 0) + addend;
   int stub_type =
     The_reloc_stub::stub_type_for_reloc(r_type, address, branch_target);
-  if (stub_type == Stub_type::ST_NONE)
+  if (stub_type == ST_NONE)
     return false;
 
   const The_aarch64_relobj* aarch64_relobj =
@@ -7790,7 +7754,7 @@ Target_aarch64<size, big_endian>::scan_erratum_843419_span(
 						errata_insn_offset) == NULL)
 		{
 		  The_erratum_stub* stub = new The_erratum_stub(
-		      relobj, Stub_type::ST_E_843419, shndx,
+		      relobj, ST_E_843419, shndx,
 		      errata_insn_offset);
 		  Address erratum_address =
 		    output_address + offset + insn_offset;

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [gold][aarch64] Patch for erratum-843419 (2 of 2 - fix erratum occurrences)
  2015-06-05 18:50   ` Han Shen
@ 2015-06-10  6:15     ` Cary Coutant
       [not found]       ` <CACkGtrjvQ67aQau4yDWnF0rOuKLsBgQU5MdXCh_f56Wvb8s5mg@mail.gmail.com>
  0 siblings, 1 reply; 6+ messages in thread
From: Cary Coutant @ 2015-06-10  6:15 UTC (permalink / raw)
  To: Han Shen; +Cc: binutils, Luis Lozano, Bhaskar

> Hi Cary, thanks for the review. (I also just came back from an offsite...)
>
> Attached the new patch e843419-2nd.patch. Also
> "diff-against-prev-patch.patch" for ease of incremental review.

This is OK. I think your ChangeLog entry needs some minor adjustments, though.

Thanks!

-cary


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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [gold][aarch64] Patch for erratum-843419 (2 of 2 - fix erratum occurrences)
       [not found]       ` <CACkGtrjvQ67aQau4yDWnF0rOuKLsBgQU5MdXCh_f56Wvb8s5mg@mail.gmail.com>
@ 2015-06-11 20:25         ` Cary Coutant
  2015-06-11 21:05           ` Han Shen
  0 siblings, 1 reply; 6+ messages in thread
From: Cary Coutant @ 2015-06-11 20:25 UTC (permalink / raw)
  To: Han Shen; +Cc: binutils, Luis Lozano, Bhaskar

[-- Attachment #1: Type: text/plain, Size: 451 bytes --]

With your last patch, gold won't build at -O0, because the
declarations of "static const int STUB_ADDR_ALIGN" need to be made
outside the class body. I've committed the attached patch to move
these initializations out of the class body.

-cary


2015-06-11  Cary Coutant  <ccoutant@gmail.com>

gold/
        * aarch64.cc (Erratum_stub::STUB_ADDR_ALIGN): Move initialization
        outside class body.
        (Reloc_stub::STUB_ADDR_ALIGN): Likewise.

[-- Attachment #2: stub-align.patch --]
[-- Type: application/octet-stream, Size: 1844 bytes --]

Fix gold build error at -O0.

In aarch64.cc, Erratum_stub::STUB_ADDR_ALIGN and Reloc_stub::STUB_ADDR_ALIGN
are declared as static const int, and initialized in the class body. These
values are referenced from outside the class body, and with no optimization,
the references go unresolved.

2015-06-11  Cary Coutant  <ccoutant@gmail.com>

gold/
	* aarch64.cc (Erratum_stub::STUB_ADDR_ALIGN): Move initialization
	outside class body.
	(Reloc_stub::STUB_ADDR_ALIGN): Likewise.


diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index 130fcc2..8dfd933 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -840,7 +840,7 @@ public:
   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 int STUB_ADDR_ALIGN;
 
   static const Insntype invalid_insn = static_cast<Insntype>(-1);
 
@@ -930,6 +930,8 @@ private:
   AArch64_address erratum_address_;
 };  // End of "Erratum_stub".
 
+template<int size, bool big_endian>
+const int Erratum_stub<size, big_endian>::STUB_ADDR_ALIGN = 4;
 
 // Comparator used in set definition.
 template<int size, bool big_endian>
@@ -980,7 +982,7 @@ class Reloc_stub : public Stub_base<size, big_endian>
   static const int MIN_ADRP_IMM = -(1 << 20);
 
   static const int BYTES_PER_INSN = 4;
-  static const int STUB_ADDR_ALIGN = 4;
+  static const int STUB_ADDR_ALIGN;
 
   // Determine whether the offset fits in the jump/branch instruction.
   static bool
@@ -1126,6 +1128,8 @@ class Reloc_stub : public Stub_base<size, big_endian>
   static const unsigned int invalid_index = static_cast<unsigned int>(-1);
 };  // End of Reloc_stub
 
+template<int size, bool big_endian>
+const int Reloc_stub<size, big_endian>::STUB_ADDR_ALIGN = 4;
 
 // Write data to output file.
 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [gold][aarch64] Patch for erratum-843419 (2 of 2 - fix erratum occurrences)
  2015-06-11 20:25         ` Cary Coutant
@ 2015-06-11 21:05           ` Han Shen
  0 siblings, 0 replies; 6+ messages in thread
From: Han Shen @ 2015-06-11 21:05 UTC (permalink / raw)
  To: Cary Coutant; +Cc: binutils, Luis Lozano, Bhaskar

Hi Cary, thanks for fixing this. I shall do an debug(-O0) build next time.

-Han

On Thu, Jun 11, 2015 at 1:25 PM, Cary Coutant <ccoutant@gmail.com> wrote:
> With your last patch, gold won't build at -O0, because the
> declarations of "static const int STUB_ADDR_ALIGN" need to be made
> outside the class body. I've committed the attached patch to move
> these initializations out of the class body.
>
> -cary
>
>
> 2015-06-11  Cary Coutant  <ccoutant@gmail.com>
>
> gold/
>         * aarch64.cc (Erratum_stub::STUB_ADDR_ALIGN): Move initialization
>         outside class body.
>         (Reloc_stub::STUB_ADDR_ALIGN): Likewise.



-- 
Han Shen |  Software Engineer |  shenhan@google.com |  +1-650-440-3330

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-06-11 21:05 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-12 18:20 [gold][aarch64] Patch for erratum-843419 (2 of 2 - fix erratum occurrences) Han Shen
2015-06-01 21:39 ` Cary Coutant
2015-06-05 18:50   ` Han Shen
2015-06-10  6:15     ` Cary Coutant
     [not found]       ` <CACkGtrjvQ67aQau4yDWnF0rOuKLsBgQU5MdXCh_f56Wvb8s5mg@mail.gmail.com>
2015-06-11 20:25         ` Cary Coutant
2015-06-11 21:05           ` Han Shen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).