This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [gold][aarch64] Patch for erratum-843419 (2 of 2 - fix erratum occurrences)


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

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